Skip to content

Commit 68a03b2

Browse files
authored
[BROWSEUI][SHELL32] Prevent crash by unsubclassing DefView during teardown (reactos#9305)
CORE-20504
1 parent 90c6642 commit 68a03b2

4 files changed

Lines changed: 43 additions & 26 deletions

File tree

‎dll/win32/browseui/shellfind/CFindFolder.cpp‎

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ struct _SearchData
281281
CStringA szQueryU8;
282282
BOOL SearchHidden;
283283
CComPtr<CFindFolder> pFindFolder;
284+
UINT SearchId;
284285

286+
explicit _SearchData(UINT InitSearchId) : SearchId(InitSearchId) {}
285287
~_SearchData()
286288
{
287289
FreeList(pPaths);
@@ -528,6 +530,15 @@ static BOOL AttribHiddenMatch(DWORD FileAttributes, _SearchData *pSearchData)
528530
return FALSE;
529531
}
530532

533+
static inline void PostUpdate(UINT Msg, LPCWSTR pszText, const _SearchData &Data)
534+
{
535+
LPWSTR pszDup;
536+
if (FAILED(SHStrDupW(pszText, &pszDup)))
537+
return;
538+
if (!PostMessageW(Data.hwnd, Msg, Data.SearchId, (LPARAM)pszDup))
539+
SHFree(pszDup);
540+
}
541+
531542
static UINT RecursiveFind(LPCWSTR lpPath, _SearchData *pSearchData)
532543
{
533544
if (WaitForSingleObject(pSearchData->hStopEvent, 0) != WAIT_TIMEOUT)
@@ -558,26 +569,20 @@ static UINT RecursiveFind(LPCWSTR lpPath, _SearchData *pSearchData)
558569
FileNameMatch(FindData.cFileName, pSearchData) &&
559570
AttribHiddenMatch(FindData.dwFileAttributes, pSearchData))
560571
{
561-
LPWSTR pszPathDup;
562-
SHStrDupW(szPath, &pszPathDup);
563-
PostMessageW(pSearchData->hwnd, WM_SEARCH_ADD_RESULT, 0, (LPARAM)pszPathDup);
572+
PostUpdate(WM_SEARCH_ADD_RESULT, szPath, *pSearchData);
564573
uTotalFound++;
565574
}
566575
status.Format(IDS_SEARCH_FOLDER, FindData.cFileName);
567-
LPWSTR pszStatusDup;
568-
SHStrDupW(status.GetBuffer(), &pszStatusDup);
569-
PostMessageW(pSearchData->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM)pszStatusDup);
576+
PostUpdate(WM_SEARCH_UPDATE_STATUS, status.GetBuffer(), *pSearchData);
570577

571578
uTotalFound += RecursiveFind(szPath, pSearchData);
572579
}
573580
else if (FileNameMatch(FindData.cFileName, pSearchData)
574581
&& AttribHiddenMatch(FindData.dwFileAttributes, pSearchData)
575582
&& ContentsMatch(szPath, pSearchData))
576583
{
584+
PostUpdate(WM_SEARCH_ADD_RESULT, szPath, *pSearchData);
577585
uTotalFound++;
578-
LPWSTR pszPathDup;
579-
SHStrDupW(szPath, &pszPathDup);
580-
PostMessageW(pSearchData->hwnd, WM_SEARCH_ADD_RESULT, 0, (LPARAM)pszPathDup);
581586
}
582587
}
583588

@@ -607,9 +612,7 @@ DWORD WINAPI CFindFolder::SearchThreadProc(LPVOID lpParameter)
607612

608613
CStringW status;
609614
status.Format(IDS_SEARCH_FILES_FOUND, uTotalFound);
610-
LPWSTR pszStatusDup;
611-
SHStrDupW(status.GetBuffer(), &pszStatusDup);
612-
::PostMessageW(data->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM)pszStatusDup);
615+
PostUpdate(WM_SEARCH_UPDATE_STATUS, status.GetBuffer(), *data);
613616
::SendMessageW(data->hwnd, WM_SEARCH_STOP, 0, 0);
614617

615618
CloseHandle(data->hStopEvent);
@@ -652,7 +655,7 @@ LRESULT CFindFolder::StartSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &
652655
UINT uItemIndex;
653656
m_shellFolderView->RemoveObject(NULL, &uItemIndex);
654657

655-
_SearchData* pSearchData = new _SearchData();
658+
_SearchData* pSearchData = new _SearchData(++m_SearchId);
656659
pSearchData->pFindFolder = this;
657660
pSearchData->hwnd = m_hWnd;
658661

