我想在我的 WPF 应用程序中托管一个外部进程的窗口。我像这样导出
HwndHost
:
class HwndHostEx : HwndHost
{
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
private IntPtr ChildHandle = IntPtr.Zero;
public HwndHostEx(IntPtr handle)
{
this.ChildHandle = handle;
}
protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent)
{
HandleRef href = new HandleRef();
if (ChildHandle != IntPtr.Zero)
{
SetParent(this.ChildHandle, hwndParent.Handle);
href = new HandleRef(this, this.ChildHandle);
}
return href;
}
protected override void DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd)
{
}
}
并像这样使用它:
HwndHostEx host = new HwndHostEx(handle);
this.PART_Host.Child = host;
其中
handle
是我想要托管的外部窗口的句柄,PART_Host
是我的 WPF 窗口内的边框:
<StackPanel UseLayoutRounding="True"
SnapsToDevicePixels="True"
Background="Transparent">
<Border Name="PART_Host" />
...
这给了我一个例外:
Hosted HWND must be a child window.
抱歉,我缺乏知识,但是在 WPF 应用程序中托管外部窗口的正确方法是什么?
在调用“SetParent”之前执行以下操作:
public const int GWL_STYLE = (-16);
public const int WS_CHILD = 0x40000000;
SetWindowLong(this.ChildHandle, GWL_STYLE, WS_CHILD);
查看文档:
似乎不可能从 WPF 应用程序内的另一个进程“附加”已经运行的窗口。
如何获取传递给 HwndHostEx 构造函数的句柄?
为了补充说明,以下是在 WPF 应用程序中托管进程的最终代码,取自 Jose 的答案:
class HwndHostEx : HwndHost
{
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, UInt32 dwNewLong);
private IntPtr ChildHandle = IntPtr.Zero;
public HwndHostEx(IntPtr handle)
{
this.ChildHandle = handle;
}
protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent)
{
HandleRef href = new HandleRef();
if (ChildHandle != IntPtr.Zero)
{
const int GWL_STYLE = (-16);
const int WS_CHILD = 0x40000000;
SetWindowLong(this.ChildHandle, GWL_STYLE, WS_CHILD);
SetParent(this.ChildHandle, hwndParent.Handle);
href = new HandleRef(this, this.ChildHandle);
}
return href;
}
protected override void DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd)
{
}
}
// to create an instance:
var processName = "Whatever.exe";
var process = System.Diagnostics.Process.GetProcesses()
.FirstOrDefault(item => item.ProcessName.ToLowerInvariant() == processName && item.MainWindowHandle != IntPtr.Zero);
var handle = process?.MainWindowHandle;
if(handle != null)
{
var host = new HwndHostEx(handle.Value);
YourControl.Grid.Children.Add(host);
}