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