You can use HWndHost to host a Win32 HWnd window inside a WPF element


 


Suppose you have some old code lying around that creates a Win32 window with an HWnd (perhaps ATL, MFC, or just C/ C++). For example, if you type some erroneous code into a VB application in Visual Studio:


 


        Dim x=4: catch ex As Exception


 


 


The “Exception” will be squiggled and the end of the squiggle will have a red underline, indicating the presence of a Smart Tag.


 


You can move your mouse over the red underline or hit Ctrl-Period to invoke the smart tag suggestions for fixing the error. In this case, 2 suggested fixes are suggested in the smart tag menu: to insert Try/End Try in various places.


 


These suggested fixes show a preview right in the smart tag menu of what the effect is of each possible correction. These windows were written originally with Win32 Hwnds, using ATL.


 


You might want to take these old Windows and host them in a more modern application, using Windows Presentation Foundation


 


 


The sample below creates 4 identical Win32 HWnd windows hosted inside an HwndHost control. This control is then put into 3 WPF Popups and 1 WPF Window. The Win32 windows are simple and the WM_PAINT message just paints green & blue rectangles.


 


The 3 popups are identical, except that:


#1 has AllowTransparency = false. The Win32 hWnd window shows just fine


#2 has AllowTransparency = true. The Win32 hWnd window doesn’t show at all, but it can be discovered by using Spy++


#3 has AllowTransparency = true, but with the StackPanel inside with a Transparent Background. The Win32 hWnd  doesn’t show at all, and you can even click through the popup


 


 


A Popup with AllowsTransparency = True requires Full Trust security. See http://blogs.msdn.com/dwayneneed/archive/2008/09/08/transparent-windows-in-wpf.aspx


 


 


 


 


Start Visual Studio (I was using VS 2008)


 


Choose File->New Project->Visual Basic->WPF Application.


 


(This also works with Temporary projects)


 


Open Window1.xaml.vb. Paste in the code below, then hit F5 to run. Try clicking on the various areas.


 


 


See also:


 


Spy on your programs


 


CreateWindowEx


 


FillRect


 


Pinvoke.Net


 


<Sample Code>


 


 


Option Strict On


 


Imports System.Runtime.InteropServices


Imports System.Windows.Interop


 


Class Window1


    Sub Load() Handles MyBase.Loaded


 


        Me.Width = 600


        Me.Height = 600


        Dim popupNoTransparency = CreatePopup(False, “NoTransP”, “AliceBlue”, 0)


        Dim popupAllowTransparency = CreatePopup(True, “AllowTransp”, “AliceBlue”, 300)


 


 


        Dim popupTransparencyWithTransBack = CreatePopup(True, “popupTransparencyWithTransBack”, “Transparent”, 600)


 


        Me.Content = CreateUIElem(“Main Window”, “Bisque”)


 


 


    End Sub


    Function CreatePopup(ByVal AllowTransparency As Boolean, ByVal Name As String, ByVal BackGround As String, ByVal Horiz As Integer) As Primitives.Popup


        Dim popup = New Primitives.Popup


        popup.AllowsTransparency = AllowTransparency


        popup.Child = CreateUIElem(Name, BackGround)


        popup.Placement = Primitives.PlacementMode.AbsolutePoint


        popup.HorizontalOffset = Horiz


        popup.IsOpen = True


        Return popup


    End Function


    Function CreateUIElem(ByVal UIElemName As String, ByVal BackGround As String) As UIElement


        Dim xaml = _


        <StackPanel


            xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation


            xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml


            Name=HwndTest Width=350 Height=450 Background=<%= BackGround %> Orientation=Vertical Opacity=.5>


            <Button><%= UIElemName %></Button>


            <UserControl Name=MyBorder></UserControl>


            <Button>Bottom Button</Button>


            <TextBlock Name=Another>some text</TextBlock>


        </StackPanel>


        Dim UIElem = CType(System.Windows.Markup.XamlReader.Load(xaml.CreateReader), StackPanel)


 


        Dim Border = CType(UIElem.FindName(“MyBorder”), UserControl)


        Dim oMyHwndHost = New MyHwndHost


        Border.Content = oMyHwndHost


 


        Return UIElem


    End Function


 


End Class


