Экспорт диалога MFC из DLL - PullRequest
6 голосов
/ 16 июля 2010

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

Затем у меня есть консольное приложение Win32 с библиотеками MFC, которое выполняет:

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) приложения?

21 июля Обновление Я создал переопределенный DoModal следующим образом:

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

Кажется, это работает, хотя я должен переопределить другой метод, чтобы сделать функциональность более общей?

Ответы [ 4 ]

9 голосов
/ 23 июля 2010

Как вы заметили, проблема в том, что MFC не находит ресурс, поскольку контекст модуля установлен на ваш основной EXE, а не на DLL, содержащую ресурс диалога.

Ручной вызов AFX_MANAGE_STATE, чтобы убедиться, что контекст DLL установлен, является одним из способов решения этой проблемы, но он не прозрачен.Идеальный способ - скомпилировать вашу DLL как библиотеку расширений, чтобы MFC мог позаботиться о загрузке ресурса из списка библиотек расширений и управлении памятью между библиотеками DLL.

Возможно, вы сможете использовать ярлыксоздайте расширение DLL и просто создайте свой собственный экземпляр CDynLinkLibrary, который добавит вашу DLL в основной список ресурсов.Я не пробовал этого, предпочитая вместо этого использовать маршрут _AFXDLL расширения dll, так что это может работать или не работать.

Статья MSDN о DLL-файлах расширений может помочь вам определить, подходят ли онив вашем случае, и какие преимущества / недостатки они приносят.

4 голосов
/ 21 марта 2012

Точно загрузите вас * .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 голосов
/ 16 июля 2010

Я не уверен, может ли эта конструкция действительно работать.Если возможно, экспортируйте только функцию, которая открывает диалоговое окно внутри DLL.

Но, возможно, использование AFX_MANAGE_STATE -macro может вам помочь.

1 голос
/ 01 июля 2014

AFX_MANAGE_STATE не работает для меня. В моем случае exe вызывал диалог из другой библиотеки DLL, которая вызывала другой диалог из 3-й библиотеки DLL. AFX_MANAGE_STATE возвращал контекст 2-й библиотеки вместо 3-го. Чтобы это исправить, я переопределяю DoModel и переключаю контекст там.

INT_PTR YourDialog::DoModal()
{
    HINSTANCE _hInstance = AfxGetResourceHandle();

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