安裝程式、啟動器或自動更新工具常需在不重新編譯的情況下替換目標 EXE 的圖示資源。Windows 提供 BeginUpdateResource / UpdateResource / EndUpdateResource 三大 API 實現資源修改。
LoadLibrary 載入來源 EXE(含目標圖示)。FindResource / LoadResource / LockResource 取得圖示資源指標與大小。BeginUpdateResource 開啟目標 EXE 寫入模式(bDeleteExistingResources = FALSE 保留其他資源)。UpdateResource 寫入圖示群組(RT_GROUP_ICON)。EndUpdateResource 提交變更。void ReplaceExeIcon(LPCTSTR srcExe, LPCTSTR dstExe, WORD srcIconId, WORD dstIconId)
{
HMODULE hSrc = LoadLibraryEx(srcExe, NULL, LOAD_LIBRARY_AS_DATAFILE);
if (!hSrc) { AfxMessageBox(_T("載入來源 EXE 失敗")); return; }
HRSRC hRes = FindResource(hSrc, MAKEINTRESOURCE(srcIconId), RT_GROUP_ICON);
if (!hRes) { AfxMessageBox(_T("找不到來源圖示資源")); FreeLibrary(hSrc); return; }
HGLOBAL hResLoad = LoadResource(hSrc, hRes);
LPVOID pData = LockResource(hResLoad);
DWORD dwSize = SizeofResource(hSrc, hRes);
HANDLE hUpdate = BeginUpdateResource(dstExe, FALSE);
if (!hUpdate) { AfxMessageBox(_T("無法開啟目標 EXE 寫入")); FreeLibrary(hSrc); return; }
BOOL ok = UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(dstIconId),
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), pData, dwSize);
if (!ok || !EndUpdateResource(hUpdate, FALSE))
AfxMessageBox(_T("資源更新失敗"));
else
AfxMessageBox(_T("圖示替換成功!"));
FreeLibrary(hSrc);
}
// 使用範例:將 a.exe 的 IDI_ICON1 替換到 switch.exe 的 IDR_MAINFRAME
ReplaceExeIcon(_T("a.exe"), _T("switch.exe"), IDI_ICON1, IDR_MAINFRAME);
LOAD_LIBRARY_AS_DATAFILE 載入,避免執行其入口點。RT_GROUP_ICON,而非單一 RT_ICON,否則多解析度圖示會損壞。BeginUpdateResource 會失敗(ERROR_ACCESS_DENIED)。UpdateResource 並指定不同 dstIconId。| 錯誤 | 原因 |
|---|---|
| ERROR_RESOURCE_DATA_NOT_FOUND | 來源資源 ID/類型錯誤 |
| ERROR_ACCESS_DENIED | 目標檔案被鎖定或無寫入權限 |
| ERROR_BAD_EXE_FORMAT | 目標非有效 PE 檔案 |