DLL(MFC)通过Window消息向C#程序传递数据

本文介绍如何在C#程序中使用MFC开发的DLL,并实现通过窗口消息传递数据的具体方法。

这是我在用C#开发IOServer遇到的一个问题,该程序需要用到原先用MFC开发的DLL,最大问题是该dll运行过程中的一些信息,通过window消息向指定的hwnd(窗体句柄)发送数据。数据的指针放在WParam参数里,LParam参数是数据的类型信息。

     C#提供  m.GetLParam()函数,可惜我的数据放在WParam参数里(这个还不能修改,否则原有程序就无法运行了,修改的代价太高),所以这个函数不能用。

    下面经过多次测试,终于获取数据成功。

   MFC DLL中的相关代码:

   


  1. TCHAR cMessage[255];  
  2.   SYSTEMTIME stime;  
  3.      GetLocalTime(&stime);  
  4.    swprintf(cMessage,_T("%04d-%02d-%02d %02d:%02d:%02d [%-16s #%03d] - %s "),stime.wYear,stime.wMonth,stime.wDay,stime.wHour,stime.wMinute,stime.wSecond,strSource,lngNO,strMessage);  
  5.         if (G_IOMRun.lngMsgFlag==0)  
  6.   {  
  7.       SendMessage(G_IOMRun.Hwnd, WM_USER+7722,(long)cMessage,lngType); //  
  8.   }  

  在C#中需要重载窗体的消息处理函数,相关代码如下:

      [DllImport("kernel32", EntryPoint = "CopyMemory")]
       


  1. public static extern void CopyMemory(StringBuilder Destination,IntPtr Source,int Length);  
  2.         /// <summary>  
  3.         /// 重载窗口函数  
  4.         /// </summary>  
  5.         /// <param name="m"></param>  
  6.         protected override void WndProc(ref Message m)  
  7.         {  
  8.             //---------------------  
  9.             if(m.Msg == 0x0400 + 7722)  
  10.             {                
  11.                StringBuilder strData = new StringBuilder(255);  
  12.                CopyMemory(strData, m.WParam, 255);  
  13.                ShowInfo((int)m.LParam,strData.ToString());  
  14.             }  
  15.             //---------------------  
  16.             base.WndProc(ref m);  
  17.         }  

注意:CopyMemory函数的声明需要自己修改(原声明如下),一定要去掉“ref” 关键字,否则会获取不正确。

