托管窗口时出现BuildWindowCore错误

时间:2015-12-09 12:44:34

标签: c# wpf

我试图在我的进程中托管另一个进程的窗口。 为此,我使用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.如何捕获此异常以防止我的应用程序崩溃? (它发生在我无法访问的系统线程中......)

3 个答案:

答案 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