[bug] NativeMessageBox incorrect behaviour

Using this code:

mMessageBox = juce::NativeMessageBox::showScopedAsync (
    juce::MessageBoxOptions()
        .withTitle ("Please confirm")
        .withMessage ("Some question asking for confirmation")
        .withButton ("Ok")
        .withButton ("Cancel"),
    [pluginContext = mPluginContext] (int i) {
        if (i == 1)
        {
            // Do the thing
        }
        else
        {
            // User cancelled
        }
    });

Produces the wrong popup when running as VST3 inside Bitwig:

Screenshot 2024-07-18 at 12.31.13

(Notice the Yes and No buttons instead of Ok and Cancel)

Also, no matter which button the user clicks, the integer value is always 1.

When running as standalone or as VST3 in Reaper the behaviour is correct:

Screenshot 2024-07-18 at 12.31.30

I suspect Bitwig might be using a different (older) version of the C++ runtime maybe?

Windows 11
Bitwig 5.1.9
JUCE 7.0.12

Anyone? Seems like a JUCE bug to me.

This seems to be a combination of a few issues.

  • The different dialog style (icons, button graphics) is likely because different hosts are loading different versions of the ComCtl32.dll library, which provides these dialogs. When we try to get the TaskDialogIndirect function while running in Bitwig, the lookup fails, which indicates that the version of this dll that is currently loaded doesn’t contain this symbol. I’m not sure whether we can work around this - we might just have to live with the host’s choice of dll version.
    • I checked the manifest of a JUCE VST3 plugin that uses the old dialog style under Bitwig:
      mt.exe -inputresource:<path-to-dll>;#1 -out:out.manifest
      
      The resulting human-readable manifest includes a <dependentAssembly> entry for Microsoft.Windows.Common-Controls version 6.0.0.0, but it’s possible this only has an effect for library symbols that are located when initially loading the comctl32 library. If we’re loading this library dynamically, it might be that we need to do some extra work to ensure we end up loading the correct version. I’ll investigate more tomorrow.
  • When running in Bitwig, we can’t create new-style dialogs, so we fall back to old-style dialogs. The old-style dialogs can only use a fixed set of button labels. JUCE will use OK/Cancel labels only if there are exactly two buttons and the text of the first button is “OK” (case sensitive!).
  • The issue with result codes is definitely a JUCE bug, I’ll put a fix together for that.

Thank you for looking into this.

I think this is perfectly reasonable and expected.

When running in Bitwig, we can’t create new-style dialogs, so we fall back to old-style dialogs

Also perfectly reasonable.

The issue with result codes is definitely a JUCE bug, I’ll put a fix together for that.

Great, thank you. I presume this will not end up in JUCE 7?

We’ve pushed a couple of related commits to develop.

The first commit fixes the result codes for old-style dialog boxes. This change is immediately obsoleted by the following commit, but we included it for the sake of completeness.

The second commit removes support for old-style dialogs completely, and instead always uses new-style dialogs. It seems that we can force this as long as we use symbols from ComCtl32.dll resolved at link-time, rather than attempting to load this library at runtime. We are able to do this now that JUCE no longer supports Windows versions earlier than Windows 10.

1 Like

Since the second commit it seems to me NativeMessageBoxes are broken on Windows. I’m using Windows 11 latest, Juce8 develop. I saw this first in my plugin and got really confused by it but then realized it happens in the DemoRunner if “Use Native Windows” is selected. This happens in both Debug and Release x64 builds and regardless of the renderer selected:

Often the dialog won’t even open and if it does, it seems to contain random garbage characters.

@reuk, I have verified this on a second machine now (just building, then activating “Use Native Windows” and clicking “Plain Alert Window”. Sometimes, it takes a few tries for any dialog to open.
I’m sorry, but I have to vent of some frustration after thinking for hours I had some crazy memory smashing bug in my plugin… was this change actually tested at all? How could it end up in the repo?

Thanks, I can repro and have a fix on the way. Not sure how I didn’t see this during testing. The issue is a use-after-free, so maybe I just got (un)lucky while I was testing and the string buffer wasn’t repurposed before it was read in TaskDialogIndirect().

1 Like

Thank you for the fix on develop. It works fine now!

For future reference, the fix is this patch:

Thanks again for reporting this issue, and apologies for introducing this regression.