如何在C++中使用资源?VS2019嵌入exe文件实现方法
Visual Studio 2019 下将EXE嵌入C++程序的实现步骤
一、将待嵌入EXE导入为项目资源
- 在解决方案资源管理器中右键你的项目节点,依次选择「添加」-「资源」。
- 在弹出的添加资源窗口点击「导入」,文件筛选器切到「所有文件」,选中你要嵌入的目标EXE后确认。
- 弹出自定义资源类型输入框时,填入自定义类型名(比如
EXE_RES,可自定义,记住这个值后续要用到),确认完成导入。 - 导入后在资源视图中查看该资源的ID(默认命名类似
IDR_EXE_RES1,定义在自动生成的resource.h中,可自行修改),在需要调用资源的代码文件开头引入#include "resource.h"。
若项目未自动关联
resource.h,手动在头文件筛选器下添加现有项,把生成的头文件加进项目即可。
二、运行时释放并运行嵌入的EXE
Windows提供了原生资源操作API,可以直接读取编译后PE文件资源段内的嵌入EXE数据,写入本地磁盘后即可正常启动,这是兼容性最高的实现方案,无额外依赖。
直接复用以下代码即可,核心逻辑都做了错误处理:
#include <Windows.h> #include <string> bool ReleaseExeFromRes(WORD resId, LPCWSTR resType, const std::wstring& savePath, std::wstring& outErr) { HRSRC hResInfo = FindResourceW(nullptr, MAKEINTRESOURCEW(resId), resType); if (!hResInfo) { outErr = L"FindResource failed, err code: " + std::to_wstring(GetLastError()); return false; } HGLOBAL hResData = LoadResource(nullptr, hResInfo); if (!hResData) { outErr = L"LoadResource failed, err code: " + std::to_wstring(GetLastError()); return false; } LPVOID pResBuf = LockResource(hResData); DWORD resSize = SizeofResource(nullptr, hResInfo); if (!pResBuf || resSize == 0) { outErr = L"LockResource/SizeofResource failed"; return false; } HANDLE hOutFile = CreateFileW(savePath.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hOutFile == INVALID_HANDLE_VALUE) { outErr = L"CreateFile failed, err code: " + std::to_wstring(GetLastError()); return false; } DWORD writtenBytes = 0; BOOL writeRet = WriteFile(hOutFile, pResBuf, resSize, &writtenBytes, nullptr); CloseHandle(hOutFile); if (!writeRet || writtenBytes != resSize) { outErr = L"WriteFile failed"; DeleteFileW(savePath.c_str()); return false; } return true; } // 调用示例 int wmain() { wchar_t tmpDir[MAX_PATH] = {0}; GetTempPathW(MAX_PATH, tmpDir); std::wstring tmpExePath = std::wstring(tmpDir) + L"tmp_embedded_app.exe"; std::wstring errMsg; // 注意第二个参数要和你之前自定义的资源类型完全一致,必须是宽字符串 if (ReleaseExeFromRes(IDR_EXE_RES1, L"EXE_RES", tmpExePath, errMsg)) { // 释放成功,启动EXE ShellExecuteW(nullptr, L"open", tmpExePath.c_str(), nullptr, nullptr, SW_SHOWNORMAL); // 如需等待嵌入EXE退出后删除临时文件,替换为CreateProcess创建进程+WaitForSingleObject等待即可 } else { MessageBoxW(nullptr, errMsg.c_str(), L"Release EXE failed", MB_ICONERROR); } return 0; }
常见踩坑点
- 架构必须匹配:如果嵌入的是64位EXE,项目就编译为x64平台;嵌入32位EXE就编译为x86平台,跨架构启动会失败。
- 资源参数不要写错:资源ID必须和
resource.h中定义的一致,自定义资源类型必须传宽字符串(前面加L前缀),这是90%的人调用失败的原因。 - 无文件落地的内存直接加载方案需要手动实现PE映射、重定位、导入表修复,兼容性差,对系统版本和被加载EXE的编译选项有要求,普通需求优先用落地临时目录的方案,稳定无坑。
- 临时文件可以增加清理逻辑:比如程序启动时先清理上次运行遗留的临时文件,或者等嵌入的进程退出后调用
DeleteFileW删除即可。
内容的提问来源于stack exchange,提问作者Star Butterfly
相关产品推荐
相关产品推荐

