A FYI for anyone using broadcastMessage to send inter-JUCE-application messages: be careful when broadcasting messages back and forth between JUCE apps (windows only). If you are receiving a broadcast message in your app, do NOT send a broadcast message back from within that receive routine or from any other thread until that receive routine returns. JUCE uses SendMessageTimeout with SMTO_BLOCK and you will get stuck in that infamous Windows SendMessage lock condition if you do this. With two apps, that means up to 16 seconds (8000ms timeout) of locking.
For those of you (like me) who must send broadcast messages back and forth (one of mine runs in a timer callback and it would be a really bad thing to spin lock within it) but want to avoid the lock condition, here is a quick and dirty fix:
In juce_MessageManager.h, replace:[code]
//==============================================================================
/** Sends a message to all other JUCE applications that are running.
@param messageText the string that will be passed to the actionListenerCallback()
method of the broadcast listeners in the other app.
@see registerBroadcastListener, ActionListener
*/
static void broadcastMessage (const String& messageText);[/code]
with:[code]
//==============================================================================
/** Sends a message to all other JUCE applications that are running.
@param messageText the string that will be passed to the actionListenerCallback()
method of the broadcast listeners in the other app.
@param wait true = waits until message has been processed by the receiving app
false = delivers message and immediately returns
@see registerBroadcastListener, ActionListener
*/
static void broadcastMessage (const String& messageText, bool wait=true);[/code]
and in juce_win32_Messaging.cpp, replace:[code]
//==============================================================================
static BOOL CALLBACK BroadcastEnumWindowProc (HWND hwnd, LPARAM lParam)
{
TCHAR windowName [64]; // no need to read longer strings than this
GetWindowText (hwnd, windowName, 64);
if (hwnd != juce_messageWindowHandle
&& String (windowName) == String (messageWindowName))
{
DWORD result;
SendMessageTimeout (hwnd, broadcastId, 0, lParam,
SMTO_BLOCK | SMTO_ABORTIFHUNG,
8000,
&result);
}
return TRUE;
}
void MessageManager::broadcastMessage (const String& value)
{
ATOM atom = GlobalAddAtom (value);
if (atom != 0)
{
EnumWindows (&BroadcastEnumWindowProc, (long) atom);
GlobalDeleteAtom (atom);
}
}
//==============================================================================[/code]
with:[code]
//==============================================================================
static HWND* handleArray = NULL;
static int* handleIndex = NULL;
static BOOL CALLBACK BroadcastEnumWindowProc (HWND hwnd, LPARAM lParam)
{
TCHAR windowName [64]; // no need to read longer strings than this
GetWindowText (hwnd, windowName, 64);
if (hwnd != juce_messageWindowHandle
&& String (windowName) == String (messageWindowName))
{
handleArray[(*handleIndex)++] = hwnd;
if(*handleIndex == HANDLEMAX)
return false;
}
return TRUE;
}
void MessageManager::broadcastMessage (const String& value, bool wait)
{
// Global atom strings cannot be longer than 255 characters
// Find some way of breaking up your strings into smaller pieces
jassert (value.length() < 255);
ATOM atom = GlobalAddAtom (value);
if (atom != 0)
{
// Initialize our array (trying to make it thread safe here)
int totalHandles = 0;
handleIndex = &totalHandles;
HWND windows[HANDLEMAX];
handleArray = windows;
// Get handles to all our top level windows
EnumWindows (&BroadcastEnumWindowProc, (long) atom);
// Now broadcast our message
for(int i = 0; i < totalHandles; i++)
{
DWORD result;
SendMessageTimeout (windows[i], broadcastId, 0, (long)atom,
(wait?SMTO_BLOCK:SMTO_NORMAL) | SMTO_ABORTIFHUNG,
8000,
&result);
}
GlobalDeleteAtom (atom);
}
}
//==============================================================================
[/code]
You can then set “wait” to false if your broadcast message is not a critical “must be received” event and you can tolerate some dropped messages.
A much better fix would be to receive the message, copy the data into a global, post a flag message, then return. The flag message would then deliver the broadcast data to the receiver. Unfortunately, I don’t have the time to do this myself, so the above fix will have to do for now.
As an aside, Jules, what’s up with using global atoms?? That was last fashionable around, oh, 1993 or so. A much better choice would be WM_COPYDATA – no 255 byte size limitation, no case insensitivty, plus we could pass around any sort of data, not just strings.
My $.02
- kbj