首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC++ DLL 編程讀者問答:隱式連結 DLL 路徑、DLL 多線程實作

     編輯:VC 教學

問題一:隱式連結時 .dll 路徑如何指定?

答:隱式連結**無法在代碼中指定 DLL 路徑**。Windows 載入器按固定順序搜尋:

  1. 應用程式執行檔所在目錄
  2. 當前工作目錄
  3. 系統目錄 (GetSystemDirectory,通常 C:\Windows\System32)
  4. Windows 目錄 (GetWindowsDirectory)
  5. PATH 環境變數列出的目錄

對策:將 DLL 放在 EXE 同目錄 (最推薦) 或系統目錄。若需自定路徑,必須改用 顯式連結 (LoadLibrary 指定完整路徑)。

問題二:DLL 中能否使用多線程?

答:完全可以。多線程是 OS 能力,與程式類型 (EXE/DLL) 無關。DLL 內建立線程與 EXE 相同。

DLL 多線程範例 (UDP 發送執行緒)

// DLL 全域
CEvent g_hSendEvent; // 手動重置事件
SOCKET g_sendSock = INVALID_SOCKET;

// 發送線程函數
DWORD WINAPI SendThreadFunc(LPVOID) {
    g_sendSock = socket(AF_INET, SOCK_DGRAM, 0);
    sockaddr_in dest = {AF_INET, htons(DEST_PORT), inet_addr(DEST_IP)};
    while (1) {
        WaitForSingleObject(g_hSendEvent, INFINITE); // 等待觸發
        g_hSendEvent.ResetEvent();
        // 從佇列取資料 sendto...
    }
    closesocket(g_sendSock);
    return 0;
}

// 匯出介面:初始化 (DLL 載入時**不可**建立線程!)
extern "C" __declspec(dllexport) bool Initialize() {
    // 建立線程
    DWORD tid; HANDLE h = CreateThread(NULL, 0, SendThreadFunc, NULL, 0, &tid);
    return h != NULL;
}

// 匯出介面:提交資料觸發發送
extern "C" __declspec(dllexport) void SendData(const char* buf, int len) {
    // 複製資料到佇列...
    g_hSendEvent.SetEvent(); // 喚醒發送線程
}

// 匯出介面:清理 (進程卸載 DLL 時呼叫)
extern "C" __declspec(dllexport) void Cleanup() {
    g_hSendEvent.SetEvent(); // 確保線程退出等待
    // 等待線程結束...
}

關鍵原則:DLL_PROCESS_ATTACH 禁止建立線程

在 DllMain 的 DLL_PROCESS_ATTACH 中建立線程會導致 **死鎖** (載入器鎖)。必須提供顯式 Initialize() 介面讓應用程式在載入完成後呼叫。

一般 DLL (衍生 CWinApp) 線程清理

int CMyDllApp::ExitInstance() {
    // 發送結束信號、等待線程、關閉 Socket
    g_hSendEvent.SetEvent();
    WaitForSingleObject(g_hThread, INFINITE);
    return CWinApp::ExitInstance();
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved