Hi
I have a .NET Application and try to call a COM Object (3th party library). I can do this as follow via Reflection:
The ugly thing is that I only have an object and must do all my calls via Reflection. So I tried to make an instance of the COM Object:Code:public void Go() { Type mandantType = Type.GetTypeFromProgID("FibuNT.Mandant"); Object mandant = Activator.CreateInstance(mandantType); mandant.GetType().InvokeMember("Login", BindingFlags.InvokeMethod, null, mandant, new object[] { 1, path, "" }); }
Both methods works successfully as long I made the call in the Main STA. I’ve I made the call from a different Thread, I can’t instance my COM object, I receive an Exception:Code:public void Go() { Interop.FibuSDK.OMandantClass mandant = new Interop.FibuSDK.OMandantClass(); mandant.Login(1, path, ""); }
Unable to cast COM object of type ‘SesamFibuSDK.OMandantClass’ to interface type ‘SesamFibuSDK.Mandant’. This operation failed because the QueryInterface call on the COM component for the interface with IID '{4E879FE0-A269-11CE-AB56-00608CDFDCF8}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)
I’ ve read that some COM object must be call in the STA Thread. So, I adapt my Code as follow. I have created a new Thread and set the ApartmentState:
In the new Thread the COM Object I received the same exception. Only if I remove the Attribute STAThread in the main it work’s:Code:[STAThread] public static void Main(string[] args) { Console.Write("Spawning Thread "); Thread t = CreateThread(); // t.Join(); } static Thread CreateThread() { ShellClass myObj = new ShellClass(); Thread myThread; myThread = new Thread(new ThreadStart(myObj.Go)); myThread.SetApartmentState(ApartmentState.STA); myThread.Start(); return myThread; } ShellClass() // … public void Go() { SesamFibuSDK.OMandant m = new SesamFibuSDK.OMandant(); } // …
Why do I receive this exception? And why does it work, if I use Reflection?Code:// [STAThread] public static void Main(string[] args) { … }
The Background is, that I will call the COM Object from a webservice. I have read the following article (but it doesn’t work):
articles.techrepublic.com.com/5100-10878_11-5152421.html#
(Application Development: Calling a COM object from a Web service in .NET)
Thanks
Pascal
Last edited by WingedPanther; 11-02-2009 at 10:14 AM. Reason: add code tags (the # button)
The Thread Apartment thingy in COM is quite complicated and was definitely not designed with .NET in mind.
Reflection might be working fine due to some magic done by the COM Callable Wrappers, I'm not sure though.
To the main problem:
When you initialize without the [STAThread] attribute you are basically initializing COM from an MTA (multi-threaded apartment) thread, this allows the COM object to be accessed from threads other than the thread that created the object. The issue with this is that if you call CoInitializeEx again and specify a different apartment state you would get an exception.
When you initialize with an STA thread: (MSDN) "while allowing for multiple threads of execution, serializes all incoming calls by requiring that calls to methods of objects created by this thread always run on the same thread – the apartment/thread that created them." - hence the reason you get an exception when accessing the object from another thread.
Luckily I encountered this problem from C++/CLI with full access to the COM object code, I assume you don't have that.
Possible solutions:
Design your code such that you create and access the object as required in the same method. OR
Dispatch all operations that require the object to the thread that created it.
thanks for the replay
I've now changed now the design. I dispatched the operation to be in the same "creation thread".
Greets
Pascal
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks