1 /* 2 * PROJECT: NT Object Namespace shell extension 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Folder view class header and implementation 5 * COPYRIGHT: Copyright 2015-2017 David Quintana <gigaherz@gmail.com> 6 */ 7 8 #pragma once 9 10 extern const GUID CLSID_NtObjectFolder; 11 12 class CFolderViewCB : 13 public CComObjectRootEx<CComMultiThreadModelNoCS>, 14 public IShellFolderViewCB 15 { 16 IShellView* m_View; 17 18 public: 19 CFolderViewCB()20 CFolderViewCB() : m_View(NULL) {} ~CFolderViewCB()21 virtual ~CFolderViewCB() {} 22 MessageSFVCB(UINT uMsg,WPARAM wParam,LPARAM lParam)23 STDMETHODIMP MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) override 24 { 25 switch (uMsg) 26 { 27 case SFVM_DEFVIEWMODE: 28 { 29 FOLDERVIEWMODE* pViewMode = (FOLDERVIEWMODE*)lParam; 30 *pViewMode = FVM_DETAILS; 31 return S_OK; 32 } 33 34 case SFVM_COLUMNCLICK: 35 return S_FALSE; 36 37 case SFVM_BACKGROUNDENUM: 38 return S_OK; 39 } 40 41 DbgPrint("MessageSFVCB unimplemented %d %08x %08x\n", uMsg, wParam, lParam); 42 return E_NOTIMPL; 43 } 44 STDMETHOD(Initialize)45 STDMETHOD(Initialize)(IShellView* psv) 46 { 47 m_View = psv; 48 return S_OK; 49 } 50 51 DECLARE_NOT_AGGREGATABLE(CFolderViewCB) 52 DECLARE_PROTECT_FINAL_CONSTRUCT() 53 54 BEGIN_COM_MAP(CFolderViewCB) 55 COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB) 56 END_COM_MAP() 57 }; 58 59 template<class TSelf, typename TItemId, class TExtractIcon> 60 class CCommonFolder : 61 public CComObjectRootEx<CComMultiThreadModelNoCS>, 62 public IShellFolder2, 63 public IPersistFolder2 64 { 65 protected: 66 WCHAR m_NtPath[MAX_PATH]; 67 68 LPITEMIDLIST m_shellPidl; 69 70 public: 71 CCommonFolder()72 CCommonFolder() : 73 m_shellPidl(NULL) 74 { 75 } 76 ~CCommonFolder()77 virtual ~CCommonFolder() 78 { 79 if (m_shellPidl) 80 ILFree(m_shellPidl); 81 } 82 83 // IShellFolder ParseDisplayName(HWND hwndOwner,LPBC pbcReserved,LPOLESTR lpszDisplayName,ULONG * pchEaten,LPITEMIDLIST * ppidl,ULONG * pdwAttributes)84 STDMETHODIMP ParseDisplayName( 85 HWND hwndOwner, 86 LPBC pbcReserved, 87 LPOLESTR lpszDisplayName, 88 ULONG *pchEaten, 89 LPITEMIDLIST *ppidl, 90 ULONG *pdwAttributes) override 91 { 92 if (!ppidl) 93 return E_POINTER; 94 95 if (pchEaten) 96 *pchEaten = 0; 97 98 if (pdwAttributes) 99 *pdwAttributes = 0; 100 101 TRACE("CCommonFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName, m_NtPath); 102 103 const TItemId * info; 104 IEnumIDList * it; 105 HRESULT hr = EnumObjects(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &it); 106 if (FAILED(hr)) 107 return hr; 108 109 PWSTR end = StrChrW(lpszDisplayName, '\\'); 110 int length = end ? end - lpszDisplayName : wcslen(lpszDisplayName); 111 112 while (TRUE) 113 { 114 hr = it->Next(1, ppidl, NULL); 115 116 if (FAILED(hr)) 117 return hr; 118 119 if (hr != S_OK) 120 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 121 122 hr = GetInfoFromPidl(*ppidl, &info); 123 if (FAILED_UNEXPECTEDLY(hr)) 124 return hr; 125 126 if (StrCmpNW(info->entryName, lpszDisplayName, length) == 0) 127 break; 128 } 129 130 // if has remaining path to parse (and the path didn't just terminate in a backslash) 131 if (end && wcslen(end) > 1) 132 { 133 CComPtr<IShellFolder> psfChild; 134 hr = BindToObject(*ppidl, pbcReserved, IID_PPV_ARG(IShellFolder, &psfChild)); 135 if (FAILED_UNEXPECTEDLY(hr)) 136 return hr; 137 138 LPITEMIDLIST child; 139 hr = psfChild->ParseDisplayName(hwndOwner, pbcReserved, end + 1, pchEaten, &child, pdwAttributes); 140 if (FAILED(hr)) 141 return hr; 142 143 LPITEMIDLIST old = *ppidl; 144 *ppidl = ILCombine(old, child); 145 ILFree(old); 146 147 // Count the path separator 148 if (pchEaten) 149 (*pchEaten) += 1; 150 } 151 else 152 { 153 if (pdwAttributes) 154 *pdwAttributes = ConvertAttributes(info, pdwAttributes); 155 } 156 157 if (pchEaten) 158 *pchEaten += wcslen(info->entryName); 159 160 return S_OK; 161 } 162 163 STDMETHOD(EnumObjects)( 164 HWND hwndOwner, 165 SHCONTF grfFlags, 166 IEnumIDList **ppenumIDList) PURE; 167 BindToObject(LPCITEMIDLIST pidl,LPBC pbcReserved,REFIID riid,void ** ppvOut)168 STDMETHODIMP BindToObject( 169 LPCITEMIDLIST pidl, 170 LPBC pbcReserved, 171 REFIID riid, 172 void **ppvOut) override 173 { 174 const TItemId * info; 175 176 if (IsEqualIID(riid, IID_IShellFolder)) 177 { 178 HRESULT hr = GetInfoFromPidl(pidl, &info); 179 if (FAILED_UNEXPECTEDLY(hr)) 180 return hr; 181 182 WCHAR path[MAX_PATH]; 183 184 StringCbCopyW(path, sizeof(path), m_NtPath); 185 PathAppendW(path, info->entryName); 186 187 LPITEMIDLIST first = ILCloneFirst(pidl); 188 LPCITEMIDLIST rest = ILGetNext(pidl); 189 190 LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, first); 191 192 CComPtr<IShellFolder> psfChild; 193 hr = InternalBindToObject(path, info, first, rest, fullPidl, pbcReserved, &psfChild); 194 195 ILFree(fullPidl); 196 ILFree(first); 197 198 if (FAILED(hr)) 199 return hr; 200 201 if (hr == S_FALSE) 202 return S_OK; 203 204 if (rest->mkid.cb > 0) 205 { 206 return psfChild->BindToObject(rest, pbcReserved, riid, ppvOut); 207 } 208 209 return psfChild->QueryInterface(riid, ppvOut); 210 } 211 212 return E_NOTIMPL; 213 } 214 215 protected: 216 STDMETHOD(InternalBindToObject)( 217 PWSTR path, 218 const TItemId * info, 219 LPITEMIDLIST first, 220 LPCITEMIDLIST rest, 221 LPITEMIDLIST fullPidl, 222 LPBC pbcReserved, 223 IShellFolder** ppsfChild) PURE; 224 STDMETHOD(ResolveSymLink)225 STDMETHOD(ResolveSymLink)( 226 const TItemId * info, 227 LPITEMIDLIST * fullPidl) 228 { 229 return E_NOTIMPL; 230 } 231 232 public: BindToStorage(LPCITEMIDLIST pidl,LPBC pbcReserved,REFIID riid,void ** ppvObj)233 STDMETHODIMP BindToStorage( 234 LPCITEMIDLIST pidl, 235 LPBC pbcReserved, 236 REFIID riid, 237 void **ppvObj) override 238 { 239 UNIMPLEMENTED; 240 return E_NOTIMPL; 241 } 242 CompareIDs(LPARAM lParam,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)243 STDMETHODIMP CompareIDs( 244 LPARAM lParam, 245 LPCITEMIDLIST pidl1, 246 LPCITEMIDLIST pidl2) override 247 { 248 HRESULT hr; 249 250 TRACE("CompareIDs %d\n", lParam); 251 252 const TItemId * id1; 253 hr = GetInfoFromPidl(pidl1, &id1); 254 if (FAILED(hr)) 255 return E_INVALIDARG; 256 257 const TItemId * id2; 258 hr = GetInfoFromPidl(pidl2, &id2); 259 if (FAILED(hr)) 260 return E_INVALIDARG; 261 262 hr = CompareIDs(lParam, id1, id2); 263 if (hr != S_EQUAL) 264 return hr; 265 266 // The wollowing snipped is basically SHELL32_CompareChildren 267 268 PUIDLIST_RELATIVE rest1 = ILGetNext(pidl1); 269 PUIDLIST_RELATIVE rest2 = ILGetNext(pidl2); 270 271 bool isEmpty1 = (rest1->mkid.cb == 0); 272 bool isEmpty2 = (rest2->mkid.cb == 0); 273 274 if (isEmpty1 || isEmpty2) 275 return MAKE_COMPARE_HRESULT(isEmpty2 - isEmpty1); 276 277 LPCITEMIDLIST first1 = ILCloneFirst(pidl1); 278 if (!first1) 279 return E_OUTOFMEMORY; 280 281 CComPtr<IShellFolder> psfNext; 282 hr = BindToObject(first1, NULL, IID_PPV_ARG(IShellFolder, &psfNext)); 283 if (FAILED_UNEXPECTEDLY(hr)) 284 return hr; 285 286 return psfNext->CompareIDs(lParam, rest1, rest2); 287 } 288 289 protected: STDMETHOD(CompareName)290 STDMETHOD(CompareName)( 291 LPARAM lParam, 292 const TItemId * first, 293 const TItemId * second) 294 { 295 bool f1 = IsFolder(first); 296 bool f2 = IsFolder(second); 297 298 HRESULT hr = MAKE_COMPARE_HRESULT(f2 - f1); 299 if (hr != S_EQUAL) 300 return hr; 301 302 bool canonical = (lParam & 0xFFFF0000) == SHCIDS_CANONICALONLY; 303 if (canonical) 304 { 305 // Shortcut: avoid comparing contents if not necessary when the results are not for display. 306 hr = MAKE_COMPARE_HRESULT(second->entryNameLength - first->entryNameLength); 307 if (hr != S_EQUAL) 308 return hr; 309 310 int minlength = min(first->entryNameLength, second->entryNameLength); 311 if (minlength > 0) 312 { 313 hr = MAKE_COMPARE_HRESULT(memcmp(first->entryName, second->entryName, minlength)); 314 if (hr != S_EQUAL) 315 return hr; 316 } 317 318 return S_EQUAL; 319 } 320 321 int minlength = min(first->entryNameLength, second->entryNameLength); 322 if (minlength > 0) 323 { 324 hr = MAKE_COMPARE_HRESULT(StrCmpNW(first->entryName, second->entryName, minlength / sizeof(WCHAR))); 325 if (hr != S_EQUAL) 326 return hr; 327 } 328 329 return MAKE_COMPARE_HRESULT(second->entryNameLength - first->entryNameLength); 330 } 331 332 public: CreateViewObject(HWND hwndOwner,REFIID riid,void ** ppvOut)333 STDMETHODIMP CreateViewObject( 334 HWND hwndOwner, 335 REFIID riid, 336 void **ppvOut) override 337 { 338 if (!IsEqualIID(riid, IID_IShellView)) 339 return E_NOINTERFACE; 340 341 _CComObject<CFolderViewCB> *pcb; 342 343 HRESULT hr = _CComObject<CFolderViewCB>::CreateInstance(&pcb); 344 if (FAILED(hr)) 345 return hr; 346 347 pcb->AddRef(); 348 349 SFV_CREATE sfv; 350 sfv.cbSize = sizeof(sfv); 351 sfv.pshf = this; 352 sfv.psvOuter = NULL; 353 sfv.psfvcb = pcb; 354 355 IShellView* view; 356 357 hr = SHCreateShellFolderView(&sfv, &view); 358 if (FAILED(hr)) 359 return hr; 360 361 pcb->Initialize(view); 362 363 pcb->Release(); 364 365 *ppvOut = view; 366 367 return S_OK; 368 } 369 GetAttributesOf(UINT cidl,PCUITEMID_CHILD_ARRAY apidl,SFGAOF * rgfInOut)370 STDMETHODIMP GetAttributesOf( 371 UINT cidl, 372 PCUITEMID_CHILD_ARRAY apidl, 373 SFGAOF *rgfInOut) override 374 { 375 const TItemId * info; 376 377 TRACE("GetAttributesOf %d\n", cidl); 378 379 if (cidl == 0) 380 { 381 *rgfInOut &= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE; 382 return S_OK; 383 } 384 385 for (int i = 0; i < (int)cidl; i++) 386 { 387 PCUITEMID_CHILD pidl = apidl[i]; 388 389 HRESULT hr = GetInfoFromPidl(pidl, &info); 390 if (FAILED_UNEXPECTEDLY(hr)) 391 return hr; 392 393 // Update attributes. 394 *rgfInOut = ConvertAttributes(info, rgfInOut); 395 } 396 397 return S_OK; 398 } 399 GetUIObjectOf(HWND hwndOwner,UINT cidl,PCUITEMID_CHILD_ARRAY apidl,REFIID riid,UINT * prgfInOut,void ** ppvOut)400 STDMETHODIMP GetUIObjectOf( 401 HWND hwndOwner, 402 UINT cidl, 403 PCUITEMID_CHILD_ARRAY apidl, 404 REFIID riid, 405 UINT *prgfInOut, 406 void **ppvOut) override 407 { 408 DWORD res; 409 TRACE("GetUIObjectOf\n"); 410 411 if (IsEqualIID(riid, IID_IContextMenu) || 412 IsEqualIID(riid, IID_IContextMenu2) || 413 IsEqualIID(riid, IID_IContextMenu3)) 414 { 415 CComPtr<IContextMenu> pcm; 416 417 HKEY keys[1]; 418 419 LPITEMIDLIST parent = m_shellPidl; 420 421 CComPtr<IShellFolder> psfParent = this; 422 423 LPCITEMIDLIST child; 424 425 int nkeys = _countof(keys); 426 if (cidl == 1 && IsSymLink(apidl[0])) 427 { 428 const TItemId * info; 429 HRESULT hr = GetInfoFromPidl(apidl[0], &info); 430 if (FAILED(hr)) 431 return hr; 432 433 LPITEMIDLIST target; 434 hr = ResolveSymLink(info, &target); 435 if (FAILED(hr)) 436 return hr; 437 438 CComPtr<IShellFolder> psfTarget; 439 hr = ::SHBindToParent(target, IID_PPV_ARG(IShellFolder, &psfTarget), &child); 440 if (FAILED(hr)) 441 { 442 ILFree(target); 443 return hr; 444 } 445 446 parent = ILClone(target); 447 ILRemoveLastID(parent); 448 psfParent = psfTarget; 449 450 apidl = &child; 451 } 452 453 if (cidl == 1 && IsFolder(apidl[0])) 454 { 455 res = RegOpenKey(HKEY_CLASSES_ROOT, L"Folder", keys + 0); 456 if (!NT_SUCCESS(res)) 457 return HRESULT_FROM_NT(res); 458 } 459 else 460 { 461 nkeys = 0; 462 } 463 464 HRESULT hr = CDefFolderMenu_Create2(parent, hwndOwner, cidl, apidl, psfParent, DefCtxMenuCallback, nkeys, keys, &pcm); 465 if (FAILED_UNEXPECTEDLY(hr)) 466 return hr; 467 468 return pcm->QueryInterface(riid, ppvOut); 469 } 470 471 if (IsEqualIID(riid, IID_IExtractIconW)) 472 { 473 return ShellObjectCreatorInit<TExtractIcon>(m_NtPath, m_shellPidl, cidl, apidl, riid, ppvOut); 474 } 475 476 if (IsEqualIID(riid, IID_IDataObject)) 477 { 478 return CIDLData_CreateFromIDArray(m_shellPidl, cidl, apidl, (IDataObject**)ppvOut); 479 } 480 481 if (IsEqualIID(riid, IID_IQueryAssociations)) 482 { 483 if (cidl == 1 && IsFolder(apidl[0])) 484 { 485 CComPtr<IQueryAssociations> pqa; 486 HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa)); 487 if (FAILED_UNEXPECTEDLY(hr)) 488 return hr; 489 490 hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"NTObjShEx.NTDirectory", NULL, hwndOwner); 491 if (FAILED_UNEXPECTEDLY(hr)) 492 return hr; 493 494 return pqa->QueryInterface(riid, ppvOut); 495 } 496 } 497 498 return E_NOTIMPL; 499 } 500 GetDisplayNameOf(LPCITEMIDLIST pidl,SHGDNF uFlags,STRRET * lpName)501 STDMETHODIMP GetDisplayNameOf( 502 LPCITEMIDLIST pidl, 503 SHGDNF uFlags, 504 STRRET *lpName) override 505 { 506 const TItemId * info; 507 508 TRACE("GetDisplayNameOf %p\n", pidl); 509 510 HRESULT hr = GetInfoFromPidl(pidl, &info); 511 if (FAILED_UNEXPECTEDLY(hr)) 512 return hr; 513 514 if (GET_SHGDN_FOR(uFlags) & SHGDN_FOREDITING) 515 { 516 hr = MakeStrRetFromString(info->entryName, info->entryNameLength, lpName); 517 if (FAILED_UNEXPECTEDLY(hr)) 518 return hr; 519 } 520 521 WCHAR path[MAX_PATH] = { 0 }; 522 523 if (GET_SHGDN_FOR(uFlags) & SHGDN_FORPARSING) 524 { 525 if (GET_SHGDN_RELATION(uFlags) != SHGDN_INFOLDER) 526 { 527 hr = GetFullName(m_shellPidl, uFlags, path, _countof(path)); 528 if (FAILED_UNEXPECTEDLY(hr)) 529 return hr; 530 } 531 } 532 533 PathAppendW(path, info->entryName); 534 535 LPCITEMIDLIST pidlNext = ILGetNext(pidl); 536 if (pidlNext && pidlNext->mkid.cb > 0) 537 { 538 LPITEMIDLIST pidlFirst = ILCloneFirst(pidl); 539 540 CComPtr<IShellFolder> psfChild; 541 hr = BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 542 if (FAILED_UNEXPECTEDLY(hr)) 543 return hr; 544 545 WCHAR temp[MAX_PATH]; 546 STRRET childName; 547 548 hr = psfChild->GetDisplayNameOf(pidlNext, uFlags | SHGDN_INFOLDER, &childName); 549 if (FAILED_UNEXPECTEDLY(hr)) 550 return hr; 551 552 hr = StrRetToBufW(&childName, pidlNext, temp, _countof(temp)); 553 if (FAILED_UNEXPECTEDLY(hr)) 554 return hr; 555 556 PathAppendW(path, temp); 557 558 ILFree(pidlFirst); 559 } 560 561 hr = MakeStrRetFromString(path, lpName); 562 if (FAILED_UNEXPECTEDLY(hr)) 563 return hr; 564 565 return S_OK; 566 } 567 SetNameOf(HWND hwnd,LPCITEMIDLIST pidl,LPCOLESTR lpszName,SHGDNF uFlags,LPITEMIDLIST * ppidlOut)568 STDMETHODIMP SetNameOf( 569 HWND hwnd, 570 LPCITEMIDLIST pidl, 571 LPCOLESTR lpszName, 572 SHGDNF uFlags, 573 LPITEMIDLIST *ppidlOut) override 574 { 575 UNIMPLEMENTED; 576 return E_NOTIMPL; 577 } 578 579 // IShellFolder2 GetDefaultSearchGUID(GUID * lpguid)580 STDMETHODIMP GetDefaultSearchGUID(GUID *lpguid) override 581 { 582 UNIMPLEMENTED; 583 return E_NOTIMPL; 584 } 585 EnumSearches(IEnumExtraSearch ** ppenum)586 STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum) override 587 { 588 UNIMPLEMENTED; 589 return E_NOTIMPL; 590 } 591 GetDefaultColumn(DWORD dwReserved,ULONG * pSort,ULONG * pDisplay)592 STDMETHODIMP GetDefaultColumn( 593 DWORD dwReserved, 594 ULONG *pSort, 595 ULONG *pDisplay) override 596 { 597 if (pSort) 598 *pSort = 0; 599 if (pDisplay) 600 *pDisplay = 0; 601 return S_OK; 602 } 603 604 STDMETHOD(GetDefaultColumnState)( 605 UINT iColumn, 606 SHCOLSTATEF *pcsFlags) PURE; 607 608 STDMETHOD(GetDetailsEx)( 609 LPCITEMIDLIST pidl, 610 const SHCOLUMNID *pscid, 611 VARIANT *pv) PURE; 612 613 STDMETHOD(GetDetailsOf)( 614 LPCITEMIDLIST pidl, 615 UINT iColumn, 616 SHELLDETAILS *psd) PURE; 617 618 STDMETHOD(MapColumnToSCID)( 619 UINT iColumn, 620 SHCOLUMNID *pscid) PURE; 621 622 // IPersist GetClassID(CLSID * lpClassId)623 STDMETHODIMP GetClassID(CLSID *lpClassId) override 624 { 625 if (!lpClassId) 626 return E_POINTER; 627 628 *lpClassId = CLSID_NtObjectFolder; 629 return S_OK; 630 } 631 632 // IPersistFolder Initialize(PCIDLIST_ABSOLUTE pidl)633 STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidl) override 634 { 635 m_shellPidl = ILClone(pidl); 636 637 StringCbCopyW(m_NtPath, sizeof(m_NtPath), L"\\"); 638 639 return S_OK; 640 } 641 642 // IPersistFolder2 GetCurFolder(PIDLIST_ABSOLUTE * pidl)643 STDMETHODIMP GetCurFolder(PIDLIST_ABSOLUTE * pidl) override 644 { 645 if (pidl) 646 *pidl = ILClone(m_shellPidl); 647 if (!m_shellPidl) 648 return S_FALSE; 649 return S_OK; 650 } 651 652 // Internal 653 protected: 654 STDMETHOD(CompareIDs)( 655 LPARAM lParam, 656 const TItemId * first, 657 const TItemId * second) PURE; 658 659 STDMETHOD_(ULONG, ConvertAttributes)( 660 const TItemId * entry, 661 PULONG inMask) PURE; 662 STDMETHOD_(BOOL,IsFolder)663 STDMETHOD_(BOOL, IsFolder)(LPCITEMIDLIST pcidl) 664 { 665 const TItemId * info; 666 667 HRESULT hr = GetInfoFromPidl(pcidl, &info); 668 if (FAILED(hr)) 669 return hr; 670 671 return IsFolder(info); 672 } 673 674 STDMETHOD_(BOOL, IsFolder)(const TItemId * info) PURE; 675 STDMETHOD_(BOOL,IsSymLink)676 STDMETHOD_(BOOL, IsSymLink)(LPCITEMIDLIST pcidl) 677 { 678 const TItemId * info; 679 680 HRESULT hr = GetInfoFromPidl(pcidl, &info); 681 if (FAILED(hr)) 682 return hr; 683 684 return IsSymLink(info); 685 } 686 STDMETHOD_(BOOL,IsSymLink)687 STDMETHOD_(BOOL, IsSymLink)(const TItemId * info) 688 { 689 return FALSE; 690 } 691 692 virtual HRESULT GetInfoFromPidl(LPCITEMIDLIST pcidl, const TItemId ** pentry) PURE; 693 694 public: DefCtxMenuCallback(IShellFolder *,HWND,IDataObject *,UINT uMsg,WPARAM,LPARAM)695 static HRESULT CALLBACK DefCtxMenuCallback(IShellFolder * /*psf*/, HWND /*hwnd*/, IDataObject * /*pdtobj*/, UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/) 696 { 697 switch (uMsg) 698 { 699 case DFM_MERGECONTEXTMENU: 700 return S_OK; 701 702 case DFM_INVOKECOMMAND: 703 case DFM_INVOKECOMMANDEX: 704 case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default 705 return S_FALSE; 706 } 707 return E_NOTIMPL; 708 } 709 710 DECLARE_NOT_AGGREGATABLE(TSelf) 711 DECLARE_PROTECT_FINAL_CONSTRUCT() 712 713 BEGIN_COM_MAP(TSelf) 714 COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) 715 COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) 716 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) 717 COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) 718 COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) 719 END_COM_MAP() 720 721 }; 722