* Sync up to trunk HEAD (r62285). Branch guys deserve the significant speedups too ;)
[reactos.git] / base / shell / rshell / CMenuSite.cpp
1 /*
2 * Shell Menu Site
3 *
4 * Copyright 2014 David Quintana
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 St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22 #include <atlwin.h>
23 #include <shlwapi_undoc.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL(menusite);
26
27 class CMenuSite :
28 public CComObjectRootEx<CComMultiThreadModelNoCS>,
29 public CWindowImpl<CMenuSite, CWindow, CControlWinTraits>,
30 public IBandSite,
31 public IDeskBarClient,
32 public IOleCommandTarget,
33 public IInputObject,
34 public IInputObjectSite,
35 public IWinEventHandler,
36 public IServiceProvider
37 {
38 private:
39 CComPtr<IUnknown> m_DeskBarSite;
40 CComPtr<IUnknown> m_BandObject;
41 CComPtr<IDeskBand> m_DeskBand;
42 CComPtr<IWinEventHandler> m_WinEventHandler;
43 HWND m_hWndBand;
44
45 public:
46 CMenuSite();
47 ~CMenuSite() {}
48
49 DECLARE_WND_CLASS_EX(_T("MenuSite"), 0, COLOR_MENU)
50
51 DECLARE_NOT_AGGREGATABLE(CMenuSite)
52 DECLARE_PROTECT_FINAL_CONSTRUCT()
53 BEGIN_COM_MAP(CMenuSite)
54 COM_INTERFACE_ENTRY_IID(IID_IBandSite, IBandSite)
55 COM_INTERFACE_ENTRY_IID(IID_IDeskBarClient, IDeskBarClient)
56 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
57 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
58 COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject)
59 COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite)
60 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
61 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
62 END_COM_MAP()
63
64 // IBandSite
65 virtual HRESULT STDMETHODCALLTYPE AddBand(IUnknown * punk);
66 virtual HRESULT STDMETHODCALLTYPE EnumBands(UINT uBand, DWORD* pdwBandID);
67 virtual HRESULT STDMETHODCALLTYPE QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName);
68 virtual HRESULT STDMETHODCALLTYPE GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv);
69
70 // IDeskBarClient
71 virtual HRESULT STDMETHODCALLTYPE SetDeskBarSite(IUnknown *punkSite);
72 virtual HRESULT STDMETHODCALLTYPE GetSize(DWORD dwWhich, LPRECT prc);
73 virtual HRESULT STDMETHODCALLTYPE UIActivateDBC(DWORD dwState);
74
75 // IOleWindow
76 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
77
78 // IOleCommandTarget
79 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText);
80 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID * pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
81
82 // IInputObject
83 virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg);
84 virtual HRESULT STDMETHODCALLTYPE HasFocusIO();
85 virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg);
86
87 // IInputObjectSite
88 virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus);
89
90 // IWinEventHandler
91 virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd);
92 virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult);
93
94 // IServiceProvider
95 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
96
97
98 // Using custom message map instead
99 virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD mapId = 0);
100
101 // UNIMPLEMENTED
102 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
103 virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(BANDSITEINFO *pbsinfo);
104 virtual HRESULT STDMETHODCALLTYPE RemoveBand(DWORD dwBandID);
105 virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(const BANDSITEINFO *pbsinfo);
106 virtual HRESULT STDMETHODCALLTYPE SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState);
107 virtual HRESULT STDMETHODCALLTYPE SetModeDBC(DWORD dwMode);
108
109 private:
110 IUnknown * ToIUnknown() { return static_cast<IDeskBarClient*>(this); }
111 };
112
113 extern "C"
114 HRESULT CMenuSite_Constructor(REFIID riid, LPVOID *ppv)
115 {
116 *ppv = NULL;
117
118 CMenuSite * site = new CComObject<CMenuSite>();
119
120 if (!site)
121 return E_OUTOFMEMORY;
122
123 HRESULT hr = site->QueryInterface(riid, ppv);
124
125 if (FAILED(hr))
126 site->Release();
127
128 return hr;
129 }
130
131 CMenuSite::CMenuSite() :
132 m_DeskBarSite(NULL),
133 m_BandObject(NULL),
134 m_DeskBand(NULL),
135 m_WinEventHandler(NULL),
136 m_hWndBand(NULL)
137 {
138 }
139
140 HRESULT STDMETHODCALLTYPE CMenuSite::ContextSensitiveHelp(BOOL fEnterMode)
141 {
142 return E_NOTIMPL;
143 }
144
145 HRESULT STDMETHODCALLTYPE CMenuSite::GetBandSiteInfo(BANDSITEINFO *pbsinfo)
146 {
147 return E_NOTIMPL;
148 }
149
150 HRESULT STDMETHODCALLTYPE CMenuSite::RemoveBand(DWORD dwBandID)
151 {
152 return E_NOTIMPL;
153 }
154
155 HRESULT STDMETHODCALLTYPE CMenuSite::SetBandSiteInfo(const BANDSITEINFO *pbsinfo)
156 {
157 return E_NOTIMPL;
158 }
159
160 HRESULT STDMETHODCALLTYPE CMenuSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
161 {
162 return E_NOTIMPL;
163 }
164
165 HRESULT STDMETHODCALLTYPE CMenuSite::SetModeDBC(DWORD dwMode)
166 {
167 return E_NOTIMPL;
168 }
169
170 HRESULT STDMETHODCALLTYPE CMenuSite::TranslateAcceleratorIO(LPMSG lpMsg)
171 {
172 return S_FALSE;
173 }
174
175 HRESULT STDMETHODCALLTYPE CMenuSite::HasFocusIO()
176 {
177 return S_FALSE;
178 }
179
180 HRESULT STDMETHODCALLTYPE CMenuSite::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
181 {
182 return S_OK;
183 }
184
185 HRESULT STDMETHODCALLTYPE CMenuSite::AddBand(IUnknown * punk)
186 {
187 HRESULT hr;
188
189 #define TO_HRESULT(x) ((HRESULT)(S_OK+(x)))
190
191 if (SHIsSameObject(punk, m_BandObject))
192 return TO_HRESULT(0);
193
194 if (m_BandObject)
195 {
196 hr = IUnknown_SetSite(m_BandObject, NULL);
197 if (FAILED(hr))
198 return hr;
199 }
200
201 m_BandObject = NULL;
202 m_DeskBand = NULL;
203 m_WinEventHandler = NULL;
204 m_hWndBand = NULL;
205
206 if (!punk)
207 return TO_HRESULT(0);
208
209 hr = punk->QueryInterface(IID_PPV_ARG(IDeskBand, &m_DeskBand));
210 if (FAILED(hr))
211 return hr;
212
213 hr = punk->QueryInterface(IID_PPV_ARG(IWinEventHandler, &m_WinEventHandler));
214 if (FAILED(hr))
215 return hr;
216
217 hr = IUnknown_SetSite(punk, this->ToIUnknown());
218 if (FAILED(hr))
219 return hr;
220
221 hr = IUnknown_GetWindow(punk, &m_hWndBand);
222 if (FAILED(hr))
223 return hr;
224
225 m_BandObject = punk;
226
227 punk->AddRef();
228
229 return TO_HRESULT(0);
230 }
231
232 HRESULT STDMETHODCALLTYPE CMenuSite::EnumBands(UINT uBand, DWORD* pdwBandID)
233 {
234 if (uBand != 0)
235 return E_FAIL;
236
237 *pdwBandID = 0;
238
239 return S_OK;
240 }
241
242 HRESULT STDMETHODCALLTYPE CMenuSite::Exec(const GUID * pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
243 {
244 return IUnknown_Exec(m_DeskBarSite, *pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
245 }
246
247 HRESULT STDMETHODCALLTYPE CMenuSite::GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv)
248 {
249 if (dwBandID != 0 || m_BandObject == NULL)
250 {
251 *ppv = NULL;
252 return E_NOINTERFACE;
253 }
254
255 return m_BandObject->QueryInterface(riid, ppv);
256 }
257
258 HRESULT STDMETHODCALLTYPE CMenuSite::GetSize(DWORD dwWhich, LPRECT prc)
259 {
260 memset(prc, 0, sizeof(*prc));
261
262 if (dwWhich != 0)
263 return S_OK;
264
265 if (m_DeskBand == NULL)
266 return S_OK;
267
268 DESKBANDINFO info = { 0 };
269 info.dwMask = DBIM_MAXSIZE;
270
271 m_DeskBand->GetBandInfo(0, 0, &info);
272
273 prc->right = info.ptMaxSize.x;
274 prc->bottom = info.ptMaxSize.y;
275
276 return S_OK;
277 }
278
279 HRESULT STDMETHODCALLTYPE CMenuSite::GetWindow(HWND *phwnd)
280 {
281 if (!IsWindow())
282 return E_FAIL;
283
284 *phwnd = m_hWnd;
285
286 return S_OK;
287 }
288
289 HRESULT STDMETHODCALLTYPE CMenuSite::IsWindowOwner(HWND hWnd)
290 {
291 if (hWnd == m_hWnd)
292 return S_OK;
293
294 if (!m_WinEventHandler)
295 return S_FALSE;
296
297 return m_WinEventHandler->IsWindowOwner(hWnd);
298 }
299
300 HRESULT STDMETHODCALLTYPE CMenuSite::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
301 {
302 if (!m_WinEventHandler)
303 return S_OK;
304
305 return m_WinEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
306 }
307
308 HRESULT STDMETHODCALLTYPE CMenuSite::QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName)
309 {
310 if (dwBandID != 0)
311 return E_FAIL;
312
313 if (!m_BandObject)
314 {
315 *ppstb = NULL;
316 return E_NOINTERFACE;
317 }
318
319 HRESULT hr = m_BandObject->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
320
321 *pdwState = 1;
322
323 if (cchName > 0)
324 pszName[0] = 0;
325
326 return hr;
327 }
328
329 HRESULT STDMETHODCALLTYPE CMenuSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
330 {
331 *ppvObject = NULL;
332
333 if (IsEqualGUID(guidService, SID_SMenuBandBottom) ||
334 IsEqualGUID(guidService, SID_SMenuBandBottomSelected) ||
335 IsEqualGUID(guidService, SID_SMenuBandChild))
336 {
337 if (m_BandObject == NULL)
338 return E_FAIL;
339
340 return IUnknown_QueryService(m_BandObject, guidService, riid, ppvObject);
341 }
342
343 if (!m_DeskBarSite)
344 return E_FAIL;
345
346 return IUnknown_QueryService(m_DeskBarSite, guidService, riid, ppvObject);
347 }
348
349 HRESULT STDMETHODCALLTYPE CMenuSite::QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
350 {
351 if (!m_DeskBarSite)
352 return E_FAIL;
353
354 return IUnknown_QueryStatus(m_DeskBarSite, *pguidCmdGroup, cCmds, prgCmds, pCmdText);
355 }
356
357 HRESULT STDMETHODCALLTYPE CMenuSite::SetDeskBarSite(IUnknown *punkSite)
358 {
359 HRESULT hr;
360
361 CComPtr<IUnknown> protectThis(this->ToIUnknown());
362
363 if (punkSite)
364 {
365 HWND hWndSite;
366
367 m_DeskBarSite = NULL;
368
369 hr = IUnknown_GetWindow(punkSite, &hWndSite);
370
371 if (FAILED(hr) || !hWndSite)
372 return E_FAIL;
373
374 if (!m_hWnd)
375 {
376 Create(hWndSite, NULL, L"MenuSite");
377 }
378
379 m_DeskBarSite = punkSite;
380
381 return S_OK;
382 }
383
384 if (m_DeskBand)
385 {
386 m_DeskBand->CloseDW(0);
387 }
388
389 hr = IUnknown_SetSite(m_BandObject, NULL);
390
391 m_BandObject = NULL;
392 m_DeskBand = NULL;
393 m_WinEventHandler = NULL;
394 m_hWndBand = NULL;
395 m_hWnd = NULL;
396 m_DeskBarSite = NULL;
397
398 return S_OK;
399 }
400
401 HRESULT STDMETHODCALLTYPE CMenuSite::UIActivateDBC(DWORD dwState)
402 {
403 if (!m_DeskBand)
404 return S_OK;
405
406 return m_DeskBand->ShowDW(dwState != 0);
407 }
408
409 HRESULT STDMETHODCALLTYPE CMenuSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
410 {
411 if (lpMsg)
412 return E_FAIL;
413
414 return IUnknown_UIActivateIO(m_BandObject, fActivate, lpMsg);
415 }
416
417 BOOL CMenuSite::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD mapId)
418 {
419 HWND hWndTarget = NULL;
420 CComPtr<IUnknown> protectThis(this->ToIUnknown());
421
422 switch (uMsg)
423 {
424 case WM_SIZE:
425 if (m_BandObject)
426 {
427 CComPtr<IMenuPopup> pMenuPopup;
428 if (SUCCEEDED(m_BandObject->QueryInterface(IID_PPV_ARG(IMenuPopup, &pMenuPopup))))
429 {
430 RECT Rect = { 0 };
431 GetClientRect(&Rect);
432 Rect.right = Rect.right;
433 pMenuPopup->OnPosRectChangeDB(&Rect);
434 }
435 }
436 hWndTarget = hWnd;
437 lResult = 1;
438 break;
439 case WM_NOTIFY:
440 hWndTarget = reinterpret_cast<LPNMHDR>(lParam)->hwndFrom;
441 break;
442 case WM_COMMAND:
443 hWndTarget = (HWND) lParam;
444 break;
445 default:
446 return FALSE;
447 }
448
449 if (hWndTarget && m_WinEventHandler &&
450 m_WinEventHandler->IsWindowOwner(hWndTarget) == S_OK)
451 {
452 if (SUCCEEDED(m_WinEventHandler->OnWinEvent(hWndTarget, uMsg, wParam, lParam, &lResult)))
453 return TRUE;
454 }
455
456 return FALSE;
457 }