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

FileChooser: Pump message thread in destructor

IFileDialog::Show and CoUninitialize both seem to require the main
message loop to be active and running when they are called. If we block
the message thread while calling these functions, we may cause a
deadlock.

The destructor of the Win32NativeFileChooser was blocking the message
thread until the background thread exited, but the background thread was
unable to make progress while the message thread was blocked.

To work around this issue, we now pump the message thread in the
destructor of the Win32NativeFileChooser. If a dialog is currently
active, this should allow it to exit gracefully.

Note that we cannot use MessageManager::runDispatchLoopUntil here:
- MessageManager::runDispatchLoopUntil will not process any messages if
  the quit message has been received, which could lead to deadlocks if the
  FileChooser is destroyed after the quit message has been posted.
- This function isn't defined when JUCE_MODAL_LOOPS_PERMITTED is disabled.
This commit is contained in:
reuk 2021-03-29 15:13:55 +01:00
parent 9549f8c95e
commit b952d0204e
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11
2 changed files with 35 additions and 17 deletions

View file

@ -260,7 +260,7 @@ JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)
const TCHAR InternalMessageQueue::messageWindowName[] = _T("JUCEWindow");
//==============================================================================
bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
bool windowsDispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
{
if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
return queue->dispatchNextMessage (returnIfNoPendingMessages);
@ -268,6 +268,11 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMes
return false;
}
bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
{
return windowsDispatchNextMessageOnSystemQueue (returnIfNoPendingMessages);
}
bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
{
if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())

View file

@ -26,6 +26,9 @@
namespace juce
{
// Implemented in juce_win32_Messageing.cpp
bool windowsDispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
class Win32NativeFileChooser : public std::enable_shared_from_this<Win32NativeFileChooser>,
private Thread
{
@ -72,7 +75,12 @@ public:
~Win32NativeFileChooser() override
{
signalThreadShouldExit();
waitForThreadToExit (-1);
while (isThreadRunning())
{
if (! windowsDispatchNextMessageOnSystemQueue (true))
Thread::sleep (1);
}
}
void open (bool async)
@ -229,7 +237,15 @@ private:
{
explicit Events (Win32NativeFileChooser& o) : owner (o) {}
JUCE_COMRESULT OnTypeChange (IFileDialog* d) override
JUCE_COMRESULT OnTypeChange (IFileDialog* d) override { return updateHwnd (d); }
JUCE_COMRESULT OnFolderChanging (IFileDialog* d, IShellItem*) override { return updateHwnd (d); }
JUCE_COMRESULT OnFileOk (IFileDialog* d) override { return updateHwnd (d); }
JUCE_COMRESULT OnFolderChange (IFileDialog* d) override { return updateHwnd (d); }
JUCE_COMRESULT OnSelectionChange (IFileDialog* d) override { return updateHwnd (d); }
JUCE_COMRESULT OnShareViolation (IFileDialog* d, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) override { return updateHwnd (d); }
JUCE_COMRESULT OnOverwrite (IFileDialog* d, IShellItem*, FDE_OVERWRITE_RESPONSE*) override { return updateHwnd (d); }
JUCE_COMRESULT updateHwnd (IFileDialog* d)
{
HWND hwnd = nullptr;
IUnknown_GetWindow (d, &hwnd);
@ -244,13 +260,6 @@ private:
return S_OK;
}
JUCE_COMRESULT OnFolderChanging (IFileDialog*, IShellItem*) override { return E_NOTIMPL; }
JUCE_COMRESULT OnFileOk (IFileDialog*) override { return E_NOTIMPL; }
JUCE_COMRESULT OnFolderChange (IFileDialog*) override { return E_NOTIMPL; }
JUCE_COMRESULT OnSelectionChange (IFileDialog*) override { return E_NOTIMPL; }
JUCE_COMRESULT OnShareViolation (IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) override { return E_NOTIMPL; }
JUCE_COMRESULT OnOverwrite (IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) override { return E_NOTIMPL; }
Win32NativeFileChooser& owner;
};
@ -491,16 +500,20 @@ private:
void run() override
{
struct ScopedCoInitialize
auto resultsCopy = [&]
{
// IUnknown_GetWindow will only succeed when instantiated in a single-thread apartment
ScopedCoInitialize() { CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); }
~ScopedCoInitialize() { CoUninitialize(); }
};
struct ScopedCoInitialize
{
// IUnknown_GetWindow will only succeed when instantiated in a single-thread apartment
ScopedCoInitialize() { CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); }
~ScopedCoInitialize() { CoUninitialize(); }
};
ScopedCoInitialize scope;
ScopedCoInitialize scope;
return openDialog (true);
}();
auto resultsCopy = openDialog (true);
auto safeOwner = owner;
auto weakThisCopy = weakThis;