mfc对话框中如何嵌入c#winform窗口

mfc对话框中如何嵌入c#winform窗口,类似下图把图一嵌入到图2指定的位置

img

img

用winexec启动程序,FindWindow找到C#的窗口(最好循环获取,因为启动需要时间,不是立刻调用就能得到)
然后用 SetWindowLong 修改窗体的样式去掉边框,用SetParent将窗体装入mfc

以下代码你需要根据实际,略微修改

#include <afxwin.h>

// 声明全局变量用于存储C#窗口的句柄
HWND g_hCSharpWnd = NULL;

// MFC对话框类
class CMyDialog : public CDialog
{
public:
    CMyDialog(CWnd* pParent = NULL) : CDialog(IDD_MYDIALOG, pParent) {}

    // MFC消息映射宏
    DECLARE_MESSAGE_MAP()

    // MFC对话框消息处理函数
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
};

// MFC消息映射宏
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
    ON_WM_CREATE()
END_MESSAGE_MAP()

// MFC对话框消息处理函数
int CMyDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDialog::OnCreate(lpCreateStruct) == -1)
        return -1;

    // 启动C#程序
    WinExec("YourCSharpProgram.exe", SW_SHOW);

    // 循环获取C#窗口句柄,直到找到为止
    while (g_hCSharpWnd == NULL)
    {
        // 使用C#窗口的标题或类名进行查找,根据实际情况修改
        g_hCSharpWnd = FindWindow(NULL, "YourCSharpWindowTitle");

        // 等待一段时间再次尝试查找
        Sleep(1000);
    }

    // 修改C#窗口的样式,去掉边框
    LONG style = GetWindowLong(g_hCSharpWnd, GWL_STYLE);
    style &= ~WS_BORDER;
    SetWindowLong(g_hCSharpWnd, GWL_STYLE, style);

    // 将C#窗口装入MFC对话框
    CWnd* pCSharpWnd = CWnd::FromHandle(g_hCSharpWnd);
    pCSharpWnd->SetParent(this);

    // 调整C#窗口的位置和大小
    CRect rect;
    GetClientRect(&rect);
    pCSharpWnd->MoveWindow(rect);

    return 0;
}

// MFC应用程序类
class CMyApp : public CWinApp
{
public:
    virtual BOOL InitInstance();
};

// MFC应用程序初始化函数
BOOL CMyApp::InitInstance()
{
    CMyDialog dlg;
    m_pMainWnd = &dlg;
    dlg.DoModal();

    return FALSE;
}

// 全局MFC应用程序对象
CMyApp theApp;

问题没得到解决,应该跟你的进程启动方式有关,也可能是你查找窗口的代码有点问题,方便的话,把c#工程发出来看一下问题。


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ClassLibrary2
{
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("hello world!");
        }
    }
}


该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
在MFC对话框中嵌入一个C# WinForm窗口,可以使用MFC中的CWinFormsControl类来实现。具体步骤如下:

1、 创建一个MFC对话框应用程序,并添加一个控件用于容纳WinForm窗口。在资源编辑器中创建一个“Picture Control”控件,可以通过“插入ActiveX控件”来添加,然后调整控件的大小和位置,以便容纳WinForm窗口。

2、 在MFC应用程序中添加一个CWinFormsControl类。右键单击项目,选择“添加类”,然后在“添加类向导”中选择“MFC”->“控件类”,输入类名并选择CWinFormsControl作为基类。

3、 在CWinFormsControl类中添加一个C# WinForm窗口。在CWinFormsControl类的头文件中,添加以下代码:

using namespace System::Windows::Forms;

public ref class CMyWinFormsControl : public CWinFormsControl
{
public:
    CMyWinFormsControl()
    {
        // 创建C# WinForm窗口
        m_pMyWinForm = gcnew MyWinForm();
        m_pMyWinForm->TopLevelControl = this;
        m_pMyWinForm->Visible = true;
    }

protected:
    MyWinForm^ m_pMyWinForm;
};

这里的MyWinForm是一个C# WinForm窗口类,它是在Visual Studio中创建的。

4、 在MFC对话框类中添加一个CWinFormsControl成员变量。在对话框类的头文件中,添加以下代码:

#include "MyWinFormsControl.h"

