Here’s the fix. Jules, please feel free to add it to the code base!
Background: VST 2.4 uses Mac Roman encoding on the Mac and CP-1252 (Windows Latin) on Windows. The solution is to convert these to and from Juce Strings. The implementation below does the converion in one direction only, but the other way around is very similar (you can probably just use the same system functions). The best place to put this code is probably in class String, although for the sake of not hackiong the Juce code base, I had to put it elsewhere as a static:
[code]const String stringFromPlatformEncodedString (const char* sourceString)
{
if (sourceString == 0 || strlen (sourceString) == 0)
return String::empty;
#if JUCE_MAC
UniChar buffer[1024] = {0};
CFStringRef cs = CFStringCreateWithCString (kCFAllocatorDefault, sourceString, kCFStringEncodingMacRoman);
CFRange range;
range.location = 0;
range.length = jmin (1024, (int)CFStringGetLength (cs));
CFStringGetCharacters (cs, range, buffer);
const String result (CharPointer_UTF16 ((int16*)&buffer));
CFRelease (cs);
return result;
#elif JUCE_WINDOWS
// 65001 is utf-8, 1252 is Windows Latin1.
const int codePage = 1252;
int sourceLength = strlen (sourceString);
int requiredSize = MultiByteToWideChar (codePage, 0, sourceString, sourceLength, 0, 0);
if (requiredSize == 0)
return String::empty;
HeapBlock <wchar_t> buffer;
buffer.calloc (requiredSize + 1);
buffer[requiredSize] = 0;
int result = MultiByteToWideChar (codePage, 0, sourceString, sourceLength, buffer, requiredSize);
if (result == 0)
return String::empty;
else
return String (CharPointer_UTF16 (buffer.getData()));
#else
// Other platforms ?
return String (platformEncodedString);
#endif
}[/code]
As a consequence, all VST-specific string API must be changed to use the conversion: juce_VST_Wrapper.cpp: getProgramName(), getProgramNameIndexed(), etc, are all using UTF8, which is wrong. Also need to change juce_VSTPluginFormat.cpp: VSTPluginInstance::getProgramName(), VSTPluginInstance::getCurrentProgramName(), VSTPluginInstance::getParameterName(), VSTPluginInstance::getParameterLabel(), … you get the idea 
The change looks similar in all functions: