Reputation: 10074
I'm having trouble with my COM component written in .NET throwing warnings that look like:
Context 0x15eec0 is disconnected. No proxy will be used to service the request on the COM component. This may cause corruption or data loss. To avoid this problem, please ensure that all contexts/apartments stay alive until the application is completely done with the RuntimeCallableWrappers that represent COM components that live inside them.
It looks like this is caused by my GUI thread calling functions in the COM thread without necessary syncronization. For reference I'm using the guidelines set in http://msdn.microsoft.com/en-us/library/ms229609%28VS.80%29.aspx for creating my GUI thread in the COM component.
My code looks something like:
class COMClass {
// this is called before SomeMethod
public void Init() {
ComObject comObject = new ComObject(); // this is imported from a TLB
// I create my GUI thread and start it as in the MSDN sample
Thread newThread = new Thread(new ThreadStart(delegate() {
Application.Run(new GUIForm(comObject));
}));
}
public void SomeMethod(){
comObject.DoSomething(); // this is where the error occurs
}
}
class GUIForm : Form {
ComObject com;
public GUIForm(ComObject com) {comObject = com;}
public void SomeButtonHandler(object sender, EventArgs e) {
comObject.SomeMethod(); // call on the GUI thread but the com object is bound to the COM thread...
}
}
Is there an established method for dealing with this? Calls to the GUI are no problem (Invoke/BeginInvoke) but calling the other way seems to be more difficult...
edit: It is also not an option to modify the COM object in any way.
Upvotes: 3
Views: 2644
Reputation: 10074
I found the problem, it wasn't the cross-thread operation persay. In my GUIForm I created a subwindow and used SetParent() to parent it to the COM server's app window. This seems to have caused the issues with the COM proxy being disconnected (although a more experience COM expert might have to enlighten me as to why it behaved like this).
Instead of parenting my control to the window I'm going to fully disconnect it and just hook WM_WINDOWPOSCHANGING to move my control with the main App window.
Upvotes: 1
Reputation: 942438
It isn't very clear from your snippet how the all-important Init() method is called and how the thread got started. Clearly, the thread on which the COM object is created is not the same thread as the one where the SomeMethod() call is made. Further assuming that the COM server is apartment threaded, COM needs to marshal the SomeMethod() call to the thread that created the object. The one that called Init(). If that thread is no longer running, hilarity ensues.
There's one glaring problem, you forgot to call Thread.SetApartmentState().
Given that COM already marshals inter-thread calls, you are probably not gaining anything by starting your own thread. You can't magically make a COM server multi-threaded if it refuses to support it.
Upvotes: 2
Reputation: 14697
Since the COM object was created on the other thread, all calls to the COM object should be made from that thread. After launching the GUI thread, you'll need to have some kind of queueing mechanism set up to wait for calls to execute methods (probably a queue of delegates). Your GUI code can push a delegate into the queue and it will be executed (on the original thread) when the original thread processes the queue. See: http://www.yoda.arachsys.com/csharp/threads/deadlocks.shtml (producer/consumer example about mid-way down the page).
Upvotes: 0