Состояние MFC недействительно, когда DLL вызывается через LoadLibrary - PullRequest
4 голосов
/ 14 декабря 2011

Я борюсь с MFC и динамически связываю DLL с LoadLibrary.Кажется, что я не могу получить правильное состояние MFC, когда приложение вызывает DLL, и DLL перезванивает в тот же вызов.В конечном итоге это приводит к множеству подтверждений.

Вот макет кода того, что я делаю.

  1. Приложение просто нормальное, прямо из мастераПриложение MFC.У меня есть кнопка где-то, и это обработчик кнопки:

    void callback()
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
    
        CDialog1 dlg;
        dlg.DoModal();
    }
    
    typedef void (*TPluginMainFunc)(void*);
    
    void CTheApp1View::OnTestRun1()
    {
            static HMODULE hPluginMFCShared = LoadLibrary( _T("PluginMFCShared") );
            if ( hPluginMFCShared )
            {
                    TPluginMainFunc func = (TPluginMainFunc) GetProcAddress( hPluginMFCShared, "plugin_main" );
                    if ( func )
                    {
                            func(callback);
                    }
            }
    }
    
  2. Тогда 'PluginMFCShared' выглядит так:

    typedef void (*TFunc)();
    
    extern "C" void GS_EXTERNAL_ENTRY plugin_main(TFunc func)
    {
            AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
    
            func();
    
            CDialog1 dlg;
            dlg.DoModal();
    }
    

Итак, идея состоит в том, что приложение (CTheApp1View :: OnTestRun1) загружает библиотеку и вызывает функцию, непосредственно передавая указатель обратного вызова.Библиотека будет использовать этот обратный вызов, чтобы выполнить что-то из приложения, прежде чем продолжить.

Я думал, что AFX_MANAGE_STATE позаботится о состоянии MFC, но, похоже, что-то еще нужно сделать.

Тестовый проект можно найти по адресу (убедитесь, что проект TheApp1 настроен на запуск проекта): SystemOfPlugins.zip

Есть идеи?

Спасибо залюбые предложения.

Ответы [ 3 ]

2 голосов
/ 14 декабря 2011

Вот еще одно предложение.В вашей переменной приложения добавьте переменную AFX_MODULE_STATE * с именем m_pModuleState и инициализируйте ее в конце функции InitInstance,

m_pModuleState = AfxGetModuleState();

Измените функцию обратного вызова, чтобы задать состояние приложения перед открытием диалога, а затем установитевернитесь в исходное состояние перед выходом из функции

void callback()
{
    //Get the original state
    AFX_MODULE_STATE* pOriginalState = AfxGetModuleState();

    //Set the mfc state
    AfxSetModuleState(((CTheApp1App*)&theApp)->m_pModuleState);

    //Do stuff here
    CDialog1 dlg;
    dlg.DoModal();

    //Set the mfc state back to its original state
    AfxSetModuleState(pOriginalState);
}

и оставьте плагин таким, каким он был в вашем примере

extern "C" void GS_EXTERNAL_ENTRY plugin_main(TFunc func)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState( ));

    func();
    CDialog1 dlg;
    dlg.DoModal();
}

Таким образом, вы вызовете AFX_MANAGE_STATE в своих плагинах, но когда некоторыеиз плагина сделать вызов функции обратного вызова, вы должны установить состояние приложения, чтобы оно могло найти хорошие ресурсы диалога и выполнять специфичные для состояния функции

0 голосов
/ 21 декабря 2011

Собираете ли вы dll с флагом препроцессора _LIB?Если это так, проверьте, действительно ли вы должны - вся концепция «MFC dll» устарела, больше нет причин использовать ее.Тогда забудьте обо всем AFX_MANAGE_STATE.В вашей dll сохраните HMODULE dll, который передается в DllMain, и используйте :: AfxSetResourceHandle () для правильного значения перед каждым использованием CDialog или подобным.Оберните его в класс, подобный интеллектуальному указателю, который устанавливает правильный дескриптор ресурса и сбрасывает его на старый (= основной, обычно 0x4000 ...), когда объект выходит из области видимости.

Дляво всех случаях, когда вы можете передать дескриптор ресурса напрямую (LoadString и т. д.), вам даже не нужно прикасаться к глобальному дескриптору.

Гораздо проще работать и гораздо прозрачнее.Дескриптор ресурса - единственный, который имеет отношение к состоянию MFC в версиях MFC начиная с VS6 в любом случае.

0 голосов
/ 14 декабря 2011

Я посмотрел на ваш код, и он заработал, изменив 2 функции:

в pluginMFCShared.cpp я вызвал AFX_MANAGE_STATE после вызова func ()

extern "C" void GS_EXTERNAL_ENTRY plugin_main(TFunc func)
{

    func();

    AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
    CDialog1 dlg;
    dlg.DoModal();
}

В app1view.cpp я удалил AFX_MANAGE_STATE

void callback()
{
    CDialog1 dlg;
    dlg.DoModal();
}

Теперь два диалоговых окна появляются один за другим

...