Something went wrong. Try again.
Reactos
Something went wrong. Try again.
21 kB · 1173 lines
C
at master
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174/* * Copyright 2003, 2004, 2005 Martin Fuchs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
// // Explorer clone // // shellclasses.h // // C++ wrapper classes for COM interfaces and shell objects // // Martin Fuchs, 20.07.2003 //
// windows shell headers#include <shellapi.h>#include <shlobj.h>
/*@@#if _MSC_VER>=1300 // VS.Net#include <comdefsp.h>using namespace _com_util;#endif*/
#ifndef _INC_COMUTIL // is comutil.h of MS headers not available?#ifndef _NO_COMUTIL#define _NO_COMUTIL#endif#endif
// work around GCC's wide string constant bug when compiling inline functions#ifdef __GNUC__extern const LPCTSTR sCFSTR_SHELLIDLIST;#undef CFSTR_SHELLIDLIST#define CFSTR_SHELLIDLIST sCFSTR_SHELLIDLIST#endif
#ifdef _MSC_VER#define NOVTABLE __declspec(novtable)#else#define NOVTABLE#endif#define ANSUNC
// Exception Handling
#ifndef _NO_COMUTIL
#define COMExceptionBase _com_error
#else
/// COM ExceptionBase class as replacement for _com_errorstruct COMExceptionBase{ COMExceptionBase(HRESULT hr) : _hr(hr) { }
HRESULT Error() const { return _hr; }
LPCTSTR ErrorMessage() const { if (_msg.empty()) { LPTSTR pBuf;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 0, _hr, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&pBuf, 0, NULL)) { _msg = pBuf; LocalFree(pBuf); } else { TCHAR buffer[128]; _sntprintf(buffer, COUNTOF(buffer), TEXT("unknown Exception: 0x%08lX"), _hr); _msg = buffer; } }
return _msg; }
protected: HRESULT _hr; mutable String _msg;};
#endif
/// Exception with context information
struct COMException : public COMExceptionBase{ typedef COMExceptionBase super;
COMException(HRESULT hr) : super(hr), _context(CURRENT_CONTEXT), _file(NULL), _line(0) { LOG(toString()); LOG(CURRENT_CONTEXT.getStackTrace()); }
COMException(HRESULT hr, const char* file, int line) : super(hr), _context(CURRENT_CONTEXT), _file(file), _line(line) { LOG(toString()); LOG(CURRENT_CONTEXT.getStackTrace()); }
COMException(HRESULT hr, const String& obj) : super(hr), _context(CURRENT_CONTEXT), _file(NULL), _line(0) { LOG(toString()); LOG(CURRENT_CONTEXT.getStackTrace()); }
COMException(HRESULT hr, const String& obj, const char* file, int line) : super(hr), _context(CURRENT_CONTEXT), _file(file), _line(line) { LOG(toString()); LOG(CURRENT_CONTEXT.getStackTrace()); }
String toString() const;
Context _context;
const char* _file; int _line;};
#define THROW_EXCEPTION(hr) throw COMException(hr, __FILE__, __LINE__)#define CHECKERROR(hr) ((void)(FAILED(hr)? THROW_EXCEPTION(hr): 0))
#ifdef _NO_COMUTIL
inline void CheckError(HRESULT hr){ if (FAILED(hr)) throw COMException(hr);}
#endif
/// COM Initialisation
struct ComInit{ ComInit() { CHECKERROR(CoInitialize(0)); }
#if (_WIN32_WINNT>=0x0400) || defined(_WIN32_DCOM) ComInit(DWORD flag) { CHECKERROR(CoInitializeEx(0, flag)); }#endif
~ComInit() { CoUninitialize(); }};
/// OLE initialisation for drag drop support
struct OleInit{ OleInit() { CHECKERROR(OleInitialize(0)); }
~OleInit() { OleUninitialize(); }};
/// Exception Handler for COM exceptions
extern void HandleException(COMException& e, HWND hwnd);
/// We use a common IMalloc object for all shell memory allocations.
struct CommonShellMalloc{ CommonShellMalloc() { _p = NULL; }
void init() { if (!_p) CHECKERROR(SHGetMalloc(&_p)); }
~CommonShellMalloc() { if (_p) _p->Release(); }
operator IMalloc*() { return _p; }
IMalloc* _p;};
/// wrapper class for IMalloc with usage of common allocator
struct ShellMalloc{ ShellMalloc() { // initialize s_cmn_shell_malloc s_cmn_shell_malloc.init(); }
IMalloc* operator->() { return s_cmn_shell_malloc; }
static CommonShellMalloc s_cmn_shell_malloc;};
/// wrapper template class for pointers to shell objects managed by IMalloc
template<typename T> struct SShellPtr{ ~SShellPtr() { _malloc->Free(_p); }
T* operator->() { return _p; }
T const* operator->() const { return _p; }
operator T const *() const { return _p; }
const T& operator*() const { return *_p; }
T& operator*() { return *_p; }
protected: SShellPtr() : _p(0) { }
SShellPtr(T* p) : _p(p) { }
void Free() { _malloc->Free(_p); _p = NULL; }
T* _p; mutable ShellMalloc _malloc; // IMalloc memory management object
private: // disallow copying of SShellPtr objects SShellPtr(const SShellPtr&) {} void operator=(SShellPtr const&) {}};
/// wrapper class for COM interface pointers
template<typename T> struct SIfacePtr{ SIfacePtr() : _p(0) { }
SIfacePtr(T* p) : _p(p) { if (p) p->AddRef(); }
SIfacePtr(IUnknown* unknown, REFIID riid) { CHECKERROR(unknown->QueryInterface(riid, (LPVOID*)&_p)); }
~SIfacePtr() { Free(); }
T* operator->() { return _p; }
const T* operator->() const { return _p; }
/* not GCC compatible operator const T*() const { return _p; } */
operator T*() { return _p; }
T** operator&() { return &_p; }
bool empty() const //NOTE: GCC seems not to work correctly when defining operator bool() AND operator T*() at one time { return !_p; }
SIfacePtr& operator=(T* p) { Free();
if (p) { p->AddRef(); _p = p; }
return *this; }
void operator=(SIfacePtr const& o) { T* h = _p;
if (o._p) o._p->AddRef();
_p = o._p;
if (h) h->Release(); }
HRESULT CreateInstance(REFIID clsid, REFIID riid) { return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&_p); }
template<typename I> HRESULT QueryInterface(REFIID riid, I* p) { return _p->QueryInterface(riid, (LPVOID*)p); }
T* get() { return _p; }
void Free() { T* h = _p; _p = NULL;
if (h) h->Release(); }
protected: SIfacePtr(const SIfacePtr& o) : _p(o._p) { if (_p) _p->AddRef(); }
T* _p;};
struct NOVTABLE ComSrvObject // NOVTABLE erlaubt, da protected Destruktor{protected: ComSrvObject() : _ref(1) {} virtual ~ComSrvObject() {}
ULONG _ref;};
struct SimpleComObject : public ComSrvObject{ ULONG IncRef() {return ++_ref;} ULONG DecRef() {ULONG ref=--_ref; if (!ref) {_ref++; delete this;} return ref;}};
// server object interfaces
template<typename BASE> struct IComSrvQI : public BASE{ IComSrvQI(REFIID uuid_base) : _uuid_base(uuid_base) { }
STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv) { *ppv = NULL;
if (IsEqualIID(riid, _uuid_base) || IsEqualIID(riid, IID_IUnknown)) {*ppv=static_cast<BASE*>(this); this->AddRef(); return S_OK;}
return E_NOINTERFACE; }
protected: IComSrvQI() {} virtual ~IComSrvQI() {}
REFIID _uuid_base;};
template<> struct IComSrvQI<IUnknown> : public IUnknown{ STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv) { *ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown)) {*ppv=this; AddRef(); return S_OK;}
return E_NOINTERFACE; }
protected: IComSrvQI<IUnknown>() {} virtual ~IComSrvQI<IUnknown>() {}};
template<typename BASE, typename OBJ> class IComSrvBase : public IComSrvQI<BASE>{ typedef IComSrvQI<BASE> super;
protected: IComSrvBase(REFIID uuid_base) : super(uuid_base) { }
public: STDMETHODIMP_(ULONG) AddRef() {return static_cast<OBJ*>(this)->IncRef();} STDMETHODIMP_(ULONG) Release() {return static_cast<OBJ*>(this)->DecRef();}};
struct ShellFolder;
/// caching of desktop ShellFolder object
struct CommonDesktop{ CommonDesktop() { _desktop = 0; }
~CommonDesktop();
void init();
operator ShellFolder&() { return *_desktop; }
protected: ShellFolder* _desktop;};
#ifndef _NO_COMUTIL // _com_ptr available?
/// IShellFolder smart pointerstruct ShellFolder : public IShellFolderPtr // IShellFolderPtr uses intrinsic extensions of the VC++ compiler.{ typedef IShellFolderPtr super;
ShellFolder(); // desktop folder ShellFolder(IShellFolder* p); ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl); ShellFolder(LPCITEMIDLIST pidl);
void attach(IShellFolder* parent, LPCITEMIDLIST pidl); String get_name(LPCITEMIDLIST pidl=NULL, SHGDNF flags=SHGDN_NORMAL) const;
bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty()};
#ifdef UNICODE#define IShellLinkPtr IShellLinkWPtr#else#define IShellLinkPtr IShellLinkAPtr#endif
/// IShellLink smart pointerstruct ShellLinkPtr : public IShellLinkPtr{ typedef IShellLinkPtr super;
ShellLinkPtr(IShellLink* p) : super(p) { p->AddRef(); }
bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty()};
#else // _com_ptr not available -> use SIfacePtr
/// IShellFolder smart pointerstruct ShellFolder : public SIfacePtr<IShellFolder>{ typedef SIfacePtr<IShellFolder> super;
ShellFolder(); ShellFolder(IShellFolder* p); ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl); ShellFolder(LPCITEMIDLIST pidl);
void attach(IShellFolder* parent, LPCITEMIDLIST pidl); String get_name(LPCITEMIDLIST pidl, SHGDNF flags=SHGDN_NORMAL) const;};
/// IShellLink smart pointerstruct ShellLinkPtr : public SIfacePtr<IShellLink>{ typedef SIfacePtr<IShellLink> super;
ShellLinkPtr(IShellLink* p) : super(p) { _p->AddRef(); }
};
#endif
extern ShellFolder& GetDesktopFolder();
#ifdef UNICODE#define path_from_pidl path_from_pidlW#else#define path_from_pidl path_from_pidlA#endif
extern HRESULT path_from_pidlA(IShellFolder* folder, LPCITEMIDLIST pidl, LPSTR buffer, int len);extern HRESULT path_from_pidlW(IShellFolder* folder, LPCITEMIDLIST pidl, LPWSTR buffer, int len);extern HRESULT name_from_pidl(IShellFolder* folder, LPCITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags);
// ILGetSize() was missing in previous versions of MinGW and is not exported from shell32.dll on Windows 2000.extern "C" UINT ILGetSize_local(LPCITEMIDLIST pidl);#define ILGetSize ILGetSize_local
#if 0#ifdef UNICODE // CFSTR_FILENAME was defined wrong in previous versions of MinGW.#define CFSTR_FILENAMEW TEXT("FileNameW")#undef CFSTR_FILENAME#define CFSTR_FILENAME CFSTR_FILENAMEW#endif#endif
/// wrapper class for item ID lists
struct ShellPath : public SShellPtr<ITEMIDLIST>{ typedef SShellPtr<ITEMIDLIST> super;
ShellPath() { }
ShellPath(IShellFolder* folder, LPCWSTR path) { CONTEXT("ShellPath::ShellPath(IShellFolder*, LPCWSTR)");
if (path) CHECKERROR(folder->ParseDisplayName(0, NULL, (LPOLESTR)path, NULL, &_p, NULL)); else _p = NULL; }
ShellPath(LPCWSTR path) { OBJ_CONTEXT("ShellPath::ShellPath(LPCWSTR)", path);
if (path) CHECKERROR(GetDesktopFolder()->ParseDisplayName(0, NULL, (LPOLESTR)path, NULL, &_p, NULL)); else _p = NULL; }
ShellPath(IShellFolder* folder, LPCSTR path) { CONTEXT("ShellPath::ShellPath(IShellFolder*, LPCSTR)");
WCHAR b[MAX_PATH];
if (path) { MultiByteToWideChar(CP_ACP, 0, path, -1, b, COUNTOF(b)); CHECKERROR(folder->ParseDisplayName(0, NULL, b, NULL, &_p, NULL)); } else _p = NULL; }
ShellPath(LPCSTR path) { CONTEXT("ShellPath::ShellPath(LPCSTR)");
WCHAR b[MAX_PATH];
if (path) { MultiByteToWideChar(CP_ACP, 0, path, -1, b, COUNTOF(b)); CHECKERROR(GetDesktopFolder()->ParseDisplayName(0, NULL, b, NULL, &_p, NULL)); } else _p = NULL; }
ShellPath(const ShellPath& o) : super(NULL) { //CONTEXT("ShellPath::ShellPath(const ShellPath&)");
if (o._p) { int l = ILGetSize(o._p); _p = (ITEMIDLIST*) _malloc->Alloc(l); if (_p) memcpy(_p, o._p, l); } }
explicit ShellPath(LPITEMIDLIST p) : super(p) { }
ShellPath(LPCITEMIDLIST p) { //CONTEXT("ShellPath::ShellPath(LPCITEMIDLIST)");
if (p) { int l = ILGetSize(p); _p = (ITEMIDLIST*) _malloc->Alloc(l); if (_p) memcpy(_p, p, l); } }
void operator=(const ShellPath& o) { //CONTEXT("ShellPath::operator=(const ShellPath&)");
ITEMIDLIST* h = _p;
if (o._p) { int l = ILGetSize(o._p);
_p = (ITEMIDLIST*) _malloc->Alloc(l); if (_p) memcpy(_p, o._p, l); } else _p = NULL;
_malloc->Free(h); }
void operator=(ITEMIDLIST* p) { //CONTEXT("ShellPath::operator=(ITEMIDLIST*)");
ITEMIDLIST* h = _p;
if (p) { int l = ILGetSize(p); _p = (ITEMIDLIST*) _malloc->Alloc(l); if (_p) memcpy(_p, p, l); } else _p = NULL;
_malloc->Free(h); }
void operator=(const SHITEMID& o) { ITEMIDLIST* h = _p;
LPBYTE p = (LPBYTE)_malloc->Alloc(o.cb+2); if (p) *(PWORD)((LPBYTE)memcpy(p, &o, o.cb)+o.cb) = 0; _p = (ITEMIDLIST*)p;
_malloc->Free(h); }
void operator+=(const SHITEMID& o) { int l0 = ILGetSize(_p); LPBYTE p = (LPBYTE)_malloc->Alloc(l0+o.cb); int l = l0 - 2;
if (p) { memcpy(p, _p, l); *(PWORD)((LPBYTE)memcpy(p+l, &o, o.cb)+o.cb) = 0; }
_malloc->Free(_p); _p = (ITEMIDLIST*)p; }
friend bool operator<(const ShellPath& a, const ShellPath& b) { int la = ILGetSize(a._p); int lb = ILGetSize(b._p);
int r = memcmp(a._p, b._p, min(la, lb)); if (r) return r < 0; else return la < lb; }
void assign(LPCITEMIDLIST pidl, size_t size) { //CONTEXT("ShellPath::assign(LPCITEMIDLIST, size_t)");
ITEMIDLIST* h = _p;
_p = (ITEMIDLIST*) _malloc->Alloc(size+sizeof(USHORT/*SHITEMID::cb*/));
if (_p) { memcpy(_p, pidl, size); ((ITEMIDLIST*)((LPBYTE)_p+size))->mkid.cb = 0; // terminator }
_malloc->Free(h); }
void assign(LPCITEMIDLIST pidl) { //CONTEXT("ShellPath::assign(LPCITEMIDLIST)");
ITEMIDLIST* h = _p;
if (pidl) { int l = ILGetSize(pidl); _p = (ITEMIDLIST*) _malloc->Alloc(l); if (_p) memcpy(_p, pidl, l); } else _p = NULL;
_malloc->Free(h); }
void split(ShellPath& parent, ShellPath& obj) const;
void GetUIObjectOf(REFIID riid, LPVOID* ppvOut, HWND hWnd=0, ShellFolder& sf=GetDesktopFolder());
ShellFolder get_folder() { return ShellFolder(_p); }
ShellFolder get_folder(IShellFolder* parent) { CONTEXT("ShellPath::get_folder()"); return ShellFolder(parent, _p); }
// convert an item id list from relative to absolute (=relative to the desktop) format ShellPath create_absolute_pidl(LPCITEMIDLIST parent_pidl) const;};
#if defined(__WINE__) && defined(NONAMELESSUNION) // Wine doesn't know of unnamed union members and uses some macros instead.#define UNION_MEMBER(x) DUMMYUNIONNAME.##x#else#define UNION_MEMBER(x) x#endif
// encapsulation of STRRET structure for easy string retrieval with conversion
#ifdef UNICODE#define StrRet StrRetW//#define tcscpyn wcscpyn#else#define StrRet StrRetA//#define tcscpyn strcpyn#endif
//extern LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count);//extern LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count);
/// easy retrieval of multi byte strings out of STRRET structuresstruct StrRetA : public STRRET{ ~StrRetA() { if (uType == STRRET_WSTR) ShellMalloc()->Free(pOleStr); }
void GetString(const SHITEMID& shiid, LPSTR b, int l) { switch(uType) { case STRRET_WSTR: WideCharToMultiByte(CP_ACP, 0, UNION_MEMBER(pOleStr), -1, b, l, NULL, NULL); break;
case STRRET_OFFSET: lstrcpynA(b, (LPCSTR)&shiid+UNION_MEMBER(uOffset), l); break;
case STRRET_CSTR: lstrcpynA(b, UNION_MEMBER(cStr), l); } }};
/// easy retrieval of wide char strings out of STRRET structuresstruct StrRetW : public STRRET{ ~StrRetW() { if (uType == STRRET_WSTR) ShellMalloc()->Free(pOleStr); }
void GetString(const SHITEMID& shiid, LPWSTR b, int l) { switch(uType) { case STRRET_WSTR: lstrcpynW(b, UNION_MEMBER(pOleStr), l); break;
case STRRET_OFFSET: MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&shiid+UNION_MEMBER(uOffset), -1, b, l); break;
case STRRET_CSTR: MultiByteToWideChar(CP_ACP, 0, UNION_MEMBER(cStr), -1, b, l); } }};
/// Retrieval of file system paths of ShellPath objectsclass FileSysShellPath : public ShellPath{ TCHAR _fullpath[MAX_PATH];
protected: FileSysShellPath() {_fullpath[0] = '\0';}
public: FileSysShellPath(const ShellPath& o) : ShellPath(o) {_fullpath[0] = '\0';}
operator LPCTSTR() {if (!SHGetPathFromIDList(_p, _fullpath)) return NULL; return _fullpath;}};
/// Browse dialog operating on shell namespacestruct FolderBrowser : public FileSysShellPath{ FolderBrowser(HWND owner, UINT flags, LPCTSTR title, LPCITEMIDLIST root=0) { _displayname[0] = '\0'; _browseinfo.hwndOwner = owner; _browseinfo.pidlRoot = root; _browseinfo.pszDisplayName = _displayname; _browseinfo.lpszTitle = title; _browseinfo.ulFlags = flags; _browseinfo.lpfn = 0; _browseinfo.lParam = 0; _browseinfo.iImage = 0;
_p = SHBrowseForFolder(&_browseinfo); }
LPCTSTR GetDisplayName() { return _displayname; }
bool IsOK() { return _p != 0; }
private: BROWSEINFO _browseinfo; TCHAR _displayname[MAX_PATH];};
/// Retrieval of special shell folder pathsstruct SpecialFolderPath : public ShellPath{ SpecialFolderPath(int folder, HWND hwnd) { HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p); CHECKERROR(hr); }};
/// Shell folder path of the desktopstruct DesktopFolderPath : public SpecialFolderPath{ DesktopFolderPath() : SpecialFolderPath(CSIDL_DESKTOP, 0) { }};
/// Retrieval of special shell folderstruct SpecialFolder : public ShellFolder{ SpecialFolder(int folder, HWND hwnd) : ShellFolder(GetDesktopFolder(), SpecialFolderPath(folder, hwnd)) { }};
/// Shell folder of the desktopstruct DesktopFolder : public ShellFolder{};
/// file system path of special folderstruct SpecialFolderFSPath{ SpecialFolderFSPath(int folder/*e.g. CSIDL_DESKTOP*/, HWND hwnd);
operator LPCTSTR() { return _fullpath; }
protected: TCHAR _fullpath[MAX_PATH];};
/* /// file system path of special folderstruct SpecialFolderFSPath : public FileSysShellPath{ SpecialFolderFSPath(int folder, HWND hwnd) { CONTEXT("SpecialFolderFSPath::SpecialFolderFSPath()");
HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p); CHECKERROR(hr); }};*/
/// wrapper class for enumerating shell namespace objects
struct ShellItemEnumerator : public SIfacePtr<IEnumIDList>{ ShellItemEnumerator(IShellFolder* folder, DWORD flags=SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN) { CONTEXT("ShellItemEnumerator::ShellItemEnumerator()");
CHECKERROR(folder->EnumObjects(0, flags, &_p)); }};
/// list of PIDLsstruct PIDList{ PIDList() { memset(&_stgm, 0, sizeof(STGMEDIUM)); }
~PIDList() { if (_stgm.hGlobal) { GlobalUnlock(_stgm.hGlobal); ReleaseStgMedium(&_stgm); } }
HRESULT GetData(IDataObject* selection) { static UINT CF_IDLIST = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
FORMATETC fetc; fetc.cfFormat = CF_IDLIST; fetc.ptd = NULL; fetc.dwAspect = DVASPECT_CONTENT; fetc.lindex = -1; fetc.tymed = TYMED_HGLOBAL;
HRESULT hr = selection->QueryGetData(&fetc); if (FAILED(hr)) return hr;
hr = selection->GetData(&fetc, &_stgm); if (FAILED(hr)) return hr;
_pIDList = (LPIDA)GlobalLock(_stgm.hGlobal);
return hr; }
operator LPIDA() {return _pIDList;}
protected: STGMEDIUM _stgm; LPIDA _pIDList;};
struct CtxMenuInterfaces{ CtxMenuInterfaces() { reset(); }
void reset(); bool HandleMenuMsg(UINT nmsg, WPARAM wparam, LPARAM lparam); IContextMenu* query_interfaces(IContextMenu* pcm1);
IContextMenu2* _pctxmenu2;
IContextMenu3* _pctxmenu3;};
template<typename BASE> struct ExtContextMenuHandlerT : public BASE{ typedef BASE super;
ExtContextMenuHandlerT(HWND hwnd) : super(hwnd) { }
template<typename PARA> ExtContextMenuHandlerT(HWND hwnd, const PARA& info) : super(hwnd, info) { }
LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) { switch(nmsg) { case WM_DRAWITEM: case WM_MEASUREITEM: if (!wparam) // Is the message menu-related? if (_cm_ifs.HandleMenuMsg(nmsg, wparam, lparam)) return TRUE;
break;
case WM_INITMENUPOPUP: if (_cm_ifs.HandleMenuMsg(nmsg, wparam, lparam)) return 0;
break;
case WM_MENUCHAR: // only supported by IContextMenu3 if (_cm_ifs._pctxmenu3) { LRESULT lResult = 0;
_cm_ifs._pctxmenu3->HandleMenuMsg2(nmsg, wparam, lparam, &lResult);
return lResult; }
return 0; }
return super::WndProc(nmsg, wparam, lparam); }
protected: CtxMenuInterfaces _cm_ifs;};
extern HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl, LPCITEMIDLIST* ppidl, int x, int y, CtxMenuInterfaces& cm_ifs);