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

EXE 與 DLL 中 FindResource 差異深度解析:為什麼 DLL 返回 NULL?

     編輯:關於VC++

問題現象

同一段資源提取代碼在 EXE 中運行正常,移植到 DLL 後 FindResource 返回 NULL,GetLastError() 返回 1813 (ERROR_RESOURCE_TYPE_NOT_FOUND)。

根因:模組句柄不同

場景正確 hModule錯誤用法
EXE 進程NULL (當前進程)通常無問題
DLL 內部GetModuleHandle(_T("MyDll.dll")) 或 &__ImageBase傳 NULL → 搜索宿主 EXE,而非 DLL 自身

修正後的通用資源提取函數

BOOL ExtractResourceToFile(LPCTSTR szDstPath, WORD wResourceID, LPCTSTR szResType = _T("ZLIB"))
{
    // 1. 獲取當前模組句柄(支援 EXE/DLL 通用)
    HMODULE hMod = GetModuleHandle(NULL);  // EXE 正確,DLL 錯誤!
    // 修正:在 DLL 中應用以下任一方式:
    // HMODULE hMod = GetModuleHandle(_T("MyDllName.dll"));  // 需知 DLL 名稱
    // HMODULE hMod = (HMODULE)&__ImageBase;                  // 推薦:編譯器內置,無需硬編碼名稱
    
    // 2. 定位資源
    HRSRC hRsrc = FindResource(hMod, MAKEINTRESOURCE(wResourceID), szResType);
    if (!hRsrc)
    {
        DWORD err = GetLastError();
        TRACE(_T("[ExtractResource] FindResource 失敗,錯誤碼: %u, 模組句柄: %p\n"), err, hMod);
        return FALSE;
    }
    
    // 3. 加載並鎖定資源
    HGLOBAL hGlobal = LoadResource(hMod, hRsrc);
    if (!hGlobal) return FALSE;
    
    DWORD dwSize = SizeofResource(hMod, hRsrc);
    LPVOID pData = LockResource(hGlobal);
    if (!pData) return FALSE;
    
    // 4. 寫入文件
    HANDLE hFile = CreateFile(szDstPath, GENERIC_WRITE, 0, NULL, 
                              CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
    
    DWORD dwWritten = 0;
    BOOL bRet = WriteFile(hFile, pData, dwSize, &dwWritten, NULL);
    CloseHandle(hFile);
    
    return bRet && (dwWritten == dwSize);
}

關鍵技術點

1. &__ImageBase 技巧

  • MSVC 內置符號,表示當前模組(EXE 或 DLL)的基地址
  • 無需硬編碼 DLL 名稱,自動適配重命名/延遲加載場景
  • 需在 cpp 文件中聲明:extern "C" IMAGE_DOS_HEADER __ImageBase;

2. 資源 ID 類型

  • 整數 ID:MAKEINTRESOURCE(wID) (wID ≤ 65535)
  • 字符串 ID:直接傳 LPCTSTR 指針

3. 資源類型

自定義類型(如 "ZLIB"、"MYDATA")需在 .rc 文件中一致聲明:

// resource.rc
IDR_ZLIB1    ZLIB    "data.zlib"
IDR_ZLIB2    ZLIB    "data2.zlib"

調試檢查清單

  1. ☐ 確認資源已編譯進目標模組(VS 資源視圖 / dumpbin /resources)
  2. ☐ 確認 hMod 指向包含資源的模組(DLL 內部勿用 NULL)
  3. ☐ 確認資源類型字符串大小寫完全匹配("ZLIB" ≠ "zlib")
  4. ☐ 確認資源 ID 未衝突(自定義資源建議 ID > 0x8000 避開系統保留)

延伸:MFC 專用簡化寫法

// 僅限 MFC 專案,AfxFindResourceHandle 自動搜尋資源鏈
HINSTANCE hResInst = AfxFindResourceHandle(MAKEINTRESOURCE(wID), szResType);
HRSRC hRsrc = FindResource(hResInst, MAKEINTRESOURCE(wID), szResType);
// 後續流程相同...
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved