Wednesday, May 4, 2011

executing the DllMain function with a Code::Blocks DLL

Some months ago, I discovered with folks that a DLL developed with the Code::Blocks IDE does not execute its entry point when it is loaded.

When you create a DLL project under Code::Blocks, two files are generated:
  • main.h: file with macros, includes and other stuff;
  • main.cpp: code of the DllMain and exported functions.
Here are the source codes:

main.h
#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>

/*  To use this exported function of dll, include this header
 *  in your project.
 */

#ifdef BUILD_DLL
    #define DLL_EXPORT __declspec(dllexport)
#else
    #define DLL_EXPORT
#endif


#ifdef __cplusplus
extern "C"
{
#endif

void DLL_EXPORT SomeFunction(const LPCSTR sometext);

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__

main.cpp
#include "main.h"

// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)

{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);

}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:

            // attach to process
            // return FALSE to fail DLL load
            break;

        case DLL_PROCESS_DETACH:
            // detach from process

            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful

}

Though our DLL exports correctly the "SomeFunction" function, the DllMain is not called when the library is loaded (by linking or dynamic loading using the LoadLibrary() function).

The solution consists in adding the following directives which wrap the DllMain code:

#ifdef __cplusplus
extern "C"
{
#endif


#ifdef __cplusplus
}
#endif

Otherwise, just rename the main.cpp file into main.c! The problem is due to the fact that the DllMain function must not escape to the extern C rule; it's ok for the "SomeFunction" function, but DllMain has to be treated too!

Now you may try the following code:

main.cpp
#include "main.h"


// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)

{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);

}

#ifdef __cplusplus
extern "C"
{
#endif
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:

            // attach to process
            // return FALSE to fail DLL load
            MessageBox(0, "Hello world!", "Message from DllMain", 0);

            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:

            // detach from thread
            break;
    }
    return TRUE; // succesful
}

#ifdef __cplusplus
}
#endif

This was just a little trick that I wish I could remember later.

Enjoy!

Ge0