【问题标题】:Exporting a MFC Dialog from a DLL从 DLL 导出 MFC 对话框
【发布时间】:2011-03-16 23:30:08
【问题描述】:

7 月 21 日:更新,见底部

在 VC++ 2005 中,我有 2 个项目。首先,一个 MFC DLL 项目(不是扩展 DLL),它有一个简单的对话框:

TestDlg.h

#pragma once
#include "afxwin.h"
#include "resource.h"
// CTestDlg dialog
namespace Dialogs
{
    class __declspec(dllexport) CTestDlg : public CDialog
    {
        DECLARE_DYNAMIC(CTestDlg )

    public:
        CTestDlg (CWnd* pParent = NULL);   // standard constructor
        virtual ~CTestDlg ();

    // Dialog Data
        enum { IDD = IDD_TEST_DLG };
    }
}

然后我有一个带有 MFC 库的 Win32 控制台应用程序:

TestApp.cpp

#include "stdafx.h"
#include "TestApp.h"
#include <TestDlg.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    // initialize MFC and print and error on failure
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: change error code to suit your needs
        _tprintf(_T("Fatal Error: MFC initialization failed\n"));
        nRetCode = 1;
    }
    else
    {

        Dialogs::CTestDlg dlg;
        dlg.DoModal();
    }
    return nRetCode;
}

它构建并运行,但没有出现对话框。步入 DoModal()...

dlgcore.cpp

INT_PTR CDialog::DoModal()
{
    // can be constructed with a resource template or InitModalIndirect
    ASSERT(m_lpszTemplateName != NULL || m_hDialogTemplate != NULL ||
        m_lpDialogTemplate != NULL);

    // load resource as necessary
    LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;
    HGLOBAL hDialogTemplate = m_hDialogTemplate;
    HINSTANCE hInst = AfxGetResourceHandle();
    if (m_lpszTemplateName != NULL)
    {
        hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
        HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
        hDialogTemplate = LoadResource(hInst, hResource);
    }
    if (hDialogTemplate != NULL)
        lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);

    // return -1 in case of failure to load the dialog template resource
    if (lpDialogTemplate == NULL)
        return -1;

    ... more stuff

无论出于何种原因,它似乎无法加载资源,在复制部分的末尾返回 -1。我看过一些关于 CodeGuru 等的文章,但没有看到任何明显的东西。我的班级没有被导出/导入吗?还是资源问题?还是我试图从控制台 (MFC) 应用程序显示它的问题?

7 月 21 日更新 我这样创建了一个覆盖的 DoModal:

INT_PTR CTestDlg::DoModal()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
    return CDialog::DoModal();
}

这似乎可行,但我应该重写一个不同的方法来获得更通用的功能吗?

【问题讨论】:

    标签: visual-c++ dll mfc


    【解决方案1】:

    正如您所指出的,问题在于 MFC 没有找到资源,因为模块上下文设置为您的主 EXE,而不是包含对话框资源的 DLL。

    手动调用AFX_MANAGE_STATE 以确保建立 DLL 上下文是解决此问题的一种方法,但它不透明。理想的方法是将您的 DLL 编译为扩展 DLL,以便 MFC 可以负责从扩展 DLL 列表中加载资源并管理 DLL 之间的内存。

    您可以使用快捷方式创建扩展 DLL,只需创建自己的 CDynLinkLibrary 实例,即可将您的 DLL 添加到主资源列表中。我没有尝试过,而是更喜欢使用扩展 dll _AFXDLL 路由,所以这可能会也可能不会。

    Extension DLLs 上的 MSDN 文章可能会帮助您确定它们是否适合您的情况,以及它们带来哪些优点/缺点。

    【讨论】:

      【解决方案2】:

      AFX_MANAGE_STATE 对我不起作用。就我而言,exe 正在从另一个 dll 调用一个对话框,该 dll 从第三个 dll 调用另一个对话框。 AFX_MANAGE_STATE 返回第二个 dll 而不是第三个的上下文。为了解决这个问题,我将覆盖 DoModel 并在那里进行上下文切换。

      INT_PTR YourDialog::DoModal()
      {
          HINSTANCE _hInstance = AfxGetResourceHandle();
      
          __try
          {
              HMODULE dllModule = ::GetModuleHandle("<Your_DlgSourceDll>.dll");
              AfxSetResourceHandle(dllModule);
              return CDialog::DoModal();
          }
          __finally
          {
              AfxSetResourceHandle(_hInstance);
          }
      }
      

      【讨论】:

        【解决方案3】:

        显式加载你的 *.lib

        Hinstance = Loadlibray("*.lib");
        
        AfxSetResourceHandle(Hinstance);
        // this way you can load the resource in you dll not the current app's resource.
        

        然后你编码的目的地:

        CTestDlg dlg;
        dlg.DoModal();
        

        【讨论】:

          【解决方案4】:

          我不确定这种结构是否真的可以工作。如果可能,只导出一个在 DLL 中打开对话框的函数。

          但也许使用AFX_MANAGE_STATE-macro 可以帮助您。

          【讨论】:

          • 我读到的几个地方可以从 DLL 中导出基于 CDialog 的类。不过你的建议还不错,像Dialogs::CTestDlg *Dialogs::ShowTestDlg()这样的方法?
          • 是的,类似的,但没有返回指向对话框类的指针。在这种情况下,您需要再次了解该课程!
          • 我已经很久没有使用 MFC 了,但我怀疑就是这样。我认为问题在于您在应用程序和 DLL 之间有单独的资源/ID 到类映射池,即使它们都是 MFC,它们也不能相互访问。我认为一直困扰我的是 HWND 到类的映射是每个线程(或类似的东西)。
          • 有什么理由反对使用 MFC 扩展 DLL?
          • 扩展 dll 设法进入应用程序的资源链,因此您的对话框会找到它的资源。但我刚刚在您的更新中看到,我的 AFX_MANAGE_STATE 提示也起到了作用!
          猜你喜欢
          • 2015-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-16
          相关资源
          最近更新 更多