Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Release "ownership" of COM object in .NET

Tags:

c#

vb.net

com

I have a customer/partner who's trying to link their application with ours using our exposed COM functionality. So far, they've got a COM object which represents an instance of our software package and then use our COM methods to programmatically build something up for the user based on what they've done in their application. It's essentially an "export" feature.

What they've asked me to do, which I can't work out how to do is to allow the user to decide when the instance is closed. What I mean by this is when our software package is loaded up, it's viewable and is interacted with by the user. When they are finished they'd naturally click the cross at the top right to exit the software. This doesn't work as the COM object is still "active" in their application. Our software package can only be closed by killing the process in task manager whilst the application that loaded it via COM remains open. Once their application exits, ours will automatically close. It seems as if their application "owns" ours because of the COM call.

I've made a quick demo app in C# to try using things like Marshal.FinalReleaseComObject(myObject) to no avail.

I realise that using COM for this kind of thing isn't really what it is intended for, but hopefully there's some sort of workaround? The customer/partner is using VB.NET but C# is fine.

like image 914
sxthomson Avatar asked May 02 '12 16:05

sxthomson


1 Answers

You've left out some critical information about your own application, including most importantly how you are implementing the COM interfaces that you expose to the client application. One aspect of your description that is a red flag for me is the instantiation of your application. You say that the client application is, "using VB to start a new process by referencing our exe." This shouldn't be necessary if you've properly implemented and registered your COM server. Let me tell you the architecture I would use to accomplish what you ask, and hopefully this will be useful to you.

To begin with, if you want to provide a COM object from within a separate process, the proper way is to implement a COM out of process server. With an out of process server, COM will start your application automatically when a client requests one of your interfaces through COM. Part of the implementation requirements of an out of process server is to shut down automatically when the last COM client releases their last interface pointer.

In order to expose a user interface from the out of process server, you'll want to spawn a separate Single-threaded Apartment (STA) thread with a message loop. This will allow you to close any window on the STA thread, including the main window, without killing your COM server. That's because the COM server implementation will be running it's own Multi-threaded Apartment (MTA) message loop thread to support the COM out of proc calls. The MTA thread is the main application thread, and the server will shut down it down when the last client interface is released.

A COM server should not shut down while interfaces remain unreleased. This means the client application has a responsibility to release interfaces properly. But your .NET test frame should have done this, so it appears something is not right with your implementation.

Assuming you follow this guidance, you will need a plan for handling the scenario in which the last client interface is release but you still have open UI windows. Once you get everything set up correctly, this shouldn't be a major problem. For example, you can simply take a reference to one of your own interfaces while the UI is open, this would prevent an MTA shutdown.

like image 141
Paul Keister Avatar answered Oct 09 '22 03:10

Paul Keister