Ensure the lifetime of CPowerRenameProcessUI on the worker thread (#11106)

* Ensure the lifetime of CPowerRenameProcessUI on the worker thread to prevent AV during shutdown

* Ensure worker thread progress dialog pointer is valid.  Also add a call to StopProgressDialog from the worker thread as the progress dialog can be particular about thread affinity for that method call.

Co-authored-by: Chris Davis (EDGE) <chrdavis@microsoft.com>
This commit is contained in:
Chris Davis
2021-05-05 02:46:13 -07:00
committed by GitHub
parent 9d59709c6c
commit bf6dcf40ef

View File

@@ -1523,7 +1523,12 @@ HRESULT CPowerRenameProgressUI::Start()
{ {
_Cleanup(); _Cleanup();
m_canceled = false; m_canceled = false;
AddRef();
m_workerThreadHandle = CreateThread(nullptr, 0, s_workerThread, this, 0, nullptr); m_workerThreadHandle = CreateThread(nullptr, 0, s_workerThread, this, 0, nullptr);
if (!m_workerThreadHandle)
{
Release();
}
return (m_workerThreadHandle) ? S_OK : E_FAIL; return (m_workerThreadHandle) ? S_OK : E_FAIL;
} }
@@ -1538,20 +1543,22 @@ DWORD WINAPI CPowerRenameProgressUI::s_workerThread(_In_ void* pv)
SetTimer(hwndMessage, TIMERID_CHECKCANCELED, CANCEL_CHECK_INTERVAL, nullptr); SetTimer(hwndMessage, TIMERID_CHECKCANCELED, CANCEL_CHECK_INTERVAL, nullptr);
if (SUCCEEDED(CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&pThis->m_sppd)))) CComPtr<IProgressDialog> sppd;
if (SUCCEEDED(CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&sppd))))
{ {
pThis->m_sppd = sppd;
wchar_t buff[100] = { 0 }; wchar_t buff[100] = { 0 };
LoadString(g_hInst, IDS_LOADING, buff, ARRAYSIZE(buff)); LoadString(g_hInst, IDS_LOADING, buff, ARRAYSIZE(buff));
pThis->m_sppd->SetLine(1, buff, FALSE, NULL); sppd->SetLine(1, buff, FALSE, NULL);
LoadString(g_hInst, IDS_LOADING_MSG, buff, ARRAYSIZE(buff)); LoadString(g_hInst, IDS_LOADING_MSG, buff, ARRAYSIZE(buff));
pThis->m_sppd->SetLine(2, buff, FALSE, NULL); sppd->SetLine(2, buff, FALSE, NULL);
LoadString(g_hInst, IDS_APP_TITLE, buff, ARRAYSIZE(buff)); LoadString(g_hInst, IDS_APP_TITLE, buff, ARRAYSIZE(buff));
pThis->m_sppd->SetTitle(buff); sppd->SetTitle(buff);
SetTimer(hwndMessage, TIMERID_CHECKCANCELED, CANCEL_CHECK_INTERVAL, nullptr); SetTimer(hwndMessage, TIMERID_CHECKCANCELED, CANCEL_CHECK_INTERVAL, nullptr);
pThis->m_sppd->StartProgressDialog(NULL, NULL, PROGDLG_MARQUEEPROGRESS, NULL); sppd->StartProgressDialog(NULL, NULL, PROGDLG_MARQUEEPROGRESS, NULL);
} }
while (pThis->m_sppd && !pThis->m_canceled) while (pThis->m_sppd && !sppd->HasUserCancelled())
{ {
MSG msg; MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
@@ -1561,8 +1568,13 @@ DWORD WINAPI CPowerRenameProgressUI::s_workerThread(_In_ void* pv)
} }
} }
// Ensure dialog is stopped
sppd->StopProgressDialog();
KillTimer(hwndMessage, TIMERID_CHECKCANCELED); KillTimer(hwndMessage, TIMERID_CHECKCANCELED);
DestroyWindow(hwndMessage); DestroyWindow(hwndMessage);
pThis->Release();
} }
CoUninitialize(); CoUninitialize();
@@ -1587,9 +1599,12 @@ void CPowerRenameProgressUI::_Cleanup()
if (m_workerThreadHandle) if (m_workerThreadHandle)
{ {
// Wait for up to 5 seconds for worker thread to finish
WaitForSingleObject(m_workerThreadHandle, 5000);
CloseHandle(m_workerThreadHandle); CloseHandle(m_workerThreadHandle);
m_workerThreadHandle = nullptr; m_workerThreadHandle = nullptr;
} }
} }
void CPowerRenameProgressUI::_UpdateCancelState() void CPowerRenameProgressUI::_UpdateCancelState()
@@ -1634,6 +1649,7 @@ LRESULT CPowerRenameProgressUI::_WndProc(_In_ HWND hwnd, _In_ UINT msg, _In_ WPA
break; break;
case WM_DESTROY: case WM_DESTROY:
_UpdateCancelState();
KillTimer(hwnd, TIMERID_CHECKCANCELED); KillTimer(hwnd, TIMERID_CHECKCANCELED);
break; break;