1

前言

我正在开发 VST 插件,它们是基于 DLL 的软件模块,由支持 VST 的主机应用程序加载。要打开 VST 插件,主机应用程序会加载 VST-DLL 并调用插件的适当函数,同时提供本机窗口句柄,插件可以使用它来绘制它的 GUI。我设法将我的原始 VSTGUI 代码移植到 wxWidgets-Framework,现在我的所有插件都在 wxMSW 和 wxMac 下运行,但我在 wxMSW 下仍然遇到问题,无法找到打开和关闭插件的正确方法,我不确定这是否是wxMSW-only 问题。

问题

如果我使用任何 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.) 每个 VST-Plugin 的 DllMain 定义如下:

// 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)

问题

如果我有多个不同 VST 插件(DLL 模块)的实例,这些实例与 C-Runtime 和 wxWidgets 库动态链接,我该如何分别防止这种行为?

最好的问候,史蒂芬

4

2 回答 2

0

当 wxWidgets 应用程序加载我们的 DLL 时,我们在使用使用 wxWidgets 创建的 LSP 时遇到了类似的问题。在调用 ::wxInitialize() 之前检查 NULL == wxTheApp。

伪代码:

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

另外,我建议在您的 DllMain() 中尽可能少地执行操作,例如,如果可能,将 wxInitAllImageHandlers() 移到其他地方。此外,您可能希望跟踪您是否调用了 ::wxInitialize() 以与 ::wxUninitialize() 配对

于 2009-08-26T22:31:32.433 回答
0

我遇到了类似的问题,但使用 Acrobat 插件。在将 Acrobat 插件调整为 Acrobat X (10) 时,我们必须删除与 ADM 相关的代码(Acrobat 对话框管理器 - 曾经是 Acrobat 7、8 和 9 上的跨平台 GUI 框架。随 Acrobat X 删除)并使用不同的图形用户界面框架。

Acrobat SDK 附带了使用 wxWidgets 作为跨平台框架的示例,因此我们采用了这种方式(我们支持 MAC 和 Windows)。Acrobat 的插件架构与您上面描述的非常相似:dll(对于 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() 函数”中完成的。

需要明确一点 - wx 库静态链接到 *.api 文件,因此每个库都应该有自己的“副本”,并且不会相互影响。

使用谷歌 2-3 天我设法找到了这篇文章,它建议应用这个补丁(仅限 2.8 倍!!!)。我相信(或希望)2.9.x 版本不会遇到这个问题(没有机会检查它)。

顺便说一句 - 补丁只是一个非常清晰的文件,因此阅读代码以理解它并保持冷静,它没有伤害是很容易的。

我希望其他使用 wx 2.8.x 并遭受相同问题困扰的人会发现这一点。

暗里

于 2011-08-29T17:23:13.197 回答