c# - HwndHost para Windows Form-Interoperabilidad Win32/WinForm
c++ wpf (2)
Necesito alojar una ventana de Win32 en un control de Windows Form. Tuve el mismo problema con WPF y resolví este problema utilizando el control HwndHost
.
Seguí este tutorial:
Tutorial: Alojamiento de un control de Win32 en WPF
¿Hay algún control equivalente en Windows Form?
Tengo un Panel
y su propiedad Handle
, uso este manejador como padre de mi ventana de destino de procesamiento Direct2D:
// 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);
El código funciona si uso el HwndHost
principal de HwndHost
con WPF. Pero no muestra nada si uso System.Windows.Forms.Panel
Handle.
Lo que tuvo que hacer en WPF para crear una ventana de destino D2D1 válida no es necesario en Winforms. Era necesario en WPF porque los controles no son ventanas en sí mismos y no tienen una propiedad Handle, la que necesita CreateHwndRenderTarget ().
En Winforms, la clase Panel ya es un objetivo de renderizado perfectamente bueno, puede usar su propiedad Handle para decirle a D2D1 dónde debe renderizar. Solo hay que decirle que deje de pintarse. Agrega una nueva clase a tu proyecto y pega este código:
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
//...
}
}
}
Compilar. Coloque el nuevo control en su formulario, reemplazando el panel existente.
Suena como una aplicación MDI. ¿Algo como esto?
[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);