using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows; namespace Win32Natives { /// /// user32.dll 包装类 /// public static class User32 { public const int GWL_STYLE = -16; public const int WS_OVERLAPPED = 0x00000000; public const int WS_POPUP = unchecked((int)0x80000000); public const int WS_CHILD = 0x40000000; public const int WS_MINIMIZE = 0x20000000; public const int WS_VISIBLE = 0x10000000; public const int WS_DISABLED = 0x08000000; public const int WS_CLIPSIBLINGS = 0x04000000; public const int WS_CLIPCHILDREN = 0x02000000; public const int WS_MAXIMIZE = 0x01000000; public const int WS_BORDER = 0x00800000; public const int WS_DLGFRAME = 0x00400000; public const int WS_VSCROLL = 0x00200000; public const int WS_HSCROLL = 0x00100000; public const int WS_SYSMENU = 0x00080000; public const int WS_THICKFRAME = 0x00040000; public const int WS_GROUP = 0x00020000; public const int WS_TABSTOP = 0x00010000; public const int WS_MINIMIZEBOX = 0x00020000; public const int WS_MAXIMIZEBOX = 0x00010000; public const int WS_CHILDWINDOW = WS_CHILD; public const int WS_CAPTION = WS_BORDER | WS_DLGFRAME; public const int WS_TILED = WS_OVERLAPPED; public const int WS_ICONIC = WS_MINIMIZE; public const int WS_SIZEBOX = WS_THICKFRAME; public const int WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW; public const int WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; public const int WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU; public const int GWL_EXSTYLE = -20; public const int WS_EX_DLGMODALFRAME = 0x00000001; public const int WS_EX_NOPARENTNOTIFY = 0x00000004; public const int WS_EX_TOPMOST = 0x00000008; public const int WS_EX_ACCEPTFILES = 0x00000010; public const int WS_EX_TRANSPARENT = 0x00000020; public const int WS_EX_MDICHILD = 0x00000040; public const int WS_EX_TOOLWINDOW = 0x00000080; public const int WS_EX_WINDOWEDGE = 0x00000100; public const int WS_EX_CLIENTEDGE = 0x00000200; public const int WS_EX_CONTEXTHELP = 0x00000400; public const int WS_EX_RIGHT = 0x00001000; public const int WS_EX_LEFT = 0x00000000; public const int WS_EX_RTLREADING = 0x00002000; public const int WS_EX_LTRREADING = 0x00000000; public const int WS_EX_LEFTSCROLLBAR = 0x00004000; public const int WS_EX_RIGHTSCROLLBAR = 0x00000000; public const int WS_EX_CONTROLPARENT = 0x00010000; public const int WS_EX_STATICEDGE = 0x00020000; public const int WS_EX_APPWINDOW = 0x00040000; public const int WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE; public const int WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST; public const int WS_EX_LAYERED = 0x00080000; public const int WS_EX_NOINHERITLAYOUT = 0x00100000; public const int WS_EX_LAYOUTRTL = 0x00400000; public const int WS_EX_COMPOSITED = 0x02000000; public const int WS_EX_NOACTIVATE = 0x08000000; public const uint LWA_COLORKEY = 0x1; public const uint LWA_ALPHA = 0x2; public const byte AC_SRC_OVER = 0x00; public const byte AC_SRC_ALPHA = 0x01; public const int ULW_COLORKEY = 0x00000001; public const int ULW_ALPHA = 0x00000002; public const int ULW_OPAQUE = 0x00000004; public const IntPtr HWND_TOPMOST = -1; public const uint SWP_ASYNCWINDOWPOS = 0x4000; public const uint SWP_DEFERERASE = 0x2000; public const uint SWP_NOSENDCHANGING = 0x0400; public const uint SWP_NOOWNERZORDER = 0x0200; public const uint SWP_NOREPOSITION = 0x0200; public const uint SWP_NOCOPYBITS = 0x0100; public const uint SWP_HIDEWINDOW = 0x0080; public const uint SWP_SHOWWINDOW = 0x0040; public const uint SWP_DRAWFRAME = 0x0020; public const uint SWP_FRAMECHANGED = 0x0020; public const uint SWP_NOACTIVATE = 0x0010; public const uint SWP_NOREDRAW = 0x0008; public const uint SWP_NOZORDER = 0x0004; public const uint SWP_NOMOVE = 0x0002; public const uint SWP_NOSIZE = 0x0001; public const int WM_SPAWN_WORKER = 0x052C; // 一个未公开的神秘消息 public const uint SMTO_NORMAL = 0x0000; public const uint SMTO_BLOCK = 0x0001; public const uint SMTO_ABORTIFHUNG = 0x0002; public const uint SMTO_NOTIMEOUTIFNOTHUNG = 0x0008; public const uint GA_PARENT = 1; public const uint GW_OWNER = 4; public const int SW_HIDE = 0; public const int SW_SHOWNORMAL = 1; public const int SW_SHOWMINIMIZED = 2; public const int SW_SHOWMAXIMIZED = 3; public const int SW_SHOWNOACTIVATE = 4; public const int SW_SHOW = 5; public const int SW_MINIMIZE = 6; public const int SW_SHOWMINNOACTIVE = 7; public const int SW_SHOWNA = 8; public const int SW_RESTORE = 9; public const int SW_SHOWDEFAULT = 10; public const uint MONITOR_DEFAULTTONULL = 0; public const uint MONITOR_DEFAULTTOPRIMARY = 1; public const uint MONITOR_DEFAULTTONEAREST = 2; [StructLayout(LayoutKind.Sequential)] public struct POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] public struct SIZE { public int cx; public int cy; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BLENDFUNCTION { public byte BlendOp; public byte BlendFlags; public byte SourceConstantAlpha; public byte AlphaFormat; } [StructLayout(LayoutKind.Sequential)] private struct LASTINPUTINFO { public uint cbSize; public uint dwTime; } [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } [StructLayout(LayoutKind.Sequential)] private struct MONITORINFOEX { public uint cbSize; public RECT rcMonitor; public RECT rcWork; public uint dwFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szDevice; } public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetDC(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); [DllImport("user32.dll", SetLastError = true)] public static extern bool GetLayeredWindowAttributes(IntPtr hWnd, ref uint crKey, ref byte bAlpha, ref uint dwFlags); [DllImport("user32.dll", SetLastError = true)] public static extern bool SetLayeredWindowAttributes(IntPtr hWnd, uint pcrKey, byte pbAlpha, uint pdwFlags); [DllImport("user32.dll", SetLastError = true)] public static extern bool UpdateLayeredWindow(IntPtr hWnd, IntPtr hdcDst, IntPtr pptDst, ref SIZE psize, IntPtr hdcSrc, ref POINT pptSrc, int crKey, ref BLENDFUNCTION pblend, int dwFlags); [DllImport("user32.dll", SetLastError = true)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); [DllImport("user32.dll", SetLastError = true)] public static extern uint GetDoubleClickTime(); [DllImport("user32.dll", SetLastError = true)] private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam, uint fuFlags, uint uTimeout, out IntPtr lpdwResult); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetAncestor(IntPtr hWnd, uint gaFlags); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); [DllImport("user32.dll", SetLastError = true)] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] public static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam); [DllImport("User32.dll")] public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] private static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); [DllImport("user32.dll")] private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi); [DllImport("user32.dll")] public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll")] public static extern int GetWindowLong(IntPtr hWnd, int nIndex); public static TimeSpan GetLastInputElapsedTime() { LASTINPUTINFO lastInputInfo = new(); lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo); uint idleTimeMillis = 1000; if (GetLastInputInfo(ref lastInputInfo)) { uint tickCount = (uint)Environment.TickCount; uint lastInputTick = lastInputInfo.dwTime; idleTimeMillis = tickCount - lastInputTick; } return TimeSpan.FromMilliseconds(idleTimeMillis); } public static IntPtr GetWorkerW() { // NOTE: Codes borrowed from @rocksdanister/lively var progman = FindWindow("Progman", null); if (progman == IntPtr.Zero) return IntPtr.Zero; // Send 0x052C to Progman. This message directs Progman to spawn a // WorkerW behind the desktop icons. If it is already there, nothing // happens. SendMessageTimeout(progman, WM_SPAWN_WORKER, 0, 0, SMTO_NORMAL, 1000, out _); // Spy++ output // ..... // 0x00010190 "" WorkerW // ... // 0x000100EE "" SHELLDLL_DefView // 0x000100F0 "FolderView" SysListView32 // 0x00100B8A "" WorkerW <-- This is the WorkerW instance we are after! // 0x000100EC "Program Manager" Progman var workerw = IntPtr.Zero; // We enumerate all Windows, until we find one, that has the SHELLDLL_DefView // as a child. // If we found that window, we take its next sibling and assign it to workerw. EnumWindows(new EnumWindowsProc((tophandle, topparamhandle) => { IntPtr p = FindWindowEx(tophandle, IntPtr.Zero, "SHELLDLL_DefView", null); if (p != IntPtr.Zero) { // Gets the WorkerW Window after the current one. workerw = FindWindowEx(IntPtr.Zero, tophandle, "WorkerW", null); } return true; }), IntPtr.Zero); // Some Windows 11 builds have a different Progman window layout. // If the above code failed to find WorkerW, we should try this. // Spy++ output // 0x000100EC "Program Manager" Progman // 0x000100EE "" SHELLDLL_DefView // 0x000100F0 "FolderView" SysListView32 // 0x00100B8A "" WorkerW <-- This is the WorkerW instance we are after! if (workerw == IntPtr.Zero) { workerw = FindWindowEx(progman, IntPtr.Zero, "WorkerW", null); } Debug.WriteLine($"HWND(WorkerW): {workerw:x8}"); return workerw; } public static bool GetScreenResolution(IntPtr hwnd, out uint width, out uint height) { IntPtr hMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); var mi = new MONITORINFOEX { cbSize = (uint)Marshal.SizeOf() }; if (GetMonitorInfo(hMon, ref mi)) { int widthPx = mi.rcMonitor.Right - mi.rcMonitor.Left; int heightPx = mi.rcMonitor.Bottom - mi.rcMonitor.Top; width = (uint)widthPx; height = (uint)heightPx; return true; } width = height = 0; return false; } public static bool GetPrimaryScreenResolution(out uint width, out uint height) { IntPtr hMon = MonitorFromWindow(IntPtr.Zero, MONITOR_DEFAULTTOPRIMARY); var mi = new MONITORINFOEX { cbSize = (uint)Marshal.SizeOf() }; if (GetMonitorInfo(hMon, ref mi)) { int widthPx = mi.rcMonitor.Right - mi.rcMonitor.Left; int heightPx = mi.rcMonitor.Bottom - mi.rcMonitor.Top; width = (uint)widthPx; height = (uint)heightPx; return true; } width = height = 0; return false; } } }