【问题标题】:class not instantiating in dll类没有在 dll 中实例化
【发布时间】:2014-01-29 20:35:57
【问题描述】:

我已经将 MFC 项目(可执行)构建为 dll,或者更准确地说,我已经像 dll 一样向其中添加了导出功能。我可以加载并执行导出的函数,但是问题是当我加载模块时,主应用程序类CMyApp theApp没有被实例化。这意味着我不能使用我真正想要的 theApp 对象。我什至修改了下面的函数,使其与标准 MFC dll 匹配。

BOOL CMyApp::InitInstance()
{
   CWinApp::InitInstance();

   return TRUE;
}

我正在使用LoadLibrary() 来加载 exe/dll。请注意,我没有从 dll 中导出任何 c++ 类,只是一些标准的 C 风格函数。这些函数在内部想要使用主应用程序对象,但它没有被实例化(它的构造函数永远不会被调用)。我需要做什么才能像在标准 mfc dll 中一样正确实例化应用程序类?

** 更新 **

理想情况下,我希望导出的函数在 exe 本身中可用,我已经这样做了,但是当我使用 LoadLibrary 加载它时,应用程序 theApp 类不会被实例化。我相信这是相同的行为,即使它是一个 dll。我的项目有很多依赖项,创建一个新的 dll 项目并添加所有文件和库太麻烦了。我真的很想更改当前项目的项目设置(如果有的话),这样我就可以像常规 MFC dll 一样使用正确实例化的应用程序类来加载它。但问题是我需要更改哪些项目设置?

注意:我将使用#define 取出主对话框对象的实例化。基本上InitInstance()函数的dll版本可以和我上面贴的一样简单。

【问题讨论】:

标签: c++ visual-studio-2010 dll mfc


【解决方案1】:

你描述的是Regular DLL Dynamically Linked to MFC。从这篇链接的文章中选择部分描述为您提供了一组特征:

动态链接到 MFC 的常规 DLL 具有以下内容 要求:

  • 这些 DLL 是使用定义的 _AFXDLL 编译的,就像动态链接到 MFC DLL 的可执行文件一样。但是 _USRDLL 是 也定义了,就像静态链接到的常规 DLL MFC。

  • 这种类型的 DLL 必须实例化一个 CWinApp 派生类。

  • 这种类型的 DLL 使用 MFC 提供的 DllMain。将所有特定于 DLL 的初始化代码放在 InitInstance 成员函数中 和 ExitInstance 中的终止代码,就像在普通 MFC 应用程序中一样。

如果您使用 VS2010 中的 New Project Wizatd 并选择创建 MFC DLL 的选项,这是您获得的默认设置,尽管您可以从向导选项中选择其他类型的 DLL:

所以,创建一个常规 DLL。它将为您生成必要的样板代码,包括CWinApp 派生类。例如:

// CMFCLibrary1App

BEGIN_MESSAGE_MAP(CMFCLibrary1App, CWinApp)
END_MESSAGE_MAP()

// CMFCLibrary1App construction

CMFCLibrary1App::CMFCLibrary1App()
{
    // TODO: add construction code here,
    // Place all significant initialization in InitInstance
}

// The one and only CMFCLibrary1App object

CMFCLibrary1App theApp;

// CMFCLibrary1App initialization

BOOL CMFCLibrary1App::InitInstance()
{
    CWinApp::InitInstance();

    return TRUE;
}

我建议您创建这样一个项目,然后将现有代码移植到其中,然后您将从一开始就拥有所有正确的项目设置和结构。这比尝试转换要容易得多,例如一个 exe 项目到一个 dll 项目。

请务必注意编写导出函数的方式不同。正如上面的链接所说:

因为这种DLL使用的是MFC的动态链接库版本, 您必须将当前模块状态显式设置为 动态链接库。为此,请在开头使用 AFX_MANAGE_STATE 宏 从 DLL 导出的每个函数。

所以即使你只导出 C 风格的函数,如果它们包装使用 MFC 的对象,那么导出的函数和导出类的任何公共函数都必须使用上述技术,尤其是对于多线程应用程序。

新项目模板也有助于插入 cmets 来解释这一点:

//TODO: If this DLL is dynamically linked against the MFC DLLs,
//      any functions exported from this DLL which call into
//      MFC must have the AFX_MANAGE_STATE macro added at the
//      very beginning of the function.
//
//      For example:
//
//      extern "C" BOOL PASCAL EXPORT ExportedFunction()
//      {
//          AFX_MANAGE_STATE(AfxGetStaticModuleState());
//          // normal function body here
//      }
//
//      It is very important that this macro appear in each
//      function, prior to any calls into MFC.  This means that
//      it must appear as the first statement within the 
//      function, even before any object variable declarations
//      as their constructors may generate calls into the MFC
//      DLL.
//
//      Please see MFC Technical Notes 33 and 58 for additional
//      details.
//

上述cmets中提到的技术注释有:

看到您使用LoadLibrary 来动态加载您的DLL,如果您是从MFC 应用程序执行此操作,您最好使用AfxLoadLibrary(以及相应的AfxFreeLibrary)。正如 MSDN 所说:

对于加载扩展 DLL 的 MFC 应用程序,我们建议您 使用 AfxLoadLibrary 而不是 LoadLibraryAfxLoadLibrary 句柄 在调用 LoadLibrary 之前进行线程同步。界面 (函数原型)到 AfxLoadLibraryLoadLibrary 相同。

documentation for AfxLoadLibrary 有更多详细信息。

【讨论】:

  • 谢谢,但是我的项目有很多依赖项,我尝试创建一个新的 dll 项目并添加所有文件,但它太麻烦了。另外,我还希望源代码管理中的同一个项目可以作为 dll 或 exe 使用#define。
  • @zadane EXE 和 DLL 将具有不同的项目属性。 #define 无法做到这一点。您可以在两个项目之间共享源文件,但我可能更愿意制作一个消耗 dll 的 exe。
  • 我想在代码文件中使用#define,主要是在InitInstance' and expose or not the export functions. I can live with changing project settings for each. I thought I can export functions even from EXE but somehow app`当我将它加载为dll模块时,类没有实例化。
  • 我最终创建了新的 dll 项目并将代码移植到其中。
【解决方案2】:

我刚刚遇到了同样的问题,我的问题是 lpszClassNameRegisterClassEx 是空的。确保您使用相同的字符串调用CreateWindow

如果您的问题不是这种情况,请使用GetLastError() 打印实际的错误消息。缺少lpszClassName 导致我出现错误代码1407

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多