Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Legacy VB6 COM+ DLL calling into native Win32 DLL -- threading issues with STA?

Come across what looks at first sight like an MT-issue, but I'm trying to understand in detail the STA model used by COM+.

Effectively, I have a legacy COM+ component, written in VB6, that calls into a native (i.e., not-COM) Win32 DLL written in C++.

Having some intermittant (and impossible to reproduce in testing) problems with it, I added some debugging code to find out what was going on and found that when the problems occur, I had log messages interleaved in the file - so it implied that the DLL was being called by two threads at once.

Now the logging goes to a per-thread file based on _getpid() and GetCurrentThreadId(), so it seems that when the code in the C++ DLL is called, it's getting called twice on the same thread at the same time. My understanding of STA says suggests this could be the case as COM marshalls the individual instances of objects onto a single thread suspends and resumes execution at will.

Unfortuantly I'm not sure where to go from here. I'm reading that I should be calling CoInitialiseEx() in DllMain() to tell COM that this is an STA DLL, but other places say this is only valid for COM DLLs and won't have any effect in a native DLL. The only other option is to wrap parts of the DLL up as critical sections to serialize access (taking whatever performance hit that has on the chin).

I could try and rework the DLL, but there is no shared state or global vars - everything's in local variables so in theory each call should get its own stack, but I'm wondering if the STA model is basically having some odd effect on this and just re-entering into the already loaded DLL at the same entry point as another call. Unfortuantly, I don't know how to prove or test this theory.

The questions basically are:

  1. When an STA COM+ component calls a native DLL, there's nothing in the STA model to prevent the active "thread" being suspended and control being passed over to another "thread" in the middle of a DLL call?
  2. Is CoInitialiseEx() the right way to resolve this, or not?
  3. If neither (1) or (2) are "good" assumptions, what's going on?
like image 901
Chris J Avatar asked Jun 29 '09 10:06

Chris J


1 Answers

In an apartment threaded COM server, each instance of the COM class is guaranteed to be accesses by a single thread. This means the instance is thread safe. However, many instances can be created simultaniously, using different threads. Now, as far as the COM server is concerned, your native DLL does not have to do anything special. Just think about kernel32.dll, which is used by every executable - does it initialize COM when used by a COM server?

From the DLL point of view, you have to make sure you're thread safe, as different instances can call you at the same time. STA will not protect you on this case. Since you say you are not using any global variables, I can only assume the problem is elsewhere, and just happens to show on circumstances that seem to point to the COM stuff. Are you sure you don't have some plain old C++ memory issues?

like image 71
eran Avatar answered Nov 15 '22 10:11

eran