http://support.microsoft.com/kb/148791/en-us
Additional care must be taken when relying on DllMain being called with DLL_THREAD_ATTACH and DLL_THREAD_DETACH because of the following conditions:
- When a thread is created in a process, the system calls DllMain with a value of DLL_THREAD_ATTACH for each of the DLLs mapped into into the process. However, if a process has several threads running in it when a new DLL is mapped
into it, DllMain isn't called with a DLL_THREAD_ATTACH value for any of the existing threads. - 不会因为进程中已有的线程调用DLL_THREAD_ATTACH
- DllMain is not called with a value DLL_THREAD_ATTACH for the process's primary thread.
- 进程的主线程不调用DLL_THREAD_ATTACH
- On thread termination (by a call to ExitThread), DllMain is called with a value of DLL_THREAD_DETACH for each of the DLLs. DllMain is not called with DLL_THREAD_DETACH for any thread unless a thread terminates by calling ExitThread.
- 线程以ExitThread结束,不调用DLL_THREAD_DETACH
- If a thread terminates due to a call to TerminateThread, DllMain isn't called with a value DLL_THREAD_DETACH.
- 线程以TerminateThread结束,不调用DLL_THREAD_DETACH
- It is possible for a thread in a process to call LoadLibrary to load a DLL causing a call to DllMain with DLL_PROCESS_ATTACH, and then on thread termination, cause a call to dllMain with DLL_THREAD_DETACH without ever calling DLL_THREAD_ATTACH.
It is therefore best that the thread that calls LoadLibrary also call FreeLibrary. - 如果非主线程调用LoadLibrary ,FreeLibrary,则DLL_PROCESS_ATTACH,DLL_THREAD_DETACH ,而没有DLL_THREAD_ATTACH
NOTE: MFC CWnd objects, CDC objects, CMenu objects, GDI objects, and CImageList objects are restricted to a per-thread, per-module basis. In other words, MFC objects created in one module or thread cannot be passed to and/or used in a different module or thread.
This has special relevance for any code added to handle DLL_THREAD_ATTACH or DLL_THREAD_DETACH in DllMain because DllMain is called for these reasons with different threads. CWnd objects, for instance, created in DllMain during DLL_PROCESS_ATTACH or in InitInstance
will not be valid during DLL_THREAD_ATTACH.
Sample Code
//////////////////////////////////////////////////////////////////// // export DllMain for the DLL // Add code in the specified sections only. // Remove code at your own risk. extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) { if (dwReason == DLL_PROCESS_ATTACH) { // ... Code abbreviated from DLLMODUL.CPP } else if (dwReason == DLL_PROCESS_DETACH) { // ... Code abbreviated from DLLMODUL.CPP } // NEW CODE ADDED HERE // ------------------- else if (dwReason == DLL_THREAD_ATTACH) { #ifdef _AFXDLL // set module state ASSERT(AfxGetThreadState()->m_pPrevModuleState == NULL); AfxGetThreadState()->m_pPrevModuleState = AfxSetModuleState(AfxGetStaticModuleState()); #endif // ADD DLL_THREAD_ATTACH CODE HERE // Remember that this won't necessarily be called for // every thread in the process into which this DLL is mapped // Threads created by the process BEFORE the DLL // was loaded will not call into DLL_THREAD_ATTACH. #ifdef _AFXDLL // restore previously-saved module state VERIFY(AfxSetModuleState(AfxGetThreadState()->m_pPrevModuleState) == AfxGetStaticModuleState()); DEBUG_ONLY(AfxGetThreadState()->m_pPrevModuleState = NULL); #endif } else if (dwReason ==DLL_THREAD_DETACH) { #ifdef _AFXDLL // set module state ASSERT(AfxGetThreadState()->m_pPrevModuleState == NULL); AfxGetThreadState()->m_pPrevModuleState = AfxSetModuleState(AfxGetStaticModuleState()); #endif // ADD DLL_THREAD_DETACH CODE HERE #ifdef _AFXDLL // restore previously-saved module state VERIFY(AfxSetModuleState(AfxGetThreadState()->m_pPrevModuleState) == AfxGetStaticModuleState()); DEBUG_ONLY(AfxGetThreadState()->m_pPrevModuleState = NULL); #endif } return TRUE; }