如何使用 mingw 编译和 link 最小的 .NET C++ 程序

How to compile and link a minimal .NET C++ program using mingw

我正在尝试编译 .NET C++ 代码的最小示例(只需调用 CLRCreateInstance 并启动 CLR 运行时主机)。我没有使用 Visual Studio,而是使用 mingw。我安装了 Windows 10 SDK with .NET goodies,并且我在 Program Files 中正确安装了头文件和 lib 文件。但是,我无法让 g++ 进入 link 我的程序:

$ g++ -o clr.exe -I"C:\Program Files (x86)\Windows Kits\NETFXSDK.8\Include\um" -L"C:\Program Files (x86)\Windows Kits\NETFXSDK.8\Lib\um\x64" -lmscoree clr.cpp
C:\Users\XXX\AppData\Local\Temp\cciBbZmZ.o:clr.cpp:(.text+0x3d): undefined reference to `_GUID const& __mingw_uuidof<ICLRMetaHost>()'
C:\Users\XXX\AppData\Local\Temp\cciBbZmZ.o:clr.cpp:(.text+0x4f): undefined reference to `CLRCreateInstance'
C:\Users\XXX\AppData\Local\Temp\cciBbZmZ.o:clr.cpp:(.text+0x78): undefined reference to `_GUID const& __mingw_uuidof<ICLRRuntimeInfo>()'
C:\Users\XXX\AppData\Local\Temp\cciBbZmZ.o:clr.cpp:(.text+0xb3): undefined reference to `_GUID const& __mingw_uuidof<ICLRRuntimeHost>()'
collect2.exe: error: ld returned 1 exit status

程序是:

#include <iostream>
#include <Windows.h>
#include <metahost.h>
#include <mscoree.h>

#pragma comment(lib, "mscoree.lib")

int main()
{

    HRESULT hr;
    ICLRMetaHost *pMetaHost = NULL;
    ICLRRuntimeInfo *pRuntimeInfo = NULL;
    ICLRRuntimeHost *pClrRuntimeHost = NULL;

    // build runtime
    hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
    hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));
    hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost,
        IID_PPV_ARGS(&pClrRuntimeHost));

    // start runtime
    hr = pClrRuntimeHost->Start();

    hr = pClrRuntimeHost->Stop();
}

经过以下两个更正,我终于让它工作了:

  1. 我从 vanilla MinGW 切换到 msys2 打包的。这解决了对 CLRCreateInstance 的未定义引用,我不知道为什么 vanilla MinGW 失败了。这基本上包括下载 msys2 和 运行ning pacman -S mingw-w64-x86_64-gcc.

  2. 感谢 this question 我能够解决其他三个未定义的引用。我仍然不确定所有这些 COM 是如何工作的,所以不幸的是我不确定这是否是解决问题的正确方法,或者我是否只是引入了一个致命错误但是好吧......我进入了 mscoree.hmetahost.h 在 .NET SDK 安装目录中,并查找链接器抱怨的内容。

例如,在mscoree.h中我发现:

EXTERN_GUID(IID_ICLRRuntimeHost, 0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02);

所以我转到我的 clr.cpp 文件并添加:

__CRT_UUID_DECL(ICLRRuntimeHost, 0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02);

这似乎工作得很好。对其他两个做了同样的事情,我的代码进入了这个,它编译并且 运行 没有错误:

#include <Windows.h>
#include <metahost.h>
#include <mscoree.h>
#include <cstdio>

__CRT_UUID_DECL(ICLRMetaHost,    0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16);
__CRT_UUID_DECL(ICLRRuntimeInfo, 0xBD39D1D2, 0xBA2F, 0x486a, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91);
__CRT_UUID_DECL(ICLRRuntimeHost, 0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02);

int main(int argc, char *argv[])
{
    HRESULT hr;
    ICLRMetaHost *pMetaHost = NULL;
    ICLRRuntimeInfo *pRuntimeInfo = NULL;
    ICLRRuntimeHost *pClrRuntimeHost = NULL;

        // build runtime
    if (CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)) != S_OK) {
        printf("[x] Error: CLRCreateInstance(..)\n");
        return 2;
    }

    if (pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)) != S_OK) {
        printf("[x] Error: GetRuntime(..)\n");
        return 2;
    }
    
    if (pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost)) != S_OK) {
        printf("[x] Error: GetInterface(..)\n");
        return 2;
    }

    // start runtime
    if (pClrRuntimeHost->Start() != S_OK) {
        printf("[x] Error: Start(..)\n");
        return 2;
    }

    // start runtime
    if (pClrRuntimeHost->Stop() != S_OK) {
        printf("[x] Error: Stop(..)\n");
        return 2;
    }

    printf("success!\n");
    return 0;

}