在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();這樣創建的窗口就不會因爲導出函數的結束而析構掉。

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