DotNet hosting test

This commit is contained in:
Simon Lübeß
2022-04-14 02:24:36 +02:00
parent 9c93ccee47
commit 6a250d4927
16 changed files with 806 additions and 13 deletions
+251
View File
@@ -0,0 +1,251 @@
#include "DotNetRuntime.h"
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// https://docs.microsoft.com/en-us/dotnet/core/tutorials/netcore-hosting
// Standard headers
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <iostream>
// Provided by the AppHost NuGet package and installed as an SDK pack
#include <nethost.h>
// Header files copied from https://github.com/dotnet/core-setup
#include <coreclr_delegates.h>
#include <hostfxr.h>
#ifdef WINDOWS
#include <Windows.h>
#define STR(s) L ## s
#define CH(c) L ## c
#define DIR_SEPARATOR L'\\'
#else
#include <dlfcn.h>
#include <limits.h>
#define STR(s) s
#define CH(c) c
#define DIR_SEPARATOR '/'
#define MAX_PATH PATH_MAX
#endif
using string_t = std::basic_string<char_t>;
namespace
{
// Globals to hold hostfxr exports
hostfxr_initialize_for_runtime_config_fn init_fptr;
hostfxr_get_runtime_delegate_fn get_delegate_fptr;
hostfxr_close_fn close_fptr;
// Forward declarations
bool load_hostfxr();
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t* assembly);
}
GE_EXPORT int GE_CALLTYPE DotNet_Init()
{
if (!load_hostfxr())
{
assert(false && "Failure: load_hostfxr()");
return EXIT_FAILURE;
}
return 0;
}
GE_EXPORT int GE_CALLTYPE TestRunDotNet(int argc, wchar_t* argv[])
{
// Get the current executable's directory
// This sample assumes the managed assembly to load and its runtime configuration file are next to the host
char_t host_path[MAX_PATH];
#if WINDOWS
auto size = ::GetFullPathNameW(argv[0], sizeof(host_path) / sizeof(char_t), host_path, nullptr);
assert(size != 0);
#else
auto resolved = realpath(argv[0], host_path);
assert(resolved != nullptr);
#endif
string_t root_path = host_path;
auto pos = root_path.find_last_of(DIR_SEPARATOR);
assert(pos != string_t::npos);
root_path = root_path.substr(0, pos + 1);
////
//// STEP 1: Load HostFxr and get exported hosting functions
////
//if (!load_hostfxr())
//{
// assert(false && "Failure: load_hostfxr()");
// return EXIT_FAILURE;
//}
//
// STEP 2: Initialize and start the .NET Core runtime
//
const string_t config_path = root_path + STR("DotNetTest.runtimeconfig.json");
load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer = nullptr;
load_assembly_and_get_function_pointer = get_dotnet_load_assembly(config_path.c_str());
assert(load_assembly_and_get_function_pointer != nullptr && "Failure: get_dotnet_load_assembly()");
//
// STEP 3: Load managed assembly and get function pointer to a managed method
//
const string_t dotnetlib_path = root_path + STR("DotNetTest.dll");
const char_t* dotnet_type = STR("DotNetTest.Lib, DotNetTest");
const char_t* dotnet_type_method = STR("Hello");
// <SnippetLoadAndGet>
// Function pointer to managed delegate
component_entry_point_fn hello = nullptr;
int rc = load_assembly_and_get_function_pointer(
dotnetlib_path.c_str(),
dotnet_type,
dotnet_type_method,
nullptr /*delegate_type_name*/,
nullptr,
(void**)&hello);
// </SnippetLoadAndGet>
assert(rc == 0 && hello != nullptr && "Failure: load_assembly_and_get_function_pointer()");
//
// STEP 4: Run managed code
//
struct lib_args
{
const char_t* message;
int number;
};
for (int i = 0; i < 3; ++i)
{
// <SnippetCallManaged>
lib_args args
{
STR("from host!"),
i
};
hello(&args, sizeof(args));
// </SnippetCallManaged>
}
// Function pointer to managed delegate with non-default signature
typedef void (CORECLR_DELEGATE_CALLTYPE* custom_entry_point_fn)(lib_args args);
custom_entry_point_fn custom = nullptr;
rc = load_assembly_and_get_function_pointer(
dotnetlib_path.c_str(),
dotnet_type,
STR("CustomEntryPointUnmanaged") /*method_name*/,
UNMANAGEDCALLERSONLY_METHOD,
nullptr,
(void**)&custom);
assert(rc == 0 && custom != nullptr && "Failure: load_assembly_and_get_function_pointer()");
lib_args args
{
STR("from host!"),
-1
};
custom(args);
return EXIT_SUCCESS;
}
/********************************************************************************************
* Function used to load and activate .NET Core
********************************************************************************************/
namespace
{
// Forward declarations
void* load_library(const char_t*);
void* get_export(void*, const char*);
#ifdef WINDOWS
void* load_library(const char_t* path)
{
std::cout << "Loading library: " << path << std::endl;
HMODULE h = ::LoadLibraryW(path);
assert(h != nullptr);
return (void*)h;
}
void* get_export(void* h, const char* name)
{
void* f = ::GetProcAddress((HMODULE)h, name);
assert(f != nullptr);
return f;
}
#else
void* load_library(const char_t* path)
{
void* h = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
assert(h != nullptr);
return h;
}
void* get_export(void* h, const char* name)
{
void* f = dlsym(h, name);
assert(f != nullptr);
return f;
}
#endif
// <SnippetLoadHostFxr>
// Using the nethost library, discover the location of hostfxr and get exports
bool load_hostfxr()
{
// Pre-allocate a large buffer for the path to hostfxr
char_t buffer[MAX_PATH];
size_t buffer_size = sizeof(buffer) / sizeof(char_t);
int rc = get_hostfxr_path(buffer, &buffer_size, nullptr);
if (rc != 0)
return false;
// Load hostfxr and get desired exports
void* lib = load_library(buffer);
init_fptr = (hostfxr_initialize_for_runtime_config_fn)get_export(lib, "hostfxr_initialize_for_runtime_config");
get_delegate_fptr = (hostfxr_get_runtime_delegate_fn)get_export(lib, "hostfxr_get_runtime_delegate");
close_fptr = (hostfxr_close_fn)get_export(lib, "hostfxr_close");
return (init_fptr && get_delegate_fptr && close_fptr);
}
// </SnippetLoadHostFxr>
// <SnippetInitialize>
// Load and initialize .NET Core and get desired function pointer for scenario
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t* config_path)
{
// Load .NET Core
void* load_assembly_and_get_function_pointer = nullptr;
hostfxr_handle cxt = nullptr;
int rc = init_fptr(config_path, nullptr, &cxt);
if (rc != 0 || cxt == nullptr)
{
std::cerr << "Init failed: " << std::hex << std::showbase << rc << std::endl;
close_fptr(cxt);
return nullptr;
}
// Get the load assembly function pointer
rc = get_delegate_fptr(
cxt,
hdt_load_assembly_and_get_function_pointer,
&load_assembly_and_get_function_pointer);
if (rc != 0 || load_assembly_and_get_function_pointer == nullptr)
std::cerr << "Get delegate failed: " << std::hex << std::showbase << rc << std::endl;
close_fptr(cxt);
return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer;
}
// </SnippetInitialize>
}