Feb 082009
 

The IPlug library for developing VST plugins has a bug causing the user edit window to get stuck open (but invisible) under some circumstances. This results in some sluggish UI behavior. This bug occurs in Windows with VST plugins and I have not been able to check for the bug in AU or Mac plugins using IPlug.

The bug happens when you open your VST plugin for editing, right click a parameter to bring up the edit box, then close the plugin gui without closing the edit box. Open the plugin gui again and try to right click to open the parameter edit again. You will find the gui somewhat unresponsive. After clicking a few times the parameter edit field will open. You may deduce that the old parameter edit box is still open but not visible and the first click closes the invisible edit box while the second opens the new one. Digging into the code reveals that this seems to be the case. Let’s take a look!

The IGraphicsWin::mParamEditWnd member holds the active edit box on your plugin. The edit box is created in IGraphicsWin::PromptUserInput and destroyed in IGraphicsWin::WndProc when the edit process is committed or cancelled. So is the edit process destroyed or cancelled when the window closes? Checking the WndProc handler for the WM_CLOSE message we can see the plugin framework is calling IGraphicsWin::CloseWindow to cleanup, and that function is as follows:

void IGraphicsWin::CloseWindow()
{
    if (mPlugWnd) {
        DestroyWindow(mPlugWnd);
        mPlugWnd = 0;

        if (--nWndClassReg == 0) {
            UnregisterClass(wndClassName, mHInstance);
        }
    }
}

Indeed we are not cleaning up the parameter edit window when the window closes. We have a few options to fix this:

  1. Try to trigger and handle a kCancel message through Windows API messaging before the window closes.
  2. Add additional code to the handling of the WM_CLOSE message.
  3. Add additional code to the CloseWindow method.

I decided on option 3 because the CloseWindow method is used in more places than the handling of WM_CLOSE so we automatically get the same cleanup everywhere it gets called. Since mParamEditWnd is also destroyed during a kCancel operation we will encapsulate the logic for tearing down the edit window in a helper function and call it from both CloseWindow and the kCancel handler. Here is the helper:

void IGraphicsWin::cleanupParamEditWindow()
{
    if (mParamEditWnd)
    {
        SetWindowLongPtr(mParamEditWnd, GWL_WNDPROC, (LONG_PTR) mDefEditProc);
        DestroyWindow(mParamEditWnd);
    }
    mParamEditWnd = 0;
    mEdParam = 0;
    mEdControl = 0;
    mDefEditProc = 0;
    mParamEditMsg = kNone;
}

This is basically the code that was being run in the handler for kCancel (in IGraphicsWin::WndProc) with the additional safeguarding against mParamEditWnd being null. The handler for kCancel in WndProc has been trimmed down:

case kCancel:
    pGraphics->cleanupParamEditWindow();
    break;

And IGraphicsWin::CloseWindow() is now calling cleanupParamEditWindow as follows:

void IGraphicsWin::CloseWindow()
{
    cleanupParamEditWindow();
    if (mPlugWnd) {
        DestroyWindow(mPlugWnd);
        mPlugWnd = 0;

        if (--nWndClassReg == 0) {
            UnregisterClass(wndClassName, mHInstance);
        }
    }
}

You don’t have to put the edit window cleanup first but it is generally good programming practice to clean up in reverse order of creation. Or if you think of it in terms of nesting of the windows you want to clean up the innermost window before cleaning up the outermost window. Following that principle dictates that we clean up the edit window before cleaning up the plugin window.

Even when fighting bugs like these, VST plugin development is fun. So stick with it!

Sorry, the comment form is closed at this time.