.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem With Events And Closing

22 REPLIES 22
Reply
Message 1 of 23
Anonymous
1207 Views, 22 Replies

Problem With Events And Closing

Hi all,

I'm getting a seemingly random crash, and I can't pin point what the problem is exactly. When I remove the code which is listening for events on the current document, document manager, and database, things seem to be alright.

The crash typically happens after I close documents, but not right away.

When the crash is occuring, I can pause execuion in VS, and it will show that there's a thread executing the finalizers (probably from the garbage collection), and also pulls up the stack trace below.

I'm posting the code with the related event handlers, and objects at the end of the post.

When the crash occurs, and I look at the dmpuserinfo.xml file, the stack section shows the following:

Clr Data:
at Autodesk.AutoCAD.Runtime.RXObject.DeleteUnmanagedObject()
at Autodesk.AutoCAD.Runtime.DisposableWrapper.Dispose(Boolean disposing)
at Autodesk.AutoCAD.Runtime.DisposableWrapper.Finalize()

Here's the code. Note that the editer removes my XML brackets on the method descriptions, so they just appear as comments.

Any help is greatly appreciated!

'''
''' Controls the RebarControllers for all open drawings.
'''

'''
Public Class RebarApplication
Implements INotifyPropertyChanged
Implements IDisposable

Private WithEvents cDocumentManager As DocumentCollection = Nothing
'''
''' Gets or sets the DocumentCollection of the owning AutoCAD application.
''' This allows the RebarApplication to moniter changes and update bars as needed.
'''

'''
'''
'''
Public Property DocumentManager() As DocumentCollection
Get
Return cDocumentManager
End Get
Set(ByVal value As DocumentCollection)
cDocumentManager = value

'Set the active document.
If value IsNot Nothing Then
'Set the active document to the current document.
CurrentDocument = value.GetDocument(HostApplicationServices.WorkingDatabase)
'Make sure theres a rebar list controller for the current document.
MountDatabase()
End If

NotifyChanged("DocumentManager")
End Set
End Property

'''
''' Ensures that a rebar list is active for the current database of the current document.
'''

'''
Protected Sub MountDatabase()
If GetCurrentDocument() Is Nothing Then Return

'Check if there's a controller for the database of the drawing.
Dim Lst As RebarListController = Me.GetControllerFor(GetCurrentDocument)

If Lst Is Nothing Then
'Try to load the controller for the document.
Dim Cnt As RebarListController = RebarListController.LoadForDatabase_Ver_1_0(HostApplicationServices.WorkingDatabase)

If Cnt IsNot Nothing Then
'If there's a controller for the drawing, then add it to the controllers list.
Controllers.Add(Cnt)
End If
End If
End Sub

Private WithEvents cCurrentDocument As Document = Nothing
'''
''' Gets or sets the current active document in AutoCAD. This helps moniter
''' changes to items of interest, and update events on bars when changes occur.
'''

'''
'''
'''
Public Property CurrentDocument() As Document
Get
Return cCurrentDocument
End Get
Set(ByVal value As Document)
cCurrentDocument = value

If value IsNot Nothing Then
'Set the current database to the database of the document.
CurrentDB = value.Database
Else
'Set the current database to null.
CurrentDB = Nothing
End If

'Alert any listening objects that the properties associated with the current document has been changed.
NotifyChanged("CurrentDocument")
NotifyChanged("CurrentController")
NotifyChanged("CurrentRebarList")
NotifyChanged("CurrentRebarListNo")
End Set
End Property

Protected WithEvents cCurrentDB As Database = Nothing
'''
''' Gets or sets the current database being monitered for changes.
'''

'''
Protected Property CurrentDB() As Database
Get
Return cCurrentDB
End Get
Set(ByVal value As Database)
cCurrentDB = value

NotifyChanged("CurrentDB")
End Set
End Property


'''
''' Ensures that a rebar list is active for the current database of the current document.
'''

'''
Protected Sub MountDatabase()
If GetCurrentDocument() Is Nothing Then Return

'Check if there's a controller for the database of the drawing.
Dim Lst As RebarListController = Me.GetControllerFor(GetCurrentDocument)

If Lst Is Nothing Then
'Try to load the controller for the document.
Dim Cnt As RebarListController = RebarListController.LoadForDatabase_Ver_1_0(HostApplicationServices.WorkingDatabase)

If Cnt IsNot Nothing Then
'If there's a controller for the drawing, then add it to the controllers list.
Controllers.Add(Cnt)
End If
End If
End Sub

Private Sub cDocumentManager_DocumentToBeDestroyed(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs) Handles cDocumentManager.DocumentToBeDestroyed
'Exit if there is no current document.
If e.Document Is Nothing Then Return

If e.Document.Database Is Nothing Then Return
If e.Document.Database.Filename = "" Then Return

'Remove the rebar list related to the document, if one exists.
Dim RLst As RebarListController = GetControllerFor(e.Document)
If RLst IsNot Nothing Then
'Remove it from the list.
RemoveControler(RLst)

