I'm working in a large multithreaded C# application handling bunches of COM interop. The other developers and I have ample opportunity to accidentally call Single-Threaded Apartment (STA) COM objects from MTA threads, and from STA threads they weren't created on. Performance is sluggish, and cross-thread marshalling is a prime suspect.
Is there a good method to test for cross-apartment marshaling? Even better, is there a defensive programming technique to test that a given COM object belongs to this thread's apartment?
The closest I've come is an assert statement placed defensively around suspicious code:
Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA);
suspiciousComInterface.SomeMethod();
While this will warn us if our BackgroundWorker
threads are calling STA objects, I am specifically worried that STA threads are using COM Runtime Callable Wrapper (RCW) objects that were created in another STA thread.
One online source suggested that this isn't possible (http://www.pcreview.co.uk/forums/detecting-cross-apartment-com-calls-t2450589.html), that the CLR obscures too much of the COM Proxy objects to make them accessible at a high-level.
I can't believe this is the only answer. Thanks!
You should be able to accomplish this by testing whether you can get to the IMarshal interface, which should be aggregated into the proxy if the call is a cross-apartment call. First, you will need to declare IMarshal somewhere in your project:
[System.Runtime.InteropServices.InterfaceTypeAttribute(1)]
[System.Runtime.InteropServices.Guid("00000003-0000-0000-C000-000000000046")]
public interface IMarshal
{
// no methods needed, just querying for the interface
}
Then, you can test for the interface like so.
if (suspiciousComInterface is IMarshal)
// cross-apartment call
else
// direct call
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With