我试图在我的进程中托管另一个进程的窗口。
为此,我使用HwndHost
这样:
public class MyHandle : HwndHost
{
#region User32.dll
private static Int32 WS_VISIBLE = 0x10000000;
private static Int32 WS_CHILD = 0x40000000;
private static Int32 WS_BORDER = 0x00800000;
private static Int32 GWL_STYLE = -16;
[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr procid);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);
#endregion
private Action WindowCoreBuilt = null;
private IntPtr m_window = IntPtr.Zero;
public MyHandle(IntPtr window, Action windowCoreBuiltDelegate)
{
m_window = window;
WindowCoreBuilt = windowCoreBuiltDelegate;
}
protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent)
{
int guestStyle = SetWindowLong(m_window, GWL_STYLE, WS_CHILD | WS_BORDER | WS_VISIBLE);
SetParent(m_window, hwndParent.Handle);
HandleRef hwnd = new HandleRef(this, m_window);
InvokeHelper.InvokeDelegate(this.Dispatcher, () => WindowCoreBuilt());
return hwnd;
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
}
}
它通常有效,但有时我得到这样的例外:
System.InvalidOperationException: BuildWindowCore failed to return the hosted child window handle.
at System.Windows.Interop.HwndHost.BuildWindow(HandleRef hwndParent)
at System.Windows.Interop.HwndHost.BuildOrReparentWindow()
at System.Windows.Interop.HwndHost.OnSourceChanged(Object sender, SourceChangedEventArgs e)
at System.Windows.SourceChangedEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
at System.Windows.PresentationSource.UpdateSourceOfElement(DependencyObject doTarget, DependencyObject doAncestor, DependencyObject doOldParent)
at System.Windows.PresentationSource.OnVisualAncestorChanged(DependencyObject uie, AncestorChangedEventArgs e)
at System.Windows.UIElement.OnVisualAncestorChanged(Object sender, AncestorChangedEventArgs e)
堆栈跟踪更深入,但我认为它并不相关
我的问题是:
1.什么可能导致这种情况,我该如何解决?
2.如何捕获此异常以防止我的应用程序崩溃? (它发生在我无法访问的系统线程中......)
答案 0 :(得分:1)
_hwnd = BuildWindowCore(hwndParent);
if(_hwnd.Handle == IntPtr.Zero || !UnsafeNativeMethods.IsWindow(_hwnd))
{
throw new InvalidOperationException(SR.Get(SRID.ChildWindowNotCreated));
}
这是抛出异常的WPF source code的特定部分。 IsWindow
直接调用Win32 IsWindow函数。
我的猜测是你以某种方式从IntPtr.Zero
返回BuildWindowCore
句柄。
答案 1 :(得分:0)
一旦子控件进程崩溃,您需要将主机控件内容清除为null。如果您没有,并且导航离开主机窗口,然后返回主机窗口,或导致应用程序以任何方式重新绘制,则此BuildWindowCore()方法将触发并失败。
您可以尝试以下技巧,但您需要确定托管控件的过程。拥有Process对象时,可以执行以下操作:
/* on a seperate thread, monitor the process */
Task.Factory.StartNew(() =>
{
ServiceHostProcess.WaitForExit();
/* back to the UI thread */
Application.Current.Dispatcher.Invoke(ClearChildControl);
});
在我的情况下,ClearChildControl
函数只是将内容清除为null,因此重绘尝试甚至不会执行BuildWindowCore
函数。
private void ClearChildControl()
{
if (null == PlayerPanel)
return;
/* this border panel hosts the control of another process */
PlayerPanel.Child = null;
}
答案 2 :(得分:0)
as" ghord说,错误来自HwndHost.BuildWindow
,但是你可以通过确保你提供的HWND不是IntPtr.Zero
来避免这种情况,并且它代表了一个窗口:
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern bool IsWindow(IntPtr hWnd);
但是,如果提供HWND的进程在您对BuildWindowCore
的调用进行服务时崩溃,那么除了抛出异常或让基类执行异常之外,您无能为力您。为避免崩溃您的应用程序,请处理Application.DispatcherUnhandledException
并将Handled
设置为true
。