2 * Copyright 2003 Martin Fuchs
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 // C++ wrapper classes for COM interfaces and shell objects
27 // Martin Fuchs, 20.07.2003
31 // windows shell headers
36 #if _MSC_VER>=1300 // VS.Net
38 using namespace _com_util;
42 #ifndef _INC_COMUTIL // is comutil.h of MS headers not available?
49 // COM Exception Handling
53 #define COMException _com_error
59 COMException(HRESULT hr)
64 LPCTSTR ErrorMessage() const
69 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
70 0, _hr, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPSTR)&pBuf, 0, NULL)) {
75 _stprintf(buffer, _T("unknown COM Exception: 0x%08X"), _hr);
88 inline void CheckError(HRESULT hr)
91 throw COMException(hr);
104 CheckError(CoInitialize(0));
107 #if (_WIN32_WINNT>=0x0400) || defined(_WIN32_DCOM)
110 CheckError(CoInitializeEx(0, flag));
121 // OLE initialisation for drag drop support
127 CheckError(OleInitialize(0));
137 // Exception Handler for COM exceptions
139 extern void HandleException(COMException& e, HWND hwnd);
142 // We use a common IMalloc object for all shell memory allocations.
144 struct CommonShellMalloc
154 CheckError(SHGetMalloc(&_p));
172 // wrapper class for IMalloc with usage of common allocator
178 // initialize s_cmn_shell_malloc
179 s_cmn_shell_malloc.init();
182 IMalloc* operator->()
184 return s_cmn_shell_malloc;
187 static CommonShellMalloc s_cmn_shell_malloc;
191 // wrapper template class for pointers to shell objects managed by IMalloc
193 template<typename T> struct SShellPtr
205 T const* operator->() const
210 operator T const *() const
215 const T& operator*() const
243 mutable ShellMalloc _malloc; // IMalloc memory management object
246 // disallow copying of SShellPtr objects
247 SShellPtr(const SShellPtr&) {}
248 void operator=(SShellPtr const&) {}
252 // wrapper class for COM interface pointers
254 template<typename T> struct SIfacePtr
278 const T* operator->() const
283 /* not GCC compatible
284 operator const T*() const
299 bool empty() const //NOTE: GCC seems not to work correctly when defining operator bool() AND operator T*()
304 SIfacePtr& operator=(T* p)
313 void operator=(SIfacePtr const& o)
336 SIfacePtr(const SIfacePtr& o)
348 // caching of desktop ShellFolder object
363 operator struct ShellFolder&()
369 ShellFolder* _desktop;
373 #ifndef _NO_COMUTIL // _com_ptr available?
375 struct ShellFolder : public IShellFolderPtr // IShellFolderPtr uses intrinsic extensions of the VC++ compiler.
377 typedef IShellFolderPtr super;
379 ShellFolder(); // desktop folder
380 ShellFolder(IShellFolder* p);
381 ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl);
382 ShellFolder(LPCITEMIDLIST pidl);
384 void attach(IShellFolder* parent, LPCITEMIDLIST pidl);
385 String get_name(LPCITEMIDLIST pidl=NULL, SHGDNF flags=SHGDN_NORMAL) const;
387 bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty()
390 #else // _com_ptr not available -> use SIfacePtr
392 struct ShellFolder : public SIfacePtr<IShellFolder>
394 typedef SIfacePtr<IShellFolder> super;
397 ShellFolder(IShellFolder* p);
398 ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl);
399 ShellFolder(LPCITEMIDLIST pidl);
401 void attach(IShellFolder* parent, LPCITEMIDLIST pidl);
402 String get_name(LPCITEMIDLIST pidl, SHGDNF flags=SHGDN_NORMAL) const;
408 extern ShellFolder& Desktop();
412 #define path_from_pidl path_from_pidlW
414 #define path_from_pidl path_from_pidlA
417 extern HRESULT path_from_pidlA(IShellFolder* folder, LPCITEMIDLIST pidl, LPSTR buffer, int len);
418 extern HRESULT path_from_pidlW(IShellFolder* folder, LPCITEMIDLIST pidl, LPWSTR buffer, int len);
419 extern HRESULT name_from_pidl(IShellFolder* folder, LPCITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags);
422 // wrapper class for item ID lists
424 struct ShellPath : public SShellPtr<ITEMIDLIST>
426 typedef SShellPtr<ITEMIDLIST> super;
432 ShellPath(IShellFolder* folder, LPCWSTR path)
435 CheckError(folder->ParseDisplayName(0, 0, (LPOLESTR)path, &l, &_p, 0));
438 ShellPath(LPCWSTR path)
441 CheckError(Desktop()->ParseDisplayName(0, 0, (LPOLESTR)path, &l, &_p, 0));
444 ShellPath(IShellFolder* folder, LPCSTR path)
449 MultiByteToWideChar(CP_ACP, 0, path, -1, b, MAX_PATH);
450 CheckError(folder->ParseDisplayName(0, 0, b, &l, &_p, 0));
453 ShellPath(LPCSTR path)
458 MultiByteToWideChar(CP_ACP, 0, path, -1, b, MAX_PATH);
459 CheckError(Desktop()->ParseDisplayName(0, 0, b, &l, &_p, 0));
462 ShellPath(const ShellPath& o)
466 int l = _malloc->GetSize(o._p);
467 _p = (ITEMIDLIST*) _malloc->Alloc(l);
472 ShellPath(ITEMIDLIST* p)
473 : SShellPtr<ITEMIDLIST>(p)
477 void operator=(const ShellPath& o)
482 int l = _malloc->GetSize(o._p);
484 _p = (ITEMIDLIST*)_malloc->Alloc(l);
493 void operator=(ITEMIDLIST* p)
498 int l = _malloc->GetSize(p);
500 _p = (ITEMIDLIST*)_malloc->Alloc(l);
509 void operator=(const SHITEMID& o)
513 LPBYTE p = (LPBYTE)_malloc->Alloc(o.cb+2);
514 *(PWORD)((LPBYTE)memcpy(p, &o, o.cb)+o.cb) = 0;
520 void operator+=(const SHITEMID& o)
522 int l0 = _malloc->GetSize(_p);
523 LPBYTE p = (LPBYTE)_malloc->Alloc(l0+o.cb);
527 *(PWORD)((LPBYTE)memcpy(p+l, &o, o.cb)+o.cb) = 0;
533 void assign(ITEMIDLIST* pidl, size_t size)
537 _p = (ITEMIDLIST*) _malloc->Alloc(size+sizeof(USHORT/*SHITEMID::cb*/));
538 memcpy(_p, pidl, size);
539 ((ITEMIDLIST*)((LPBYTE)_p+size))->mkid.cb = 0; // terminator
544 void assign(ITEMIDLIST* pidl)
549 int l = _malloc->GetSize(pidl);
550 _p = (ITEMIDLIST*)_malloc->Alloc(l);
558 void split(ShellPath& parent, ShellPath& obj) const
560 SHITEMID *piid, *piidLast;
563 // find last item-id and calculate total size of pidl
564 for(piid=piidLast=&_p->mkid; piid->cb; ) {
567 piid = (SHITEMID*)((LPBYTE)piid + (piid->cb));
570 // copy parent folder portion
571 size -= piidLast->cb; // don't count "object" item-id
574 parent.assign(_p, size);
576 // copy "object" portion
577 obj.assign((ITEMIDLIST*)piidLast, piidLast->cb);
580 void GetUIObjectOf(REFIID riid, LPVOID* ppvOut, HWND hWnd=0, ShellFolder& sf=Desktop())
582 ShellPath parent, obj;
586 LPCITEMIDLIST idl = obj;
588 if (parent && parent->mkid.cb)
589 // use the IShellFolder of the parent
590 CheckError(ShellFolder((IShellFolder*)sf,parent)->GetUIObjectOf(hWnd, 1, &idl, riid, 0, ppvOut));
591 else // else use desktop folder
592 CheckError(sf->GetUIObjectOf(hWnd, 1, &idl, riid, 0, ppvOut));
595 ShellFolder get_folder()
597 return ShellFolder(_p);
600 ShellFolder get_folder(IShellFolder* parent)
602 return ShellFolder(parent, _p);
606 // convert an item id list from relative to absolute (=relative to the desktop) format
607 LPITEMIDLIST create_absolute_pidl(LPCITEMIDLIST parent_pidl, HWND hwnd) const
609 // create a new item id list with _p append behind parent_pidl
610 int l1 = _malloc->GetSize((void*)parent_pidl) - sizeof(USHORT/*SHITEMID::cb*/);
611 int l2 = _malloc->GetSize(_p);
613 LPITEMIDLIST p = (LPITEMIDLIST) _malloc->Alloc(l1+l2);
615 memcpy(p, parent_pidl, l1);
616 memcpy((LPBYTE)p+l1, _p, l2);
623 #ifdef __GCC__ // Wine doesn't know of unnamed union members and uses some macros instead.
624 #define UNION_MEMBER(x) DUMMYUNIONNAME.##x
626 #define UNION_MEMBER(x) x
630 // encapsulation of STRRET structure for easy string retrieval with conversion
633 #define StrRet StrRetW
634 #define tcscpyn wcscpyn
636 #define StrRet StrRetA
637 #define tcscpyn strcpyn
640 extern LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count);
641 extern LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count);
643 struct StrRetA : public STRRET
647 if (uType == STRRET_WSTR)
648 ShellMalloc()->Free(pOleStr);
651 void GetString(const SHITEMID& shiid, LPSTR b, int l)
655 WideCharToMultiByte(CP_ACP, 0, UNION_MEMBER(pOleStr), -1, b, l, NULL, NULL);
659 strcpyn(b, (LPCSTR)&shiid+UNION_MEMBER(uOffset), l);
663 strcpyn(b, UNION_MEMBER(cStr), l);
668 struct StrRetW : public STRRET
672 if (uType == STRRET_WSTR)
673 ShellMalloc()->Free(pOleStr);
676 void GetString(const SHITEMID& shiid, LPWSTR b, int l)
680 wcscpyn(b, UNION_MEMBER(pOleStr), l);
684 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&shiid+UNION_MEMBER(uOffset), -1, b, l);
688 MultiByteToWideChar(CP_ACP, 0, UNION_MEMBER(cStr), -1, b, l);
694 class FileSysShellPath : public ShellPath
696 TCHAR _fullpath[MAX_PATH];
699 FileSysShellPath() {_fullpath[0] = '\0';}
702 FileSysShellPath(const ShellPath& o) : ShellPath(o) {_fullpath[0] = '\0';}
704 operator LPCTSTR() {SHGetPathFromIDList(_p, _fullpath); return _fullpath;}
708 struct FolderBrowser : public FileSysShellPath
710 FolderBrowser(HWND owner, UINT flags, LPCTSTR title, LPCITEMIDLIST root=0)
712 _displayname[0] = '\0';
713 _browseinfo.hwndOwner = owner;
714 _browseinfo.pidlRoot = root;
715 _browseinfo.pszDisplayName = _displayname;
716 _browseinfo.lpszTitle = title;
717 _browseinfo.ulFlags = flags;
718 _browseinfo.lpfn = 0;
719 _browseinfo.lParam = 0;
720 _browseinfo.iImage = 0;
722 _p = SHBrowseForFolder(&_browseinfo);
725 LPCTSTR GetDisplayName()
736 BROWSEINFO _browseinfo;
737 TCHAR _displayname[MAX_PATH];
741 struct SpecialFolderPath : public ShellPath
743 SpecialFolderPath(int folder, HWND hwnd)
745 /*HRESULT hr = */SHGetSpecialFolderLocation(hwnd, folder, &_p);
749 struct DesktopFolder : public SpecialFolderPath
752 : SpecialFolderPath(CSIDL_DESKTOP, 0)
757 struct SpecialFolder : public ShellFolder
759 SpecialFolder(int folder, HWND hwnd)
760 : ShellFolder(Desktop(), SpecialFolderPath(folder, hwnd))
766 #if _WIN32_IE>=0x400 // is SHGetSpecialFolderPath() available?
768 /// file system path of special folder
769 struct SpecialFolderFSPath
771 SpecialFolderFSPath(int folder/*e.g. CSIDL_DESKTOP*/, HWND hwnd)
775 SHGetSpecialFolderPath(hwnd, _fullpath, folder, TRUE);
784 TCHAR _fullpath[MAX_PATH];
787 #else // _WIN32_IE<0x400 -> use SHGetSpecialFolderLocation()
789 struct SpecialFolderFSPath : public FileSysShellPath
791 SpecialFolderFSPath(int folder, HWND hwnd)
793 HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p);
800 // wrapper class for enumerating shell namespace objects
802 struct ShellItemEnumerator : public SIfacePtr<IEnumIDList>
804 ShellItemEnumerator(IShellFolder* folder, DWORD flags=SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN)
806 CheckError(folder->EnumObjects(0, flags, &_p));