committed by
GitHub
4 changed files with 161 additions and 61 deletions
@ -1,59 +1,10 @@ |
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Runtime.InteropServices; |
|||
using Avalonia.Win32.Interop; |
|||
|
|||
namespace Avalonia.Win32 |
|||
{ |
|||
internal class OffscreenParentWindow |
|||
{ |
|||
public static IntPtr Handle { get; } = CreateParentWindow(); |
|||
|
|||
private static UnmanagedMethods.WndProc? s_wndProcDelegate; |
|||
|
|||
private static IntPtr CreateParentWindow() |
|||
{ |
|||
s_wndProcDelegate = ParentWndProc; |
|||
|
|||
var wndClassEx = new UnmanagedMethods.WNDCLASSEX |
|||
{ |
|||
cbSize = Marshal.SizeOf<UnmanagedMethods.WNDCLASSEX>(), |
|||
hInstance = UnmanagedMethods.GetModuleHandle(null), |
|||
lpfnWndProc = s_wndProcDelegate, |
|||
lpszClassName = "AvaloniaEmbeddedWindow-" + Guid.NewGuid(), |
|||
}; |
|||
|
|||
var atom = UnmanagedMethods.RegisterClassEx(ref wndClassEx); |
|||
|
|||
if (atom == 0) |
|||
{ |
|||
throw new Win32Exception(); |
|||
} |
|||
|
|||
var hwnd = UnmanagedMethods.CreateWindowEx( |
|||
0, |
|||
atom, |
|||
null, |
|||
(int)UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW, |
|||
UnmanagedMethods.CW_USEDEFAULT, |
|||
UnmanagedMethods.CW_USEDEFAULT, |
|||
UnmanagedMethods.CW_USEDEFAULT, |
|||
UnmanagedMethods.CW_USEDEFAULT, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero); |
|||
|
|||
if (hwnd == IntPtr.Zero) |
|||
{ |
|||
throw new Win32Exception(); |
|||
} |
|||
|
|||
return hwnd; |
|||
} |
|||
|
|||
private static IntPtr ParentWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) |
|||
{ |
|||
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); |
|||
} |
|||
private static SimpleWindow s_simpleWindow = new(null); |
|||
public static IntPtr Handle { get; } = s_simpleWindow.Handle; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,92 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.ComponentModel; |
|||
using System.Runtime.InteropServices; |
|||
using Avalonia.Win32.Interop; |
|||
|
|||
namespace Avalonia.Win32; |
|||
|
|||
internal class SimpleWindow : IDisposable |
|||
{ |
|||
private readonly UnmanagedMethods.WndProc? _wndProc; |
|||
private static UnmanagedMethods.WndProc s_wndProcDelegate; |
|||
public IntPtr Handle { get; private set; } |
|||
private static string s_className; |
|||
private static uint s_classAtom; |
|||
private static ConcurrentDictionary<IntPtr, SimpleWindow> s_Instances = new(); |
|||
|
|||
static SimpleWindow() |
|||
{ |
|||
s_wndProcDelegate = WndProc; |
|||
var wndClassEx = new UnmanagedMethods.WNDCLASSEX |
|||
{ |
|||
cbSize = Marshal.SizeOf<UnmanagedMethods.WNDCLASSEX>(), |
|||
hInstance = UnmanagedMethods.GetModuleHandle(null), |
|||
lpfnWndProc = s_wndProcDelegate, |
|||
lpszClassName = s_className = "AvaloniaSimpleWindow-" + Guid.NewGuid(), |
|||
}; |
|||
|
|||
s_classAtom = UnmanagedMethods.RegisterClassEx(ref wndClassEx); |
|||
} |
|||
|
|||
public SimpleWindow(UnmanagedMethods.WndProc? wndProc) |
|||
{ |
|||
_wndProc = wndProc; |
|||
var handle = GCHandle.Alloc(this); |
|||
try |
|||
{ |
|||
var hwnd = UnmanagedMethods.CreateWindowEx( |
|||
0, |
|||
s_classAtom, |
|||
null, |
|||
(int)UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW, |
|||
UnmanagedMethods.CW_USEDEFAULT, |
|||
UnmanagedMethods.CW_USEDEFAULT, |
|||
UnmanagedMethods.CW_USEDEFAULT, |
|||
UnmanagedMethods.CW_USEDEFAULT, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero, |
|||
GCHandle.ToIntPtr(handle)); |
|||
if (hwnd == IntPtr.Zero) |
|||
{ |
|||
throw new Win32Exception(); |
|||
} |
|||
|
|||
Handle = hwnd; |
|||
} |
|||
finally |
|||
{ |
|||
handle.Free(); |
|||
} |
|||
} |
|||
|
|||
private static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) |
|||
{ |
|||
SimpleWindow? window; |
|||
if (msg == (uint)UnmanagedMethods.WindowsMessage.WM_CREATE) |
|||
{ |
|||
var handle = Marshal.ReadIntPtr(lParam); |
|||
window = (SimpleWindow?)GCHandle.FromIntPtr(handle).Target; |
|||
if (window == null) |
|||
return IntPtr.Zero; |
|||
s_Instances.TryAdd(hWnd, window); |
|||
} |
|||
else |
|||
{ |
|||
s_Instances.TryGetValue(hWnd, out window); |
|||
} |
|||
|
|||
if (msg == (uint)UnmanagedMethods.WindowsMessage.WM_DESTROY) |
|||
s_Instances.TryRemove(hWnd, out _); |
|||
|
|||
return window?._wndProc?.Invoke(hWnd, msg, wParam, lParam) |
|||
?? UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
UnmanagedMethods.DestroyWindow(Handle); |
|||
Handle = IntPtr.Zero; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue