Thank you Mr Igor.
The object does has a FTM.
actually works. I know most of the calls I made are illegal and I expected
the program to crash. But that's not happening here.
behavior is as expected. As you rightly pointed out that I am getting away
by violating COM rules. What has surprised me is why is COM so lenient when
the threading model is "Both".
I also wanted to know the lifetime of a COM object. Till I tried this
calls made will make the program crash. I guess this supposition must be
true only for STA based object. As there is only one MTA in the process the
object can still live.
The code snippet what I pasted here was the edited version. My actual test
constructor and destructor of the object.
behavior.
My main thread as well as my other two threads are all STA. The threading
model is still "Both". The thread id of the main thread is 3168, Thread1 is
1072 and Thread2 is 932.I create the object in Thread1. The constructor as
well as the function displays the thread id as 1072. In the thread2 I
932. Finally when I release the pointer in the main thread, the destructor
of the object is displaying the thread id as 3168.
Thanks in advance.
Dinesh.
"Dinesh Venugopalan" <dinesh@epiance.com> wrote in message
news:%23EvS1YJbIHA.3696@TK2MSFTNGP03.phx.gbl
I have a global pointer to an object whose threading model is "Both".
"Both" doesn't mean the object's pointer may be freely passed between
apartments. For that, you need to also aggregate free-threaded marshaller
(FTM). "Both" only means that the object lives in whatever apartment
created it originally. But once created, it belongs to that apartment.
TestLib::ITestBothClassPtr spBoth = NULL;
DWORD WINAPI ThreadProc1(LPVOID lpParam);
DWORD WINAPI ThreadProc2(LPVOID lpParam);
int _tmain(int argc, _TCHAR* argv[])
{
//CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);
CoInitializeEx(NULL,COINIT_MULTITHREADED);
DWORD dwThreadId = 0
HANDLE hThread =
CreateThread(NULL,0,ThreadProc1,NULL,0,&dwThreadId);
WaitForSingleObject(hThread,INFINITE);
hThread = CreateThread(NULL,0,ThreadProc2,NULL,0,&dwThreadId);
WaitForSingleObject(hThread,INFINITE);
spBoth->Test();
This is illegal. The object was originally created in an STA, and you are
passing its pointer to MTA without marshalling. Moreover, the STA thread
that created the object is already dead, taking the object with it I
believe. So you are calling through a dangling pointer to a non-existent
object.
spBoth = NULL;
CoUninitialize();
return 0;
}
DWORD WINAPI ThreadProc1(LPVOID lpParam)
{
CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);
//CoInitializeEx(NULL,COINIT_MULTITHREADED);
spBoth.CreateInstance(__uuidof(TestLib::TestBothClass));
spBoth->Test();
CoUninitialize();
spBoth->Test();
You are making a COM call after you've already uninitialized COM. This is
illegal.
return 1;
}
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
spBoth->Test();
You a) making a COM call without initializing COM first, and b) using a
COM pointer from a "wrong" thread without marshalling.
return 1;
}
It does not matter what threading model we follow.
1. Here the second call to spBoth->Test() in ThreadProc1 works though
I are calling it after CoUninitialize().
You are violating COM rules, but you just happen to get away with it. Just
because it appears to work doesn't mean it's a good idea.
It would be interesting to also print from the object's constructor and
destructor, and see if any calls arrive after the object has already been
destroyed.
Also ThreadProc2's
spBoth->Test() works properly. According to me both these calls
should have failed. Can anyone tell me why?
You have a direct pointer to the object. The call is a regular virtual
method call. No COM infrastructure is involved to check whether the call
is legal. But of course you are calling the object in a manner that it
stated it didn't support (by specifying a particular threading model). In
real life, the object may fail in strange and mysterios ways (especially
an object you didn't write yourself).
2. If I stop calling CoInitializeEx in the primary thread the second
call to spBoth->Test() in ThreadProc1 as well as spBoth->Test() in
ThreadProc2 crashes. Is COM doing something special for primary
thread of an application?
If I recall correctly, in WinNT and above, if a main thread joins MTA, all
threads that didn't explicitly call CoInitialize[Ex] also automatically
join MTA. This is an undocumented feature, it's not a good idea to rely on
it.
3. In the main thread I commented off CoInitializeEx and
CoUninitialize(). In the thread ThreadProc1 I commented off the call
to CoUninitialize() and in ThreadProc2 I added CoInitializeEx and
CoUninitialize(). Here spBoth->Test() crashes in ThreadProc2.
CreateInstance fails in thread 1 (since COM is not initialized), so thread
2 calls through NULL pointer. Try printing the value of the pointer before
every call, to see for yourself.
What is the point of this exercise? Why are you interested in finding out
how precisely your program breaks if you violate COM rules? Why not just
follow them?
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925