Each dll can have an entry point function dllmain, which will be called at different times. The following is the general form of dllmain:
Bool winapi dllmain (hinstance hinstdll, // handle to DLL module DWORD fdwreason, // reason for calling function lpvoid lpreserved) // reserved {// perform actions based on the reason for calling. switch (fdwreason) {Case dll_process_attach: // initialize once for each new process. // return false to fail DLL load. break; Case dll_thread_attach: // do thread-specific initialization. break; Case dll_thread_detach: // do thread-specific cleanup. break; Case dll_process_detach: // perform any necessary cleanup. break;} return true; // successful dll_process_attach .}
AboveCodeFrom msdn, almost all dllmain is presented in this form.
Let's take a look at the parameters passed in by this function:
1. hinstance hinstdll
This parameter is the handle of the DLL instance, that is, the location of the DLL mapped to the process address space in the process address space.
2. DWORD fdwreason
This parameter indicates the reason for calling the dllmain function. There are four values, that is, the value after case in the function. The meaning of each value, which will be discussed later.
3. lpvoid lpreserved
Retained.
Now let's discuss the four values of fdwreason, which directly reflect the circumstances in which the operating system will call dllmain.
1. dll_process_attach
When the system maps a DLL to the process address space for the first time, it will call dllmain and pass in dll_process_attach for fdwreason.
Note that this is only true for the first ing. For example, if another thread explicitly loads the DLL again, the operating system only increases the usage count of the DLL and does not use dll_process_attach to call dllmain again.
The processing of dll_process_attach represents the DLL initialization.
The returned value of dllmain is also for the dll_process_attach message. It does not work for the other three values.
For implicit loading, if dllmain returns falseProgramIt fails to start. For explicit loading, the loadlibrary returns NULL.
2. dll_process_detach
When the system revokes a DLL ing from the process address space, it will pass in dll_process_detach to dllmain. We should place some cleanup code here.
When freelibrary is used, if the usage count of this thread is 0, the operating system uses dll_process_detach to call dllmain. If the count is greater than 0, the DLL count is simply reduced.
3. dll_thread_attach
When a process creates a thread, the system checks the currentMappedTo all DLL images in the process space, and use dll_thread_attach to call the dllmain of each DLL.
The new thread will execute its thread function only when all the DLL has completed the processing of dll_thread_attach.
In addition, the main thread cannot use dll_thread_attach to call dllmain, because the main thread must use dll_process_attach to call dllmain during process initialization.
4. dll_thread_detach
If the thread is to terminate, exitthread is called, but this function does not terminate the thread immediately. Instead, it uses dll_thread_detach to call the dllmain of all DLL images in the current process address space.
After the dllmain of each DLL is processed, the system will actually end the thread.
Finally, let's take a look at the serialization call of dllmain.
For example:
There are two threads in the process: A and B. A dll named somedll. dll is mapped to the process address space. Both threads are going to use createthread to create the other two threads, C and D.
When thread a calls createthread to create thread C, the system uses dll_thread_attach to call somedll. DLL dllmain. When thread C executes the code, thread B calls createthread to create thread D.
At this time, the system will also use dll_thread_attach to call the dllmain of somedll. dll. This time, let thread D execute the code in it.
However, the system will serialize the dllmain, And it will suspend thread d Until thread C finishes executing the code returned in the dllmain.
When the C thread executes the code in dllmain and returns the code, it can continue to execute the C thread function. At this time, the system will wake up thread D and let d execute the code in dllmain. After the return value, thread D starts to execute the thread function.