如何嵌入非托管 C++形成 .NET 应用程序?

发布于 2024-10-19 21:49:38 字数 282 浏览 3 评论 0原文

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

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

当我说“嵌入”时,我的意思是放入表单,就像将按钮、面板等拖放到表单上一样。我不想只制作一个儿童表格。

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

I have been able to successfully wrap my unmanaged Borland C++ dll, and launch it's forms from a C# .NET 4.0 application. Is it possible to embed a form from the dll directly into a .NET application?

To clarify, the original form is being used as an embedded control in a Borland C++ project already. It essentially looks like a custom control, sitting on a panel within the application.

When I say 'embed' I mean place INTO a form in the same way you drop buttons, panels, etc on to a form. I'm not looking to just make a child form.

If this is not possible, then perhaps a better question would be how do I embed an unmanged custom control into a .Net application?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

妥活 2024-10-26 21:49:38

是的,您只需要使用 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;

        }

 }

Yes, you just need to use some low-level win32 functions from user32.dll : SetParent, GetWindowLog, SetWindowLong , MoveWindow . You can create an empty .NET container control, set the parent of the native window to the .NET control, then (optionally) modify the window style (i.e. to remove borders of native window), and pay attention to resize it together with the .NET control. Note that, at a managed level, the .NET control will be unaware it has any children.

In the .NET control do something like

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);

}

Then override the WndProc of the .NET control to make it resize the native form appropriately -- for example to fill the client area.

 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;

        }

 }
孤寂小茶 2024-10-26 21:49:38

假设 OP 希望将包含表单的本机 DLL 嵌入到 .NET 应用程序中,而不仅仅是修改其显示方式。

注意 我编写此响应时 简短,不。您需要将 C++ DLL 与您的发行版打包在一起,并以与现在相同的方式导入/包装其函数。

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

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

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

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

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

Note I wrote this response assuming that the OP wanted to literally embed the native DLL containing the form in the .NET app, not just modify the way in which it's displayed.

In short, no. You'll need to package the C++ DLL with your distribution and import/wrap its functions the same way that you're doing now.

I seem to recall from my Delphi (which uses the same compiler back-end as Borland C++) days that the form designer generates C++ code which creates a winproc/message loop, etc for each of the assets in the form via with Win32 API.

Since all of that code is unmanaged, it can't be compiled into a managed assembly. You could port it to managed C++, but that would kill most of the benefit of having it in C++ to start with, and you're stuck with a crappy exception model and all of the other wonderful parts of C++. In that case, you'd probably be better off just rewriting it in C#.

But, since this is software, and almost anything is possible, here's a really lame solution: embed the DLL as a binary resource in your .NET app and, at run time, pull its contents into a binary stream, save it to disk and then load it (I'm not sure if there is a way to execute an unmanaged DLL from memory, other than cheating by putting it on a RAM disk).

The only thing this gets you is the ability to hide the DLL, but I really don't see the point.

Edit
Do you mean embed as in show as a child window, or embed as in place the code within the .NET project?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文