Проблемы с использованием wxWidgets (wxMSW) в нескольких экземплярах DLL - PullRequest
1 голос
/ 10 июля 2009

Введение

Я разрабатываю VST-плагины, которые являются программными модулями на основе DLL и загружаются хост-приложениями, поддерживающими VST. Чтобы открыть VST-плагин, хост-приложения загружают VST-DLL и вызывают соответствующую функцию плагина, предоставляя дескриптор собственного окна, который плагин может использовать для рисования своего GUI. Мне удалось портировать свой оригинальный VSTGUI код для wxWidgets-Framework, и теперь все мои плагины работают под wxMSW и wxMac, но у меня все еще есть проблемы с wxMSW, чтобы найти правильный способ открывать и закрывать плагины, и я не уверен, что это проблема только для wxMSW.

Задача

Если я использую какое-либо приложение VST-хоста, я могу без проблем открывать и закрывать несколько экземпляров одного из моих VST-плагинов. Как только я открываю другой из моих VST-плагинов, помимо моего первого VST-плагина, а затем закрываю все экземпляры моего первого VST-плагина, приложение через короткое время вылетает из функции wxEventHandlerr :: ProcessEvent, сообщая, что объект wxTheApp больше не действует во время выполнения wxTheApp-> FilterEvent (см. ниже). Похоже, что объекты wxTheApp были удалены после закрытия всех экземпляров первого плагина и больше не доступны для второго плагина.

bool wxEvtHandler::ProcessEvent(wxEvent& event)
{
    // allow the application to hook into event processing
    if ( wxTheApp )
    {
        int rc = wxTheApp->FilterEvent(event);
        if ( rc != -1 )
        {
            wxASSERT_MSG( rc == 1 || rc == 0,
                          _T("unexpected wxApp::FilterEvent return value") );

            return rc != 0;
        }
        //else: proceed normally
    }

    ....
}

Предпосылки

1.) Все мои VST-плагины динамически связаны с библиотеками C-Runtime и wxWidgets. Что касается wxWidgets Форум, кажется, это лучший способ запустить несколько экземпляров программного обеспечения рядом.

2.) DllMain каждого VST-плагина определяется следующим образом:

// WXW
#include "wx/app.h"
#include "wx/defs.h"
#include "wx/gdicmn.h"
#include "wx/image.h"

#ifdef __WXMSW__
#include <windows.h>
#include "wx/msw/winundef.h"

BOOL APIENTRY DllMain
( HANDLE hModule,
  DWORD ul_reason_for_call,
  LPVOID lpReserved )
{
        switch (ul_reason_for_call)
        {
            case DLL_PROCESS_ATTACH:
        {
                  wxInitialize();
                ::wxInitAllImageHandlers();
            break;
        }
            case DLL_THREAD_ATTACH:
                       break;
            case DLL_THREAD_DETACH:
                       break;
            case DLL_PROCESS_DETACH:
                       wxUninitialize();
                           break;
        }

    return TRUE; 
}

#endif // __WXMSW__

class Application : public wxApp {};
IMPLEMENT_APP_NO_MAIN(Application)

Вопрос

Как я могу предотвратить это поведение соответственно, как я могу правильно обрабатывать объект wxTheApp, если у меня есть несколько экземпляров различных VST-плагинов (DLL-модулей), которые динамически связаны с библиотеками C-Runtime и wxWidgets?

С наилучшими пожеланиями, Штеффен

Ответы [ 2 ]

0 голосов
/ 29 августа 2011

Я столкнулся с подобной проблемой, но с плагинами Acrobat. При настройке наших плагинов Acrobat для Acrobat X (10) нам пришлось удалить код, связанный с ADM (Acrobat Dialog Manager - раньше использовался как кроссплатформенная инфраструктура графического интерфейса в Acrobat 7, 8 и 9. Удалено с помощью Acrobat X) и использовать другой GUI Framework.

В состав Acrobat SDK входят примеры использования wxWidgets в качестве кроссплатформенной инфраструктуры, поэтому мы пошли по этому пути (мы поддерживаем MAC и Windows). Архитектура плагинов Acrobat очень похожа на ту, что вы описали выше: dlls (для плагинов Acrobat расширение двоичного файла - * .api), которые динамически загружаются основным процессом (exe), а их функции вызываются в документированном, предварительно определенный порядок.

Поскольку пример Acrobat wxWidgets был написан для версии 2.8.12, и в связи с тем, что это стабильная версия, мы решили НЕ использовать текущую версию 2.9.x.

Таким образом, мы статически связали наши плагины (всего 3 разных плагина) с библиотеками wx2.8.12 и выяснили, что, если установлены 3 из них, те, что были загружены последними, не работают. Под этим я подразумеваю - наши пользовательские wxFrames, wxWindows & wxDialogs, принадлежащие этим двум плагинам, были испорчены (как кто-то пытался стереть их с помощью резины: -)).

Глубоко копаясь, мы сузили его до того факта, что первый загружаемый плагин инициализирует wxWidgets, а второй - нет, хотя явный вызов wxInitialize (). Что-то там пошло не так ....

Здесь я забыл упомянуть - в плагине Acrobat вы не можете изменить функцию DllMain (), поэтому инициализация wx выполняется в «Plugin Init () function».

Просто чтобы прояснить: библиотеки wx статически связаны с файлами * .api, поэтому каждый из них должен иметь свою собственную "копию" и не влиять друг на друга.

Используя Google в течение 2-3 полных дней, мне удалось найти эту запись , который предложил применить этот патч (ТОЛЬКО для 2.8x !!!). Я полагаю (или надеюсь), что версия 2.9.x не страдает от этой проблемы (не было возможности проверить это).

Кстати: патч - это всего лишь один файл, который очень понятен, поэтому прочитать код, чтобы понять его и быть спокойным, что он не причиняет вреда, довольно легко.

Я надеюсь, что другие, использующие wx 2.8.x и страдающие той же проблемой, найдут это.

Омри

0 голосов
/ 27 августа 2009

У нас были похожие проблемы с использованием LSP, созданного с помощью wxWidgets, когда приложение wxWidgets загрузило нашу DLL. Проверьте NULL == wxTheApp перед вызовом :: wxInitialize ().

Псевдокод:

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
    switch(dwReason) {
        case DLL_PROCESS_ATTACH :
            if(NULL == wxTheApp) {
                ::wxInitialize();
            }
            break;
    }
}

Кроме того, я предлагаю сделать как можно меньше в вашей DllMain (), например. переместите wxInitAllImageHandlers () в другое место, если это возможно. Кроме того, вы можете отследить, вызвали ли вы :: wxInitialize () для сопряжения с :: wxUninitialize ()

...