From a337b94dfaf317a9c8902e00150ab4ee2f4cb9ff Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Fri, 23 Jul 2021 14:33:16 -0700 Subject: [PATCH] .NET 5 --- MoonWorks.csproj | 32 +++---- src/MoonWorksDllMap.cs | 201 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 16 deletions(-) create mode 100644 src/MoonWorksDllMap.cs diff --git a/MoonWorks.csproj b/MoonWorks.csproj index d2a6ab1..27ff0d6 100644 --- a/MoonWorks.csproj +++ b/MoonWorks.csproj @@ -1,24 +1,24 @@ - - netstandard2.0 - x64 - true - + + net5.0 + x64 + true + - - $(DefaultItemExcludes);lib\**\* - + + $(DefaultItemExcludes);lib\**\* + - - - - - + + + + + - + - PreserveNewest - + PreserveNewest + diff --git a/src/MoonWorksDllMap.cs b/src/MoonWorksDllMap.cs new file mode 100644 index 0000000..c6eeea9 --- /dev/null +++ b/src/MoonWorksDllMap.cs @@ -0,0 +1,201 @@ +#region License + +/* MoonWorks - Game Development Framework + * Copyright 2021 Evan Hemsley + */ + +/* Derived from code by Ethan Lee (Copyright 2009-2021). + * Released under the Microsoft Public License. + * See fna.LICENSE for details. + */ +#endregion + +#region Using Statements +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Xml; +#endregion + +namespace MoonWorks +{ + internal static class MoonWorksDllMap + { + #region Private Static Variables + + private static Dictionary mapDictionary + = new Dictionary(); + + #endregion + + #region Private Static Methods + + private static string GetPlatformName() + { + if (OperatingSystem.IsWindows()) + { + return "windows"; + } + else if (OperatingSystem.IsMacOS()) + { + return "osx"; + } + else if (OperatingSystem.IsLinux()) + { + return "linux"; + } + else if (OperatingSystem.IsFreeBSD()) + { + return "freebsd"; + } + else + { + // Maybe this platform statically links? + return "unknown"; + } + } + + #endregion + + #region DllImportResolver Callback Method + + private static IntPtr MapAndLoad( + string libraryName, + Assembly assembly, + DllImportSearchPath? dllImportSearchPath + ) { + string mappedName; + if (!mapDictionary.TryGetValue(libraryName, out mappedName)) + { + mappedName = libraryName; + } + return NativeLibrary.Load(mappedName, assembly, dllImportSearchPath); + } + + #endregion + + #region Module Initializer + + [ModuleInitializer] + public static void Init() + { + // Get the platform and architecture + string os = GetPlatformName(); + string cpu = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); + string wordsize = (IntPtr.Size * 8).ToString(); + + // Get the path to the assembly + Assembly assembly = Assembly.GetExecutingAssembly(); + string assemblyPath = ""; + if (assembly.Location != null) + { + assemblyPath = Path.GetDirectoryName(assembly.Location); + } + + // Locate the config file + string xmlPath = Path.Combine( + assemblyPath, + assembly.GetName().Name + ".dll.config" + ); + if (!File.Exists(xmlPath)) + { + // Let's hope for the best... + return; + } + + // Load the XML + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(xmlPath); + + // The NativeLibrary API cannot remap function names. :( + if (xmlDoc.GetElementsByTagName("dllentry").Count > 0) + { + string msg = "Function remapping is not supported by .NET Core. Ignoring dllentry elements..."; + Console.WriteLine(msg); + + // Log it in the debugger for non-console apps. + if (Debugger.IsAttached) + { + Debug.WriteLine(msg); + } + } + + // Parse the XML into a mapping dictionary + foreach (XmlNode node in xmlDoc.GetElementsByTagName("dllmap")) + { + XmlAttribute attribute; + + // Check the OS + attribute = node.Attributes["os"]; + if (attribute != null) + { + bool containsOS = attribute.Value.Contains(os); + bool invert = attribute.Value.StartsWith("!"); + if ((!containsOS && !invert) || (containsOS && invert)) + { + continue; + } + } + + // Check the CPU + attribute = node.Attributes["cpu"]; + if (attribute != null) + { + bool containsCPU = attribute.Value.Contains(cpu); + bool invert = attribute.Value.StartsWith("!"); + if ((!containsCPU && !invert) || (containsCPU && invert)) + { + continue; + } + } + + // Check the word size + attribute = node.Attributes["wordsize"]; + if (attribute != null) + { + bool containsWordsize = attribute.Value.Contains(wordsize); + bool invert = attribute.Value.StartsWith("!"); + if ((!containsWordsize && !invert) || (containsWordsize && invert)) + { + continue; + } + } + + // Check for the existence of 'dll' and 'target' attributes + XmlAttribute dllAttribute = node.Attributes["dll"]; + XmlAttribute targetAttribute = node.Attributes["target"]; + if (dllAttribute == null || targetAttribute == null) + { + continue; + } + + // Get the actual library names + string oldLib = dllAttribute.Value; + string newLib = targetAttribute.Value; + if (string.IsNullOrWhiteSpace(oldLib) || string.IsNullOrWhiteSpace(newLib)) + { + continue; + } + + // Don't allow duplicates + if (mapDictionary.ContainsKey(oldLib)) + { + continue; + } + + mapDictionary.Add(oldLib, newLib); + } + + // Set the resolver callback for our native assemblies + NativeLibrary.SetDllImportResolver(typeof(SDL2.SDL).Assembly, MapAndLoad); + NativeLibrary.SetDllImportResolver(typeof(RefreshCS.Refresh).Assembly, MapAndLoad); + NativeLibrary.SetDllImportResolver(typeof(FAudio).Assembly, MapAndLoad); + } + + #endregion + } +}