More DLL goodness.

Published June 13, 2005
Advertisement
What? More DLL nonsense?
Just when you thought you had it all down, someone had to throw a monkey wrench into the clockwork. This time it's going to be on DllMain! That funny function that gets called more than once.

DllMain, what is it?
DllMain is an optional entry point into a DLL. It gets called whenever processes or threads are initialized or terminated. It is also called when LoadLibrary or FreeLibrary are called.

This function lets you do things at the creation and termination of a process, along with the creation and termination of a thread. You can also handle cases where LoadLibrary or FreeLibrary get called. In generaly, you will use it to initialize and release resources that the DLL requires. In general, the DllMain function should only do simple initialization tasks. Such tasks include, but aren't limited to:

  • Setting up thread local storage (TLS)

  • Creating synchronization objects (Such as critical sections, mutexes, or semaphores)

  • Opening files (such as log files)


Of course, the opposites of these should also be performed when termination occures. Do not call LoadLibrary FreeLibrary in your DllMain method. You can setup nasty dependency loops in the DLL load order, or cause a DLL to be accessed after it's termination routine has been called.

Using DLL main
So, first lets get a small bit of code out of the way, primarily the shared header.
#ifndef SIMPLE_H#define SIMPLE_H#ifdef _MSC_VER#ifdef SIMPLEDLL_EXPORTS#define DLLIMP __declspec(dllexport)#else#define DLLIMP __declspec(dllimport)#endif#else#define DLLIMP#endifextern "C" DLLIMP int GetProcessRegistrationCount();extern "C" DLLIMP int GetThreadRegistrationCount();extern "C" DLLIMP int GetDynamicLoadCount();typedef int (*GetDllStatisticSignature)();#endif

Using DllMain is a simple task, just define it in your source file like you do main, give it a body that does something, then compile and link. The operating system will take care of calling the function with the right parameters and at the right times.

The DllMain function is passed several parameters, one of which enables it to determine the reason for it being called. There are four reasons:

  • DLL_PROCESS_ATTACH is passed if it is being attached to the process, or if LoadLibrary was called.

  • DLL_PROCESS_DETACH is passed if it is being detached from a process, or if FreeLibrary was called.

  • DLL_THREAD_ATTACH is passed if it is being attached to a thread, note that this is not passed if the thread is the primary thread of a process, instead DLL_PROCESS_ATTACH is used.

  • DLL_THREAD_DETACH is passed if it is being detached from a thread, again, this will not be called if the thread is the primary thread of the process. DLL_PROCESS_DETACH will be called instead.


If the DLL was loaded using LoadLibrary, or is being unloaded through FreeLibrary, then the reserved component of the DllMain function will be set to 0.

What follows is the source file that goes with the above header:
#include #include "Simple.h"int processRegistrationCount = 0;int threadRegistrationCount = 0;int dynamicLoadCount = 0;BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD reason, void* reserved) {	switch(reason) {		case DLL_PROCESS_ATTACH:			if(reserved == 0)				dynamicLoadCount++; //LoadLibrary was called			processRegistrationCount++;			break;		case DLL_PROCESS_DETACH:			if(reserved == 0)				dynamicLoadCount--; //FreeLibrary was called			processRegistrationCount--;			break;		case DLL_THREAD_ATTACH:			threadRegistrationCount++;			break;		case DLL_THREAD_DETACH:			threadRegistrationCount--;			break;		default:			return false;//error	}	return true;}int GetProcessRegistrationCount() {	return processRegistrationCount;}int GetThreadRegistrationCount() {	return threadRegistrationCount;}int GetDynamicLoadCount() {	return dynamicLoadCount;}


Putting using this in a simple statically linked application, we get:
#include #include #include #include "../SimpleDll/Simple.h"void SimpleThread(void*) {	std::wcout<"Process Registration Count: "
< std::wcout<"Thread Registration Count: "<}

int main() {
std::wcout<"Dynamic Load Count: "< std::wcout<"Process Registration Count: "< std::wcout<"Thread Registration Count: "< uintptr_t handle = _beginthread(SimpleThread, 0, 0);
WaitForSingleObject(reinterpret_cast(handle), INFINITE);
std::wcout<"Process Registration Count: "< std::wcout<"Thread Registration Count: "<}



The resulting output should be:
Dynamic Load Count: 0Process Registration Count: 1Thread Registration Count: 0Process Registration Count: 1Thread Registration Count: 1Process Registration Count: 1Thread Registration Count: 0

Which is what we expect (if you've been following me so far.)

Questions?
Previous Entry Some people...
0 likes 4 comments

Comments

Mushu
Get a girlfriend. If you have one, spend more time with her.
June 13, 2005 10:48 PM
Washu
Quote:Get a girlfriend. If you have one, spend more time with her.


The blow up anime doll says: If you get a GF, I'm so leaving.
June 13, 2005 10:50 PM
noaktree
Quote:The blow up anime doll says: If you get a GF, I'm so leaving.
Maybe you could talk her into a threeway.
June 14, 2005 12:15 AM
MustEatYemen
An all painter three way?
June 29, 2005 07:34 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement