#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 #include #include #include #include #include // Provided by the AppHost NuGet package and installed as an SDK pack #include // Header files copied from https://github.com/dotnet/core-setup #include #include #ifdef WINDOWS #include #define STR(s) L ## s #define CH(c) L ## c #define DIR_SEPARATOR L'\\' #else #include #include #define STR(s) s #define CH(c) c #define DIR_SEPARATOR '/' #define MAX_PATH PATH_MAX #endif using string_t = std::basic_string; 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; load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer; hostfxr_handle hostContext; // Forward declarations bool load_hostfxr(); load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t* assembly); } struct lib_args { const char_t* message; int number; }; typedef void (CORECLR_DELEGATE_CALLTYPE* custom_entry_point_fn)(lib_args args); custom_entry_point_fn GetFunctionPointer(load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer, const string_t& dotnetlib_path, const char_t* dotnet_type, const char_t* method_name) { // Function pointer to managed delegate with non-default signature custom_entry_point_fn custom = nullptr; int 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()"); return custom; } void LoadRuntime(const char_t* configPath) { load_assembly_and_get_function_pointer = get_dotnet_load_assembly(configPath); assert(load_assembly_and_get_function_pointer != nullptr && "Failure: get_dotnet_load_assembly()"); } 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"); // // 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); // 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) { // lib_args args { STR("from host!"), i }; hello(&args, sizeof(args)); // } // 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()"); custom_entry_point_fn custom = GetFunctionPointer( load_assembly_and_get_function_pointer, dotnetlib_path, dotnet_type, STR("CustomEntryPointUnmanaged") /*method_name*/); 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 // // 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); } // // // 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; hostContext = nullptr; int rc = init_fptr(config_path, nullptr, &hostContext); if (rc != 0 || hostContext == nullptr) { std::cerr << "Init failed: " << std::hex << std::showbase << rc << std::endl; close_fptr(hostContext); return nullptr; } // Get the load assembly function pointer rc = get_delegate_fptr( hostContext, 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; // TODO: close_fptr(hostContext); ??? return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer; } // } 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 DotNet_Deinit() { int result = close_fptr(hostContext); hostContext = nullptr; return result; } GE_EXPORT void GE_CALLTYPE DotNet_LoadRuntime(const char_t* configPath) { LoadRuntime(configPath); } GE_EXPORT int GE_CALLTYPE DotNet_LoadAssemblyAndGetFunctionPointer(const char_t* assemblyPath, const char_t* typeName, const char_t* methodName, const char_t* delegateTypeName, void** outDelegate) { int rc = load_assembly_and_get_function_pointer( assemblyPath, typeName, methodName, delegateTypeName, nullptr, outDelegate); assert(rc == 0 && outDelegate != nullptr && "Failure: load_assembly_and_get_function_pointer()"); return rc; }