'Dispose of the rebar list controller.
RLst.Dispose()
End If

'Set the current document to null if it is the one being destroyed.
If e.Document Is Me.CurrentDocument Then Me.CurrentDocument = Nothing
End Sub

Private Sub cDocumentManager_DocumentActivated(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs) Handles cDocumentManager.DocumentActivated
'Check if there's a controller for the database of the drawing.
Dim Lst As RebarListController = Me.GetControllerFor(e.Document)

If Lst Is Nothing Then
'Try to load the controller for the document.
Dim Cnt As RebarListController = RebarListController.LoadForDatabase_Ver_1_0(e.Document.Database)

If Cnt IsNot Nothing Then
'If there's a controller for the drawing, then add it to the controllers list.
Controllers.Add(Cnt)
End If
End If

'Set the new CurrentDocument.
CurrentDocument = DocumentManager.GetDocument(HostApplicationServices.WorkingDatabase)
End Sub

'''
''' Loads the rebar list for the current drawing.
'''

'''
'''
Public Sub LoadForCurrentDrawing_Ver_1_0()
'Remove the current rebar list.
If Controllers.Contains(CurrentController) Then _
Me.Controllers.Remove(CurrentController)

'Get the list from the drawing.
Dim Lst As RebarListController = RebarListController.LoadFromDictionary_Ver_1_0
'Add the controller to the set of controllers.
Me.Controllers.Add(Lst)
'Set the database for the current controller.
Lst.OwningDatabase = HostApplicationServices.WorkingDatabase
'Set the current list at 1.
CurrentDatabaseNo = 1
End Sub

'''
''' Saves the rebar list for the current drawing.
'''

