【问题标题】:Merge managed program into unmanaged C++ Executable将托管程序合并到非托管 C++ 可执行文件中
【发布时间】:2014-10-01 14:20:28
【问题描述】:

我的目标是只有一个可执行文件。

  • 是否可以将托管 .exe 合并到非托管 .exe 中?

有很多关于以相反方式做事的信息(将非托管代码合并到托管项目中),但我找不到任何关于转向另一个方向的信息。

背景:

用于系统要求/兼容性检查器。
我在 .NET 2 中使用 C# 编写了大部分内容。
但是,这部分只有在确定系统至少安装了 .NET 2 时才会运行。
这就是"DotNetVersionIdentifier.exe" 发挥作用的地方。
无论是否安装了 .NET Framework,它的 unmanaged code 都会运行。如果安装了 .NET 2.0 或更高版本,我没有显示已安装 .NET 版本的对话框,而是修改了代码以运行我的 C# 程序,否则报告自定义消息。

  • 我想将 C# 程序打包到 C++ 可执行文件中,这样我只需要分发一个 .exe

我尝试过使用 ILMerge,但由于我的非托管代码无法编译为中间语言,它会崩溃...

我可以将我的 C# 项目添加到 C++ 解决方案中,但它仍会编译为两个单独的可执行文件。

这种方法:How to Append Data to the End of an .EXE File 听起来很吸引人,但已经过时了。

这个想法似乎可行:How to embed an exe inside another exe as a resource and then launch it,我现在正在研究它。

【问题讨论】:

  • 那么您在寻找什么类型的帮助呢?实际上,您可以将文件作为资源添加到托管或本机应用程序,保存并作为您建议的链接运行。
  • 我还没有开始工作,所以我只是试探一下是否有其他/更好的方法。
  • 我仍然不清楚...资源是做标题中要求的直接方式(如果它对您的情况有好处-您的电话)...链接的文章看起来很合理...“我是否应该手动检测是否安装了 .Net 2.0”作为基于意见的主题。
  • 好的,我还在努力。当我开始这次冒险时,这似乎并不简单。问题不是征求意见。我有一个明确的问题,正在寻求解决方案。
  • @AlexeiLevenkov 事实证明,使用资源确实有效。 Kumar 博客上的伪代码需要进行大量调整才能使其正常工作。他还描述了手动将文件添加为资源,这对我来说导致了 VS 中的问题。我已经发布了我的结果。

标签: c# c++ windows native


【解决方案1】:

我设法通过使用资源as outlined here 实现了我的目标。

这是我如何使它工作的。 (我是 C++ 新手,如果您发现任何愚蠢之处,请告诉我)

  • 将托管代码编译为单个文件
  • 将托管代码可执行文件重命名为 .txt
  • 创建一个新的 Visual C++ Win32 控制台应用程序
  • 添加新项目 - 资源文件 (.rc)
  • 打开资源文件,添加资源,选择导入,类型输入“TEXT”
  • 修改“DWORD 大小” 以匹配托管 .txt 文件的大小

其余的可以用代码转储来解释。
希望这会帮助某人(像我这样的 C++ 新手......)

#include "stdafx.h"
#include "resource.h"
#include "windows.h"
#include "iostream"
#include <string>
#include <sstream>

using namespace std;

namespace std
{
    HRSRC hrsrc = NULL;
    HGLOBAL hGlbl = NULL;
    BYTE *pExeResource = NULL;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    DWORD size = 8192; //hardcoding the size of the exe resource (in bytes)
    HINSTANCE g_Handle = NULL;
    HINSTANCE hInstance = NULL; // Passing NULL uses the instance that started the process( CSMerged.exe ).

    template <typename T>
    string NumberToString(T pNumber)
    {
        ostringstream oOStrStream;
        oOStrStream << pNumber;
        return oOStrStream.str();
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    hrsrc = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_TEXT1), _T("TEXT"));
    if (hrsrc == NULL)
    {
        cout << "hrsc is null! \n";
        cin.get(); // leave the console open.
        return FALSE;
    }

    hGlbl = LoadResource(hInstance, hrsrc);
    if (hGlbl == NULL)
    {
        cout << "hGlbl is null! \n";
        cin.get(); // leave the console open.
        return FALSE;
    }

    pExeResource = (BYTE*)LockResource(hGlbl);
    if (pExeResource == NULL)
    {
        cout << "pExeResource is null! \n";
        cin.get(); // leave the console open.
        return FALSE;
    }

    hFile = CreateFile(L"ManagedCode.exe", GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        DWORD bytesWritten = 0;
        WriteFile(hFile, pExeResource, size, &bytesWritten, NULL);
        CloseHandle(hFile);
    }

    PROCESS_INFORMATION pi;
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    int ret = CreateProcess(L"ManagedCode.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

    if (ret == 1) { return 0; } // the process started successfully, so I'm done here.
    else
    {
        cout << "CreatePrecess returns " + NumberToString(ret) + ". \n";
        cin.get(); // leave the console open
    }

    return 0;
}

Resource.h - 这是自动生成的,以及当我使用 VS2013 的 GUI 导入资源时对 Recource.rc 的修改。

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Resource.rc
//
#define IDR_TEXT1                       101

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        102
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

我应该添加一些我必须更改的其他内容才能使其在 Windows XP 上运行:

  • 确保平台目标是 Win32
  • 将配置属性>常规>平台工具集设置为“Visual Studio 2013 - Windows XP (x120_xp)”
  • 将配置属性>C/C++>代码生成>运行时库设置为“多线程(/MT)

【讨论】:

    猜你喜欢
    • 2011-02-12
    • 1970-01-01
    • 2018-03-17
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多