eWasOpenForRead Error When BlockTableRecord.ModelSpace Is Opened For Write
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
After implementing a system for caching the state of all dynamic blocks managed by an existing plugin in order to avoid unessesary reading/writing to dynamic block properties, an issue which never occured before appeared. The changes described have the effect of dramatically reducing reads/writes to dynamic block properties. Some intensive operations in the plugin run much faster because of these optimizations, and much less memory is utilized by acad.exe (setting dynamic block properties to the same value as is current causes memory consumption). This is a related post which has caused me to make the described optimizations (along with a desire for faster performance): http://forums.autodesk.com/t5/net/net-plugin-causes-high-memory-consumption-leak-not-in-managed/td-p...
The issue appears randomly, though the more times certain operations are performed, the more likely the issue is to occur. After the issue occurs, any attempt to open the BlockTableRecord for ModelSpace for write results in an exception with the message eWasOpenForRead, making it impossible to insert new block instances in the drawing, at least using my code.
I'm wondering if any of you have advice about how to force the read lock on this record to close programatically. Or if you have advice on how to enumerate the locks on this BlockTableRecord to help me debug? Or a description of what might cause this situation to occur? It seems a transaction may not be properly Committed/Aborted or otherwise disposed of. Though all of my code involving drawing database transactions is wrapped in using blocks and either commit or abort is always called. There should be no open drawing database transactions when this function is called since I only have this one plugin loaded and all transactions are performed on the main thread.
Here is the code for the function where the error occurs (it is responsible for inserting a block instance into the drawing and a few related activities like setting the layer the block instance resides on):
Public Shared Function InsertBlock(ByVal DatabaseIn As Database, ByVal BTRToAddTo As String, ByVal InsPt As Geometry.Point3d, ByVal BlockName As String, ByVal XScale As Double, ByVal YScale As Double, ByVal ZScale As Double, ByVal LayerName As String, ByVal TransformBy As Matrix3d, Optional ByVal Rotation As Double = 0) As DatabaseServices.ObjectId
If String.IsNullOrEmpty(LayerName) Then Throw New ArgumentNullException("LayerName")
If Not LayerHelper.LayerExists(DatabaseIn, LayerName) Then
Dim layerManager As ACADLayerCache = ACADLayerCacheSingleton.Instance()
Dim layerColor As System.Drawing.Color? = layerManager.GetLayerColor(LayerName)
If layerColor IsNot Nothing Then
LayerHelper.AddLayer(DatabaseIn, LayerName, Autodesk.AutoCAD.Colors.Color.FromColor(layerColor.Value))
Else
LayerHelper.AddLayer(DatabaseIn, LayerName, Autodesk.AutoCAD.Colors.Color.FromColor(Drawing.Color.White))
End If
End If
Dim id As ObjectId = Nothing
Dim doc As Document = ApplicationServices.Application.DocumentManager.MdiActiveDocument
Using lock As DocumentLock = doc.LockDocument()
Using trans As Transaction = DatabaseIn.TransactionManager.StartOpenCloseTransaction()
Try
Using myBlockTable As BlockTable = trans.GetObject(DatabaseIn.BlockTableId, OpenMode.ForRead)
If myBlockTable.Has(BlockName) = False Then
Return Nothing
End If
'If the specified BlockTableRecord does not exist, return
If myBlockTable.Has(BTRToAddTo) = False Then
Return Nothing
End If
Using myBlockDef As BlockTableRecord = trans.GetObject(myBlockTable(BlockName), OpenMode.ForRead)
Using myBlockTableRecord As BlockTableRecord = trans.GetObject(myBlockTable(BTRToAddTo), OpenMode.ForWrite)
'Create a new BlockReference
Using myBlockRef As New BlockReference(InsPt, myBlockDef.Id)
'Set the scale factors
myBlockRef.ScaleFactors = New Geometry.Scale3d(XScale, YScale, ZScale)
'Add the new BlockReference to the specified BlockTableRecord
myBlockRef.Rotation = Rotation
myBlockRef.TransformBy(TransformBy)
myBlockTableRecord.AppendEntity(myBlockRef)
'Add the BlockReference to the BlockTableRecord.
trans.AddNewlyCreatedDBObject(myBlockRef, True)
Using blockEnt As Entity = trans.GetObject(myBlockRef.Id, OpenMode.ForWrite)
Try
blockEnt.Layer = LayerName
Catch ex As System.Exception
End Try
Dim myAttColl As DatabaseServices.AttributeCollection = myBlockRef.AttributeCollection
'Find Attributes and add them to the AttributeCollection
'of the BlockReference
For Each myEntID As ObjectId In myBlockDef
Using myEnt As Entity = trans.GetObject(myEntID, OpenMode.ForWrite)
'myEnt.Layer = LayerName
If TypeOf myEnt Is DatabaseServices.AttributeDefinition Then
Dim myAttDef As DatabaseServices.AttributeDefinition = myEnt
Using myAttRef As New DatabaseServices.AttributeReference
myAttRef.SetAttributeFromBlock(myAttDef, myBlockRef.BlockTransform)
myAttColl.AppendAttribute(myAttRef)
trans.AddNewlyCreatedDBObject(myAttRef, True)
End Using
End If
End Using
Next
trans.Commit()
id = myBlockRef.Id
End Using
End Using
End Using
End Using
End Using
Catch ex As System.Exception
trans.Abort()
Try
EventLog.WriteEntry("NiC", "DynamicBlockHelper.InsertBlock - " + ex.GetType().Name + ": " + ex.Message + Environment.NewLine + ex.StackTrace, EventLogEntryType.Error)
Catch eex As System.Exception
End Try
End Try
End Using
End Using
Return id
End Function
I highlighted the line of code where the exception occurs in red. Note that I handle the exception by checking the validity of the ObjectID returned by the function.
If no one has suggestions on how to track down the source of this problem or how to force the BlockTableRecord to close, I will put together a working example plugin which can be used to reproduce the error. Posting more of the plugin code here just isn't practical because of how much of it there is. I realize I'm not giving you much to go on at this point. I just hoping someone can provide some advice.
Or maybe I will find a solution on my own, in which case I'll post it here.
Thanks,
Kevin