• entries
    146
  • comments
    436
  • views
    197742

More DLL goodness.

Sign in to follow this  

149 views

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
#endif

extern "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: 0
Process Registration Count: 1
Thread Registration Count: 0
Process Registration Count: 1
Thread Registration Count: 1
Process Registration Count: 1
Thread Registration Count: 0

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

Questions?
Sign in to follow this  


4 Comments


Recommended Comments

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.

Share this comment


Link to comment
Quote:
The blow up anime doll says: If you get a GF, I'm so leaving.
Maybe you could talk her into a threeway.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now