xref: /reactos/base/shell/explorer/desktop.cpp (revision feff2b1e)
1 /*
2  * ReactOS Explorer
3  *
4  * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "precomp.h"
22 
23 class CDesktopThread
24 {
25 private:
26     CComPtr<ITrayWindow> m_Tray;
27     HANDLE m_hInitEvent;
28     HANDLE m_hThread;
29     DWORD m_ThreadId;
30 
31     DWORD DesktopThreadProc();
32     static DWORD WINAPI s_DesktopThreadProc(LPVOID lpParameter);
33 
34 public:
35     CDesktopThread();
36     ~CDesktopThread();
37 
38     HRESULT Initialize(ITrayWindow* pTray);
39     void Destroy();
40 };
41 
42 /*******************************************************************/
43 
CDesktopThread()44 CDesktopThread::CDesktopThread():
45     m_Tray(NULL),
46     m_hInitEvent(NULL),
47     m_hThread(NULL),
48     m_ThreadId(0)
49 {
50 }
51 
~CDesktopThread()52 CDesktopThread::~CDesktopThread()
53 {
54     Destroy();
55 }
56 
Initialize(ITrayWindow * pTray)57 HRESULT CDesktopThread::Initialize(ITrayWindow* pTray)
58 {
59     HANDLE Handles[2];
60 
61     if (!pTray || m_Tray)
62     {
63         return E_FAIL;
64     }
65 
66     m_hInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
67     if (!m_hInitEvent)
68     {
69         return E_FAIL;
70     }
71 
72     m_Tray = pTray;
73     m_hThread = CreateThread(NULL, 0, s_DesktopThreadProc, (LPVOID)this, 0, &m_ThreadId);
74 
75     if (!m_hThread)
76     {
77         CloseHandle(m_hInitEvent);
78         m_hInitEvent = NULL;
79 
80         m_Tray = NULL;
81 
82         return E_FAIL;
83     }
84 
85     Handles[0] = m_hThread;
86     Handles[1] = m_hInitEvent;
87 
88     for (;;)
89     {
90         DWORD WaitResult = MsgWaitForMultipleObjects(_countof(Handles), Handles, FALSE, INFINITE, QS_ALLEVENTS);
91 
92         if (WaitResult == WAIT_OBJECT_0 + _countof(Handles))
93         {
94             TrayProcessMessages(m_Tray);
95         }
96         else if (WaitResult != WAIT_FAILED && WaitResult != WAIT_OBJECT_0)
97         {
98             break;
99         }
100         else
101         {
102             CloseHandle(m_hThread);
103             m_hThread = NULL;
104             m_ThreadId = 0;
105 
106             CloseHandle(m_hInitEvent);
107             m_hInitEvent = NULL;
108 
109             m_Tray = NULL;
110 
111             return E_FAIL;
112         }
113     }
114     return S_OK;
115 }
116 
Destroy()117 void CDesktopThread::Destroy()
118 {
119     if (m_hThread)
120     {
121         DWORD WaitResult = WaitForSingleObject(m_hThread, 0);
122         if (WaitResult == WAIT_TIMEOUT)
123         {
124             /* Send WM_QUIT message to the thread and wait for it to terminate */
125             PostThreadMessageW(m_ThreadId, WM_QUIT, 0, 0);
126             WaitForSingleObject(m_hThread, INFINITE);
127         }
128 
129         CloseHandle(m_hThread);
130         m_hThread = NULL;
131         m_ThreadId = 0;
132     }
133 
134     if (m_hInitEvent)
135     {
136         CloseHandle(m_hInitEvent);
137         m_hInitEvent = NULL;
138     }
139 
140     m_Tray = NULL;
141 }
142 
DesktopThreadProc()143 DWORD CDesktopThread::DesktopThreadProc()
144 {
145     CComPtr<IShellDesktopTray> pSdt;
146     HANDLE hDesktop;
147     HRESULT hRet;
148     DWORD dwResult = 1;
149 
150     OleInitialize(NULL);
151 
152     hRet = m_Tray->QueryInterface(IID_PPV_ARG(IShellDesktopTray, &pSdt));
153     if (!SUCCEEDED(hRet))
154     {
155         goto Cleanup;
156     }
157 
158     hDesktop = _SHCreateDesktop(pSdt);
159     if (!hDesktop)
160     {
161         goto Cleanup;
162     }
163 
164     if (!SetEvent(m_hInitEvent))
165     {
166         /* Failed to notify that we initialized successfully, kill ourselves
167          * to make the main thread wake up! */
168         goto Cleanup;
169     }
170 
171     _SHDesktopMessageLoop(hDesktop);
172     dwResult = 0;
173 
174 Cleanup:
175     OleUninitialize();
176     return dwResult;
177 }
178 
s_DesktopThreadProc(LPVOID lpParameter)179 DWORD WINAPI CDesktopThread::s_DesktopThreadProc(LPVOID lpParameter)
180 {
181     CDesktopThread* pDesktopThread = static_cast<CDesktopThread*>(lpParameter);
182     return pDesktopThread->DesktopThreadProc();
183 }
184 
185 /*******************************************************************/
186 
187 HANDLE
DesktopCreateWindow(IN OUT ITrayWindow * Tray)188 DesktopCreateWindow(IN OUT ITrayWindow *Tray)
189 {
190     CDesktopThread* pDesktopThread = new CDesktopThread();
191 
192     HRESULT hres = pDesktopThread->Initialize(Tray);
193     if (FAILED_UNEXPECTEDLY(hres))
194     {
195         delete pDesktopThread;
196         return NULL;
197     }
198 
199     return pDesktopThread;
200 }
201 
202 VOID
DesktopDestroyShellWindow(IN HANDLE hDesktop)203 DesktopDestroyShellWindow(IN HANDLE hDesktop)
204 {
205     CDesktopThread* pDesktopThread = reinterpret_cast<CDesktopThread*>(hDesktop);
206     delete pDesktopThread;
207 }
208