From f9c1f4e739c0dab3aa6af4b34eaa0b42d18c1122 Mon Sep 17 00:00:00 2001 From: glax Date: Mon, 15 Apr 2024 22:56:46 +0200 Subject: [PATCH] Moved user32Dll Imports to seperate File. Added Z-Order. --- OBSBlur/Window/WindowManager.cs | 74 +++++++++++++----------- OBSBlur/Window/WindowManagerUser32Dll.cs | 65 +++++++++++++++++++++ 2 files changed, 105 insertions(+), 34 deletions(-) create mode 100644 OBSBlur/Window/WindowManagerUser32Dll.cs diff --git a/OBSBlur/Window/WindowManager.cs b/OBSBlur/Window/WindowManager.cs index 4c58893..6ecf22c 100644 --- a/OBSBlur/Window/WindowManager.cs +++ b/OBSBlur/Window/WindowManager.cs @@ -1,12 +1,13 @@ using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; namespace OBSBlur.Window; -public class WindowManager : IDisposable +public partial class WindowManager : IDisposable { - public readonly HashSet Windows = new(1024); + private readonly HashSet _windows = new(1024); + private List _zOrder = GetWindowZOrder(); + public IntPtr[] WindowZOrder => _zOrder.ToArray(); + public WindowInfo[] WindowInfos => _windows.ToArray(); public int UpdateInterval = 10; private bool _keepUpdating = true; public WindowManager() @@ -15,14 +16,46 @@ public class WindowManager : IDisposable { while (_keepUpdating) { - Windows.Clear(); + WindowInfo[] windowInfoBefore = WindowInfos; + IntPtr[] zOrderBefore = WindowZOrder; + _windows.Clear(); EnumWindows(GetWindowInfo, 0); + _zOrder = GetWindowZOrder(); + + WindowsUpdated?.Invoke(WindowInfos); + WindowInfo[] changedWindows = WindowInfos.Where(info => !windowInfoBefore.Contains(info)).ToArray(); + if(changedWindows.Length > 0) + WindowsChanged?.Invoke(windowInfoBefore.Where(b => changedWindows.Select(c => c.WindowHandle).Contains(b.WindowHandle)).ToArray(), changedWindows); + if (zOrderBefore.Length != WindowZOrder.Length) + WindowZOrderChanged?.Invoke(WindowZOrder); + else + { + IntPtr[] zOrderAfter = WindowZOrder; + for(int i = 0; i < zOrderBefore.Length; i++) + if (!zOrderBefore[i].Equals(zOrderAfter[i])) + { + WindowZOrderChanged?.Invoke(zOrderAfter); + break; + } + + } + + Thread.Sleep(UpdateInterval); } - Thread.Sleep(UpdateInterval); }); t.Start(); } + public delegate void WindowsUpdatedHandler(WindowInfo[] windowInfos); + public event WindowsUpdatedHandler WindowsUpdated; + + public delegate void WindowsChangedHandler(WindowInfo[] before, WindowInfo[] after); + public event WindowsChangedHandler WindowsChanged; + + public delegate void WindowZOrderChangedHandler(IntPtr[] newOrder); + + public event WindowZOrderChangedHandler WindowZOrderChanged; + private bool GetWindowInfo(IntPtr windowHandle, IntPtr lParam) { WindowPlacement windowPlacement = new (); @@ -43,38 +76,11 @@ public class WindowManager : IDisposable if (windowTitle.Length < 1) return true; - Windows.Add(new WindowInfo(windowHandle, windowTitle, processInfo, windowPlacement)); + _windows.Add(new WindowInfo(windowHandle, windowTitle, processInfo, windowPlacement)); return true; } - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); - - private delegate bool EnumWindowsProc(IntPtr windowHandle, IntPtr lParam); - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowPlacement(IntPtr windowHandle, ref WindowPlacement lpwndpl); - - [DllImport("user32.dll")] - private static extern uint GetWindowThreadProcessId(IntPtr windowHandle, out uint lpdwProcessId); - - - [DllImport("user32.dll", CharSet = CharSet.Auto)] - static extern IntPtr SendMessage(IntPtr windowHandle, uint message, IntPtr wParam, [Out] StringBuilder lParam); - - public static string GetWindowTextRaw(IntPtr windowHandle) - { - // ReSharper disable twice InconsistentNaming - const uint WM_GETTEXTLENGTH = 0x000E; - const uint WM_GETTEXT = 0x000D; - // Allocate correct string length first - int length = (int)SendMessage(windowHandle, WM_GETTEXTLENGTH, IntPtr.Zero, null); - StringBuilder sb = new (length + 1); - SendMessage(windowHandle, WM_GETTEXT, sb.Capacity, sb); - return sb.ToString(); - } public void Dispose() { diff --git a/OBSBlur/Window/WindowManagerUser32Dll.cs b/OBSBlur/Window/WindowManagerUser32Dll.cs new file mode 100644 index 0000000..5a7b4ce --- /dev/null +++ b/OBSBlur/Window/WindowManagerUser32Dll.cs @@ -0,0 +1,65 @@ +using System.Runtime.InteropServices; +using System.Text; + +namespace OBSBlur.Window; + +public partial class WindowManager +{ + [DllImport("user32.dll")] + private static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll", SetLastError = true)] + static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); + + [DllImport("user32.dll", SetLastError = true)] + static extern IntPtr GetDesktopWindow(); + + [DllImport("user32.dll")] + static extern IntPtr GetTopWindow(IntPtr hWnd); + static List GetWindowZOrder() + { + const uint GW_HWNDNEXT = 2; + const uint GW_HWNDLAST = 1; + IntPtr desktopWindow = GetDesktopWindow(); + IntPtr topWindow = GetTopWindow(desktopWindow); + IntPtr bottomWindow = GetWindow(topWindow, GW_HWNDLAST); + + IntPtr currentWindow = topWindow; + List order = new(); + do + { + order.Add(currentWindow); + } while ((currentWindow = GetWindow(currentWindow, GW_HWNDNEXT)) != bottomWindow); + + return order; + } + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); + + private delegate bool EnumWindowsProc(IntPtr windowHandle, IntPtr lParam); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowPlacement(IntPtr windowHandle, ref WindowPlacement lpwndpl); + + [DllImport("user32.dll")] + private static extern uint GetWindowThreadProcessId(IntPtr windowHandle, out uint lpdwProcessId); + + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + static extern IntPtr SendMessage(IntPtr windowHandle, uint message, IntPtr wParam, [Out] StringBuilder lParam); + + public static string GetWindowTextRaw(IntPtr windowHandle) + { + // ReSharper disable twice InconsistentNaming + const uint WM_GETTEXTLENGTH = 0x000E; + const uint WM_GETTEXT = 0x000D; + // Allocate correct string length first + int length = (int)SendMessage(windowHandle, WM_GETTEXTLENGTH, IntPtr.Zero, null); + StringBuilder sb = new (length + 1); + SendMessage(windowHandle, WM_GETTEXT, sb.Capacity, sb); + return sb.ToString(); + } +} \ No newline at end of file