1 /* 2 * Copyright 2003, 2004, 2005 Martin Fuchs 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 20 // 21 // Explorer clone 22 // 23 // shellclasses.h 24 // 25 // C++ wrapper classes for COM interfaces and shell objects 26 // 27 // Martin Fuchs, 20.07.2003 28 // 29 30 31 // windows shell headers 32 #include <shellapi.h> 33 #include <shlobj.h> 34 35 /*@@ 36 #if _MSC_VER>=1300 // VS.Net 37 #include <comdefsp.h> 38 using namespace _com_util; 39 #endif 40 */ 41 42 #ifndef _INC_COMUTIL // is comutil.h of MS headers not available? 43 #ifndef _NO_COMUTIL 44 #define _NO_COMUTIL 45 #endif 46 #endif 47 48 // work around GCC's wide string constant bug when compiling inline functions 49 #ifdef __GNUC__ 50 extern const LPCTSTR sCFSTR_SHELLIDLIST; 51 #undef CFSTR_SHELLIDLIST 52 #define CFSTR_SHELLIDLIST sCFSTR_SHELLIDLIST 53 #endif 54 55 #ifdef _MSC_VER 56 #define NOVTABLE __declspec(novtable) 57 #else 58 #define NOVTABLE 59 #endif 60 #define ANSUNC 61 62 63 // Exception Handling 64 65 #ifndef _NO_COMUTIL 66 67 #define COMExceptionBase _com_error 68 69 #else 70 71 /// COM ExceptionBase class as replacement for _com_error 72 struct COMExceptionBase 73 { 74 COMExceptionBase(HRESULT hr) 75 : _hr(hr) 76 { 77 } 78 79 HRESULT Error() const 80 { 81 return _hr; 82 } 83 84 LPCTSTR ErrorMessage() const 85 { 86 if (_msg.empty()) { 87 LPTSTR pBuf; 88 89 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 90 0, _hr, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&pBuf, 0, NULL)) { 91 _msg = pBuf; 92 LocalFree(pBuf); 93 } else { 94 TCHAR buffer[128]; 95 _sntprintf(buffer, COUNTOF(buffer), TEXT("unknown Exception: 0x%08lX"), _hr); 96 _msg = buffer; 97 } 98 } 99 100 return _msg; 101 } 102 103 protected: 104 HRESULT _hr; 105 mutable String _msg; 106 }; 107 108 #endif 109 110 111 /// Exception with context information 112 113 struct COMException : public COMExceptionBase 114 { 115 typedef COMExceptionBase super; 116 117 COMException(HRESULT hr) 118 : super(hr), 119 _context(CURRENT_CONTEXT), 120 _file(NULL), _line(0) 121 { 122 LOG(toString()); 123 LOG(CURRENT_CONTEXT.getStackTrace()); 124 } 125 126 COMException(HRESULT hr, const char* file, int line) 127 : super(hr), 128 _context(CURRENT_CONTEXT), 129 _file(file), _line(line) 130 { 131 LOG(toString()); 132 LOG(CURRENT_CONTEXT.getStackTrace()); 133 } 134 135 COMException(HRESULT hr, const String& obj) 136 : super(hr), 137 _context(CURRENT_CONTEXT), 138 _file(NULL), _line(0) 139 { 140 LOG(toString()); 141 LOG(CURRENT_CONTEXT.getStackTrace()); 142 } 143 144 COMException(HRESULT hr, const String& obj, const char* file, int line) 145 : super(hr), 146 _context(CURRENT_CONTEXT), 147 _file(file), _line(line) 148 { 149 LOG(toString()); 150 LOG(CURRENT_CONTEXT.getStackTrace()); 151 } 152 153 String toString() const; 154 155 Context _context; 156 157 const char* _file; 158 int _line; 159 }; 160 161 #define THROW_EXCEPTION(hr) throw COMException(hr, __FILE__, __LINE__) 162 #define CHECKERROR(hr) ((void)(FAILED(hr)? THROW_EXCEPTION(hr): 0)) 163 164 165 #ifdef _NO_COMUTIL 166 167 inline void CheckError(HRESULT hr) 168 { 169 if (FAILED(hr)) 170 throw COMException(hr); 171 } 172 173 #endif 174 175 176 /// COM Initialisation 177 178 struct ComInit 179 { 180 ComInit() 181 { 182 CHECKERROR(CoInitialize(0)); 183 } 184 185 #if (_WIN32_WINNT>=0x0400) || defined(_WIN32_DCOM) 186 ComInit(DWORD flag) 187 { 188 CHECKERROR(CoInitializeEx(0, flag)); 189 } 190 #endif 191 192 ~ComInit() 193 { 194 CoUninitialize(); 195 } 196 }; 197 198 199 /// OLE initialisation for drag drop support 200 201 struct OleInit 202 { 203 OleInit() 204 { 205 CHECKERROR(OleInitialize(0)); 206 } 207 208 ~OleInit() 209 { 210 OleUninitialize(); 211 } 212 }; 213 214 215 /// Exception Handler for COM exceptions 216 217 extern void HandleException(COMException& e, HWND hwnd); 218 219 220 /// We use a common IMalloc object for all shell memory allocations. 221 222 struct CommonShellMalloc 223 { 224 CommonShellMalloc() 225 { 226 _p = NULL; 227 } 228 229 void init() 230 { 231 if (!_p) 232 CHECKERROR(SHGetMalloc(&_p)); 233 } 234 235 ~CommonShellMalloc() 236 { 237 if (_p) 238 _p->Release(); 239 } 240 241 operator IMalloc*() 242 { 243 return _p; 244 } 245 246 IMalloc* _p; 247 }; 248 249 250 /// wrapper class for IMalloc with usage of common allocator 251 252 struct ShellMalloc 253 { 254 ShellMalloc() 255 { 256 // initialize s_cmn_shell_malloc 257 s_cmn_shell_malloc.init(); 258 } 259 260 IMalloc* operator->() 261 { 262 return s_cmn_shell_malloc; 263 } 264 265 static CommonShellMalloc s_cmn_shell_malloc; 266 }; 267 268 269 /// wrapper template class for pointers to shell objects managed by IMalloc 270 271 template<typename T> struct SShellPtr 272 { 273 ~SShellPtr() 274 { 275 _malloc->Free(_p); 276 } 277 278 T* operator->() 279 { 280 return _p; 281 } 282 283 T const* operator->() const 284 { 285 return _p; 286 } 287 288 operator T const *() const 289 { 290 return _p; 291 } 292 293 const T& operator*() const 294 { 295 return *_p; 296 } 297 298 T& operator*() 299 { 300 return *_p; 301 } 302 303 protected: 304 SShellPtr() 305 : _p(0) 306 { 307 } 308 309 SShellPtr(T* p) 310 : _p(p) 311 { 312 } 313 314 void Free() 315 { 316 _malloc->Free(_p); 317 _p = NULL; 318 } 319 320 T* _p; 321 mutable ShellMalloc _malloc; // IMalloc memory management object 322 323 private: 324 // disallow copying of SShellPtr objects 325 SShellPtr(const SShellPtr&) {} 326 void operator=(SShellPtr const&) {} 327 }; 328 329 330 /// wrapper class for COM interface pointers 331 332 template<typename T> struct SIfacePtr 333 { 334 SIfacePtr() 335 : _p(0) 336 { 337 } 338 339 SIfacePtr(T* p) 340 : _p(p) 341 { 342 if (p) 343 p->AddRef(); 344 } 345 346 SIfacePtr(IUnknown* unknown, REFIID riid) 347 { 348 CHECKERROR(unknown->QueryInterface(riid, (LPVOID*)&_p)); 349 } 350 351 ~SIfacePtr() 352 { 353 Free(); 354 } 355 356 T* operator->() 357 { 358 return _p; 359 } 360 361 const T* operator->() const 362 { 363 return _p; 364 } 365 366 /* not GCC compatible 367 operator const T*() const 368 { 369 return _p; 370 } */ 371 372 operator T*() 373 { 374 return _p; 375 } 376 377 T** operator&() 378 { 379 return &_p; 380 } 381 382 bool empty() const //NOTE: GCC seems not to work correctly when defining operator bool() AND operator T*() at one time 383 { 384 return !_p; 385 } 386 387 SIfacePtr& operator=(T* p) 388 { 389 Free(); 390 391 if (p) { 392 p->AddRef(); 393 _p = p; 394 } 395 396 return *this; 397 } 398 399 void operator=(SIfacePtr const& o) 400 { 401 T* h = _p; 402 403 if (o._p) 404 o._p->AddRef(); 405 406 _p = o._p; 407 408 if (h) 409 h->Release(); 410 } 411 412 HRESULT CreateInstance(REFIID clsid, REFIID riid) 413 { 414 return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&_p); 415 } 416 417 template<typename I> HRESULT QueryInterface(REFIID riid, I* p) 418 { 419 return _p->QueryInterface(riid, (LPVOID*)p); 420 } 421 422 T* get() 423 { 424 return _p; 425 } 426 427 void Free() 428 { 429 T* h = _p; 430 _p = NULL; 431 432 if (h) 433 h->Release(); 434 } 435 436 protected: 437 SIfacePtr(const SIfacePtr& o) 438 : _p(o._p) 439 { 440 if (_p) 441 _p->AddRef(); 442 } 443 444 T* _p; 445 }; 446 447 448 struct NOVTABLE ComSrvObject // NOVTABLE erlaubt, da protected Destruktor 449 { 450 protected: 451 ComSrvObject() : _ref(1) {} 452 virtual ~ComSrvObject() {} 453 454 ULONG _ref; 455 }; 456 457 struct SimpleComObject : public ComSrvObject 458 { 459 ULONG IncRef() {return ++_ref;} 460 ULONG DecRef() {ULONG ref=--_ref; if (!ref) {_ref++; delete this;} return ref;} 461 }; 462 463 464 // server object interfaces 465 466 template<typename BASE> struct IComSrvQI : public BASE 467 { 468 IComSrvQI(REFIID uuid_base) 469 : _uuid_base(uuid_base) 470 { 471 } 472 473 STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv) 474 { 475 *ppv = NULL; 476 477 if (IsEqualIID(riid, _uuid_base) || IsEqualIID(riid, IID_IUnknown)) 478 {*ppv=static_cast<BASE*>(this); this->AddRef(); return S_OK;} 479 480 return E_NOINTERFACE; 481 } 482 483 protected: 484 IComSrvQI() {} 485 virtual ~IComSrvQI() {} 486 487 REFIID _uuid_base; 488 }; 489 490 template<> struct IComSrvQI<IUnknown> : public IUnknown 491 { 492 STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv) 493 { 494 *ppv = NULL; 495 496 if (IsEqualIID(riid, IID_IUnknown)) 497 {*ppv=this; AddRef(); return S_OK;} 498 499 return E_NOINTERFACE; 500 } 501 502 protected: 503 IComSrvQI<IUnknown>() {} 504 virtual ~IComSrvQI<IUnknown>() {} 505 }; 506 507 508 template<typename BASE, typename OBJ> 509 class IComSrvBase : public IComSrvQI<BASE> 510 { 511 typedef IComSrvQI<BASE> super; 512 513 protected: 514 IComSrvBase(REFIID uuid_base) 515 : super(uuid_base) 516 { 517 } 518 519 public: 520 STDMETHODIMP_(ULONG) AddRef() {return static_cast<OBJ*>(this)->IncRef();} 521 STDMETHODIMP_(ULONG) Release() {return static_cast<OBJ*>(this)->DecRef();} 522 }; 523 524 525 526 struct ShellFolder; 527 528 529 /// caching of desktop ShellFolder object 530 531 struct CommonDesktop 532 { 533 CommonDesktop() 534 { 535 _desktop = 0; 536 } 537 538 ~CommonDesktop(); 539 540 void init(); 541 542 operator ShellFolder&() 543 { 544 return *_desktop; 545 } 546 547 protected: 548 ShellFolder* _desktop; 549 }; 550 551 552 #ifndef _NO_COMUTIL // _com_ptr available? 553 554 /// IShellFolder smart pointer 555 struct ShellFolder : public IShellFolderPtr // IShellFolderPtr uses intrinsic extensions of the VC++ compiler. 556 { 557 typedef IShellFolderPtr super; 558 559 ShellFolder(); // desktop folder 560 ShellFolder(IShellFolder* p); 561 ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl); 562 ShellFolder(LPCITEMIDLIST pidl); 563 564 void attach(IShellFolder* parent, LPCITEMIDLIST pidl); 565 String get_name(LPCITEMIDLIST pidl=NULL, SHGDNF flags=SHGDN_NORMAL) const; 566 567 bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty() 568 }; 569 570 #ifdef UNICODE 571 #define IShellLinkPtr IShellLinkWPtr 572 #else 573 #define IShellLinkPtr IShellLinkAPtr 574 #endif 575 576 /// IShellLink smart pointer 577 struct ShellLinkPtr : public IShellLinkPtr 578 { 579 typedef IShellLinkPtr super; 580 581 ShellLinkPtr(IShellLink* p) 582 : super(p) 583 { 584 p->AddRef(); 585 } 586 587 bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty() 588 }; 589 590 #else // _com_ptr not available -> use SIfacePtr 591 592 /// IShellFolder smart pointer 593 struct ShellFolder : public SIfacePtr<IShellFolder> 594 { 595 typedef SIfacePtr<IShellFolder> super; 596 597 ShellFolder(); 598 ShellFolder(IShellFolder* p); 599 ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl); 600 ShellFolder(LPCITEMIDLIST pidl); 601 602 void attach(IShellFolder* parent, LPCITEMIDLIST pidl); 603 String get_name(LPCITEMIDLIST pidl, SHGDNF flags=SHGDN_NORMAL) const; 604 }; 605 606 /// IShellLink smart pointer 607 struct ShellLinkPtr : public SIfacePtr<IShellLink> 608 { 609 typedef SIfacePtr<IShellLink> super; 610 611 ShellLinkPtr(IShellLink* p) 612 : super(p) 613 { 614 _p->AddRef(); 615 } 616 617 }; 618 619 #endif 620 621 622 extern ShellFolder& GetDesktopFolder(); 623 624 625 #ifdef UNICODE 626 #define path_from_pidl path_from_pidlW 627 #else 628 #define path_from_pidl path_from_pidlA 629 #endif 630 631 extern HRESULT path_from_pidlA(IShellFolder* folder, LPCITEMIDLIST pidl, LPSTR buffer, int len); 632 extern HRESULT path_from_pidlW(IShellFolder* folder, LPCITEMIDLIST pidl, LPWSTR buffer, int len); 633 extern HRESULT name_from_pidl(IShellFolder* folder, LPCITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags); 634 635 636 // ILGetSize() was missing in previous versions of MinGW and is not exported from shell32.dll on Windows 2000. 637 extern "C" UINT ILGetSize_local(LPCITEMIDLIST pidl); 638 #define ILGetSize ILGetSize_local 639 640 #if 0 641 #ifdef UNICODE // CFSTR_FILENAME was defined wrong in previous versions of MinGW. 642 #define CFSTR_FILENAMEW TEXT("FileNameW") 643 #undef CFSTR_FILENAME 644 #define CFSTR_FILENAME CFSTR_FILENAMEW 645 #endif 646 #endif 647 648 649 /// wrapper class for item ID lists 650 651 struct ShellPath : public SShellPtr<ITEMIDLIST> 652 { 653 typedef SShellPtr<ITEMIDLIST> super; 654 655 ShellPath() 656 { 657 } 658 659 ShellPath(IShellFolder* folder, LPCWSTR path) 660 { 661 CONTEXT("ShellPath::ShellPath(IShellFolder*, LPCWSTR)"); 662 663 if (path) 664 CHECKERROR(folder->ParseDisplayName(0, NULL, (LPOLESTR)path, NULL, &_p, NULL)); 665 else 666 _p = NULL; 667 } 668 669 ShellPath(LPCWSTR path) 670 { 671 OBJ_CONTEXT("ShellPath::ShellPath(LPCWSTR)", path); 672 673 if (path) 674 CHECKERROR(GetDesktopFolder()->ParseDisplayName(0, NULL, (LPOLESTR)path, NULL, &_p, NULL)); 675 else 676 _p = NULL; 677 } 678 679 ShellPath(IShellFolder* folder, LPCSTR path) 680 { 681 CONTEXT("ShellPath::ShellPath(IShellFolder*, LPCSTR)"); 682 683 WCHAR b[MAX_PATH]; 684 685 if (path) { 686 MultiByteToWideChar(CP_ACP, 0, path, -1, b, COUNTOF(b)); 687 CHECKERROR(folder->ParseDisplayName(0, NULL, b, NULL, &_p, NULL)); 688 } else 689 _p = NULL; 690 } 691 692 ShellPath(LPCSTR path) 693 { 694 CONTEXT("ShellPath::ShellPath(LPCSTR)"); 695 696 WCHAR b[MAX_PATH]; 697 698 if (path) { 699 MultiByteToWideChar(CP_ACP, 0, path, -1, b, COUNTOF(b)); 700 CHECKERROR(GetDesktopFolder()->ParseDisplayName(0, NULL, b, NULL, &_p, NULL)); 701 } else 702 _p = NULL; 703 } 704 705 ShellPath(const ShellPath& o) 706 : super(NULL) 707 { 708 //CONTEXT("ShellPath::ShellPath(const ShellPath&)"); 709 710 if (o._p) { 711 int l = ILGetSize(o._p); 712 _p = (ITEMIDLIST*) _malloc->Alloc(l); 713 if (_p) memcpy(_p, o._p, l); 714 } 715 } 716 717 explicit ShellPath(LPITEMIDLIST p) 718 : super(p) 719 { 720 } 721 722 ShellPath(LPCITEMIDLIST p) 723 { 724 //CONTEXT("ShellPath::ShellPath(LPCITEMIDLIST)"); 725 726 if (p) { 727 int l = ILGetSize(p); 728 _p = (ITEMIDLIST*) _malloc->Alloc(l); 729 if (_p) memcpy(_p, p, l); 730 } 731 } 732 733 void operator=(const ShellPath& o) 734 { 735 //CONTEXT("ShellPath::operator=(const ShellPath&)"); 736 737 ITEMIDLIST* h = _p; 738 739 if (o._p) { 740 int l = ILGetSize(o._p); 741 742 _p = (ITEMIDLIST*) _malloc->Alloc(l); 743 if (_p) memcpy(_p, o._p, l); 744 } 745 else 746 _p = NULL; 747 748 _malloc->Free(h); 749 } 750 751 void operator=(ITEMIDLIST* p) 752 { 753 //CONTEXT("ShellPath::operator=(ITEMIDLIST*)"); 754 755 ITEMIDLIST* h = _p; 756 757 if (p) { 758 int l = ILGetSize(p); 759 _p = (ITEMIDLIST*) _malloc->Alloc(l); 760 if (_p) memcpy(_p, p, l); 761 } 762 else 763 _p = NULL; 764 765 _malloc->Free(h); 766 } 767 768 void operator=(const SHITEMID& o) 769 { 770 ITEMIDLIST* h = _p; 771 772 LPBYTE p = (LPBYTE)_malloc->Alloc(o.cb+2); 773 if (p) *(PWORD)((LPBYTE)memcpy(p, &o, o.cb)+o.cb) = 0; 774 _p = (ITEMIDLIST*)p; 775 776 _malloc->Free(h); 777 } 778 779 void operator+=(const SHITEMID& o) 780 { 781 int l0 = ILGetSize(_p); 782 LPBYTE p = (LPBYTE)_malloc->Alloc(l0+o.cb); 783 int l = l0 - 2; 784 785 if (p) { 786 memcpy(p, _p, l); 787 *(PWORD)((LPBYTE)memcpy(p+l, &o, o.cb)+o.cb) = 0; 788 } 789 790 _malloc->Free(_p); 791 _p = (ITEMIDLIST*)p; 792 } 793 794 friend bool operator<(const ShellPath& a, const ShellPath& b) 795 { 796 int la = ILGetSize(a._p); 797 int lb = ILGetSize(b._p); 798 799 int r = memcmp(a._p, b._p, min(la, lb)); 800 if (r) 801 return r < 0; 802 else 803 return la < lb; 804 } 805 806 void assign(LPCITEMIDLIST pidl, size_t size) 807 { 808 //CONTEXT("ShellPath::assign(LPCITEMIDLIST, size_t)"); 809 810 ITEMIDLIST* h = _p; 811 812 _p = (ITEMIDLIST*) _malloc->Alloc(size+sizeof(USHORT/*SHITEMID::cb*/)); 813 814 if (_p) { 815 memcpy(_p, pidl, size); 816 ((ITEMIDLIST*)((LPBYTE)_p+size))->mkid.cb = 0; // terminator 817 } 818 819 _malloc->Free(h); 820 } 821 822 void assign(LPCITEMIDLIST pidl) 823 { 824 //CONTEXT("ShellPath::assign(LPCITEMIDLIST)"); 825 826 ITEMIDLIST* h = _p; 827 828 if (pidl) { 829 int l = ILGetSize(pidl); 830 _p = (ITEMIDLIST*) _malloc->Alloc(l); 831 if (_p) memcpy(_p, pidl, l); 832 } else 833 _p = NULL; 834 835 _malloc->Free(h); 836 } 837 838 void split(ShellPath& parent, ShellPath& obj) const; 839 840 void GetUIObjectOf(REFIID riid, LPVOID* ppvOut, HWND hWnd=0, ShellFolder& sf=GetDesktopFolder()); 841 842 ShellFolder get_folder() 843 { 844 return ShellFolder(_p); 845 } 846 847 ShellFolder get_folder(IShellFolder* parent) 848 { 849 CONTEXT("ShellPath::get_folder()"); 850 return ShellFolder(parent, _p); 851 } 852 853 // convert an item id list from relative to absolute (=relative to the desktop) format 854 ShellPath create_absolute_pidl(LPCITEMIDLIST parent_pidl) const; 855 }; 856 857 858 #if defined(__WINE__) && defined(NONAMELESSUNION) // Wine doesn't know of unnamed union members and uses some macros instead. 859 #define UNION_MEMBER(x) DUMMYUNIONNAME.##x 860 #else 861 #define UNION_MEMBER(x) x 862 #endif 863 864 865 // encapsulation of STRRET structure for easy string retrieval with conversion 866 867 #ifdef UNICODE 868 #define StrRet StrRetW 869 //#define tcscpyn wcscpyn 870 #else 871 #define StrRet StrRetA 872 //#define tcscpyn strcpyn 873 #endif 874 875 //extern LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count); 876 //extern LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count); 877 878 /// easy retrieval of multi byte strings out of STRRET structures 879 struct StrRetA : public STRRET 880 { 881 ~StrRetA() 882 { 883 if (uType == STRRET_WSTR) 884 ShellMalloc()->Free(pOleStr); 885 } 886 887 void GetString(const SHITEMID& shiid, LPSTR b, int l) 888 { 889 switch(uType) { 890 case STRRET_WSTR: 891 WideCharToMultiByte(CP_ACP, 0, UNION_MEMBER(pOleStr), -1, b, l, NULL, NULL); 892 break; 893 894 case STRRET_OFFSET: 895 lstrcpynA(b, (LPCSTR)&shiid+UNION_MEMBER(uOffset), l); 896 break; 897 898 case STRRET_CSTR: 899 lstrcpynA(b, UNION_MEMBER(cStr), l); 900 } 901 } 902 }; 903 904 /// easy retrieval of wide char strings out of STRRET structures 905 struct StrRetW : public STRRET 906 { 907 ~StrRetW() 908 { 909 if (uType == STRRET_WSTR) 910 ShellMalloc()->Free(pOleStr); 911 } 912 913 void GetString(const SHITEMID& shiid, LPWSTR b, int l) 914 { 915 switch(uType) { 916 case STRRET_WSTR: 917 lstrcpynW(b, UNION_MEMBER(pOleStr), l); 918 break; 919 920 case STRRET_OFFSET: 921 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&shiid+UNION_MEMBER(uOffset), -1, b, l); 922 break; 923 924 case STRRET_CSTR: 925 MultiByteToWideChar(CP_ACP, 0, UNION_MEMBER(cStr), -1, b, l); 926 } 927 } 928 }; 929 930 931 /// Retrieval of file system paths of ShellPath objects 932 class FileSysShellPath : public ShellPath 933 { 934 TCHAR _fullpath[MAX_PATH]; 935 936 protected: 937 FileSysShellPath() {_fullpath[0] = '\0';} 938 939 public: 940 FileSysShellPath(const ShellPath& o) : ShellPath(o) {_fullpath[0] = '\0';} 941 942 operator LPCTSTR() {if (!SHGetPathFromIDList(_p, _fullpath)) return NULL; return _fullpath;} 943 }; 944 945 946 /// Browse dialog operating on shell namespace 947 struct FolderBrowser : public FileSysShellPath 948 { 949 FolderBrowser(HWND owner, UINT flags, LPCTSTR title, LPCITEMIDLIST root=0) 950 { 951 _displayname[0] = '\0'; 952 _browseinfo.hwndOwner = owner; 953 _browseinfo.pidlRoot = root; 954 _browseinfo.pszDisplayName = _displayname; 955 _browseinfo.lpszTitle = title; 956 _browseinfo.ulFlags = flags; 957 _browseinfo.lpfn = 0; 958 _browseinfo.lParam = 0; 959 _browseinfo.iImage = 0; 960 961 _p = SHBrowseForFolder(&_browseinfo); 962 } 963 964 LPCTSTR GetDisplayName() 965 { 966 return _displayname; 967 } 968 969 bool IsOK() 970 { 971 return _p != 0; 972 } 973 974 private: 975 BROWSEINFO _browseinfo; 976 TCHAR _displayname[MAX_PATH]; 977 }; 978 979 980 /// Retrieval of special shell folder paths 981 struct SpecialFolderPath : public ShellPath 982 { 983 SpecialFolderPath(int folder, HWND hwnd) 984 { 985 HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p); 986 CHECKERROR(hr); 987 } 988 }; 989 990 /// Shell folder path of the desktop 991 struct DesktopFolderPath : public SpecialFolderPath 992 { 993 DesktopFolderPath() 994 : SpecialFolderPath(CSIDL_DESKTOP, 0) 995 { 996 } 997 }; 998 999 /// Retrieval of special shell folder 1000 struct SpecialFolder : public ShellFolder 1001 { 1002 SpecialFolder(int folder, HWND hwnd) 1003 : ShellFolder(GetDesktopFolder(), SpecialFolderPath(folder, hwnd)) 1004 { 1005 } 1006 }; 1007 1008 /// Shell folder of the desktop 1009 struct DesktopFolder : public ShellFolder 1010 { 1011 }; 1012 1013 1014 /// file system path of special folder 1015 struct SpecialFolderFSPath 1016 { 1017 SpecialFolderFSPath(int folder/*e.g. CSIDL_DESKTOP*/, HWND hwnd); 1018 1019 operator LPCTSTR() 1020 { 1021 return _fullpath; 1022 } 1023 1024 protected: 1025 TCHAR _fullpath[MAX_PATH]; 1026 }; 1027 1028 /* 1029 /// file system path of special folder 1030 struct SpecialFolderFSPath : public FileSysShellPath 1031 { 1032 SpecialFolderFSPath(int folder, HWND hwnd) 1033 { 1034 CONTEXT("SpecialFolderFSPath::SpecialFolderFSPath()"); 1035 1036 HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p); 1037 CHECKERROR(hr); 1038 } 1039 }; 1040 */ 1041 1042 1043 /// wrapper class for enumerating shell namespace objects 1044 1045 struct ShellItemEnumerator : public SIfacePtr<IEnumIDList> 1046 { 1047 ShellItemEnumerator(IShellFolder* folder, DWORD flags=SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN) 1048 { 1049 CONTEXT("ShellItemEnumerator::ShellItemEnumerator()"); 1050 1051 CHECKERROR(folder->EnumObjects(0, flags, &_p)); 1052 } 1053 }; 1054 1055 1056 /// list of PIDLs 1057 struct PIDList 1058 { 1059 PIDList() 1060 { 1061 memset(&_stgm, 0, sizeof(STGMEDIUM)); 1062 } 1063 1064 ~PIDList() 1065 { 1066 if (_stgm.hGlobal) { 1067 GlobalUnlock(_stgm.hGlobal); 1068 ReleaseStgMedium(&_stgm); 1069 } 1070 } 1071 1072 HRESULT GetData(IDataObject* selection) 1073 { 1074 static UINT CF_IDLIST = RegisterClipboardFormat(CFSTR_SHELLIDLIST); 1075 1076 FORMATETC fetc; 1077 fetc.cfFormat = CF_IDLIST; 1078 fetc.ptd = NULL; 1079 fetc.dwAspect = DVASPECT_CONTENT; 1080 fetc.lindex = -1; 1081 fetc.tymed = TYMED_HGLOBAL; 1082 1083 HRESULT hr = selection->QueryGetData(&fetc); 1084 if (FAILED(hr)) 1085 return hr; 1086 1087 hr = selection->GetData(&fetc, &_stgm); 1088 if (FAILED(hr)) 1089 return hr; 1090 1091 _pIDList = (LPIDA)GlobalLock(_stgm.hGlobal); 1092 1093 return hr; 1094 } 1095 1096 operator LPIDA() {return _pIDList;} 1097 1098 protected: 1099 STGMEDIUM _stgm; 1100 LPIDA _pIDList; 1101 }; 1102 1103 1104 struct CtxMenuInterfaces 1105 { 1106 CtxMenuInterfaces() 1107 { 1108 reset(); 1109 } 1110 1111 void reset(); 1112 bool HandleMenuMsg(UINT nmsg, WPARAM wparam, LPARAM lparam); 1113 IContextMenu* query_interfaces(IContextMenu* pcm1); 1114 1115 IContextMenu2* _pctxmenu2; 1116 1117 IContextMenu3* _pctxmenu3; 1118 }; 1119 1120 template<typename BASE> struct ExtContextMenuHandlerT 1121 : public BASE 1122 { 1123 typedef BASE super; 1124 1125 ExtContextMenuHandlerT(HWND hwnd) 1126 : super(hwnd) 1127 { 1128 } 1129 1130 template<typename PARA> ExtContextMenuHandlerT(HWND hwnd, const PARA& info) 1131 : super(hwnd, info) 1132 { 1133 } 1134 1135 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 1136 { 1137 switch(nmsg) { 1138 case WM_DRAWITEM: 1139 case WM_MEASUREITEM: 1140 if (!wparam) // Is the message menu-related? 1141 if (_cm_ifs.HandleMenuMsg(nmsg, wparam, lparam)) 1142 return TRUE; 1143 1144 break; 1145 1146 case WM_INITMENUPOPUP: 1147 if (_cm_ifs.HandleMenuMsg(nmsg, wparam, lparam)) 1148 return 0; 1149 1150 break; 1151 1152 case WM_MENUCHAR: // only supported by IContextMenu3 1153 if (_cm_ifs._pctxmenu3) { 1154 LRESULT lResult = 0; 1155 1156 _cm_ifs._pctxmenu3->HandleMenuMsg2(nmsg, wparam, lparam, &lResult); 1157 1158 return lResult; 1159 } 1160 1161 return 0; 1162 } 1163 1164 return super::WndProc(nmsg, wparam, lparam); 1165 } 1166 1167 protected: 1168 CtxMenuInterfaces _cm_ifs; 1169 }; 1170 1171 1172 extern HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl, 1173 LPCITEMIDLIST* ppidl, int x, int y, CtxMenuInterfaces& cm_ifs); 1174