1 /*
2  * PROJECT:     ReactOS shell extensions
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        dll/shellext/qcklnch/CISFBand.cpp
5  * PURPOSE:     Quick Launch Toolbar (Taskbar Shell Extension)
6  * PROGRAMMERS: Shriraj Sawant a.k.a SR13 <sr.official@hotmail.com>
7  */
8 
9 #include "shellbars.h"
10 
11 #include <commoncontrols.h>
12 #include <shellapi.h>
13 #include <wingdi.h>
14 #include <uxtheme.h>
15 
16 /*
17 TODO:
18     ** drag and drop support
19     ** tooltips
20     ** handle change notifications
21     ** Fix position of the items context menu
22     ** Implement responding to theme change
23 */
24 
25 //*****************************************************************************************
26 // *** CISFBand ***
27 
28 CISFBand::CISFBand() :
29     m_BandID(0),
30     m_pidl(NULL),
31     m_textFlag(true),
32     m_iconFlag(true),
33     m_QLaunch(false)
34 {
35 }
36 
37 CISFBand::~CISFBand()
38 {
39     CloseDW(0);
40 }
41 
42 // Toolbar
43 /*++
44 * @name CreateSimpleToolbar
45 *
46 * Creates a toolbar and fills it up with buttons for enumerated objects.
47 *
48 * @param hWndParent
49 *        Handle to the parent window, which receives the appropriate messages from child toolbar.
50 *
51 * @return The error code.
52 *
53 *--*/
54 HRESULT CISFBand::CreateSimpleToolbar(HWND hWndParent)
55 {
56     // Declare and initialize local constants.
57     const DWORD buttonStyles = BTNS_AUTOSIZE;
58 
59     // Create the toolbar.
60     m_hWnd = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
61         WS_CHILD | TBSTYLE_FLAT | TBSTYLE_LIST | CCS_NORESIZE | CCS_NODIVIDER, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
62         hWndParent, NULL, 0, NULL);
63     if (m_hWnd == NULL)
64         return E_FAIL;
65 
66     if (!m_textFlag)
67         SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
68 
69     // Set the image list.
70     HIMAGELIST* piml;
71     HRESULT hr = SHGetImageList(SHIL_SMALL, IID_IImageList, (void**)&piml);
72     if (FAILED_UNEXPECTEDLY(hr))
73     {
74         DestroyWindow();
75         return hr;
76     }
77     SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)piml);
78 
79     // Enumerate objects
80     CComPtr<IEnumIDList> pEndl;
81     LPITEMIDLIST pidl;
82     STRRET stret;
83     hr = m_pISF->EnumObjects(0, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS, &pEndl);
84     if (FAILED_UNEXPECTEDLY(hr))
85     {
86         DestroyWindow();
87         return hr;
88     }
89 
90     for (int i=0; pEndl->Next(1, &pidl, NULL) != S_FALSE; i++)
91     {
92          WCHAR sz[MAX_PATH];
93          int index = SHMapPIDLToSystemImageListIndex(m_pISF, pidl, NULL);
94          hr = m_pISF->GetDisplayNameOf(pidl, SHGDN_NORMAL, &stret);
95          if (FAILED_UNEXPECTEDLY(hr))
96          {
97              StringCchCopyW(sz, MAX_PATH, L"<Unknown-Name>");
98          }
99          else
100              StrRetToBuf(&stret, pidl, sz, _countof(sz));
101 
102          TBBUTTON tb = { MAKELONG(index, 0), i, TBSTATE_ENABLED, buttonStyles,{ 0 }, (DWORD_PTR)pidl, (INT_PTR)sz };
103          SendMessage(m_hWnd, TB_INSERTBUTTONW, i, (LPARAM)&tb);
104     }
105 
106     // Resize the toolbar, and then show it.
107     SendMessage(m_hWnd, TB_AUTOSIZE, 0, 0);
108 
109     return hr;
110 }
111 
112 /*****************************************************************************/
113 
114 // *** IObjectWithSite ***
115     STDMETHODIMP CISFBand::SetSite(IUnknown *pUnkSite)
116     {
117         HRESULT hr;
118         HWND hwndParent;
119 
120         TRACE("CISFBand::SetSite(0x%p)\n", pUnkSite);
121 
122         hr = IUnknown_GetWindow(pUnkSite, &hwndParent);
123         if (FAILED(hr))
124         {
125             TRACE("Querying site window failed: 0x%x\n", hr);
126             return hr;
127         }
128         m_Site = pUnkSite;
129 
130         hr = CreateSimpleToolbar(hwndParent);
131         if (FAILED_UNEXPECTEDLY(hr))
132             return hr;
133 
134         return S_OK;
135     }
136 
137     STDMETHODIMP CISFBand::GetSite(IN REFIID riid, OUT VOID **ppvSite)
138     {
139         TRACE("CISFBand::GetSite(0x%p,0x%p)\n", riid, ppvSite);
140 
141         HRESULT hr;
142         if (m_Site != NULL)
143         {
144             hr = m_Site->QueryInterface(riid, ppvSite);
145             if (FAILED(hr)) return hr;
146         }
147 
148         *ppvSite = NULL;
149         return E_FAIL;
150     }
151 
152 /*****************************************************************************/
153 // *** IDeskBand ***
154     STDMETHODIMP CISFBand::GetWindow(OUT HWND *phwnd)
155     {
156         if (!m_hWnd)
157             return E_FAIL;
158         if (!phwnd)
159             return E_POINTER;
160         *phwnd = m_hWnd;
161 
162         return S_OK;
163     }
164 
165     STDMETHODIMP CISFBand::ContextSensitiveHelp(IN BOOL fEnterMode)
166     {
167         /* FIXME: Implement */
168         return E_NOTIMPL;
169     }
170 
171     STDMETHODIMP CISFBand::ShowDW(IN BOOL bShow)
172     {
173         if (m_hWnd)
174         {
175             ShowWindow(bShow ? SW_SHOW : SW_HIDE);
176             return S_OK;
177         }
178 
179         return E_FAIL;
180     }
181 
182     STDMETHODIMP CISFBand::CloseDW(IN DWORD dwReserved)
183     {
184         if (m_hWnd)
185         {
186             ShowWindow(SW_HIDE);
187 
188             TBBUTTON tb;
189             for (int i = 0; SendMessage(m_hWnd, TB_GETBUTTON, i, (LPARAM)&tb); i++)
190             {
191                 CoTaskMemFree((LPITEMIDLIST)tb.dwData);
192             }
193 
194             DestroyWindow();
195             m_hWnd = NULL;
196             return S_OK;
197         }
198 
199         return E_FAIL;
200     }
201 
202     STDMETHODIMP CISFBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
203     {
204         /* No need to implement this method */
205 
206         return E_NOTIMPL;
207     }
208 
209     STDMETHODIMP CISFBand::GetBandInfo(IN DWORD dwBandID, IN DWORD dwViewMode, IN OUT DESKBANDINFO *pdbi)
210     {
211         TRACE("CTaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, m_hWnd);
212 
213         if (m_hWnd && pdbi)
214         {
215             m_BandID = dwBandID;
216 
217             RECT actualRect;
218             POINTL actualSize;
219             POINTL idealSize;
220             POINTL maxSize;
221             POINTL itemSize;
222 
223             GetWindowRect(&actualRect);
224             actualSize.x = actualRect.right - actualRect.left;
225             actualSize.y = actualRect.bottom - actualRect.top;
226 
227             // Obtain the ideal size, to be used as min and max
228             SendMessageW(m_hWnd, TB_AUTOSIZE, 0, 0);
229             SendMessageW(m_hWnd, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&maxSize));
230 
231             idealSize = maxSize;
232             SendMessageW(m_hWnd, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&idealSize));
233 
234             // Obtain the button size, to be used as the integral size
235             DWORD size = SendMessageW(m_hWnd, TB_GETBUTTONSIZE, 0, 0);
236             itemSize.x = GET_X_LPARAM(size);
237             itemSize.y = GET_Y_LPARAM(size);
238 
239             if (pdbi->dwMask & DBIM_MINSIZE)
240             {
241                 if (m_QLaunch)
242                     pdbi->ptMinSize.x = idealSize.x;
243                 else
244                     pdbi->ptMinSize.x = -1;
245                 pdbi->ptMinSize.y = idealSize.y;
246             }
247             if (pdbi->dwMask & DBIM_MAXSIZE)
248             {
249                 pdbi->ptMaxSize = maxSize;
250             }
251             if (pdbi->dwMask & DBIM_INTEGRAL)
252             {
253                 pdbi->ptIntegral = itemSize;
254             }
255             if (pdbi->dwMask & DBIM_ACTUAL)
256             {
257                 pdbi->ptActual = actualSize;
258             }
259             if (pdbi->dwMask & DBIM_TITLE)
260             {
261                 if (m_QLaunch || !ILGetDisplayNameEx(NULL, m_pidl, pdbi->wszTitle, ILGDN_INFOLDER))
262                 {
263                     pdbi->dwMask &= ~DBIM_TITLE;
264                 }
265             }
266             if (pdbi->dwMask & DBIM_MODEFLAGS)
267             {
268                 pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT | DBIMF_USECHEVRON | DBIMF_NOMARGINS | DBIMF_BKCOLOR;
269                 if (m_QLaunch)
270                 {
271                     pdbi->dwModeFlags |= DBIMF_ADDTOFRONT;
272                 }
273             }
274             if (pdbi->dwMask & DBIM_BKCOLOR)
275                 pdbi->dwMask &= ~DBIM_BKCOLOR;
276 
277             return S_OK;
278         }
279 
280         return E_FAIL;
281     }
282 
283 /*****************************************************************************/
284 // *** IPersistStream ***
285     STDMETHODIMP CISFBand::GetClassID(OUT CLSID *pClassID)
286     {
287         *pClassID = CLSID_ISFBand;
288 
289         return S_OK;
290     }
291 
292     STDMETHODIMP CISFBand::IsDirty()
293     {
294         /* The object hasn't changed since the last save! */
295 
296         return S_FALSE;
297     }
298 
299     STDMETHODIMP CISFBand::Load(IN IStream *pStm)
300     {
301         TRACE("CISFBand::Load called\n");
302         /* Nothing to do */
303 
304         return S_OK;
305     }
306 
307     STDMETHODIMP CISFBand::Save(IN IStream *pStm, IN BOOL fClearDirty)
308     {
309         /* Nothing to do */
310 
311         return S_OK;
312     }
313 
314     STDMETHODIMP CISFBand::GetSizeMax(OUT ULARGE_INTEGER *pcbSize)
315     {
316         TRACE("CISFBand::GetSizeMax called\n");
317 
318         return S_OK;
319     }
320 
321 /*****************************************************************************/
322 // *** IWinEventHandler ***
323     STDMETHODIMP CISFBand::ContainsWindow(IN HWND hWnd)
324     {
325         if (hWnd == m_hWnd || IsChild(hWnd))
326         {
327             TRACE("CISFBand::ContainsWindow(0x%p) returns S_OK\n", hWnd);
328             return S_OK;
329         }
330 
331         return S_FALSE;
332     }
333 
334     STDMETHODIMP CISFBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
335     {
336         switch (uMsg)
337         {
338             case WM_COMMAND:
339             {
340                 TBBUTTON tb;
341                 bool chk = SendMessage(m_hWnd, TB_GETBUTTON, LOWORD(wParam), (LPARAM)&tb);
342                 if (chk)
343                     SHInvokeDefaultCommand(m_hWnd, m_pISF, (LPITEMIDLIST)tb.dwData);
344 
345                 if (theResult)
346                     *theResult = TRUE;
347                 break;
348             }
349             case WM_NOTIFY:
350             {
351                 switch (((LPNMHDR)lParam)->code)
352                 {
353                     case NM_RCLICK:
354                     {
355                         HRESULT hr;
356                         POINT pt = ((LPNMMOUSE)lParam)->pt; // Already in screen coordinates
357                         CComPtr<IContextMenu> picm;
358                         HMENU fmenu = CreatePopupMenu();
359                         TBBUTTON tb;
360 
361                         bool chk = SendMessage(m_hWnd, TB_GETBUTTON, ((LPNMMOUSE)lParam)->dwItemSpec, (LPARAM)&tb);
362                         LPITEMIDLIST pidl = (LPITEMIDLIST)tb.dwData;
363 
364                         if (chk)
365                         {
366                             hr = m_pISF->GetUIObjectOf(m_hWnd, 1, &pidl, IID_NULL_PPV_ARG(IContextMenu, &picm));
367                             if (FAILED_UNEXPECTEDLY(hr))
368                                 return hr;
369 
370                             hr = picm->QueryContextMenu(fmenu, 0, 1, 0x7FFF, CMF_DEFAULTONLY);
371                             if (FAILED_UNEXPECTEDLY(hr))
372                                 return hr;
373 
374                             int id = TrackPopupMenuEx(fmenu, TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_RETURNCMD, pt.x, pt.y, m_hWnd, 0);
375                             if (id > 0)
376                             {
377                                 CMINVOKECOMMANDINFOEX info = { 0 };
378                                 info.cbSize = sizeof(info);
379                                 info.fMask = CMIC_MASK_PTINVOKE;
380                                 if (GetKeyState(VK_CONTROL) < 0)
381                                 {
382                                     info.fMask |= CMIC_MASK_CONTROL_DOWN;
383                                 }
384                                 if (GetKeyState(VK_SHIFT) < 0)
385                                 {
386                                     info.fMask |= CMIC_MASK_SHIFT_DOWN;
387                                 }
388                                 info.hwnd = m_hWnd;
389                                 info.lpVerb = MAKEINTRESOURCEA(id - 1);
390                                 info.nShow = SW_SHOWNORMAL;
391                                 info.ptInvoke = pt;
392                                 picm->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
393                             }
394                         }
395                         DestroyMenu(fmenu);
396 
397                         if (theResult)
398                             *theResult = TRUE;
399                         break;
400                     }
401                     default:
402                         if (theResult)
403                             *theResult = FALSE;
404                 }
405 
406                 break;
407             }
408             default:
409                 if (theResult)
410                     *theResult = FALSE;
411         }
412 
413         return S_OK;
414     }
415 
416     STDMETHODIMP CISFBand::IsWindowOwner(HWND hWnd)
417     {
418         return (hWnd == m_hWnd) ? S_OK : S_FALSE;
419     }
420 
421 /*****************************************************************************/
422 // *** IOleCommandTarget methods ***
423     STDMETHODIMP CISFBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
424     {
425         UNIMPLEMENTED;
426 
427         return E_NOTIMPL;
428     }
429 
430     STDMETHODIMP CISFBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
431     {
432         if (IsEqualIID(*pguidCmdGroup, IID_IBandSite))
433         {
434             return S_OK;
435         }
436 
437         if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
438         {
439             if (nCmdID == DBID_SETWINDOWTHEME)
440             {
441                 if (pvaIn && V_VT(pvaIn) == VT_BSTR && V_BSTR(pvaIn))
442                 {
443                     SetWindowTheme(m_hWnd, V_BSTR(pvaIn), NULL);
444                 }
445             }
446             return S_OK;
447         }
448 
449         UNIMPLEMENTED;
450 
451         return E_NOTIMPL;
452     }
453 
454 /*****************************************************************************/
455 // *** IShellFolderBand ***
456     STDMETHODIMP CISFBand::GetBandInfoSFB(PBANDINFOSFB pbi)
457     {
458         if (pbi->dwMask == ISFB_MASK_IDLIST)
459         {
460             pbi->pidl = ILClone(m_pidl);
461             if (!pbi->pidl)
462                 return E_OUTOFMEMORY;
463             return S_OK;
464         }
465 
466         return E_NOTIMPL;
467     }
468 
469     STDMETHODIMP CISFBand::InitializeSFB(IShellFolder *psf, PCIDLIST_ABSOLUTE pidl)
470     {
471         HRESULT hr;
472 
473         if (!psf && !pidl)
474             return E_INVALIDARG;
475 
476         if (psf && pidl)
477             return E_INVALIDARG;
478 
479         if (pidl != NULL)
480         {
481             CComPtr<IShellFolder> psfDesktop;
482             hr = SHGetDesktopFolder(&psfDesktop);
483             if (FAILED_UNEXPECTEDLY(hr))
484                 return hr;
485 
486             if (_ILIsDesktop(pidl))
487             {
488                 m_pISF = psfDesktop;
489             }
490             else
491             {
492                 hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &m_pISF));
493                 if (FAILED_UNEXPECTEDLY(hr))
494                     return hr;
495             }
496 
497             m_pidl = ILClone(pidl);
498         }
499 
500         if (psf != NULL)
501         {
502             CComPtr<IPersistFolder2> ppf2;
503             hr = psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
504             if (FAILED_UNEXPECTEDLY(hr))
505                 return hr;
506 
507             hr = ppf2->GetCurFolder(&m_pidl);
508             if (FAILED_UNEXPECTEDLY(hr))
509                 return hr;
510 
511             m_pISF = psf;
512         }
513 
514         return S_OK;
515     }
516 
517     STDMETHODIMP CISFBand::SetBandInfoSFB( PBANDINFOSFB pbi)
518     {
519         if ((pbi->dwMask & ISFB_MASK_STATE) &&
520             (pbi->dwState & ISFB_STATE_QLINKSMODE) &&
521             (pbi->dwStateMask & ISFB_STATE_QLINKSMODE))
522         {
523             m_QLaunch = true;
524             m_textFlag = false;
525             if (m_hWnd)
526                 SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
527         }
528 
529         return E_NOTIMPL;
530     }
531 
532 /*****************************************************************************/
533 // *** IContextMenu ***
534     STDMETHODIMP CISFBand::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
535     {
536         /*HRESULT hr = E_INVALIDARG;
537 
538         if (idCmd == IDM_DISPLAY)
539         {
540             switch (uFlags)
541             {
542             case GCS_HELPTEXTW:
543                 // Only useful for pre-Vista versions of Windows that
544                 // have a Status bar.
545                 hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
546                     cchMax,
547                     L"Display File Name");
548                 break;
549 
550             case GCS_VERBW:
551                 // GCS_VERBW is an optional feature that enables a caller
552                 // to discover the canonical name for the verb that is passed in
553                 // through idCommand.
554                 hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
555                     cchMax,
556                     L"DisplayFileName");
557                 break;
558             }
559         }
560         return hr;  */
561 
562         return S_OK;
563     }
564 
565     STDMETHODIMP CISFBand::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
566     {
567         if (!HIWORD(pici->lpVerb))
568         {
569             switch (LOWORD(pici->lpVerb))
570             {
571                 case IDM_LARGE_ICONS:
572                 {
573                     m_iconFlag = false;
574 
575                     HIMAGELIST* piml = (HIMAGELIST*) SendMessage(m_hWnd, TB_GETIMAGELIST, 0, 0);
576                     HRESULT hr = SHGetImageList(SHIL_LARGE, IID_IImageList, (void**)&piml);
577                     if (FAILED_UNEXPECTEDLY(hr)) return hr;
578                     SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)piml);
579                     hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
580                     if (FAILED_UNEXPECTEDLY(hr)) return hr;
581                     break;
582                 }
583                 case IDM_SMALL_ICONS:
584                 {
585                     m_iconFlag = true;
586 
587                     HIMAGELIST* piml = (HIMAGELIST*)SendMessage(m_hWnd, TB_GETIMAGELIST, 0, 0);
588                     HRESULT hr = SHGetImageList(SHIL_SMALL, IID_IImageList, (void**)&piml);
589                     if (FAILED_UNEXPECTEDLY(hr)) return hr;
590                     SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)piml);
591                     hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
592                     if (FAILED_UNEXPECTEDLY(hr)) return hr;
593                     break;
594                 }
595                 case IDM_OPEN_FOLDER:
596                 {
597                     SHELLEXECUTEINFO shexinfo;
598 
599                     memset(&shexinfo, 0x0, sizeof(shexinfo));
600 
601                     shexinfo.cbSize = sizeof(shexinfo);
602                     shexinfo.fMask = SEE_MASK_IDLIST;
603                     shexinfo.lpVerb = _T("open");
604                     shexinfo.lpIDList = m_pidl;
605                     shexinfo.nShow = SW_SHOW;
606 
607                     if (!ShellExecuteEx(&shexinfo))
608                         return E_FAIL;
609 
610                     break;
611                 }
612                 case IDM_SHOW_TEXT:
613                 {
614                     if (m_textFlag)
615                     {
616                         m_textFlag = false;
617                         SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
618                         HRESULT hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
619                         if (FAILED_UNEXPECTEDLY(hr)) return hr;
620                     }
621                     else
622                     {
623                         m_textFlag = true;
624                         SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, 0);
625                         HRESULT hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
626                         if (FAILED_UNEXPECTEDLY(hr)) return hr;
627                     }
628                     break;
629                 }
630                 default:
631                     return E_FAIL;
632             }
633         }
634 
635         return S_OK;
636     }
637 
638     STDMETHODIMP CISFBand::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
639     {
640         HMENU qMenu = LoadMenu(GetModuleHandleW(L"browseui.dll"), MAKEINTRESOURCE(IDM_POPUPMENU));
641 
642         if(m_textFlag)
643             CheckMenuItem(qMenu, IDM_SHOW_TEXT, MF_CHECKED);
644         else
645             CheckMenuItem(qMenu, IDM_SHOW_TEXT, MF_UNCHECKED);
646 
647         if (m_iconFlag)
648         {
649             CheckMenuItem(qMenu, IDM_SMALL_ICONS, MF_CHECKED);
650             CheckMenuItem(qMenu, IDM_LARGE_ICONS, MF_UNCHECKED);
651         }
652         else
653         {
654             CheckMenuItem(qMenu, IDM_LARGE_ICONS, MF_CHECKED);
655             CheckMenuItem(qMenu, IDM_SMALL_ICONS, MF_UNCHECKED);
656         }
657 
658         if (_ILIsDesktop(m_pidl))
659             DeleteMenu(qMenu, IDM_OPEN_FOLDER, MF_BYCOMMAND);
660 
661         UINT idMax = Shell_MergeMenus(hmenu, GetSubMenu(qMenu, 0), indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
662         DestroyMenu(qMenu);
663         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(idMax - idCmdFirst +1));
664     }
665 
666 /*****************************************************************************/
667 // C Constructor
668     extern "C"
669     HRESULT WINAPI RSHELL_CISFBand_CreateInstance(REFIID riid, void** ppv)
670     {
671         return ShellObjectCreator<CISFBand>(riid, ppv);
672     }
673 
674