[DllImport("kernel32", EntryPoint="CopyMemory")]
 


  1. public static extern void CopyMemory (  
  2.         ref int Destination,  
  3.         ref int Source,  
  4.         int Length  














本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/323484,如需转载请自行联系原作者
<think>我们正在解决用户的问题:如何在MFC项目中调用由QT编写的DLL,并提供示例。根据引用[1][2][3]提供的示例,我们可以知道:1.可以将Qt窗口和控件封装在DLL中,然后由MFC程序调用。2.需要解决嵌入Qt窗口到MFC窗口,并实现消息传递和事件循环的问题。然而,引用[3]提到了一些问题:嵌入的Qt窗口不能跟随MFC窗口移动,以及数据交互问题。因此,我们需要一个更完善的示例。引用[4][5]则提供了QT编写DLL供外部程序(包括VC/C#/C)调用的示例,其中包含了事件(回调函数)的处理。综合以上,我们将分步骤说明如何在MFC调用QT编写的DLL,并提供一个简单的示例(不涉及复杂界面,以函数调用和事件处理为例)。步骤:1.使用Qt创建一个DLL项目,导出函数和类供外部调用。2.在MFC应用程序中加载该DLL调用其函数。3.处理事件循环和窗口嵌入问题(如果需要嵌入Qt窗口)。由于用户的问题集中在方法上,我们重点说明步骤和关键代码。注意:如果涉及窗口嵌入,需要解决事件循环和窗口父子关系问题。我们可以参考qtwinmigrate(一个用于在MFC中嵌入Qt窗口的工具)的方法,但引用[3]提到使用qtwinmigrate的示例存在窗口不跟随移动的问题,因此我们需要确保正确设置父窗口。下面我们分两种情况说明:情况一:只调用DLL中的函数(不涉及界面)情况二:调用DLL中的Qt窗口并嵌入到MFC窗口中由于用户明确提到“MFC调用QT编写的DLL方法示例”,我们两种都提供。情况一:非界面调用(函数和事件)参考引用[5]的C#示例,我们可以为MFC(C++)提供一个类似的示例。情况二:界面调用(嵌入窗口)参考引用[1][2][3],我们需要在DLL中封装一个Qt窗口,并在MFC中创建父窗口来嵌入。我们先从情况一开始,因为比较简单。情况一示例:QT编写DLL(非界面)1.创建QtDLL项目-使用QtCreator创建一个新的库项目,选择“C++库”,类型为“共享库”。-在项目中选择适当的Qt版本(比如MinGW或MSVC,建议与MFC项目使用的编译器一致,如MSVC)。-定义导出的函数(使用extern"C"和__declspec(dllexport))以方便C++调用。示例DLL代码(Qt部分):假设我们导出一个函数用于计算加法,并支持设置回调函数(事件)。qtdll_global.h(由Qt创建项目时自动生成,我们修改它):```cpp#ifndefQTDLL_GLOBAL_H#defineQTDLL_GLOBAL_H#include<QtCore/qglobal.h>#ifdefined(QTDLL_LIBRARY)#defineQTDLL_EXPORTQ_DECL_EXPORT#else#defineQTDLL_EXPORTQ_DECL_IMPORT#endif//为了C语言调用,使用extern"C"#ifdef__cplusplusextern"C"{#endif//导出函数声明QTDLL_EXPORTintadd(inti);typedefvoid(*CallbackFun)(int);//回调函数类型QTDLL_EXPORTvoidSetFunCallBack(CallbackFunpCallbackFun);#ifdef__cplusplus}#endif#endif//QTDLL_GLOBAL_H```在DLL的实现文件(如qtdll.cpp)中:```cpp#include"qtdll_global.h"#include<QDebug>//回调函数指针staticCallbackFuns_pCallbackFun=nullptr;QTDLL_EXPORTintadd(inti){intresult=i+100;//如果有回调,调用回调if(s_pCallbackFun){s_pCallbackFun(result);}returnresult;}QTDLL_EXPORTvoidSetFunCallBack(CallbackFunpCallbackFun){s_pCallbackFun=pCallbackFun;}```2.编译生成DLL(如qtdll.dll)和导入库(qtdll.lib)3.在MFC项目中调用:-将生成的dll和lib文件放到MFC项目的合适位置(如项目目录下)。-在MFC代码中包含头文件(qtdll_global.h,但注意这个头文件是Qt生成的,可能包含Qt头文件,如果MFC项目不想引入Qt,可以单独写一个纯C的头文件)。-另一种做法:在MFC项目中,我们不需要包含Qt的头文件,而是使用函数指针动态加载,或者单独写一个不含Qt的头文件。为了简单,我们采用动态加载DLL的方式(这样就不需要Qt的头文件了)。MFC示例代码(动态加载):```cpp//定义函数指针类型typedefint(*AddFunc)(int);typedefvoid(*SetCallbackFunc)(void(*)(int));//回调函数voidMyCallback(inti){AfxMessageBox(CString(_T("回调值:"))+CString(MAKEINTRESOURCE(i)));}voidCMyMFCDlg::OnButtonCallQtDll(){HINSTANCEhDLL=LoadLibrary(_T("qtdll.dll"));if(hDLL!=NULL){AddFuncaddFunc=(AddFunc)GetProcAddress(hDLL,"add");SetCallbackFuncsetCallback=(SetCallbackFunc)GetProcAddress(hDLL,"SetFunCallBack");if(addFunc&&setCallback){//设置回调setCallback(MyCallback);//调用add函数intresult=addFunc(5);CStringstr;str.Format(_T("计算结果:%d"),result);AfxMessageBox(str);}else{AfxMessageBox(_T("函数加载失败"));}FreeLibrary(hDLL);}else{AfxMessageBox(_T("DLL加载失败"));}}```情况二:嵌入Qt窗口到MFC窗口根据引用[1][2][3],我们需要在DLL中封装一个Qt窗口,并导出创建窗口的函数。同时,我们需要解决窗口嵌入和事件循环问题。这里,我们参考引用[4]提到的qtwinmigrate,使用其提供的qmfcapp.h和qmfcapp.cpp来初始化Qt事件循环。步骤:1.在QtDLL项目中,使用qtwinmigrate(需要先下载并编译,然后将头文件和源文件加入项目)。2.在DLL中导出一个函数,用于创建Qt窗口并设置父窗口(HWND)。由于qtwinmigrate的详细使用较为复杂,我们只给出关键步骤:在QtDLL项目中:-将qtwinmigrate的src目录下的qmfcapp.h、qmfcapp.cpp、qwinhost.h、qwinhost.cpp等文件加入项目。-在DLL的导出函数中,初始化Qt应用程序对象(使用QMfcApp),然后创建Qt窗口并设置父窗口。示例DLL代码(界面):```cpp#include"qtdll_global.h"#include<QWidget>#include<QLabel>#include<QVBoxLayout>#include"qmfcapp.h"//导出一个创建窗口的函数QTDLL_EXPORTvoid*createQtWindow(HWNDparentHandle){//确保Qt应用程序已经初始化(使用QMfcApp)staticboolbQtInitialized=false;if(!bQtInitialized){staticintargc=0;staticchar**argv=NULL;QMfcApp::instance()->initInstance();//初始化bQtInitialized=true;}//将父窗口的HWND转换为QWidgetQWidget*parentWidget=QWidget::find((WId)parentHandle);if(!parentWidget){parentWidget=newQWinHost(parentHandle);parentWidget->setObjectName("MFCParentContainer");}//创建Qt窗口QWidget*childWidget=newQWidget(parentWidget);childWidget->setWindowTitle("QtinMFC");QLabel*label=newQLabel("HellofromQtDLL!",childWidget);QVBoxLayout*layout=newQVBoxLayout(childWidget);layout->addWidget(label);childWidget->setLayout(layout);childWidget->resize(200,100);childWidget->show();return(void*)childWidget->winId();//返回窗口句柄,如果需要}```在MFC中,我们创建一个窗口(比如一个静态控件)作为容器,然后将这个容器的句柄传递给DLLMFC示例代码:```cpp//定义函数指针typedefvoid*(*CreateQtWindowFunc)(HWND);voidCMyMFCDlg::OnButtonCreateQtWindow(){//假设我们有一个静态控件IDC_STATIC_CONTAINERCWnd*pContainer=GetDlgItem(IDC_STATIC_CONTAINER);if(pContainer){HINSTANCEhDLL=LoadLibrary(_T("qtdll.dll"));if(hDLL!=NULL){CreateQtWindowFunccreateFunc=(CreateQtWindowFunc)GetProcAddress(hDLL,"createQtWindow");if(createFunc){void*hQtWnd=createFunc(pContainer->GetSafeHwnd());//可以保存hQtWnd,以便后续操作}//注意:不能立即FreeLibrary,因为窗口还在使用中。应该在不需要窗口时再卸载。}}}```注意:在MFC中,当对话框关闭时,需要确保先销毁Qt窗口再卸载DLL。另外,事件循环需要由QMfcApp处理,在MFC消息循环中需要调用QMfcApp的相应方法(如QMfcApp::runEventLoop)来处理Qt事件。但是,qtwinmigrate的QMfcApp会接管MFC消息循环,所以我们需要在MFC应用程序初始化时进行设置。由于涉及内容较多,这里只提供一个基本思路。具体实现可参考qtwinmigrate的示例。总结:1.对于非界面调用,我们只需导出C函数,并在MFC中动态加载调用。2.对于界面调用,我们需要使用qtwinmigrate等工具来帮助嵌入Qt窗口,并正确处理事件循环。用户可以根据需要选择合适的方式。注意:以上代码仅为示例,实际使用时需要根据项目需求调整。相关问题:1.在MFC调用QtDLL时,如何处理事件循环以避免界面无响应?2.如何实现MFC程序与QtDLL中的窗口之间的数据交互?3.在嵌入Qt窗口到MFC窗口时,如何解决窗口不跟随移动的问题?</think>### 在MFC项目中调用QT编写的DLL方法详解 #### 核心原理 在MFC调用QT编写的DLL需要解决两个关键问题: 1. **窗口嵌入**:将Qt窗口嵌入MFC容器窗口(如`CStatic`控件) 2. **事件循环**:整合Qt事件循环与MFC消息循环 3. **数据交互**:通过接口实现MFC与Qt的数据传递 #### 完整实现步骤(含代码示例) --- ##### 1. QT DLL项目设置 (Qt Creator) ```cpp // QTDLL.pro QT += core gui widgets TARGET = QtDLL TEMPLATE = lib CONFIG += c++11 dll // qtdll_global.h #ifdef QTDLL_LIBRARY #define QTDLL_EXPORT Q_DECL_EXPORT #else #define QTDLL_EXPORT Q_DECL_IMPORT #endif // qt_window.h #include <QWidget> class QTDLL_EXPORT QtEmbeddedWindow : public QWidget { Q_OBJECT public: explicit QtEmbeddedWindow(QWidget* parent = nullptr); signals: void dataUpdated(const QString& data); // 数据更新信号 }; ``` --- ##### 2. MFC调用端实现 (Visual Studio) ```cpp // MFC对话框头文件 #include <Windows.h> #pragma comment(lib, "QtDLL.lib") class CMyDialog : public CDialogEx { public: // 声明DLL函数 typedef void* (*CreateQtWindowFunc)(HWND, int, int, int, int); typedef void (*UpdateDataFunc)(const char*); HINSTANCE m_hDll; CreateQtWindowFunc m_pCreateQtWindow; UpdateDataFunc m_pUpdateData; }; ``` ```cpp // 初始化DLL void CMyDialog::OnInitDialog() { CDialogEx::OnInitDialog(); m_hDll = LoadLibrary(_T("QtDLL.dll")); if (m_hDll) { m_pCreateQtWindow = (CreateQtWindowFunc)GetProcAddress(m_hDll, "CreateQtWindow"); m_pUpdateData = (UpdateDataFunc)GetProcAddress(m_hDll, "UpdateData"); // 创建Qt窗口容器 CRect rect; GetDlgItem(IDC_QT_CONTAINER)->GetWindowRect(&rect); ScreenToClient(&rect); // 创建Qt窗口 HWND hQtWnd = (HWND)m_pCreateQtWindow( GetSafeHwnd(), rect.left, rect.top, rect.Width(), rect.Height() ); } } // 数据传递示例 void CMyDialog::OnBnClickedSendData() { CString strData = _T("Hello from MFC"); if (m_pUpdateData) { m_pUpdateData(CT2A(strData)); } } // 释放DLL void CMyDialog::OnDestroy() { if (m_hDll) FreeLibrary(m_hDll); CDialogEx::OnDestroy(); } ``` --- ##### 3. 关键问题解决方案 1. **窗口跟随问题** 在Qt窗口类中重写事件处理: ```cpp // qt_window.cpp void QtEmbeddedWindow::resizeEvent(QResizeEvent* event) { if (HWND hParent = ::GetParent((HWND)winId())) { RECT rc; ::GetClientRect(hParent, &rc); setGeometry(0, 0, rc.right, rc.bottom); } } ``` 2. **数据交互机制** ```cpp // DLL导出函数 extern "C" QTDLL_EXPORT void UpdateData(const char* data) { emit qApp->findChild<QtEmbeddedWindow*>()->dataUpdated(data); } // MFC接收Qt数据 void __stdcall DataCallback(const char* data) { AfxMessageBox(CString(data)); } ``` 3. **事件循环整合** 在DLL初始化代码中添加: ```cpp // dllmain.cpp #include <QMfcApp> BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) { if (reason == DLL_PROCESS_ATTACH) { static int argc = 0; static char **argv = { NULL }; static QMfcApp app(argc, argv); } return TRUE; } ``` --- #### 完整项目参考 1. [QT-MFC混合编程示例](https://gitcode.com/open-source-toolkit/6eb91) 演示DLL封装Qt窗口和MFC/Qt调用的完整实现[^1] 2. [事件交互解决方案](https://gitcode.com/open-source-toolkit/1f246) 提供Qt/MFC事件回调机制的实现方法[^2] > **注意**:需确保MFC和QT项目使用**相同编译器**(如MSVC 2019)和**相同位宽**(32/64位),否则会导致兼容性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值