HwndHost for Windows Form - Win32 / WinForm 互操作性

Posted

技术标签:

【中文标题】HwndHost for Windows Form - Win32 / WinForm 互操作性【英文标题】:HwndHost for Windows Form - Win32 / WinForm Interoperability 【发布时间】:2015-06-23 03:38:30 【问题描述】:

我需要在 Windows 窗体控件中托管一个 Win32 窗口。我在使用 WPF 时遇到了同样的问题,我通过使用 HwndHost 控件解决了这个问题。

我遵循了这个教程:

Walkthrough: Hosting a Win32 Control in WPF

Windows 窗体中是否有任何等效控件?

我有一个Panel 及其Handle 属性,我将此句柄用作我的 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);

如果我将 HwndHost 父句柄与 WPF 一起使用,则该代码有效。但如果我使用 System.Windows.Forms.Panel 句柄,它不会呈现任何内容。

【问题讨论】:

您可能对NativeWindow感兴趣。 所有 Winforms 控件都已经是 Win32 窗口,因此“托管”没有多大意义。您需要更好地描述此窗口的性质。谁拥有它?你是如何创建它的? @HansPassant 请看我的编辑。 这段代码有错误检查吗?你需要 if (hwnd == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();现在你就会知道为什么它不起作用了。 @HansPassant 我的 hwnd 是一个有效的指针,它不为空。我之前使用 WPF 进行的所有检查仍然保持不变,并且所有测试都通过了。 【参考方案1】:

您必须在 WPF 中执行的创建有效 D2D1 目标窗口的操作在 Winforms 中是不必要的。这在 WPF 中是必要的,因为控件本身不是窗口,并且没有 Handle 属性,而 CreateHwndRenderTarget() 需要该属性。

在 Winforms 中,Panel 类已经是一个非常好的渲染目标,你可以使用它的 Handle 属性来告诉 D2D1 在哪里渲染。你只需要告诉它停止绘画本身。向您的项目添加一个新类并粘贴此代码:

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
            //...
        
    

编译。将新控件拖放到表单上,替换现有面板。

【讨论】:

我不明白我必须传递什么句柄作为 CreateWindow 函数的父参数。我尝试在 OnHandleCreated 方法中使用 Control.Handle 属性,但它不起作用。请也查看我的编辑。 此外,我注意到未调用 CreateParams 属性(当我在其中设置断点时)。 不要,当您将控件放在面板上时,它是完全自动的。如果您在代码中执行此操作,则必须使用表单的 Controls.Add() 方法将控件添加到面板。添加一些代码后,这看起来完全是不必要的。 CreateHwndRenderTarget() 所需要的只是一个有效的窗口句柄。面板的Handle属性已经够用了,再多帮点也没意义。 C++ 代码所做的与 Panel 所做的相同。很遗憾你发布了如此糟糕的sn-p。 对不起,我还是不明白。我有我发布的 C++ 代码,我在其中创建了一个窗口并设置了它的父级。然后我使用窗口句柄来创建我的 Direct2D 渲染目标。使用 WPF,我使用 HwndHost 控件和 BuildWindowCore 方法来获取句柄(CreateWindow 函数中的父参数),它可以工作。现在使用 Forms.Control 类我无法做同样的事情,即我不知道我必须在哪里、何时以及将什么句柄传递给我的 C++ 代码,就像我之前使用 WPF 所做的那样。你能说清楚一点吗? 您需要跳过 WPF 中的那些环节,因为控件没有 Handle 属性。在 Winforms 中不需要。【参考方案2】:

听起来像一个 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);

【讨论】:

以上是关于HwndHost for Windows Form - Win32 / WinForm 互操作性的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 窗体中显示 textBox.Text,“idx”遍历 for 循环

springmvc的form标签

通过Powershell从Richtextbox-Scroll事件中读取EventArgs

如何用wpf调用mfc程序呢?

Rails 5:form_for 与 form_with

form_for 关闭 <form> 标签