DllMain entry point

Expand
32 out of 54 rated this helpful - Rate this topic

DllMain entry point

Applies to: desktop apps only

An optional entry point into a dynamic-link library (DLL). When the system starts or terminates a process or thread, it calls the entry-point function for each loaded DLL using the first thread of the process. The system also calls the entry-point function for a DLL when it is loaded or unloaded using the LoadLibrary and FreeLibrary functions.

Warning  There are serious limits on what you can do in a DLL entry point. To provide more complex initialization, create an initialization routine for the DLL. You can require applications to call the initialization routine before calling any other routines in the DLL.

Syntax

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

Parameters

hinstDLL [in]

A handle to the DLL module. The value is the base address of the DLL. The HINSTANCE of a DLL is the same as the HMODULE of the DLL, so hinstDLL can be used in calls to functions that require a module handle.

fdwReason [in]

The reason code that indicates why the DLL entry-point function is being called. This parameter can be one of the following values.

ValueMeaning
DLL_PROCESS_ATTACH
1

The DLL is being loaded into the virtual address space of the current process as a result of the process starting up or as a result of a call to LoadLibrary. DLLs can use this opportunity to initialize any instance data or to use the TlsAlloc function to allocate a thread local storage (TLS) index.

The lpReserved parameter indicates whether the DLL is being loaded statically or dynamically.

DLL_PROCESS_DETACH
0

The DLL is being unloaded from the virtual address space of the calling process because it was loaded unsuccessfully or the reference count has reached zero (the processes has either terminated or called FreeLibrary one time for each time it called LoadLibrary).

The lpReserved parameter indicates whether the DLL is being unloaded as a result of a FreeLibrary call, a failure to load, or process termination.

The DLL can use this opportunity to call the TlsFree function to free any TLS indices allocated by using TlsAlloc and to free any thread local data.

Note that the thread that receives the DLL_PROCESS_DETACH notification is not necessarily the same thread that received the DLL_PROCESS_ATTACH notification.

DLL_THREAD_ATTACH
2

The current process is creating a new thread. When this occurs, the system calls the entry-point function of all DLLs currently attached to the process. The call is made in the context of the new thread. DLLs can use this opportunity to initialize a TLS slot for the thread. A thread calling the DLL entry-point function with DLL_PROCESS_ATTACH does not call the DLL entry-point function with DLL_THREAD_ATTACH.

Note that a DLL's entry-point function is called with this value only by threads created after the DLL is loaded by the process. When a DLL is loaded using LoadLibrary, existing threads do not call the entry-point function of the newly loaded DLL.

DLL_THREAD_DETACH
3

A thread is exiting cleanly. If the DLL has stored a pointer to allocated memory in a TLS slot, it should use this opportunity to free the memory. The system calls the entry-point function of all currently loaded DLLs with this value. The call is made in the context of the exiting thread.

 

lpvReserved [in]

If fdwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.

If fdwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if FreeLibrary has been called or the DLL load failed and non-NULL if the process is terminating.

Return value

When the system calls the DllMain function with the DLL_PROCESS_ATTACH value, the function returns TRUE if it succeeds or FALSE if initialization fails. If the return value is FALSE when DllMain is called because the process uses the LoadLibrary function, LoadLibrary returns NULL. (The system immediately calls your entry-point function with DLL_PROCESS_DETACH and unloads the DLL.) If the return value is FALSE when DllMain is called during process initialization, the process terminates with an error. To get extended error information, call GetLastError.

When the system calls the DllMain function with any value other than DLL_PROCESS_ATTACH, the return value is ignored.

Remarks

DllMain is a placeholder for the library-defined function name. You must specify the actual name you use when you build your DLL. For more information, see the documentation included with your development tools.

During initial process startup or after a call to LoadLibrary, the system scans the list of loaded DLLs for the process. For each DLL that has not already been called with the DLL_PROCESS_ATTACH value, the system calls the DLL's entry-point function. This call is made in the context of the thread that caused the process address space to change, such as the primary thread of the process or the thread that called LoadLibrary. Access to the entry point is serialized by the system on a process-wide basis. Threads in DllMain hold the loader lock so no additional DLLs can be dynamically loaded or initialized.

If the DLL's entry-point function returns FALSE following a DLL_PROCESS_ATTACH notification, it receives a DLL_PROCESS_DETACH notification and the DLL is unloaded immediately. However, if the DLL_PROCESS_ATTACH code throws an exception, the entry-point function will not receive the DLL_PROCESS_DETACH notification.

There are cases in which the entry-point function is called for a terminating thread even if the entry-point function was never called with DLL_THREAD_ATTACH for the thread:

  • The thread was the initial thread in the process, so the system called the entry-point function with the DLL_PROCESS_ATTACH value.
  • The thread was already running when a call to the LoadLibrary function was made, so the system never called the entry-point function for it.

