windows下如何使用QT编写dll程序
2010-03-19 22:40
931 查看
本文转自 : http://blog.csdn.net/tingsking18/archive/2009/12/08/4967172.aspx
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
函数:
view plain
copy to clipboard
print
?
#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
方法中去,
view plain
copy to clipboard
print
?
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
中的导出函数:
view plain
copy to clipboard
print
?
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;这样子的调用也是不可取的。
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
函数:
view plain
copy to clipboard
?
#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
方法中去,
view plain
copy to clipboard
?
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
中的导出函数:
view plain
copy to clipboard
?
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;这样子的调用也是不可取的。
相关文章推荐
- windows下如何使用QT编写dll程序 .
- Windows下如何使用QT编写dll程序
- windows下如何使用QT编写dll程序
- Windows下如何使用QT编写dll程序
- Windows下如何使用QT编写dll程序
- Windows下如何使用QT编写dll程序
- Windows下如何使用QT编写dll程序
- windows qt 使用c++ posix接口编写多线程程序(真神奇)good
- 用QT在Windows下编写dll程序
- windows qt 使用c++ posix接口编写多线程程序(一)
- 用QT在Windows下编写dll程序
- VS使用QT编写dll程序
- 如何通过putty的ssh在windows上使用linux的Xwindows-GUI程序 zz
- 如何使用java程序实现windows锁屏
- VSTS 编写测试Test技巧:如何使用Deployment Items在测试类中引用文件,和普通Windows项目不一样哦。
- 如何让 Qt 的程序使用 Sleep(主线程没有Sleep函数,但线程可用自带的保护函数Sleep)
- 解决Tslib移植之后自己编写的QT程序不能使用触屏的问题
- 使用OPCDAAuto.dll编写C# OPC采集程序
- 在Windows 7 下使用Visual Studio 2010 编写自动申请管理员权限运行的程序
- 编写Qt Designer自定义控件(一)——如何创建并使用Qt自定义控件