Windows 窗体的 HwndHost - Win32/WinForm 互操作性
HwndHost for Windows Form - Win32 / WinForm Interoperability
我需要在 Windows 表单控件中托管 Win32 window。我在 WPF 中遇到了同样的问题,我通过使用 HwndHost
控件解决了这个问题。
我遵循了这个教程:
Walkthrough: Hosting a Win32 Control in WPF
Windows窗体中是否有等效控件?
我有一个 Panel
及其 Handle
属性,我将此句柄用作我的 Direct2D 渲染目标的父级 window:
// Register the window class.
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
// Redraws the entire window if a movement or size adjustment changes the height
// or the width of the client area.
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = Core::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.hCursor = LoadCursor(nullptr, IDI_APPLICATION);
wcex.lpszClassName = L"SVGCoreClassName";
RegisterClassEx(&wcex);
hwnd = CreateWindow(
L"SVGCoreClassName", // class name
L"", // window name
WS_CHILD | WS_VISIBLE, // style
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y
CW_USEDEFAULT, // width
CW_USEDEFAULT, // height
parent, // parent window
nullptr, // window menu
HINST_THISCOMPONENT, // instance of the module to be associated with the window
this); // pointer passed to the WM_CREATE message
...
hr = d2dFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(hwnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY),
&renderTarget);
如果我在 WPF 中使用 HwndHost
父句柄,代码就可以工作。但是如果我使用 System.Windows.Forms.Panel
句柄,它不会渲染任何东西。
听起来像一个 MDI 应用程序。是这样的吗?
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
Form f = new Form();
Button b1 = new Button { Text = "Notepad" };
b1.Click += delegate {
using (var p = Process.Start("notepad.exe")) {
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, f.Handle);
MoveWindow(p.MainWindowHandle, 50, 50, 300, 300, true);
}
};
f.Controls.Add(b1);
Application.Run(f);
在 WPF 中创建有效的 D2D1 目标所必须执行的操作 window 在 Winforms 中不需要。这在 WPF 中是必要的,因为控件本身不是 windows,也没有句柄 属性,而 CreateHwndRenderTarget() 需要它。
在 Winforms 中,Panel class 已经是一个非常好的渲染目标,您可以使用它的 Handle 属性 来告诉 D2D1 在哪里渲染。你只需要告诉它停止绘画本身。向您的项目添加一个新的 class 并粘贴此代码:
using System;
using System.Windows.Forms;
class D2D1RenderTarget : Control {
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
if (!this.DesignMode) {
this.SetStyle(ControlStyles.UserPaint, false);
// Initialize D2D1 here, use this.Handle
//...
}
}
}
编译。将新控件拖放到窗体上,替换现有面板。
我需要在 Windows 表单控件中托管 Win32 window。我在 WPF 中遇到了同样的问题,我通过使用 HwndHost
控件解决了这个问题。
我遵循了这个教程:
Walkthrough: Hosting a Win32 Control in WPF
Windows窗体中是否有等效控件?
我有一个 Panel
及其 Handle
属性,我将此句柄用作我的 Direct2D 渲染目标的父级 window:
// Register the window class.
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
// Redraws the entire window if a movement or size adjustment changes the height
// or the width of the client area.
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = Core::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.hCursor = LoadCursor(nullptr, IDI_APPLICATION);
wcex.lpszClassName = L"SVGCoreClassName";
RegisterClassEx(&wcex);
hwnd = CreateWindow(
L"SVGCoreClassName", // class name
L"", // window name
WS_CHILD | WS_VISIBLE, // style
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y
CW_USEDEFAULT, // width
CW_USEDEFAULT, // height
parent, // parent window
nullptr, // window menu
HINST_THISCOMPONENT, // instance of the module to be associated with the window
this); // pointer passed to the WM_CREATE message
...
hr = d2dFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(hwnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY),
&renderTarget);
如果我在 WPF 中使用 HwndHost
父句柄,代码就可以工作。但是如果我使用 System.Windows.Forms.Panel
句柄,它不会渲染任何东西。
听起来像一个 MDI 应用程序。是这样的吗?
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
Form f = new Form();
Button b1 = new Button { Text = "Notepad" };
b1.Click += delegate {
using (var p = Process.Start("notepad.exe")) {
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, f.Handle);
MoveWindow(p.MainWindowHandle, 50, 50, 300, 300, true);
}
};
f.Controls.Add(b1);
Application.Run(f);
在 WPF 中创建有效的 D2D1 目标所必须执行的操作 window 在 Winforms 中不需要。这在 WPF 中是必要的,因为控件本身不是 windows,也没有句柄 属性,而 CreateHwndRenderTarget() 需要它。
在 Winforms 中,Panel class 已经是一个非常好的渲染目标,您可以使用它的 Handle 属性 来告诉 D2D1 在哪里渲染。你只需要告诉它停止绘画本身。向您的项目添加一个新的 class 并粘贴此代码:
using System;
using System.Windows.Forms;
class D2D1RenderTarget : Control {
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
if (!this.DesignMode) {
this.SetStyle(ControlStyles.UserPaint, false);
// Initialize D2D1 here, use this.Handle
//...
}
}
}
编译。将新控件拖放到窗体上,替换现有面板。