Accessing COM EXE-server from diffent threads
Hi everyone,
I am stuck with a problem: my MFC-application loads dynamically a DLL which accesses a COM-Server from 3 diffent threads. When the main thread calls functions from the COM-server it all works fine but if another thread tries to access any function from the COM-server I receive an error.
CoInitializeEx(NULL, COINIT_MULTITHREADED) is executed in all threads before accessing the server.
For test purposes I have written a small programm (also MFC) which does the same as my application (calls same function inside the DLL) but here it works fine.
Has someone any clue what the issue may be?
Edit: the code is 8001010e: The application called an interface that was marshalled for a different thread.
Regards
Padan.
Re: Accessing COM EXE-server from diffent threads
Are you accessing this COM server from all your threads using the same pointer?
Re: Accessing COM EXE-server from diffent threads
Yes, the interface pointer is a member variable.
The DLL was not written by me but it also works works in another application where it was originally used.
Re: Accessing COM EXE-server from diffent threads
You'll need to use the global interface table to access an STA from a different thread.
See http://msdn.microsoft.com/en-us/libr...29(VS.85).aspx
Re: Accessing COM EXE-server from diffent threads
Thank you, maybe I will try that.
But I still wonder why the DLL works with 2 programmes and not with the 3rd. If possible I'd prefer not to modify the DLL.
Re: Accessing COM EXE-server from diffent threads
Quote:
Originally Posted by
Padan
Thank you, maybe I will try that.
But I still wonder why the DLL works with 2 programmes and not with the 3rd. If possible I'd prefer not to modify the DLL.
You don't need to modify the Dll (e.g. in-proc COM server).
If the COM server is an STA and you want to call use a pointer to it in different threads, then you need to use the GIT.
The problem isn't with the dll, it's with the fact that you are calling it from multiple threads.
Re: Accessing COM EXE-server from diffent threads
Quote:
Originally Posted by
Padan
When the main thread calls functions from the COM-server it all works fine
I think you are fetching the interface pointer in the main thread, and using it in another thread as well, but this will not work, you should not use a interface pointer fetched in one thread in another thread, you can only do this my marshalling the interface pointer.
Assuming , that you have IMyInterface *ptrMyInterface, once this interface is fetched in the main thread, before you start the other thread, pass the interface pointer to another thread by
doing this.
IStream *pStream = NULL;
HRESULT hr =::CoMarshalInterThreadInterfaceInStream(IID_IMyInterface,ptrMyInterface,&pStream);
HANDLE h = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)ThreadProc,pStream,NULL,&dwid);
Then inside the thread, you have to unmarshall this interface pointer
UINT ThreadProc(LPVOID lp)
{
HRESULT hr;
::CoInitialize(NULL,COINIT_MULTITHREDED);
IStream *pStream = (IStream *)lp;
IMyInterface *ptrMyInterface;
hr = ::CoGetInterfaceAndReleaseStream(pStream,IID_IMyInterface,reinterpret_cast<void **>(&pEvent));
//make call using the interface pointer.
}
regards
pradish
Re: Accessing COM EXE-server from diffent threads
Arjay, I changed the code to use the global interface table and do not receive any errors anymore. But the access is very slow so I receive internal timeouts quite often.
I had to change the DLL because it accesses the COM Exe-server. My programme loads the DLL. And the DLL has multiple threads. ;)
pradish, thanks for the code. I might possibly try that but there seems to be an issue in the application.
Might other COM-DLLs conflict with the COM Exe-server, e.g. MSXML?
Re: Accessing COM EXE-server from diffent threads
What I am referring to is use the GIT which is what the code that Pradish provided - it's the same technique. So you say, you used the GIT, but didn't use Pradish's code - what code did you use?
In terms of a slowdown, you might want to review the differences between how STA and MTA COM objects work. In a nutshell, STA objects use a message queuing mechanism to serialize incoming requests. If there are multiple STA COM objects residing in the same apartment, their requests will be serialized in the message queue (and performance may suffer).
Re: Accessing COM EXE-server from diffent threads
I use the following code:
Code:
CoCreateInstance(CLSID_StdGlobalInterfaceTable,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGlobalInterfaceTable,
(void **)&pGIT);
HRESULT hResult = pGIT->RegisterInterfaceInGlobal( m_pInterface, IID_IMyInterface, &dwCookie);
...
HRESULT hr = pGIT->GetInterfaceFromGlobal( dwCookie, IID_IMyInterface, (void **)&pInterface );
The code itself works fine.
There is always only one client for the COM-server, it runs as a MTA though. In the original environment where the DLL is used there are more than one client at a time (up to 10) and the application does have any performance issues.
It wouldn't matter so much if I'd receive slowdowns when calling functions but the events of the COM-servers sometimes arrive very late (10 - 20 seconds delay).
Re: Accessing COM EXE-server from diffent threads
Hi Padan,
i am making a wild guess..i may be wrong, but you can check this
In the CProxy_XXXXXX class
HRESULT Fire_OnSomeEvent()
{
HRESULT hr = S_OK;
T * pThis = static_cast<T *>(this);
int cConnections = m_vec.GetSize(); //check this size, does this match with the number of
clients who have registerd for callbaks, if yes, then the problem is something else.
in most cases the callbacks take time because they have invalid client address.
other Trivial issues:
The pGIT pointer that you are using is a global pointer and you are using therad synchronization primitives to protect the
GIT form being accessed by multiple threads simultaniously
regards
pradish
regards
pradish
Re: Accessing COM EXE-server from diffent threads
Hello pradish and sorry for the late reply.
Yes, there is only one client registered and the DLL uses synchronization mechanism but this doesn't block the access to the GIT. Only one thread accesses the COM client inside the DLL (at runtime).
I still do not know why the DLL works fine with two application and does not with the 3rd.