This commit is contained in:
Simon Lübeß
2022-05-03 22:52:37 +02:00
parent 63b9270710
commit 4874cfe511
8 changed files with 10 additions and 591 deletions
+1
View File
@@ -3,4 +3,5 @@ Dependencies = {corlib = "*", GlitchLog = "*", GlitchyEngine = "*"}
[Project]
Name = "GlitchyEditor"
TargetType = "BeefGUIApplication"
StartupObject = "GlitchyEngine.Program"
+1 -108
View File
@@ -6,6 +6,7 @@ using GlitchyEngine.Collections;
using GlitchyEditor.EditWindows;
using GlitchyEngineHelper;
using System.IO;
using GlitchyEngineHelper.DotNet;
namespace GlitchyEditor
{
@@ -28,29 +29,6 @@ namespace GlitchyEditor
public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow;
[CRepr]
struct lib_args
{
public char16* Message;
public int32 number;
};
[CRepr]
struct CreateInstanceArgs
{
//public StringView TypeName;
public char8* TypeName;
public int TypeNameLength;
};
struct ManagedReference;
public typealias CreateInstanceDelegate = function [CallingConvention(.Stdcall)] ManagedReference*(CreateInstanceArgs* arg, int32 arg_size_in_bytes);
public typealias FreeInstanceDelegate = function [CallingConvention(.Stdcall)] void(ManagedReference* arg);
public typealias InstanceMethodDelegate = function [CallingConvention(.Stdcall)] void(ManagedReference* arg);
/// Creates a new editor for the given world
public this(Scene scene)
{
@@ -58,7 +36,6 @@ namespace GlitchyEditor
String exeDir = Path.GetDirectoryPath(exePath, .. scope String());
String runtimeConfig = scope String(exeDir, "/DotNetScriptingHelper.runtimeconfig.json");
String assemblyPath = scope String(exeDir, "/DotNetScriptingHelper.dll");
DotNetContext dotty = new DotNetContext(assemblyPath);
@@ -66,93 +43,9 @@ namespace GlitchyEditor
dotty.Init();
///int res = dotty.SetRuntimePropertyValue("APP_PATH", exeDir);
CreateInstanceDelegate createInstance;
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.InteropHelper, DotNetScriptingHelper", "CreateInstance", out createInstance);
String typeName = "DotNetScriptingHelper.TestEntityScript, DotNetScriptingHelper";
CreateInstanceArgs instanceArgs = .
{
TypeName = typeName.Ptr,
TypeNameLength = typeName.Length
};
ManagedReference* instance = createInstance(&instanceArgs, sizeof(CreateInstanceArgs));
InstanceMethodDelegate update;
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "UpdateEntity", out update);
FreeInstanceDelegate freeInstance;
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.InteropHelper, DotNetScriptingHelper", "FreeInstance", out freeInstance);
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "CreateInstance", out DotNetScriptComponent.CreateInstanceFn);
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "UpdateEntity", out DotNetScriptComponent.UpdateInstanceFn);
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "DestroyEntity", out DotNetScriptComponent.DestroyInstanceFn);
/*void* reffy = DotNetScriptComponent.DelCreateInstance(typeName.Ptr, (int32)typeName.Length, EcsEntity.[Friend]CreateEntityID(1337, 420));
for (int i < 10)
{
update(instance);
update((.)reffy);
}
freeInstance(instance);
freeInstance((.)reffy);*/
//DotNetRuntime.Deinit();
/*DotNetRuntime.Init();
DotNetRuntime.LoadRuntime(runtimeConfig);
CreateInstanceDelegate createInstance;
DotNetRuntime.LoadAssemblyAndGetFunctionPointerUnmanagedCallersOnly(assemblyPath, "DotNetScriptingHelper.InteropHelper, DotNetScriptingHelper", "CreateInstance", out createInstance);
DotNetRuntime.ManagedDelegate someDel1;
DotNetRuntime.ManagedDelegate someDel2;
DotNetRuntime.LoadAssemblyAndGetFunctionPointer(assemblyPath, "DotNetScriptingHelper.InteropHelper, DotNetScriptingHelper", "SomeMethod", out someDel1);
someDel1(null, 0); // System.Runtime.InteropServices.Marshal, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
int32 iy = DotNetRuntime.GetFunctionPointer("DotNetScriptingHelper.InteropHelper, DotNetScriptingHelper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "SomeMethod", out someDel2);
//DotNetRuntime.GetFunctionPointer("System", DotNetScriptingHelper", "SomeMethod", out someDel2);
/*
FreeInstanceDelegate freeInstance = null;
//DotNetRuntime.LoadAssemblyAndGetFunctionPointer(assemblyPath, "DotNetScriptingHelper.InteropHelper, DotNetScriptingHelper", "FreeInstance", "DotNetScriptingHelper.InteropHelper+FreeInstanceEntryPoint, DotNetScriptingHelper", out freeInstance);
DotNetRuntime.GetFunctionPointer("DotNetScriptingHelper.InteropHelper, DotNetScriptingHelper", "FreeInstance", "DotNetScriptingHelper.InteropHelper+FreeInstanceEntryPoint, DotNetScriptingHelper", out freeInstance);
InstanceMethodDelegate update;
DotNetRuntime.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "UpdateEntity", out update);
DotNetRuntime.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "CreateInstance", out DotNetScriptComponent.DelCreateInstance);
String typeName = "DotNetScriptingHelper.TestEntityScript, DotNetScriptingHelper";
CreateInstanceArgs instanceArgs = .
{
TypeName = typeName.Ptr,
TypeNameLength = typeName.Length
};
ManagedReference* instance = createInstance(&instanceArgs, sizeof(CreateInstanceArgs));
void* reffy = DotNetScriptComponent.DelCreateInstance(typeName.Ptr, (int32)typeName.Length, EcsEntity.[Friend]CreateEntityID(1337, 420));
for (int i < 10)
{
update(instance);
update((.)reffy);
}
freeInstance(instance);
freeInstance((.)reffy);
DotNetRuntime.Deinit();
*/*/
_scene = scene;
_ecsWorld = _scene.[Friend]_ecsWorld;
+1 -1
View File
@@ -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>
)
-370
View File
@@ -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;
}
-3
View File
@@ -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*
{
+2 -2
View File
@@ -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);
}
}
-101
View File
@@ -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
}
}
}