Skip to content

Instantly share code, notes, and snippets.

@Ohjurot
Created February 4, 2022 16:22
Show Gist options
  • Save Ohjurot/a10dceea7da1e957003e0405c8594553 to your computer and use it in GitHub Desktop.
Save Ohjurot/a10dceea7da1e957003e0405c8594553 to your computer and use it in GitHub Desktop.
C# .NET 6 Embedding in c++ (Portable version - Build your own runtime and distribute the shared folder)
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
using System.Runtime.InteropServices;
namespace CsCode
{
public static class CsMain
{
[UnmanagedCallersOnly]
public static int Test(IntPtr str)
{
int result = 0;
String csstr = "";
if (str.ToInt64() != 0)
{
String t_csstr = Marshal.PtrToStringAnsi(str);
if(t_csstr != null)
{
if (t_csstr.Length != 0)
{
csstr = t_csstr;
result = 1;
}
}
}
Console.WriteLine(csstr);
return result;
}
}
}
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <iostream>
#include <hostfxr.h>
#include <coreclr_delegates.h>
#define HOSTFXR_PATH_LEN 1024
struct HostFxr
{
// Functions
inline int32_t initializeForRuntimeConfig(
const char_t* runtime_config_path,
const hostfxr_initialize_parameters* parameters,
hostfxr_handle* host_context_handle)
{
return _initialize_for_runtime_config(runtime_config_path, parameters, host_context_handle);
}
inline int32_t getRuntimeDelegate(
const hostfxr_handle host_context_handle,
hostfxr_delegate_type type,
void** delegate)
{
return _get_runtime_delegate(host_context_handle, type, delegate);
}
inline int32_t close(
const hostfxr_handle host_context_handle)
{
return _close(host_context_handle);
}
inline int loadAssemblyAndGetFunctionPointer(
const char_t* assembly_path,
const char_t* type_name,
const char_t* method_name,
const char_t* delegate_type_name,
void* reserved,
void** delegate)
{
return _load_assembly_and_get_function_pointer(assembly_path, type_name, method_name, delegate_type_name, reserved, delegate);
}
// FPTR-TABLE
hostfxr_initialize_for_runtime_config_fn _initialize_for_runtime_config = nullptr;
hostfxr_get_runtime_delegate_fn _get_runtime_delegate = nullptr;
hostfxr_close_fn _close = nullptr;
load_assembly_and_get_function_pointer_fn _load_assembly_and_get_function_pointer = nullptr;
};
int main()
{
const wchar_t* fxrPath = L"./hostfxr.dll";
SetEnvironmentVariable(L"DOTNET_MULTILEVEL_LOOKUP", L"0"); // Prevent .NET from loading an installed runtime aka. force the embeded one
// Load FXR
HMODULE lib = LoadLibrary(fxrPath);
if (lib != NULL)
{
std::cout << "loaded hostfxr.dll module" << std::endl;
// Init host fxr
HostFxr hostFxr;
hostFxr._initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)GetProcAddress(lib, "hostfxr_initialize_for_runtime_config");
hostFxr._get_runtime_delegate = (hostfxr_get_runtime_delegate_fn)GetProcAddress(lib, "hostfxr_get_runtime_delegate");
hostFxr._close = (hostfxr_close_fn)GetProcAddress(lib, "hostfxr_close");
// Check if host fxr loaded
if (hostFxr._initialize_for_runtime_config && hostFxr._get_runtime_delegate && hostFxr._close)
{
std::cout << "loaded hostfxr.dll functions" << std::endl;
// Get module file name
WCHAR exeFile[1024];
GetModuleFileName(NULL, exeFile, 1024);
// Execution dir
WCHAR workDir[1024];
GetCurrentDirectory(1024, workDir);
// Describe runtime path
hostfxr_initialize_parameters fxrParams;
fxrParams.size = sizeof(hostfxr_initialize_parameters);
fxrParams.host_path = exeFile; // The host of the application (not required)
fxrParams.dotnet_root = workDir; // I have builded and installed a custom .NET runtime to make this app portable
// Create context
hostfxr_handle ctx = nullptr;
if (hostFxr.initializeForRuntimeConfig(L"./conf.runtimeconfig.json", &fxrParams, &ctx) == 0)
{
std::cout << "loaded .NETCore" << std::endl;
// Get hdt_load_assembly_and_get_function_pointer
if (hostFxr.getRuntimeDelegate(ctx, hdt_load_assembly_and_get_function_pointer, (void**)&hostFxr._load_assembly_and_get_function_pointer) == 0)
{
std::cout << "loaded hdt_load_assembly_and_get_function_pointer" << std::endl;
// Build assembly path
WCHAR dllFile[1024];
wcscpy_s<1024>(dllFile, exeFile);
auto* lsts = wcsrchr(dllFile, L'\\');
if (lsts) *lsts = L'\0';
wcscat_s<1024>(dllFile, L"\\CsCode.dll");
// Load the assembly and get function
typedef int(*csFunction)(const char*);
csFunction ptrFuc = nullptr;
if (hostFxr.loadAssemblyAndGetFunctionPointer(
dllFile,
L"CsCode.CsMain, CsCode",
L"Test",
UNMANAGEDCALLERSONLY_METHOD,
nullptr,
(void**)&ptrFuc) == 0)
{
std::cout << "loaded CsCode.CsMain.ComponentEntryPoint" << std::endl;
std::cout << "Calling CS: ";
int result = ptrFuc("Hello World!");
std::cout << "CS Returned: #" << result << std::endl;
}
int i = 0;
}
// Free context
hostFxr.close(ctx);
}
}
// Close FXR
FreeLibrary(lib);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment