使用SetWindowLong无法移除外部RDP进程的滚动条
问题描述
我正在尝试通过C#代码移除启动的RDP窗口的滚动条。我的代码通过启动mstsc.exe并传入rdp文件路径打开RDP窗口,但打开后需要移除其水平和垂直滚动条。目前的样式设置可成功移除厚边框、最小化和最大化按钮,但WS_HSCROLL和WS_VSCROLL的设置似乎被忽略。
现有代码示例
Process m_proc = new Process { StartInfo = { FileName = "mstsc.exe", Arguments = rdpFullPath } }; m_proc.Start(); // 等待进程启动并创建RDP主窗口 while (m_proc.MainWindowHandle == IntPtr.Zero) { Thread.Sleep(2000); } // 移除厚边框以禁止调整窗口大小,并移除最小化和最大化按钮 var currentStyle = UnsafeNativeMethods.GetWindowLong(m_proc.MainWindowHandle, UnsafeNativeMethods.GWL_STYLE); currentStyle &= ~UnsafeNativeMethods.WS_THICKFRAME; currentStyle &= ~UnsafeNativeMethods.WS_MINIMIZEBOX; currentStyle &= ~UnsafeNativeMethods.WS_MAXIMIZEBOX; currentStyle &= ~UnsafeNativeMethods.WS_HSCROLL; currentStyle &= ~UnsafeNativeMethods.WS_VSCROLL; UnsafeNativeMethods.SetWindowLong(m_proc.MainWindowHandle, UnsafeNativeMethods.GWL_STYLE, currentStyle); UnsafeNativeMethods.SetWindowPos(m_proc.MainWindowHandle, UnsafeNativeMethods.HWND_TOPMOST, 0, 0, 0, 0, UnsafeNativeMethods.SWP_NOMOVE | UnsafeNativeMethods.SWP_NOSIZE | UnsafeNativeMethods.SWP_NOZORDER | UnsafeNativeMethods.SWP_NOOWNERZORDER | UnsafeNativeMethods.SWP_FRAMECHANGED);
相关定义
public const int WS_HSCROLL = 0x00100000; public const int WS_VSCROLL = 0x00200000; [DllImport("user32.dll")] public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll")] 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 bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
解决方法
你修改的是RDP主窗口的样式,但滚动条属于RDP窗口内部的子控件(显示远程桌面内容的容器),而非主窗口本身。需要找到该子控件的句柄,再修改它的窗口样式。
步骤说明
- 用
FindWindowEx查找RDP主窗口下的子控件,类名通常为MsTscAxHost(不同系统版本可能有差异,可通过Spy++工具确认)。 - 对该子控件执行样式修改,移除
WS_HSCROLL和WS_VSCROLL。 - 调用
SetWindowPos刷新控件样式。
修改后的代码
Process m_proc = new Process { StartInfo = { FileName = "mstsc.exe", Arguments = rdpFullPath } }; m_proc.Start(); // 等待主窗口创建,缩短间隔避免不必要延迟 while (m_proc.MainWindowHandle == IntPtr.Zero) { Thread.Sleep(500); } // 移除主窗口的边框和最大化/最小化按钮 var mainStyle = UnsafeNativeMethods.GetWindowLong(m_proc.MainWindowHandle, UnsafeNativeMethods.GWL_STYLE); mainStyle &= ~UnsafeNativeMethods.WS_THICKFRAME; mainStyle &= ~UnsafeNativeMethods.WS_MINIMIZEBOX; mainStyle &= ~UnsafeNativeMethods.WS_MAXIMIZEBOX; UnsafeNativeMethods.SetWindowLong(m_proc.MainWindowHandle, UnsafeNativeMethods.GWL_STYLE, mainStyle); // 循环查找RDP子控件,确保控件已加载 IntPtr rdpChildHandle = IntPtr.Zero; for (int i = 0; i < 10; i++) { rdpChildHandle = UnsafeNativeMethods.FindWindowEx(m_proc.MainWindowHandle, IntPtr.Zero, "MsTscAxHost", null); if (rdpChildHandle != IntPtr.Zero) break; Thread.Sleep(500); } if (rdpChildHandle != IntPtr.Zero) { // 移除子控件的滚动条样式 var childStyle = UnsafeNativeMethods.GetWindowLong(rdpChildHandle, UnsafeNativeMethods.GWL_STYLE); childStyle &= ~UnsafeNativeMethods.WS_HSCROLL; childStyle &= ~UnsafeNativeMethods.WS_VSCROLL; UnsafeNativeMethods.SetWindowLong(rdpChildHandle, UnsafeNativeMethods.GWL_STYLE, childStyle); // 刷新子控件样式 UnsafeNativeMethods.SetWindowPos(rdpChildHandle, IntPtr.Zero, 0, 0, 0, 0, UnsafeNativeMethods.SWP_NOMOVE | UnsafeNativeMethods.SWP_NOSIZE | UnsafeNativeMethods.SWP_FRAMECHANGED); } // 刷新主窗口样式 UnsafeNativeMethods.SetWindowPos(m_proc.MainWindowHandle, UnsafeNativeMethods.HWND_TOPMOST, 0, 0, 0, 0, UnsafeNativeMethods.SWP_NOMOVE | UnsafeNativeMethods.SWP_NOSIZE | UnsafeNativeMethods.SWP_NOZORDER | UnsafeNativeMethods.SWP_NOOWNERZORDER | UnsafeNativeMethods.SWP_FRAMECHANGED);
补充定义
需要在UnsafeNativeMethods中添加FindWindowEx的定义:
[DllImport("user32.dll", SetLastError = true)] public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