@@ -743,6 +746,16 @@ LRESULT CFindFolder::StopSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
743746
{
744747
SetEvent(m_hStopEvent);
745748
m_hStopEvent = NULL;
749+
750+
// Wait for all in-flight messages with data we need to free
751+
PostMessageW(WM_SEARCH_STOPPED, 0, 0);
752+
for (MSG msg; PeekMessageW(&msg, m_hWnd, WM_SEARCH_START, WM_SEARCH_STOPPED, PM_REMOVE);)
753+
{
754+
if (msg.message == WM_SEARCH_STOPPED)
755+
break;
756+
if (msg.message == WM_SEARCH_ADD_RESULT || msg.message == WM_SEARCH_UPDATE_STATUS)
757+
SHFree((void*)msg.lParam);
758+
}
746759
}
747760
return 0;
748761
}
@@ -753,6 +766,8 @@ LRESULT CFindFolder::AddResult(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bH
753766
return 0;
754767

755768
CComHeapPtr<WCHAR> lpPath((LPWSTR) lParam);
769+
if (wParam != m_SearchId)
770+
return 0;
756771

757772
CComHeapPtr<ITEMIDLIST> lpSearchPidl(_ILCreate(lpPath));
758773
if (lpSearchPidl)
@@ -767,11 +782,8 @@ LRESULT CFindFolder::AddResult(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bH
767782
LRESULT CFindFolder::UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
768783
{
769784
CComHeapPtr<WCHAR> status((LPWSTR) lParam);
770-
if (m_shellBrowser)
771-
{
785+
if (m_shellBrowser && wParam == m_SearchId)
772786
m_shellBrowser->SetStatusTextSB(status);
773-
}
774-
775787
return 0;
776788
}
777789

@@ -1211,6 +1223,11 @@ STDMETHODIMP CFindFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
12111223
}
12121224
case SFVM_WINDOWCLOSING:
12131225
{
1226+
SendMessage(WM_SEARCH_STOP, 0, 0);
1227+
1228+
// [CORE-20504] LVN_ITEMACTIVATE in the DefView ListView can trigger a navigation that destroys this IShellFolder,
1229+
// unsubclass now so we don't get a message after our "this" is dead.
1230+
UnsubclassWindow();
12141231
m_shellFolderView = NULL;
12151232
m_shellBrowser = NULL;
12161233
return S_OK;

‎dll/win32/browseui/shellfind/CFindFolder.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class CFindFolder :
7373
CComPtr<IShellFolderView> m_shellFolderView;
7474
CComPtr<IShellBrowser> m_shellBrowser;
7575
HANDLE m_hStopEvent;
76+
UINT m_SearchId = 0;
7677

7778
HRESULT GetFSFolderAndChild(LPCITEMIDLIST pidl, IShellFolder **ppSF, PCUITEMID_CHILD *ppidlLast = NULL);
7879
HRESULT GetFSFolder2AndChild(LPCITEMIDLIST pidl, IShellFolder2 **ppSF, PCUITEMID_CHILD *ppidlLast = NULL);

‎dll/win32/browseui/shellfind/shellfind.h‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@
2626

2727
#include "../resource.h"
2828

29-
#define WM_SEARCH_START WM_USER + 0
30-
#define WM_SEARCH_STOP WM_USER + 1
31-
#define WM_SEARCH_ADD_RESULT WM_USER + 2
32-
#define WM_SEARCH_UPDATE_STATUS WM_USER + 3
29+
#define WM_SEARCH_START (WM_USER + 0) // Must be ordered before any message with a payload
30+
#define WM_SEARCH_STOP (WM_USER + 1)
31+
#define WM_SEARCH_ADD_RESULT (WM_USER + 2)
32+
#define WM_SEARCH_UPDATE_STATUS (WM_USER + 3)
33+
#define WM_SEARCH_STOPPED (WM_USER + 9) // Must be ordered after any message with a payload
3334

3435
typedef struct tagLOCATIONITEM
3536
{

‎dll/win32/shell32/CDefView.cpp‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3254,16 +3254,14 @@ HRESULT WINAPI CDefView::DestroyViewWindow()
32543254
m_hMenu = NULL;
32553255
}
32563256

3257+
if (m_hWnd)
3258+
_DoFolderViewCB(SFVM_WINDOWCLOSING, (WPARAM)m_hWnd, 0);
3259+
32573260
if (m_ListView)
3258-
{
32593261
m_ListView.DestroyWindow();
3260-
}
32613262

32623263
if (m_hWnd)
3263-
{
3264-
_DoFolderViewCB(SFVM_WINDOWCLOSING, (WPARAM)m_hWnd, 0);
32653264
DestroyWindow();
3266-
}
32673265

32683266
m_pShellBrowser.Release();
32693267
m_pCommDlgBrowser.Release();

0 commit comments

Comments
 (0)