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:
parent
9549f8c95e
commit
b952d0204e
2 changed files with 35 additions and 17 deletions
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue