locked
Any way to get an HWND of a UserControl? RRS feed

  • Question

  • I'm trying to make a UserControl that I can use as the frame of an unmanaged window using a 3rd party unmanaged library.

     

    The libary has a call where I pass it an HWND and a RECT, and it will make a child window for displaying it's content.  Back when using windows forms, I had this working just fine.  Now I'm attempting to do the same thing in WPF.

     

    I can see how to get the window handle of the parent window... I use the WindowInteropHelper class and pass it's constructor the "this" of my window.  But I can't find anything like that for a UserControl.  I've checked to make sure that if I use the window as the target for the unmanaged content's parent, that it works, so now I've just got to find a way to get this in a control.

     

    I have one goal here:

    1. Make a UserControl that I can use as the target for my lib's functionality, so I can use it as a viewer of this special content.

     

    The motivation for this goal is that I am creating the complete functionality for my application as content creation/manipulation classes, so that a designer using expression blend will be able to completely do the UI on their own.  The only thing stopping me from finishing this right now is that I need a way for the UI designer to place and configure a specialized content window that meets the requirement of binding with the aforementioned library.

     

    Thanks,

    Jim Tomasko

     

    Friday, August 24, 2007 4:54 AM

Answers

  • I think the fundamental problem here is that in WPF controls are not windows.  Unlike the Win32 model where every control has an HWND associated with it, in WPF pretty much the only thing with an HWND is the Window which hosts everything else.  With that being the case, porting your code from WinForms to WPF, and expecting a UserControl to have an HWND, is not going to work out easily.  I think that Peter's suggestion of subclassing HwndSource is the way to go.

     

    The idea of using HwndSource to get the HWND of a UserControl is not going to work because, as stated earlier, a UserControl does not have an HWND.  In fact, if you run this (assume this.Content is a UserControl):

     

    Code Snippet

    void Window1_Loaded(object sender, RoutedEventArgs e)

    {

    HwndSource panelHwnd = HwndSource.FromVisual(this.Content as UserControl) as HwndSource;

    WindowInteropHelper windowHwnd =new WindowInteropHelper(this);

    bool same = panelHwnd.Handle == windowHwnd.Handle;

    Debug.Assert(same);

    }

     

     

    ...the assertion does not fail.  So, the call to HwndSource.FromVisual() just walks up the element tree looking for the first Win32 Window it can find.  What it finds is the main Window itself, not some special Window somehow owned by the UserControl.

     

    Regarding your trouble with subclassing UserControl, try explicitly specifying the base class in the C# code-behind to be UserControl.  In the example code you posted, the XAML explicitly declared what the base class is, but the C# code did not.  Doing so might fix the problem.  You can subclass whatever non-sealed class you need to.

     

    HTH

    Saturday, September 1, 2007 1:08 AM
  • Hi

     

    Do you look for something like:

     

    // Control element

    Button b = new Button();

     

    // Get the HWND

    HwndSource hwnd = (HwndSource)HwndSource.FromVisual(b);

     

     

    regards,

    David

     

    Wednesday, August 29, 2007 7:55 AM
  • Hello, if you just want to get the handle of your UserControl and don’t want host it in Win32 window, you can use Dave‘s answer.

     

    YourUserControl  wpfctrl = new YourUserControl();

    HwndSource source = (HwndSource)HwndSource.FromVisual(wpfctrl);

    IntPtr hWnd = source.Handle;

    Saturday, September 1, 2007 12:25 AM

