同一段資源提取代碼在 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);
}
&__ImageBase 技巧extern "C" IMAGE_DOS_HEADER __ImageBase;MAKEINTRESOURCE(wID) (wID ≤ 65535)LPCTSTR 指針自定義類型(如 "ZLIB"、"MYDATA")需在 .rc 文件中一致聲明:
// resource.rc
IDR_ZLIB1 ZLIB "data.zlib"
IDR_ZLIB2 ZLIB "data2.zlib"
dumpbin /resources)hMod 指向包含資源的模組(DLL 內部勿用 NULL)"ZLIB" ≠ "zlib")// 僅限 MFC 專案,AfxFindResourceHandle 自動搜尋資源鏈
HINSTANCE hResInst = AfxFindResourceHandle(MAKEINTRESOURCE(wID), szResType);
HRSRC hRsrc = FindResource(hResInst, MAKEINTRESOURCE(wID), szResType);
// 後續流程相同...