DLL Main в Windows Vs. __attribute __ ((конструктор)) точки входа в Linux

Рассмотреть код

EXE:

int main ()
{

printf("Executable Main, loading library\n");
#ifdef HAVE_WINDOWS
HMODULE lib = LoadLibraryA ("testdll.dll");
#elif defined(HAVE_LINUX)
void * lib  = dlopen("testdll.so", RTLD_LAZY);
#endif

if (lib) {
printf("Executable Main, Freeing library\n");
#ifdef HAVE_WINDOWS
FreeLibrary (lib);
#elif defined(HAVE_LINUX)
dlclose(lib);
#endif
}
printf("Executable Main, exiting\n");
return 0;
}

DLL

struct Moo
{
Moo() { printf("DLL Moo, constructor\n"); }
~Moo() { printf("DLL Moo, destructor\n"); }
};

Moo m;

#ifdef HAVE_WINDOWS
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD  ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("DllMain, DLL_PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
printf("DllMain, DLL_THREAD_ATTACH\n");
break;
case DLL_THREAD_DETACH:
printf("DllMain, DLL_THREAD_DETACH\n");
break;
case DLL_PROCESS_DETACH:
printf("DllMain, DLL_PROCESS_DETACH\n");
break;
default:
printf("DllMain, ????\n");
break;
}
return TRUE;
}
#else
CP_BEGIN_EXTERN_C
__attribute__((constructor))
/**
* initializer of the dylib.
*/
static void Initializer(int argc, char** argv, char** envp)
{
printf("DllInitializer\n");
}

__attribute__((destructor))
/**
* It is called when dylib is being unloaded.
*
*/
static void Finalizer()
{
printf("DllFinalizer\n");
}

CP_END_EXTERN_C
#endif

Выход отличается:

На окнах

Executable Main, loading library
DLL Moo, constructor
DllMain, DLL_PROCESS_ATTACH
Executable Main, Freeing library
DllMain, DLL_PROCESS_DETACH
DLL Moo, destructor
Executable Main, exiting

Linux

Executable Main, loading library
DllInitializer
DLL Moo, constructor
Executable Main, Freeing library
DllFinalizer
DLL Moo, destructor
Executable Main, exiting

В Windows конструктор Moo вызывается до DLLMain, а в Linux он вызывается после инициализатора, определенного с помощью атрибута ((конструктор)).

ЗАЧЕМ?

4

Решение

Moo конструктор не называется до DllMain, это называется от DllMain, Чтобы быть точным, его называют из реального DllMain, функция Windows вызывает в первую очередь. Это настоящий DllMain вызывает конструкторы C ++, а затем вызывает ваш C ++ DllMain, Причина этого реального DllMain именно для инициализации конструкторов, что раньше не требовалось в C

Linux (GCC / ELF) вообще не имеет этой концепции; у него есть только конструкторы. Ваш ручной ctor и c ++ ctor для Moo обрабатываются одинаково.

5

Другие решения

Есть выход:

StartupCleanup.cpp:

// Redefine the same StartupCleanup class as it is in DllMain.cpp
// Definition of constructor and destructor must stay in DllMain.cpp
// And including here any headers which may define normal static or global constructors/destructors is strictly forbidden!
struct StartupAndCleanup
{
/**/  StartupAndCleanup();
/**/ ~StartupAndCleanup();
};

// It ensures this instance is the first to be constructed *BEFORE* any normal static or global constructors calls
// and the last to be destructed *AFTER* all normal destructors calls.
// The key to do so is using #pragma init_seg(lib), but that key applies for all the static and global constructors/destructors in the same .obj file!
#pragma warning(push)
#pragma warning(disable:4073)
#pragma init_seg(lib)
#pragma warning(pop)

// this function is just to keep linker from discarding startupAndCleanup.obj when linking to an executable or dll
void needStartupAndCleanup()
{
}

static StartupAndCleanup startupAndCleanup;

DllMain.cpp:

...
// Definition of this class should be the same as in StartupAndCleanup.cpp!
struct StartupAndCleanup
{
/**/  StartupAndCleanup();
/**/ ~StartupAndCleanup();
};

StartupAndCleanup::StartupAndCleanup()
{
// Do your initialization here !
}

StartupAndCleanup::~StartupAndCleanup()
{
// Do your termination here !
}

Вы DllMain должны быть просто пустой оболочкой и выполнять обычную безопасную инициализацию и завершение в тех конструкторах и деструкторах, как для Linux.

ПРИМЕЧАНИЕ: будьте осторожны! Вы не можете создавать / удалять потоки внутри статических или глобальных конструкторов / деструкторов, если планируете их синхронизировать.
Это все, ребята!

РЕДАКТИРОВАТЬ: вам также нужно вызывать needStartupAndCleanup () в функции, вы знаете, что она связана, в противном случае файл объекта StartupCleanup.obj будет отброшен, а также эти глобальные конструктор / деструктор.

0

По вопросам рекламы [email protected]