將另一個執行檔(如 WordPad write.exe)作為自訂資源嵌入本程式,運行時解壓寫入磁碟並啟動,是「單一執行檔部署」的經典技巧。本文示範如何在 C++Builder 中使用 Windows Resource API(FindResource、LoadResource、LockResource)讀取內嵌資源並重建為獨立檔案。
write.exe,大小 204,800 位元組)。.res 檔:
CUSTOM(或 RT_RCDATA)1111(自訂整數).res 檔加入專案(Project → Add to Project)。// 資源參數
const DWORD RES_ID = 1111;
const char* RES_TYPE = "CUSTOM";
const DWORD RES_SIZE = 204800; // 預先已知的資源大小
void ExtractEmbeddedExe()
{
HRSRC hMyRes = NULL; // 資源控制代碼
HGLOBAL hgpt = NULL; // 資源記憶體區塊控制代碼
LPVOID lpBuff = NULL; // 資源資料指標
DWORD rcSize = RES_SIZE;
LPDWORD dwByte = &rcSize;
HANDLE hFile = INVALID_HANDLE_VALUE;
// 1. 定位資源
hMyRes = FindResource(
(HMODULE)GetWindowLong(Handle, GWL_HINSTANCE),
MAKEINTRESOURCE(RES_ID),
RES_TYPE
);
if (hMyRes == NULL)
{
ShowMessage("FindResource 失敗: " + SysErrorMessage(GetLastError()));
return;
}
// 2. 載入資源至記憶體
hgpt = LoadResource(NULL, hMyRes);
if (hgpt == NULL)
{
ShowMessage("LoadResource 失敗: " + SysErrorMessage(GetLastError()));
return;
}
// 3. 鎖定資源取得資料指標
lpBuff = LockResource(hgpt);
if (lpBuff == NULL)
{
ShowMessage("LockResource 失敗");
return;
}
// 4. 寫入檔案
try
{
hFile = CreateFile(
"e:\\mywriter.exe",
GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
);
if (hFile == INVALID_HANDLE_VALUE)
throw "CreateFile 失敗";
if (!WriteFile(hFile, lpBuff, rcSize, dwByte, NULL))
throw "WriteFile 失敗";
if (*dwByte != RES_SIZE)
throw "寫入位元組數不符";
ShowMessage("釋放成功: e:\\mywriter.exe");
}
__finally
{
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
// 注意:LoadResource 返回的 HGLOBAL 無需 UnlockResource/FreeResource
// 系統會在模組卸載時自動釋放
}
}
FindResource(hInst, MAKEINTRESOURCE(ID), "CUSTOM")
│
▼ 返回 HRSRC (資源目錄項)
LoadResource(hInst, hMyRes)
│
▼ 返回 HGLOBAL (全域記憶體控制代碼)
LockResource(hgpt)
│
▼ 返回 LPVOID (資料實際位址)
WriteFile(hFile, lpBuff, size, ...)
│
▼ 完成釋放
| 問題 | 原因 | 解決 |
|---|---|---|
| FindResource 返回 NULL | 資源類型/ID 不符、未正確連結 .res | 用 Resource Hacker 打開編譯後的 .exe 驗證資源是否存在 |
| 釋出檔案無法執行 | 資源大小常數 RES_SIZE 與實際不符 | 用 SizeofResource 動態取得大小,勿硬編碼 |
| LockResource 返回資料不全 | 資源未正確對齊或被截斷 | 確認 .res 檔建立時為二進位模式,無額外標頭 |
| 執行釋出檔案報錯 | 目標機缺少相依 DLL(如 MFC、VB6 執行庫) | 確保目標執行檔為獨立靜態連結或附帶相依檔 |
// 替代硬編碼 RES_SIZE
DWORD resSize = SizeofResource(
(HMODULE)GetWindowLong(Handle, GWL_HINSTANCE), hMyRes
);
GetTempPath)較固定路徑安全,用完刪除。掌握「資源內嵌 → 運行時釋放」模式,不僅能實現單一檔案部署,更是理解 Windows 資源管理機制的絕佳切入點。