views:

442

answers:

3

I am using anonymous methods to handle events in a COM object. Once the program terminates, it appears that the resources I am using in the anonymous method are not being "closed correctly" in that I get a first chance exception (InvalidComObjectException) for every resource I was watching. I suppose this isn't a big deal, but it doesn't feel "right."

I can't fathom a way to access those captured variables outside the scope of the anonymous methods (which you're not supposed to be able to do, anyway). How can I close/dispose of the resources prior to exiting the application?

EDIT: After a brief re-read, it may not be clear what I'm doing here. I am writing a managed application that consumes a COM object.

Further Edit: I am using ArcGIS Engine to manipulate GIS data. In this particular case, I am using the VisibilityChanged event in ILayerEvents_Event to monitor when a GIS layer is made visible or invisible. The event ONLY passes a bool (visible or not visible) and NOT the layer name, so a method would need to be created for EACH layer to create it's visibility state change. Since I'm dealing with dynamic layers, I needed a way to somehow do this dynamically, hence the anonymous methods.

Inside the anonymoua method, I have an ILayer variable which grabs the ILayerEvents_Event from an outer loop (in an ILayer context) so that I know which layer I'm working with. It's at this point that I'm stuck. The functionality works and everything is grand until I exit the application, leaving those 20+ references hanging there with no place to go but to an exception.

I have no idea when the user will hide/show a layer for the last time, so there's no way to null things out on the last go. I suppose I can just leave it as is (or, perhaps there's a better way to do this than the anonymous methods) since it doesn't seem to be hurting anything. I just think I'm missing something.

+1  A: 

You'd need to hook into the application exit event if you really wanted to. However, I think it would be nice to do better than that.

What are you using the anonymous method for? Can you work out when it's been used for the last time, and dispose the COM objects then? Can you make the anonymous methods acquire the COM objects and dispose them, all within the same block?

As you can see, the devil's in the details :)

Jon Skeet
I've added a bit more information in the question. Any help would be great.
Michael Todd
+2  A: 

Try to use unsafe mode in C#, create stuff on the heap and delete it when done. Another idea is to store a reference to the resources in variables that are outside of the anonymous method, and close them correctly at the programs termination. Then again, all you may need is a call to Dispose().

A little more info would be helpful. When is the exception being thrown? What do you mean by resources and "closed correctly."

I've added a bit more information above. Do you think that something like keeping a List<> of the referenced objects and then handling them when done would be in order?
Michael Todd
+1  A: 

It's not quite possible to know this from how you've described it, but maybe you have a COM object that is holding references to C# objects, due to methods on those objects being enlisted as event handlers for an event exposed on the COM object, and when the COM object is no longer in use, it gets finalized. Assuming the COM object is "apartment" based, this means that a message will be posted from the finalizer thread to the Windows message queue of the thread that created the COM object, requesting that Release should be called on the COM object. At that point, the COM object will likely call Release on the C# objects implementing any enlisted event handlers. This is all probably happening when the last of your application's managed code has finished running, and so the CLR is in the process of trying to unload itself. It may be that during shutdown, the CLR has to cope with any possible reference count leaks by allowing objects to be collected or put into an invalid state before their reference counts have dropped to zero. So this might (pure conjecture) explain what you are seeing.

If so, you need to shut down the COM object at a time of your own choosing. The solution is to call Marshal.ReleaseComObject in a loop until it returns zero, on the COM object, as part of the normal shutdown of the application.

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject(VS.71).aspx

Update, based on updated question:

Okay, so you have some COM objects referred to by the anonymous method closures. The only thing that will happen to those COM objects is that Release will be called on them. If that's causing a problem, it is most likely due to them already being in an invalid state.

So I'd recommend that when you make the set of anonymous method closures which hold references to the COM objects, you should also add those COM objects to a separate list. This will allow you to then call Marshal.ReleaseComObject on them when you're discarding this whole system.

Daniel Earwicker