接到任務要做一個既可以在Qt下又可以在VC,C#下使用,且含有界面的dll封裝形式的組件, 糾結了大概四五天的樣子,找遍了整個互聯網,這方面的資料太少了,僅有一兩個被轉載了n多遍的沒有新意的介紹,且實用性不強,本人經過數天摸索成功在VC下調用Qt編譯的帶界面的DLL。
首先強調一下環境:
操作系統: win8
VS 版本: VS2010
Qt 版本: qt-opensource-windows-x86-mingw482_opengl-5.3.0.exe
qtwinmingrate版本: qt-solutions-ov3r1oads-qt-solutions 此版本較爲新,2.8 在Qt5下用不了。
參考:1,http://blog.csdn.net/normallife/article/details/5397980
2, http://www.rebaoxian.com/28649.html
3,http://qimo601.iteye.com/blog/1675575
參考十分有限而且粗略,不適合新手來做,沒有例子,沒有詳細的代碼。且所用Qt版本老舊
我的工作
1 首先安裝好Qt5.3, 這個不用多說。
2 下載下來qt-solutions-ov3r1oads-qt-solutions 解壓後進入D:\qt-solutions-ov3r1oads-qt-solutions\qtwinmigrate\examples\qtdll 目錄,該目錄下面有qtdll.pro工程文件 用 qt5.3打開該文件。
3 測試是否可以進行編譯,上述文件後在Qtcreater 中構建,或者編譯該項目,編譯通過後會彈出下圖所示自定義執行檔對話框,此種情況很正常,因爲是dll 項目無程序入口qt讓指定入口,關閉即可。第一次編譯出現此界面,隨後就不會出了,關閉後找到dll生成目錄我的機子上爲D:\qt-solutions-ov3r1oads-qt-solutions\qtwinmigrate\examples\build-qtdll-Desktop_Qt_5_3_0_MinGW_32bit-Debug\debug 如果成功該目錄下會有我們期待已久的qtdialog.dll。
4 上述步驟順利的話說明你的可以往下進行了。我開始的理解是這個qtdialog.dll 即使我所需要的,將它拷貝出來就可以用了,可實踐證明我想多了。用VS2010建了一個MFC工程進行測試,測試例子很簡單就一個基於對話框的界面上面放一個按鈕,按鈕事件是調用該dll.
HMODULE mod = LoadLibrary( "qtdialog.dll" );
DWORD err= GetLastError();
if ( mod ) { typedef BOOL(*pShowDialog)(HWND parent);
pShowDialog showDialog = (pShowDialog)GetProcAddress( mod, "showDialog" );
if ( showDialog )
showDialog( theApp.m_pMainWnd->m_hWnd );
FreeLibrary( mod );
} else {
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
接下來就是一個痛苦的過程了,
問題1:無論如何也不能加載qtdialog.dll ,mod 的值始終都是0, 工程目錄下明明有該dll文件。
解決辦法: 調用 LoadLibrary();後立馬調用GetLastError()得到錯誤碼,分析錯誤碼。
錯誤碼爲126 意思是無法加載相應模塊。這可怎麼辦呢?後來想想是不是dll依賴的一些qt的庫沒有複製過來導致的,遂使用Depends.exe查看該dll的依賴項,果不其然依賴挺多的後將各個依賴項在qt的安裝目錄下通過搜索找到放到MFC工程目錄下。找到這些後還會提示有依賴項,總之把所有的依賴項添加完畢我一共添加了下圖那麼多可能有些是多餘的。當然這是debug版本下的都帶了個d.因爲這個依賴項的問題搞了整整一天!
問題2:依賴問題解決了也能載入dll了而且mod不爲空,而且能夠得到showDialog()函數的地址 但是一直出這樣的錯誤,太坑爹了,不知道什麼原因呀!!
解決辦法:首先嚐試了各種方法,下載舊版本的VC運行時,修復dll ............總之就差重裝系統了,沒有解決,最後想想是不是這種調用方法有問題?
按照參考2 中的方法試一下。
打開qtdll工程,打開源文件中的main.cpp 備用,然後右鍵單擊qtdll工程添加新文件“qt界面設計師類”繼承與mainwindow 類當然也可以是其他的界面類,
在界面上隨意放置兩個組件,如button,label等
然後將main函數中的下面一段:
//extern "C" __declspec(dllexport) bool showDialog( HWND parent )
//{
// QWinWidget win( parent );
// win.showCentered();
// QMessageBox::about( &win, "About QtMfc", "QtMfc Version 1.0\nCopyright (C) 2003" );
// return TRUE;
//}
換成
extern "C" __declspec(dllexport)int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyJieMian w;
w.show();
return a.exec();
}
重新編譯通過。重新將生成的dll文件拷貝到MFC測試工程中
5 測試成功
將MFC按鈕響應程序改爲下述代碼
void CMFCDLLDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
HMODULE mod = LoadLibrary( "qtdialog.dll" );
DWORD err= GetLastError();
if ( mod ) {
typedef int (*Mymain)(int argc, char *argv[]);
Mymain mmain= (Mymain)GetProcAddress(mod,"main");
char* b="abc";
char**a=&b;
mmain(0,a);
FreeLibrary( mod );
} else {
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
}
按下MFC中的按鈕奇蹟出現了,雖然醜了點但是還是出現了Qt下設計好的界面了。