When a DLL is unloaded from a process as a result of an unsuccessful load of the DLL, termination of the process, or a call to FreeLibrary, the system does not call the DLL's entry-point function with the DLL_THREAD_DETACH value for the individual threads of the process. The DLL is only sent a DLL_PROCESS_DETACH notification. DLLs can take this opportunity to clean up all resources for all threads known to the DLL.

When handling DLL_PROCESS_DETACH, a DLL should free resources such as heap memory only if the DLL is being unloaded dynamically (the lpReserved parameter is NULL). If the process is terminating (the lpvReserved parameter is non-NULL), all threads in the process except the current thread either have exited already or have been explicitly terminated by a call to the ExitProcess function, which might leave some process resources such as heaps in an inconsistent state. In this case, it is not safe for the DLL to clean up the resources. Instead, the DLL should allow the operating system to reclaim the memory.

If you terminate a process by calling TerminateProcess or TerminateJobObject, the DLLs of that process do not receive DLL_PROCESS_DETACH notifications. If you terminate a thread by calling TerminateThread, the DLLs of that thread do not receive DLL_THREAD_DETACH notifications.

The entry-point function should perform only simple initialization or termination tasks. It must not call the LoadLibrary or LoadLibraryEx function (or a function that calls these functions), because this may create dependency loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code. Similarly, the entry-point function must not call the FreeLibrary function (or a function that calls FreeLibrary) during process termination, because this can result in a DLL being used after the system has executed its termination code.

Because Kernel32.dll is guaranteed to be loaded in the process address space when the entry-point function is called, calling functions in Kernel32.dll does not result in the DLL being used before its initialization code has been executed. Therefore, the entry-point function can call functions in Kernel32.dll that do not load other DLLs. For example, DllMain can create synchronization objects such as critical sections and mutexes, and use TLS. Unfortunately, there is not a comprehensive list of safe functions in Kernel32.dll.

Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other system components. Conversely, calling functions such as these during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized.

Because DLL notifications are serialized, entry-point functions should not attempt to communicate with other threads or processes. Deadlocks may occur as a result.

For information on best practices when writing a DLL, see http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx.

If your DLL is linked with the C run-time library (CRT), the entry point provided by the CRT calls the constructors and destructors for global and static C++ objects. Therefore, these restrictions for DllMain also apply to constructors and destructors and any code that is called from them.

Examples

For an example, see Dynamic-Link Library Entry-Point Function.

Requirements

Minimum supported client

Windows XP

Minimum supported server

Windows Server 2003

See also

Dynamic-Link Library Entry-Point Function
Dynamic-Link Library Functions
FreeLibrary
GetModuleFileName
LoadLibrary
TlsAlloc
TlsFree

 

 

Send comments about this topic to Microsoft

Build date: 5/5/2012

