melkyades
melkyades

Reputation: 1786

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

I'm trying to compile a minimal example of .NET C++ code (just calling CLRCreateInstance and starting a CLR runtime host). I'm not using Visual Studio, but mingw. I installed the Windows 10 SDK with .NET goodies, and I have the header and lib files correctly installed in Program Files. However, I cannot get g++ to link my program:

$ g++ -o clr.exe -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\Include\um" -L"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.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

the program is:

#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();
}

Upvotes: 1

Views: 1090

Answers (1)

melkyades
melkyades

Reputation: 1786

I finally made it work with the following two corrections:

  1. I switched from vanilla MinGW to an msys2 packaged one. This solved the undefined reference to CLRCreateInstance, which I don't know why was failing with the vanilla MinGW. This basically consisted in downloading msys2 and running pacman -S mingw-w64-x86_64-gcc.

  2. Thanks to this question I was able to solve the other three undefined references. I'm still not sure how all these COM things work, so unfortunately I'm not sure if this is the right way to solve the problem, or if I just introduced a fatal error but well... I went into mscoree.h and metahost.h in .NET SDK install dir, and looked for the things the linker was complaining about.

For example, in mscoree.h I found:

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

so I went to my clr.cpp file and added:

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

which seems to work just fine. Did the same for the other two, and my code got into this, which compiled and run without errors:

#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;

}

Upvotes: 2

Related Questions