在軟體保護、安裝包製作、單檔案部署等場景中,常需將一個完整的可執行檔 (EXE) 作為資源內嵌到主程式中,運行時釋放到磁碟並執行。本文示範在 C++ Builder 中使用自訂資源 (RCDATA/CUSTOM) 內嵌 write.exe (寫字板),並透過 FindResource/LoadResource/LockResource API 釋放重建的完整流程。
CUSTOM) 資源導入,指定資源 ID (如 1111)。ShellExecute 或 CreateProcess 啟動。
// 資源定義 (在 .rc 檔或 IDE 資源管理器中添加)
// CUSTOM 1111 "write.exe" // 類型 CUSTOM, ID 1111, 來源檔案
#include <windows.h>
void ExtractAndRunEmbeddedExe() {
// 1. 定位資源
HRSRC hRes = FindResource(
(HMODULE)GetModuleHandle(NULL), // 當前模組句柄
MAKEINTRESOURCE(1111), // 資源 ID
"CUSTOM" // 資源類型
);
if (!hRes) {
ShowMessage("找不到資源: " + SysErrorMessage(GetLastError()));
return;
}
// 2. 載入資源到全域記憶體
HGLOBAL hGlobal = LoadResource(NULL, hRes);
if (!hGlobal) {
ShowMessage("載入資源失敗: " + SysErrorMessage(GetLastError()));
return;
}
// 3. 鎖定獲取記憶體指標
LPVOID pData = LockResource(hGlobal);
if (!pData) {
ShowMessage("鎖定資源失敗");
return;
}
// 4. 獲取資源大小
DWORD dwSize = SizeofResource(NULL, hRes);
if (dwSize == 0) {
ShowMessage("資源大小為 0");
return;
}
// 5. 寫入磁碟檔案
AnsiString outPath = "C:\\Temp\\MyWriter.exe"; // 實際應用用 GetTempPath
HANDLE hFile = CreateFile(
outPath.c_str(), GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
ShowMessage("建立檔案失敗: " + SysErrorMessage(GetLastError()));
return;
}
DWORD dwWritten;
if (!WriteFile(hFile, pData, dwSize, &dwWritten, NULL) || dwWritten != dwSize) {
ShowMessage("寫入檔案失敗或不完整");
} else {
ShowMessage("釋放成功: " + outPath);
// 6. 執行釋放的程式
ShellExecute(Handle, "open", outPath.c_str(), NULL, NULL, SW_SHOW);
}
CloseHandle(hFile);
// 無需 UnlockResource/FreeResource (LoadResource 記憶體由系統管理)
}
| API | 用途 | 注意事項 |
|---|---|---|
FindResource | 在模組資源表中查找資源目錄項 | 類型名區分大小寫;MAKEINTRESOURCE 用於整數 ID |
LoadResource | 載入資源數據到全域堆疊,返回 HGLOBAL | 不增加引用計數;資源數據在模組卸載前常駐 |
LockResource | 將 HGLOBAL 轉為實際記憶體指標 | 不可呼叫 UnlockResource (已過時);指標有效直到模組卸載 |
SizeofResource | 獲取資源原始大小 (位元組) | 必須用於 WriteFile 長度參數 |
.res 檔再鏈接。若不想寫入磁碟,可在記憶體中直接映射 PE 映像並建立進程 (所謂 RunPE 技術):
CREATE_SUSPENDED)。WriteProcessMemory)。ResumeThread)。「資源內嵌 EXE + 運行時釋放」是單檔案部署、安裝程式生成器、軟體護盾殼的基礎技術。C++ Builder 透過標準 Windows 資源 API 即可輕松實現。關鍵在於資源編輯器正確導入二進位資料,以及釋放時精確控制檔案路徑、權限與清理策略。