如何将非托管 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 应用程序中?的主要内容,如果未能解决你的问题,请参考以下文章