Object Disposed Exception with Syntax Editor

SyntaxEditor for Windows Forms Forum

Posted 12 years ago by Michael Deskevich - Alion Science
Version: 4.0.0246
Avatar
I'm having a problem debugging some code that uses the SyntaxEditor. The issue is that after closing the MDI form that holds a SyntaxEditor control, I get a ObjectDisposedException.

Here's the exception:

System.ObjectDisposedException was unhandled
  Message="Cannot access a disposed object.\r\nObject name: 'CSharpEditor'."
  Source="System.Windows.Forms"
  ObjectName="CSharpEditor"
  StackTrace:
       at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
       at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
       at ActiproSoftware.SyntaxEditor.SyntaxEditor.k(Object A_0, EventArgs A_1)
       at ActiproSoftware.SyntaxEditor.Document.OnSemanticParseDataChanged(EventArgs e)
       at ActiproSoftware.SyntaxEditor.Document.a(ISemanticParseData A_0, TextRange A_1, Boolean A_2)
       at ActiproSoftware.SyntaxEditor.Document.ActiproSoftware.SyntaxEditor.ISemanticParseDataTarget.NotifySemanticParseComplete(SemanticParserServiceRequest request)
       at ActiproSoftware.SyntaxEditor.SemanticParserService.a(SemanticParserServiceRequest A_0)
       at ActiproSoftware.SyntaxEditor.SemanticParserService.c()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
The problem is that during the MDI window close, the code goes through and calls the Dispose() method on all of the controls. Later after the window is closed the above exception is thrown. I have verified that the code that closes the window is called, and the exception isn't thrown from that code. It appears to be thrown from a thread separate from my main code.

I have done a few things to narrow down the issue:

I commented out the call to Dispose() on my MDI form and the exception is no longer thrown.

I have tried to set the reference to the syntax editor to null after disposing so that I would get a null reference exception instead of the object disposed exception, but that didn't change anything, I still get the object disposed exception.

The stack trace leads me to believe that the OnSemanticParseDataChanged event handler is getting called on a non-existant SyntaxEditor control, however, I never turned on that event, nor do I know where I should turn that event handler off.

Or maybe I'm completely wrong what this error is. I am sure, however, that the offending code is being called from a thread that did not create nor have control over.

Any Ideas?

Mike

Comments (18)

Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Michael,

This may have been fixed in a later build than what you are running. Can you try the latest maintenance release to see if you still have the issue?


Actipro Software Support

Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
Do you _really_ think this has been fixed, or is this the standard reply for people not using the latest version? The reason I ask, is that it's a non trivial change where I am to change the libraries we build against, so I'd rather not start that process unless I have a good shot at it solving my problem.
Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
I know there has been more disposal work done since your build but now that I'm looking at the build 246 code, it did have the particular item I was thinking of already. Namely, this code (which is called in your stack):
void ISemanticParseDataTarget.NotifySemanticParseComplete(SemanticParserServiceRequest request) {
    // Quit if disposed
    if (this.IsDisposed)
        return;

... More code
}
So since you are executing that code, it would seem that in your scenario, the Document is not yet disposed but the SyntaxEditor is. Because if the Document was disposed, the IsDisposed check above would fail and you would never get into the exception scenario.

Is it possible for you to check to see if this is in fact the case by debugging and seeing if the Document has been disposed or not?


Actipro Software Support

Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
Ok, I got the newest version of the SyntaxEditor installed and I still get the same problem.

I'm not quite sure I know what you mean by checking to see if the Document is disposed? Unfortunately, I'm trying to fix code I didn't write, so I don't know all the details. Here's what I have figured out though:

When the CloseWindow event for one of the MDI forms is received, it starts by disposing all of the components on the form. I have traced through the code and it successfully exits from the CloseWindow event handler so I know that everything in the MDI form has been disposed and there were no exceptions thrown during the disposal.

Then at a later time after everything has been disposed, I get the exception from a different thread. And according to the debugger all of the code for the stack trace is "external code" so I cannot debug it.

I have explicitly commented out the disposal of the SyntaxEditor and the problem goes away, and maybe that's a good enough solution, but I really don't know since I don't know what the original programmers were thinking when they put the manual disposal in there rather than just waiting for the GC to clean everything up.
Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
I meant to check to see what the value of editor.Document.IsDisposed is at the time the exception occurs. My guess is that the SyntaxEditor disposed but the Document is not. That's what I'd like for you to check out and post back.


Actipro Software Support

Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
I put a breakpoint in the Dispose function for my Syntax Editor and I do see that this.Document.IsDisposed is false.

