如何隐藏其他应用窗口的关闭、最大化、最小化按钮?SetWindowLongPtr失效
如何让移除Windows应用标题栏的代码对所有应用生效?
我有一段C#代码可以移除Windows应用中包含关闭、最小化、最大化按钮的整个标题栏区域,代码如下:
private const int SWP_NOMOVE = 0x0002; private const int SWP_NOSIZE = 0x0001; private const int SWP_FRAMECHANGED = 0x0020; private const int GWL_STYLE = -16; private const int WS_SYSMENU = 0x80000; private const int WS_CAPTION = 0xC00000; [DllImport("user32.dll", SetLastError = true)] private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); [DllImport("user32.dll", SetLastError = true)] private static extern int SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); public void RemoveMenuAndTitle(IntPtr hwnd) { if (hwnd != IntPtr.Zero) { IntPtr stylePtr; if (IntPtr.Size == 4) // 32-bit system { stylePtr = new IntPtr(GetWindowLongPtr(hwnd, GWL_STYLE).ToInt32()); } else // 64-bit system { stylePtr = GetWindowLongPtr(hwnd, GWL_STYLE); } long style = stylePtr.ToInt64(); style &= ~(WS_SYSMENU | WS_CAPTION); // Set the modified style back to the window IntPtr result = (IntPtr)SetWindowLongPtr(hwnd, GWL_STYLE, new IntPtr(style)); if (result == IntPtr.Zero) { int error = Marshal.GetLastWin32Error(); Console.WriteLine("SetWindowLongPtr failed with error code: {0}", error); } else { // Force a redraw of the window SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); } } }
这段代码在记事本、VLC等应用上可正常工作,但在Windows计算器、Chrome等应用上无响应且未抛出异常。我期望这段代码能对所有应用生效,请问该如何解决?
问题原因分析
- UWP应用(如Windows计算器):这类应用依赖Desktop Window Manager(DWM)提供的自定义框架,传统的
WS_CAPTION等窗口样式不直接控制标题栏外观,应用会自行维护界面框架,修改系统样式后会被重置或忽略。 - 自定义窗口框架的应用(如Chrome):Chrome等应用不依赖系统默认标题栏,而是自行绘制标题栏区域。修改系统窗口样式后,应用的内部逻辑会重新检测并绘制自定义标题栏,覆盖你的修改。
- 权限限制:如果目标应用以管理员权限运行,你的程序若没有同等权限,将无法修改其窗口属性。
- 样式重置时机:部分应用在启动、窗口状态变化(如最大化/还原)时会重新设置窗口样式,你的修改会被覆盖。
解决方案
1. 针对UWP应用的处理
UWP应用依赖DWM框架,需通过DwmSetWindowAttribute修改DWM属性来隐藏标题栏:
private const int DWMWA_NO_NONCLIENT_PIXELATION = 22; private const int DWMWA_NCAPTION_BUTTON_BOUNDS = 3; [StructLayout(LayoutKind.Sequential)] private struct RECT { public int Left; public int Top; public int Right; public int Bottom; } [DllImport("dwmapi.dll", SetLastError = true)] private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, ref int pvAttribute, int cbAttribute); [DllImport("dwmapi.dll", SetLastError = true)] private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, ref RECT pvAttribute, int cbAttribute); // 在RemoveMenuAndTitle方法中添加以下逻辑 int disableNonClient = 1; DwmSetWindowAttribute(hwnd, DWMWA_NO_NONCLIENT_PIXELATION, ref disableNonClient, sizeof(int)); // 设置空的标题栏按钮区域以隐藏按钮 RECT emptyRect = new RECT(); DwmSetWindowAttribute(hwnd, DWMWA_NCAPTION_BUTTON_BOUNDS, ref emptyRect, Marshal.SizeOf(typeof(RECT)));
2. 针对自定义框架应用的处理
对于Chrome这类自行绘制标题栏的应用,可通过查找并隐藏其自定义标题栏控件:
[DllImport("user32.dll", SetLastError = true)] private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); private const int SW_HIDE = 0; // 在RemoveMenuAndTitle中添加 IntPtr chromeTitleBar = FindWindowEx(hwnd, IntPtr.Zero, "Chrome_WidgetWin_1", null); if (chromeTitleBar != IntPtr.Zero) { ShowWindow(chromeTitleBar, SW_HIDE); }
注:Chrome的控件类名可能随版本更新变化,需自行验证最新类名。
3. 提升程序权限
在程序的app.manifest中添加管理员权限要求,确保能修改高权限进程的窗口:
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <security> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo> </assembly>
4. 防止样式被重置
设置定时器定期检查窗口样式,若发现标题栏样式被恢复则重新应用修改:
private Timer _styleCheckTimer; public void StartStyleMonitoring(IntPtr hwnd) { _styleCheckTimer = new Timer(CheckAndApplyStyle, hwnd, 0, 1000); } private void CheckAndApplyStyle(object state) { IntPtr hwnd = (IntPtr)state; IntPtr stylePtr = GetWindowLongPtr(hwnd, GWL_STYLE); long style = stylePtr.ToInt64(); if ((style & (WS_SYSMENU | WS_CAPTION)) != 0) { RemoveMenuAndTitle(hwnd); } }
5. 扩展窗口样式修改范围
移除更多与标题栏相关的窗口样式,确保彻底清除系统标题栏相关属性:
private const int WS_THICKFRAME = 0x00040000; private const int WS_MINIMIZEBOX = 0x00020000; private const int WS_MAXIMIZEBOX = 0x00010000; // 修改样式代码 style &= ~(WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
内容的提问来源于stack exchange,提问作者Anandu Ramachandran
相关产品推荐
相关产品推荐

