10 changed files with 259 additions and 10 deletions
@ -0,0 +1 @@ |
|||||
|
native |
||||
@ -0,0 +1,233 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Diagnostics; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
|
||||
|
//Library loaders were taken from https://github.com/kekekeks/evhttp-sharp/tree/master/EvHttpSharp/Interop (MIT licensed)
|
||||
|
|
||||
|
namespace Perspex.Skia |
||||
|
{ |
||||
|
class MethodTableImpl : MethodTable |
||||
|
{ |
||||
|
public MethodTableImpl() : base(GetMethodTable()) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
class DetectedPlatformInfo |
||||
|
{ |
||||
|
public DetectedPlatformInfo(IDynLoader loader, string name, string cpuArch, string dllExtension) |
||||
|
{ |
||||
|
Loader = loader; |
||||
|
Name = name; |
||||
|
CpuArch = cpuArch; |
||||
|
DllExtension = dllExtension; |
||||
|
} |
||||
|
|
||||
|
public IDynLoader Loader { get; } |
||||
|
public string Name { get; } |
||||
|
public string CpuArch { get;} |
||||
|
public string DllExtension { get; } |
||||
|
} |
||||
|
|
||||
|
static DetectedPlatformInfo DetectPlatform() |
||||
|
{ |
||||
|
var macInfo = new DetectedPlatformInfo(new OsxLoader(), "Darwin", IntPtr.Size == 4 ? "i686" : "x86_64", ".dylib"); |
||||
|
switch (Environment.OSVersion.Platform) |
||||
|
{ |
||||
|
case PlatformID.Unix: |
||||
|
// Well, there are chances MacOSX is reported as Unix instead of MacOSX.
|
||||
|
// Instead of platform check, we'll do a feature checks (Mac specific root folders)
|
||||
|
if (Directory.Exists("/Applications") |
||||
|
& Directory.Exists("/System") |
||||
|
& Directory.Exists("/Users") |
||||
|
& Directory.Exists("/Volumes")) |
||||
|
return macInfo; |
||||
|
else |
||||
|
{ |
||||
|
string cpuArch; |
||||
|
using (var proc = |
||||
|
Process.Start( |
||||
|
(new ProcessStartInfo("uname", "-p") |
||||
|
{ |
||||
|
UseShellExecute = false, |
||||
|
RedirectStandardOutput = true |
||||
|
}))) |
||||
|
{ |
||||
|
proc.WaitForExit(); |
||||
|
cpuArch = proc.StandardOutput.ReadToEnd().Trim(); |
||||
|
} |
||||
|
return new DetectedPlatformInfo(new LinuxLoader(), "Linux", cpuArch, ".so"); |
||||
|
} |
||||
|
|
||||
|
case PlatformID.MacOSX: |
||||
|
return macInfo; |
||||
|
|
||||
|
default: |
||||
|
return new DetectedPlatformInfo(new Win32Loader(), "Windows", IntPtr.Size == 4 ? "i686" : "x86_64", ".dll"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static IEnumerable<string> GeneratePossiblePaths() |
||||
|
{ |
||||
|
foreach ( |
||||
|
var basePath in |
||||
|
new[] {Assembly.GetEntryAssembly(), typeof (MethodTable).Assembly}.Select( |
||||
|
a => Path.GetDirectoryName(a.GetModules()[0].FullyQualifiedName)) |
||||
|
.Concat(new[] { Directory.GetCurrentDirectory()})) |
||||
|
{ |
||||
|
yield return Path.Combine(basePath); |
||||
|
yield return Path.Combine(basePath, "native"); |
||||
|
yield return Path.Combine(basePath, "lib"); |
||||
|
yield return Path.Combine(basePath, "lib", "native"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static IntPtr GetMethodTable() |
||||
|
{ |
||||
|
var plat = DetectPlatform(); |
||||
|
|
||||
|
var name = "libperspesk" + plat.DllExtension; |
||||
|
var paths = GeneratePossiblePaths().Select(p => Path.Combine(p, plat.Name, plat.CpuArch, name)).ToList(); |
||||
|
var dll = paths.FirstOrDefault(File.Exists); |
||||
|
var msg = "Unable to find native library in following paths: '" + |
||||
|
string.Join("', '", paths) + "'"; |
||||
|
Console.Error.WriteLine(msg); |
||||
|
if (dll == null) |
||||
|
throw new FileNotFoundException(msg); |
||||
|
IntPtr hLib = plat.Loader.LoadLibrary(dll); |
||||
|
IntPtr pGetMethodTable = plat.Loader.GetProcAddress(hLib, "GetPerspexMethodTable"); |
||||
|
var getTable = (GetPerspexMethodTableDelegate) |
||||
|
Marshal.GetDelegateForFunctionPointer(pGetMethodTable, typeof (GetPerspexMethodTableDelegate)); |
||||
|
return getTable(); |
||||
|
} |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] |
||||
|
delegate IntPtr GetPerspexMethodTableDelegate(); |
||||
|
|
||||
|
|
||||
|
internal interface IDynLoader |
||||
|
{ |
||||
|
IntPtr LoadLibrary(string dll); |
||||
|
IntPtr GetProcAddress(IntPtr dll, string proc); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
class LinuxLoader : IDynLoader |
||||
|
{ |
||||
|
// ReSharper disable InconsistentNaming
|
||||
|
[DllImport("libdl.so.2")] |
||||
|
private static extern IntPtr dlopen(string path, int flags); |
||||
|
|
||||
|
[DllImport("libdl.so.2")] |
||||
|
private static extern IntPtr dlsym(IntPtr handle, string symbol); |
||||
|
|
||||
|
[DllImport("libdl.so.2")] |
||||
|
private static extern IntPtr dlerror(); |
||||
|
|
||||
|
// ReSharper restore InconsistentNaming
|
||||
|
|
||||
|
static string DlError() |
||||
|
{ |
||||
|
return Marshal.PtrToStringAuto(dlerror()); |
||||
|
} |
||||
|
|
||||
|
public IntPtr LoadLibrary(string dll) |
||||
|
{ |
||||
|
var handle = dlopen(dll, 1); |
||||
|
if (handle == IntPtr.Zero) |
||||
|
throw new Win32Exception(DlError()); |
||||
|
return handle; |
||||
|
} |
||||
|
|
||||
|
public IntPtr GetProcAddress(IntPtr dll, string proc) |
||||
|
{ |
||||
|
var ptr = dlsym(dll, proc); |
||||
|
if (ptr == IntPtr.Zero) |
||||
|
throw new Win32Exception(DlError()); |
||||
|
return ptr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class Win32Loader : IDynLoader |
||||
|
{ |
||||
|
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] |
||||
|
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); |
||||
|
|
||||
|
[DllImport("kernel32", EntryPoint = "LoadLibraryW", SetLastError = true, CharSet = CharSet.Unicode)] |
||||
|
private static extern IntPtr LoadLibrary(string lpszLib); |
||||
|
|
||||
|
[DllImport("kernel32", EntryPoint = "SetDllDirectoryW", SetLastError = true, CharSet = CharSet.Unicode)] |
||||
|
extern static bool SetDllDirectory(string lpPathName); |
||||
|
|
||||
|
[DllImport("kernel32", EntryPoint = "GetDllDirectoryW", SetLastError = true, CharSet = CharSet.Unicode)] |
||||
|
extern static int GetDllDirectory(int nBufferLength, char[] lpBuffer); |
||||
|
|
||||
|
IntPtr IDynLoader.LoadLibrary(string dll) |
||||
|
{ |
||||
|
var buffer = new char[2048]; |
||||
|
int oldLen = GetDllDirectory(buffer.Length, buffer); |
||||
|
var oldDir = new string(buffer, 0, oldLen); |
||||
|
|
||||
|
SetDllDirectory(Path.GetDirectoryName(dll)); |
||||
|
|
||||
|
var handle = LoadLibrary(dll); |
||||
|
if (handle == IntPtr.Zero) |
||||
|
throw new Win32Exception(Marshal.GetLastWin32Error()); |
||||
|
SetDllDirectory(oldDir); |
||||
|
|
||||
|
return handle; |
||||
|
} |
||||
|
|
||||
|
IntPtr IDynLoader.GetProcAddress(IntPtr dll, string proc) |
||||
|
{ |
||||
|
var ptr = GetProcAddress(dll, proc); |
||||
|
if (ptr == IntPtr.Zero) |
||||
|
throw new Win32Exception(Marshal.GetLastWin32Error()); |
||||
|
return ptr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class OsxLoader : IDynLoader |
||||
|
{ |
||||
|
// ReSharper disable InconsistentNaming
|
||||
|
[DllImport("/usr/lib/libSystem.dylib")] |
||||
|
public static extern IntPtr dlopen(string path, int mode); |
||||
|
|
||||
|
[DllImport("/usr/lib/libSystem.dylib")] |
||||
|
private static extern IntPtr dlsym(IntPtr handle, string symbol); |
||||
|
|
||||
|
[DllImport("/usr/lib/libSystem.dylib")] |
||||
|
private static extern IntPtr dlerror(); |
||||
|
|
||||
|
// ReSharper restore InconsistentNaming
|
||||
|
|
||||
|
static string DlError() |
||||
|
{ |
||||
|
return Marshal.PtrToStringAuto(dlerror()); |
||||
|
} |
||||
|
|
||||
|
public IntPtr LoadLibrary(string dll) |
||||
|
{ |
||||
|
var handle = dlopen(dll, 1); |
||||
|
if (handle == IntPtr.Zero) |
||||
|
throw new Win32Exception(DlError()); |
||||
|
return handle; |
||||
|
} |
||||
|
|
||||
|
public IntPtr GetProcAddress(IntPtr dll, string proc) |
||||
|
{ |
||||
|
var ptr = dlsym(dll, proc); |
||||
|
if (ptr == IntPtr.Zero) |
||||
|
throw new Win32Exception(DlError()); |
||||
|
return ptr; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,10 @@ |
|||||
|
$scriptpath = $MyInvocation.MyCommand.Path |
||||
|
$dir = Split-Path $scriptpath |
||||
|
Push-Location $dir |
||||
|
|
||||
|
Add-Type -AssemblyName System.IO.Compression.FileSystem |
||||
|
rm -Force -Recurse .\native -ErrorAction SilentlyContinue |
||||
|
mkdir native |
||||
|
$url = cat native.url |
||||
|
Invoke-WebRequest $url -OutFile native\native.zip |
||||
|
[System.IO.Compression.ZipFile]::ExtractToDirectory("native\native.zip", "native") |
||||
@ -0,0 +1 @@ |
|||||
|
https://dl.dropboxusercontent.com/u/18301199/Perspex.Skia/abi-0001.zip |
||||
Loading…
Reference in new issue