windows下如何使用QT編寫dll程式
轉自:http://blog.csdn.net/normallife/article/details/5397980
Windows 下如何使用 QT 編寫 dll 程式
因為 QT 必須有呼叫 QApplication 的 exec 方法,這樣才能產生訊息迴圈, QT 的程式才可以執行。所以說如果我們使用了 QT 編寫了 dll 程式,在普通的 windows 程式中是不能呼叫的。在呼叫的時候會出現錯誤。當然 QT 提供瞭解決方法:那就是 QTWinmigrate
這裡是 QT 官方網站對 QTWinmigrate 的介紹:
http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Windows/qtwinmigrate
下面我來介紹一下使用 QTWinmigrate 來編寫 dll 的方法。
首先,我們要重寫 DllMain 函式:
- #include <qtwinmigrate/qmfcapp.h>
- #include <qtwinmigrate/qwinwidget.h>
- #include <qmessagebox.h>
- #include <windows.h>
- BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved )
- {
- static bool ownApplication = FALSE;
- if ( dwReason == DLL_PROCESS_ATTACH )
- ownApplication = QMfcApp::pluginInstance( hInstance );
- if ( dwReason == DLL_PROCESS_DETACH && ownApplication )
- delete qApp;
- return TRUE;
- }
- #include <qtwinmigrate/qmfcapp.h>
- #include <qtwinmigrate/qwinwidget.h>
- #include <qmessagebox.h>
- #include <windows.h>
- BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved )
- {
- static bool ownApplication = FALSE;
- if ( dwReason == DLL_PROCESS_ATTACH )
- ownApplication = QMfcApp::pluginInstance( hInstance );
- if ( dwReason == DLL_PROCESS_DETACH && ownApplication )
- delete qApp;
- return TRUE;
- }
大家都知道 DllMain 函式是 windows 動態庫的入口函式,如果在 dll 中使用了 QT 的 ui 介面前,全域性的 QApplication 必須首先要建立,並且應用程式必須建立 EventLoop 。
進入到 QmfcApp::pluginInstance 方法中去,
- bool QMfcApp::pluginInstance(Qt:: HANDLE plugin)
- {
- if (qApp)
- return FALSE;
- QT_WA({
- hhook = SetWindowsHookExW(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
- }, {
- hhook = SetWindowsHookExA(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
- });
- int argc = 0;
- (void ) new QApplication(argc, 0);
- if (plugin) {
- char filename[256];
- if (GetModuleFileNameA(( HINSTANCE )plugin, filename, 255))
- LoadLibraryA(filename);
- }
- return TRUE;
- }
- bool QMfcApp::pluginInstance(Qt::HANDLE plugin)
- {
- if (qApp)
- return FALSE;
- QT_WA({
- hhook = SetWindowsHookExW(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
- }, {
- hhook = SetWindowsHookExA(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
- });
- int argc = 0;
- (void)new QApplication(argc, 0);
- if (plugin) {
- char filename[256];
- if (GetModuleFileNameA((HINSTANCE)plugin, filename, 255))
- LoadLibraryA(filename);
- }
- return TRUE;
- }
我們可以看到: Qapplication 被建立了出來。 QmfcApp::pluginInstanc 是為了保證程式中存在一個 Qapplication 物件,並且 dll 要把這個 Qapplication 的例項載入到記憶體中。
下面是 dll 中的匯出函式:
- 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) bool showDialog( HWND parent )
- {
- QWinWidget win( parent );
- win.showCentered();
- QMessageBox::about( &win, "About QtMfc", "QtMfc Version 1.0/nCopyright (C) 2003" );
- return TRUE;
- }
dll 中的匯出函式要用 extern "C" 形式, QwinWidget 為 native win32 視窗提供堆疊等等。
這樣還沒有寫完程式。不行你拿這個程式來
qmake -project
qmake
nmake
這樣是無論如何也編譯不過的。
如果你仔細看qtwinmigrate的example的話,你就會注意到:
include(D:/qt4.4.3/qtwinmigrate-2.8-opensource/src/qtwinmigrate.pri)
編譯的時候一定要在*.pro檔案中加上這一句!切記,切記!
參考: http://doc.trolltech.com/solutions/qtwinmigrate/winmigrate-qt-dll-example.html
讀後感:
我發現一個問題啊:從bool QMfcApp::pluginInstance(Qt::HANDLE plugin) 的實現可以知道三件事:
1.Qt注入了鉤子函式,去過濾host application(主程式)的訊息,如果碰到Qt的訊息,就讓Qt add-in(.dll etc)工程去處理。
2.建立了一個QtApplication物件。
3.載入此Qt add-in(.dll etc)。
對於第一件事和第三件事,我不敢苟同Qt的做法。
第一件事,既然注入了鉤子函式,那麼什麼時候free掉(關掉)?如果不free(關掉),那麼鉤子函式就一直存在。大家有可能認為在Qt dll unload/free(解除安裝)的時候去關掉鉤子函式不就行了嗎,可是大家看:
if ( dwReason == DLL_PROCESS_DETACH && ownApplication )
delete qApp;
這裡僅僅delete qApp; 沒有去解除安裝鉤子函式啊。也許你覺得解除安裝鉤子與否無所謂,可是如果連Qt dll都不存在了,而鉤子函式還存在,那麼QtFilterProc去那裡執行,crash也就發生了。
對於第三件事,也許是Qt想到了上面提到的情況,所以就直接loadlibrary Qt add-in(.dll etc),也沒有freelibrary,意思就是讓Qt add-in(.dll etc)一直存在(和host application一樣的生命週期),這樣來避免crash.可是這種做法比較牽強,因為對於add-in(.dll etc)而言,程式設計師當然是想什麼時候unload(解除安裝)就什麼時候unload(解除安裝),可以節省記憶體。
請教高人後的解答:
對於第一件事:
在QMfxApp的解構函式中解除安裝了鉤子函式
QMfcApp::~QMfcApp()
{
if (hhook) {
UnhookWindowsHookEx(hhook);
hhook = 0;
}
#ifdef QTWINMIGRATE_WITHMFC
for (int a = 0; a < mfc_argc; ++a) {
char *arg = mfc_argv[a];
delete[] arg;
}
delete []mfc_argv;
mfc_argc = 0;
mfc_argv = 0;
mfc_app = 0;
#endif
}
對於第三件事,是Qt 的一個bug.
參考文章:
http://blog.csdn.net/tingsking18/archive/2009/12/28/5091580.aspx
過了些天后,自己又想了想覺得還有幾點需要考慮:
- #include <qtwinmigrate/qmfcapp.h>
- #include <qtwinmigrate/qwinwidget.h>
- #include <qmessagebox.h>
- #include <windows.h>
- BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved )
- {
- static bool ownApplication = FALSE;
- if ( dwReason == DLL_PROCESS_ATTACH )
- ownApplication = QMfcApp::pluginInstance( hInstance );
- if ( dwReason == DLL_PROCESS_DETACH && ownApplication )
- delete qApp;
- return TRUE;
- }
上面給的例子有許多對於C++設計原則相悖的地方(紅色標出來的語句)。
首先,QMfcApp::pluginInstance(hInstance);這個語句的實現裡有loadlibrary的操作,而對於DllMain裡的DLL_PROCESS_ATTACH,去呼叫有loadlibrary的語句實在是不好的設計(容易產生loadlibrary死鎖)。
再者,delete qApp;這樣子的呼叫也是不可取的。
相關文章
- 用QT在Windows下編寫dll程式QTWindows
- 編寫第一個Qt程式QT
- 如何在windows下發布QT應用程式(qt專案打包)WindowsQT
- 使用Delphi呼叫C++編寫的DLLC++
- 為Linux 應用程式編寫 DLL(轉)Linux
- 使用Delphi,SDK編寫Windows簡單程式 (轉)Windows
- 如何在Windows下使用make編譯MakefileWindows編譯
- 全方位解讀DLL檔案—編寫DLL
- 如何編寫一個使用Objective-C的下載器程式Object
- 如何使用CMake生成Windows DLL版本控制資訊Windows
- DLL庫的編寫(匯出、匯入)與使用
- Python如何使用tkinter編寫GUI程式PythonGUI
- Qt DLL總結【二】-建立及呼叫QT的 DLLQT
- windows下使用mingw和msvc靜態編譯Qt5.15.xxWindows編譯QT
- C++編寫DLL的方法C++
- Windows下編譯使用AliyunOSSCSDKWindows編譯
- Windows下Qt使用dump定位崩潰位置(1)WindowsQT
- VC在windows下編寫用於序列通訊的程式 (轉)Windows
- Windows下DLL程式設計技術及應用 (轉)Windows程式設計
- Qt之qss檔案編寫QT
- Python呼叫windows下DLL詳解 - ctypes庫的使用PythonWindows
- 如何編寫MapReduce程式碼
- Windows下編譯使用AliyunOSSPHPSDKWindows編譯PHP
- 如何使用 Laravel Collections 類編寫神級程式碼Laravel
- C#呼叫c++編寫的dllC#C++
- mingw 編譯生成的dll 如何在vs中使用編譯
- Qt學習之路(59): 編寫跨平臺的程式薦QT
- 使用QT編寫Opencv2/3的LIB設定QTOpenCV
- Qt/C++編寫的mqtt除錯助手使用說明QTC++MQ除錯
- (轉)Qt之qss檔案編寫QT
- windows核心程式設計--DLL基本Windows程式設計
- 如何編寫健壯的程式
- Windows下使用Sublime text3快速編輯Linux檔案,寫ShellWindowsLinux
- windows上使用clang編譯程式Windows編譯
- Qt for Windows:Qt 5.8.0 MinGW 靜態編譯版本(包含OpenSSL)QTWindows編譯
- linux下QT在windows下執行LinuxQTWindows
- C# Windows Service 服務程式的編寫C#Windows
- 用C語言編寫windows服務程式C語言Windows