I get an eNullObjectId error. I thought I found the answer here, but I couldn't get it to work. Please don't answer in C#. I've used code converters and they don't work well.
Public Function FindReplace(ldate As String, fn As String, strFind As List(Of String), strReplace As List(Of String)) Dim ed As Autodesk.AutoCAD.EditorInput.Editor = Core.Application.DocumentManager.MdiActiveDocument.Editor, db As Database = New Database(False, True), dwgDir As String = IO.Path.GetDirectoryName(fn), dwgName As String = IO.Path.GetFileName(fn), dwgfullname As String = dwgDir & "\" & dwgName, log As New List(Of String) Using db Try 'FileOpenMode.OpenForReadAndAllShare db.ReadDwgFile(fn, FileOpenMode.OpenForReadAndAllShare, False, Nothing) Catch __unusedException1__ As System.Exception ed.WriteMessage(vbLf & "Unable to read drawing file.") End Try Dim lg As New List(Of String())(), txtClass = RXObject.GetClass(GetType(DBText)), mtxtClass = RXObject.GetClass(GetType(MText)), blkrefClass = RXObject.GetClass(GetType(BlockReference)) Using tr = db.TransactionManager.StartTransaction Dim loDic As DBDictionary = CType(tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, False), DBDictionary) For Each entry As DBDictionaryEntry In loDic Dim layout = CType(tr.GetObject(entry.Value, OpenMode.ForRead), Layout) Dim btr As BlockTableRecord = CType(tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead), BlockTableRecord) For Each objID As ObjectId In btr If objID.ObjectClass.IsDerivedFrom(blkrefClass) Then Dim blkRef As BlockReference = CType(tr.GetObject(objID, OpenMode.ForRead), BlockReference), acblkName As String = blkRef.Name, ' Error is here nbtr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord), attCol As AttributeCollection = blkRef.AttributeCollection If attCol IsNot Nothing Then For Each attId As ObjectId In attCol Dim att As AttributeReference = CType(tr.GetObject(attId, OpenMode.ForWrite), AttributeReference), wksp As String = att.BlockName.ToString, hand As String = att.Handle.ToString, val As String = att.TextString, locX As String = att.Position.X.ToString, locY As String = att.Position.Y.ToString, locZ As String = att.Position.Z.ToString For i = 0 To strFind.Count - 1 If val.Contains(strFind(i)) = True Then att.TextString = val.Replace(strFind(i), strReplace(i)) att.RecordGraphicsModified(True) att.AdjustAlignment(db) log.Add(ldate & "," & att.TextString & "," & val & "," & "Attribute" & "," & dwgName & "," & wksp & "," & hand & "," & locX & "," & locY & "," & locZ) Dim wbd As Database = HostApplicationServices.WorkingDatabase HostApplicationServices.WorkingDatabase = db att.AdjustAlignment(db) End If Next Next End If End If Next Next tr.Commit() End Using db.SaveAs(fn, DwgVersion.AC1027) End Using Return log End Function
Solved! Go to Solution.
Solved by ActivistInvestor. Go to Solution.
Hi,
Just a thought as you do not want a C# reply, try to replace:
If objID.ObjectClass.IsDerivedFrom(blkrefClass) Then
with:
If objID.ObjectClass = blkrefClass Then
so that you discard types which inherit from BlockReference as MInsertBlock, Table and ViewRepBlockReference.
And please the next time you post code, clean it before posting by deleting all unnecessary and unnecessary lines.
Some of us have to make an effort to read VB, make it easier for people to ask for help ...
I attempted the change you suggested and I still get the same error. I've tried locking the drawing as well, but that doesn't work. Based on the error message I get, listed below, I think there is some connection to locked viewports or viewports on lock layers. When I go back into the file that the program failed on and modify the viewports to display not locked and make sure the layer is on and unlocked, then the routine can handle the file fine. Apologies for any excess code, as I part-time coder showing enough/too much always seems to be a struggle. As in this case, the code doesn't touch viewports, so I can't see what could be causing the issue.
If objID.ObjectClass = blkrefClass Then Dim blkRef As BlockReference = CType(tr.GetObject(objID, OpenMode.ForRead), BlockReference) If blkRef IsNot Nothing Then Dim nbtr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord), acblkName As String = blkRef.Name, attCol As AttributeCollection = blkRef.AttributeCollection If attCol IsNot Nothing Then For Each attId As ObjectId In attCol Dim att As AttributeReference = CType(tr.GetObject(attId, OpenMode.ForWrite), AttributeReference), wksp As String = att.BlockName.ToString, hand As String = att.Handle.ToString, val As String = att.TextString, locX As String = att.Position.X.ToString, locY As String = att.Position.Y.ToString, locZ As String = att.Position.Z.ToString For i = 0 To strFind.Count - 1 If val.Contains(strFind(i)) = True Then att.TextString = val.Replace(strFind(i), strReplace(i)) att.RecordGraphicsModified(True) att.AdjustAlignment(db) log.Add(ldate & "," & att.TextString & "," & val & "," & "Attribute" & "," & dwgName & "," & wksp & "," & hand & "," & locX & "," & locY & "," & locZ) Dim wbd As Database = HostApplicationServices.WorkingDatabase HostApplicationServices.WorkingDatabase = db att.AdjustAlignment(db) End If Next Next End If End If End If
Error message:
Autodesk.AutoCAD.Runtime.Exception: eNullObjectId
at Autodesk.AutoCAD.DatabaseServices.TransactionManager.GetObjectInternal(AcDbTransactionManager* pTM, ObjectId id, OpenMode mode, Boolean openErased, Boolean forceOpenOnLockedLayer)
at Autodesk.AutoCAD.DatabaseServices.Transaction.GetObject(ObjectId id, OpenMode mode)
at Joshua.frmPermianBasinWellSiteFacilityGenerator.FindReplace(String ldate, String fn, List`1 strFind, List`1 strReplace) in E:\Joshua\16APR18\Joshua\frmPermianBasinWellSiteFacilityGenerator.vb:line 430
at Joshua.frmPermianBasinWellSiteFacilityGenerator.cmdGenerate_Click(Object sender, EventArgs e) in E:\Joshua\16APR18\Joshua\frmPermianBasinWellSiteFacilityGenerator.vb:line 231
at System.Windows.Forms.Control.OnClick(EventArgs e)
The error is not originating from the line you say it was:
acblkName As String = blkRef.Name, 'Error is here
The error is in a call to Transaction.GetObject() which is getting a null ObjectId.
I have no idea which call to GetObject() it is, because the line number in the exception message is relative to the start of the file.
Correctly identify the the line of code that is throwing the exception if you want more help.
The line that throws the error is listed below
Dim nbtr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord), ' This is the line that throws the error acblkName As String = blkRef.Name,
@WPercifulwrote:The line that throws the error is listed below
Dim nbtr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord), ' This is the line that throws the error acblkName As String = blkRef.Name,
After looking at your above code again, You are making it extremely difficult for others to help you.
You have numerous assignment statement in a single line of code, separated by commas. That's the first bad coding habit you have to get rid of, because the compiler doesn't identify individual statements, it only identifies a line number.
We are not going to guess which of the many assignment statements you have in a single line of code is the one that's throwing the exception.
Separate them into multiple lines of code, one assignment statement per line, and then tell us which of them it is.
To make sure I was following you, I rewrote that section to this:
Dim nbtr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord) Dim acblkName As String = blkRef.Name Dim attCol As AttributeCollection = blkRef.AttributeCollection
The line below throws the error:
Dim nbtr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
Just before the line of code that's throwing the exception, add this:
If blkRef.BlockTableRecord.IsNull Then ed.WriteMessage("\nBlockReference {0} has a null BlockTableRecord", blkRef.Handle.ToString()) EndIf
If you see this message displayed, enter this LISP and post what it returns:
Command: (entget (handent "<handle>"))
Where <handle> is the value displayed by the above call to WriteMessage().
I will be implementing your advice shortly, but first I've cleaned up all of my code per your comments. Then I rested and posted below. Thank you for your patience! This time the error was here:
If blkRef IsNot Nothing Then
Cleaned up code:
Public Function FindReplace(ldate As String, fn As String, strFind As List(Of String), strReplace As List(Of String)) ' Using docLock As DocumentLock = Core.Application.DocumentManager.MdiActiveDocument.LockDocument() Dim ed As Autodesk.AutoCAD.EditorInput.Editor = Core.Application.DocumentManager.MdiActiveDocument.Editor Dim db As Database = New Database(False, True) Dim dwgDir As String = IO.Path.GetDirectoryName(fn) Dim dwgName As String = IO.Path.GetFileName(fn) Dim dwgfullname As String = dwgDir & "\" & dwgName Dim Log As New List(Of String) Using db Try 'FileOpenMode.OpenForReadAndAllShare db.ReadDwgFile(fn, FileOpenMode.OpenForReadAndAllShare, False, Nothing) Catch __unusedException1__ As System.Exception ed.WriteMessage(vbLf & "Unable to read drawing file.") End Try Dim lg As New List(Of String())() Dim txtClass = RXObject.GetClass(GetType(DBText)) Dim mtxtClass = RXObject.GetClass(GetType(MText)) Dim blkrefClass = RXObject.GetClass(GetType(BlockReference)) Using tr = db.TransactionManager.StartTransaction Dim loDic As DBDictionary = CType(tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, False), DBDictionary) For Each entry As DBDictionaryEntry In loDic Dim layout = CType(tr.GetObject(entry.Value, OpenMode.ForRead), Layout) Dim btr As BlockTableRecord = CType(tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead), BlockTableRecord) For Each objID As ObjectId In btr If objID.ObjectClass.IsDerivedFrom(txtClass) Then Dim txt As DBText = CType(tr.GetObject(objID, OpenMode.ForWrite), DBText) Dim wksp As String = txt.BlockName.ToString Dim hand As String = txt.Handle.ToString Dim val As String = txt.TextString Dim locX As String = txt.Position.X.ToString Dim locY As String = txt.Position.Y.ToString Dim locZ As String = txt.Position.Z.ToString For i = 0 To strFind.Count - 1 If val.Contains(strFind(i)) Then txt.TextString = val.Replace(strFind(i), strReplace(i)) txt.RecordGraphicsModified(True) log.Add(ldate & "," & txt.TextString & "," & val & "," & "DBText" & "," & dwgName & "," & wksp & "," & hand & "," & locX & "," & locY & "," & locZ) ' Need this code in order to insure that the attributes alignment remains txt.AdjustAlignment(db) End If Next End If If objID.ObjectClass.IsDerivedFrom(mtxtClass) Then Dim mtxt As MText = CType(tr.GetObject(objID, OpenMode.ForWrite), MText) Dim wksp As String = mtxt.BlockName.ToString Dim hand As String = mtxt.Handle.ToString Dim Val As String = mtxt.Contents.ToString Dim locX As String = mtxt.Location.X.ToString Dim locY As String = mtxt.Location.Y.ToString Dim locZ As String = mtxt.Location.Z.ToString For i = 0 To strFind.Count - 1 If val.Contains(strFind(i)) = True Then mtxt.Contents = val.Replace(strFind(i), strReplace(i)) mtxt.RecordGraphicsModified(True) log.Add(ldate & "," & mtxt.Contents & "," & val & "," & "MText" & "," & dwgName & "," & wksp & "," & hand & "," & locX & "," & locY & "," & locZ) End If Next End If If objID.ObjectClass = blkrefClass Then Dim blkRef As BlockReference = CType(tr.GetObject(objID, OpenMode.ForRead), BlockReference) If blkRef IsNot Nothing Then Dim nbtr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord) Dim acblkName As String = blkRef.Name Dim attCol As AttributeCollection = blkRef.AttributeCollection If attCol IsNot Nothing Then For Each attId As ObjectId In attCol Dim att As AttributeReference = CType(tr.GetObject(attId, OpenMode.ForWrite), AttributeReference) Dim wksp As String = att.BlockName.ToString Dim hand As String = att.Handle.ToString Dim Val As String = att.TextString Dim locX As String = att.Position.X.ToString Dim locY As String = att.Position.Y.ToString Dim locZ As String = att.Position.Z.ToString For i = 0 To strFind.Count - 1 If val.Contains(strFind(i)) = True Then att.TextString = val.Replace(strFind(i), strReplace(i)) att.RecordGraphicsModified(True) att.AdjustAlignment(db) log.Add(ldate & "," & att.TextString & "," & val & "," & "Attribute" & "," & dwgName & "," & wksp & "," & hand & "," & locX & "," & locY & "," & locZ) Dim wbd As Database = HostApplicationServices.WorkingDatabase HostApplicationServices.WorkingDatabase = db att.AdjustAlignment(db) End If Next Next End If End If End If Next Next tr.Commit() End Using db.SaveAs(fn, DwgVersion.AC1027) 'db.SaveAs(fn, Autodesk.AutoCAD.DatabaseServices.DwgVersion.Current) End Using Return log ' End Using End Function
@WPercifulwrote:I will be implementing your advice shortly, but first I've cleaned up all of my code per your comments. Then I rested and posted below. Thank you for your patience! This time the error was here:
If blkRef IsNot Nothing Then
What is the error? An eNullObjectId exception can't happen on the above line.
This line of code:
Dim nbtr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
Results in this error:
Autodesk.AutoCAD.Runtime.Exception: eNullObjectId
at Autodesk.AutoCAD.DatabaseServices.TransactionManager.GetObjectInternal(AcDbTransactionManager* pTM, ObjectId id, OpenMode mode, Boolean openErased, Boolean forceOpenOnLockedLayer)
at Autodesk.AutoCAD.DatabaseServices.Transaction.GetObject(ObjectId id, OpenMode mode)
at Joshua.frmPermianBasinWellSiteFacilityGenerator.FindReplace(String ldate, String fn, List`1 strFind, List`1 strReplace) in E:\Joshua\16APR18\Joshua\frmPermianBasinWellSiteFacilityGenerator.vb:line 433
The function is processing a folder of drawings. When it crashed I attempts to paste in the lisp that you wrote in your one post. Replaced 'handle' with the value that was written down. The lisp returns nil, as it doesn't find a handent.
You didn't mention that you're processing drawings not open in the editor. If the file isn't open in the editor, the LISP will not work. You can write down the handle value displayed, and then open the file that was being processed when the error occurred in the editor and then use the LISP.
This may not be it, but you're changing the working database to the database you're processing and not changing it back to the current database afterwards:
Dim wbd As Database = HostApplicationServices.WorkingDatabase HostApplicationServices.WorkingDatabase = db att.AdjustAlignment(db) HostApplicationServices.WorkingDatabase = wdb
Try this code snippet that I cleaned up. I deleted everything that I thought was not directly related to your problem. If it does not cause more error, you can add other features that you find useful by testing them one by one.
Private Sub FindReplace(ByVal fn As String, ByVal strFind As List(Of String), ByVal strReplace As List(Of String)) Dim textClass = RXObject.GetClass(GetType(DBText)) Dim mtextClass = RXObject.GetClass(GetType(MText)) Dim brclass = RXObject.GetClass(GetType(BlockReference)) Dim workingDb = HostApplicationServices.WorkingDatabase Using db = New Database(False, True) db.ReadDwgFile(fn, FileOpenMode.OpenForReadAndAllShare, False, Nothing) HostApplicationServices.WorkingDatabase = db Using tr = db.TransactionManager.StartTransaction() Dim layoutDict = CType(tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead), DBDictionary) For Each entry As DBDictionaryEntry In layoutDict Dim layout = CType(tr.GetObject(entry.Value, OpenMode.ForRead), Layout) Dim btr = CType(tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead), BlockTableRecord) For Each id As ObjectId In btr Dim objClass = id.ObjectClass If objClass.IsDerivedFrom(textClass) Then Dim text = CType(tr.GetObject(id, OpenMode.ForRead), DBText) Dim value = text.TextString For i As Integer = 0 To strFind.Count - 1 If value.Contains(strFind(i)) Then If Not text.IsWriteEnabled Then tr.GetObject(id, OpenMode.ForWrite, False, True) text.TextString = value.Replace(strFind(i), strReplace(i)) End If Next ElseIf objClass.IsDerivedFrom(mtextClass) Then Dim mtext = CType(tr.GetObject(id, OpenMode.ForRead), MText) Dim value = mtext.Contents For i As Integer = 0 To strFind.Count - 1 If value.Contains(strFind(i)) Then If Not mtext.IsWriteEnabled Then tr.GetObject(id, OpenMode.ForWrite, False, True) mtext.Contents = value.Replace(strFind(i), strReplace(i)) End If Next ElseIf objClass = brclass Then Dim br = CType(tr.GetObject(id, OpenMode.ForRead), BlockReference) For Each attId As ObjectId In br.AttributeCollection Dim att = CType(tr.GetObject(attId, OpenMode.ForRead), AttributeReference) Dim value = att.TextString For i As Integer = 0 To strFind.Count - 1 If value.Contains(strFind(i)) Then If Not att.IsWriteEnabled Then tr.GetObject(attId, OpenMode.ForWrite, False, True) att.TextString = value.Replace(strFind(i), strReplace(i)) att.AdjustAlignment(db) End If Next Next End If Next Next tr.Commit() db.SaveAs(fn, DwgVersion.AC1027) End Using End Using
This morning I went back over it and realized you had given me the answer yesterday.
If blkRef.BlockTableRecord.IsNull Then ed.WriteMessage("\nBlockReference {0} has a null BlockTableRecord", blkRef.Handle.ToString()) Else ' Moved my code here EndIf
I also added this
HostApplicationServices.WorkingDatabase = wdb
Thank you for all of your help!
M,
Merci beaucoup! I will be working to streamline my code and write it cleaner. You've been very helpful.
That's fine, but skipping the opening of the BlockTableRecord doesn't really solve the problem if you actually need to open the BlockTableRecord (your code gets the block name but doesn't use it).
I'd still like to know why that's happening, as there shouldn't be a BlockReference with a null BlockTableRecord property, unless the DWG file is corrupt.
@WPercifulwrote:This morning I went back over it and realized you had given me the answer yesterday.
If blkRef.BlockTableRecord.IsNull Then ed.WriteMessage("\nBlockReference {0} has a null BlockTableRecord", blkRef.Handle.ToString()) Else ' Moved my code here EndIf
I also added this
HostApplicationServices.WorkingDatabase = wdbThank you for all of your help!
PLease forgive my ignorance, but not being an experienced LISP programmer, what was the final code that fixed the error. I'm getting the same error message "eNullObjectId" when I try to insert a pipe support in AutoCAD Plant 3D.
Regards,
Jesse
Can't find what you're looking for? Ask the community or share your knowledge.