将托管程序合并到非托管C ++可执行文件中

时间:2014-10-01 14:20:28

标签: c# c++ windows native

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

  • 是否可以将托管的.exe合并为非托管的.exe文件?

有很多关于做事情的信息(将非托管代码合并到托管项目中),但我还没有找到任何关于朝另一个方向发展的事情。

背景:

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

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

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

ILMerge doesn't accept unmanaged code...

我可以将我的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我现在正在调查它。

1 个答案:

答案 0 :(得分:2)

我设法通过使用资源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
  • 配置属性&gt;常规&gt;平台工具集设置为&#34; Visual Studio 2013 - Windows XP(x120_xp)&#34;
  • 配置属性&gt; C / C ++&gt;代码生成&gt;运行时库设置为&#34;多线程(/ MT)