標籤:c style class blog code java
DLL相關的東西
1、DLL的載入方式
隱式:
#pragma comment(lib, "XX.lib");
編譯器去尋找名為XX.dll的DLL,除了名字相同,該DLL和該LIB的GUID也相同。
顯式:
HINSTANCE hInst = LoadLibrary(TEXT("XX.dll"));
if(NULL == hInst) retrun;
HINSTANCE hInst = LoadLibrary(TEXT("XX.dll"), NULL, FLAGS);
第三個參數為一些標誌,詳見核心編程。
2、DLL的入口函數
原型
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
);
其中hModule為該DLL在當前進程地址空間中的位置,ul_reason_for_call為調用此函數的原因,lpReserved如果為明確式載入則為0,如果為隱式載入則為非0。
詳細說一下ul_reason_for_call
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){#ifdef _DEBUG switch (ul_reason_for_call) { //只在該DLL第一次載入進地址空間的時候被調用一次 //此後當該DLL被載入進不同進程的地址空間時讓然不調用 //當主調線程通過該reason調用DllMain函數時,主調線程不會收到DLL_THREAD_ATTACH通知 case DLL_PROCESS_ATTACH: OutputDebugString(TEXT("\r\n***********B Dll DLL_PROCESS_ATTACH ***********\r\n")); break; //當該DLL已經被載入到進程地址空間後,當有新【線程建立】的時候,新建立的線程先執行此段代碼 //然後再去執行線程本身的代碼 //不管有幾個DLL,每個DLL的此處代碼都會被新線程執行 case DLL_THREAD_ATTACH: OutputDebugString(TEXT("\r\n***********B Dll DLL_THREAD_ATTACH ***********\r\n")); break; //當該DLL已經被載入到進程地址空間後,當有【線程結束】的時候,該線程結束之前會調用此處代碼 //然後才返回 //不管有幾個DLL,每個DLL的此處代碼都會被執行 case DLL_THREAD_DETACH: OutputDebugString(TEXT("\r\n***********B Dll DLL_THREAD_DETACH *********** \r\n")); break; //只有在該DLL從記憶體中卸載的時候才會被調用一次 case DLL_PROCESS_DETACH: OutputDebugString(TEXT("\r\n***********B Dll DLL_PROCESS_DETACH ***********\r\n")); break; }#endif return TRUE;}
demo
有兩個DLL, ADll.dll 和 BDll.dll
在程式中載入這個兩個DLL, 然後建立一個新線程,看輸出
//載入DLLvoid CUseABDllDlg::OnBnClickedBtnLoadlib(){ HINSTANCE hInstA = LoadLibrary(_T("ADll.dll")); HINSTANCE HIntB = LoadLibrary(_T("BDll.dll")); if (NULL == hInstA || NULL == HIntB) { AfxMessageBox(_T("載入DLL失敗")); return; } }//線程函數UINT WINAPI WorkThread(LPVOID lpParam){#ifdef _DEBUG OutputDebugString(TEXT("\r\n&&&&&&&&&&&&&&&&&&線程被建立&&&&&&&&&&&&&&&&&\r\n"));#endif return 0U;}//建立線程void CUseABDllDlg::OnBnClickedButton2(){ HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, WorkThread, NULL, 0, NULL); if (NULL == hThread || INVALID_HANDLE_VALUE == hThread) { AfxMessageBox(_T("建立線程失敗")); }}
輸出
結論:
每建立一個新線程,當前進程地址空間中的DLL的DllMain函數都會通過DLL_THREAD_ATTACH通知被調用一次
每結束一個線程,進程地址空間空的DLL的DllMain函數都會通過DLL_THREAD_DETACH通知被調用一次。