mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 02:13:29 +00:00
1174 lines
21 KiB
C++
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);
|