xref: /reactos/base/shell/explorer/desktop.cpp (revision 22f0c3a8)
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 
30     DWORD DesktopThreadProc();
31     static DWORD WINAPI s_DesktopThreadProc(LPVOID lpParameter);
32 
33 public:
34     CDesktopThread();
35     ~CDesktopThread();
36 
37     HRESULT Initialize(ITrayWindow* pTray);
38     void Destroy();
39 };
40 
41 /*******************************************************************/
42 
43 CDesktopThread::CDesktopThread():
44     m_Tray(NULL),
45     m_hInitEvent(NULL),
46     m_hThread(NULL)
47 {
48 }
49 
50 CDesktopThread::~CDesktopThread()
51 {
52     Destroy();
53 }
54 
55 HRESULT CDesktopThread::Initialize(ITrayWindow* pTray)
56 {
57     HANDLE Handles[2];
58 
59     if (!pTray || m_Tray)
60     {
61         return E_FAIL;
62     }
63 
64     m_hInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
65     if (!m_hInitEvent)
66     {
67         return E_FAIL;
68     }
69 
70     m_Tray = pTray;
71     m_hThread = CreateThread(NULL, 0, s_DesktopThreadProc, (LPVOID)this, 0, NULL);
72 
73     if (!m_hThread)
74     {
75         CloseHandle(m_hInitEvent);
76         m_hInitEvent = NULL;
77 
78         m_Tray = NULL;
79 
80         return E_FAIL;
81     }
82 
83     Handles[0] = m_hThread;
84     Handles[1] = m_hInitEvent;
85 
86     for (;;)
87     {
88         DWORD WaitResult = MsgWaitForMultipleObjects(_countof(Handles), Handles, FALSE, INFINITE, QS_ALLEVENTS);
89 
90         if (WaitResult == WAIT_OBJECT_0 + _countof(Handles))
91         {
92             TrayProcessMessages(m_Tray);
93         }
94         else if (WaitResult != WAIT_FAILED && WaitResult != WAIT_OBJECT_0)
95         {
96             break;
97         }
98         else
99         {
100             CloseHandle(m_hThread);
101             m_hThread = NULL;
102 
103             CloseHandle(m_hInitEvent);
104             m_hInitEvent = NULL;
105 
106             m_Tray = NULL;
107 
108             return E_FAIL;
109         }
110     }
111     return S_OK;
112 }
113 
114 void CDesktopThread::Destroy()
115 {
116     if (m_hThread)
117     {
118         DWORD WaitResult = WaitForSingleObject(m_hThread, 0);
119         if (WaitResult == WAIT_TIMEOUT)
120         {
121             /* Send WM_QUIT message to the thread and wait for it to terminate */
122             PostThreadMessageW(GetThreadId(m_hThread), WM_QUIT, 0, 0);
123             WaitForSingleObject(m_hThread, INFINITE);
124         }
125 
126         CloseHandle(m_hThread);
127         m_hThread = NULL;
128     }
129 
130     if (m_hInitEvent)
131     {
132         CloseHandle(m_hInitEvent);
133         m_hInitEvent = NULL;
134     }
135 
136     m_Tray = NULL;
137 }
138 
139 DWORD CDesktopThread::DesktopThreadProc()
140 {
141     CComPtr<IShellDesktopTray> pSdt;
142     HANDLE hDesktop;
143     HRESULT hRet;
144     DWORD dwResult = 1;
145 
146     OleInitialize(NULL);
147 
148     hRet = m_Tray->QueryInterface(IID_PPV_ARG(IShellDesktopTray, &pSdt));
149     if (!SUCCEEDED(hRet))
150     {
151         goto Cleanup;
152     }
153 
154     hDesktop = _SHCreateDesktop(pSdt);
155     if (!hDesktop)
156     {
157         goto Cleanup;
158     }
159 
160     if (!SetEvent(m_hInitEvent))
161     {
162         /* Failed to notify that we initialized successfully, kill ourselves
163          * to make the main thread wake up! */
164         goto Cleanup;
165     }
166 
167     _SHDesktopMessageLoop(hDesktop);
168     dwResult = 0;
169 
170 Cleanup:
171     OleUninitialize();
172     return dwResult;
173 }
174 
175 DWORD WINAPI CDesktopThread::s_DesktopThreadProc(LPVOID lpParameter)
176 {
177     CDesktopThread* pDesktopThread = static_cast<CDesktopThread*>(lpParameter);
178     return pDesktopThread->DesktopThreadProc();
179 }
180 
181 /*******************************************************************/
182 
183 HANDLE
184 DesktopCreateWindow(IN OUT ITrayWindow *Tray)
185 {
186     CDesktopThread* pDesktopThread = new CDesktopThread();
187 
188     HRESULT hres = pDesktopThread->Initialize(Tray);
189     if (FAILED_UNEXPECTEDLY(hres))
190     {
191         delete pDesktopThread;
192         return NULL;
193     }
194 
195     return pDesktopThread;
196 }
197 
198 VOID
199 DesktopDestroyShellWindow(IN HANDLE hDesktop)
200 {
201     CDesktopThread* pDesktopThread = reinterpret_cast<CDesktopThread*>(hDesktop);
202     delete pDesktopThread;
203 }
204