[RSHELL]
[reactos.git] / base / shell / rshell / CMenuToolbars.cpp
1 /*
2 * Shell Menu Band
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 <windowsx.h>
22 #include <CommonControls.h>
23 #include <shlwapi_undoc.h>
24
25 #include "CMenuBand.h"
26 #include "CMenuToolbars.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(CMenuToolbars);
29
30 extern "C"
31 HRESULT WINAPI SHGetImageList(
32 _In_ int iImageList,
33 _In_ REFIID riid,
34 _Out_ void **ppv
35 );
36
37 // FIXME: Enable if/when wine comctl supports this flag properly
38 #define USE_TBSTYLE_EX_VERTICAL 0
39
40 #define TIMERID_HOTTRACK 1
41 #define SUBCLASS_ID_MENUBAND 1
42
43 HRESULT CMenuToolbarBase::DisableMouseTrack(BOOL bDisable)
44 {
45 m_disableMouseTrack = bDisable;
46 return S_OK;
47 }
48
49 HRESULT CMenuToolbarBase::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
50 {
51 NMHDR * hdr;
52 NMPGCALCSIZE* csize;
53 SIZE tbs;
54
55 *theResult = 0;
56 switch (uMsg)
57 {
58 case WM_COMMAND:
59 return OnCommand(wParam, lParam, theResult);
60
61 case WM_NOTIFY:
62 hdr = reinterpret_cast<LPNMHDR>(lParam);
63 switch (hdr->code)
64 {
65 case TTN_GETDISPINFOA:
66 case TTN_GETDISPINFOW:
67 return S_OK;
68
69 case TBN_DELETINGBUTTON:
70 return OnDeletingButton(reinterpret_cast<LPNMTOOLBAR>(hdr));
71
72 case PGN_CALCSIZE:
73 csize = reinterpret_cast<LPNMPGCALCSIZE>(hdr);
74
75 GetIdealSize(tbs);
76 if (csize->dwFlag == PGF_CALCHEIGHT)
77 {
78 csize->iHeight = tbs.cy;
79 }
80 else if (csize->dwFlag == PGF_CALCWIDTH)
81 {
82 csize->iHeight = tbs.cx;
83 }
84 return S_OK;
85
86 case TBN_DROPDOWN:
87 wParam = reinterpret_cast<LPNMTOOLBAR>(hdr)->iItem;
88 return OnCommand(wParam, 0, theResult);
89
90 case TBN_HOTITEMCHANGE:
91 return OnHotItemChange(reinterpret_cast<LPNMTBHOTITEM>(hdr), theResult);
92
93 case NM_RCLICK:
94 return OnContextMenu(reinterpret_cast<LPNMMOUSE>(hdr));
95
96 case NM_CUSTOMDRAW:
97 return OnCustomDraw(reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr), theResult);
98
99 case RBN_CHILDSIZE:
100 return S_OK;
101
102 default:
103 DbgPrint("WM_NOTIFY unknown code %d, %d\n", hdr->code, hdr->idFrom);
104 }
105 return S_OK;
106 }
107
108 return S_FALSE;
109 }
110
111 HRESULT CMenuToolbarBase::OnCustomDraw(LPNMTBCUSTOMDRAW cdraw, LRESULT * theResult)
112 {
113 RECT rc;
114 HDC hdc;
115 HBRUSH bgBrush;
116 HBRUSH hotBrush;
117 COLORREF clrText;
118 COLORREF clrTextHighlight;
119 bool isHot, isPopup;
120 TBBUTTONINFO btni;
121
122 switch (cdraw->nmcd.dwDrawStage)
123 {
124 case CDDS_PREPAINT:
125 if (m_toolbarFlags & SMINIT_VERTICAL)
126 *theResult = CDRF_NOTIFYITEMDRAW;
127 return S_OK;
128
129 case CDDS_ITEMPREPAINT:
130
131 clrText = GetSysColor(COLOR_MENUTEXT);
132 clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
133
134 bgBrush = GetSysColorBrush(COLOR_MENU);
135 hotBrush = GetSysColorBrush(m_useFlatMenus ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT);
136
137 rc = cdraw->nmcd.rc;
138 hdc = cdraw->nmcd.hdc;
139
140 isHot = m_hotBar == this && m_hotItem == static_cast<INT>(cdraw->nmcd.dwItemSpec);
141 isPopup = m_popupBar == this && m_popupItem == static_cast<INT>(cdraw->nmcd.dwItemSpec);
142
143 if (isHot || (m_hotItem < 0 && isPopup))
144 {
145 cdraw->nmcd.uItemState |= CDIS_HOT;
146 }
147 else
148 {
149 cdraw->nmcd.uItemState &= ~CDIS_HOT;
150 }
151
152 if (cdraw->nmcd.uItemState&CDIS_HOT)
153 {
154 FillRect(hdc, &rc, hotBrush);
155 SetTextColor(hdc, clrTextHighlight);
156 cdraw->clrText = clrTextHighlight;
157 }
158 else
159 {
160 FillRect(hdc, &rc, bgBrush);
161 SetTextColor(hdc, clrText);
162 cdraw->clrText = clrText;
163 }
164
165 cdraw->iListGap += 4;
166
167 *theResult = CDRF_NOTIFYPOSTPAINT | TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | 0x00800000; // FIXME: the last bit is Vista+, for debugging only
168 return S_OK;
169
170 case CDDS_ITEMPOSTPAINT:
171 btni.cbSize = sizeof(btni);
172 btni.dwMask = TBIF_STYLE;
173 SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, cdraw->nmcd.dwItemSpec, reinterpret_cast<LPARAM>(&btni));
174 if (btni.fsStyle & BTNS_DROPDOWN)
175 {
176 SelectObject(cdraw->nmcd.hdc, m_marlett);
177 WCHAR text[] = L"8";
178 SetBkMode(cdraw->nmcd.hdc, TRANSPARENT);
179 RECT rc = cdraw->nmcd.rc;
180 rc.right += 1;
181 DrawTextEx(cdraw->nmcd.hdc, text, 1, &rc, DT_NOCLIP | DT_VCENTER | DT_RIGHT | DT_SINGLELINE, NULL);
182 }
183 *theResult = TRUE;
184 return S_OK;
185 }
186 return S_OK;
187 }
188
189 CMenuToolbarBase::CMenuToolbarBase(CMenuBand *menuBand, BOOL usePager) :
190 m_hwnd(NULL),
191 m_useFlatMenus(FALSE),
192 m_SubclassOld(NULL),
193 m_disableMouseTrack(FALSE),
194 m_menuBand(menuBand),
195 m_hwndToolbar(NULL),
196 m_dwMenuFlags(0),
197 m_hasIdealSize(FALSE),
198 m_usePager(usePager),
199 m_hotItem(-1),
200 m_popupItem(-1),
201 m_isTracking(FALSE)
202 {
203 m_marlett = CreateFont(
204 0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET,
205 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
206 DEFAULT_QUALITY, FF_DONTCARE, L"Marlett");
207 }
208
209 CMenuToolbarBase::~CMenuToolbarBase()
210 {
211 DeleteObject(m_marlett);
212 }
213
214 HRESULT CMenuToolbarBase::IsWindowOwner(HWND hwnd)
215 {
216 return (m_hwnd && m_hwnd == hwnd) ||
217 (m_hwndToolbar && m_hwndToolbar == hwnd) ? S_OK : S_FALSE;
218 }
219
220 void CMenuToolbarBase::InvalidateDraw()
221 {
222 InvalidateRect(m_hwnd, NULL, FALSE);
223 }
224
225 HRESULT CMenuToolbarBase::ShowWindow(BOOL fShow)
226 {
227 ::ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE);
228
229 UpdateImageLists();
230
231 SystemParametersInfo(SPI_GETFLATMENU, 0, &m_useFlatMenus, 0);
232
233 return S_OK;
234 }
235
236 HRESULT CMenuToolbarBase::UpdateImageLists()
237 {
238 if ((m_toolbarFlags & (SMINIT_TOPLEVEL| SMINIT_VERTICAL)) == SMINIT_TOPLEVEL) // not vertical.
239 {
240 /* Hide the placeholders for the button images */
241 SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0);
242 return S_OK;
243 }
244
245 int shiml;
246 if (m_menuBand->UseBigIcons())
247 {
248 shiml = SHIL_LARGE;
249 SendMessageW(m_hwndToolbar, TB_SETPADDING, 0, MAKELPARAM(4, 0));
250 }
251 else
252 {
253 shiml = SHIL_SMALL;
254 SendMessageW(m_hwndToolbar, TB_SETPADDING, 0, MAKELPARAM(4, 4));
255 }
256
257 IImageList * piml;
258 HRESULT hr = SHGetImageList(shiml, IID_PPV_ARG(IImageList, &piml));
259 if (SUCCEEDED(hr))
260 {
261 SendMessageW(m_hwndToolbar, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(piml));
262 }
263 else
264 {
265 SendMessageW(m_hwndToolbar, TB_SETIMAGELIST, 0, 0);
266 }
267 return S_OK;
268 }
269
270 HRESULT CMenuToolbarBase::Close()
271 {
272 DestroyWindow(m_hwndToolbar);
273 if (m_hwndToolbar != m_hwnd)
274 DestroyWindow(m_hwnd);
275 m_hwndToolbar = NULL;
276 m_hwnd = NULL;
277 return S_OK;
278 }
279
280 HRESULT CMenuToolbarBase::CreateToolbar(HWND hwndParent, DWORD dwFlags)
281 {
282 LONG tbStyles = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
283 TBSTYLE_TOOLTIPS | TBSTYLE_TRANSPARENT | TBSTYLE_REGISTERDROP | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_CUSTOMERASE |
284 CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_TOP;
285 LONG tbExStyles = TBSTYLE_EX_DOUBLEBUFFER;
286
287 if (dwFlags & SMINIT_VERTICAL)
288 {
289 tbStyles |= CCS_VERT;
290
291 #if USE_TBSTYLE_EX_VERTICAL
292 // FIXME: Use when it works in ros (?)
293 tbExStyles |= TBSTYLE_EX_VERTICAL | WS_EX_TOOLWINDOW;
294 #endif
295 }
296
297 m_toolbarFlags = dwFlags;
298
299 RECT rc;
300
301 if (!::GetClientRect(hwndParent, &rc) || (rc.left == rc.right) || (rc.top == rc.bottom))
302 {
303 rc.left = 0;
304 rc.top = 0;
305 rc.right = 1;
306 rc.bottom = 1;
307 }
308
309 HWND hwndToolbar = CreateWindowEx(
310 tbExStyles, TOOLBARCLASSNAMEW, NULL,
311 tbStyles, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
312 hwndParent, NULL, _AtlBaseModule.GetModuleInstance(), 0);
313
314 if (hwndToolbar == NULL)
315 return E_FAIL;
316
317 if (m_usePager)
318 {
319 LONG pgStyles = PGS_VERT | WS_CHILD | WS_VISIBLE;
320 LONG pgExStyles = 0;
321
322 HWND hwndPager = CreateWindowEx(
323 pgExStyles, WC_PAGESCROLLER, NULL,
324 pgStyles, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
325 hwndParent, NULL, _AtlBaseModule.GetModuleInstance(), 0);
326
327 ::SetParent(hwndToolbar, hwndPager);
328 ::SetParent(hwndPager, hwndParent);
329
330 SendMessage(hwndPager, PGM_SETCHILD, 0, reinterpret_cast<LPARAM>(hwndToolbar));
331 m_hwndToolbar = hwndToolbar;
332 m_hwnd = hwndPager;
333 }
334 else
335 {
336 ::SetParent(hwndToolbar, hwndParent);
337 m_hwndToolbar = hwndToolbar;
338 m_hwnd = hwndToolbar;
339 }
340
341 /* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */
342 SendMessageW(hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
343
344 SetWindowLongPtr(hwndToolbar, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
345 m_SubclassOld = (WNDPROC) SetWindowLongPtr(hwndToolbar, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(CMenuToolbarBase::s_SubclassProc));
346
347 UpdateImageLists();
348
349 return S_OK;
350 }
351
352 HRESULT CMenuToolbarBase::GetIdealSize(SIZE& size)
353 {
354 size.cx = size.cy = 0;
355
356 if (m_hwndToolbar && !m_hasIdealSize)
357 {
358 SendMessageW(m_hwndToolbar, TB_AUTOSIZE, 0, 0);
359 SendMessageW(m_hwndToolbar, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&m_idealSize));
360 m_hasIdealSize = TRUE;
361 }
362
363 size = m_idealSize;
364
365 return S_OK;
366 }
367
368 HRESULT CMenuToolbarBase::SetPosSize(int x, int y, int cx, int cy)
369 {
370 if (m_hwnd != m_hwndToolbar)
371 {
372 SetWindowPos(m_hwndToolbar, NULL, x, y, cx, m_idealSize.cy, 0);
373 }
374 SetWindowPos(m_hwnd, NULL, x, y, cx, cy, 0);
375 if (m_toolbarFlags & SMINIT_VERTICAL)
376 {
377 DWORD btnSize = SendMessage(m_hwndToolbar, TB_GETBUTTONSIZE, 0, 0);
378 SendMessage(m_hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, HIWORD(btnSize)));
379 }
380 return S_OK;
381 }
382
383 HRESULT CMenuToolbarBase::GetWindow(HWND *phwnd)
384 {
385 if (!phwnd)
386 return E_FAIL;
387
388 *phwnd = m_hwnd;
389
390 return S_OK;
391 }
392
393 LRESULT CALLBACK CMenuToolbarBase::s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
394 {
395 CMenuToolbarBase * pthis = reinterpret_cast<CMenuToolbarBase *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
396 return pthis->SubclassProc(hWnd, uMsg, wParam, lParam);
397 }
398
399 LRESULT CMenuToolbarBase::SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
400 {
401 LRESULT lr;
402
403 switch (uMsg)
404 {
405 case WM_USER_ISTRACKEDITEM:
406 m_SubclassOld(hWnd, uMsg, wParam, lParam);
407 return IsTrackedItem(wParam);
408 case WM_USER_CHANGETRACKEDITEM:
409 m_isTracking = TRUE;
410 m_SubclassOld(hWnd, uMsg, wParam, lParam);
411 return ChangeTrackedItem(wParam);
412
413 case WM_COMMAND:
414 OnWinEvent(hWnd, uMsg, wParam, lParam, &lr);
415 break;
416 case WM_NOTIFY:
417 OnWinEvent(hWnd, uMsg, wParam, lParam, &lr);
418 break;
419 case WM_TIMER:
420 if (wParam == TIMERID_HOTTRACK)
421 {
422 KillTimer(hWnd, TIMERID_HOTTRACK);
423
424 m_menuBand->_OnPopupSubMenu(NULL, NULL, NULL, NULL, -1);
425
426 if (HasSubMenu(m_hotItem) == S_OK)
427 {
428 PopupItem(m_hotItem);
429 }
430 }
431 }
432
433 return m_SubclassOld(hWnd, uMsg, wParam, lParam);
434 }
435
436 HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot, LRESULT * theResult)
437 {
438 if (m_disableMouseTrack && hot->dwFlags & HICF_MOUSE)
439 {
440 *theResult = 1;
441 return S_OK;
442 }
443
444 if (hot->dwFlags & HICF_LEAVING)
445 {
446 KillTimer(m_hwndToolbar, TIMERID_HOTTRACK);
447
448 if (m_menuBand->_OnHotItemChanged(NULL, -1) == S_FALSE)
449 {
450 *theResult = 1;
451 return S_OK;
452 }
453 else
454 {
455 m_hotItem = -1;
456 m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
457 return S_OK;
458 }
459 }
460 else if (m_hotItem != hot->idNew)
461 {
462 if (hot->dwFlags & HICF_MOUSE &&
463 m_toolbarFlags & SMINIT_VERTICAL)
464 {
465 DWORD elapsed = 0;
466 SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0);
467 SetTimer(m_hwndToolbar, TIMERID_HOTTRACK, elapsed, NULL);
468 }
469
470 m_hotItem = hot->idNew;
471 m_menuBand->_OnHotItemChanged(this, m_hotItem);
472 m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
473
474 if (m_isTracking && !(m_toolbarFlags & SMINIT_VERTICAL))
475 {
476 KillTimer(m_hwndToolbar, TIMERID_HOTTRACK);
477
478 m_menuBand->_OnPopupSubMenu(NULL, NULL, NULL, NULL, -1);
479
480 if (HasSubMenu(m_hotItem) == S_OK)
481 {
482 PopupItem(m_hotItem);
483 }
484 }
485 return S_OK;
486 }
487 return S_OK;
488 }
489
490 HRESULT CMenuToolbarBase::OnHotItemChanged(CMenuToolbarBase * toolbar, INT item)
491 {
492 BOOL wasChecked = FALSE;
493 if (m_hotBar == this && !(m_toolbarFlags & SMINIT_VERTICAL))
494 {
495 wasChecked = SendMessage(m_hwndToolbar, TB_ISBUTTONCHECKED, m_hotItem, 0);
496 if (wasChecked)
497 {
498 SendMessage(m_hwndToolbar, TB_CHECKBUTTON, m_hotItem, FALSE);
499 }
500 }
501 m_hotBar = toolbar;
502 m_hotItem = item;
503 if (wasChecked && m_hotBar == this && !(m_toolbarFlags & SMINIT_VERTICAL))
504 {
505 SendMessage(m_hwndToolbar, TB_CHECKBUTTON, m_hotItem, TRUE);
506 }
507 InvalidateDraw();
508 return S_OK;
509 }
510
511 HRESULT CMenuToolbarBase::OnPopupItemChanged(CMenuToolbarBase * toolbar, INT item)
512 {
513 if (toolbar == NULL && m_popupBar == this)
514 {
515 SendMessage(m_hwndToolbar, TB_CHECKBUTTON, m_popupItem, FALSE);
516 m_isTracking = FALSE;
517 }
518 m_popupBar = toolbar;
519 m_popupItem = item;
520 InvalidateDraw();
521 return S_OK;
522 }
523
524 HRESULT CMenuToolbarBase::IsTrackedItem(INT index)
525 {
526 TBBUTTON btn;
527
528 if (m_hotBar != this)
529 return S_FALSE;
530
531 SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
532
533 if (m_hotItem == btn.idCommand)
534 return S_OK;
535 return S_FALSE;
536 }
537
538 HRESULT CMenuToolbarBase::ChangeTrackedItem(INT index)
539 {
540 TBBUTTON btn;
541 SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
542
543 if (m_hotItem != btn.idCommand)
544 {
545 SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0);
546 }
547 return S_OK;
548 }
549
550 HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, UINT index, IShellMenu* childShellMenu)
551 {
552 IBandSite* pBandSite;
553 IDeskBar* pDeskBar;
554
555 HRESULT hr = 0;
556 RECT rc = { 0 };
557 RECT rcx = { 0 };
558
559 if (!SendMessage(m_hwndToolbar, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
560 return E_FAIL;
561
562 GetWindowRect(m_hwnd, &rcx);
563
564 POINT a = { rc.left, rc.top };
565 POINT b = { rc.right, rc.bottom };
566 POINT c = { rcx.left, rcx.top };
567 POINT d = { rcx.right, rcx.bottom };
568
569 ClientToScreen(m_hwndToolbar, &a);
570 ClientToScreen(m_hwndToolbar, &b);
571 ClientToScreen(m_hwnd, &c);
572 ClientToScreen(m_hwnd, &d);
573
574 POINTL pt = { a.x, b.y };
575 RECTL rcl = { c.x, c.y, d.x, d.y };
576
577 if(m_toolbarFlags & SMINIT_VERTICAL)
578 {
579 pt.x = b.x - 3;
580 pt.y = a.y - 3;
581 }
582
583 #if USE_SYSTEM_MENUSITE
584 hr = CoCreateInstance(CLSID_MenuBandSite,
585 NULL,
586 CLSCTX_INPROC_SERVER,
587 IID_PPV_ARG(IBandSite, &pBandSite));
588 #else
589 hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
590 #endif
591 if (FAILED_UNEXPECTEDLY(hr))
592 return hr;
593 #if WRAP_MENUSITE
594 hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite));
595 if (FAILED_UNEXPECTEDLY(hr))
596 return hr;
597 #endif
598
599 #if USE_SYSTEM_MENUDESKBAR
600 hr = CoCreateInstance(CLSID_MenuDeskBar,
601 NULL,
602 CLSCTX_INPROC_SERVER,
603 IID_PPV_ARG(IDeskBar, &pDeskBar));
604 #else
605 hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar));
606 #endif
607 if (FAILED_UNEXPECTEDLY(hr))
608 return hr;
609 #if WRAP_MENUDESKBAR
610 hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar));
611 if (FAILED_UNEXPECTEDLY(hr))
612 return hr;
613 #endif
614
615 hr = pDeskBar->SetClient(pBandSite);
616 if (FAILED_UNEXPECTEDLY(hr))
617 return hr;
618
619 hr = pBandSite->AddBand(childShellMenu);
620 if (FAILED_UNEXPECTEDLY(hr))
621 return hr;
622
623 CComPtr<IMenuPopup> popup;
624 hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup));
625 if (FAILED_UNEXPECTEDLY(hr))
626 return hr;
627
628 m_isTracking = TRUE;
629 m_menuBand->_OnPopupSubMenu(popup, &pt, &rcl, this, uItem);
630
631 return S_OK;
632 }
633
634 HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, UINT index, HMENU menu)
635 {
636 RECT rc = { 0 };
637 RECT rcx = { 0 };
638
639 if (!SendMessage(m_hwndToolbar, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
640 return E_FAIL;
641
642 GetClientRect(m_hwndToolbar, &rcx);
643
644 POINT a = { rc.left, rc.top };
645 POINT b = { rc.right, rc.bottom };
646 POINT c = { rc.left, rc.top };
647 POINT d = { rc.right, rc.bottom };
648
649 ClientToScreen(m_hwndToolbar, &a);
650 ClientToScreen(m_hwndToolbar, &b);
651 ClientToScreen(m_hwndToolbar, &c);
652 ClientToScreen(m_hwndToolbar, &d);
653
654 POINT pt = { a.x, b.y };
655 RECT rcl = { c.x, c.y, d.x, d.y };
656
657 if (m_toolbarFlags & SMINIT_VERTICAL)
658 {
659 pt.x = b.x;
660 pt.y = a.y;
661 }
662
663 HMENU popup = GetSubMenu(menu, index);
664
665 m_isTracking = TRUE;
666 m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, pt.x, pt.y, rcl);
667
668 SendMessage(m_hwndToolbar, TB_CHECKBUTTON, uItem, FALSE);
669 m_isTracking = FALSE;
670
671 return S_OK;
672 }
673
674 HRESULT CMenuToolbarBase::DoContextMenu(IContextMenu* contextMenu)
675 {
676 HRESULT hr;
677 HMENU hPopup = CreatePopupMenu();
678
679 if (hPopup == NULL)
680 return E_FAIL;
681
682 hr = contextMenu->QueryContextMenu(hPopup, 0, 0, UINT_MAX, CMF_NORMAL);
683 if (FAILED_UNEXPECTEDLY(hr))
684 {
685 DestroyMenu(hPopup);
686 return hr;
687 }
688
689 DWORD dwPos = GetMessagePos();
690 UINT uCommand = ::TrackPopupMenu(hPopup, TPM_RETURNCMD, GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), 0, m_hwnd, NULL);
691 if (uCommand == 0)
692 return S_FALSE;
693
694 CMINVOKECOMMANDINFO cmi = { 0 };
695 cmi.cbSize = sizeof(cmi);
696 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
697 cmi.hwnd = m_hwnd;
698 hr = contextMenu->InvokeCommand(&cmi);
699
700 DestroyMenu(hPopup);
701 return hr;
702 }
703
704 HRESULT CMenuToolbarBase::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
705 {
706 theResult = 0;
707 if (HasSubMenu(wParam) == S_OK)
708 {
709 KillTimer(m_hwndToolbar, TIMERID_HOTTRACK);
710 PopupItem(wParam);
711 return S_FALSE;
712 }
713 HRESULT hr = m_menuBand->_MenuItemHotTrack(MPOS_EXECUTE);
714 if (FAILED_UNEXPECTEDLY(hr))
715 return hr;
716 return S_OK; // filter out a possible S_FALSE from here.
717 }
718
719 HRESULT CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType)
720 {
721 int prev = m_hotItem;
722 int index = -1;
723
724 if (dwSelectType != 0xFFFFFFFF)
725 {
726 int count = SendMessage(m_hwndToolbar, TB_BUTTONCOUNT, 0, 0);
727
728 if (m_hotItem >= 0)
729 {
730 TBBUTTONINFO info = { 0 };
731 info.cbSize = sizeof(TBBUTTONINFO);
732 info.dwMask = 0;
733 index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, m_hotItem, reinterpret_cast<LPARAM>(&info));
734 }
735
736 if (dwSelectType == VK_HOME)
737 {
738 index = 0;
739 dwSelectType = VK_DOWN;
740 }
741 else if (dwSelectType == VK_END)
742 {
743 index = count - 1;
744 dwSelectType = VK_UP;
745 }
746 else if (index < 0)
747 {
748 if (dwSelectType == VK_UP)
749 {
750 index = count - 1;
751 }
752 else if (dwSelectType == VK_DOWN)
753 {
754 index = 0;
755 }
756 }
757 else
758 {
759 if (dwSelectType == VK_UP)
760 {
761 index--;
762 }
763 else if (dwSelectType == VK_DOWN)
764 {
765 index++;
766 }
767 }
768
769 TBBUTTON btn = { 0 };
770 while (index >= 0 && index < count)
771 {
772 DWORD res = SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
773 if (!res)
774 return E_FAIL;
775
776 if (btn.dwData)
777 {
778 if (prev != btn.idCommand)
779 {
780 SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0);
781 }
782 return S_OK;
783 }
784
785 if (dwSelectType == VK_UP)
786 {
787 index--;
788 }
789 else if (dwSelectType == VK_DOWN)
790 {
791 index++;
792 }
793 }
794 }
795
796 if (prev != -1)
797 {
798 SendMessage(m_hwndToolbar, TB_SETHOTITEM, -1, 0);
799 }
800 return S_FALSE;
801 }
802
803 HRESULT CMenuToolbarBase::AddButton(DWORD commandId, LPCWSTR caption, BOOL hasSubMenu, INT iconId, DWORD_PTR buttonData, BOOL last)
804 {
805 TBBUTTON tbb = { 0 };
806
807 tbb.fsState = TBSTATE_ENABLED;
808 #if !USE_TBSTYLE_EX_VERTICAL
809 if (!last && (m_toolbarFlags & SMINIT_VERTICAL))
810 tbb.fsState |= TBSTATE_WRAP;
811 #endif
812 tbb.fsStyle = 0;
813
814 if (hasSubMenu && (m_toolbarFlags & SMINIT_VERTICAL))
815 tbb.fsStyle |= BTNS_DROPDOWN;
816
817 if (!(m_toolbarFlags & SMINIT_VERTICAL))
818 tbb.fsStyle |= BTNS_AUTOSIZE | BTNS_CHECKGROUP;
819
820 tbb.iString = (INT_PTR) caption;
821 tbb.idCommand = commandId;
822
823 tbb.iBitmap = iconId;
824 tbb.dwData = buttonData;
825
826 if (!SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb)))
827 return HRESULT_FROM_WIN32(GetLastError());
828
829 return S_OK;
830 }
831
832 HRESULT CMenuToolbarBase::AddSeparator(BOOL last)
833 {
834 TBBUTTON tbb = { 0 };
835
836 tbb.fsState = TBSTATE_ENABLED;
837 #if !USE_TBSTYLE_EX_VERTICAL
838 if (!last && (m_toolbarFlags & SMINIT_VERTICAL))
839 tbb.fsState |= TBSTATE_WRAP;
840 #endif
841 tbb.fsStyle = BTNS_SEP;
842 tbb.iBitmap = 0;
843
844 if (!SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb)))
845 return HRESULT_FROM_WIN32(GetLastError());
846
847 return S_OK;
848 }
849
850 HRESULT CMenuToolbarBase::AddPlaceholder()
851 {
852 TBBUTTON tbb = { 0 };
853 PCWSTR MenuString = L"(Empty)";
854
855 tbb.fsState = 0;
856 tbb.fsStyle = 0;
857 tbb.iString = (INT_PTR) MenuString;
858 tbb.iBitmap = -1;
859
860 if (!SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb)))
861 return HRESULT_FROM_WIN32(GetLastError());
862
863 return S_OK;
864 }
865
866 HRESULT CMenuToolbarBase::GetDataFromId(INT uItem, INT* pIndex, DWORD_PTR* pData)
867 {
868 TBBUTTONINFO info = { 0 };
869 info.cbSize = sizeof(TBBUTTONINFO);
870 info.dwMask = 0;
871 int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
872 if (index < 0)
873 return E_FAIL;
874
875 if (pIndex)
876 *pIndex = index;
877
878 if (pData)
879 {
880 TBBUTTON btn = { 0 };
881 if (!SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn)))
882 return E_FAIL;
883 *pData = btn.dwData;
884 }
885
886 return S_OK;
887 }
888
889
890 HRESULT CMenuToolbarBase::PopupItem(INT uItem)
891 {
892 INT index;
893 DWORD_PTR dwData;
894
895 if (!(m_toolbarFlags & SMINIT_VERTICAL))
896 {
897 SendMessage(m_hwndToolbar, TB_SETHOTITEM, uItem, 0);
898 SendMessage(m_hwndToolbar, TB_CHECKBUTTON, uItem, TRUE);
899 }
900
901 GetDataFromId(uItem, &index, &dwData);
902
903 return InternalPopupItem(uItem, index, dwData);
904 }
905
906 HRESULT CMenuToolbarBase::HasSubMenu(INT uItem)
907 {
908 INT index;
909 DWORD_PTR dwData;
910
911 GetDataFromId(uItem, &index, &dwData);
912
913 return InternalHasSubMenu(uItem, index, dwData);
914 }
915
916 CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand *menuBand) :
917 CMenuToolbarBase(menuBand, FALSE),
918 m_hmenu(NULL)
919 {
920 }
921
922 HRESULT CMenuStaticToolbar::GetMenu(
923 _Out_opt_ HMENU *phmenu,
924 _Out_opt_ HWND *phwnd,
925 _Out_opt_ DWORD *pdwFlags)
926 {
927 if (phmenu)
928 *phmenu = m_hmenu;
929 if (phwnd)
930 *phwnd = NULL;
931 if (pdwFlags)
932 *pdwFlags = m_dwMenuFlags;
933
934 return S_OK;
935 }
936
937 HRESULT CMenuStaticToolbar::SetMenu(
938 HMENU hmenu,
939 HWND hwnd,
940 DWORD dwFlags)
941 {
942 m_hmenu = hmenu;
943 m_dwMenuFlags = dwFlags;
944
945 return S_OK;
946 }
947
948 HRESULT CMenuStaticToolbar::FillToolbar(BOOL clearFirst)
949 {
950 int i;
951 int ic = GetMenuItemCount(m_hmenu);
952
953 if (clearFirst)
954 {
955 while (SendMessage(m_hwndToolbar, TB_DELETEBUTTON, 0, 0))
956 {
957 // empty;
958 }
959 }
960
961 int count = 0;
962 for (i = 0; i < ic; i++)
963 {
964 BOOL last = i + 1 == ic;
965
966 MENUITEMINFOW info;
967
968 info.cbSize = sizeof(info);
969 info.dwTypeData = NULL;
970 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
971
972 if (!GetMenuItemInfoW(m_hmenu, i, TRUE, &info))
973 {
974 DbgPrint("Error obtaining info for menu item at pos=%d\n", i);
975 continue;
976 }
977
978 count++;
979
980 if (info.fType & MFT_SEPARATOR)
981 {
982 AddSeparator(last);
983 }
984 else if (!(info.fType & MFT_BITMAP))
985 {
986
987 info.cch++;
988 info.dwTypeData = (PWSTR) HeapAlloc(GetProcessHeap(), 0, (info.cch + 1) * sizeof(WCHAR));
989
990 info.fMask = MIIM_STRING | MIIM_SUBMENU | MIIM_ID;
991 GetMenuItemInfoW(m_hmenu, i, TRUE, &info);
992
993 SMINFO * sminfo = new SMINFO();
994 sminfo->dwMask = SMIM_ICON | SMIM_FLAGS;
995 // FIXME: remove before deleting the toolbar or it will leak
996
997 HRESULT hr = m_menuBand->_CallCBWithItemId(info.wID, SMC_GETINFO, 0, reinterpret_cast<LPARAM>(sminfo));
998 if (FAILED_UNEXPECTEDLY(hr))
999 return hr;
1000
1001 AddButton(info.wID, info.dwTypeData, info.hSubMenu != NULL, sminfo->iIcon, reinterpret_cast<DWORD_PTR>(sminfo), last);
1002
1003 HeapFree(GetProcessHeap(), 0, info.dwTypeData);
1004 }
1005 }
1006
1007 DbgPrint("Created toolbar with %d buttons.\n", count);
1008
1009 return S_OK;
1010 }
1011
1012 HRESULT CMenuStaticToolbar::OnDeletingButton(const NMTOOLBAR * tb)
1013 {
1014 delete reinterpret_cast<SMINFO*>(tb->tbButton.dwData);
1015 return S_OK;
1016 }
1017
1018 HRESULT CMenuStaticToolbar::OnContextMenu(NMMOUSE * rclick)
1019 {
1020 CComPtr<IContextMenu> contextMenu;
1021 HRESULT hr = m_menuBand->_CallCBWithItemId(rclick->dwItemSpec, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IContextMenu), reinterpret_cast<LPARAM>(&contextMenu));
1022 if (hr != S_OK)
1023 return hr;
1024
1025 return DoContextMenu(contextMenu);
1026 }
1027
1028 HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1029 {
1030 HRESULT hr;
1031 hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1032 if (FAILED_UNEXPECTEDLY(hr))
1033 return hr;
1034
1035 // in case the clicked item has a submenu, we do not need to execute the item
1036 if (hr == S_FALSE)
1037 {
1038 DbgPrint("CMenuToolbarBase::OnCommand told us to cancel.\n");
1039 return hr;
1040 }
1041
1042 return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0);
1043 }
1044
1045 HRESULT CMenuStaticToolbar::InternalPopupItem(INT uItem, INT index, DWORD_PTR dwData)
1046 {
1047 SMINFO * nfo = reinterpret_cast<SMINFO*>(dwData);
1048 if (!nfo)
1049 return E_FAIL;
1050
1051 if (nfo->dwFlags&SMIF_TRACKPOPUP)
1052 {
1053 return PopupSubMenu(uItem, index, m_hmenu);
1054 }
1055 else
1056 {
1057 CComPtr<IShellMenu> shellMenu;
1058 HRESULT hr = m_menuBand->_CallCBWithItemId(uItem, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IShellMenu), reinterpret_cast<LPARAM>(&shellMenu));
1059 if (FAILED_UNEXPECTEDLY(hr))
1060 return hr;
1061
1062 return PopupSubMenu(uItem, index, shellMenu);
1063 }
1064 }
1065
1066 HRESULT CMenuStaticToolbar::InternalHasSubMenu(INT uItem, INT index, DWORD_PTR dwData)
1067 {
1068 return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE;
1069 }
1070
1071 CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) :
1072 CMenuToolbarBase(menuBand, TRUE),
1073 m_shellFolder(NULL),
1074 m_idList(NULL),
1075 m_hKey(NULL)
1076 {
1077 }
1078
1079 CMenuSFToolbar::~CMenuSFToolbar()
1080 {
1081 }
1082
1083 HRESULT CMenuSFToolbar::FillToolbar(BOOL clearFirst)
1084 {
1085 HRESULT hr;
1086 int i = 0;
1087 PWSTR MenuString;
1088
1089 IEnumIDList * eidl;
1090 m_shellFolder->EnumObjects(m_hwndToolbar, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &eidl);
1091
1092 LPITEMIDLIST item = static_cast<LPITEMIDLIST>(CoTaskMemAlloc(sizeof(ITEMIDLIST)));
1093 ULONG fetched;
1094 hr = eidl->Next(1, &item, &fetched);
1095 while (SUCCEEDED(hr) && fetched > 0)
1096 {
1097 INT index = 0;
1098 INT indexOpen = 0;
1099
1100 STRRET sr = { STRRET_CSTR, { 0 } };
1101
1102 hr = m_shellFolder->GetDisplayNameOf(item, SIGDN_NORMALDISPLAY, &sr);
1103 if (FAILED_UNEXPECTEDLY(hr))
1104 return hr;
1105
1106 StrRetToStr(&sr, NULL, &MenuString);
1107
1108 index = SHMapPIDLToSystemImageListIndex(m_shellFolder, item, &indexOpen);
1109
1110 LPCITEMIDLIST itemc = item;
1111
1112 SFGAOF attrs = SFGAO_FOLDER;
1113 hr = m_shellFolder->GetAttributesOf(1, &itemc, &attrs);
1114
1115 DWORD_PTR dwData = reinterpret_cast<DWORD_PTR>(ILClone(item));
1116 // FIXME: remove before deleting the toolbar or it will leak
1117
1118 // Fetch next item already, so we know if the current one is the last
1119 hr = eidl->Next(1, &item, &fetched);
1120
1121 AddButton(++i, MenuString, attrs & SFGAO_FOLDER, index, dwData, FAILED(hr) || fetched == 0);
1122
1123 CoTaskMemFree(MenuString);
1124 }
1125 CoTaskMemFree(item);
1126
1127 // If no items were added, show the "empty" placeholder
1128 if (i == 0)
1129 {
1130 return AddPlaceholder();
1131 }
1132
1133 DbgPrint("Created toolbar with %d buttons.\n", i);
1134
1135 return hr;
1136 }
1137
1138 HRESULT CMenuSFToolbar::OnDeletingButton(const NMTOOLBAR * tb)
1139 {
1140 ILFree(reinterpret_cast<LPITEMIDLIST>(tb->tbButton.dwData));
1141 return S_OK;
1142 }
1143
1144 HRESULT CMenuSFToolbar::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1145 {
1146 m_shellFolder = psf;
1147 m_idList = ILClone(pidlFolder);
1148 m_hKey = hKey;
1149 m_dwMenuFlags = dwFlags;
1150 return S_OK;
1151 }
1152
1153 HRESULT CMenuSFToolbar::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1154 {
1155 HRESULT hr;
1156
1157 hr = m_shellFolder->QueryInterface(riid, ppv);
1158 if (FAILED_UNEXPECTEDLY(hr))
1159 return hr;
1160
1161 if (pdwFlags)
1162 *pdwFlags = m_dwMenuFlags;
1163
1164 if (ppidl)
1165 {
1166 LPITEMIDLIST pidl = NULL;
1167
1168 if (m_idList)
1169 {
1170 pidl = ILClone(m_idList);
1171 if (!pidl)
1172 {
1173 (*(IUnknown**) ppv)->Release();
1174 return E_FAIL;
1175 }
1176 }
1177
1178 *ppidl = pidl;
1179 }
1180
1181 return hr;
1182 }
1183
1184 HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick)
1185 {
1186 HRESULT hr;
1187 CComPtr<IContextMenu> contextMenu;
1188 LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(rclick->dwItemData);
1189
1190 hr = m_shellFolder->GetUIObjectOf(m_hwndToolbar, 1, &pidl, IID_IContextMenu, NULL, reinterpret_cast<VOID **>(&contextMenu));
1191 if (hr != S_OK)
1192 return hr;
1193
1194 return DoContextMenu(contextMenu);
1195 }
1196
1197 HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1198 {
1199 HRESULT hr;
1200 hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1201 if (FAILED_UNEXPECTEDLY(hr))
1202 return hr;
1203
1204 // in case the clicked item has a submenu, we do not need to execute the item
1205 if (hr == S_FALSE)
1206 {
1207 DbgPrint("CMenuToolbarBase::OnCommand told us to cancel.\n");
1208 return hr;
1209 }
1210
1211 DWORD_PTR data;
1212 GetDataFromId(wParam, NULL, &data);
1213
1214 return m_menuBand->_CallCBWithItemPidl(reinterpret_cast<LPITEMIDLIST>(data), SMC_SFEXEC, 0, 0);
1215 }
1216
1217 HRESULT CMenuSFToolbar::InternalPopupItem(INT uItem, INT index, DWORD_PTR dwData)
1218 {
1219 HRESULT hr;
1220 UINT uId;
1221 UINT uIdAncestor;
1222 DWORD flags;
1223 CComPtr<IShellMenuCallback> psmc;
1224 CComPtr<IShellMenu> shellMenu;
1225
1226 LPITEMIDLIST pidl = reinterpret_cast<LPITEMIDLIST>(dwData);
1227
1228 if (!pidl)
1229 return E_FAIL;
1230
1231 #if USE_SYSTEM_MENUBAND
1232 hr = CoCreateInstance(CLSID_MenuBand,
1233 NULL,
1234 CLSCTX_INPROC_SERVER,
1235 IID_PPV_ARG(IShellMenu, &shellMenu));
1236 #else
1237 hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &shellMenu));
1238 #endif
1239 if (FAILED_UNEXPECTEDLY(hr))
1240 return hr;
1241 #if WRAP_MENUBAND
1242 hr = CMenuBand_Wrapper(shellMenu, IID_PPV_ARG(IShellMenu, &shellMenu));
1243 if (FAILED_UNEXPECTEDLY(hr))
1244 return hr;
1245 #endif
1246
1247 m_menuBand->GetMenuInfo(&psmc, &uId, &uIdAncestor, &flags);
1248
1249 // FIXME: not sure what to use as uId/uIdAncestor here
1250 hr = shellMenu->Initialize(psmc, 0, uId, SMINIT_VERTICAL);
1251 if (FAILED_UNEXPECTEDLY(hr))
1252 return hr;
1253
1254 CComPtr<IShellFolder> childFolder;
1255 hr = m_shellFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &childFolder));
1256 if (FAILED_UNEXPECTEDLY(hr))
1257 return hr;
1258
1259 hr = shellMenu->SetShellFolder(childFolder, NULL, NULL, 0);
1260 if (FAILED_UNEXPECTEDLY(hr))
1261 return hr;
1262
1263 return PopupSubMenu(uItem, index, shellMenu);
1264 }
1265
1266 HRESULT CMenuSFToolbar::InternalHasSubMenu(INT uItem, INT index, DWORD_PTR dwData)
1267 {
1268 HRESULT hr;
1269 LPCITEMIDLIST pidl = reinterpret_cast<LPITEMIDLIST>(dwData);
1270
1271 SFGAOF attrs = SFGAO_FOLDER;
1272 hr = m_shellFolder->GetAttributesOf(1, &pidl, &attrs);
1273 if (FAILED_UNEXPECTEDLY(hr))
1274 return hr;
1275
1276 return (attrs & SFGAO_FOLDER) ? S_OK : S_FALSE;
1277 }