Force HwndHost Initialization

In my WPF application, I host Win32 content using HwndHost. However, creating HwndHost does not create its own window. Rather, this is done in an overridden method BuildWindowCore(), which is later called WPF.

My hosted content needs a window handle to its own window for its own initialization. Unfortunately, I cannot force a window to be created (i.e. WPF calls BuildWindowCore), so I have a second thread that checks HwndHost until it is initialized.

In .NET 4.0 / WPF 4.0 a new method has been added WindowInteropHelper.EnsureHandle(). I was hoping this would solve the situation, but it only works for Window, not HwndHost (which is not obtained from Window). Do you have a suggestion, what could I do instead?

EDIT:

I forgot to add a few more restrictions for a possible solution:

  • HwndHost is placed in a control, which, depending on user settings, can be a child of the main application window or can be placed in a new window (via a third-party docking manager). This means that at the time of creating the window, I don’t know exactly what the parent window will be (and therefore its hWnd).
  • While the native code needs hWnd during its initialization, the window is displayed only when the user asks for it to be shown (i.e., it is invisible at the beginning). It is necessary to show the window, only to hide it immediately, should be avoided if possible.
+5
source share
4 answers

, . :

HwndHost () hWnd . , CreateWindow(), hWnd. hWnd , HwndHost Handle. , ( № 2).

BuildWindowCore() hWnd , . , SetParent() ( №1). , , hWnd!

( ):

public class Win32Window : HwndHost
{
    public Win32Window(IntPtr parentHwnd)
    {
        this.ParentHwnd = parentHwnd;
        this.Win32Handle = NativeMethods.CreateWindowEx( /* parameters omitted*/ );
    }

    public IntPtr Win32Handle { get; private set; }
    private IntPtr ParentHwnd { get; set; }

    protected override HandleRef BuildWindowCore(HandleRef hwndParent)
    {
        if (hwndParent.Handle != this.ParentHwnd)
        {
            NativeMethods.SetParent(this.Win32Handle, hwndParent.Handle);
        }

        return new HandleRef(this, this.Win32Handle);
    }
}
+3

, , :

1) HwndHost, Rect ( BuildWindowCore):

public class MyHwndHost : HwndHost
{
    public MyHwndHost(Rect boundingBox)
    {
        BoundingBox = boundingBox;
    } 
}

2) WPF Border:

<Window Loaded="Window_Loaded">
    <Border Name="HostElement" />
</Window>

3) HwndHost Window_Loaded:

void Window_Loaded(object sender, RoutedEventArgs e)
{
    MyHwndHost host = new MyHwndHost(LayoutInformation.GetLayoutSlot(HostElement));
    HostElement.Child = host;
}

4) Window_Loaded HWND P/Invoke, ++/CLI. , HWND , HWND .

+1

A bit late, but did you try calling UpdateLayout()in the hosting control? It worked for me

0
source

I added an event OnHandleCreatedto my HwndHost-inherited class , which contains an IntPtr handle. This event is fired internally BuildWindowCore().

So it comes down to:

public class Win32WindowHost : HwndHost { ... }

var host = new Win32WindowHost();
host.OnHandleCreated += ( sender, e ) =>
{
    var handle = e.Handle;
    // Do stuff.
};

It works with pleasure.

0
source

All Articles