Add project files.

This commit is contained in:
Razmoth
2022-09-27 17:40:31 +04:00
parent 871d908948
commit a476ace7d7
305 changed files with 71340 additions and 84 deletions

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;netstandard2.0;net5.0;net6.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.18.00</Version>
<AssemblyVersion>0.18.00</AssemblyVersion>
<FileVersion>0.18.00</FileVersion>
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,124 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace AssetStudio.PInvoke
{
public static class DllLoader
{
public static void PreloadDll(string dllName)
{
var dllDir = GetDirectedDllDirectory();
// Not using OperatingSystem.Platform.
// See: https://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Win32.LoadDll(dllDir, dllName);
}
else
{
Posix.LoadDll(dllDir, dllName);
}
}
private static string GetDirectedDllDirectory()
{
var localPath = Process.GetCurrentProcess().MainModule.FileName;
var localDir = Path.GetDirectoryName(localPath);
var subDir = Environment.Is64BitProcess ? "x64" : "x86";
var directedDllDir = Path.Combine(localDir, subDir);
return directedDllDir;
}
private static class Win32
{
internal static void LoadDll(string dllDir, string dllName)
{
var dllFileName = $"{dllName}.dll";
var directedDllPath = Path.Combine(dllDir, dllFileName);
// Specify SEARCH_DLL_LOAD_DIR to load dependent libraries located in the same platform-specific directory.
var hLibrary = LoadLibraryEx(directedDllPath, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
if (hLibrary == IntPtr.Zero)
{
var errorCode = Marshal.GetLastWin32Error();
var exception = new Win32Exception(errorCode);
throw new DllNotFoundException(exception.Message, exception);
}
}
// HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
// HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibraryEx(string lpLibFileName, IntPtr hFile, uint dwFlags);
private const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x1000;
private const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x100;
}
private static class Posix
{
internal static void LoadDll(string dllDir, string dllName)
{
string dllExtension;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
dllExtension = ".so";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
dllExtension = ".dylib";
}
else
{
throw new NotSupportedException();
}
var dllFileName = $"lib{dllName}{dllExtension}";
var directedDllPath = Path.Combine(dllDir, dllFileName);
const int ldFlags = RTLD_NOW | RTLD_GLOBAL;
var hLibrary = DlOpen(directedDllPath, ldFlags);
if (hLibrary == IntPtr.Zero)
{
var pErrStr = DlError();
// `PtrToStringAnsi` always uses the specific constructor of `String` (see dotnet/core#2325),
// which in turn interprets the byte sequence with system default codepage. On OSX and Linux
// the codepage is UTF-8 so the error message should be handled correctly.
var errorMessage = Marshal.PtrToStringAnsi(pErrStr);
throw new DllNotFoundException(errorMessage);
}
}
// OSX and most Linux OS use LP64 so `int` is still 32-bit even on 64-bit platforms.
// void *dlopen(const char *filename, int flag);
[DllImport("libdl", EntryPoint = "dlopen")]
private static extern IntPtr DlOpen([MarshalAs(UnmanagedType.LPStr)] string fileName, int flags);
// char *dlerror(void);
[DllImport("libdl", EntryPoint = "dlerror")]
private static extern IntPtr DlError();
private const int RTLD_LAZY = 0x1;
private const int RTLD_NOW = 0x2;
private const int RTLD_GLOBAL = 0x100;
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
namespace AssetStudio.PInvoke
{
// Generally the technique from Steamworks.NET
public class Utf8StringHandle : SafeHandleZeroOrMinusOneIsInvalid
{
static Utf8StringHandle()
{
Utf8 = new UTF8Encoding(false);
}
public Utf8StringHandle(string str)
: base(true)
{
IntPtr buffer;
if (str == null)
{
buffer = IntPtr.Zero;
}
else
{
if (str.Length == 0)
{
buffer = Marshal.AllocHGlobal(1);
unsafe
{
*(byte*)buffer = 0;
}
}
else
{
var strlen = Utf8.GetByteCount(str);
var strBuffer = new byte[strlen + 1];
Utf8.GetBytes(str, 0, str.Length, strBuffer, 0);
buffer = Marshal.AllocHGlobal(strBuffer.Length);
Marshal.Copy(strBuffer, 0, buffer, strBuffer.Length);
}
}
SetHandle(buffer);
}
public static string ReadUtf8StringFromPointer(IntPtr lpstr)
{
if (lpstr == IntPtr.Zero || lpstr == new IntPtr(-1))
{
return null;
}
var byteCount = 0;
unsafe
{
var p = (byte*)lpstr.ToPointer();
while (*p != 0)
{
byteCount += 1;
p += 1;
}
}
if (byteCount == 0)
{
return string.Empty;
}
var strBuffer = new byte[byteCount];
Marshal.Copy(lpstr, strBuffer, 0, byteCount);
var str = Utf8.GetString(strBuffer);
return str;
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
Marshal.FreeHGlobal(handle);
}
return true;
}
private static readonly UTF8Encoding Utf8;
}
}