All replies

  • So, you want to host an 3rd party Hwnd in your WPF app, which needs the parent Hwnd...

     

    What you want to do is derive from HwndHost. Check it out here:

    http://msdn2.microsoft.com/en-us/library/system.windows.interop.hwndhost.aspx

     

    Cheers,


    Peter

    Saturday, August 25, 2007 2:41 AM
  • UIElement myWPF = new UIElement();
    HwndSource source = new HwndSource(
                0, // class style
                WS_VISIBLE | WS_CHILD, // window style
                0, // exstyle
                x, y, width, height,
                "My WPF Control", // NAME
                IntPtr(parent)        // parent window
                );

    source.RootVisual = myWPF;
    HWND WPFHwnd = (HWND) source.Handle.ToPointer();

     

    Saturday, August 25, 2007 3:10 AM
  • Thanks Peter, I'm working hard on getting my familuraity up with WPF.  Even with all the time I'm spending, I would not have found this without help... but nothing a year or two of work will not cure.

     

    Unfortunately, I'm still stuck.  Using Yiling's and your replies, I see that there is a path to getting this to work.  Unfortunately I'm still in the "cookbook stage" of my knowledge, and am having trouble getting this to work with a UserControl.

     

    Unless I am missing something else I have not found, my control needs to be based on a UserControl so that it will be exposed by Expression Blend for use by a designer.  I currently have the following code for the shell of this control:

     

    <UserControl
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     x:Class="SvClient.SvcViewControl"
     x:Name="SvcViewControl1"
     Width="320" Height="200">

     <Grid x:Name="LayoutRoot" Background="#FFBEFBFB"/>
    </UserControl>

     

    Along with a C# partial class defined as:

     

    public partial class SvcViewControl { ... }

     

    If I attempt to inherit any other base class on the partial definition (such as HwndHost or UIElement), I get a compile error telling me that my partial class must not specify different base classes.  This all seems reasonable to me, but in the last two days I've attempted to find if there is a way to inform my WPF code that this class inherits from something else, or some other way to get around this.

     

    Any ideas?

     

    Thanks again,

    Jim Tomasko

     

    Sunday, August 26, 2007 11:37 PM
  • Thank you Yiling for that answer.  It is definatly 75% of my answer, but I'm still missing one piece of the puzzle.  Two of you replied, so I only wrote the full responce once.

     

    It's a pleasure to be in the company of people that are so helpful.

     

    Jim Tomasko

     

     

    Sunday, August 26, 2007 11:39 PM
  • Hello, I don't think you need to inherit from HwndHost, instead inherit from UserControl. And use you SvcViewControl to raplace the UIElement in my previous sample code.

    Monday, August 27, 2007 4:21 AM
  • Hi

     

    Do you look for something like:

     

    // Control element

    Button b = new Button();

     

    // Get the HWND

    HwndSource hwnd = (HwndSource)HwndSource.FromVisual(b);

     

     

    regards,

    David

     

    Wednesday, August 29, 2007 7:55 AM
  • Hi Yiling,

     

    Sorry my reply has taken so long... I was redirected from this task for a while.

     

    I'm not sure what is supposed to go into "parent" in the HwndSource function.

     

    I'm not sure if this has been clear as of yet, but I do not have a win32 window to point at during the time I need to create a handle to my usercontrol. (Maybe this doesn't matter, but I can't tell you what a hard time I'm having reading this and understanding it.  This WPF is very new to me, although I have been a windows programmer for many years.)

     

    I'm not attempting to create a window (unless I have to make a child to my userwindow just to get it's HWND).  What I'm trying to do is just get the HWND of my usercontrol.  Once I have that, I will call a libaray function that requires an HWND and a rectangle, which will build it's content as a child of the window given by the HWND.

     

    Thanks again,

    Jim Tomasko

     

     

    Friday, August 31, 2007 8:58 PM
  • Hello, if you just want to get the handle of your UserControl and don’t want host it in Win32 window, you can use Dave‘s answer.

     

    YourUserControl  wpfctrl = new YourUserControl();

    HwndSource source = (HwndSource)HwndSource.FromVisual(wpfctrl);

    IntPtr hWnd = source.Handle;

    Saturday, September 1, 2007 12:25 AM
  • I think the fundamental problem here is that in WPF controls are not windows.  Unlike the Win32 model where every control has an HWND associated with it, in WPF pretty much the only thing with an HWND is the Window which hosts everything else.  With that being the case, porting your code from WinForms to WPF, and expecting a UserControl to have an HWND, is not going to work out easily.  I think that Peter's suggestion of subclassing HwndSource is the way to go.

     

    The idea of using HwndSource to get the HWND of a UserControl is not going to work because, as stated earlier, a UserControl does not have an HWND.  In fact, if you run this (assume this.Content is a UserControl):

     

    Code Snippet

    void Window1_Loaded(object sender, RoutedEventArgs e)

    {

    HwndSource panelHwnd = HwndSource.FromVisual(this.Content as UserControl) as HwndSource;

    WindowInteropHelper windowHwnd =new WindowInteropHelper(this);

    bool same = panelHwnd.Handle == windowHwnd.Handle;

    Debug.Assert(same);

    }

     

     

    ...the assertion does not fail.  So, the call to HwndSource.FromVisual() just walks up the element tree looking for the first Win32 Window it can find.  What it finds is the main Window itself, not some special Window somehow owned by the UserControl.

     

    Regarding your trouble with subclassing UserControl, try explicitly specifying the base class in the C# code-behind to be UserControl.  In the example code you posted, the XAML explicitly declared what the base class is, but the C# code did not.  Doing so might fix the problem.  You can subclass whatever non-sealed class you need to.

     

    HTH

    Saturday, September 1, 2007 1:08 AM
  • Thanks to everyone for looking at this.  I got a lot of good ideas on where to look and what is and is not possible.

     

    So after much reading, mostly directed by these posts... I've finally come to see that only the parent window has a handle.  So what it looks like is the answer is to do the following:

    1. Get the HWND of the parent window (which is the only HWND in that entire hierarchy)

    2. Use my UserControl as a sort of placeholder as to where the content from my library will go.

    3. Call my lib's content creation function, which wants an HWND and a rectangle... the HWND will be the one and only, and the rectangle will come from my usercontrol.

    4. Monitor changes in the UserControl's position, and report that back to the lib to change the size of the content.

     

    While this seems a bit on the "cludgey" side, I guess the real design problem is not with WPF, and more with how my content library makes me talk with it.

     

    Thanks again!

    Jim

     

     

    Saturday, September 1, 2007 3:37 AM
  • I get null handle all the time . im doign this code in .Net 3.5 and VS2010. my HwdSource source = HwndSource.FromVisual(grid1) as HwndSource  returns a null ! do i need to enable anything in the project property ? Thank you
    Thursday, March 17, 2011 5:59 PM
  • Hi Jim,

    I assume you solved this long ago, but this is what I did in a similar case.

    I created a WinForms UserControl which does have a HWND (the Handle property).

    Then, I hosted it in WPF using the WindowsHost element.

    David


    header

    Friday, April 27, 2012 3:44 PM
  • cant get hwnd valuedo you need to host winform controller ?

    then try this

    http://msdn.microsoft.com/en-us/library/ms752055%28v=vs.90%29.aspx

    Wednesday, April 10, 2013 5:06 AM