在MFC中使用Qt生成的DLL

http://doc.qt.digia.com/solutions/4/qtwinmigrate/winmigrate-walkthrough.html(原文地址)

qtwinmigrate-2.8-opensource.zip可以到csdn资源内下载,点此下载 

这个练习是基于MFC生成的程序迁移到Qt的例子,这个程序通过微软Visual Studio的MFC应用程序向导生成。 

入门(Getting Started)

(注:这个例子在文件qtwinmigrate-2.8-opensource\examples\mfc\step1中,而且这例子要用VC6.0或者用Qt Creator才能打开)

先把工程文件 qtmfc1.dsp 导入到VS的工作空间,并且确保这个VS工程可以正常的编译和运行。(在step1中没有找到qtmfc1.dsp,倒是有个qtmfc.dsp)

这个MFC程序有一个使用DLL提供的对话框接口,这个很简接口很简单:DLL导入一个名字是showDialog的C语言风格的函数,这个函数把整个窗口作为父句柄。这个DLL以模态方式显示它的对话框,并且在函数返回后卸载掉。

以下代码是在MFC应用程序的OnAppAbout消息处理函数。(这个消息处理函数就是响应“关于。。。。。”的单击,源代码在step1目录下qtmfc.cpp中)

void WindowsApp::OnAppAbout()                 //这部分的源代码在step1目录下

 {

     HMODULE mod = LoadLibrary("qtdialog.dll" );     

  //这个是测试Qt生成的Dll的部分,先动态载入,再使用导出的函数

     if ( mod )

{

         typedefBOOL(*pShowDialog)(HWND parent);

         pShowDialog showDialog =(pShowDialog)GetProcAddress( mod, "showDialog" );

         if ( showDialog )

             showDialog(theApp.m_pMainWnd->m_hWnd ); 

         FreeLibrary( mod );

     }

else

 {

         CAboutDlg aboutDlg;

         aboutDlg.DoModal();

       }

  }

  如果这个DLL被正确载入并且showDialog()被正确导出,那么导出的函数就会被调用,否则调用显示默认的MFC关于对话框。

插件扩展

(这个工程生成的dll就是上个例子用的那个)

(注:这个例子在文件qtwinmigrate-2.8-opensource\examples\qtdll中,可以用Qt Creator 编译生成dll,也可以添加到vs新建的工程当中去,已经测试过,可以正常使用)

 

示例目录下的qtdll文件下的工程通过QMessageBox类实现了插件接口。为了使用这个类,一个QApplication对象必须在当前进程中存在,而且除了mfc的标准事件派送外,还要有一个Qt的消息循环。

这个DLL也要确保它和其它的基于Qt的DLL能够运行在同一个进程中,甚至进程中可能已经存在一个QApplication对象,并且这个创建QApplication对象的DLL还要继续运行在内在中,防止其它DLL使用内存地址。

上述所列的事情全部被QMFC::pluginInstance()函数解决。这个函数创建一个QApplication对象,并且安装一个能够使Win32标准消息循环和Qt事件循共同工作的消息钩子函数。如果DLL实例作为参数被传递,那么pluginInstance()也会增加这个DLL的使用计数,直到这个进程结束。

 当DLL被加载的时候,这个pluginInstance()也可以用于DllMain入口函数的重载版本。一个静态的变量被用于记录DLL是否和QApplication对象关联。当DLL被卸载后,这个QAplication对象就可以通过全局指针qApp删除了。

     为了使用这个pluginInstance函数和跟它有相关的Qt类,我们需要包含一些头文件。

#include <qmfcapp.h>
 #include <qwinwidget.h>
 
 #include <QtGui/QMessageBox>
 #include <windows.h>
 
//用DllMain()函数就是为了使用hInstance,作为qwinwidget的参数

 BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpvReserved*/
 {
     static bool ownApplication = FALSE; //这部分内容不用更改,使用时直接copy就行
     if ( dwReason == DLL_PROCESS_ATTACH )
         ownApplication = QMfcApp::pluginInstance( hInstance );
     if ( dwReason == DLL_PROCESS_DETACH && ownApplication )
         delete qApp; 
     return TRUE;
 }

然后DLL的接口就通过导出C语言风格的showDialog函数来实现。QWinWidget类可以在这个时候使用,用于存放对话框,并且关联上Qt 对话框。

extern "C" __declspec(dllexport) bool showDialog( HWND parent )       //这个是导出的函数
 {
     
//到这个地方,看到QWinWidget了吧?它的参数就是使用Dll的主程序的句柄
     QWinWidget win( parent );                               
     win.showCentered();
     QMessageBox::about( &win, "About QtMfc", "QtMfc Version 1.0\nCopyright (C) 2003" );

     
//这部分官方代码原文中并没有,是我添加的,已经测试过,可以在vs工程下正常使用 
////////////////////////////////////////////////////////////////
        QMainWindow* mainwin=new QMainWindow();                       
        QLineEdit *edit = new QLineEdit( widget );
        mainwin->setCentralWidget(edit);
        mainwin->show();
////////////////////////////////////////////////////////////////
     win.show();
     qApp->exec();   //有这个就可以把信号和槽添加进来,已经测试过,支持信号和槽
     return TRUE;
 }

(个人总结:我已经测试过qtwinmigrate-2.8-opensource\examples\qtdll目录下的工程可以在Qt Creator上可以生成dll和lib文件,生成的dll在其它vs工程上完全正常使用。所以如果以后要再用Qt开发vs下用的dll,完全可以把这个作为模板,DllMain()内的代码不用动,只是更换掉要导入的函数即可。

完整的代码如下图:



在上面的代码中,左边的qtwinmingrate.pri提供了一个Qt/MFC 迁移框架,里面有qmfcappp、qwinhost、qwinwidget三个类,就像上面说的,QMfcApp:: pluginInstance(hInstance)提供Qt和MFC消息循环共同工作的机制,并接受DllMian()函数传来的句柄,然后使用qwinwidget类接受这个句柄,有了这个父类,其它的小部件,包括各种控件就可以向上放了,当然,也可以支持信号和槽机制。另外,如果加了信号和槽功能后,最好在return TRUE;前面加上一句 qApp->exec();这样创建的窗口就不会因为导出函数的结束而析构掉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章