What it really comes down to is that initialiseJuce_GUI() really has to be called on the main thread, so we’ve got to find something that gets called by that.
How about the DllMain call? Does that happen on the gui thread?
Agh… How do other plugins possibly work?? In windows it’s just not possible to send or receive messages unless you get at least a brief chance to run on the thread that’s going to be running the dispatch loop.
I don’t think we can make wavelab create the gui from its main thread.
I found a discussion of others who had the same problem using wxWidgets for the gui here:
And since I assume, making juce deal with the situation that a host doesn’t create and manipulate the gui from its mainthread would mean a huge effort, the chances are not very good to make juce and wavelab work together.
Just wondering if there is any other options since wavelab is a very important audio editor with a lot of users and not being able to support it is a major issue. It’s amazing that steinberg decided on different implementations of their own format across their own audio software.
I’m pretty stumped by this one, but am still pondering it. We can get a handle on the main window, and from that can get the main thread ID. It might be possible to create juce’s messaging window on a background thread but then attach it to their main thread somehow…
This won’t work, I think. I did a lot of testing and it was possible to get a handle on the main window, but this is not handled by the main thread. To be more specific, when I call
"DWORD threadId = GetWindowThreadProcessId (hwnd, &processId);"
and hwnd is the main window handle, then the returned threadId is definetly not the main thread…
The strange thing is, that when Wavelab starts up and recognizes a new plugin for the first time, the plugin gets checked and the complete WIN32 startup section in the juce_VST_Wrapper gets called from Wavelabs main thread. But when you open the plugin, the WIN32 startup section is called from a background thread. It will never be called from the main thread again, untill the plugin was recompiled and therefore Wavelab does its initial check again.
Any headway with the wavelab issue? There must be a way as it stands no Juce plugin is working… Please jules if you have the time it would be greatly appreciated if you can have a look in to this again.
It seems that this issue only affects version >= 1.50 of the juce framework. I tried the juce VST plugin demo(juce_vst.dll) of a 1.46 release and it worked without any problems in wavelab. The new one(JuceDemoPlugin.dll) of 1.50 doesnt work anymore.
[quote=“patrickkunz”]It seems that this issue only affects version >= 1.50 of the juce framework. I tried the juce VST plugin demo(juce_vst.dll) of a 1.46 release and it worked without any problems in wavelab. The new one(JuceDemoPlugin.dll) of 1.50 doesnt work anymore.
Hope this helps finding the issue.[/quote]
Sorry, I think that 1.46 just appeared to work because it wasn’t correctly locking the message manager, so never caused a deadlock. It might have worked, but only by chance - it certainly wasn’t thread-safe.
Yep, the difference to 1.46 is that the dispatcher didn’t use the MessageManagerLocks then. Without the locks there’s no issues in Wavelab. Now admittedly I’m not quite “threadsafe” myself but couldn’t it be that the MessageManagerLocks are not needed when the dispatcher is called from a background thread like in Wavelab? I.e. could one check for that and only create the MessageManagerLocks when actually needed? If this is completely stupid then beat me… but please tell me why it’s stupid before.
It might work in your special case, but this is definetly no solution. I tried two of my plugins without that lock and although they where loaded into wavelab, there was a lot of strange behaviour and after a while some moreless random crashes, especially when working with timers and threads (maybe coincidence, but it seemed to me like this).
So there is still no solution to load juce plugins into wavelab.
Basically, it merges the inputs/dispatch loop of 2 threads, so your plugin will receive the same message as the main thread.
Or you could use the GetThreadTimes (returns the thread creation time) to figure out the first thread (it’s the main thread).
I’ve managed to find the ID of the main thread in wavelab in a pretty hacky way by assuming that the main thread owns most of the windows for the respective process ID.
HWND h = ::GetTopWindow(0 );
Array<int> ThreadIds,Counts;
int i,maxcount=0;
DWORD pid,dwThreadId;
while ( h )
{
dwThreadId = ::GetWindowThreadProcessId( h,&pid);
if ( pid == GetCurrentProcessId())
{
if (ThreadIds.contains((int) dwThreadId))
{
i=ThreadIds.indexOf((int) dwThreadId);
Counts.set(i,Counts[i]+1);
}
else
{
ThreadIds.add((int) dwThreadId);
Counts.add(1);
}
}
h = ::GetNextWindow( h , GW_HWNDNEXT);
if (h== ::GetTopWindow(0)) break;
}
for (i=Counts.size();--i>=0;)
{
if (Counts[i]>maxcount)
{
maxcount=Counts[i];
dwThreadId=ThreadIds[i];
}
}
After this, dwThreadId contains the main thread id (of course it COULD go wrong if a worker thread has more windows than the main thread but practically it seems to work).
However, even if I assign the current message thread in the messager to this ID I still get stuck in the endless loop that friscokid figured out. At this point I realized that there’s probably a problem with the loop itself when there’s no thread or no job to check, as in our case. So I changed it from
if ((threadToCheck!=0) || job!=0)
{
while (! events->lockedEvent.wait (50))
{
if ((threadToCheck->threadShouldExit()) || (job->shouldExit()))
{
events->releaseEvent.signal();
events->decReferenceCount();
MessageManager::instance->lockingLock.exit();
return;
}
}
}
and got rid of all the stuff with the thread ID again. Seems to work… any objections? Do I still need to change the current message thread ID? Doesn’t seem to make a difference but I have tested it only briefly.
Haha, you’re right… after a few hours of searching for a way to get the main thread ID my mind probably shut down. But ok, suppose I have the main thread ID (be it by checking the windows or the thread times), is there anything else except setting the message thread ID that I’d have to take care of (in the way you outlined a few posts earlier) ? Because that didn’t work here…
Well, the tricky bit would be ensuring the MessageManager::doPlatformSpecificInitialisation() is first called by the thread that you find. Probably the only way to do that would be with a SendAsyncProc call.