[NTOS:KE/x64] Handle NMI vs swapgs race condition
[reactos.git] / base / shell / explorer / taskband.cpp
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 /*****************************************************************************
24 ** CTaskBand ****************************************************************
25 *****************************************************************************/
26
27 const GUID CLSID_ITaskBand = { 0x68284FAA, 0x6A48, 0x11D0, { 0x8C, 0x78, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xB4 } };
28
29 class CTaskBand :
30 public CComCoClass<CTaskBand>,
31 public CComObjectRootEx<CComMultiThreadModelNoCS>,
32 public IObjectWithSite,
33 public IDeskBand,
34 public IDeskBar,
35 public IPersistStream,
36 public IWinEventHandler,
37 public IOleCommandTarget
38 {
39 CComPtr<ITrayWindow> m_Tray;
40 CComPtr<IUnknown> m_Site;
41 CComPtr<IUnknown> m_TasksWnd;
42
43 HWND m_hWnd;
44
45 public:
46 CTaskBand() :
47 m_hWnd(NULL)
48 {
49 }
50
51 virtual ~CTaskBand() { }
52
53 /*****************************************************************************/
54
55 virtual HRESULT STDMETHODCALLTYPE GetWindow(OUT HWND *phwnd)
56 {
57 if (!m_hWnd)
58 return E_FAIL;
59 if (!phwnd)
60 return E_INVALIDARG;
61 *phwnd = m_hWnd;
62 return S_OK;
63 }
64
65 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
66 IN BOOL fEnterMode)
67 {
68 /* FIXME: Implement */
69 return E_NOTIMPL;
70 }
71
72 virtual HRESULT STDMETHODCALLTYPE ShowDW(
73 IN BOOL bShow)
74 {
75 /* We don't do anything... */
76 return S_OK;
77 }
78
79 virtual HRESULT STDMETHODCALLTYPE CloseDW(
80 IN DWORD dwReserved)
81 {
82 /* We don't do anything... */
83 return S_OK;
84 }
85
86 virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(
87 LPCRECT prcBorder,
88 IUnknown *punkToolbarSite,
89 BOOL fReserved)
90 {
91 /* No need to implement this method */
92 return E_NOTIMPL;
93 }
94
95 virtual HRESULT STDMETHODCALLTYPE GetBandInfo(
96 IN DWORD dwBandID,
97 IN DWORD dwViewMode,
98 IN OUT DESKBANDINFO *pdbi)
99 {
100 TRACE("CTaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, m_hWnd);
101
102 if (m_hWnd != NULL)
103 {
104 HWND hwndToolbar = ::GetWindow(m_hWnd, GW_CHILD);
105
106 /* The task band never has a title */
107 pdbi->dwMask &= ~DBIM_TITLE;
108
109 /* NOTE: We don't return DBIMF_UNDELETEABLE here, the band site will
110 handle us differently and add this flag for us. The reason for
111 this is future changes that might allow it to be deletable.
112 We want the band site to be in charge of this decision rather
113 the band itself! */
114 /* FIXME: What about DBIMF_NOGRIPPER and DBIMF_ALWAYSGRIPPER */
115 pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT;
116
117 /* Obtain the button size, to be used as the minimum size */
118 DWORD size = SendMessageW(hwndToolbar, TB_GETBUTTONSIZE, 0, 0);
119 pdbi->ptMinSize.x = 0;
120 pdbi->ptMinSize.y = GET_Y_LPARAM(size);
121
122 if (dwViewMode & DBIF_VIEWMODE_VERTICAL)
123 {
124 pdbi->ptIntegral.x = 0;
125 pdbi->ptIntegral.y = 1;
126 }
127 else
128 {
129 pdbi->ptIntegral.x = 0;
130 pdbi->ptIntegral.y = GET_Y_LPARAM(size);
131 }
132
133 /* Ignored: pdbi->ptMaxSize.x */
134 pdbi->ptMaxSize.y = -1;
135
136 RECT rcToolbar;
137 ::GetWindowRect(hwndToolbar, &rcToolbar);
138 /* FIXME: We should query the height from the task bar object!!! */
139 pdbi->ptActual.x = rcToolbar.right - rcToolbar.left;
140 pdbi->ptActual.y = rcToolbar.bottom - rcToolbar.top;
141
142 TRACE("H: %d, Min: %d,%d, Integral.y: %d Actual: %d,%d\n", (dwViewMode & DBIF_VIEWMODE_VERTICAL) == 0,
143 pdbi->ptMinSize.x, pdbi->ptMinSize.y, pdbi->ptIntegral.y,
144 pdbi->ptActual.x, pdbi->ptActual.y);
145
146 return S_OK;
147 }
148
149 return E_FAIL;
150 }
151
152 /*****************************************************************************/
153 // *** IOleCommandTarget methods ***
154 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
155 {
156 UNIMPLEMENTED;
157 return E_NOTIMPL;
158 }
159
160 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
161 {
162 if (IsEqualIID(*pguidCmdGroup, IID_IBandSite))
163 {
164 return S_OK;
165 }
166
167 if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
168 {
169 return S_OK;
170 }
171
172 UNIMPLEMENTED;
173 return E_NOTIMPL;
174 }
175
176 /*****************************************************************************/
177
178 virtual HRESULT STDMETHODCALLTYPE SetClient(
179 IN IUnknown *punkClient)
180 {
181 TRACE("IDeskBar::SetClient(0x%p)\n", punkClient);
182 return E_NOTIMPL;
183 }
184
185 virtual HRESULT STDMETHODCALLTYPE GetClient(
186 OUT IUnknown **ppunkClient)
187 {
188 TRACE("IDeskBar::GetClient(0x%p)\n", ppunkClient);
189 return E_NOTIMPL;
190 }
191
192 virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(
193 IN RECT *prc)
194 {
195 TRACE("IDeskBar::OnPosRectChangeDB(0x%p=(%d,%d,%d,%d))\n", prc, prc->left, prc->top, prc->right, prc->bottom);
196 if (prc->bottom - prc->top == 0)
197 return S_OK;
198
199 return S_FALSE;
200 }
201
202 /*****************************************************************************/
203
204 virtual HRESULT STDMETHODCALLTYPE GetClassID(
205 OUT CLSID *pClassID)
206 {
207 TRACE("CTaskBand::GetClassID(0x%p)\n", pClassID);
208 /* We're going to return the (internal!) CLSID of the task band interface */
209 *pClassID = CLSID_ITaskBand;
210 return S_OK;
211 }
212
213 virtual HRESULT STDMETHODCALLTYPE IsDirty()
214 {
215 /* The object hasn't changed since the last save! */
216 return S_FALSE;
217 }
218
219 virtual HRESULT STDMETHODCALLTYPE Load(
220 IN IStream *pStm)
221 {
222 TRACE("CTaskBand::Load called\n");
223 /* Nothing to do */
224 return S_OK;
225 }
226
227 virtual HRESULT STDMETHODCALLTYPE Save(
228 IN IStream *pStm,
229 IN BOOL fClearDirty)
230 {
231 /* Nothing to do */
232 return S_OK;
233 }
234
235 virtual HRESULT STDMETHODCALLTYPE GetSizeMax(
236 OUT ULARGE_INTEGER *pcbSize)
237 {
238 TRACE("CTaskBand::GetSizeMax called\n");
239 /* We don't need any space for the task band */
240 pcbSize->QuadPart = 0;
241 return S_OK;
242 }
243
244 /*****************************************************************************/
245
246 virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite)
247 {
248 HRESULT hRet;
249 HWND hwndSite;
250
251 TRACE("CTaskBand::SetSite(0x%p)\n", pUnkSite);
252
253 hRet = IUnknown_GetWindow(pUnkSite, &hwndSite);
254 if (FAILED_UNEXPECTEDLY(hRet))
255 return hRet;
256
257 TRACE("CreateTaskSwitchWnd(Parent: 0x%p)\n", hwndSite);
258
259 hRet = CTaskSwitchWnd_CreateInstance(hwndSite, m_Tray, IID_PPV_ARG(IUnknown, &m_TasksWnd));
260 if (FAILED_UNEXPECTEDLY(hRet))
261 return hRet;
262
263 hRet = IUnknown_GetWindow(m_TasksWnd, &m_hWnd);
264 if (FAILED_UNEXPECTEDLY(hRet))
265 return hRet;
266
267 m_Site = pUnkSite;
268
269 return S_OK;
270 }
271
272 virtual HRESULT STDMETHODCALLTYPE GetSite(
273 IN REFIID riid,
274 OUT VOID **ppvSite)
275 {
276 TRACE("CTaskBand::GetSite(0x%p,0x%p)\n", riid, ppvSite);
277
278 if (m_Site != NULL)
279 {
280 return m_Site->QueryInterface(riid, ppvSite);
281 }
282
283 *ppvSite = NULL;
284 return E_FAIL;
285 }
286
287 /*****************************************************************************/
288
289 virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
290 IN HWND hWnd,
291 IN UINT uMsg,
292 IN WPARAM wParam,
293 IN LPARAM lParam,
294 OUT LRESULT *plrResult)
295 {
296 TRACE("CTaskBand: IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p)\n", hWnd, uMsg, wParam, lParam, plrResult);
297 return E_NOTIMPL;
298 }
299
300 virtual HRESULT STDMETHODCALLTYPE ContainsWindow(
301 IN HWND hWnd)
302 {
303 if (hWnd == m_hWnd ||
304 IsChild(m_hWnd, hWnd))
305 {
306 TRACE("CTaskBand::ContainsWindow(0x%p) returns S_OK\n", hWnd);
307 return S_OK;
308 }
309
310 return S_FALSE;
311 }
312
313 virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
314 {
315 //UNIMPLEMENTED;
316 return E_NOTIMPL;
317 }
318
319 virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd)
320 {
321 return (hWnd == m_hWnd) ? S_OK : S_FALSE;
322 }
323
324 /*****************************************************************************/
325
326 HRESULT STDMETHODCALLTYPE Initialize(IN OUT ITrayWindow *tray, HWND hWndStartButton)
327 {
328 m_Tray = tray;
329 return S_OK;
330 }
331
332 DECLARE_NOT_AGGREGATABLE(CTaskBand)
333
334 DECLARE_PROTECT_FINAL_CONSTRUCT()
335 BEGIN_COM_MAP(CTaskBand)
336 COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDeskBand)
337 COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
338 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
339 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
340 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
341 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
342 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
343 END_COM_MAP()
344 };
345
346 HRESULT CTaskBand_CreateInstance(IN ITrayWindow *Tray, HWND hWndStartButton, REFIID riid, void **ppv)
347 {
348 return ShellObjectCreatorInit<CTaskBand>(Tray, hWndStartButton, riid, ppv);
349 }