However, I do not have access to the object at the exact time of the exception as it's thrown from a different thread and I cannot investigate the value of IsDisposed at that time.

Here's a rough outline of what the code looks like

In the MDI Form:

OnCloseWindow()
{
//do some cleanup

Panel.Dispose()

//do some other cleanup
}

then in the Panel's Class

Dispose(bool disposing)
{
base.Dispose(disposing)
}

It continues in this down through the class hierarchy until one of the panels disposes the SyntaxEditor that it contains.

The key is that the OnCloseWindow function returns with no execeptions. Everything is disposed just fine and then later from a different thread, I get the exception.
Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
As a temporary workaround can you insert a line at whatever level the SyntaxEditor is disposed that calls this BEFORE the SyntaxEditor is disposed:
editor.Document.Dispose();
Please reply with whether that prevents the exception.


Actipro Software Support

Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
Nope, that didn't fix it.

I had the guy who owns that part of the code add a

void Dispose()
{
if (Document!=null)
{
Document.Dispose()
}
base.Dispose()
}

in our child class of SyntaxEditor.
Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
One more bit of info:

The Document.IsDisposed value does change from false to true after the call to Document.Dispose, so we know that that code is getting called correctly.

Mike
Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hmm, that doesn't make sense. If it is in fact true then I don't see how it could get to that same stack trace since there is that IsDisposed check in the code I posted in a previous message. Are you sure that you get the same stack trace once you've added this code?

Also is it possible for your to build a tiny app that can repro this and send it over so we can debug it here?


Actipro Software Support

Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
I haven't been able to make something small that reproduces this. I just got word that .257 was out today and I just tried it and I still get the same error. Here's the stack trace with all the latest code:
System.ObjectDisposedException was unhandled
  Message="Cannot access a disposed object.\r\nObject name: 'CSharpEditor'."
  Source="System.Windows.Forms"
  ObjectName="CSharpEditor"
  StackTrace:
       at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
       at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
       at ActiproSoftware.SyntaxEditor.SyntaxEditor.k(Object A_0, EventArgs A_1)
       at ActiproSoftware.SyntaxEditor.Document.OnSemanticParseDataChanged(EventArgs e)
       at ActiproSoftware.SyntaxEditor.Document.a(ISemanticParseData A_0, TextRange A_1, Boolean A_2, Object A_3)
       at ActiproSoftware.SyntaxEditor.Document.ActiproSoftware.SyntaxEditor.ISemanticParseDataTarget.NotifySemanticParseComplete(SemanticParserServiceRequest request)
       at ActiproSoftware.SyntaxEditor.SemanticParserService.a(SemanticParserServiceRequest A_0)
       at ActiproSoftware.SyntaxEditor.SemanticParserService.c()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Another customer is running into the same thing. After working with him I believe that what is happening is that the invoke call DOES take place (meaning it got past the IsDisposed checks added in build 257) however somewhere while executing the invoked code, the SyntaxEditor disposes from the main thread and that exception just gets reported back to the invoke calling code.

Before the dispose, try calling SemanticParserService.Stop(). That should kill the worker thread, thereby preventing the multi-threading and the possibility of this happening.


Actipro Software Support

Posted 12 years ago by Jake Pearson - Software Developer, Alion Science and Technology
Avatar
Hi,
I'm helping Mike with this problem. In our case, we have lots of SyntaxEditors so I thought I wasn't supposed to stop the SemanticParserService until the application is completed. Am I misunderstanding?

thanks,
Jake
Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Correct if you are using more than that one SyntaxEditor that option may not be good. Here are some things we're dicussing with another customer on a similar issue:

1) Perhaps we need something new such as a SemanticParserService.Cancel that stops the thread only if it is parsing the Document being disposed and
then restarts the thread for the next parse op. But then it also would go through the pending parse operations and remove any for that Document as
well. Maybe we could even build a call to this into the Document.Dispose code.

2) Put try catches around the parse execution code so that if an ObjectDisposedException occurs, it is caught and not bubbled up. Since the object is disposed, we should be able to safely eat the message since we no longer care about that Document.

I'd love to hear your comments on possible implementation of these ideas.


Actipro Software Support

Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
Generally, I prefer the second option. If it's an exception that I shouldn't have to care about, then I shouldn't see it or have to add extra code to avoid it.
Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
Any more updates to this issue?
Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Yes we're hoping to deploy a new maintenance release later today or tomorrow that has code changes related to this.


Actipro Software Support

Posted 12 years ago by Michael Deskevich - Alion Science
Avatar
FYI - It looks like that fixed the problem I was having. Thanks!
The latest build of this product (v2018.1 build 0342) was released 11 days ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.