class CMyDialog : public CDialogEx
{
public:
    CMyWinFormsControl m_myWinFormsControl;
};

5、 在OnInitDialog()函数中创建CWinFormsControl对象并将其添加到MFC对话框中。在对话框类的源文件中,添加以下代码:

BOOL CMyDialog::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 获取控件句柄
    CWnd* pWnd = GetDlgItem(IDC_WINFORMS_CONTROL);

    // 创建CWinFormsControl对象
    RECT rect;
    pWnd->GetWindowRect(&rect);
    ScreenToClient(&rect);
    m_myWinFormsControl.Create(NULL, NULL, WS_CHILD | WS_VISIBLE, rect, this, IDC_WINFORMS_CONTROL);

    return TRUE;
}

这里的IDC_WINFORMS_CONTROL是在资源编辑器中创建的控件ID。

6、 在MFC对话框类的OnSize()函数中调整CWinFormsControl对象的大小。在对话框类的源文件中,添加以下代码:

void CMyDialog::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);

    // 调整控件大小
    if (m_myWinFormsControl.GetSafeHwnd())
    {
        CRect rect;
        GetDlgItem(IDC_WINFORMS_CONTROL)->GetWindowRect(&rect);
        ScreenToClient(&rect);
        m_myWinFormsControl.MoveWindow(&rect);
    }
}

这样就完成了在MFC对话框中嵌入一个C# WinForm窗口的操作。在运行程序时,你应该能够看到C# WinForm窗口被嵌入到了MFC对话框中,并且可以在MFC应用程序中与其交互。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

引用ChatGPT部分内容参考:
以下是将C# WinForm嵌入MFC对话框的示例代码:
在MFC的对话框资源中添加一个需要使用的ActiveX控件,并将其命名为“axWinForm”。
在你的MFC应用程序的头文件中包含用于嵌入C# WinForm的类:

#import "mscorlib.tlb" raw_interfaces_only, raw_native_types, no_namespace
#import "System.Windows.Forms.tlb" raw_interfaces_only, raw_native_types, no_namespace named_guids

创建一个用于管理C# WinForm窗口的C++封装类:

class CWinForm {
public:
  CWinForm(void);
  virtual ~CWinForm(void);

  BOOL Create(CWnd* pParentWnd, RECT rc);
  LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);

  void Show(void);
  void Hide(void);
  HWND GetSafeHwnd(void) const;

protected:
  HWND m_hWnd;
  CComPtr<System::Windows::Forms::Form> m_pForm;
  CComPtr<System::Windows::Forms::Control> m_pHost;
};

后续操作都可以在CWinForm类中进行。
在CWinForm类的实现文件中添加以下代码:

CWinForm::CWinForm(void) : m_hWnd(NULL)
{
    CoInitialize(NULL);
}

CWinForm::~CWinForm(void)
{
    if (m_pForm != NULL) {
        m_pForm->Close();
        m_pForm.Release();
    }
    CoUninitialize();
}

BOOL CWinForm::Create(CWnd* pParentWnd, RECT rc)
{
    m_pHost = GetDlgItem(pParentWnd->GetSafeHwnd(), IDC_WINFORM);

    HRESULT hr = ::CoCreateInstance(CLSID_CorRuntimeHost, NULL,
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pRuntimeHost));
    if (FAILED(hr)) {
        return FALSE;
    }

    m_pRuntimeHost->Start();

    IUnknownPtr ptr;
    hr = m_pRuntimeHost->GetDefaultDomain(&ptr);
    if (FAILED(hr)) {
        return FALSE;
    }

    CComBSTR bstrAssembly("MyWinForm");
    CComBSTR bstrTypeName("MyWinForm.Form1");
    CComPtr<IDispatch> pDispatch;
    hr = ptr->CreateInstance(bstrAssembly, bstrTypeName, &pDispatch);

    if (FAILED(hr)) {
        return FALSE;
    }

    hr = pDispatch.QueryInterface(&m_pForm);
    if (FAILED(hr)) {
        return FALSE;
    }

    m_pHost->GetControlUnknown()->QueryInterface(IID_PPV_ARGS(&m_pOleClientSite));
    hr = m_pForm->put_Visible(VARIANT_TRUE);
    if (FAILED(hr)) {
        return FALSE;
    }

    hr = m_pForm->QueryInterface(&m_pOleObject);
    if (FAILED(hr)) {
        return FALSE;
    }

    m_pOleObject->SetClientSite(m_pOleClientSite);

    HWND hWndHost;
    m_pHost->GetControlWindow(&hWndHost);

    int nLeft = rc.left;
    int nTop = rc.top;
    int nWidth = rc.right - rc.left;
    int nHeight = rc.bottom - rc.top;

    ::MoveWindow(hWndHost, nLeft, nTop, nWidth, nHeight, TRUE);

    return TRUE;
}

