Created
November 10, 2019 03:27
-
-
Save TinkerWorX/0162901e8d9b04c93b7f603737adcec2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
namespace Ultralight.Net.Interop | |
{ | |
[StructLayout(LayoutKind.Sequential)] | |
public struct Platform | |
{ | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
public delegate IntPtr GetterDelegate(IntPtr that); | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
public delegate void SetterDelegate(IntPtr that, IntPtr value); | |
public struct VirtualTable | |
{ | |
public IntPtr dtor; | |
public IntPtr comparer; | |
public IntPtr config; | |
public IntPtr set_gpu_driver; | |
public IntPtr gpu_driver; | |
public IntPtr set_font_loader; | |
public IntPtr font_loader; | |
public IntPtr set_file_system; | |
public IntPtr file_system; | |
} | |
private readonly unsafe VirtualTable* methods; | |
public IntPtr config() | |
{ | |
unsafe | |
{ | |
fixed (Platform* pThis = &this) | |
{ | |
var function = Marshal.GetDelegateForFunctionPointer<GetterDelegate>(this.methods->config); | |
return function(new IntPtr(pThis)); | |
} | |
} | |
} | |
public void set_gpu_driver(IntPtr value) | |
{ | |
unsafe | |
{ | |
fixed (Platform* pThis = &this) | |
{ | |
var function = Marshal.GetDelegateForFunctionPointer<SetterDelegate>(this.methods->set_gpu_driver); | |
function(new IntPtr(pThis), value); | |
} | |
} | |
} | |
public IntPtr gpu_driver() | |
{ | |
unsafe | |
{ | |
fixed (Platform* pThis = &this) | |
{ | |
var function = Marshal.GetDelegateForFunctionPointer<GetterDelegate>(this.methods->gpu_driver); | |
return function(new IntPtr(pThis)); | |
} | |
} | |
} | |
public IntPtr font_loader() | |
{ | |
unsafe | |
{ | |
fixed (Platform* pThis = &this) | |
{ | |
var function = Marshal.GetDelegateForFunctionPointer<GetterDelegate>(this.methods->font_loader); | |
return function(new IntPtr(pThis)); | |
} | |
} | |
} | |
public void set_font_loader(IntPtr value) | |
{ | |
unsafe | |
{ | |
fixed (Platform* pThis = &this) | |
{ | |
var function = Marshal.GetDelegateForFunctionPointer<SetterDelegate>(this.methods->set_font_loader); | |
function(new IntPtr(pThis), value); | |
} | |
} | |
} | |
public IntPtr file_system() | |
{ | |
unsafe | |
{ | |
fixed (Platform* pThis = &this) | |
{ | |
var function = Marshal.GetDelegateForFunctionPointer<GetterDelegate>(this.methods->file_system); | |
return function(new IntPtr(pThis)); | |
} | |
} | |
} | |
public void set_file_system(IntPtr value) | |
{ | |
unsafe | |
{ | |
fixed (Platform* pThis = &this) | |
{ | |
var function = Marshal.GetDelegateForFunctionPointer<SetterDelegate>(this.methods->set_file_system); | |
function(new IntPtr(pThis), value); | |
} | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
using System.Threading; | |
namespace Ultralight.Net.ConsoleDemo | |
{ | |
public class FileSystem | |
{ | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
private delegate IntPtr EmptyMethodDelegate(IntPtr pThis); | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
[return: MarshalAs(UnmanagedType.I1)] | |
private delegate bool FileExistsDelegate(IntPtr pThis, IntPtr pPath); | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
[return: MarshalAs(UnmanagedType.I1)] | |
private delegate bool GetFileSizeADelegate(IntPtr pThis, IntPtr pFile, out long length); | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
[return: MarshalAs(UnmanagedType.I1)] | |
private delegate bool GetFileSizeBDelegate(IntPtr pThis, IntPtr pPath, out long length); | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
[return: MarshalAs(UnmanagedType.I1)] | |
private delegate bool GetFileMimeTypeDelegate(IntPtr pThis, IntPtr pPath, IntPtr pResult); | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
private delegate IntPtr OpenFileDelegate(IntPtr pThis, IntPtr pPath, [MarshalAs(UnmanagedType.I1)] bool openForWriting); | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
private delegate void CloseFileDelegate(IntPtr pThis, IntPtr pFile); | |
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
private delegate long ReadFromFileDelegate(IntPtr pThis, IntPtr pFile, IntPtr pBuffer, long length); | |
public struct VirtualTable | |
{ | |
public IntPtr dtor; | |
public IntPtr FileExists; // must implement | |
public IntPtr DeleteFile_; | |
public IntPtr DeleteEmptyDirectory; | |
public IntPtr MoveFile_; | |
public IntPtr GetFileSizeA; // must implement | |
public IntPtr GetFileSizeB; // must implement | |
public IntPtr GetFileMimeType; // must implement | |
public IntPtr GetFileModificationTime; | |
public IntPtr GetFileCreationTime; | |
public IntPtr GetMetadataType; | |
public IntPtr GetPathByAppendingComponent; | |
public IntPtr CreateDirectory_; | |
public IntPtr GetHomeDirectory; | |
public IntPtr GetFilenameFromPath; | |
public IntPtr GetDirectoryNameFromPath; | |
public IntPtr GetVolumeFreeSpace; | |
public IntPtr GetVolumeId; | |
public IntPtr ListDirectory; | |
public IntPtr OpenTemporaryFile; | |
public IntPtr OpenFile; // must implement | |
public IntPtr CloseFile; // must implement | |
public IntPtr SeekFile; | |
public IntPtr TruncateFile; | |
public IntPtr WriteToFile; | |
public IntPtr ReadFromFile; // must implement | |
public IntPtr CopyFile_; | |
} | |
public readonly unsafe VirtualTable* Methods; | |
public FileSystem() | |
{ | |
unsafe | |
{ | |
this.Methods = (VirtualTable*)Marshal.AllocHGlobal(sizeof(VirtualTable)); | |
this.Methods->dtor = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->FileExists = Marshal.GetFunctionPointerForDelegate<FileExistsDelegate>(this.FileExists); | |
this.Methods->DeleteFile_ = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->DeleteEmptyDirectory = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->MoveFile_ = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetFileSizeA = Marshal.GetFunctionPointerForDelegate<GetFileSizeADelegate>(this.GetFileSizeA); | |
this.Methods->GetFileSizeB = Marshal.GetFunctionPointerForDelegate<GetFileSizeBDelegate>(this.GetFileSizeB); | |
this.Methods->GetFileMimeType = Marshal.GetFunctionPointerForDelegate<GetFileMimeTypeDelegate>(this.GetFileMimeType); | |
this.Methods->GetFileModificationTime = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetFileCreationTime = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetMetadataType = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetPathByAppendingComponent = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->CreateDirectory_ = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetHomeDirectory = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetFilenameFromPath = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetDirectoryNameFromPath = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetVolumeFreeSpace = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->GetVolumeId = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->ListDirectory = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->OpenTemporaryFile = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->OpenFile = Marshal.GetFunctionPointerForDelegate<OpenFileDelegate>(this.OpenFile); | |
this.Methods->CloseFile = Marshal.GetFunctionPointerForDelegate<CloseFileDelegate>(this.CloseFile); | |
this.Methods->SeekFile = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->TruncateFile = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->WriteToFile = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
this.Methods->ReadFromFile = Marshal.GetFunctionPointerForDelegate<ReadFromFileDelegate>(this.ReadFromFile); | |
this.Methods->CopyFile_ = Marshal.GetFunctionPointerForDelegate<EmptyMethodDelegate>(this.EmptyMethod); | |
} | |
} | |
private IntPtr EmptyMethod(IntPtr pThis) | |
{ | |
Console.WriteLine($"EmptyMethod({pThis.ToString("X16")})"); | |
return IntPtr.Zero; | |
} | |
private bool FileExists(IntPtr pThis, IntPtr pPath) | |
{ | |
Console.WriteLine($"FileExists({pThis.ToString("X16")}, ...)"); | |
return false; | |
} | |
private bool GetFileSizeA(IntPtr pThis, IntPtr pFile, out long length) | |
{ | |
Console.WriteLine($"GetFileSize({pThis.ToString("X16")}, ...)"); | |
length = file.Length; | |
return true; | |
} | |
private bool GetFileSizeB(IntPtr pThis, IntPtr pPath, out long length) | |
{ | |
var path = Marshal.PtrToStringUni(Marshal.ReadIntPtr(pPath)); | |
Console.WriteLine($"GetFileSize({pThis.ToString("X16")}, {path}, ...)"); | |
length = 0; | |
return false; | |
} | |
private bool GetFileMimeType(IntPtr pThis, IntPtr pPath, IntPtr pResult) | |
{ | |
var path = Marshal.PtrToStringUni(Marshal.ReadIntPtr(pPath)); | |
Console.WriteLine($"GetFileMimeType({pThis.ToString("X16")}, {path}, ...)"); | |
Interop.UltralightApi.String16__Create(pResult, "text/html"); | |
return true; | |
} | |
private System.IO.FileStream file; | |
private IntPtr OpenFile(IntPtr pThis, IntPtr pPath, bool openForWriting) | |
{ | |
var path = Marshal.PtrToStringUni(Marshal.ReadIntPtr(pPath)); | |
Console.WriteLine($"OpenFile({pThis.ToString("X16")}, {path}, {openForWriting})"); | |
this.file = System.IO.File.OpenRead(path); | |
return IntPtr.Zero; | |
} | |
private void CloseFile(IntPtr pThis, IntPtr pFile) | |
{ | |
Console.WriteLine($"CloseFile({pThis.ToString("X16")}, ...)"); | |
this.file?.Close(); | |
this.file?.Dispose(); | |
this.file = null; | |
} | |
private long ReadFromFile(IntPtr pThis, IntPtr pFile, IntPtr pBuffer, long length) | |
{ | |
Console.WriteLine($"ReadFromFile({pThis.ToString("X16")}, ..., {length})"); | |
unsafe | |
{ | |
return file.Read(new Span<byte>((void*)pBuffer, (int)length)); | |
} | |
} | |
} | |
public class Program | |
{ | |
public unsafe static void Main(string[] args) | |
{ | |
ULRenderer.Initialize(new ULConfig()); | |
var instance = Interop.UltralightApi.Platform__Instance(); | |
var fileSystem = new FileSystem(); | |
var pFileSystem = fileSystem.Methods; | |
instance->set_file_system(new IntPtr(&pFileSystem)); | |
var view = ULRenderer.Instance.CreateView(512, 512, true); | |
view.ConsoleMessage += (sender, e) => { Console.WriteLine($"ConsoleMessage({e.Message})"); }; | |
view.CursorChanged += (sender, e) => { Console.WriteLine($"CursorChanged({e.Cursor})"); }; | |
view.DocumentObjectModelReady += (sender, e) => { Console.WriteLine("DocumentObjectModelReady()"); }; | |
view.HistoryUpdated += (sender, e) => { Console.WriteLine("HistoryUpdated()"); }; | |
view.LoadingBegun += (sender, e) => { Console.WriteLine("LoadingBegun()"); }; | |
view.LoadingFinished += (sender, e) => { Console.WriteLine("LoadingFinished()"); }; | |
view.TitleChanged += (sender, e) => { Console.WriteLine($"TitleChanged(\"{e.Title}\")"); }; | |
view.TooltipChanged += (sender, e) => { Console.WriteLine($"TooltipChanged(\"{e.Tooltip}\")"); }; | |
view.UrlChanged += (sender, e) => { Console.WriteLine($"UrlChanged(\"{e.Url}\")"); }; | |
view.LoadUrl("file:///D:/Development/Desolation/Prototyping/UltralightMvvm/UltralightMvvm/Views/Main.html"); | |
while (true) | |
{ | |
ULRenderer.Instance.Update(); | |
ULRenderer.Instance.Render(); | |
if (view.IsBitmapDirty) | |
{ | |
Console.WriteLine("Bitmap is dirty"); | |
unsafe | |
{ | |
using var path = new ULString(System.IO.Path.Combine(Environment.CurrentDirectory, "output.png")); | |
Console.WriteLine("Saving to " + path); | |
Interop.UltralightApi.ulBitmapWritePNG(view.GetBitmap().DangerousGetHandle() /* clears the dirty flag */, path.DangerousGetHandle()); | |
} | |
} | |
Thread.Sleep(100); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment