mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Cleanup
This commit is contained in:
@@ -38,7 +38,7 @@ configure_file("${DOTNET_APP_HOST}/${NET_HOST_DLL_NAME}" "${CMAKE_CURRENT_BINARY
|
||||
|
||||
# Add source to this project's executable.
|
||||
add_library (GlitchyEngineHelper STATIC
|
||||
"GlitchyEngineHelper.cpp" "GlitchyEngineHelper.h" "vendor/xxHash/xxhash.c" "vendor/xxHash/xxhash.h" "vendor/DirectXTK/Src/DDSTextureLoader.cpp" "DotNetRuntime.h" "DotNetRuntime.cpp"
|
||||
"GlitchyEngineHelper.cpp" "GlitchyEngineHelper.h" "vendor/xxHash/xxhash.c" "vendor/xxHash/xxhash.h" "vendor/DirectXTK/Src/DDSTextureLoader.cpp"
|
||||
# Link object files from nethost into library (kinda dirty I think, but avoids linking to nethost.lib when compiling in beef)
|
||||
$<TARGET_OBJECTS:NetHost>
|
||||
)
|
||||
|
||||
@@ -1,370 +0,0 @@
|
||||
#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;
|
||||
|
||||
load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer;
|
||||
get_function_pointer_fn 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;
|
||||
}
|
||||
|
||||
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()");
|
||||
|
||||
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
|
||||
|
||||
// <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;
|
||||
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;
|
||||
}
|
||||
// </SnippetInitialize>
|
||||
}
|
||||
|
||||
// Load and initialize .NET Core and get desired function pointer for scenario
|
||||
void InitDotNet(const char_t* config_path)
|
||||
{
|
||||
// Load .NET Core
|
||||
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;
|
||||
}
|
||||
|
||||
// Get the load assembly function pointer
|
||||
rc = get_delegate_fptr(
|
||||
hostContext,
|
||||
hdt_load_assembly_and_get_function_pointer,
|
||||
(void**)&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;
|
||||
|
||||
rc = get_delegate_fptr(
|
||||
hostContext,
|
||||
hdt_get_function_pointer,
|
||||
(void**)&get_function_pointer);
|
||||
|
||||
if (rc != 0 || get_function_pointer == nullptr)
|
||||
std::cerr << "Get delegate failed: " << std::hex << std::showbase << rc << std::endl;
|
||||
|
||||
// TODO: close_fptr(hostContext); ???
|
||||
}
|
||||
|
||||
void LoadRuntime(const char_t* configPath)
|
||||
{
|
||||
InitDotNet(configPath);
|
||||
|
||||
assert(load_assembly_and_get_function_pointer != nullptr && get_function_pointer != nullptr && "Failure: get_dotnet_load_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 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;
|
||||
}
|
||||
|
||||
GE_EXPORT int GE_CALLTYPE DotNet_GetFunctionPointer(const char_t* typeName, const char_t* methodName, const char_t* delegateTypeName, void** outDelegate)
|
||||
{
|
||||
int rc = get_function_pointer(
|
||||
typeName,
|
||||
methodName,
|
||||
delegateTypeName,
|
||||
nullptr,
|
||||
nullptr,
|
||||
outDelegate);
|
||||
|
||||
//assert(rc == 0 && outDelegate != nullptr && "Failure: DotNet_GetFunctionPointer()");
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "GlitchyEngineHelper.h"
|
||||
@@ -4,7 +4,7 @@ using System.Interop;
|
||||
using System.Diagnostics;
|
||||
using GlitchyEngineHelper.DotNet;
|
||||
|
||||
namespace GlitchyEngineHelper
|
||||
namespace GlitchyEngineHelper.DotNet
|
||||
{
|
||||
class DotNetContext
|
||||
{
|
||||
@@ -13,8 +13,6 @@ namespace GlitchyEngineHelper
|
||||
#else
|
||||
internal typealias char = char8;
|
||||
#endif
|
||||
|
||||
HostFxr.Handle cxt = null;
|
||||
|
||||
HostFxr.InitializeForDotnetCommandLineFn InitFn;
|
||||
HostFxr.GetRuntimeDelegateFn GetDelegate;
|
||||
@@ -74,7 +72,8 @@ namespace GlitchyEngineHelper
|
||||
null
|
||||
);
|
||||
|
||||
//int rc = InitFn(ptr, null, &cxt);
|
||||
HostFxr.Handle cxt = null;
|
||||
|
||||
int rc = InitFn(1, &args, null, &cxt);
|
||||
|
||||
if (rc != 0 || cxt == null)
|
||||
@@ -100,10 +99,10 @@ namespace GlitchyEngineHelper
|
||||
Close(cxt);
|
||||
}
|
||||
|
||||
public int SetRuntimePropertyValue(StringView property, StringView value)
|
||||
/*public int SetRuntimePropertyValue(StringView property, StringView value)
|
||||
{
|
||||
return SetRuntimePropertyValueFn(cxt, RawPointer!(property), RawPointer!(value));
|
||||
}
|
||||
}*/
|
||||
|
||||
public int LoadAssemblyAndGetFunctionPointer<T>(StringView libraryPath, StringView typeName, StringView methodName, StringView delegateName, out T outDelegate) where T: operator explicit void*
|
||||
{
|
||||
@@ -16,8 +16,8 @@ namespace GlitchyEngineHelper.DotNet
|
||||
|
||||
[CallingConvention(.Stdcall), LinkName("get_hostfxr_path")]
|
||||
public static extern int get_hostfxr_path(
|
||||
DotNet.char * buffer,
|
||||
c_size * buffer_size,
|
||||
char* buffer,
|
||||
c_size* buffer_size,
|
||||
get_hostfxr_parameters *parameters);
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
using System;
|
||||
using System.Interop;
|
||||
|
||||
namespace GlitchyEngineHelper
|
||||
{
|
||||
static class DotNetRuntime
|
||||
{
|
||||
[LinkName("TestRunDotNet"), CallingConvention(.Cdecl)]
|
||||
public static extern c_int TestRunDotNet(c_int argc, c_wchar** argv);
|
||||
|
||||
[LinkName("DotNet_Init"), CallingConvention(.Cdecl)]
|
||||
public static extern c_int Init();
|
||||
|
||||
[LinkName("DotNet_Deinit"), CallingConvention(.Cdecl)]
|
||||
public static extern c_int Deinit();
|
||||
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
private typealias char_t = char16;
|
||||
#else
|
||||
private typealias char_t = char8;
|
||||
#endif
|
||||
|
||||
[LinkName("DotNet_LoadRuntime"), CallingConvention(.Cdecl)]
|
||||
private static extern void Internal_LoadRuntime(char_t* configPath);
|
||||
|
||||
private static char_t* UNMANAGEDCALLERSONLY_METHOD = (char_t*)(void*)-1;
|
||||
|
||||
public static void LoadRuntime(StringView configPath)
|
||||
{
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
Internal_LoadRuntime(configPath.ToScopedNativeWChar!());
|
||||
#else
|
||||
Internal_LoadRuntime(configPath.Ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
[LinkName("DotNet_LoadAssemblyAndGetFunctionPointer"), CallingConvention(.Cdecl)]
|
||||
private static extern c_int DotNet_LoadAssemblyAndGetFunctionPointer(char_t* assemblyPath, char_t* typeName, char_t* methodName, char_t* delegateName, void** outDelegate);
|
||||
|
||||
public typealias ManagedDelegate = function int32(void *arg, int32 arg_size_in_bytes);
|
||||
|
||||
public static c_int LoadAssemblyAndGetFunctionPointer<T>(StringView assemblyPath, StringView typeName, StringView methodName, StringView? delegateName, out T outDelegate) where T : var
|
||||
{
|
||||
outDelegate = null;
|
||||
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
return DotNet_LoadAssemblyAndGetFunctionPointer(assemblyPath.ToScopedNativeWChar!(), typeName.ToScopedNativeWChar!(), methodName.ToScopedNativeWChar!(), delegateName?.ToScopedNativeWChar!(), (void**)&outDelegate);
|
||||
#else
|
||||
Runtime.NotImplemented();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static c_int LoadAssemblyAndGetFunctionPointer(StringView assemblyPath, StringView typeName, StringView methodName, out ManagedDelegate outDelegate)
|
||||
{
|
||||
return LoadAssemblyAndGetFunctionPointer<ManagedDelegate>(assemblyPath, typeName, methodName, null, out outDelegate);
|
||||
}
|
||||
|
||||
public static c_int LoadAssemblyAndGetFunctionPointerUnmanagedCallersOnly<T>(StringView assemblyPath, StringView typeName, StringView methodName, out T outDelegate) where T : var
|
||||
{
|
||||
outDelegate = null;
|
||||
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
return DotNet_LoadAssemblyAndGetFunctionPointer(assemblyPath.ToScopedNativeWChar!(), typeName.ToScopedNativeWChar!(), methodName.ToScopedNativeWChar!(), UNMANAGEDCALLERSONLY_METHOD, (void**)&outDelegate);
|
||||
#else
|
||||
Runtime.NotImplemented();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
[LinkName("DotNet_GetFunctionPointer"), CallingConvention(.Cdecl)]
|
||||
private static extern c_int DotNet_GetFunctionPointer(char_t* typeName, char_t* methodName, char_t* delegateName, void** outDelegate);
|
||||
|
||||
public static c_int GetFunctionPointer<T>(StringView typeName, StringView methodName, StringView delegateName, out T outDelegate) where T : var
|
||||
{
|
||||
outDelegate = null;
|
||||
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
return DotNet_GetFunctionPointer(typeName.ToScopedNativeWChar!(), methodName.ToScopedNativeWChar!(), delegateName.ToScopedNativeWChar!(), (void**)&outDelegate);
|
||||
#else
|
||||
Runtime.NotImplemented();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static c_int GetFunctionPointer(StringView typeName, StringView methodName, out ManagedDelegate outDelegate)
|
||||
{
|
||||
return GetFunctionPointer<ManagedDelegate>(typeName, methodName, null, out outDelegate);
|
||||
}
|
||||
|
||||
public static c_int GetFunctionPointerUnmanagedCallersOnly<T>(StringView typeName, StringView methodName, out T outDelegate) where T : var
|
||||
{
|
||||
outDelegate = null;
|
||||
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
return DotNet_GetFunctionPointer(typeName.ToScopedNativeWChar!(), methodName.ToScopedNativeWChar!(), UNMANAGEDCALLERSONLY_METHOD, (void**)&outDelegate);
|
||||
#else
|
||||
Runtime.NotImplemented();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user