LRESULT CWinForm::SendMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
    CComQIPtr<IOleInPlaceActiveObject, &IID_IOleInPlaceActiveObject> ipActive(m_pOleInPlaceObject);
    if (ipActive) {
        ipActive->TranslateAccelerator(&m_msg);
    }

    LRESULT lResult = 0;
    BOOL bHandled = FALSE;

    if (m_pForm) {
        m_pForm->ProcessKeyPreview(&m_msg, &bHandled);

        if (!bHandled) {
            lResult = CWnd::DefWindowProc(message, wParam, lParam);
        }
    }

    return lResult;
}

void CWinForm::Show(void)
{
    m_pForm->Show();
}

void CWinForm::Hide(void)
{
    m_pForm->Hide();
}

HWND CWinForm::GetSafeHwnd(void) const
{
    if (m_pForm) {
        CComPtr<IWin32Window> pWin32Window;
        m_pForm->QueryInterface(&pWin32Window);

        HWND hWnd;
        pWin32Window->get_Handle((HWND*)hWnd);

        return hWnd;
    }

    return nullptr;
}

在MFC对话框的OnInitDialog()中添加以下代码:

BOOL CMyDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    RECT rc;
    GetDlgItem(IDC_WINFORM)->GetWindowRect(&rc);
    ScreenToClient(&rc);

    m_winform.Create(this, rc);

    return TRUE;
}

最后添加以下代码以在需要时调用WinForm窗口的方法:

m_winform.SendMessage(WM_KEYUP, VK_SPACE, 0);

请根据实际需要进行更改和修改。

  • 这有个类似的问题, 你可以参考下: https://ask.csdn.net/questions/906934
  • 这篇博客也不错, 你可以看下C# WinForm界面设计教程(C# Windows窗体应用程序)
  • 除此之外, 这篇博客: C#Winform中控件的布局思想中的 布局 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • AutoScaleMode:当屏幕分辨率或字体发生改变时,窗体和控件是如何发生变化的。
    - None : 禁用自动缩放。(默认时)
    - Font :根据类使用的字体(通常为系统字体)的维度控制缩放。如果希望控件或窗体根据操作系统中字体的大小进行拉伸或缩小,则按 Font 缩放十分有用,如果控件或窗体的绝对大小无关紧要,则应使用这种方式进行缩放。比如:一个按钮的文字,改变了系统的字体大小,按钮也随着变大到能完整显示文字。例子:新建一个winform,字体为 ‘宋体 9pt’,上面还有一个button,用来参考,然后,先改变winform的字体大小,就改为‘宋体 16pt’吧。这时候,连按钮都变大了。
    - Dpi : 根据显示分辨率控制缩放。常用分辨率为 96 和 120 DPI。如果要相对于屏幕确定控件或窗体的大小,则按 Dpi 缩放十分有用。例如,对于显示图表或其他图形的控件,可能希望使用每英寸点数 (DPI) 缩放,以便该控件始终占据一定百分比的屏幕
    - Inherit : 根据类的父类的缩放模式控制缩放。如果不存在父类,则禁用自动缩放。
    AutoScroll:只是当控件内容大于它的可见区域时是否自动显示滚动条。
    - TRUE—是
    - FALSE—否
    AutoSize:指定控件是否自动调整自身的大小以适应其内容的大小。
    - TRUE—是
    - FALSE—否
    AutoSizeMode:指定用户界面元素自动调整自身大小的模式。
    - GrowOnly—生成的窗体可以用鼠标调节大小
    - GrowAndShrik—生成的窗体不可以用鼠标调节大小
    Anchor:定义某个控件绑定到的容器的边缘,当控件锚定到某个边缘时,与指定边缘最接近的控件边缘与指定边缘之间的距离将保持不变。
    -Top——表示控件中与父窗体(或父控件)相关的顶部应该保持固定(Anchor相当于是将控件钉在了父控件上,不管父控件怎么放大缩小,它与父控件边缘距离都将保持绝度距离不变)
    - Bottom——表示控件中与父窗体(或父控件)相关的底边应该保持固定
    - Left——表示控件中与父窗体(或父控件)相关的左边缘应该保持固定
    - Right——表示控件中与父窗体(或父控件)相关的右边缘应该保持固定
    - None——漂浮
    Dock:用于指定控件应停放在窗口的边框上,用户重新设置了窗口的大小,这个控件将继续停放在窗口的边框上,例如,如果指定控件停放在窗口的底部边界上,则无论窗口的大小改变,这个控件都将改变大小,或移动其位置,确保总是位于屏幕的底部。虽然Anchor属性也可以实现这一点,但是dock属性使得你能够在父窗体中让子窗体可以在上方(或旁边)互相“堆叠”。
    - Top——迫使控件位于父窗体(或控件)的顶部。如果有同一个父窗体的其它子控件也被设置为停驻在顶部的话,那么控件将在彼此上方相互堆叠。
    - Bottom——迫使控件位于父窗体(或控件)的底部。如果有同一个父窗体的其它子控件也被设置为停驻在底部的话,那么控件将在彼此上方相互堆叠。
    - Left——迫使控件位于父窗体(或控件)的左边。如果有同一个父窗体的其它子控件也被设置为停驻在左边的话,那么控件将在彼此旁边相互堆叠。
    - Right——迫使控件位于父窗体(或控件)的右边。如果有同一个父窗体的其它子控件也被设置为停驻在右边的话,那么控件将在彼此旁边相互堆叠。
    - Fill——迫使控件位于父窗体(或控件)的上方。如果有同一个父窗体的其它子控件也被设置为停驻在上方的话,那么控件将在彼此上方相互堆叠。
    - None——表示控件将会正常运转。

