From e51fc77c3fb063ca27987ba8e0431f0251f94ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Wed, 27 Apr 2022 12:22:12 +0200 Subject: [PATCH] Use Init for dotnet commandline --- GlitchyEditor/src/Editor.bf | 45 ++- .../DotNetScriptingHelper.csproj | 2 +- .../DotNetScriptingHelper/ScriptableEntity.cs | 4 +- GlitchyEngineHelper/src/DotNet.bf | 266 ++++++++++++++++++ 4 files changed, 313 insertions(+), 4 deletions(-) create mode 100644 GlitchyEngineHelper/src/DotNet.bf diff --git a/GlitchyEditor/src/Editor.bf b/GlitchyEditor/src/Editor.bf index 9f94ae5..c27f15c 100644 --- a/GlitchyEditor/src/Editor.bf +++ b/GlitchyEditor/src/Editor.bf @@ -61,7 +61,48 @@ namespace GlitchyEditor String runtimeConfig = scope String(exeDir, "/DotNetScriptingHelper.runtimeconfig.json"); String assemblyPath = scope String(exeDir, "/DotNetScriptingHelper.dll"); - DotNetRuntime.Init(); + DotNet dotty = new DotNet(assemblyPath); + defer delete dotty; + + 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); + + InstanceMethodDelegate freeInstance; + dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, InteropHelper", "FreeInstance", out freeInstance); + + //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(instance); + freeInstance((.)reffy);*/ + + //DotNetRuntime.Deinit(); + + /*DotNetRuntime.Init(); DotNetRuntime.LoadRuntime(runtimeConfig); @@ -110,7 +151,7 @@ namespace GlitchyEditor DotNetRuntime.Deinit(); - */ + */*/ while(true) { diff --git a/GlitchyEngineHelper/DotNetScriptingHelper/DotNetScriptingHelper.csproj b/GlitchyEngineHelper/DotNetScriptingHelper/DotNetScriptingHelper.csproj index 13ca085..e232230 100644 --- a/GlitchyEngineHelper/DotNetScriptingHelper/DotNetScriptingHelper.csproj +++ b/GlitchyEngineHelper/DotNetScriptingHelper/DotNetScriptingHelper.csproj @@ -3,7 +3,7 @@ net6.0 true - + true enable enable True diff --git a/GlitchyEngineHelper/DotNetScriptingHelper/ScriptableEntity.cs b/GlitchyEngineHelper/DotNetScriptingHelper/ScriptableEntity.cs index be1d8a4..8d04dfc 100644 --- a/GlitchyEngineHelper/DotNetScriptingHelper/ScriptableEntity.cs +++ b/GlitchyEngineHelper/DotNetScriptingHelper/ScriptableEntity.cs @@ -14,8 +14,10 @@ public abstract class ScriptableEntity [UnmanagedCallersOnly] public static void UpdateEntity(IntPtr entityPtr) { - GCHandle entityHandle = GCHandle.FromIntPtr(entityPtr); + Console.WriteLine("Trying to do stuff!"); + GCHandle entityHandle = GCHandle.FromIntPtr(entityPtr); + if (entityHandle.Target is ScriptableEntity entity) { entity.OnUpdate(); diff --git a/GlitchyEngineHelper/src/DotNet.bf b/GlitchyEngineHelper/src/DotNet.bf new file mode 100644 index 0000000..6428fb7 --- /dev/null +++ b/GlitchyEngineHelper/src/DotNet.bf @@ -0,0 +1,266 @@ +using System; +using System.IO; +using System.Interop; +using System.Diagnostics; + +using internal GlitchyEngineHelper.DotNet; + +namespace GlitchyEngineHelper +{ + class DotNet + { +#if BF_PLATFORM_WINDOWS + internal typealias char = char16; +#else + internal typealias char = char8; +#endif + + HostFxr.Handle cxt = null; + + HostFxr.InitializeForDotnetCommandLineFn InitFn; + HostFxr.GetRuntimeDelegateFn GetDelegate; + HostFxr.CloseFn Close; + HostFxr.SetRuntimePropertyValueFn SetRuntimePropertyValueFn; + + CoreClr.LoadAssemblyAndGetFunctionPointerFn LoadAssemblyAndGetFunctionPointerFn; + CoreClr.GetFunctionPointerFn GetFunctionPointerFn; + + private const char* UNMANAGEDCALLERSONLY_METHOD = (char*)(void*)-1; + + private String _configPath ~ delete _; + + public this(String configPath) + { + _configPath = new String(configPath); + } + + private mixin RawPointer(StringView str) + { +#if BF_PLATFORM_WINDOWS + str.ToScopedNativeWChar!:mixin() +#else + str.CStr() +#endif + } + + public void Init() + { + LoadHostFxr(); + + InitAndStartRuntime(); + } + + private void LoadHostFxr() + { + char[256] buffer = ?; + c_size bufferSize = buffer.Count; + int rc = NetHost.get_hostfxr_path(&buffer, &bufferSize, null); + + Debug.Assert(rc == 0); + + // Load hostfxr and get desired exports + void* lib = LoadLibrary(&buffer); + InitFn = GetExport(lib, "hostfxr_initialize_for_dotnet_command_line"); + GetDelegate = GetExport(lib, "hostfxr_get_runtime_delegate"); + SetRuntimePropertyValueFn = GetExport(lib, "hostfxr_set_runtime_property_value"); + Close = GetExport(lib, "hostfxr_close"); + + Debug.Assert(InitFn != null && GetDelegate != null && Close != null); + } + + private void InitAndStartRuntime() + { + char* ptr = RawPointer!(_configPath); + + char*[2] args = char*[]( + ptr, + null + ); + + //int rc = InitFn(ptr, null, &cxt); + int rc = InitFn(1, &args, null, &cxt); + + if (rc != 0 || cxt == null) + { + Debug.WriteLine($"Init failed: {rc}"); + Close(cxt); + + Debug.Assert(rc == 0); + + return; + } + + Debug.Assert(rc == 0); + + rc = GetDelegate(cxt, .LoadAssemblyAndGetFunctionPointer, (void**)&LoadAssemblyAndGetFunctionPointerFn); + + Debug.Assert(rc == 0, scope $"Get delegate failed: {rc}"); + + rc = GetDelegate(cxt, .GetFunctionPointer, (void**)&GetFunctionPointerFn); + + Debug.Assert(rc == 0, scope $"Get delegate failed: {rc}"); + + Close(cxt); + } + + public int SetRuntimePropertyValue(StringView property, StringView value) + { + return SetRuntimePropertyValueFn(cxt, RawPointer!(property), RawPointer!(value)); + } + + public int LoadAssemblyAndGetFunctionPointer(String libraryPath, String typeName, String methodName, String delegateName, out T outDelegate) where T: operator explicit void* + { + void* funPtr = null; + +#if BF_PLATFORM_WINDOWS + int rc = LoadAssemblyAndGetFunctionPointerFn(libraryPath.ToScopedNativeWChar!(), typeName.ToScopedNativeWChar!(), methodName.ToScopedNativeWChar!(), delegateName.ToScopedNativeWChar!(), null, out funPtr); +#endif + + outDelegate = (T)funPtr; + + return rc; + } + + public int LoadAssemblyAndGetFunctionPointerUnmanagedCallersOnly(String libraryPath, String typeName, String methodName, out T outDelegate) where T: operator explicit void* + { + void* funPtr = null; + +#if BF_PLATFORM_WINDOWS + int rc = LoadAssemblyAndGetFunctionPointerFn(libraryPath.ToScopedNativeWChar!(), typeName.ToScopedNativeWChar!(), methodName.ToScopedNativeWChar!(), UNMANAGEDCALLERSONLY_METHOD, null, out funPtr); +#endif + + outDelegate = (T)funPtr; + + return rc; + } + + public int GetFunctionPointer(String typeName, String methodName, String delegateName, out T outDelegate) where T: operator explicit void* + { + void* funPtr = null; + +#if BF_PLATFORM_WINDOWS + int rc = GetFunctionPointerFn(typeName.ToScopedNativeWChar!(), methodName.ToScopedNativeWChar!(), delegateName.ToScopedNativeWChar!(), null, null, out funPtr); +#endif + + outDelegate = (T)funPtr; + + return rc; + } + + public int GetFunctionPointerUnmanagedCallersOnly(String typeName, String methodName, out T outDelegate) where T: operator explicit void* + { + void* funPtr = null; + +#if BF_PLATFORM_WINDOWS + int rc = GetFunctionPointerFn(typeName.ToScopedNativeWChar!(), methodName.ToScopedNativeWChar!(), UNMANAGEDCALLERSONLY_METHOD, null, null, out funPtr); +#endif + + outDelegate = (T)funPtr; + + return rc; + } + +#if BF_PLATFORM_WINDOWS + private void* LoadLibrary(char* path) + { + Windows.HInstance handle = Windows.LoadLibraryW(path); + + Debug.Assert(handle != 0); + + return (void*)(int)handle; + } + + private T GetExport(void* handle, char8* name) where T : operator explicit void* + { + void* f = Windows.GetProcAddress((Windows.HModule)(int)handle, name); + + Debug.Assert(f != null); + + return (T)f; + } +#else + private void* LoadLibrary(char* path) + { + // TODO! + } +#endif + } + + static class HostFxr + { +#if BF_PLATFORM_WINDOWS + internal typealias char = char16; +#else + internal typealias char = char8; +#endif + + public enum DelegateType : c_int + { + ComActivation, + LoadInMemoryAssembly, + WinrtActivation, + ComRegister, + ComUnregister, + LoadAssemblyAndGetFunctionPointer, + GetFunctionPointer, + } + + public typealias Handle = void*; + + [CRepr] + public struct InitializeParameters + { + public c_size Size = sizeof(InitializeParameters); + public char* HostPath; + public char* DotnetRoot; + }; + + public typealias InitializeForRuntimeConfigFn = function [CallingConvention(.Cdecl)] int32(char* runtimeConfigPath, InitializeParameters* parameters, Handle* hostContextHandle); + public typealias InitializeForDotnetCommandLineFn = function [CallingConvention(.Cdecl)] int32(c_int argc, char** argv, InitializeParameters* parameters, Handle* hostContextHandle); + public typealias GetRuntimeDelegateFn = function [CallingConvention(.Cdecl)] int32(Handle host_context_handle, DelegateType type, void** outDelegate); + public typealias SetRuntimePropertyValueFn = function [CallingConvention(.Cdecl)] int32(Handle host_context_handle, char* name, char* value); + public typealias CloseFn = function [CallingConvention(.Cdecl)] int32(Handle host_context_handle); + } + + static class CoreClr + { +#if BF_PLATFORM_WINDOWS + internal typealias char = char16; +#else + internal typealias char = char8; +#endif + + public typealias LoadAssemblyAndGetFunctionPointerFn = function [CallingConvention(.Stdcall)] c_int( + char* assemblyPath, + char* typeName, + char* methodName, + char* delegateTypeName, + void* reserved, + out void* outDelegate); + + public typealias GetFunctionPointerFn = function [CallingConvention(.Stdcall)] c_int( + char* typeName, + char* MethodName, + char* delegateTypeName, + void* loadContext, + void* reserved, + out void* outDelegate + ); + } + + static class NetHost + { + public struct get_hostfxr_parameters + { + public c_size size; + public DotNet.char* assembly_path; + public DotNet.char* dotnet_root; + }; + + [CallingConvention(.Stdcall), LinkName("get_hostfxr_path")] + public static extern int get_hostfxr_path( + DotNet.char * buffer, + c_size * buffer_size, + get_hostfxr_parameters *parameters); + } +} \ No newline at end of file