reactos/modules/rosapps/applications/explorer-old/utility/shellclasses.h

1174 lines
21 KiB
C++

/*
* 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_error
struct 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 pointer
struct 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 pointer
struct 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 pointer
struct 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 pointer
struct 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 structures
struct 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 structures
struct 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 objects
class 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 namespace
struct 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 paths
struct SpecialFolderPath : public ShellPath
{
SpecialFolderPath(int folder, HWND hwnd)
{
HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p);
CHECKERROR(hr);
}
};
/// Shell folder path of the desktop
struct DesktopFolderPath : public SpecialFolderPath
{
DesktopFolderPath()
: SpecialFolderPath(CSIDL_DESKTOP, 0)
{
}
};
/// Retrieval of special shell folder
struct SpecialFolder : public ShellFolder
{
SpecialFolder(int folder, HWND hwnd)
: ShellFolder(GetDesktopFolder(), SpecialFolderPath(folder, hwnd))
{
}
};
/// Shell folder of the desktop
struct DesktopFolder : public ShellFolder
{
};
/// file system path of special folder
struct SpecialFolderFSPath
{
SpecialFolderFSPath(int folder/*e.g. CSIDL_DESKTOP*/, HWND hwnd);
operator LPCTSTR()
{
return _fullpath;
}
protected:
TCHAR _fullpath[MAX_PATH];
};
/*
/// file system path of special folder
struct 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 PIDLs
struct 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);