solving com threading issues in a net durable topic consumer

Thu, Jun 17, 2010

I’ve recently been adding Groupwise functionality to GADfly which means using COM as that’s the only way to access the Groupwise Admin API, via the Groupwise client. I’ll go over how to do that in a later post but once I’d plumbed the COM functionality into GADfly via my MatrixClient for C#, I started to get a weird error. The basic setup is I register a message handler to deal with GW messages with MatrixClient and when a message arrives on a JMS topic, my durable subscriber gets the message, parses out the info and create a Groupwise account from it. However, the event handler was causing the GW class to barf in a big way:

Unable to cast COM object of type ‘AdminTypeLibrary.SystemClass’ to interface type ‘AdminTypeLibrary.DIADSystem’.
This operation failed because the QueryInterface call on the COM component for the interface with
IID ‘{35FC2357-811A-11D0-8A96-00805FC16077}’ failed due to the following error:
No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))
That’s a telltale sign of a threading problem which is easily solved by using:
[STAThread]
before the Main method. In this case the only main method is in the Program.cs that starts the test and putting it there caused a system lockup. No matter where I put it, I always got that COM interface error. The problem stems from the way MatrixClient works. It’s basically a wrapper I wrote for the Apache NMS library and the event handler is called on different threads, which causes mayhem in the Runtime Callable Wrapper (RCW) that .NET provides as an easy to use abstraction layer on top of the Groupwise COM DLL.

The solution? Spawn a new thread with its apartment set to STA:

GW gwHandler = new GW(); // Does all the COM stuff for creating/deleting GW accounts
Thread gwThread = new Thread(gwHandler);
gwThread.SetApartmentState(ApartmentState.STA);
gwThread.Start();
I needed to do this as the Groupwise COM server uses the Single Threaded Apartment (STA) model. Spawning a new thread means I can take a step back from the deep threading in NMS and regain control of the COM levers.

comments powered by Disqus