以下内容引用CHATGPT、有用望采纳:

在MFC对话框中嵌入C# WinForm窗口,可以使用ActiveX控件来实现。

首先,在C# WinForm项目中,将窗口作为ActiveX控件导出。

  1. 在项目中添加COM组件支持,选择“将程序集添加到COM组件列表”。
  2. 在“程序集信息”中,勾选“使程序集可用于COM”。
  3. 在“控件属性”中,勾选“使控件可用于COM”。
  4. 在“控件属性”中,设置“控件标识符”。

然后,在MFC项目中,添加ActiveX控件。

  1. 在对话框中添加ActiveX控件。
  2. 在“属性”中,设置“控件ID”和“控件类型”。
  3. 在“属性”中,设置“控件名”和“控件标识符”。

最后,在MFC项目中,使用ActiveX控件。

  1. 在对话框类中,添加成员变量,类型为CWnd或者COleControl。
  2. 在OnInitDialog()函数中,使用Create方法创建ActiveX控件。
  3. 在OnSize()函数中,使用MoveWindow方法调整ActiveX控件的大小和位置。

示例代码:

C# WinForm项目中,导出ActiveX控件:

namespace WinFormControlLibrary
{
    [ComVisible(true)]
    [Guid("D2A8D2A1-6E1F-4A0C-9CDD-4B0B3C9B4E4B")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(IWinFormControl))]
    public partial class WinFormControl : UserControl, IWinFormControl
    {
        public WinFormControl()
        {
            InitializeComponent();
        }

        public string GetText()
        {
            return textBox1.Text;
        }

        public void SetText(string text)
        {
            textBox1.Text = text;
        }

        #region IWinFormControl 成员

        string IWinFormControl.GetText()
        {
            return GetText();
        }

        void IWinFormControl.SetText(string text)
        {
            SetText(text);
        }

        #endregion
    }

    [ComVisible(true)]
    [Guid("D1D0C2C0-12D9-4F58-BD5B-5A657F2D9B3F")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IWinFormControl
    {
        string GetText();
        void SetText(string text);
    }
}

MFC项目中,使用ActiveX控件:

// 在对话框类中添加成员变量
CWnd m_wndWinFormControl;

