如何将非托管 C++ 表单嵌入到 .NET 应用程序中?

Posted

技术标签:

【中文标题】如何将非托管 C++ 表单嵌入到 .NET 应用程序中?【英文标题】:How can I embed an unmanaged C++ form into a .NET application? 【发布时间】:2011-03-01 15:48:27 【问题描述】:

我已经能够成功包装我的非托管 Borland C++ dll,并从 C# .NET 4.0 应用程序启动它的表单。是否可以将 dll 中的表单直接嵌入到 .NET 应用程序中?

为了澄清,原始表单已经在 Borland C++ 项目中用作嵌入式控件。它本质上看起来像一个自定义控件,位于应用程序的面板上。

当我说“嵌入”时,我的意思是将按钮、面板等放到表单上的方式相同的方式放置到表单中。我不想只制作一个子窗体。

如果这是不可能的,那么也许更好的问题是如何将未管理的自定义控件嵌入到 .Net 应用程序中?

【问题讨论】:

你的意思是嵌入显示为子窗口,还是嵌入在.NET项目中的代码? 【参考方案1】:

是的,您只需要使用 user32.dll 中的一些低级 win32 函数:SetParent、GetWindowLog、SetWindowLong、MoveWindow。您可以创建一个空的 .NET 容器控件,将原生窗口的父级设置为 .NET 控件,然后(可选)修改窗口样式(即移除原生窗口的边框),并注意与.NET 控制。请注意,在托管级别,.NET 控件将不知道它有任何子控件。

在 .NET 控件中执行类似的操作

public void AddNativeChildWindow(IntPtr hWndChild)

        //adjust window style of child in case it is a top-level window
        int iStyle = GetWindowLong(hWndChild, GWL_STYLE);
        iStyle = iStyle & (int)(~(WS_OVERLAPPEDWINDOW | WS_POPUP));
        iStyle = iStyle | WS_CHILD;
        SetWindowLong(hWndChild, GWL_STYLE, iStyle);


        //let the .NET control  be the parent of the native window
        SetParent((IntPtr)hWndChild, this.Handle);
         this._childHandle=hWndChild;

        // just for fun, send an appropriate message to the .NET control 
        SendMessage(this.Handle, WM_PARENTNOTIFY, (IntPtr)1, (IntPtr)hWndChild);


然后覆盖 .NET 控件的 WndProc 以使其适当地调整本机窗体的大小 - 例如填充客户区。

 protected override unsafe void WndProc(ref Message m)
    

        switch (m.Msg)
        
            case WM_PARENTNOTIFY:
                   //... maybe change the border styles , etc
                   break;
              case WM_SIZE:
                iWid =(int)( (int)m.LParam & 0xFFFF);
                iHei= (int) (m.LParam) >> 16;
                if (_childHandle != (IntPtr)0)
                

                    MoveWindow(_childHandle, 0, 0, iWid, iHei, true);

                
                break;

        

 

【讨论】:

这当然使本机窗体成为 .NET 应用程序的子窗体之一,但并没有真正解决在 .NET 应用程序中“嵌入”窗口的问题。我们似乎对这个问题的解释完全不同。 这个问题模棱两可。 我试图进一步澄清这个问题。本质上,我正在寻找一种将表单放置在 .NET 表单中的方法,就像在表单上放置按钮和标签一样。我想将其嵌入为表单控件,而不仅仅是子窗口。 如果您将它包装在我描述的自定义控件中,您也可以像任何其他控件一样在表单设计器中使用它。只是 IDE 不知道如何处理您的本机事件,您需要在包装器中手动处理。【参考方案2】:

注意 我写这个回复是假设 OP 想要在 .NET 应用程序中嵌入包含表单的本机 DLL,而不仅仅是修改它的显示方式。 em>

简而言之,不。您需要将 C++ DLL 与您的发行版一起打包,并以与现在相同的方式导入/包装其函数。

我似乎记得在我的 Delphi(它使用与 Borland C++ 相同的编译器后端)中,表单设计器生成 C++ 代码,该代码通过 with 为表单中的每个资产创建一个 winproc/message 循环等Win32 API。

由于所有这些代码都是非托管的,因此无法将其编译为托管程序集。您可以将它移植到托管 C++,但这会扼杀在 C++ 中开始使用它的大部分好处,并且您会陷入糟糕的异常模型和 C++ 的所有其他精彩部分。在这种情况下,您最好用 C# 重写它。

但是,由于这是软件,几乎一切皆有可能,这是一个非常糟糕的解决方案:将 DLL 作为二进制资源嵌入到您的 .NET 应用程序中,并在运行时将其内容拉入二进制流中,然后保存到磁盘然后加载它(我不确定是否有办法从内存中执行非托管 DLL,而不是通过将其放在 RAM 磁盘上作弊)。

这让你唯一得到的是隐藏 DLL 的能力,但我真的不明白这一点。

编辑 你的意思是嵌入显示为子窗口,还是嵌入在.NET项目中的代码?

【讨论】:

以上是关于如何将非托管 C++ 表单嵌入到 .NET 应用程序中?的主要内容,如果未能解决你的问题,请参考以下文章

将非托管 C++ dll 添加到托管 C++ dll

如何将非托管 dll 和托管程序集合并到一个文件中?

将非托管 EXE 作为资源合并到托管 C# 代码中

如何将托管 c++ 库导入 C# 应用程序(目标 .net 版本 3.5)

如何将非托管库引用添加到 NUnit 测试

将非托管方法作为回调传递给托管 C++/CLI 类