Skip to content

Instantly share code, notes, and snippets.

@xpn
Created April 11, 2018 21:34
Show Gist options
  • Star 64 You must be signed in to star a gist
  • Fork 32 You must be signed in to fork a gist
  • Save xpn/e95a62c6afcf06ede52568fcd8187cc2 to your computer and use it in GitHub Desktop.
Save xpn/e95a62c6afcf06ede52568fcd8187cc2 to your computer and use it in GitHub Desktop.
A quick example showing loading CLR via native code
#include "stdafx.h"
int main()
{
ICLRMetaHost *metaHost = NULL;
IEnumUnknown *runtime = NULL;
ICLRRuntimeInfo *runtimeInfo = NULL;
ICLRRuntimeHost *runtimeHost = NULL;
IUnknown *enumRuntime = NULL;
LPWSTR frameworkName = NULL;
DWORD bytes = 2048, result = 0;
HRESULT hr;
printf("CLR via native code.... @_xpn_\n\n");
if (CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost) != S_OK) {
printf("[x] Error: CLRCreateInstance(..)\n");
return 2;
}
if (metaHost->EnumerateInstalledRuntimes(&runtime) != S_OK) {
printf("[x] Error: EnumerateInstalledRuntimes(..)\n");
return 2;
}
frameworkName = (LPWSTR)LocalAlloc(LPTR, 2048);
if (frameworkName == NULL) {
printf("[x] Error: malloc could not allocate\n");
return 2;
}
// Enumerate through runtimes and show supported frameworks
while (runtime->Next(1, &enumRuntime, 0) == S_OK) {
if (enumRuntime->QueryInterface<ICLRRuntimeInfo>(&runtimeInfo) == S_OK) {
if (runtimeInfo != NULL) {
runtimeInfo->GetVersionString(frameworkName, &bytes);
wprintf(L"[*] Supported Framework: %s\n", frameworkName);
}
}
}
// For demo, we just use the last supported runtime
if (runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost) != S_OK) {
printf("[x] ..GetInterface(CLSID_CLRRuntimeHost...) failed\n");
return 2;
}
if (runtimeHost == NULL || bytes == 0) {
wprintf(L"[*] Using runtime: %s\n", frameworkName);
}
// Start runtime, and load our assembly
runtimeHost->Start();
printf("[*] ======= Calling .NET Code =======\n\n");
if (runtimeHost->ExecuteInDefaultAppDomain(
L"myassembly.dll",
L"myassembly.Program",
L"test",
L"argtest",
&result
) != S_OK) {
printf("[x] Error: ExecuteInDefaultAppDomain(..) failed\n");
return 2;
}
printf("[*] ======= Done =======\n");
return 0;
}
@pabloko
Copy link

pabloko commented Dec 8, 2022

@blue-devil if you check the documentation for ICLRRuntimeHost::ExecuteInDefaultAppDomain:

The invoked method must have the following signature:

static int pwzMethodName (String pwzArgument)

So this method is a convenient helper to launch a typical main entry point.

If you want to be able to bind both languages you should use ICLRRuntimeHost::SetHostControl and create your own implementation of IHostControl that exposes an interface that can be used in managed code, create a managed AppDomainManager that also implements such interface, then obtain the ICLRControl and set the AppDomainManager managed to back your unmanaged interface. Theres a tutorial you can follow here:
https://www.mode19.net/posts/clrhostingright/

This may sound a bit complicated but it works. If youre just looking to comunicate between managed and unmanaged code, check out UnamanagedExports nuget package, wich allows you to generate native dll libraries from managed code, wich lowers the complexity of this process by a magnitude.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment