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 ?
  1. #include <qtwinmigrate/qmfcapp.h>
  2. #include <qtwinmigrate/qwinwidget.h>
  3. #include <qmessagebox.h>
  4. #include <windows.h>
  5. BOOL  WINAPI DllMain(  HINSTANCE  hInstance,  DWORD  dwReason,  LPVOID  lpvReserved )
  6. {
  7. static   bool  ownApplication = FALSE;
  8. if  ( dwReason == DLL_PROCESS_ATTACH )
  9. ownApplication = QMfcApp::pluginInstance( hInstance );
  10. if  ( dwReason == DLL_PROCESS_DETACH && ownApplication )
  11. delete  qApp;
  12. return  TRUE;
  13. }
[cpp] view plaincopyprint?
  1. #include <qtwinmigrate/qmfcapp.h>
  2. #include <qtwinmigrate/qwinwidget.h>
  3. #include <qmessagebox.h>
  4. #include <windows.h>
  5. BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved )
  6. {
  7. static bool ownApplication = FALSE;
  8. if ( dwReason == DLL_PROCESS_ATTACH )
  9. ownApplication = QMfcApp::pluginInstance( hInstance );
  10. if ( dwReason == DLL_PROCESS_DETACH && ownApplication )
  11. delete qApp;
  12. return TRUE;
  13. }

#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 ?
  1. bool  QMfcApp::pluginInstance(Qt:: HANDLE  plugin)
  2. {
  3. if  (qApp)
  4. return  FALSE;
  5. QT_WA({
  6. hhook = SetWindowsHookExW(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
  7. }, {
  8. hhook = SetWindowsHookExA(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
  9. });
  10. int  argc = 0;
  11. (void ) new  QApplication(argc, 0);
  12. if  (plugin) {
  13. char  filename[256];
  14. if  (GetModuleFileNameA(( HINSTANCE )plugin, filename, 255))
  15. LoadLibraryA(filename);
  16. }
  17. return  TRUE;
  18. }
[cpp] view plaincopyprint?
  1. bool QMfcApp::pluginInstance(Qt::HANDLE plugin)
  2. {
  3. if (qApp)
  4. return FALSE;
  5. QT_WA({
  6. hhook = SetWindowsHookExW(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
  7. }, {
  8. hhook = SetWindowsHookExA(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
  9. });
  10. int argc = 0;
  11. (void)new QApplication(argc, 0);
  12. if (plugin) {
  13. char filename[256];
  14. if (GetModuleFileNameA((HINSTANCE)plugin, filename, 255))
  15. LoadLibraryA(filename);
  16. }
  17. return TRUE;
  18. }

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 ?
  1. extern   "C"   __declspec ( dllexport )  bool  showDialog(  HWND  parent )
  2. {
  3. QWinWidget win( parent );
  4. win.showCentered();
  5. QMessageBox::about( &win, "About QtMfc" ,  "QtMfc Version 1.0/nCopyright (C) 2003"  );
  6. return  TRUE;
  7. }
[cpp] view plaincopyprint?
  1. extern "C" __declspec(dllexport) bool showDialog( HWND parent )
  2. {
  3. QWinWidget win( parent );
  4. win.showCentered();
  5. QMessageBox::about( &win, "About QtMfc", "QtMfc Version 1.0/nCopyright (C) 2003" );
  6. return TRUE;
  7. }

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

过了些天后,自己又想了想觉得还有几点需要考虑:

  1. #include <qtwinmigrate/qmfcapp.h>
  2. #include <qtwinmigrate/qwinwidget.h>
  3. #include <qmessagebox.h>
  4. #include <windows.h>
  5. BOOL  WINAPI DllMain(  HINSTANCE  hInstance,  DWORD  dwReason,  LPVOID  lpvReserved )
  6. {
  7. static   bool  ownApplication = FALSE;
  8. if  ( dwReason == DLL_PROCESS_ATTACH )
  9. ownApplication = QMfcApp::pluginInstance( hInstance );
  10. if  ( dwReason == DLL_PROCESS_DETACH && ownApplication )
  11. delete  qApp;
  12. return  TRUE;
  13. }

上面给的例子有许多对于C++设计原则相悖的地方(红色标出来的语句)。

首先,QMfcApp::pluginInstance(hInstance);这个语句的实现里有loadlibrary的操作,而对于DllMain里的DLL_PROCESS_ATTACH,去调用有loadlibrary的语句实在是不好的设计(容易产生loadlibrary死锁)。

再者,delete qApp;这样子的调用也是不可取的。

转载于:https://www.cnblogs.com/zd_ad/archive/2012/10/11/2719684.html

windows下如何使用QT编写dll程序 .相关推荐

  1. Qt编写OpenMP程序--循环测试

    第一篇:https://blog.csdn.net/hats8888/article/details/46378281 最近一个客户需要处理大量股票数据,并跑到数据库里,原来的程序导入数据到数据库需要 ...

  2. Windows下如何使用VScode编写C语言代码及运行

    Windows下如何使用VScode编写C语言代码及scanf的输入运行配置 一.安装VS code及插件 1.VS code官网下载地址 2.VS code插件安装 二.配置gcc环境(MinGW- ...

  3. KETTLE调度第三篇:Windows下调度Dos脚本编写和遇到的一些问题解决

    KETTLE调度第三篇:Windows下调度Dos脚本编写和遇到的一些问题解决 参考文章: (1)KETTLE调度第三篇:Windows下调度Dos脚本编写和遇到的一些问题解决 (2)https:// ...

  4. Windows下查看exe可执行程序或dll动态库所依赖dll动态库的方法

    Windows下查看exe可执行程序或dll动态库所依赖dll动态库的方法 如需转载请标明出处:http://blog.csdn.net/itas109 技术交流:129518033 文章目录 Win ...

  5. qt编译c语言dll,QT编写DLL给外部程序调用,提供VC/C#/C调用示例(含事件)

    最近这阵子,接了个私活,封装一个开发包俗称的SDK给客户调用,查阅了不少人家的SDK,绝大部分用VC编写,并且VC6.0居多,估计也是为了兼容大量的XP用户及IE浏览器,XP自带了VC6.0运行库,因 ...

  6. Linux 下重新编译Windows下生成的Qt工程

    原址:https://blog.csdn.net/Fanpei_moukoy/article/details/21613703 以下内容亲测通过 其实qt才是真正的跨平台,java简直太搞笑了,假跨平 ...

  7. Windows下动态链接之三:DLL Hell !

    不止Linux下关于共享库存在版本兼容性困扰问题,Windows下DLL共享库的使用问题更甚.很多Windows的应用程序在发布release版本时会一次性将所有用到的DLL一起打包形成一个大的安装包 ...

  8. windows下的dos命令快速打开应用程序

    开始菜单中的"运行"是通向程序的快捷途径,输入特定的命令后,即可快速的打开Windows的大部分程序,熟练的运用它,将给我们的操作带来诸多便捷. winver 检查Windows版 ...

  9. Ubuntu下使用AMD APP编写OpenCL程序

    对于Ubuntu或其近亲(Lubuntu.Kubuntu.Mint等)编写OpenCL程序也不会太难.由于本例用的是AMD APP SDK,因此需要AMD的GPU以及相关驱动.首先,去AMD官网下载G ...

最新文章

  1. 基于YOLOv5的智慧工地安全帽检测(1)
  2. 2003配置php环境,2003配置PHP环境(有利于升级)
  3. 算法---计数质数(Java)
  4. Firewall配置
  5. 如何设置mysql远程访问
  6. VI3之vCenterServer配置的备份与还原
  7. python的设计具有很强的可读性_Python是什么?具有怎么样的特点呢?
  8. 草图大师SketchUp2019下载与安装教程
  9. 写给大家看的量子力学——量子通信、量子隐形传输技术简介
  10. 《逆袭进大厂》第十三弹之Redis重点篇
  11. inventor软件绘制百叶窗方法_Inventor教程之工具面板上的编辑功能
  12. 商业插画师走尺印象:只为做生活的设计师
  13. 无线网络为什么经常掉线
  14. 用计算机刻录光盘,教你怎么用电脑刻录数据光盘
  15. jQuery 效果 - 淡入淡出
  16. STM32网址大全(快速定位网址查找资料)
  17. 华为mate30老是显示无法连接服务器,华为Mate30 Pro手机微信信息老是发不出,提示无法连接到网络...
  18. C语言项目源码,C语言源码大全
  19. 关于字节,半字,字到底有多多少位
  20. 管理信息系统(大一C语言课程设计)

热门文章

  1. Android Studio 字体大小设置
  2. GraphQL 、flask-graphql、Graphene| 一种配得上凡尔赛的API框架
  3. centos7下搭建hadoop、hbase、hive、spark分布式系统架构
  4. matlab2c使用c++实现matlab函数系列教程-fft函数
  5. 实验总结:Java+oracle数据库实现图书馆管理系统
  6. Linux关键字查询
  7. WebPack 简明学习教程
  8. 注意地方hadoop中的pi值计算
  9. lucene分析(未完成)
  10. Asp.Net细节性问题精萃