none
Marshalling COM interface between threads--help!

    Question

  • I am developing a Windows Forms 2.0 application that references a COM primary interop assembly to communicate with a COTS product. I am still very new to working with COM from .Net and the threading issues that are involved, so I am unsure how to marshall a COM interface between threads--I have the main UI thread, of course, but for many of the data access calls I use a BackgroundWorker component to execute the calls asynchronously. The issue I am having is that I am attempting to maintain a single instance of the Database object (part of the COM API) because creating it is very resource intensive, but I am getting an exception that the worker thread is attempting to access an interface that was mashalled for a different thread. The main UI thread initially creates the Database object (this class I wrote to handle creating this Database object implements a thread-safe Singleton pattern) and the exception of course only occurs when the background worker thread attempts to call a method on the same object that the main UI thread created. I have seen multiple articles on various scenarios but none that seemed to address what I am trying to do. This is not a remoting scenario and I cannot customize the interop assemblies to change the default marshalling behavior. I can only change how my code accesses the resources in the COM API. Can someone please give me an example in C# of how to marshall a COM interface across multiple threads? I was told by the technical support group that developed this COTS API to simply change the thread apartment state from STA to MTA, but I can't do this--in fact it throws an exception when the app loads to to being unable to register drag and drop..etc.

    Thanks very much,

    Larkin
    Tuesday, February 07, 2006 3:59 PM

Answers

All replies

  • Here's an MSDN article that may help you: http://msdn2.microsoft.com/en-us/library/5s8ee185(en-US,VS.80).aspx

     

    Tuesday, February 07, 2006 4:25 PM
  • Thanks--I've actually looked through that documentation quite a bit, and while it provides lengthly information on theory--mostly for exposing .Net components to COM, which is not what I am doing--it has no examples whatsoever (thanks MSDN) to explain this theory. The response I received from the API support people was to use the CoMashalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream functions on the two threads respectively to get a copy of the COM interface on my background worker thread. I am guessing these functions are included in some Win32 library, but I can't find them, much less how to actually use them.
    Tuesday, February 07, 2006 4:44 PM
  • [DllImport("ole32.dll")]
    static extern int CoMarshalInterThreadInterfaceInStream([In] ref Guid riid,
       [MarshalAs(UnmanagedType.IUnknown)] object pUnk, out UCOMIStream ppStm);

    [DllImport("ole32.dll")]
    static extern int CoGetInterfaceAndReleaseStream(UCOMIStream pStm, [In] ref
       Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

     

    If you are going into COM itf marshaling you might want to read this as well:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/html/0c1feee7-e33b-4b5d-8e35-4de6895e3947.asp

     

    --Ivo

    Thursday, February 09, 2006 2:06 AM
  • Note that there  is no need to ever call these API's from managed side, Interface marshaling is done automatically by the CLR under the covers.
    The role of the CLR is to make COM interop as seamless as possible by taking away these kind of complexities from the developer of managed components that need to call into COM.
     
    Willy.
     

    [DllImport("ole32.dll")]
    static extern int CoMarshalInterThreadInterfaceInStream([In] ref Guid riid,
    [MarshalAs(UnmanagedType.IUnknown)] object pUnk, out UCOMIStream ppStm);

    [DllImport("ole32.dll")]
    static extern int CoGetInterfaceAndReleaseStream(UCOMIStream pStm, [In] ref
    Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

    If you are going into COM itf marshaling you might want to read this as well:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/html/0c1feee7-e33b-4b5d-8e35-4de6895e3947.asp

    --Ivo

    Saturday, February 11, 2006 4:32 PM
  • I wish that were completely true--however if that was the case I wouldn't be having an issue at all. It is clear that if I don't explicitly marshal the interface across my application threads I will get an exception every time a worker thread tries to call a method on a COM object that was created by the main UI thread.
    Tuesday, February 14, 2006 3:46 PM
  • Please be more explicit, what issue/exception exactly?
     I know that, when you pass an interface pointer from a context to another, say from STA to an MTA thread, the CLR looks for the apartment/thread where the object was born in, if this is not the same as the target thread/apartment, it calls an internal (mscorwsk.dll)  version of OLE!CoMarshalInterThreadInterfaceInStream which finally calls into OLE32!CoMarshalInterface.
    I'm sharing interface pointers (well they aren't interface pointers they are RCW, and that's the whole point) between threads since v1.of .NET in my applications without any problem. Reason that this is done in the CLR is to free the application developer from this gory details, can you ask a VB.NET developer to call these C style OLE32 API's?
     
     
    Willy.
     
    I wish that were completely true--however if that was the case I wouldn't be having an issue at all. It is clear that if I don't explicitly marshal the interface across my application threads I will get an exception every time a worker thread tries to call a method on a COM object that was created by the main UI thread.
    Tuesday, February 14, 2006 8:25 PM
  • Thanks for the help with these pinvokes.

    Here's the mother of all pinvoke references with thanks to Adam Nathan!

    www.pinvoke.net

    ie: http://www.pinvoke.net/default.aspx/ole32/CoMarshalInterThreadInterfaceInStream.html

    Thursday, December 07, 2006 9:04 PM
  • Is there an API we can use to get the apartment where an object was created in ?

    -mab

    Friday, December 22, 2006 4:10 PM
  • fyi - I've started a related thread here , asking "Does interop do cross-thread marshalling for COM or do I need to use CoMarshalInterThreadInterfaceInStream or similar?", as there seems to be disagreement as to whether the CLR/interop does this automatically.
    Thursday, May 28, 2009 1:13 AM