代码之家  ›  专栏  ›  技术社区  ›  Mr. Boy

从DLL导出MFC对话框

  •  6
  • Mr. Boy  · 技术社区  · 14 年前

    7月21日:更新,见底部

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

    测试程序

    #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控制台应用程序,它可以:

    测试程序

    #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。我看过一些关于代码师等的文章,没有看到任何明显的东西。我的类没有被导出/导入吗?还是资源问题?或者是我试图从控制台(MFC)应用程序显示它的问题?

    7月21日更新 我创建了一个重写的domodal,如下所示:

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

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

    4 回复  |  直到 7 年前
        1
  •  9
  •   Serve Laurijssen    7 年前

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

    手动呼叫 AFX_MANAGE_STATE 确保建立DLL上下文是一种方法,但它不是透明的。理想的方法是将您的dll编译为扩展dll,以便MFC能够从扩展dll列表中加载资源并管理dll之间的内存。

    您可以快速创建扩展dll,只需创建自己的 CDynLinkLibrary 实例,它将您的dll添加到主资源列表中。我没有尝试过这样做,而是选择扩展dll_afxdll路由,因此这可能有效,也可能无效。

    有关的msdn文章 Extension DLLs 可以帮助您确定它们是否适合您的情况,以及它们带来的优势/缺点。

        2
  •  4
  •   dusan    12 年前

    明确地加载你*.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();
    
        3
  •  2
  •   dwo    14 年前

    我不确定这个建筑是否真的能用。如果可能,只导出一个函数,该函数将打开dll中的对话框。

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

        4
  •  1
  •   user3169966    10 年前

    AFX管理州不适合我。在我的例子中,exe正在从另一个dll调用一个对话框,该对话框正在从第三个dll调用另一个对话框。afx_manage_state正在返回第二个dll的上下文,而不是第三个dll的上下文。为了解决这个问题,我将覆盖domodel并在那里进行上下文切换。

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