// 在OnInitDialog()函数中,创建ActiveX控件
m_wndWinFormControl.Create(_T("WinFormControlLibrary.WinFormControl.1"), NULL, WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, IDC_WINFORMCONTROL);

// 在OnSize()函数中,调整ActiveX控件的大小和位置
CRect rect;
GetDlgItem(IDC_WINFORMCONTROL)->GetWindowRect(&rect);
ScreenToClient(&rect);
m_wndWinFormControl.MoveWindow(rect);

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
在MFC对话框中嵌入C# Winform窗口可以使用MFC中的CStatic控件。下面是详细步骤:

  1. 在MFC对话框上添加一个CStatic控件,并为其设置唯一的ID,例如 IDC_WINFORM。

  2. 在MFC中使用C++/CLI创建一个中间层,并在其中创建C# Winform控件。这里我假设您已经熟悉了C++/CLI和C# Winform开发,并已经有了可添加到控件中的C# Winform窗体。

  3. 将中间层窗体声明为MFC中的CStatic控件的变量。在此处定义一个名为m_winform的CStatic变量。

CStatic m_winform;
  1. 在初始化对话框函数OnInitDialog()中,使用如下代码将中间层窗口绑定到m_winform控件上。
//在C++/CLI中创建一个名为"WinformWrapper"的中间层窗体
m_winform.Create("", WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, IDC_WINFORM);
HWND hWinformWrapper = (HWND)m_winform.GetSafeHwnd();

//将中间层窗体绑定到m_winform上
WinformWrapper^ pWinformDlg = gcnew WinformWrapper();
pWinformDlg->CreateControl();
IntPtr hWinform = pWinformDlg->Handle;
::SetParent((HWND)hWinform.ToPointer(), hWinformWrapper);

以上代码中,WinformWrapper是在C++/CLI中定义的中间层,其包含了您所编写的C# Winform控件代码。使用Create()方法创建一个可见的m_winform控件,并将其绑定到C++/CLI中间层上的窗口。最后使用SetParent()方法将中间层窗口绑定到CStatic控件上。

  1. 此时您的C# Winform窗口应该已经嵌入到MFC对话框中了。您可以通过调整m_winform控件的位置和大小来调整嵌入的位置和大小。
CRect rect;
m_winform.GetClientRect(&rect);
m_winform.MoveWindow(20, 20, rect.Width(), rect.Height());

完整的示例代码如下:

MFC对话框的头文件:

#include "WinformWrapper.h"
#include <vcclr.h> //需要包含vcclr.h头文件

//定义一个名为m_winform的CStatic控件
CStatic m_winform;

MFC对话框的实现文件:

BOOL CMFCDlg::OnInitDialog()
{
  //省略其他初始化代码

  //在C++/CLI中创建一个名为"WinformWrapper"的中间层窗体
  m_winform.Create("", WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, IDC_WINFORM);
  HWND hWinformWrapper = (HWND)m_winform.GetSafeHwnd();

  //将中间层窗体绑定到m_winform上
  WinformWrapper^ pWinformDlg = gcnew WinformWrapper();
  pWinformDlg->CreateControl();
  IntPtr hWinform = pWinformDlg->Handle;
  ::SetParent((HWND)hWinform.ToPointer(), hWinformWrapper);

  //调整m_winform控件的位置和大小
  CRect rect;
  m_winform.GetClientRect(&rect);
  m_winform.MoveWindow(20, 20, rect.Width(), rect.Height());

  return TRUE;
}

中间层头文件WinformWrapper.h:

#pragma once
#include <Windows.h>

using namespace System::Windows::Forms;

//定义一个名为WinformWrapper的中间层窗体
public ref class WinformWrapper : public Form
{
public:
  //使用CreateControl方法创建控件,定义为public类型
  void CreateControl()
  {
    this->SuspendLayout();
    this->TopLevel = false;
    this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::None;
    this->Dock = DockStyle::Fill;
    this->ResumeLayout(false);
  }
};

请注意,在Windows Forms中,我们不能显式地调用CreateWindowEx或CreateDialog来创建控件和窗口。相反,我们可以使用CreateControl方法创建控件,并在其中定义其窗口句柄。在中间层中,我们需要使用System::Windows::Forms::Control的SuspendLayout和ResumeLayout方法来禁止和重新启用屏幕布局操作。
如果我的回答解决了您的问题,请采纳!