Skip to content

Instantly share code, notes, and snippets.

@itsho
Last active January 23, 2024 17:13
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save itsho/8b0e761d9114e27c8570fbf95465bbfc to your computer and use it in GitHub Desktop.
Save itsho/8b0e761d9114e27c8570fbf95465bbfc 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 */
}
}
}
@inxomnyaa
Copy link

any idea why this is working fine for notepad and winver, but explorer.exe shows in a separate window?

@itsho
Copy link
Author

itsho commented Aug 10, 2021

Probably because Explorer.exe is the whole shell. And you can't host it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment