转载外部程序调用Qt5带界面的dll

转自https://blog.csdn.net/shuishanga/article/details/52183159

外部程序调用Qt5带界面的dll

2016年08月12日 09:37:37 chsmiao 阅读数:5586

 

一、            主要参考

参考1:http://blog.csdn.net/libin88211/article/details/38183791

参考2:http://blog.csdn.net/suifenghuidong/article/details/12032077

参考3:http://blog.csdn.net/tingsking18/article/details/4967172

参考4:http://bbs.csdn.net/topics/370053884

 

二、            背景及环境

目标:在MFC、VC++控制台程序里能调用Qt5编写的带界面的DLL。

Qt5直接编译的DLL在MFC、VC++控制台程序里是不能调用的,为了实现上述目标,开始在度娘上查找资料。首先发现了解决方法是qtwinmigrate,但正如参考1中所写,想找一个现成可用的资料真是不容易。后来把能查出的基本都浏览了一遍,经过一些曲折的学习测试,终于基本实现。所以还是梳理下,便于之后查看,也给有需要的小伙伴们提供一个参考。

本人环境:

软件

版本

Qt

qt-opensource-windows-x86-mingw492-5.6.0.exe

Visual Studio

VS2010

QtWinmigrate

https://github.com/qtproject/qt-solutions

       重点说下,qtwinmigrate我是在GitHub(https://github.com/qtproject/qt-solutions)上down下来的,发现是可用的。GitHub嘛,相信大家都懂,最好自己down了。若确实没用过GitHub又懒得去弄,也可在这里(http://download.csdn.net/detail/shuishanga/9601396)下载。

 

三、            具体使用    

3.1         编译qtwinmigrate

将下载好的qtwinmigrate解压,用Qt Creator打开…\qtwinmigrate\examples\qtdll\qtdll.pro,然后在Release模式下构建。

图1 qtdll及构建

       构建完成后,会在…\qtwinmigrate\examples\build-qtdll-Desktop_Qt_5_6_0_MinGW_32bit-Release\release下生成qtdialog.dll 。

3.2         找到DLL的依赖项

上步中生成了DLL,但是还不能直接拿去使用,此时LoadLibrary是加载不上的,因为还需要其依赖的Qt库。网上有些使用Dependency Walker等软件来找DLL依赖项,当然可以,但是过于麻烦。这里采用Qt官方开发环境里自带的工具:windeployqt.exe。如我安装的5.6版本可以在Qt安装目录…\5.6\mingw49_32\bin下找到。

具体使用方法:

先将上步生成的qtdialog.dll 复制到一个新建文件夹,如D:\MyQtDLL。在开始菜单中打开Qt命令行,在命令行中定位到DLL相应目录,执行“windeployqt qtdialog.dll”。此时qtdialog.dll的依赖项便自动copy到其目录下了。

这里有些依赖项可能用不到,比如translations文件夹,删除就行。

   

 

图2 打开Qt命令行

 

图3 使用Qt命令行

 

图4 qtdialog.dll及其依赖项

3.3         调用Qt5编译的DLL

MFC或者VC++控制台程序在调用Qt5编译的DLL时,需要将上步中qtdialog.dll所在文件夹内所有内容复制到工程编译的exe文件夹内。

1.        MFC调用

为测试,用VS2010新建一个MFC对话框程序,简单地在界面上放一个按钮,并在按钮点击事件中加载DLL,弹出Qt5的DLL的界面。

 

 
  1. void XXX::OnBnClickedButton1()

  2. {

  3. const char* dllName = "qtdialog.dll";

  4.  
  5. HMODULE hDLL = LoadLibrary(dllName);

  6.  
  7. if (hDLL != NULL)

  8. {

  9. typedef bool(*pShow)(HWND parent);

  10.  
  11. pShow fp1 = pShow(GetProcAddress(hDLL, "showDialog"));

  12. if (fp1 != NULL)

  13. {

  14. fp1(theApp.m_pMainWnd->m_hWnd);

  15. }

  16.  
  17. FreeLibrary(hDLL);

  18. }

  19. else

  20. {

  21. CString strInfo;

  22. strInfo.Format("Cannot Find %s", dllName);

  23. MessageBox(strInfo);

  24. }

  25. }


记住运行前将qtdialog.dll所在文件夹内的全部内容复制到工程编译的exe文件夹内。编译成功后,运行如下如

 

 

图5  MFC调用qtdialog.dll

2.        控制台程序调用

 

 
  1. #include <iostream>

  2. #include <Windows.h>

  3. using std::cout;

  4. using std::endl;

  5.  
  6. int main()

  7. {

  8. const char* dllName = "qtdialog.dll";

  9.  
  10. HMODULE hDLL = LoadLibrary(dllName);

  11.  
  12. if (hDLL != NULL)

  13. {

  14. typedef bool(*pShow)(HWND parent);

  15.  
  16. pShow fp1 = pShow(GetProcAddress(hDLL, "showDialog"));

  17. if (fp1 != NULL)

  18. {

  19. //ShowWindow(GetConsoleWindow(), SW_HIDE);

  20. fp1(GetConsoleWindow());

  21. }

  22.  
  23. FreeLibrary(hDLL);

  24. }

  25. else

  26. {

  27. cout << "Cannot Find " << dllName << endl;

  28. }

  29.  
  30. return 0;

  31. }

 

 

 

图6  控制台调用qtdialog.dll

3.4         修改qtwinmigrate,加载自写界面

上面例子中直接使用了qtwinmigrate中自带的QMessageBox,这里将其修改下变为一个自己写的界面。

随便用Qt Creator新建一个Dialog,如这里TestDlg:

图7  新建TestDlg

将TestDlg的头文件和源文件复制到qtdll目录下,并在Qt Creator中qtdll项目上右键添加进来。

图8 将TestDlg文件复制到qtdll下并在工程中添加

此时修改接口函数为:

 

 
  1. extern "C" __declspec(dllexport) bool showDialog( HWND parent )

  2. {

  3. QWinWidget win( parent );

  4. win.showCentered();

  5.  
  6. CMyDialog mydlg(&win);

  7. mydlg.exec();

  8.  
  9. return TRUE;

  10. }

 

然后重新构建,同上步骤。此时MFC、VC++控制台的调用结果:

图9 MFC调用qtdll自写界面

 

图10 控制台调用qtdll自写界面

 

四、            其他问题

4.1         接口函数问题 int main(int argc, char *argv[]) ?

在参考1和4中指出用int main(int argc, char *argv[]) 做接口函数,并在其中创建QApplication对象。

接口函数:

 

 
  1. extern "C"__declspec(dllexport) int main(int argc, char *argv[])

  2. {

  3. QApplication a(argc, argv);

  4. CTestDialog w;

  5. w.show();

  6. return a.exec();

  7. }

测试:

 

 
  1. HMODULE hDLL = LoadLibrary(dllName);

  2.  
  3. if (hDLL != NULL)

  4. {

  5. typedef bool(*pShow)(HWND parent);

  6.  
  7. typedef int(*pMain)(int, char *[]);

  8. pMain fMain =pMain(GetProcAddress(hDLL, "main"));

  9. if (fMain != NULL)

  10. {

  11. fMain(0, 0);

  12. }

  13.  
  14. FreeLibrary(hDLL);

  15. }

结合源码和参考3可知其实QApplication对象在QmfcApp::pluginInstance已经创建。并且QMfcApp::pluginInstance(hInstance)提供了Qt和MFC消息循环共同工作的机制。因此个人觉得采用showDialog中QWinWidget方式更好些。

对于3.4的小例子,测试发现使用发现两种方法都可以。但是测试自写的一个更复杂的界面时发现,多次点击按钮加载DLL时,采用main接口函数会出现异常崩溃现象,如下图:

 

图11 main接口发生异常情况

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值