'''
Public Sub SaveForCurrentDrawing_Ver_1_0()
CurrentRebarList.SaveToDictionary_Ver_1_0()
End Sub

End Class
22 REPLIES 22
Message 21 of 23
Anonymous
in reply to: Anonymous

btw... I just checked to see how the {code} tags worked in the web browser
as I'm using a news reader. I have
ony four posts on this in the news reader and notice there are a bunch in
the web browser. So if my point/question
was covered Sorry!

"Paul Richardson" wrote in message
news:6224873@discussion.autodesk.com...
The only difference in the following code in IL form is show below the code.
A few extra lines in finally block
and the 'callvirt' call in the finally block. Anyone know why the
difference? I've never had a problem with 'using'.

{code}
public class UsingVTryFinally
{
//class scope to make the IL cleaner to read.
private static readonly Document doc =
Application.DocumentManager.MdiActiveDocument;

private static Editor ed = doc.Editor;

private static void UsingTest()
{

PromptEntityResult per = ed.GetEntity("Select an entity: ");

using (Transaction tr =
doc.Database.TransactionManager.StartTransaction())
{
Entity bt =
(Entity)tr.GetObject
(doc.Database.BlockTableId, OpenMode.ForRead);

}
}

private static void TryTest()
{

PromptEntityResult per = ed.GetEntity("Select an entity: ");

Transaction tr =
doc.Database.TransactionManager.StartTransaction();

try
{
Entity bt =
(Entity)tr.GetObject
(doc.Database.BlockTableId, OpenMode.ForRead);
}
finally
{
tr.Dispose();
}
}
}
{code}

//using statement IL finally block
{code}
finally
{
IL_0043: ldloc.0
IL_0044: brfalse.s IL_004c
IL_0046: ldloc.0
IL_0047: callvirt instance void
[mscorlib]System.IDisposable::Dispose()
IL_004c: endfinally
} // end handler
{code}

//try finally finally block
{code}
finally
{
IL_0043: ldloc.0
IL_0044: callvirt instance void
[acdbmgd]Autodesk.AutoCAD.Runtime.DisposableWrapper::Dispose()
IL_0049: endfinally
} // end handler
{code}

wrote in message news:6224768@discussion.autodesk.com...
chandru.pachai said:

"And also remember that do not use using {} block when you open some object
using transaction.getObject() method, that will also cause you problem."

?!
What problem it could cause? Is that why sample codes from Autodesk use
Try...Catch...Finally transaction.Dispose() End Try? Is this some kind of
insider (or from insider) news?
Message 22 of 23
Anonymous
in reply to: Anonymous

It's probably because using() checks the using variable to ensure it is not
null before it calls Dispose() on it.

IOW, using is functionally equivalent to this:

{code}

IDisposable disposable = ...
try
{
// use disposable here
}
finally
{
if( disposable != null )
disposable.Dispose();
}

{code}

You can leverage that to have an object disposed of by using() conditionally
by just assigning the using variable to null.

{code}

using( IDisposable disposable = ... )
{
if( condition )
disposable = null; // supress call to Dispose()
}

{code}

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009

http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm

Email: string.Format("{0}@{1}.com", "tonyt", "caddzone");


"Paul Richardson" wrote in message
news:6224873@discussion.autodesk.com...
The only difference in the following code in IL form is show below the code.
A few extra lines in finally block
and the 'callvirt' call in the finally block. Anyone know why the
difference? I've never had a problem with 'using'.

{code}
public class UsingVTryFinally
{
//class scope to make the IL cleaner to read.
private static readonly Document doc =
Application.DocumentManager.MdiActiveDocument;

private static Editor ed = doc.Editor;

private static void UsingTest()
{

PromptEntityResult per = ed.GetEntity("Select an entity: ");

using (Transaction tr =
doc.Database.TransactionManager.StartTransaction())
{
Entity bt =
(Entity)tr.GetObject
(doc.Database.BlockTableId, OpenMode.ForRead);

}
}

private static void TryTest()
{

PromptEntityResult per = ed.GetEntity("Select an entity: ");

Transaction tr =
doc.Database.TransactionManager.StartTransaction();

try
{
Entity bt =
(Entity)tr.GetObject
(doc.Database.BlockTableId, OpenMode.ForRead);
}
finally
{
tr.Dispose();
}
}
}
{code}

//using statement IL finally block
{code}
finally
{
IL_0043: ldloc.0
IL_0044: brfalse.s IL_004c
IL_0046: ldloc.0
IL_0047: callvirt instance void
[mscorlib]System.IDisposable::Dispose()
IL_004c: endfinally
} // end handler
{code}

//try finally finally block
{code}
finally
{
IL_0043: ldloc.0
IL_0044: callvirt instance void
[acdbmgd]Autodesk.AutoCAD.Runtime.DisposableWrapper::Dispose()
IL_0049: endfinally
} // end handler
{code}

wrote in message news:6224768@discussion.autodesk.com...
chandru.pachai said:

"And also remember that do not use using {} block when you open some object
using transaction.getObject() method, that will also cause you problem."

?!
What problem it could cause? Is that why sample codes from Autodesk use
Try...Catch...Finally transaction.Dispose() End Try? Is this some kind of
insider (or from insider) news?
Message 23 of 23
Anonymous
in reply to: Anonymous

Thank you Sir!
"Tony Tanzillo" wrote in message
news:6224931@discussion.autodesk.com...
It's probably because using() checks the using variable to ensure it is not
null before it calls Dispose() on it.

IOW, using is functionally equivalent to this:

{code}

IDisposable disposable = ...
try
{
// use disposable here
}
finally
{
if( disposable != null )
disposable.Dispose();
}

{code}

You can leverage that to have an object disposed of by using() conditionally
by just assigning the using variable to null.

{code}

using( IDisposable disposable = ... )
{
if( condition )
disposable = null; // supress call to Dispose()
}

{code}

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009

http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm

Email: string.Format("{0}@{1}.com", "tonyt", "caddzone");


"Paul Richardson" wrote in message
news:6224873@discussion.autodesk.com...
The only difference in the following code in IL form is show below the code.
A few extra lines in finally block
and the 'callvirt' call in the finally block. Anyone know why the
difference? I've never had a problem with 'using'.

{code}
public class UsingVTryFinally
{
//class scope to make the IL cleaner to read.
private static readonly Document doc =
Application.DocumentManager.MdiActiveDocument;

private static Editor ed = doc.Editor;

private static void UsingTest()
{

PromptEntityResult per = ed.GetEntity("Select an entity: ");

using (Transaction tr =
doc.Database.TransactionManager.StartTransaction())
{
Entity bt =
(Entity)tr.GetObject
(doc.Database.BlockTableId, OpenMode.ForRead);

}
}

private static void TryTest()
{

PromptEntityResult per = ed.GetEntity("Select an entity: ");

Transaction tr =
doc.Database.TransactionManager.StartTransaction();

try
{
Entity bt =
(Entity)tr.GetObject
(doc.Database.BlockTableId, OpenMode.ForRead);
}
finally
{
tr.Dispose();
}
}
}
{code}

//using statement IL finally block
{code}
finally
{
IL_0043: ldloc.0
IL_0044: brfalse.s IL_004c
IL_0046: ldloc.0
IL_0047: callvirt instance void
[mscorlib]System.IDisposable::Dispose()
IL_004c: endfinally
} // end handler
{code}

//try finally finally block
{code}
finally
{
IL_0043: ldloc.0
IL_0044: callvirt instance void
[acdbmgd]Autodesk.AutoCAD.Runtime.DisposableWrapper::Dispose()
IL_0049: endfinally
} // end handler
{code}

wrote in message news:6224768@discussion.autodesk.com...
chandru.pachai said:

"And also remember that do not use using {} block when you open some object
using transaction.getObject() method, that will also cause you problem."

?!
What problem it could cause? Is that why sample codes from Autodesk use
Try...Catch...Finally transaction.Dispose() End Try? Is this some kind of
insider (or from insider) news?

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost