Qt/MFC 迁移框架工具:正确退出 DLL?

Posted

技术标签:

【中文标题】Qt/MFC 迁移框架工具:正确退出 DLL?【英文标题】:Qt/MFC Migration Framework tool: properly exiting DLL? 【发布时间】:2011-02-25 00:54:32 【问题描述】:

我正在按照以下示例使用 Qt/MFC 迁移框架工具: http://doc.qt.nokia.com/solutions/4/qtwinmigrate/winmigrate-qt-dll-example.html

我构建的 dll 由基于 MFC 的第 3 方应用程序加载。第 3 方应用程序基本上调用我导出的 DLL 函数之一来启动我的插件和另一个函数来关闭我的应用程序。目前我在关机功能中什么也没做。

当我在 3rd 方应用程序中加载我的 DLL 时,将调用启动函数并且我的 DLL 成功启动并且我可以看到我的消息框。但是,如果我关闭我的插件然后尝试再次启动它,我会收到以下错误:

Debug Error!

Program: <my 3rd party app>
Module: 4.7.1
File: global\qglobal.cpp
Line: 2262
ASSERT failure in QWidget: "Widgets must be created in the GUI
thread.", file kernel\qwidget.cpp line 1233

(Press Retry to debug the application)

Abort Retry Ignore

这让我觉得我没有做任何事情来正确关闭我的插件。我需要做什么才能正确关闭它?

更新: http://doc.qt.nokia.com/solutions/4/qtwinmigrate/winmigrate-walkthrough.html 说:

DLL 还必须确保它 可以和其他Qt一起加载 基于同一进程中的 DLL(在 在这种情况下 QApplication 对象将 可能已经存在),并且 创建 QApplication 的 DLL 对象仍然加载到内存中 避免使用其他 DLL 的内存 该进程不再可用。

所以我想知道是否有什么问题我需要以某种方式保持加载原始 DLL 无论如何?

【问题讨论】:

【参考方案1】:

我得到了这个工作!经过许多令人沮丧的工作后,我得到了它的工作。我正在使用 Qt/MFC 迁移文档中提供的代码:

 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;
 

此结构适用于我的插件 DLL 的单次加载,但在后续加载时失败。我不相信 DllMain 是调用 pluginInstance 的正确位置(至少对于我的用例而言)。我认为问题在于我的第 3 方应用程序只调用了一次 DllMain,并且在应用程序退出之前不会卸载 DLL。因此,当我启动我的插件然后将其关闭然后再次启动它时,通过调用 pluginInstance 初始化的 QApplication 仍然存在。我认为我的第 3 方应用程序每次启动插件时都会启动单独的线程,所以当我第二次启动插件时,它是一个新线程,但仍在尝试使用 DllMain 中的原始 QApplication 设置(DLL 仍在加载)。因此我的错误是因为它是试图写入 GUI 的新线程。

我正在构建的第 3 方 MFC 应用程序在我的 DLL 中需要两个导出,Startup() 和 Shutdown(),它会在相关时间调用。

因此,我没有按照演练的建议进行操作,而是执行以下操作(伪代码):

extern "C" __declspec(dllexport) void Startup()

  QMfcApp::pluginInstance( 3rdPartyApp::GetPluginHandle() );
  QWinWidget win( 3rdPartyApp::GetParentWindow() );
  win.showCentered();
  QMessageBox::about( &win, "About", "Hello World" );


 extern "C" __declspec(dllexport) void Shutdown()

  qApp->quit();
  delete qApp;

这对于单个插件来说很好,但是如果我创建多个插件,我不确定这将如何工作,因为事件循环集成我认为所有插件应该只有一个 QApplication(基于我的阅读的 Qt/MFC 文档)。

【讨论】:

【参考方案2】:

据我所知,当您加载 Qt DLL 时,基于 MFC 的应用程序会隐式加载与 Qt 框架相关的 DLL。此外,当您在 Dll 中启动 QApplication 时,它只会生成一个 QApplication 实例。但是,当您关闭 QApplication 时,与 Qt 框架相关的 Dll 不会从基于 MFC 的应用程序中卸载。其中一个 DLL 具有永久的 QApplication 实例。最佳解决方案是可执行文件不是 Dll。

【讨论】:

我认为你是对的,一个 DLL 永久拥有 QApplication 实例。当您启动一个新的 DLL(或重新启动同一个 DLL)时,您如何连接到现有的 QApplication 实例以便创建 GUI 对象?

以上是关于Qt/MFC 迁移框架工具:正确退出 DLL?的主要内容,如果未能解决你的问题,请参考以下文章

做windows界面,用QT还是MFC?

VC++程序调试时出现“ 下面的框架可能不正确和/或缺失,没有为 kernel32.dll 加载符号”怎么回事?

框架如何迁移? | X2Paddle 小工具教你玩转模型迁移

开源的 .NET 数据库迁移框架

对界面编程来说c++的mfc,qt和c#的winform,wpf哪个应用多?学哪个好?

ABP框架数据迁移报错