Skip to content

Commit b207064

Browse files
authored
Fix open/save file dialog getting stuck after Windows 11 update (#2457)
We will run those APIs on separate STA thread and pump messages while waiting for the dialog to end. fixes #2431 fixes #2426 fixes #2418 fixes #2417 fixes #2390 fixes #2372 fixes #2371 fixes #2370 fixes #2364 fixes #2361 fixes #2360 fixes #2343 fixes #2332 fixes #2322 fixes #2320 fixes #2319 fixes #2312 fixes #2299
1 parent 7566280 commit b207064

3 files changed

Lines changed: 94 additions & 7 deletions

File tree

Src/Lib/Settings.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,7 +1670,7 @@ LRESULT CSettingsDlg::OnBackup( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
16701670
ofn.lpstrTitle=title;
16711671
ofn.lpstrDefExt=L".xml";
16721672
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
1673-
if (GetSaveFileName(&ofn))
1673+
if (GetSaveFileNameSafe(&ofn))
16741674
{
16751675
CString err=g_SettingsManager.SaveSettingsXml(path);
16761676
if (!err.IsEmpty())
@@ -1699,7 +1699,7 @@ LRESULT CSettingsDlg::OnBackup( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
16991699
CString title=LoadStringEx(IDS_XML_TITLE_LOAD);
17001700
ofn.lpstrTitle=title;
17011701
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
1702-
if (GetOpenFileName(&ofn))
1702+
if (GetOpenFileNameSafe(&ofn))
17031703
{
17041704
SetCurTab(m_Index,true); // reload tab once to force-close any active edit boxes
17051705
CString error=g_SettingsManager.LoadSettingsXml(path);

Src/Lib/SettingsUIHelper.cpp

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <uxtheme.h>
1616
#include <map>
1717
#include <algorithm>
18+
#include <thread>
1819

1920
const KNOWNFOLDERID FOLDERID_DesktopRoot={'DESK', 'TO', 'P', {'D', 'E', 'S', 'K', 'T', 'O', 'P', 0x00}};
2021

@@ -1193,7 +1194,7 @@ bool BrowseCommandHelper( HWND parent, wchar_t *text )
11931194
ofn.lpstrFile=text;
11941195
ofn.nMaxFile=_MAX_PATH;
11951196
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR|OFN_NODEREFERENCELINKS;
1196-
if (GetOpenFileName(&ofn))
1197+
if (GetOpenFileNameSafe(&ofn))
11971198
{
11981199
wchar_t buf[_MAX_PATH];
11991200
UnExpandEnvStrings(text,buf,_countof(buf));
@@ -1216,7 +1217,8 @@ bool BrowseCommandHelper( HWND parent, wchar_t *text )
12161217
return false;
12171218
}
12181219

1219-
bool BrowseLinkHelper( HWND parent, wchar_t *text, bool bFoldersOnly )
1220+
// Internal implementation that must be run on an STA thread with COM initialized.
1221+
static bool BrowseLinkHelperImpl( HWND parent, wchar_t *text, bool bFoldersOnly )
12201222
{
12211223
DoEnvironmentSubst(text,_MAX_PATH);
12221224

@@ -1276,6 +1278,41 @@ bool BrowseLinkHelper( HWND parent, wchar_t *text, bool bFoldersOnly )
12761278
return pResult!=NULL;
12771279
}
12781280

1281+
// Run IFileOpenDialog on a separate STA thread and pump messages on the caller while waiting.
1282+
bool BrowseLinkHelper( HWND parent, wchar_t *text, bool bFoldersOnly )
1283+
{
1284+
bool result = false;
1285+
1286+
std::thread worker([&parent, &text, &bFoldersOnly, &result]() mutable {
1287+
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1288+
result = BrowseLinkHelperImpl(parent, text, bFoldersOnly);
1289+
CoUninitialize();
1290+
});
1291+
1292+
// Pump messages while waiting for the worker (dialog) to finish
1293+
while (true)
1294+
{
1295+
HANDLE hWorker = worker.native_handle();
1296+
if (MsgWaitForMultipleObjects(1, &hWorker, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0)
1297+
break;
1298+
1299+
MSG msg;
1300+
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1301+
{
1302+
if (msg.message == WM_QUIT)
1303+
{
1304+
PostQuitMessage((int)msg.wParam);
1305+
break;
1306+
}
1307+
TranslateMessage(&msg);
1308+
DispatchMessage(&msg);
1309+
}
1310+
}
1311+
worker.join();
1312+
1313+
return result;
1314+
}
1315+
12791316
bool BrowseIconHelper( HWND parent, wchar_t *text )
12801317
{
12811318
int id=0;
@@ -2011,7 +2048,7 @@ LRESULT CBrowseForIconDlg::OnBrowse( WORD wNotifyCode, WORD wID, HWND hWndCtl, B
20112048
CString title=LoadStringEx(IDS_ICON_TITLE);
20122049
ofn.lpstrTitle=title;
20132050
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
2014-
if (GetOpenFileName(&ofn))
2051+
if (GetOpenFileNameSafe(&ofn))
20152052
{
20162053
wchar_t buf[_MAX_PATH];
20172054
UnExpandEnvStrings(path,buf,_countof(buf));
@@ -2210,7 +2247,7 @@ bool BrowseForBitmap( HWND hWndParent, wchar_t *path, bool bAllowJpeg )
22102247
CString title=LoadStringEx(IDS_BMP_TITLE);
22112248
ofn.lpstrTitle=title;
22122249
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
2213-
if (GetOpenFileName(&ofn))
2250+
if (GetOpenFileNameSafe(&ofn))
22142251
{
22152252
wchar_t buf[_MAX_PATH];
22162253
UnExpandEnvStrings(path,buf,_countof(buf));
@@ -2242,7 +2279,7 @@ bool BrowseForSound( HWND hWndParent, wchar_t *path )
22422279
CString title=LoadStringEx(IDS_WAV_TITLE);
22432280
ofn.lpstrTitle=title;
22442281
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
2245-
if (GetOpenFileName(&ofn))
2282+
if (GetOpenFileNameSafe(&ofn))
22462283
{
22472284
wchar_t buf[_MAX_PATH];
22482285
UnExpandEnvStrings(path,buf,_countof(buf));
@@ -3630,3 +3667,49 @@ DWORD ParseColor(const wchar_t* str)
36303667
wchar_t* end;
36313668
return wcstoul(str, &end, 16) & 0xFFFFFF;
36323669
}
3670+
3671+
// Run GetOpenFileName/GetSaveFileName on a separate STA thread and pump messages on the caller
3672+
template <typename auto Fnc>
3673+
static BOOL GetFileNameSafe(OPENFILENAME* pOfn)
3674+
{
3675+
BOOL result = FALSE;
3676+
3677+
std::thread worker([&pOfn, &result]() mutable {
3678+
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
3679+
result = Fnc(pOfn);
3680+
CoUninitialize();
3681+
});
3682+
3683+
// Pump messages while waiting for the worker (dialog) to finish
3684+
while (true)
3685+
{
3686+
HANDLE hWorker = worker.native_handle();
3687+
if (MsgWaitForMultipleObjects(1, &hWorker, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0)
3688+
break;
3689+
3690+
MSG msg;
3691+
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
3692+
{
3693+
if (msg.message == WM_QUIT)
3694+
{
3695+
PostQuitMessage((int)msg.wParam);
3696+
break;
3697+
}
3698+
TranslateMessage(&msg);
3699+
DispatchMessage(&msg);
3700+
}
3701+
}
3702+
worker.join();
3703+
3704+
return result;
3705+
}
3706+
3707+
BOOL GetOpenFileNameSafe(OPENFILENAME* pOfn)
3708+
{
3709+
return GetFileNameSafe<GetOpenFileNameW>(pOfn);
3710+
}
3711+
3712+
BOOL GetSaveFileNameSafe(OPENFILENAME* pOfn)
3713+
{
3714+
return GetFileNameSafe<GetSaveFileNameW>(pOfn);
3715+
}

Src/Lib/SettingsUIHelper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,7 @@ DWORD BgrToRgb(DWORD val);
395395

396396
// parse color from hexadecimal string
397397
DWORD ParseColor(const wchar_t* str);
398+
399+
// safe versions of GetOpenFileName/GetSaveFileName (run API on a separate STA thread and pump messages on the caller)
400+
BOOL GetOpenFileNameSafe(OPENFILENAME* pOfn);
401+
BOOL GetSaveFileNameSafe(OPENFILENAME* pOfn);

0 commit comments

Comments
 (0)