proper way to use BuildWindowCore params?

In the following code, I'm attempting to make my own .NET 2.0 form act as a FrameworkElement. I'm having trouble in the BuildWindowCore function. As I understand it, I'm supposed to take my existing form and make it a child of the input HWND. I don't know how to take the hwndParent.Handle and turn that into a System.Windows.Forms.Control. I've stepped through the code a number of times trying different things includeing WINAPI SetParent all with no luck. It's too bad Wrapper is null. That would at least give me an idea as to what type of object it is.

publicclassAppWindow :HwndHost

{

privateAppForm _appForm;// AppForm inherits from System.Windows.Forms.Form

public AppWindow(AppForm appForm)

{

if (appForm ==null)

thrownewArgumentNullException("appForm");

_appForm = appForm;

}

protectedoverride System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent)

{

// hwndParent.Wrapper == null but hwndParent.Handle == some number

_appForm.Parent = System.Windows.Forms.Control.FromHandle(hwndParent.Handle);

// BUG: _appForm.Parent still null

returnnew System.Runtime.InteropServices.HandleRef(_appForm, _appForm.Handle);

}

protectedoverridevoid DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd)

{

_appForm.Dispose();

}

}

[3896 byte] By [Brannon] at [2007-12-30]
# 1
The following code can do the trick here:
[System.Windows.Markup.ContentProperty("Child")]
public class FormHost : HwndHost
{
 private System.Windows.Forms.Form child;
 public System.Windows.Forms.Form Child
 {
 get { return child; }
 set { child = value; }
 }
 
 public FormHost(System.Windows.Forms.Form child)
 {
 this.child = child;
 }
 
 public FormHost() : this(null) { }
 
 protected override HandleRef BuildWindowCore(HandleRef hwndParent)
 {
 HandleRef childHwnd = new HandleRef(this, child.Handle);
 System.Windows.Forms.Integration.WindowsFormsHost.EnableWindowsFormsInterop();
 if (child != null)
 {
 SetWindowLong(Child.Handle, GWL_STYLE, WS_CHILD);
 SetParent(childHwnd.Handle, hwndParent.Handle);
 }
 return childHwnd;
 }
 
 protected override void DestroyWindowCore(HandleRef hwnd)
 {
 child.Dispose();
 }
 
 public static readonly Int32 GWL_STYLE = -16;
 public static readonly Int32 WS_CHILD = 0x40000000;
 
 [DllImport("User32", CharSet = CharSet.Auto, ExactSpelling = true)]
 internal static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);
 [DllImport("user32.dll")]
 static extern Int32 SetWindowLong(IntPtr hWnd, Int32 nIndex, Int32 dwNewLong);
 
}

Sheva

ZhouYong at 2007-10-9 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 2

Thank you for the reply. I have several questions on it.

1. Would this code work on Vista? I get nervous when I see user32.dll calls.

2. Can we get these two calls into the .NET framework or the Interop in an upcoming version? They seem quite useful. Either that or add a FromHandle function to the Interop.

3. The sample code creates childHwnd without checking the child == null. That seems bad to me.

4. The childHwnd is created with a wrapper of FormHost rather than the owner of the handle. This seems to contradict the help on HandleRef to me.

Brannon at 2007-10-9 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 3

The code below works on WinXP. I set this to a Window.Content. It displays, but what I want is for this to be the top level window. (Or hide the top level window and make this look like it is the top-level window.) To move a window I want to grab the title bar in this AppWindow.Child, not the title bar in the Parent of this.

[System.Windows.Markup.ContentProperty("Child")]

public class AppWindow : HwndHost

{

private System.Windows.Forms.Form _child; // AppForm inherits from System.Windows.Forms.Form

public AppWindow(System.Windows.Forms.Form child) : base()

{

if (child == null)

throw new ArgumentNullException("child");

_child = child;

}

public System.Windows.Forms.Form Child

{

get { return _child; }

set { _child = value; }

}

public AppWindow() : this(null) { }

protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent)

{

// hwndParent.Wrapper == null but hwndParent.Handle == some number

System.Windows.Forms.Integration.WindowsFormsHost.EnableWindowsFormsInterop();

SetWindowLong(_child.Handle, GWL_STYLE, WS_CHILD);

SetParent(_child.Handle, hwndParent.Handle);

// BUG: _appForm.Parent still null

return new System.Runtime.InteropServices.HandleRef(_child, _child.Handle);

}

protected override void DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd)

{

_child.Dispose();

}

public static readonly Int32 GWL_STYLE = -16;

public static readonly Int32 WS_CHILD = 0x40000000;

[DllImport("User32", CharSet = CharSet.Auto)]

internal static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);

[DllImport("User32", CharSet = CharSet.Auto)]

static extern Int32 SetWindowLong(IntPtr hWnd, Int32 nIndex, Int32 dwNewLong);

}

Brannon at 2007-10-9 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 4
I've posted an article on how to host top-level forms in WPF, and I've taken some of the advice from Brannon.

Sheva

ZhouYong at 2007-10-9 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 5
Thanks for the article on the topic, but apparently I'm still missing something on the usage. Putting an instance your FormHost class into the Content member of a Window object does some interesting things. Straight out I see two title bars: one from my existing form and one from the new Window instance. I can set WindowStyle to None, but that still does not allow me to click on the hosted title bar and drag the window around, etc. Also, I couldn't see a way to remove the border from the Window object.
Brannon at 2007-10-9 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...

Visual Studio Orcas

Site Classified