"Adriano Coser" wrote:
Carl, I think it's OK now.
I called CoInitializeEx( NULL, COINIT_APARTMEN TTHREADED); on DllMain of one
of my DLLs when reason == DLL_PROCESS_ATT ACH. Then I called CoUninitialize( )
when read == DLL_PROCESS_DET ACH.
Now the program is running! Thanks a lot, you made my weekend.
But in the output window I'm getting the inverse message that I had before:
Managed Debugging Assistant 'InvalidApartme ntStateChange' has detected a
problem in 'c:\Fontes\QiCa d.NET\QiCad.NET .exe'.
Additional Information: Thread is attempting to set the apartment state to
MTA, but it has already been set to STA.
Do you believe I should call CoInitializeEx in all my mixed mode DLLs?
Thanks again for your help.
Adriano.
AltoQi - Tecnologia Aplicada Ã* Engenharia Adriano Coser Departamento de
Desenvolvimento Tel.: (48) 239-7000 ramal: 7069 e-mail: co***@altoqi.co m.br
website: www.altoqi.com.br
"Carl Daniel [VC++ MVP]" <cp************ *************** **@mvps.org.nos pam>
escreveu na mensagem news:%2******** ********@TK2MSF TNGP14.phx.gbl. .. Adriano Coser wrote: Hi Carl.
I've just realized that the static instances I created to set the
apartment state on my DLLs (like the following) are not initialized
before _tWinMain.
I put breakpoints on DllMain and on the constructor of QIVCadCctor
and the program only stops on DllMain. Could this be the problem?
What else can I do to call managed code on a mixed mode DLL
initialization?
Why not simply set the apartment to the STA in native code instead of
managed? I would assume that a simple call to CoInitialize() in DllMain()
would be sufficient (I hope I'm not getting myself in trouble by not
verifying that it's actually safe to call CoInitialize() from DllMain()).
-cd
No, you should never call a method from DllMain which has managed code in it
or calls another method with managed code. You can easily get into a loader
lock problem.
The recommended way to move code out of DllMain is to declare a global
managed object. In the constructor of that object you should call the code
which you were initially calling in DllMain. The module constructor will
initialize see this global and call the constructor.
Note: A managed object here is not a ref/value class object. You cannot
have global ref objects. Here managed object means a native class compiled
with /clr or under #pragma managed.
The reason is this works is because in mixed assemblies, the initializations
are done by the module constructor. It is very important to remember that the
module constructor for an assembly is called only if some managed code is
first executed either in the host assembly or in your Dll itself. If you dont
"use" that managed object you will never invoke the module constructor, thus
your constructor will never be called and data will be uninitialized.
Let me give you an example,
///////////////////////
cl /clr /LD /Zi 1.cpp
cl /clr /EHa t.cpp /Zi /link 1.lib
/////////////////////
/////////////////
//1.cpp
#pragma once
#include <stdio.h>
#include <windows.h>
class __declspec(dlle xport) A
{
public:
A()
{
System::Console ::WriteLine("Mo dule constructor doing initialization based
on the global instance of the class A\n");
System::Console ::WriteLine("Co de from DllMain, now in constructor
executed\n");
}
void foo()
{
printf("foo called so that the linker knows not to throw away an unuse
object in t.cpp \n");
}
};
#pragma unmanaged
// Global instance of object
A obj;
extern "C"
BOOL WINAPI DllMain(HINSTAN CE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// REMOVE ALL MANAGED CODE FROM DLLMAIN.
return true;
}
///////////////////////////////
//t.cpp
#include <windows.h>
using namespace System;
#include <stdio.h>
#using "1.dll"
class __declspec(dlli mport) A
{
public:
void foo();
};
int main()
{
LoadLibrary("1. dll");
A obj;
obj.foo();
}