From ebe7f68e9d166381eb61f3a5656667ca5be44012 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 27 Apr 2023 10:50:13 +0200 Subject: [PATCH] Windows - Use user32 APIs to manage windows for input provider and Vulkan --- .../Extensions/IWindowImplExtensions.cs | 18 ------- .../Providers/Input/WindowsInputProvider.cs | 43 ++++------------ .../SkiaSharp/Vulkan/Win32VkContext.cs | 15 +++--- src/Artemis.UI.Windows/User32.cs | 51 +++++++++++++++++++ .../Utilities/WindowUtilities.cs | 11 +--- 5 files changed, 69 insertions(+), 69 deletions(-) delete mode 100644 src/Artemis.UI.Windows/Extensions/IWindowImplExtensions.cs create mode 100644 src/Artemis.UI.Windows/User32.cs diff --git a/src/Artemis.UI.Windows/Extensions/IWindowImplExtensions.cs b/src/Artemis.UI.Windows/Extensions/IWindowImplExtensions.cs deleted file mode 100644 index 18355336e..000000000 --- a/src/Artemis.UI.Windows/Extensions/IWindowImplExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Linq; -using Artemis.UI.Exceptions; -using Avalonia.Platform; - -namespace Artemis.UI.Windows.Extensions; - -public static class IWindowImplExtensions -{ - public static IPlatformHandle GetHandle(this IWindowImpl window) - { - // This is unfortunate - IPlatformHandle? handle = (IPlatformHandle?) window.GetType().GetProperties().FirstOrDefault(p => p.Name == "Handle")?.GetValue(window); - if (handle == null) - throw new ArtemisUIException("Could not get IWindowImpl internal platform handle, Avalonia API change?"); - - return handle; - } -} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs b/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs index 2052da205..45c5624d3 100644 --- a/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs +++ b/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs @@ -4,10 +4,7 @@ using System.Runtime.InteropServices; using System.Timers; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Windows.Extensions; using Artemis.UI.Windows.Utilities; -using Avalonia.Controls.Platform; -using Avalonia.Platform; using Linearstar.Windows.RawInput; using Linearstar.Windows.RawInput.Native; using Serilog; @@ -19,7 +16,7 @@ public class WindowsInputProvider : InputProvider private const int GWL_WNDPROC = -4; private const int WM_INPUT = 0x00FF; - private readonly IWindowImpl _window; + private readonly nint _hWnd; private readonly nint _hWndProcHook; private readonly WndProc? _fnWndProcHook; private readonly IInputService _inputService; @@ -32,7 +29,7 @@ public class WindowsInputProvider : InputProvider private nint CustomWndProc(nint hWnd, uint msg, nint wParam, nint lParam) { OnWndProcCalled(hWnd, msg, wParam, lParam); - return CallWindowProc(_hWndProcHook, hWnd, msg, wParam, lParam); + return User32.CallWindowProc(_hWndProcHook, hWnd, msg, wParam, lParam); } public WindowsInputProvider(ILogger logger, IInputService inputService) @@ -44,16 +41,14 @@ public class WindowsInputProvider : InputProvider _taskManagerTimer.Elapsed += TaskManagerTimerOnElapsed; _taskManagerTimer.Start(); - _window = PlatformManager.CreateWindow(); - - IPlatformHandle handle = _window.GetHandle(); - _hWndProcHook = GetWindowLongPtr(handle.Handle, GWL_WNDPROC); + _hWnd = User32.CreateWindowEx(0, "STATIC", "", 0x80000000, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + _hWndProcHook = User32.GetWindowLongPtr(_hWnd, GWL_WNDPROC); _fnWndProcHook = CustomWndProc; nint newLong = Marshal.GetFunctionPointerForDelegate(_fnWndProcHook); - SetWindowLongPtr(handle.Handle, GWL_WNDPROC, newLong); + User32.SetWindowLongPtr(_hWnd, GWL_WNDPROC, newLong); - RawInputDevice.RegisterDevice(HidUsageAndPage.Keyboard, RawInputDeviceFlags.InputSink, handle.Handle); - RawInputDevice.RegisterDevice(HidUsageAndPage.Mouse, RawInputDeviceFlags.InputSink, handle.Handle); + RawInputDevice.RegisterDevice(HidUsageAndPage.Keyboard, RawInputDeviceFlags.InputSink, _hWnd); + RawInputDevice.RegisterDevice(HidUsageAndPage.Mouse, RawInputDeviceFlags.InputSink, _hWnd); } public static Guid Id { get; } = new("6737b204-ffb1-4cd9-8776-9fb851db303a"); @@ -238,31 +233,11 @@ public class WindowsInputProvider : InputProvider #endregion #region Native - - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - static extern IntPtr CallWindowProc(nint lpPrevWndFunc, IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Unicode)] - private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); - - [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Unicode)] - private static extern IntPtr SetWindowLongPtr(nint hWnd, int nIndex, IntPtr dwNewLong); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetCursorPos(ref Win32Point pt); - - [StructLayout(LayoutKind.Sequential)] - private struct Win32Point - { - public readonly int X; - public readonly int Y; - } - + private static Win32Point GetCursorPosition() { Win32Point w32Mouse = new(); - GetCursorPos(ref w32Mouse); + User32.GetCursorPos(ref w32Mouse); return w32Mouse; } diff --git a/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Win32VkContext.cs b/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Win32VkContext.cs index 690f28168..6e70f6bdb 100644 --- a/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Win32VkContext.cs +++ b/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Win32VkContext.cs @@ -1,8 +1,5 @@ using System; using System.Linq; -using Artemis.UI.Windows.Extensions; -using Avalonia.Controls.Platform; -using Avalonia.Platform; using SharpVk; using SharpVk.Khronos; @@ -10,12 +7,16 @@ namespace Artemis.UI.Windows.SkiaSharp.Vulkan; internal sealed class Win32VkContext : VkContext { + private readonly nint _hWnd; + public Win32VkContext() { - Window = PlatformManager.CreateWindow(); + // Use WS_CHILD and WS_VISIBLE with WS_VISIBLE set to false + _hWnd = User32.CreateWindowEx(0, "STATIC", "", 0x80000000, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + Instance = Instance.Create(null, new[] {"VK_KHR_surface", "VK_KHR_win32_surface"}); PhysicalDevice = Instance.EnumeratePhysicalDevices().First(); - Surface = Instance.CreateWin32Surface(Kernel32.CurrentModuleHandle, Window.GetHandle().Handle); + Surface = Instance.CreateWin32Surface(Kernel32.CurrentModuleHandle, _hWnd); (GraphicsFamily, PresentFamily) = FindQueueFamilies(); @@ -45,12 +46,10 @@ internal sealed class Win32VkContext : VkContext }; } - public IWindowImpl Window { get; } - public override void Dispose() { base.Dispose(); - Window.Dispose(); + User32.DestroyWindow(_hWnd); } private IntPtr Proc(string name, IntPtr instanceHandle, IntPtr deviceHandle) diff --git a/src/Artemis.UI.Windows/User32.cs b/src/Artemis.UI.Windows/User32.cs new file mode 100644 index 000000000..b407f9e51 --- /dev/null +++ b/src/Artemis.UI.Windows/User32.cs @@ -0,0 +1,51 @@ +using System; +using System.Runtime.InteropServices; + +namespace Artemis.UI.Windows; + +static class User32 +{ + [DllImport("user32.dll")] + public static extern IntPtr CreateWindowEx( + uint dwExStyle, + string lpClassName, + string lpWindowName, + uint dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam); + + [DllImport("user32.dll")] + public static extern bool DestroyWindow(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll")] + public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + public static extern IntPtr CallWindowProc(nint lpPrevWndFunc, IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Unicode)] + public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Unicode)] + public static extern IntPtr SetWindowLongPtr(nint hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetCursorPos(ref Win32Point pt); +} + +[StructLayout(LayoutKind.Sequential)] +public struct Win32Point +{ + public readonly int X; + public readonly int Y; +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/Utilities/WindowUtilities.cs b/src/Artemis.UI.Windows/Utilities/WindowUtilities.cs index 414c12eab..716cc5892 100644 --- a/src/Artemis.UI.Windows/Utilities/WindowUtilities.cs +++ b/src/Artemis.UI.Windows/Utilities/WindowUtilities.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.InteropServices; namespace Artemis.UI.Windows.Utilities; @@ -8,15 +7,9 @@ public static class WindowUtilities public static int GetActiveProcessId() { // Get foreground window handle - IntPtr hWnd = GetForegroundWindow(); + IntPtr hWnd = User32.GetForegroundWindow(); - GetWindowThreadProcessId(hWnd, out uint processId); + User32.GetWindowThreadProcessId(hWnd, out uint processId); return (int) processId; } - - [DllImport("user32.dll")] - private static extern IntPtr GetForegroundWindow(); - - [DllImport("user32.dll")] - private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); } \ No newline at end of file