Skip to content

Instantly share code, notes, and snippets.

@inxomnyaa
Forked from itsho/HwndHostEx.cs
Created August 9, 2021 02:25
Show Gist options
  • Save inxomnyaa/40e2658947e0960500c7dc75f6114503 to your computer and use it in GitHub Desktop.
Save inxomnyaa/40e2658947e0960500c7dc75f6114503 to your computer and use it in GitHub Desktop.
Hosting an app inside a WPF app (System.Windows.Interop)
using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;
namespace HostingAppTest
{
// based on https://stackoverflow.com/q/30186930/426315
public class HwndHostEx : HwndHost
{
private readonly IntPtr _childHandle;
public HwndHostEx(IntPtr handle)
{
_childHandle = handle;
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
var childRef = new HandleRef();
if (_childHandle != IntPtr.Zero)
{
var childStyle = (IntPtr)(Win32API.WindowStyles.WS_CHILD |
// Child window should be have a thin-line border
Win32API.WindowStyles.WS_BORDER |
// the parent cannot draw over the child's area. this is needed to avoid refresh issues
Win32API.WindowStyles.WS_CLIPCHILDREN |
Win32API.WindowStyles.WS_VISIBLE |
Win32API.WindowStyles.WS_MAXIMIZE);
childRef = new HandleRef(this, _childHandle);
Win32API.SetWindowLongPtr(childRef, Win32API.GWL_STYLE, childStyle);
Win32API.SetParent(_childHandle, hwndParent.Handle);
}
return childRef;
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
}
}
}
using System.Diagnostics;
namespace HostingAppTest
{
public class LoadingChildExample
{
public void LoadChild()
{
var procInfo = new ProcessStartInfo("calc.exe");
var childProc = new Process(procInfo);
childProc.Start();
var hostedChild = new HwndHostEx(childProc.MainWindowHandle);
// Any FrameworkElement that inherits from System.Windows.Controls.Decorator can host the child.
// No need to use WindowsFormsHost!
decoratorControl.Child = hostedChild;
}
}
}
using System;
using System.Runtime.InteropServices;
namespace HostingAppTest
{
public class Win32API
{
[DllImport("User32.dll")]
internal static extern IntPtr SetParent(IntPtr hwc, IntPtr hwp);
/// <summary>
/// This static method is required because legacy OSes do not support SetWindowLongPtr
/// </summary>
internal static IntPtr SetWindowLongPtr(HandleRef hWnd, int nIndex, IntPtr dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
else
return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32()));
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(HandleRef hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
/// <summary>
/// This static method is required because Win32 does not support GetWindowLongPtr directly
/// </summary>
internal static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
return GetWindowLongPtr64(hWnd, nIndex);
else
return GetWindowLongPtr32(hWnd, nIndex);
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool BringWindowToTop(HandleRef hWnd);
internal const int GWL_STYLE = -16;
internal const int GWL_EXSTYLE = -20;
[Flags]
internal enum WindowStyles : uint
{
WS_OVERLAPPED = 0x00000000,
WS_POPUP = 0x80000000,
WS_CHILD = 0x40000000,
WS_MINIMIZE = 0x20000000,
WS_VISIBLE = 0x10000000,
WS_DISABLED = 0x08000000,
WS_CLIPSIBLINGS = 0x04000000,
WS_CLIPCHILDREN = 0x02000000,
WS_MAXIMIZE = 0x01000000,
WS_BORDER = 0x00800000,
WS_DLGFRAME = 0x00400000,
WS_VSCROLL = 0x00200000,
WS_HSCROLL = 0x00100000,
WS_SYSMENU = 0x00080000,
WS_THICKFRAME = 0x00040000,
WS_GROUP = 0x00020000,
WS_TABSTOP = 0x00010000,
WS_MINIMIZEBOX = 0x00020000,
WS_MAXIMIZEBOX = 0x00010000,
WS_CAPTION = WS_BORDER | WS_DLGFRAME,
WS_TILED = WS_OVERLAPPED,
WS_ICONIC = WS_MINIMIZE,
WS_SIZEBOX = WS_THICKFRAME,
WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW,
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
WS_CHILDWINDOW = WS_CHILD,
//Extended Window Styles
WS_EX_DLGMODALFRAME = 0x00000001,
WS_EX_NOPARENTNOTIFY = 0x00000004,
WS_EX_TOPMOST = 0x00000008,
WS_EX_ACCEPTFILES = 0x00000010,
WS_EX_TRANSPARENT = 0x00000020,
//#if(WINVER >= 0x0400)
WS_EX_MDICHILD = 0x00000040,
WS_EX_TOOLWINDOW = 0x00000080,
WS_EX_WINDOWEDGE = 0x00000100,
WS_EX_CLIENTEDGE = 0x00000200,
WS_EX_CONTEXTHELP = 0x00000400,
WS_EX_RIGHT = 0x00001000,
WS_EX_LEFT = 0x00000000,
WS_EX_RTLREADING = 0x00002000,
WS_EX_LTRREADING = 0x00000000,
WS_EX_LEFTSCROLLBAR = 0x00004000,
WS_EX_RIGHTSCROLLBAR = 0x00000000,
WS_EX_CONTROLPARENT = 0x00010000,
WS_EX_STATICEDGE = 0x00020000,
WS_EX_APPWINDOW = 0x00040000,
WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE),
WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST),
//#endif /* WINVER >= 0x0400 */
//#if(WIN32WINNT >= 0x0500)
WS_EX_LAYERED = 0x00080000,
//#endif /* WIN32WINNT >= 0x0500 */
//#if(WINVER >= 0x0500)
WS_EX_NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children
WS_EX_LAYOUTRTL = 0x00400000, // Right to left mirroring
//#endif /* WINVER >= 0x0500 */
//#if(WIN32WINNT >= 0x0500)
WS_EX_COMPOSITED = 0x02000000,
WS_EX_NOACTIVATE = 0x08000000
//#endif /* WIN32WINNT >= 0x0500 */
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment