From 1aa95f389772901970369afa3abfb207df6f57f6 Mon Sep 17 00:00:00 2001 From: Thamatip Chitpong Date: Tue, 24 May 2022 18:58:24 +0700 Subject: [PATCH] [EXPLORER] Implement CDesktopThread::Destroy (#4371) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now Explorer exits properly without using ExitProcess hack. Signed-off-by: Thamatip Chitpong Reviewed-by: Mark Jansen Reviewed-by: Hermès Bélusca-Maïto Reviewed-by: Stanislav Motylkov --- base/shell/explorer/desktop.cpp | 238 ++++++++++++++++++++------------ 1 file changed, 152 insertions(+), 86 deletions(-) diff --git a/base/shell/explorer/desktop.cpp b/base/shell/explorer/desktop.cpp index 94a30ea4cd7..764c9b0f975 100644 --- a/base/shell/explorer/desktop.cpp +++ b/base/shell/explorer/desktop.cpp @@ -22,98 +22,164 @@ class CDesktopThread { - HANDLE m_hEvent; +private: CComPtr m_Tray; + HANDLE m_hInitEvent; + HANDLE m_hThread; - DWORD DesktopThreadProc() - { - CComPtr pSdt; - HANDLE hDesktop; - HRESULT hRet; - - OleInitialize(NULL); - - hRet = m_Tray->QueryInterface(IID_PPV_ARG(IShellDesktopTray, &pSdt)); - if (!SUCCEEDED(hRet)) - return 1; - - hDesktop = _SHCreateDesktop(pSdt); - if (hDesktop == NULL) - return 1; - - if (!SetEvent(m_hEvent)) - { - /* Failed to notify that we initialized successfully, kill ourselves - to make the main thread wake up! */ - return 1; - } - - _SHDesktopMessageLoop(hDesktop); - - /* FIXME: Properly rundown the main thread! */ - ExitProcess(0); - - return 0; - } - - static DWORD CALLBACK s_DesktopThreadProc(IN OUT LPVOID lpParameter) - { - return reinterpret_cast(lpParameter)->DesktopThreadProc(); - } + DWORD DesktopThreadProc(); + static DWORD WINAPI s_DesktopThreadProc(LPVOID lpParameter); public: - CDesktopThread() : - m_hEvent(NULL), - m_Tray(NULL) - { - } + CDesktopThread(); + ~CDesktopThread(); - HRESULT Initialize(IN OUT ITrayWindow *pTray) - { - HANDLE hThread; - HANDLE Handles[2]; - - m_Tray = pTray; - - m_hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!m_hEvent) - return E_FAIL; - - hThread = CreateThread(NULL, 0, s_DesktopThreadProc, (PVOID)this, 0, NULL); - if (!hThread) - { - CloseHandle(m_hEvent); - return E_FAIL; - } - - Handles[0] = hThread; - Handles[1] = m_hEvent; - - for (;;) - { - DWORD WaitResult = MsgWaitForMultipleObjects(_countof(Handles), Handles, FALSE, INFINITE, QS_ALLEVENTS); - if (WaitResult == WAIT_OBJECT_0 + _countof(Handles)) - { - TrayProcessMessages(m_Tray); - } - else if (WaitResult != WAIT_FAILED && WaitResult != WAIT_OBJECT_0) - { - break; - } - } - - CloseHandle(hThread); - CloseHandle(m_hEvent); - - return S_OK; - } - - void Destroy() - { - return; - } + HRESULT Initialize(ITrayWindow* pTray); + void Destroy(); }; +/*******************************************************************/ + +CDesktopThread::CDesktopThread(): + m_Tray(NULL), + m_hInitEvent(NULL), + m_hThread(NULL) +{ +} + +CDesktopThread::~CDesktopThread() +{ + Destroy(); +} + +HRESULT CDesktopThread::Initialize(ITrayWindow* pTray) +{ + HANDLE Handles[2]; + + if (!pTray || m_Tray) + { + return E_FAIL; + } + + m_hInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!m_hInitEvent) + { + return E_FAIL; + } + + m_Tray = pTray; + m_hThread = CreateThread(NULL, 0, s_DesktopThreadProc, (LPVOID)this, 0, NULL); + + if (!m_hThread) + { + CloseHandle(m_hInitEvent); + m_hInitEvent = NULL; + + m_Tray = NULL; + + return E_FAIL; + } + + Handles[0] = m_hThread; + Handles[1] = m_hInitEvent; + + for (;;) + { + DWORD WaitResult = MsgWaitForMultipleObjects(_countof(Handles), Handles, FALSE, INFINITE, QS_ALLEVENTS); + + if (WaitResult == WAIT_OBJECT_0 + _countof(Handles)) + { + TrayProcessMessages(m_Tray); + } + else if (WaitResult != WAIT_FAILED && WaitResult != WAIT_OBJECT_0) + { + break; + } + else + { + CloseHandle(m_hThread); + m_hThread = NULL; + + CloseHandle(m_hInitEvent); + m_hInitEvent = NULL; + + m_Tray = NULL; + + return E_FAIL; + } + } + return S_OK; +} + +void CDesktopThread::Destroy() +{ + if (m_hThread) + { + DWORD WaitResult = WaitForSingleObject(m_hThread, 0); + if (WaitResult == WAIT_TIMEOUT) + { + /* Send WM_QUIT message to the thread and wait for it to terminate */ + PostThreadMessageW(GetThreadId(m_hThread), WM_QUIT, 0, 0); + WaitForSingleObject(m_hThread, INFINITE); + } + + CloseHandle(m_hThread); + m_hThread = NULL; + } + + if (m_hInitEvent) + { + CloseHandle(m_hInitEvent); + m_hInitEvent = NULL; + } + + m_Tray = NULL; +} + +DWORD CDesktopThread::DesktopThreadProc() +{ + CComPtr pSdt; + HANDLE hDesktop; + HRESULT hRet; + DWORD dwResult = 1; + + OleInitialize(NULL); + + hRet = m_Tray->QueryInterface(IID_PPV_ARG(IShellDesktopTray, &pSdt)); + if (!SUCCEEDED(hRet)) + { + goto Cleanup; + } + + hDesktop = _SHCreateDesktop(pSdt); + if (!hDesktop) + { + goto Cleanup; + } + + if (!SetEvent(m_hInitEvent)) + { + /* Failed to notify that we initialized successfully, kill ourselves + * to make the main thread wake up! */ + goto Cleanup; + } + + _SHDesktopMessageLoop(hDesktop); + dwResult = 0; + +Cleanup: + OleUninitialize(); + return dwResult; +} + +DWORD WINAPI CDesktopThread::s_DesktopThreadProc(LPVOID lpParameter) +{ + CDesktopThread* pDesktopThread = static_cast(lpParameter); + return pDesktopThread->DesktopThreadProc(); +} + +/*******************************************************************/ + HANDLE DesktopCreateWindow(IN OUT ITrayWindow *Tray) { @@ -133,5 +199,5 @@ VOID DesktopDestroyShellWindow(IN HANDLE hDesktop) { CDesktopThread* pDesktopThread = reinterpret_cast(hDesktop); - pDesktopThread->Destroy(); + delete pDesktopThread; }