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 https://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:
<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="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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
Anonymous
June 18, 2009
PingBack from http://barstoolsite.info/story.php?id=7173Anonymous
April 03, 2014
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.