Class MyHwndHost


    Inherits HwndHost


 


    Protected Overrides Function BuildWindowCore(ByVal hwndParent As System.Runtime.InteropServices.HandleRef) As System.Runtime.InteropServices.HandleRef


        Dim hwndMain As IntPtr = CreateWindowEx(0, “static”, “”, WindowStyles.WS_CHILD Or WindowStyles.WS_HSCROLL Or WindowStyles.WS_VSCROLL, _


                                     0, 0, 200, 300, hwndParent.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)


        Return New HandleRef(Me, hwndMain)


    End Function


 


    Protected Overrides Sub DestroyWindowCore(ByVal hwnd As System.Runtime.InteropServices.HandleRef)


        DestroyWindow(hwnd.Handle)


    End Sub


    Protected Overrides Function WndProc(ByVal hwnd As System.IntPtr, ByVal msg As Integer, ByVal wParam As System.IntPtr, ByVal lParam As System.IntPtr, ByRef handled As Boolean) As System.IntPtr


        Select Case msg


            Case WM_.WM_PAINT


                Dim ps As New PAINTSTRUCT


                BeginPaint(hwnd, ps)


                Dim hDC = ps.hdc


                Dim r = New RECT


                GetClientRect(hwnd, r)


                r.Right = CInt(r.Right / 2) ‘ create a rect of left half


 


                Dim hbrGreen = CreateSolidBrush(CType(&HFF00, IntPtr))


                Dim hbrBlue = CreateSolidBrush(CType(&HFF0000, IntPtr))


                FillRect(hDC, r, hbrGreen)


                r.Left += r.Right – r.Left


                r.Right *= 2    ‘ create a rect of right half


                FillRect(hDC, r, hbrBlue)


                EndPaint(hwnd, ps)


                DeleteObject(hbrGreen)


                DeleteObject(hbrBlue)


                handled = True


                Return IntPtr.Zero


        End Select


        Return MyBase.WndProc(hwnd, msg, wParam, lParam, handled)


    End Function


#Region “WIN32 Defs”


    Public Enum COLOR


        COLOR_SCROLLBAR = 0


        COLOR_BACKGROUND = 1


        COLOR_DESKTOP = 1


        COLOR_ACTIVECAPTION = 2


        COLOR_INACTIVECAPTION = 3


        COLOR_MENU = 4


        COLOR_WINDOW = 5


        COLOR_WINDOWFRAME = 6


        COLOR_MENUTEXT = 7


        COLOR_WINDOWTEXT = 8


        COLOR_CAPTIONTEXT = 9


        COLOR_ACTIVEBORDER = 10


        COLOR_INACTIVEBORDER = 11


        COLOR_APPWORKSPACE = 12


        COLOR_HIGHLIGHT = 13


        COLOR_HIGHLIGHTTEXT = 14


        COLOR_BTNFACE = 15


        COLOR_3DFACE = 15


        COLOR_BTNSHADOW = 16


        COLOR_3DSHADOW = 16


        COLOR_GRAYTEXT = 17


        COLOR_BTNTEXT = 18


        COLOR_INACTIVECAPTIONTEXT = 19


        COLOR_BTNHIGHLIGHT = 20


        COLOR_3DHIGHLIGHT = 20


        COLOR_3DHILIGHT = 20


        COLOR_BTNHILIGHT = 20


        COLOR_3DDKSHADOW = 21


        COLOR_3DLIGHT = 22


        COLOR_INFOTEXT = 23


        COLOR_INFOBK = 24


    End Enum


    <StructLayout(LayoutKind.Sequential)> _


        Public Structure RECT


        Public Left As Integer


        Public Top As Integer


        Public Right As Integer


        Public Bottom As Integer


 


        Public Function ToRect() As System.Windows.Rect


            Return New System.Windows.Rect(Left, Top, Right – Left, Bottom – Top)


        End Function


    End Structure


 


    <DllImport(“user32.dll”, CharSet:=CharSet.Auto)> _


    Private Shared Function GetClientRect(ByVal hWnd As System.IntPtr, _


       ByRef lpRECT As RECT) As Integer


    End Function


 


 


 


    Enum WM_


        WM_PAINT = &HF


    End Enum


    <Flags()> _


    Enum WindowStyles


        WS_OVERLAPPED = &H0


        WS_POPUP = &H80000000


        WS_CHILD = &H40000000


        WS_MINIMIZE = &H20000000


        WS_VISIBLE = &H10000000


        WS_DISABLED = &H8000000


        WS_CLIPSIBLINGS = &H4000000


        WS_CLIPCHILDREN = &H2000000


        WS_MAXIMIZE = &H1000000


        WS_BORDER = &H800000


        WS_DLGFRAME = &H400000


        WS_VSCROLL = &H200000


        WS_HSCROLL = &H100000


        WS_SYSMENU = &H80000


        WS_THICKFRAME = &H40000


        WS_GROUP = &H20000


        WS_TABSTOP = &H10000


        WS_MINIMIZEBOX = &H20000


        WS_MAXIMIZEBOX = &H10000


        WS_CAPTION = WS_BORDER Or WS_DLGFRAME


        WS_TILED = WS_OVERLAPPED


        WS_ICONIC = WS_MINIMIZE


        WS_SIZEBOX = WS_THICKFRAME


        WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW


        WS_OVERLAPPEDWINDOW = WS_OVERLAPPED Or WS_CAPTION Or WS_SYSMENU Or WS_THICKFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX


        WS_POPUPWINDOW = WS_POPUP Or WS_BORDER Or WS_SYSMENU


        WS_CHILDWINDOW = WS_CHILD


    End Enum


    <DllImport(“user32.dll”, SetLastError:=True, CharSet:=CharSet.Auto)> _


    Private Shared Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As Int32) As Boolean


    End Function


    <DllImport(“user32.dll”)> _


    Public Shared Function UpdateWindow( _


     ByVal hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean


    End Function


    <DllImport(“user32.dll”, CharSet:=CharSet.Auto)> _


    Private Shared Function CreateWindowEx( _


         ByVal dwExStyle As UInteger, _


         ByVal lpClassName As String, _


         ByVal lpWindowName As String, _


         ByVal dwStyle As WindowStyles, _


         ByVal x As Integer, _


         ByVal y As Integer, _


         ByVal nWidth As Integer, _


         ByVal nHeight As Integer, _


         ByVal hWndParent As IntPtr, _


         ByVal hMenut As IntPtr, _


         ByVal hInstancet As IntPtr, _


         ByVal lpParamt As IntPtr) As IntPtr


    End Function


#If 0 Then


hwndMain = CreateWindowEx(


    0,                      // no extended styles          


    “MainWClass”,           // class name                  


    “Main Window”,          // window name                 


    WS_OVERLAPPEDWINDOW |   // overlapped window           


             WS_HSCROLL |   // horizontal scroll bar       


             WS_VSCROLL,    // vertical scroll bar         


    CW_USEDEFAULT,          // default horizontal position 


    CW_USEDEFAULT,          // default vertical position   


    CW_USEDEFAULT,          // default width               


    CW_USEDEFAULT,          // default height              


    (HWND) NULL,            // no parent or owner window   


    (HMENU) NULL,           // class menu used             


    hinstance,              // instance handle             


    NULL);                  // no window creation data     


 


#End If


    <DllImport(“user32.dll”, SetLastError:=True, CharSet:=CharSet.Auto)> _


    Private Shared Function DestroyWindow(ByVal hwnd As IntPtr) As Boolean


    End Function


 


    Const CW_USEDEFAULT As Int32 = &H80000000


 


    Enum Show_Window


        SW_HIDE = 0


        SW_SHOWNORMAL = 1


        SW_NORMAL = 1


        SW_SHOWMINIMIZED = 2


        SW_SHOWMAXIMIZED = 3


        SW_MAXIMIZE = 3


        SW_SHOWNOACTIVATE = 4


        SW_SHOW = 5


        SW_MINIMIZE = 6


        SW_SHOWMINNOACTIVE = 7


        SW_SHOWNA = 8


        SW_RESTORE = 9


        SW_SHOWDEFAULT = 10


        SW_FORCEMINIMIZE = 11


        SW_MAX = 11


    End Enum


    <StructLayout(LayoutKind.Sequential, Pack:=4)> _


      Public Structure PAINTSTRUCT


        Public hdc As IntPtr


        Public fErase As Integer


        Public rcPaint As RECT


        Public fRestore As Integer


        Public fIncUpdate As Integer


        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=32)> _


        Public rgbReserved As Byte()


    End Structure


    <DllImport(“user32.dll”)> _


    Public Shared Function BeginPaint( _


     ByVal hWnd As IntPtr, ByRef lpPaint As PAINTSTRUCT) As IntPtr


    End Function


    <DllImport(“user32.dll”)> _


    Public Shared Function EndPaint( _


     ByVal hWnd As IntPtr, ByRef lpPaint As PAINTSTRUCT) As IntPtr


    End Function


    <DllImport(“user32.dll”)> _


    Public Shared Function FillRect(ByVal hDC As IntPtr, ByRef lpRect As RECT, ByVal hBR As IntPtr) As IntPtr


    End Function


    <DllImport(“gdi32.dll”)> _


    Public Shared Function CreateSolidBrush(ByVal crColor As IntPtr) As IntPtr


    End Function


 


    <DllImport(“gdi32.dll”)> _


    Public Shared Function DeleteObject(ByVal hObject As IntPtr) As IntPtr


    End Function


 


 


 


 


#End Region


 


End Class


 


 


 


 


 


</Sample Code>


 

Comments (2)

  1. Brady Kelly says:

    This doesn't work for me. I get three of the external MainWindow in my Visual Studio IDE screen, at the top left, horizontally next to each other, and one WPF MainWindow with the created MainWindow inside it, scrollbars and buttons not working.