[RSHELL]
[reactos.git] / base / shell / rshell / CMenuDeskBar.cpp
1 /*
2 * Shell Menu Desk Bar
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 #include "precomp.h"
21 #include <atlwin.h>
22 #include <shlwapi_undoc.h>
23
24 WINE_DEFAULT_DEBUG_CHANNEL(CMenuDeskBar);
25
26 const static GUID CGID_MenuDeskBar = { 0x5C9F0A12, 0x959E, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x08, 0x26, 0x36 } };
27
28 typedef CWinTraits<
29 WS_POPUP | WS_DLGFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
30 WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_PALETTEWINDOW
31 > CMenuWinTraits;
32
33 class CMenuDeskBar :
34 public CWindowImpl<CMenuDeskBar, CWindow, CMenuWinTraits>,
35 public CComCoClass<CMenuDeskBar>,
36 public CComObjectRootEx<CComMultiThreadModelNoCS>,
37 public IOleCommandTarget,
38 public IServiceProvider,
39 public IInputObjectSite,
40 public IInputObject,
41 public IMenuPopup,
42 public IObjectWithSite,
43 public IBanneredBar,
44 public IInitializeObject
45 {
46 private:
47 CComPtr<IUnknown> m_Site;
48 CComPtr<IUnknown> m_Client;
49 CComPtr<IMenuPopup> m_SubMenuParent;
50 CComPtr<IMenuPopup> m_SubMenuChild;
51
52 HWND m_ClientWindow;
53
54 DWORD m_IconSize;
55 HBITMAP m_Banner;
56
57 INT m_Level;
58
59 BOOL m_Shown;
60
61 public:
62 CMenuDeskBar();
63 ~CMenuDeskBar();
64
65 DECLARE_NOT_AGGREGATABLE(CMenuDeskBar)
66 DECLARE_PROTECT_FINAL_CONSTRUCT()
67
68 DECLARE_WND_CLASS_EX(_T("BaseBar"), CS_SAVEBITS | CS_DROPSHADOW, COLOR_3DFACE)
69
70 BEGIN_MSG_MAP(CMenuDeskBar)
71 MESSAGE_HANDLER(WM_SIZE, _OnSize)
72 MESSAGE_HANDLER(WM_NOTIFY, _OnNotify)
73 MESSAGE_HANDLER(WM_PAINT, _OnPaint)
74 MESSAGE_HANDLER(WM_ACTIVATE, _OnActivate)
75 MESSAGE_HANDLER(WM_ACTIVATEAPP, _OnAppActivate)
76 END_MSG_MAP()
77
78 BEGIN_COM_MAP(CMenuDeskBar)
79 COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup)
80 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
81 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
82 COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite)
83 COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject)
84 COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IMenuPopup)
85 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IMenuPopup)
86 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
87 COM_INTERFACE_ENTRY_IID(IID_IBanneredBar, IBanneredBar)
88 COM_INTERFACE_ENTRY_IID(IID_IInitializeObject, IInitializeObject)
89 END_COM_MAP()
90
91 // *** IMenuPopup methods ***
92 virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags);
93 virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType);
94 virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet);
95
96 // *** IOleWindow methods ***
97 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
98 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
99
100 // *** IObjectWithSite methods ***
101 virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite);
102 virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, PVOID *ppvSite);
103
104 // *** IBanneredBar methods ***
105 virtual HRESULT STDMETHODCALLTYPE SetIconSize(DWORD iIcon);
106 virtual HRESULT STDMETHODCALLTYPE GetIconSize(DWORD* piIcon);
107 virtual HRESULT STDMETHODCALLTYPE SetBitmap(HBITMAP hBitmap);
108 virtual HRESULT STDMETHODCALLTYPE GetBitmap(HBITMAP* phBitmap);
109
110 // *** IInitializeObject methods ***
111 virtual HRESULT STDMETHODCALLTYPE Initialize(THIS);
112
113 // *** IOleCommandTarget methods ***
114 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText);
115 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
116
117 // *** IServiceProvider methods ***
118 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
119
120 // *** IInputObjectSite methods ***
121 virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(LPUNKNOWN lpUnknown, BOOL bFocus);
122
123 // *** IInputObject methods ***
124 virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL bActivating, LPMSG lpMsg);
125 virtual HRESULT STDMETHODCALLTYPE HasFocusIO(THIS);
126 virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg);
127
128 // *** IDeskBar methods ***
129 virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient);
130 virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient);
131 virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(LPRECT prc);
132
133 private:
134 // message handlers
135 LRESULT _OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
136 LRESULT _OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
137 LRESULT _OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
138 LRESULT _OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
139 LRESULT _OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
140
141 BOOL _IsSubMenuParent(HWND hwnd);
142 HRESULT _CloseBar();
143 };
144
145 extern "C"
146 HRESULT CMenuDeskBar_Constructor(REFIID riid, LPVOID *ppv)
147 {
148 *ppv = NULL;
149
150 CMenuDeskBar * deskbar = new CComObject<CMenuDeskBar>();
151
152 if (!deskbar)
153 return E_OUTOFMEMORY;
154
155 HRESULT hr = deskbar->QueryInterface(riid, ppv);
156
157 if (FAILED(hr))
158 deskbar->Release();
159
160 return hr;
161 }
162
163 INT deskBarCount=0;
164
165 CMenuDeskBar::CMenuDeskBar() :
166 m_Client(NULL),
167 m_Banner(NULL),
168 m_Level(deskBarCount++),
169 m_Shown(FALSE)
170 {
171 }
172
173 CMenuDeskBar::~CMenuDeskBar()
174 {
175 deskBarCount--;
176 }
177
178 HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS)
179 {
180 return S_OK;
181 }
182
183 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetWindow(HWND *lphwnd)
184 {
185 if (lphwnd == NULL)
186 return E_POINTER;
187 *lphwnd = m_hWnd;
188 return S_OK;
189 }
190
191 HRESULT STDMETHODCALLTYPE CMenuDeskBar::ContextSensitiveHelp(BOOL fEnterMode)
192 {
193 return E_NOTIMPL;
194 }
195
196 HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
197 {
198 CComPtr<IInputObjectSite> ios;
199
200 HRESULT hr = m_Client->QueryInterface(IID_PPV_ARG(IInputObjectSite, &ios));
201 if (FAILED(hr))
202 return hr;
203
204 return ios->OnFocusChangeIS(punkObj, fSetFocus);
205 }
206
207 HRESULT STDMETHODCALLTYPE CMenuDeskBar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
208 OLECMD prgCmds [], OLECMDTEXT *pCmdText)
209 {
210 return E_NOTIMPL;
211 }
212
213 HRESULT STDMETHODCALLTYPE CMenuDeskBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
214 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
215 {
216 if (IsEqualIID(*pguidCmdGroup, CGID_MenuDeskBar))
217 {
218 switch (nCmdID)
219 {
220 case 2: // refresh
221 return S_OK;
222 case 3: // load complete
223 return S_OK;
224 case 4: // set font metrics
225 return S_OK;
226 }
227 }
228 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
229 {
230 }
231 else if (IsEqualIID(*pguidCmdGroup, IID_IDeskBarClient))
232 {
233 switch (nCmdID)
234 {
235 case 0:
236 // hide current band
237 break;
238 case 2:
239 break;
240 case 3:
241 break;
242 }
243 }
244 return E_NOTIMPL;
245 }
246
247 HRESULT STDMETHODCALLTYPE CMenuDeskBar::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
248 {
249 if (IsEqualGUID(guidService, SID_SMenuPopup) ||
250 IsEqualGUID(guidService, SID_SMenuBandParent) ||
251 IsEqualGUID(guidService, SID_STopLevelBrowser))
252 {
253 return this->QueryInterface(riid, ppvObject);
254 }
255
256 if (m_Site == NULL)
257 return E_NOINTERFACE;
258
259 return IUnknown_QueryService(m_Site, guidService, riid, ppvObject);
260 }
261
262 HRESULT STDMETHODCALLTYPE CMenuDeskBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
263 {
264 return IUnknown_UIActivateIO(m_Client, fActivate, lpMsg);
265 }
266
267 HRESULT STDMETHODCALLTYPE CMenuDeskBar::HasFocusIO()
268 {
269 CComPtr<IInputObject> io;
270
271 HRESULT hr = m_Client->QueryInterface(IID_PPV_ARG(IInputObject, &io));
272 if (FAILED(hr))
273 return hr;
274
275 return io->HasFocusIO();
276 }
277
278 HRESULT STDMETHODCALLTYPE CMenuDeskBar::TranslateAcceleratorIO(LPMSG lpMsg)
279 {
280 CComPtr<IInputObject> io;
281
282 HRESULT hr = m_Client->QueryInterface(IID_PPV_ARG(IInputObject, &io));
283 if (FAILED(hr))
284 return hr;
285
286 return io->TranslateAcceleratorIO(lpMsg);
287 }
288
289 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetClient(IUnknown *punkClient)
290 {
291 CComPtr<IDeskBarClient> pDeskBandClient;
292 HRESULT hr;
293
294 m_Client.Release();
295
296 if (punkClient == NULL)
297 return S_OK;
298
299 if (m_hWnd == NULL)
300 {
301 Create(NULL);
302 }
303
304 hr = punkClient->QueryInterface(IID_PPV_ARG(IUnknown, &m_Client));
305 if (FAILED(hr))
306 return hr;
307
308 hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDeskBandClient));
309 if (FAILED(hr))
310 return hr;
311
312 hr = pDeskBandClient->SetDeskBarSite(static_cast<IDeskBar*>(this));
313 if (FAILED(hr))
314 return hr;
315
316 return IUnknown_GetWindow(m_Client, &m_ClientWindow);
317 }
318
319 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetClient(IUnknown **ppunkClient)
320 {
321 if (ppunkClient == NULL)
322 return E_POINTER;
323
324 if (!m_Client)
325 return E_FAIL;
326
327 return m_Client->QueryInterface(IID_PPV_ARG(IUnknown, ppunkClient));
328 }
329
330 HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnPosRectChangeDB(LPRECT prc)
331 {
332 if (prc == NULL)
333 return E_POINTER;
334
335 return S_OK;
336 }
337
338 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSite(IUnknown *pUnkSite)
339 {
340 // Windows closes the bar if this is called when the bar is shown
341
342 if (m_Shown)
343 _CloseBar();
344
345 m_Site = pUnkSite;
346
347 IUnknown_QueryService(m_Site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_SubMenuParent));
348
349 return S_OK;
350 }
351
352 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetSite(REFIID riid, void **ppvSite)
353 {
354 if (m_Site == NULL)
355 return E_FAIL;
356
357 return m_Site->QueryInterface(riid, ppvSite);
358 }
359
360 HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
361 {
362 HRESULT hr;
363 CComPtr<IOleCommandTarget> oct;
364 CComPtr<IInputObject> io;
365 CComPtr<IDeskBand> band;
366 CComPtr<IDeskBarClient> dbc;
367
368 if (m_hWnd == NULL)
369 return E_FAIL;
370
371 hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IOleCommandTarget, &oct));
372 if (FAILED(hr))
373 return hr;
374
375 hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc));
376 if (FAILED(hr))
377 return hr;
378
379 // Windows calls this, but it appears to be unimplemented?
380 hr = dbc->SetModeDBC(1);
381 // Allow it to fail with E_NOTIMPL.
382
383 // No clue about the arg, using anything != 0
384 hr = dbc->UIActivateDBC(TRUE);
385 if (FAILED(hr))
386 return hr;
387
388 RECT rc = { 0 };
389 hr = dbc->GetSize(0, &rc);
390 if (FAILED(hr))
391 return hr;
392
393 // Unknown meaning
394 const int CMD = 19;
395 const int CMD_EXEC_OPT = 0;
396
397 hr = IUnknown_QueryServiceExec(m_Client, SID_SMenuBandChild, &CLSID_MenuBand, CMD, CMD_EXEC_OPT, NULL, NULL);
398 if (FAILED(hr))
399 return hr;
400
401 ::AdjustWindowRect(&rc, ::GetWindowLong(m_hWnd, GWL_STYLE), FALSE);
402 rc.right -= rc.left;
403 rc.bottom -= rc.top;
404
405 if (m_Banner != NULL)
406 {
407 BITMAP bm;
408 ::GetObject(m_Banner, sizeof(bm), &bm);
409 rc.right += bm.bmWidth;
410 }
411
412 int x = ppt->x;
413 int y = ppt->y - rc.bottom;
414 int cx = rc.right;
415 int cy = rc.bottom;
416
417 RECT rcWorkArea;
418 SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
419
420 int waHeight = rcWorkArea.bottom - rcWorkArea.top;
421
422 if (y < rcWorkArea.top)
423 {
424 y = rcWorkArea.top;
425 }
426
427 if (cy > waHeight)
428 {
429 cy = waHeight;
430 }
431 else if (y + cy > rcWorkArea.bottom)
432 {
433 y = rcWorkArea.bottom - cy;
434 }
435
436 this->SetWindowPos(HWND_TOPMOST, x, y, cx, cy, SWP_SHOWWINDOW);
437
438 m_Shown = true;
439
440 // HACK: The bar needs to be notified of the size AFTER it is shown.
441 // Quick & dirty way of getting it done.
442 BOOL bHandled;
443 _OnSize(WM_SIZE, 0, 0, bHandled);
444
445 UIActivateIO(TRUE, NULL);
446
447
448 return S_OK;
449 }
450
451 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetIconSize(THIS_ DWORD iIcon)
452 {
453 HRESULT hr;
454 m_IconSize = iIcon;
455
456 // Unknown meaning (set flags? set icon size?)
457 const int CMD = 16;
458 const int CMD_EXEC_OPT = iIcon ? 0 : 2; // seems to work
459
460 hr = IUnknown_QueryServiceExec(m_Client, SID_SMenuBandChild, &CLSID_MenuBand, CMD, CMD_EXEC_OPT, NULL, NULL);
461 if (FAILED(hr))
462 return hr;
463
464 BOOL bHandled;
465 _OnSize(WM_SIZE, 0, 0, bHandled);
466
467 return hr;
468 }
469
470 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetIconSize(THIS_ DWORD* piIcon)
471 {
472 if (piIcon)
473 *piIcon = m_IconSize;
474 return S_OK;
475 }
476
477 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetBitmap(THIS_ HBITMAP hBitmap)
478 {
479 m_Banner = hBitmap;
480
481 BOOL bHandled;
482 _OnSize(WM_SIZE, 0, 0, bHandled);
483
484 return S_OK;
485 }
486
487 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetBitmap(THIS_ HBITMAP* phBitmap)
488 {
489 if (phBitmap)
490 *phBitmap = m_Banner;
491 return S_OK;
492 }
493
494 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
495 {
496 // Called by the MenuBand to assign itself as the logical child of the DeskBar
497
498 if (fSet)
499 {
500 m_SubMenuChild = pmp;
501 }
502 else
503 {
504 if (m_SubMenuChild)
505 {
506 if (SHIsSameObject(pmp, m_SubMenuChild))
507 {
508 m_SubMenuChild = NULL;
509 }
510 }
511 }
512 return S_OK;
513 }
514
515 HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect(DWORD dwSelectType)
516 {
517 /* As far as I can tell, the submenu hierarchy looks like this:
518
519 The DeskBar's Child is the Band it contains.
520 The DeskBar's Parent is the SID_SMenuPopup of the Site.
521
522 The Band's Child is the IMenuPopup of the child submenu.
523 The Band's Parent is the SID_SMenuPopup of the Site (the DeskBar).
524
525 When the DeskBar receives a selection event:
526 If it requires closing the window, it will notify the Child (Band) using CancelLevel.
527 If it has to spread upwards (everything but CancelLevel), it will notify the Parent.
528
529 When the Band receives a selection event, this is where it gets fuzzy:
530 In which cases does it call the Parent? Probably not CancelLevel.
531 In which cases does it call the Child?
532 How does it react to calls?
533
534 */
535
536 switch (dwSelectType)
537 {
538 case MPOS_EXECUTE:
539 case MPOS_FULLCANCEL:
540 case MPOS_CANCELLEVEL:
541
542 _CloseBar();
543
544 if (dwSelectType == MPOS_CANCELLEVEL)
545 return S_OK;
546
547 case MPOS_SELECTLEFT:
548 case MPOS_SELECTRIGHT:
549 case MPOS_CHILDTRACKING:
550 if (m_SubMenuParent)
551 return m_SubMenuParent->OnSelect(dwSelectType);
552 break;
553 }
554
555 return S_OK;
556 }
557
558 HRESULT CMenuDeskBar::_CloseBar()
559 {
560 CComPtr<IDeskBarClient> dbc;
561 HRESULT hr;
562
563 m_Shown = false;
564
565 if (m_SubMenuChild)
566 {
567 hr = m_SubMenuChild->OnSelect(MPOS_CANCELLEVEL);
568 if (FAILED(hr))
569 return hr;
570 }
571
572 hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc));
573 if (FAILED(hr))
574 return hr;
575
576 hr = dbc->UIActivateDBC(FALSE);
577 if (FAILED(hr))
578 return hr;
579
580 SetWindowPos(m_hWnd, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
581
582 return UIActivateIO(FALSE, NULL);
583 }
584
585 BOOL CMenuDeskBar::_IsSubMenuParent(HWND hwnd)
586 {
587 CComPtr<IMenuPopup> popup = m_SubMenuParent;
588
589 while (popup)
590 {
591 HRESULT hr;
592 CComPtr<IOleWindow> window;
593
594 hr = popup->QueryInterface(IID_PPV_ARG(IOleWindow, &window));
595 if (FAILED(hr))
596 return FALSE;
597
598 HWND parent;
599
600 hr = window->GetWindow(&parent);
601 if (SUCCEEDED(hr) && hwnd == parent)
602 return TRUE;
603
604 popup = NULL;
605 hr = IUnknown_GetSite(window, IID_PPV_ARG(IMenuPopup, &popup));
606 if (FAILED(hr))
607 return FALSE;
608 }
609
610 return FALSE;
611 }
612
613 LRESULT CMenuDeskBar::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
614 {
615 if (m_Client)
616 {
617 RECT rc;
618
619 GetClientRect(&rc);
620
621 if (m_Banner != NULL)
622 {
623 BITMAP bm;
624 ::GetObject(m_Banner, sizeof(bm), &bm);
625 rc.left += bm.bmWidth;
626 }
627
628 ::SetWindowPos(m_ClientWindow, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0);
629 }
630
631 return 0;
632 }
633
634 LRESULT CMenuDeskBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
635 {
636 if (!m_Client)
637 return 0;
638
639 CComPtr<IWinEventHandler> winEventHandler;
640 HRESULT hr = m_Client->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
641 if (FAILED(hr))
642 return 0;
643
644 if (winEventHandler)
645 {
646 LRESULT result;
647 hr = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result);
648 if (FAILED(hr))
649 return 0;
650 return result;
651 }
652
653 return 0;
654 }
655
656 LRESULT CMenuDeskBar::_OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
657 {
658 bHandled = FALSE;
659
660 if (m_Banner && !m_IconSize)
661 {
662 BITMAP bm;
663 PAINTSTRUCT ps;
664 HDC hdc = BeginPaint(&ps);
665
666 HDC hdcMem = ::CreateCompatibleDC(hdc);
667 HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_Banner);
668
669 ::GetObject(m_Banner, sizeof(bm), &bm);
670
671 RECT rc;
672 if (!GetClientRect(&rc))
673 WARN("GetClientRect failed\n");
674
675 const int bx = bm.bmWidth;
676 const int by = bm.bmHeight;
677 const int cy = rc.bottom;
678
679 TRACE("Painting banner: %d by %d\n", bm.bmWidth, bm.bmHeight);
680
681 if (!::StretchBlt(hdc, 0, 0, bx, cy - by, hdcMem, 0, 0, bx, 1, SRCCOPY))
682 WARN("StretchBlt failed\n");
683
684 if (!::BitBlt(hdc, 0, cy - by, bx, by, hdcMem, 0, 0, SRCCOPY))
685 WARN("BitBlt failed\n");
686
687 ::SelectObject(hdcMem, hbmOld);
688 ::DeleteDC(hdcMem);
689
690 EndPaint(&ps);
691 }
692
693 return TRUE;
694 }
695
696 LRESULT CMenuDeskBar::_OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
697 {
698 if (wParam != 0)
699 return 0;
700
701 // HACK! I just want it to work !!!
702 CComPtr<IDeskBar> db;
703 HRESULT hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IDeskBar, &db));
704 if (FAILED(hr))
705 return 0;
706
707 CComPtr<IUnknown> punk;
708
709 hr = db->GetClient(&punk);
710 if (FAILED(hr))
711 return 0;
712
713 if (!punk && m_Shown)
714 {
715 if (!_IsSubMenuParent(reinterpret_cast<HWND>(lParam)))
716 {
717 OnSelect(MPOS_FULLCANCEL);
718 }
719 }
720
721 return 0;
722 }
723
724 LRESULT CMenuDeskBar::_OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
725 {
726 if (wParam == 0)
727 {
728 OnSelect(MPOS_FULLCANCEL);
729 }
730 return 0;
731 }