1515#include < uxtheme.h>
1616#include < map>
1717#include < algorithm>
18+ #include < thread>
1819
1920const 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+
12791316bool 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+ }
0 commit comments