You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 11:30:43