跨进程设置父子窗口除了owner方案 C# 跨进程 设置窗口owner – 唐宋元明清2188 – 博客园,还有Win32-SetParent SetParent 函数 (winuser.h) – Win32 apps | Microsoft Learn
SetParent可以实现将子窗口嵌入另一个窗口中
1 [DllImport("user32.dll", SetLastError = true)] 2 static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
hWndChild是子窗口,hWndNewParent是新父窗口句柄,返回参数为子窗口的上一次父窗口句柄
我们建个demo试试,
可以使用syp++-查找窗口句柄。这里为了效率高,直接显示窗口句柄方便获取:
1 CurrentHandleTextBox.Text = new WindowInteropHelper(this).Handle.ToString("X");
启动2个demo窗口,根据另一个窗口句柄和当前窗口句柄,设置SetParent
1 private void AddChildWindow_OnClick(object sender, RoutedEventArgs e) 2 { 3 var inputInt32 = Convert.ToInt32(InputTextBox.Text, 16); 4 IntPtr inputPtr = (IntPtr)inputInt32; 5 var currentInPtr = new WindowInteropHelper(this).Handle; 6 7 var result = SetParent(inputPtr, currentInPtr); 8 MessageBox.Show($"SetParent Result:{result}"); 9 }
显示效果如下:
设置成功时,结果:
65552是上一个父窗口句柄,这是哪个窗口呢?
我们把65552换成16进制,通过syp++,能看到是这是桌面窗口,即默认父窗口句柄是桌面的
上面Demo详见 kybs00/SetParentDemo
SetParent函数非常强大,适合那些需要设置子窗口只在父窗口区域内显示,比如分屏软件,可以把父窗口完全当作一个显示器来使用。
根据小伙伴反馈,应用设置了uiAccess后,在此进程打开其它软件,其它软件内部调用SetParent实现相关功能时会失败。
时间: 2025-01-08 18:03:44,034 线程ID: [1] 错误描述: 寄宿的 HWND 必须是指定父级的子窗口。 异常: System.InvalidOperationException: 寄宿的 HWND 必须是指定父级的子窗口。 在 System.Windows.Interop.HwndHost.BuildWindow(HandleRef hwndParent) 在 System.Windows.Interop.HwndHost.BuildOrReparentWindow() 在 System.Windows.Interop.HwndHost.OnSourceChanged(Object sender, SourceChangedEventArgs e) 在 System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) 在 System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) 在 System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) 在 System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) 在 System.Windows.PresentationSource.UpdateSourceOfElement(DependencyObject doTarget, DependencyObject doAncestor, DependencyObject doOldParent) 在 System.Windows.PresentationSource.OnVisualAncestorChanged(DependencyObject uie, AncestorChangedEventArgs e) 在 System.Windows.UIElement.OnVisualAncestorChanged(Object sender, AncestorChangedEventArgs e) 在 System.Windows.Media.Visual.ProcessAncestorChangedNotificationRecursive(DependencyObject e, AncestorChangedEventArgs args) 在 System.Windows.Media.Visual.ProcessAncestorChangedNotificationRecursive(DependencyObject e, AncestorChangedEventArgs args) 在 System.Windows.Media.Visual.ProcessAncestorChangedNotificationRecursive(DependencyObject e, AncestorChangedEventArgs args) 在 System.Windows.Media.Visual.AddVisualChild(Visual child) 在 System.Windows.FrameworkElement.set_TemplateChild(UIElement value) 在 System.Windows.Controls.ContentPresenter.UseContentTemplate.BuildVisualTree(FrameworkElement container) 在 System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate) 在 System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container) 在 System.Windows.FrameworkElement.ApplyTemplate() 在 System.Windows.FrameworkElement.MeasureCore(Size availableSize) 在 System.Windows.UIElement.Measure(Size availableSize) 在 System.Windows.Controls.Border.MeasureOverride(Size constraint) 在 System.Windows.FrameworkElement.MeasureCore(Size availableSize) 在 System.Windows.UIElement.Measure(Size availableSize) 在 System.Windows.Controls.Control.MeasureOverride(Size constraint) 在 System.Windows.FrameworkElement.MeasureCore(Size availableSize) 在 System.Windows.UIElement.Measure(Size availableSize) 在 System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV) 在 System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged) 在 System.Windows.Controls.Grid.MeasureOverride(Size constraint) 在 System.Windows.FrameworkElement.MeasureCore(Size availableSize) 在 System.Windows.UIElement.Measure(Size availableSize) 在 System.Windows.ContextLayoutManager.UpdateLayout() 在 MagicWindowSplit.SplitService.<SplitWindow>d__25.MoveNext() --- 引发异常的上一位置中堆栈跟踪的末尾 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 MagicWindowSplit.SplitService.<SelectControlSplit>d__16.MoveNext() --- 引发异常的上一位置中堆栈跟踪的末尾 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) 在 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
uiAccess进程启动软件,会默认添加管理员权限。为了简化后续描述,我们称“uiAccess权限进程启动其它软件”,有uiAccess影响。
下面我们启动俩个相同demo.exe,使用俩个不同进程的窗口,来验证SetParent情况
1.俩个均有uiAccess影响的窗口 – 正常
2.有uiAccess影响的窗口A、非uiAccess影响窗口B,在A内设置A为B的子窗口 – 正常
3.有uiAccess影响的窗口A、非uiAccess影响窗口B,在B内设置A为B的子窗口 – 错误,返回值0
原因是管理员权限问题,非管理员权限无法设置管理员权限窗口为其子窗口,仅用管理员权限验证也是一样的结果。
4. 有uiAccess影响的窗口A、非uiAccess影响窗口B,在A内设置B为A的子窗口 – 正常
5. 有uiAccess影响的窗口A、非uiAccess影响窗口B,在B内设置B为A的子窗口 – 错误
原因是管理员权限问题,非管理员权限无法设置管理员权限窗口为其父窗口,仅用管理员权限验证也是一样的结果。
所以设置SetParent失败与uiAccess影响无关,仅仅是管理员权限不足。 而上面小伙伴反馈的分屏软件调用SetParent异常是业务逻辑问题,毅仔有相关介绍 System.InvalidOperationException:“寄宿的 HWND 必须是指定父级的子窗口。” – walterlv 可以参照解决 SetParent其它问题可以参考: SetParent 函数修改父窗口的误区-CSDN博客 使用 SetParent 制作父子窗口的时候,如何设置子窗口的窗口样式以避免抢走父窗口的焦点 – walterlv 使用 SetParent 跨进程设置父子窗口时的一些问题(小心卡死) – walterlv
来源链接:https://www.cnblogs.com/kybs0/p/18664127
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
暂无评论内容