https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1aa95f389772901970369afa3abfb207df6f57f6

commit 1aa95f389772901970369afa3abfb207df6f57f6
Author:     Thamatip Chitpong <[email protected]>
AuthorDate: Tue May 24 18:58:24 2022 +0700
Commit:     GitHub <[email protected]>
CommitDate: Tue May 24 14:58:24 2022 +0300

    [EXPLORER] Implement CDesktopThread::Destroy (#4371)
    
    Now Explorer exits properly without using ExitProcess hack.
    
    Signed-off-by: Thamatip Chitpong <[email protected]>
    Reviewed-by: Mark Jansen <[email protected]>
    Reviewed-by: Hermès Bélusca-Maïto <[email protected]>
    Reviewed-by: Stanislav Motylkov <[email protected]>
---
 base/shell/explorer/desktop.cpp | 186 +++++++++++++++++++++++++++-------------
 1 file changed, 126 insertions(+), 60 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,97 +22,163 @@
 
 class CDesktopThread
 {
-    HANDLE m_hEvent;
+private:
     CComPtr<ITrayWindow> m_Tray;
+    HANDLE m_hInitEvent;
+    HANDLE m_hThread;
 
-    DWORD DesktopThreadProc()
-    {
-        CComPtr<IShellDesktopTray> pSdt;
-        HANDLE hDesktop;
-        HRESULT hRet;
+    DWORD DesktopThreadProc();
+    static DWORD WINAPI s_DesktopThreadProc(LPVOID lpParameter);
 
-        OleInitialize(NULL);
+public:
+    CDesktopThread();
+    ~CDesktopThread();
 
-        hRet = m_Tray->QueryInterface(IID_PPV_ARG(IShellDesktopTray, &pSdt));
-        if (!SUCCEEDED(hRet))
-            return 1;
+    HRESULT Initialize(ITrayWindow* pTray);
+    void Destroy();
+};
 
-        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;
-        }
+CDesktopThread::CDesktopThread():
+    m_Tray(NULL),
+    m_hInitEvent(NULL),
+    m_hThread(NULL)
+{
+}
 
-        _SHDesktopMessageLoop(hDesktop);
+CDesktopThread::~CDesktopThread()
+{
+    Destroy();
+}
 
-        /* FIXME: Properly rundown the main thread! */
-        ExitProcess(0);
+HRESULT CDesktopThread::Initialize(ITrayWindow* pTray)
+{
+    HANDLE Handles[2];
 
-        return 0;
+    if (!pTray || m_Tray)
+    {
+        return E_FAIL;
     }
 
-    static DWORD CALLBACK s_DesktopThreadProc(IN OUT LPVOID lpParameter)
+    m_hInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+    if (!m_hInitEvent)
     {
-        return 
reinterpret_cast<CDesktopThread*>(lpParameter)->DesktopThreadProc();
+        return E_FAIL;
     }
 
-public:
-    CDesktopThread() :
-        m_hEvent(NULL),
-        m_Tray(NULL)
+    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;
     }
 
-    HRESULT Initialize(IN OUT ITrayWindow *pTray)
+    Handles[0] = m_hThread;
+    Handles[1] = m_hInitEvent;
+
+    for (;;)
     {
-        HANDLE hThread;
-        HANDLE Handles[2];
+        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;
 
-        m_Tray = pTray;
+            CloseHandle(m_hInitEvent);
+            m_hInitEvent = NULL;
 
-        m_hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-        if (!m_hEvent)
-            return E_FAIL;
+            m_Tray = NULL;
 
-        hThread = CreateThread(NULL, 0, s_DesktopThreadProc, (PVOID)this, 0, 
NULL);
-        if (!hThread)
-        {
-            CloseHandle(m_hEvent);
             return E_FAIL;
         }
+    }
+    return S_OK;
+}
 
-        Handles[0] = hThread;
-        Handles[1] = m_hEvent;
-
-        for (;;)
+void CDesktopThread::Destroy()
+{
+    if (m_hThread)
+    {
+        DWORD WaitResult = WaitForSingleObject(m_hThread, 0);
+        if (WaitResult == WAIT_TIMEOUT)
         {
-            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;
-            }
+            /* 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(hThread);
-        CloseHandle(m_hEvent);
+        CloseHandle(m_hThread);
+        m_hThread = NULL;
+    }
 
-        return S_OK;
+    if (m_hInitEvent)
+    {
+        CloseHandle(m_hInitEvent);
+        m_hInitEvent = NULL;
     }
 
-    void Destroy()
+    m_Tray = NULL;
+}
+
+DWORD CDesktopThread::DesktopThreadProc()
+{
+    CComPtr<IShellDesktopTray> pSdt;
+    HANDLE hDesktop;
+    HRESULT hRet;
+    DWORD dwResult = 1;
+
+    OleInitialize(NULL);
+
+    hRet = m_Tray->QueryInterface(IID_PPV_ARG(IShellDesktopTray, &pSdt));
+    if (!SUCCEEDED(hRet))
     {
-        return;
+        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<CDesktopThread*>(lpParameter);
+    return pDesktopThread->DesktopThreadProc();
+}
+
+/*******************************************************************/
 
 HANDLE
 DesktopCreateWindow(IN OUT ITrayWindow *Tray)
@@ -133,5 +199,5 @@ VOID
 DesktopDestroyShellWindow(IN HANDLE hDesktop)
 {
     CDesktopThread* pDesktopThread = 
reinterpret_cast<CDesktopThread*>(hDesktop);
-    pDesktopThread->Destroy();
+    delete pDesktopThread;
 }

Reply via email to