Did you find this helpful?
(1500 characters remaining)
Community Additions ADD
How can DllMain be a placeholder?
This statement:$0 "The name DllMain is a placeholder for a user-defined function. You must specify the actual name you use when you build your DLL. For more information, see the documentation included with your development tools"$0 $0 is rather misleading, and appears to be contradicted in this MSDN artcile entitled "Initializing a DLL$0 " (http://msdn.microsoft.com/en-us/library/7h0a8139.aspx):$0 $0 "The C run-time library provides an entry-point function called _DllMainCRTStartup, and it calls DllMain. Depending on the type of DLL, you should have a function called DllMain in your source code or you should use the DllMain provided in the MFC library."$0 $0 After much research and trials, it is clear that the standard name for automatic initialization by Windows is "DllMain". This name is called for 4 reasons as explained in this article. It would be useful if an expert could clarify why the "placeholder" statement is made. All advice in MSDN forums states that the "DllMain" entry point is required if one wants Windows to call it automatically.$0 $0$0 $0 $0<hr>$0 $0$0 $0 $0This is no contradiction.  The Windows documentation tells you to check your compiler documentation for the real name, since it is chosen by the compiler vendor and might not be "DllMain".  The Visual C++ compiler documentation tells you that Microsoft libraries assume the name "DllMain" for the user-provided library initialization function.  Only if you used a different compiler would you need to be concerned about a different name.$0
7/7/2011
64 bit: bug either in code or documentation!
<removed>
3/3/2011
Cannot get rid of automatic DllMain
Hello All,

When I try to set a custom entry point, declaring and defining my own DllMain, I get the following: "_DllMain@12 already defined "

It seems that the MFC provides me with its own version of DllMain. Is there any way to disable that and use only mine?

Thanks.

Ivan
1/28/2011
A basic, working DLL and Test Application. Built under VC++ 2010 Express
Here is a functioning DLL and test application.
DLL:
-----------------------------------------------------------------------------

/*This works!!!
But:
1) Sometimes it gives a multiple definition error for DllMain. Why is not clear!
2) This DLL code requires NO header file and no entry point must be specified to the linker.
*/
//Based on MS Website for DLL Main for VS2010
// Access to std::cout and std::endl
#include <windows.h>
#include <iostream>
#define DECLDIR __declspec(dllexport)
int addmore=5;
// Get rid of name mangling
extern "C"
{
// Define our 2 functions
// Add will return the sum of two numbers
DECLDIR int MyAdd( int a, int b )
{
return( a + b+ addmore);
}
// Function will print out a text string
DECLDIR void MyFunction( void )
{
std::cout << "cout from the LouDLLMain MyFunction!" << std::endl;
}
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved )
{
addmore=10;
MessageBox(0, TEXT("stuff"), TEXT( "more stuff"), 0);
std::cout << "Hello from LoudDLL!!" << std::endl;
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
-------------------------------------------
Test Application:

//Note: No properties need to be added to be able to compile and link this program
// LOADING DLLS THE HARD(ER) WAY (Dynamic Loading)
#include <iostream>
// Need Windows.h for HINSTANCE and DLL Loading and Releasing functions.
#include <windows.h>
// Function pointers that will be used for the DLL functions.
typedef int (*AddFunc)(int,int);
typedef void (*FunctionFunc)();
// Must have a main function
int main()
{
// Typedef functions to hold what is in the DLL
AddFunc _AddFunc;
FunctionFunc _FunctionFunc;
// The Instance of the DLL.
// LoadLibrary used to load a DLL
HINSTANCE hInstLibrary = LoadLibrary(TEXT("LousDLL.dll"));
if (hInstLibrary)
{
// Our DLL is loaded and ready to go.
// Set up our function pointers.
_AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "MyAdd");
_FunctionFunc = (FunctionFunc)GetProcAddress(hInstLibrary, "MyFunction");
// Check if _AddFunc is currently holding a function, if not don't run it.
if (_AddFunc)
{
std::cout << "23 + 43 = " << _AddFunc(23, 43) << std::endl;
}
// Check if _FunctionFunc is currently holding a function, if not don't run it.
if (_FunctionFunc)
{
_FunctionFunc();
}
// We're done with the DLL so we need to release it from memory.
FreeLibrary(hInstLibrary);
}
else
{
// Our DLL failed to load!
std::cout << "DLL Failed To Load!" << std::endl;
}
// Wait for the user to press enter to exit
std::cin.get();
return 0;
}

-----------------------------------------------------------------------------

12/13/2010
Loading the library of DllMain in DllMain

It is stated that loadlibrary should not be called from inside Dllmain.
But what if you load the library of Dllmain.
I don't think that would cause problems, because it is already loaded (more or less).
I would really like to know if this is correct.

(you might wonder why:
to ensure that a dll injected by setwindowhookex does not
unload if the injecting program closes/hangs. That can
be usefull if you use that dll for apihooking.)

12/1/2009
Do not use the CRT in DllMain if possible!
It is also a bad idea to use CRT function in DllMain, whether directly or indirectly by using static initializers. Some CRT functions require Kernel calls that use LoadLibrary internally. You may face deadlocks under some circumstances if you use CRT functions in multi threaded programs. An example of such race condition: using LoadLibrary on a DLL that uses getenv() in the static context/DllMain (singleton) while another thread is using stat(). For reference see http://blog.barthe.ph/2009/07/30/no-stdlib-in-dllmai/


8/31/2009
Limits
For example, they are limits with threads synchronization, which can generate deadlocks. This is due to the fact that calls to DllMain are serialized :
http://blogs.msdn.com/oldnewthing/archive/2007/09/04/4731478.aspx
4/21/2009
Additional information

This article does not adequately explain up-front why there are limits to what can be performed within DllMain ().

Sources for detailed explanations:

1 - Microsoft Press book "Programming Applications for MS Windows", 4th Ed, by Jeffrey Richter, Chapter 20.


2 - Microsoft Support Article ID 177917 titled "Initializing a DLL Using DLLMain Optional Entry Point":

http://support.microsoft.com/kb/177917

12/13/2008
Agreed.
A named mutex is better than the file idea.
Don't use "file" kludge
"Alternatively, the initialization routine can create a file with an ACL that restricts access, and each routine in the DLL would call the initialization routine if the file does not exist."

Such kludge should be discouraged; it's bad enough that such suggestion is even made. It won't work if other processes are using the same DLL; also if the app is terminated without cleanup, or the OS fails, the file won't be deleted. There are other more robust methods for that.
5/8/2008