2015-12-09 3 views
2

Я пытаюсь разместить окно другого процесса в моем процессе. Для этого я использую HwndHost так:Ошибка BuildWindowCore при размещении окна

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) 

StackTrace идет гораздо глубже, но я не думаю, что это актуально.
Мои вопросы:
1. Что может быть причиной этого и как его исправить?
2. Как я могу поймать это исключение, чтобы предотвратить сбой приложения? (Это происходит в системе потоков, что у меня нет доступа к ...)

ответ

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.

0

Необходимо удалить содержимое элемента управления хостом, как только завершится процесс управления дочерним элементом. Если вы этого не сделаете, и вы переходите от окна хоста, а затем обратно в окно хоста или заставляете приложение перерисовывать каким-либо образом, этот метод BuildWindowCore() будет срабатывать и сбой.

Вы можете попробовать следующий трюк, НО вам нужно будет выяснить процесс, в котором находится элемент управления. Если у вас есть объект процесса, вы можете сделать это:

/* on a seperate thread, monitor the process */ 
Task.Factory.StartNew(() => 
{ 
    ServiceHostProcess.WaitForExit(); 
    /* back to the UI thread */ 
    Application.Current.Dispatcher.Invoke(ClearChildControl); 
}); 

ClearChildControl функция в моем случае, просто очищает содержимое в нуль, поэтому попытка Repaint обыкновение даже выполнять функцию BuildWindowCore.

private void ClearChildControl() 
{ 
    if (null == PlayerPanel) 
     return; 

    /* this border panel hosts the control of another process */ 
    PlayerPanel.Child = null; 
} 
0

Как «говорит 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

Смежные вопросы