Re: Multithreading issues related to an ActiveX control
 
Thanks for your quick answer.
"Brian Muth" <bmuth@mvps.org>, iletisinde ?unu yazd?, 
news:%23fgSHKd5HHA.4880@TK2MSFTNGP03.phx.gbl...
Your code is trying to compensate for a faulty design. The problem with 
your approach is that you can't control which thread the client code is 
going to use to call in to your DLL. This is disastrous since your COM 
object has been instantiated in a single-threaded apartment.
You might imagine that switching to an MTA by calling CoInitializeEx (0, 
COINIT_MULTITHREADED) in your Initialize() function might be the answer. 
This is also faulty. The thread that initializes the MTA is required to 
outlive the apartment, and again your DLL code has no control over this. 
Moreover, I suspect the call to CoInitializeEx (0, COINIT_MULTITHREADED) 
will fail anyway, since it is highly likely the thread has already called 
CoInitialize() by the parent code. (I note in your code you don't check 
the return code of CoInitialize(). You should be.)
I have already switched to CoInitializeEx (0, COINIT_MULTITHREADED) with the 
change I have made. I think that's how I have got it this way.
The best solution is for your DLL to spawn a worker thread. The worker 
thread can freely establish either an MTA or an STA, whichever is more 
appropriate for your application, and will have full control over the 
object lifetime. The only obstacle is there may be some trickiness to get 
the worker thread to shut down without the cooperation of the parent code. 
I'm guessing this won't be a problem for you if the parent code is already 
calling Initialize() and Uninitialize(). That's where you will spawn and 
shut down your thread.
Actually my first try was to spawn a worker thread. And your right it's has 
been a problem to shut it down. Since I cannot change the parent code, the 
main app has started give an exception during the shutdown.
Just a few comments about the code you posted:
=====================================
#import "c:/applicationpath/interface.dll"
using namespace XXX;
class CVerifyUser
{
public:
long VerifyUser(CString csUserID, CString csPassword)
{
 BSTR bstrUserID = csUserID.AllocSysString();
 BSTR bstrPassword = csPassword.AllocSysString();
 try
 {
  HRESULT hr;
  hr = m_pVerifyUser->raw_VerifyUser( &bstrUserID, &bstrPassword, &lRet);
 }
//...
Do you call SysFreeString() on the bstrUserID and bstrPassword variables?
No. Thanks for that. Actually this part of code was written by somebody 
else. I will fix it.
}
long Uninitialize()
{
if (m_pVerifyUser != NULL) {
 m_pVerifyUser.Release();
}
CoUninitialize();
}
long Initialize()
{
CoInitialize(NULL);
You should be checking the return code here. It's quite possible 
CoInitialize(NULL) will fail. The STA may already be established by the 
parent code. In this case, you don't want to call CoUninitialize() in you 
Uninitialize() routine.
Actually there is a check in the code but I have omitted it to keep the 
posting short.
//...
 hr = m_pVerifyUser.CreateInstance("XXX.UserVerification");
}
CVerifyUser();
virtual ~CVerifyUser();
private:
_UserVerificationPtr m_pVerifyUser;
};
HTH
Brian