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;
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                             ClientToScreen(&pt);
367                             hr = m_pISF->GetUIObjectOf(m_hWnd, 1, &pidl, IID_NULL_PPV_ARG(IContextMenu, &picm));
368                             if (FAILED_UNEXPECTEDLY(hr))
369                                 return hr;
370 
371                             hr = picm->QueryContextMenu(fmenu, 0, 1, 0x7FFF, CMF_DEFAULTONLY);
372                             if (FAILED_UNEXPECTEDLY(hr))
373                                 return hr;
374 
375                             int id = TrackPopupMenuEx(fmenu, TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_RETURNCMD, pt.x, pt.y, m_hWnd, 0);
376                             if (id > 0)
377                             {
378                                 CMINVOKECOMMANDINFOEX info = { 0 };
379                                 info.cbSize = sizeof(info);
380                                 info.fMask = CMIC_MASK_PTINVOKE;
381                                 if (GetKeyState(VK_CONTROL) < 0)
382                                 {
383                                     info.fMask |= CMIC_MASK_CONTROL_DOWN;
384                                 }
385                                 if (GetKeyState(VK_SHIFT) < 0)
386                                 {
387                                     info.fMask |= CMIC_MASK_SHIFT_DOWN;
388                                 }
389                                 info.hwnd = m_hWnd;
390                                 info.lpVerb = MAKEINTRESOURCEA(id - 1);
391                                 info.nShow = SW_SHOWNORMAL;
392                                 info.ptInvoke = pt;
393                                 picm->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
394                             }
395                         }
396                         DestroyMenu(fmenu);
397 
398                         if (theResult)
399                             *theResult = TRUE;
400                         break;
401                     }
402                     default:
403                         if (theResult)
404                             *theResult = FALSE;
405                 }
406 
407                 break;
408             }
409             default:
410                 if (theResult)
411                     *theResult = FALSE;
412         }
413 
414         return S_OK;
415     }
416 
417     STDMETHODIMP CISFBand::IsWindowOwner(HWND hWnd)
418     {
419         return (hWnd == m_hWnd) ? S_OK : S_FALSE;
420     }
421 
422 /*****************************************************************************/
423 // *** IOleCommandTarget methods ***
424     STDMETHODIMP CISFBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
425     {
426         UNIMPLEMENTED;
427 
428         return E_NOTIMPL;
429     }
430 
431     STDMETHODIMP CISFBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
432     {
433         if (IsEqualIID(*pguidCmdGroup, IID_IBandSite))
434         {
435             return S_OK;
436         }
437 
438         if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
439         {
440             if (nCmdID == DBID_SETWINDOWTHEME)
441             {
442                 if (pvaIn && V_VT(pvaIn) == VT_BSTR && V_BSTR(pvaIn))
443                 {
444                     SetWindowTheme(m_hWnd, V_BSTR(pvaIn), NULL);
445                 }
446             }
447             return S_OK;
448         }
449 
450         UNIMPLEMENTED;
451 
452         return E_NOTIMPL;
453     }
454 
455 /*****************************************************************************/
456 // *** IShellFolderBand ***
457     STDMETHODIMP CISFBand::GetBandInfoSFB(PBANDINFOSFB pbi)
458     {
459         if (pbi->dwMask == ISFB_MASK_IDLIST)
460         {
461             pbi->pidl = ILClone(m_pidl);
462             if (!pbi->pidl)
463                 return E_OUTOFMEMORY;
464             return S_OK;
465         }
466 
467         return E_NOTIMPL;
468     }
469 
470     STDMETHODIMP CISFBand::InitializeSFB(IShellFolder *psf, PCIDLIST_ABSOLUTE pidl)
471     {
472         HRESULT hr;
473 
474         if (!psf && !pidl)
475             return E_INVALIDARG;
476 
477         if (psf && pidl)
478             return E_INVALIDARG;
479 
480         if (pidl != NULL)
481         {
482             CComPtr<IShellFolder> psfDesktop;
483             hr = SHGetDesktopFolder(&psfDesktop);
484             if (FAILED_UNEXPECTEDLY(hr))
485                 return hr;
486 
487             if (_ILIsDesktop(pidl))
488             {
489                 m_pISF = psfDesktop;
490             }
491             else
492             {
493                 hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &m_pISF));
494                 if (FAILED_UNEXPECTEDLY(hr))
495                     return hr;
496             }
497 
498             m_pidl = ILClone(pidl);
499         }
500 
501         if (psf != NULL)
502         {
503             CComPtr<IPersistFolder2> ppf2;
504             hr = psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
505             if (FAILED_UNEXPECTEDLY(hr))
506                 return hr;
507 
508             hr = ppf2->GetCurFolder(&m_pidl);
509             if (FAILED_UNEXPECTEDLY(hr))
510                 return hr;
511 
512             m_pISF = psf;
513         }
514 
515         return S_OK;
516     }
517 
518     STDMETHODIMP CISFBand::SetBandInfoSFB( PBANDINFOSFB pbi)
519     {
520         if ((pbi->dwMask & ISFB_MASK_STATE) &&
521             (pbi->dwState & ISFB_STATE_QLINKSMODE) &&
522             (pbi->dwStateMask & ISFB_STATE_QLINKSMODE))
523         {
524             m_QLaunch = true;
525             m_textFlag = false;
526             if (m_hWnd)
527                 SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
528         }
529 
530         return E_NOTIMPL;
531     }
532 
533 /*****************************************************************************/
534 // *** IContextMenu ***
535     STDMETHODIMP CISFBand::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
536     {
537         /*HRESULT hr = E_INVALIDARG;
538 
539         if (idCmd == IDM_DISPLAY)
540         {
541             switch (uFlags)
542             {
543             case GCS_HELPTEXTW:
544                 // Only useful for pre-Vista versions of Windows that
545                 // have a Status bar.
546                 hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
547                     cchMax,
548                     L"Display File Name");
549                 break;
550 
551             case GCS_VERBW:
552                 // GCS_VERBW is an optional feature that enables a caller
553                 // to discover the canonical name for the verb that is passed in
554                 // through idCommand.
555                 hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
556                     cchMax,
557                     L"DisplayFileName");
558                 break;
559             }
560         }
561         return hr;  */
562 
563         return S_OK;
564     }
565 
566     STDMETHODIMP CISFBand::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
567     {
568         if (!HIWORD(pici->lpVerb))
569         {
570             switch (LOWORD(pici->lpVerb))
571             {
572                 case IDM_LARGE_ICONS:
573                 {
574                     m_iconFlag = false;
575 
576                     HIMAGELIST* piml = (HIMAGELIST*) SendMessage(m_hWnd, TB_GETIMAGELIST, 0, 0);
577                     HRESULT hr = SHGetImageList(SHIL_LARGE, IID_IImageList, (void**)&piml);
578                     if (FAILED_UNEXPECTEDLY(hr)) return hr;
579                     SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)piml);
580                     hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
581                     if (FAILED_UNEXPECTEDLY(hr)) return hr;
582                     break;
583                 }
584                 case IDM_SMALL_ICONS:
585                 {
586                     m_iconFlag = true;
587 
588                     HIMAGELIST* piml = (HIMAGELIST*)SendMessage(m_hWnd, TB_GETIMAGELIST, 0, 0);
589                     HRESULT hr = SHGetImageList(SHIL_SMALL, IID_IImageList, (void**)&piml);
590                     if (FAILED_UNEXPECTEDLY(hr)) return hr;
591                     SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)piml);
592                     hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
593                     if (FAILED_UNEXPECTEDLY(hr)) return hr;
594                     break;
595                 }
596                 case IDM_OPEN_FOLDER:
597                 {
598                     SHELLEXECUTEINFO shexinfo;
599 
600                     memset(&shexinfo, 0x0, sizeof(shexinfo));
601 
602                     shexinfo.cbSize = sizeof(shexinfo);
603                     shexinfo.fMask = SEE_MASK_IDLIST;
604                     shexinfo.lpVerb = _T("open");
605                     shexinfo.lpIDList = m_pidl;
606                     shexinfo.nShow = SW_SHOW;
607 
608                     if (!ShellExecuteEx(&shexinfo))
609                         return E_FAIL;
610 
611                     break;
612                 }
613                 case IDM_SHOW_TEXT:
614                 {
615                     if (m_textFlag)
616                     {
617                         m_textFlag = false;
618                         SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
619                         HRESULT hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
620                         if (FAILED_UNEXPECTEDLY(hr)) return hr;
621                     }
622                     else
623                     {
624                         m_textFlag = true;
625                         SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, 0);
626                         HRESULT hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
627                         if (FAILED_UNEXPECTEDLY(hr)) return hr;
628                     }
629                     break;
630                 }
631                 default:
632                     return E_FAIL;
633             }
634         }
635 
636         return S_OK;
637     }
638 
639     STDMETHODIMP CISFBand::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
640     {
641         HMENU qMenu = LoadMenu(GetModuleHandleW(L"browseui.dll"), MAKEINTRESOURCE(IDM_POPUPMENU));
642 
643         if(m_textFlag)
644             CheckMenuItem(qMenu, IDM_SHOW_TEXT, MF_CHECKED);
645         else
646             CheckMenuItem(qMenu, IDM_SHOW_TEXT, MF_UNCHECKED);
647 
648         if (m_iconFlag)
649         {
650             CheckMenuItem(qMenu, IDM_SMALL_ICONS, MF_CHECKED);
651             CheckMenuItem(qMenu, IDM_LARGE_ICONS, MF_UNCHECKED);
652         }
653         else
654         {
655             CheckMenuItem(qMenu, IDM_LARGE_ICONS, MF_CHECKED);
656             CheckMenuItem(qMenu, IDM_SMALL_ICONS, MF_UNCHECKED);
657         }
658 
659         if (_ILIsDesktop(m_pidl))
660             DeleteMenu(qMenu, IDM_OPEN_FOLDER, MF_BYCOMMAND);
661 
662         UINT idMax = Shell_MergeMenus(hmenu, GetSubMenu(qMenu, 0), indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
663         DestroyMenu(qMenu);
664         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(idMax - idCmdFirst +1));
665     }
666 
667 /*****************************************************************************/
668 // C Constructor
669     extern "C"
670     HRESULT WINAPI RSHELL_CISFBand_CreateInstance(REFIID riid, void** ppv)
671     {
672         return ShellObjectCreator<CISFBand>(riid, ppv);
673     }
674 
675