1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Windows: Added an overflow buffer to the event loop to catch messages posted after hitting the PostMessage() limit

This commit is contained in:
ed 2019-11-08 18:10:56 +00:00
parent 1fe5e49980
commit ce9bb8b605
2 changed files with 200 additions and 120 deletions

View file

@ -25,110 +25,90 @@ namespace juce
extern HWND juce_messageWindowHandle;
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
bool juce_isRunningInUnity();
#endif
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
LRESULT juce_offerEventToActiveXControl (::MSG&);
#endif
using CheckEventBlockedByModalComps = bool (*)(const MSG&);
CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr;
using SettingChangeCallbackFunc = void (*)(void);
SettingChangeCallbackFunc settingChangeCallback = nullptr;
//==============================================================================
class InternalMessageQueue
{
public:
InternalMessageQueue()
{
messageWindow = std::make_unique<HiddenMessageWindow> (messageWindowName, (WNDPROC) messageWndProc);
juce_messageWindowHandle = messageWindow->getHWND();
}
~InternalMessageQueue()
{
juce_messageWindowHandle = 0;
clearSingletonInstance();
}
JUCE_DECLARE_SINGLETON (InternalMessageQueue, false)
//==============================================================================
void broadcastMessage (const String& message)
{
auto localCopy = message;
Array<HWND> windows;
EnumWindows (&broadcastEnumWindowProc, (LPARAM) &windows);
for (int i = windows.size(); --i >= 0;)
{
COPYDATASTRUCT data;
data.dwData = broadcastMessageMagicNumber;
data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType);
data.lpData = (void*) localCopy.toUTF32().getAddress();
DWORD_PTR result;
SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA,
(WPARAM) juce_messageWindowHandle,
(LPARAM) &data,
SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result);
}
}
bool postMessage (MessageManager::MessageBase* message)
{
message->incReferenceCount();
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
bool juce_isRunningInUnity();
if (juce_isRunningInUnity())
return SendNotifyMessage (juce_messageWindowHandle, customMessageID, 0, (LPARAM) message) != 0;
#endif
//==============================================================================
namespace WindowsMessageHelpers
{
const unsigned int customMessageID = WM_USER + 123;
const unsigned int broadcastMessageMagicNumber = 0xc403;
if (PostMessage (juce_messageWindowHandle, customMessageID, 0, (LPARAM) message) != 0)
return true;
const TCHAR messageWindowName[] = _T("JUCEWindow");
std::unique_ptr<HiddenMessageWindow> messageWindow;
void dispatchMessageFromLParam (LPARAM lParam)
if (GetLastError() == ERROR_NOT_ENOUGH_QUOTA)
{
if (auto message = reinterpret_cast<MessageManager::MessageBase*> (lParam))
{
JUCE_TRY
{
message->messageCallback();
}
JUCE_CATCH_EXCEPTION
const ScopedLock sl (lock);
overflowQueue.add (message);
message->decReferenceCount();
}
return true;
}
BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam)
return false;
}
bool dispatchNextMessage (bool returnIfNoPendingMessages)
{
if (hwnd != juce_messageWindowHandle)
{
TCHAR windowName[64] = { 0 }; // no need to read longer strings than this
GetWindowText (hwnd, windowName, 63);
if (String (windowName) == messageWindowName)
reinterpret_cast<Array<HWND>*> (lParam)->add (hwnd);
}
return TRUE;
}
void handleBroadcastMessage (const COPYDATASTRUCT* data)
{
if (data != nullptr && data->dwData == broadcastMessageMagicNumber)
{
struct BroadcastMessage : public CallbackMessage
{
BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {}
void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); }
String message;
};
(new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData),
data->cbData / sizeof (CharPointer_UTF32::CharType)))
->post();
}
}
//==============================================================================
LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept
{
if (h == juce_messageWindowHandle)
{
if (message == customMessageID)
{
// (These are trapped early in our dispatch loop, but must also be checked
// here in case some 3rd-party code is running the dispatch loop).
dispatchMessageFromLParam (lParam);
return 0;
}
if (message == WM_COPYDATA)
{
handleBroadcastMessage (reinterpret_cast<const COPYDATASTRUCT*> (lParam));
return 0;
}
if (message == WM_SETTINGCHANGE)
if (settingChangeCallback != nullptr)
settingChangeCallback();
}
return DefWindowProc (h, message, wParam, lParam);
}
}
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
LRESULT juce_offerEventToActiveXControl (::MSG&);
#endif
//==============================================================================
bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
{
using namespace WindowsMessageHelpers;
MSG m;
if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE))
if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE) && overflowQueue.size() == 0)
return false;
if (GetMessage (&m, (HWND) 0, 0, 0) >= 0)
@ -165,57 +145,157 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMes
}
}
dispatchOverflowMessages();
return true;
}
private:
//==============================================================================
static LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept
{
if (h == juce_messageWindowHandle)
{
if (message == customMessageID)
{
// (These are trapped early in our dispatch loop, but must also be checked
// here in case some 3rd-party code is running the dispatch loop).
dispatchMessageFromLParam (lParam);
if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
queue->dispatchOverflowMessages();
return 0;
}
if (message == WM_COPYDATA)
{
handleBroadcastMessage (reinterpret_cast<const COPYDATASTRUCT*> (lParam));
return 0;
}
if (message == WM_SETTINGCHANGE)
if (settingChangeCallback != nullptr)
settingChangeCallback();
}
return DefWindowProc (h, message, wParam, lParam);
}
static BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam)
{
if (hwnd != juce_messageWindowHandle)
{
TCHAR windowName[64] = { 0 }; // no need to read longer strings than this
GetWindowText (hwnd, windowName, 63);
if (String (windowName) == messageWindowName)
reinterpret_cast<Array<HWND>*> (lParam)->add (hwnd);
}
return TRUE;
}
static void dispatchMessageFromLParam (LPARAM lParam)
{
if (auto message = reinterpret_cast<MessageManager::MessageBase*> (lParam))
{
JUCE_TRY
{
message->messageCallback();
}
JUCE_CATCH_EXCEPTION
message->decReferenceCount();
}
}
static void handleBroadcastMessage (const COPYDATASTRUCT* data)
{
if (data != nullptr && data->dwData == broadcastMessageMagicNumber)
{
struct BroadcastMessage : public CallbackMessage
{
BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {}
void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); }
String message;
};
(new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData),
data->cbData / sizeof (CharPointer_UTF32::CharType)))
->post();
}
}
void dispatchOverflowMessages()
{
const ScopedLock sl (lock);
for (int i = 0; i < overflowQueue.size(); ++i)
{
auto message = overflowQueue.getUnchecked (i);
message->incReferenceCount();
dispatchMessageFromLParam ((LPARAM) message.get());
}
overflowQueue.clear();
}
//==============================================================================
static constexpr unsigned int customMessageID = WM_USER + 123;
static constexpr unsigned int broadcastMessageMagicNumber = 0xc403;
static const TCHAR messageWindowName[];
std::unique_ptr<HiddenMessageWindow> messageWindow;
CriticalSection lock;
ReferenceCountedArray<MessageManager::MessageBase> overflowQueue;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalMessageQueue)
};
JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)
const TCHAR InternalMessageQueue::messageWindowName[] = _T("JUCEWindow");
//==============================================================================
bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
{
if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
return queue->dispatchNextMessage (returnIfNoPendingMessages);
return false;
}
bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
{
message->incReferenceCount();
if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
{
queue->postMessage (message);
return true;
}
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
if (juce_isRunningInUnity())
return SendNotifyMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0;
#endif
return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0;
return false;
}
void MessageManager::broadcastMessage (const String& value)
{
auto localCopy = value;
Array<HWND> windows;
EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows);
for (int i = windows.size(); --i >= 0;)
{
COPYDATASTRUCT data;
data.dwData = WindowsMessageHelpers::broadcastMessageMagicNumber;
data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType);
data.lpData = (void*) localCopy.toUTF32().getAddress();
DWORD_PTR result;
SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA,
(WPARAM) juce_messageWindowHandle,
(LPARAM) &data,
SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result);
}
if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
queue->broadcastMessage (value);
}
//==============================================================================
void MessageManager::doPlatformSpecificInitialisation()
{
OleInitialize (0);
using namespace WindowsMessageHelpers;
messageWindow.reset (new HiddenMessageWindow (messageWindowName, (WNDPROC) messageWndProc));
juce_messageWindowHandle = messageWindow->getHWND();
InternalMessageQueue::getInstance();
}
void MessageManager::doPlatformSpecificShutdown()
{
WindowsMessageHelpers::messageWindow = nullptr;
InternalMessageQueue::deleteInstance();
OleUninitialize();
}

View file

@ -56,7 +56,7 @@ extern void juce_repeatLastProcessPriority();
extern void juce_checkCurrentlyFocusedTopLevelWindow(); // in juce_TopLevelWindow.cpp
extern bool juce_isRunningInWine();
typedef bool (*CheckEventBlockedByModalComps) (const MSG&);
using CheckEventBlockedByModalComps = bool (*)(const MSG&);
extern CheckEventBlockedByModalComps isEventBlockedByModalComps;
static bool shouldDeactivateTitleBar = true;
@ -496,7 +496,7 @@ static double getGlobalDPI()
#endif
//==============================================================================
typedef void (*SettingChangeCallbackFunc) (void);
using SettingChangeCallbackFunc = void (*)(void);
extern SettingChangeCallbackFunc settingChangeCallback;
//==============================================================================