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