从DLL导出MFC对话框

时间:2010-07-16 13:47:24

标签: visual-c++ dll mfc

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();
}

这似乎有效但我是否应该重写一种不同的方法来使功能更通用?

4 个答案:

答案 0 :(得分:9)

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

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

您可以快速创建扩展DLL,只需创建自己的CDynLinkLibrary实例,即将DLL添加到主资源列表中。我没有试过这个,宁愿采取扩展名dll _AFXDLL路由,所以这可能会也可能不会。

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

答案 1 :(得分:4)

明确加载* .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();

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

AFX_MANAGE_STATE对我不起作用。在我的情况下,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);
    }
}