using System.Runtime.InteropServices; using Avalonia.Controls; using LanMountainDesktop.Platform.Abstractions; namespace LanMountainDesktop.Platform.Windows; /// /// Windows 桌面层实现:将窗口设为桌面图标宿主(SHELLDLL_DefView)的子窗口。 /// 自 LanMountainDesktop.Services.MainWindowDesktopLayerService 迁移,行为不变。 /// public sealed class WindowsMainWindowDesktopLayerService : IMainWindowDesktopLayerService { private const int GWL_STYLE = -16; private const int GWL_EXSTYLE = -20; private const long WS_CHILD = 0x40000000L; private const long WS_POPUP = 0x80000000L; private const long WS_CAPTION = 0x00C00000L; private const long WS_THICKFRAME = 0x00040000L; private const long WS_MINIMIZEBOX = 0x00020000L; private const long WS_MAXIMIZEBOX = 0x00010000L; private const long WS_SYSMENU = 0x00080000L; private const uint SWP_NOSIZE = 0x0001; private const uint SWP_NOMOVE = 0x0002; private const uint SWP_NOACTIVATE = 0x0010; private const uint SWP_SHOWWINDOW = 0x0040; private const uint SWP_FRAMECHANGED = 0x0020; private static readonly IntPtr HWND_TOP = IntPtr.Zero; private static readonly IntPtr HWND_BOTTOM = new(1); private readonly object _gate = new(); private readonly Dictionary _restoreStates = []; public bool IsSupported => true; public void EnableOrRefresh(Window window) { ArgumentNullException.ThrowIfNull(window); var handle = GetWindowHandle(window); if (handle == IntPtr.Zero) { window.Opened -= OnDeferredOpened; window.Opened += OnDeferredOpened; return; } EnableOrRefresh(handle); } public void Disable(Window window) { ArgumentNullException.ThrowIfNull(window); window.Opened -= OnDeferredOpened; var handle = GetWindowHandle(window); if (handle == IntPtr.Zero) { return; } WindowRestoreState? restoreState; lock (_gate) { if (!_restoreStates.Remove(handle, out restoreState)) { return; } } try { _ = SetParent(handle, restoreState.Parent); SetWindowLongPtr(handle, GWL_STYLE, restoreState.Style); SetWindowLongPtr(handle, GWL_EXSTYLE, restoreState.ExStyle); _ = SetWindowPos( handle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW); PlatformLog.Info("MainWindowDesktopLayer", $"Disabled desktop layer. Window={handle}."); } catch (Exception ex) { PlatformLog.Warn("MainWindowDesktopLayer", $"Failed to disable desktop layer. Window={handle}.", ex); } } private void OnDeferredOpened(object? sender, EventArgs e) { if (sender is not Window window) { return; } window.Opened -= OnDeferredOpened; EnableOrRefresh(window); } private void EnableOrRefresh(IntPtr handle) { if (handle == IntPtr.Zero || !IsWindow(handle)) { return; } SaveRestoreStateIfNeeded(handle); var desktopHost = ResolveDesktopIconHost(); if (desktopHost != IntPtr.Zero && IsWindow(desktopHost)) { ApplyDesktopChildStyle(handle); if (GetParent(handle) != desktopHost) { _ = SetParent(handle, desktopHost); } _ = SetWindowPos( handle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW); PlatformLog.Info("MainWindowDesktopLayer", $"Enabled desktop layer. Window={handle}; Host={desktopHost}."); return; } _ = SetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW); PlatformLog.Warn("MainWindowDesktopLayer", $"Desktop icon host not found. Falling back to HWND_BOTTOM. Window={handle}."); } private void SaveRestoreStateIfNeeded(IntPtr handle) { lock (_gate) { if (_restoreStates.ContainsKey(handle)) { return; } _restoreStates[handle] = new WindowRestoreState( GetParent(handle), GetWindowLongPtr(handle, GWL_STYLE), GetWindowLongPtr(handle, GWL_EXSTYLE)); } } private static void ApplyDesktopChildStyle(IntPtr handle) { var style = GetWindowLongPtr(handle, GWL_STYLE).ToInt64(); style |= WS_CHILD; style &= ~(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU); SetWindowLongPtr(handle, GWL_STYLE, new IntPtr(style)); } private static IntPtr ResolveDesktopIconHost() { var topLevelWindows = new List(); EnumWindows((handle, _) => { topLevelWindows.Add(handle); return true; }, IntPtr.Zero); foreach (var topLevelWindow in topLevelWindows) { var worker = FindWindowEx(topLevelWindow, IntPtr.Zero, "WorkerW", null); if (worker == IntPtr.Zero) { continue; } var defView = FindWindowEx(worker, IntPtr.Zero, "SHELLDLL_DefView", null); if (defView != IntPtr.Zero) { return defView; } } foreach (var topLevelWindow in topLevelWindows) { var defView = FindWindowEx(topLevelWindow, IntPtr.Zero, "SHELLDLL_DefView", null); if (defView != IntPtr.Zero) { return defView; } } return IntPtr.Zero; } private static IntPtr GetWindowHandle(Window window) { try { return window.TryGetPlatformHandle()?.Handle ?? IntPtr.Zero; } catch { return IntPtr.Zero; } } private sealed record WindowRestoreState(IntPtr Parent, IntPtr Style, IntPtr ExStyle); private delegate bool EnumWindowsProc(IntPtr handle, IntPtr lParam); [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")] private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); [DllImport("user32.dll")] private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint flags); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll")] private static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool IsWindow(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr FindWindowEx(IntPtr hParent, IntPtr hChildAfter, string? lpszClass, string? lpszWindow); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); }