1002 lines
27 KiB
C++
1002 lines
27 KiB
C++
|
#include "shole.h"
|
||
|
#include "ids.h"
|
||
|
#include "scguid.h"
|
||
|
|
||
|
#ifdef FEATURE_SHELLEXTENSION
|
||
|
|
||
|
extern "C" const TCHAR c_szCLSID[];
|
||
|
|
||
|
class CTemplateFolder : public IShellFolder, public IPersistFolder
|
||
|
{
|
||
|
public:
|
||
|
CTemplateFolder();
|
||
|
~CTemplateFolder();
|
||
|
inline BOOL ConstructedSuccessfully() { return _hdpaMap != NULL; }
|
||
|
|
||
|
// IUnKnown
|
||
|
virtual HRESULT __stdcall QueryInterface(REFIID,void **);
|
||
|
virtual ULONG __stdcall AddRef(void);
|
||
|
virtual ULONG __stdcall Release(void);
|
||
|
|
||
|
// IShellFolder
|
||
|
virtual HRESULT __stdcall ParseDisplayName(HWND hwndOwner,
|
||
|
LPBC pbcReserved, LPOLESTR lpszDisplayName,
|
||
|
ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
|
||
|
|
||
|
virtual HRESULT __stdcall EnumObjects( THIS_ HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumIDList);
|
||
|
|
||
|
virtual HRESULT __stdcall BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved,
|
||
|
REFIID riid, LPVOID * ppvOut);
|
||
|
virtual HRESULT __stdcall BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved,
|
||
|
REFIID riid, LPVOID * ppvObj);
|
||
|
virtual HRESULT __stdcall CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
||
|
virtual HRESULT __stdcall CreateViewObject (HWND hwndOwner, REFIID riid, LPVOID * ppvOut);
|
||
|
virtual HRESULT __stdcall GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
|
||
|
ULONG * rgfInOut);
|
||
|
virtual HRESULT __stdcall GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
|
||
|
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut);
|
||
|
virtual HRESULT __stdcall GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
|
||
|
virtual HRESULT __stdcall SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
|
||
|
LPCOLESTR lpszName, DWORD uFlags,
|
||
|
LPITEMIDLIST * ppidlOut);
|
||
|
|
||
|
// IPersistFolder
|
||
|
virtual HRESULT __stdcall GetClassID(LPCLSID lpClassID);
|
||
|
virtual HRESULT __stdcall Initialize(LPCITEMIDLIST pidl);
|
||
|
|
||
|
protected:
|
||
|
// Defview callback
|
||
|
friend HRESULT CALLBACK DefViewCallback(
|
||
|
LPSHELLVIEW psvOuter, LPSHELLFOLDER psf,
|
||
|
HWND hwndOwner, UINT uMsg,
|
||
|
WPARAM wParam, LPARAM lParam);
|
||
|
HRESULT GetDetailsOfDVM(UINT ici, DETAILSINFO *pdi);
|
||
|
|
||
|
BOOL IsMyPidl(LPCITEMIDLIST pidl)
|
||
|
{ return (pidl->mkid.abID[0] == 'S' && pidl->mkid.abID[1] == 'N'); }
|
||
|
|
||
|
UINT _cRef;
|
||
|
|
||
|
//
|
||
|
// To speed up name lookups, we cache the mapping between CLSIDs and
|
||
|
// display names. We cannot persist this mapping because it won't
|
||
|
// survive localization or ANSI/UNICODE interop.
|
||
|
//
|
||
|
typedef struct {
|
||
|
CLSID clsid;
|
||
|
TCHAR achName[MAX_PATH];
|
||
|
} CLSIDMAP, *PCLSIDMAP;
|
||
|
|
||
|
HDPA _hdpaMap;
|
||
|
|
||
|
HRESULT GetNameOf(LPCITEMIDLIST pidl, LPCTSTR *ppsz);
|
||
|
};
|
||
|
|
||
|
class CEnumTemplate : public IEnumIDList
|
||
|
{
|
||
|
public:
|
||
|
CEnumTemplate(DWORD grfFlags);
|
||
|
~CEnumTemplate();
|
||
|
|
||
|
protected:
|
||
|
// IUnKnown
|
||
|
virtual HRESULT __stdcall QueryInterface(REFIID,void **);
|
||
|
virtual ULONG __stdcall AddRef(void);
|
||
|
virtual ULONG __stdcall Release(void);
|
||
|
|
||
|
virtual HRESULT __stdcall Next(ULONG celt,
|
||
|
LPITEMIDLIST *rgelt,
|
||
|
ULONG *pceltFetched);
|
||
|
virtual HRESULT __stdcall Skip(ULONG celt);
|
||
|
virtual HRESULT __stdcall Reset();
|
||
|
virtual HRESULT __stdcall Clone(IEnumIDList **ppenum);
|
||
|
|
||
|
UINT _cRef;
|
||
|
const DWORD _grfFlags;
|
||
|
UINT _iCur;
|
||
|
HKEY _hkeyCLSID;
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// For Win95/NT interop, our PIDLs are always UNICODE.
|
||
|
// Use explicit packing for Win32/64 interop.
|
||
|
#include <pshpack1.h>
|
||
|
typedef struct _TIDL {
|
||
|
USHORT cb; // This matches SHITEMID
|
||
|
BYTE abID[2]; // This matches SHITEMID
|
||
|
CLSID clsid;
|
||
|
} TIDL;
|
||
|
typedef const UNALIGNED TIDL *PTIDL;
|
||
|
|
||
|
//
|
||
|
// This is the TIDL constructor -- it has the cbZero at the end.
|
||
|
//
|
||
|
typedef struct _TIDLCONS {
|
||
|
TIDL tidl;
|
||
|
USHORT cbZero;
|
||
|
} TIDLCONS;
|
||
|
|
||
|
#include <poppack.h>
|
||
|
|
||
|
class CTemplateUIObj : public IExtractIcon, public IDataObject, public IContextMenu
|
||
|
{
|
||
|
public:
|
||
|
static HRESULT Create(REFCLSID, REFIID, LPVOID*);
|
||
|
protected:
|
||
|
CTemplateUIObj(REFCLSID rclsid)
|
||
|
: _clsid(rclsid), _cRef(1)
|
||
|
{ DllAddRef(); }
|
||
|
~CTemplateUIObj() { DllRelease(); }
|
||
|
HRESULT _CreateInstance(IStorage* pstg);
|
||
|
|
||
|
// IUnKnown
|
||
|
virtual HRESULT __stdcall QueryInterface(REFIID,void **);
|
||
|
virtual ULONG __stdcall AddRef(void);
|
||
|
virtual ULONG __stdcall Release(void);
|
||
|
|
||
|
// *** IExtractIcon methods ***
|
||
|
virtual HRESULT __stdcall GetIconLocation(
|
||
|
UINT uFlags, LPTSTR szIconFile,
|
||
|
UINT cchMax, int * piIndex,
|
||
|
UINT * pwFlags);
|
||
|
|
||
|
virtual HRESULT __stdcall Extract(
|
||
|
LPCTSTR pszFile, UINT nIconIndex,
|
||
|
HICON *phiconLarge, HICON *phiconSmall,
|
||
|
UINT nIconSize);
|
||
|
|
||
|
// IDataObject
|
||
|
virtual HRESULT __stdcall GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
|
||
|
virtual HRESULT __stdcall GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
|
||
|
virtual HRESULT __stdcall QueryGetData(FORMATETC *pformatetc);
|
||
|
virtual HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut);
|
||
|
virtual HRESULT __stdcall SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
|
||
|
virtual HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
|
||
|
virtual HRESULT __stdcall DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
|
||
|
virtual HRESULT __stdcall DUnadvise(DWORD dwConnection);
|
||
|
virtual HRESULT __stdcall EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
|
||
|
|
||
|
// IContextMenu
|
||
|
virtual HRESULT __stdcall QueryContextMenu(
|
||
|
HMENU hmenu,
|
||
|
UINT indexMenu,
|
||
|
UINT idCmdFirst,
|
||
|
UINT idCmdLast,
|
||
|
UINT uFlags);
|
||
|
|
||
|
virtual HRESULT __stdcall InvokeCommand(
|
||
|
LPCMINVOKECOMMANDINFO lpici);
|
||
|
|
||
|
virtual HRESULT __stdcall GetCommandString(
|
||
|
UINT idCmd,
|
||
|
UINT uType,
|
||
|
UINT * pwReserved,
|
||
|
LPSTR pszName,
|
||
|
UINT cchMax);
|
||
|
|
||
|
UINT _cRef;
|
||
|
CLSID _clsid;
|
||
|
};
|
||
|
|
||
|
|
||
|
CTemplateFolder::CTemplateFolder() : _cRef(1)
|
||
|
{
|
||
|
_hdpaMap = DPA_Create(10);
|
||
|
OleInitialize(NULL);
|
||
|
DllAddRef();
|
||
|
}
|
||
|
|
||
|
CTemplateFolder::~CTemplateFolder()
|
||
|
{
|
||
|
if (_hdpaMap) {
|
||
|
for (int i = DPA_GetPtrCount(_hdpaMap) - 1; i >= 0; i--) {
|
||
|
PCLSIDMAP pmap = (PCLSIDMAP)DPA_FastGetPtr(_hdpaMap, i);
|
||
|
LocalFree(pmap);
|
||
|
}
|
||
|
DPA_Destroy(_hdpaMap);
|
||
|
}
|
||
|
|
||
|
OleUninitialize();
|
||
|
DllRelease();
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IShellFolder) || IsEqualIID(riid, IID_IUnknown))
|
||
|
{
|
||
|
*ppvObj = (IShellFolder*)this;
|
||
|
_cRef++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IPersistFolder))
|
||
|
{
|
||
|
*ppvObj = (IPersistFolder*)this;
|
||
|
_cRef++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
*ppvObj = NULL;
|
||
|
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
ULONG CTemplateFolder::AddRef()
|
||
|
{
|
||
|
_cRef++;
|
||
|
return _cRef;
|
||
|
}
|
||
|
|
||
|
ULONG CTemplateFolder::Release()
|
||
|
{
|
||
|
_cRef--;
|
||
|
if (_cRef > 0)
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder_CreateInstance(LPUNKNOWN * ppunk)
|
||
|
{
|
||
|
*ppunk = NULL;
|
||
|
|
||
|
CTemplateFolder* ptfld = new CTemplateFolder();
|
||
|
if (ptfld) {
|
||
|
if (ptfld->ConstructedSuccessfully()) {
|
||
|
*ppunk = (IShellFolder *)ptfld;
|
||
|
return S_OK;
|
||
|
}
|
||
|
ptfld->Release();
|
||
|
}
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::ParseDisplayName(HWND hwndOwner,
|
||
|
LPBC pbcReserved, LPOLESTR lpszDisplayName,
|
||
|
ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::EnumObjects(HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumIDList)
|
||
|
{
|
||
|
*ppenumIDList = new CEnumTemplate(grfFlags);
|
||
|
return *ppenumIDList ? S_OK : E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved,
|
||
|
REFIID riid, LPVOID * ppvOut)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved,
|
||
|
REFIID riid, LPVOID * ppvObj)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the name is in the cache, celebrate our good fortune and return it.
|
||
|
// Else, go get the name from the registry and cache it for later.
|
||
|
//
|
||
|
HRESULT CTemplateFolder::GetNameOf(LPCITEMIDLIST pidl, LPCTSTR *ppsz)
|
||
|
{
|
||
|
if (!IsMyPidl(pidl))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
HRESULT hres;
|
||
|
PTIDL ptidl = (PTIDL)pidl;
|
||
|
CLSIDMAP map;
|
||
|
map.clsid = ptidl->clsid; // Align the CLSID
|
||
|
PCLSIDMAP pmap;
|
||
|
for (int i = DPA_GetPtrCount(_hdpaMap) - 1; i >= 0; i--) {
|
||
|
pmap = (PCLSIDMAP)DPA_FastGetPtr(_hdpaMap, i);
|
||
|
if (IsEqualGUID(pmap->clsid, map.clsid)) {
|
||
|
*ppsz = pmap->achName;
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Not in cache -- go find it in the registry
|
||
|
//
|
||
|
TCHAR szKey[GUIDSTR_MAX + 6];
|
||
|
_KeyNameFromCLSID(map.clsid, szKey, ARRAYSIZE(szKey));
|
||
|
LONG dwSize = ARRAYSIZE(map.achName);
|
||
|
LONG lError = RegQueryValue(HKEY_CLASSES_ROOT, szKey, map.achName, &dwSize);
|
||
|
if (lError == ERROR_SUCCESS)
|
||
|
{
|
||
|
UINT cb = FIELD_OFFSET(CLSIDMAP, achName[lstrlen(map.achName)+1]);
|
||
|
pmap = (PCLSIDMAP)LocalAlloc(LMEM_FIXED, cb);
|
||
|
if (pmap) {
|
||
|
CopyMemory(pmap, &map, cb);
|
||
|
if (DPA_AppendPtr(_hdpaMap, pmap) >= 0) {
|
||
|
*ppsz = pmap->achName;
|
||
|
hres = S_OK;
|
||
|
} else {
|
||
|
LocalFree(pmap);
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
} else {
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hres = HRESULT_FROM_WIN32(lError);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
||
|
{
|
||
|
LPCTSTR psz1, psz2;
|
||
|
HRESULT hres;
|
||
|
|
||
|
hres = GetNameOf(pidl1, &psz1);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
hres = GetNameOf(pidl2, &psz2);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
hres = ResultFromShort(lstrcmpi(psz1, psz2));
|
||
|
}
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CTemplateFolder::GetDetailsOfDVM(UINT ici, DETAILSINFO *pdi)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
switch (ici) {
|
||
|
case 0:
|
||
|
if (pdi->pidl) {
|
||
|
hres = GetDisplayNameOf(pdi->pidl, SHGDN_NORMAL, &pdi->str);
|
||
|
} else {
|
||
|
pdi->fmt = LVCFMT_LEFT;
|
||
|
pdi->cxChar = 30;
|
||
|
pdi->str.uType = STRRET_CSTR;
|
||
|
lstrcpyA(pdi->str.cStr, "Name");
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
hres = E_NOTIMPL;
|
||
|
break;
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CALLBACK DefViewCallback(LPSHELLVIEW psvOuter, LPSHELLFOLDER psf,
|
||
|
HWND hwndOwner, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
// DefView GPF if I don't pass the callback function!
|
||
|
// DebugMsg(DM_TRACE, "sc TR - DefViewCallBack %d,%x,%x", uMsg, wParam, lParam);
|
||
|
switch(uMsg)
|
||
|
{
|
||
|
case DVM_WINDOWDESTROY:
|
||
|
DebugMsg(DM_TRACE, TEXT("sc TR - DefViewCallBack Calling OleFlushClipboard"));
|
||
|
OleFlushClipboard();
|
||
|
return S_OK;
|
||
|
case DVM_GETDETAILSOF:
|
||
|
return ((CTemplateFolder*)psf)->GetDetailsOfDVM((UINT)wParam, (DETAILSINFO*)lParam);
|
||
|
}
|
||
|
// DefView GPF if it returns S_FALSE as the default!
|
||
|
return E_FAIL; // S_FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CTemplateFolder::CreateViewObject (HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IShellView))
|
||
|
{
|
||
|
CSFV csfv = {
|
||
|
SIZEOF(CSFV), // cbSize
|
||
|
this, // pshf
|
||
|
NULL, // psvOuter
|
||
|
NULL, // pidl
|
||
|
0,
|
||
|
DefViewCallback, // pfnCallback
|
||
|
FVM_ICON,
|
||
|
};
|
||
|
return SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW *)ppvOut);
|
||
|
}
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
|
||
|
ULONG * rgfInOut)
|
||
|
{
|
||
|
if (cidl==1)
|
||
|
{
|
||
|
UINT rgfOut = SFGAO_CANCOPY /* | SFGAO_HASPROPSHEET */;
|
||
|
*rgfInOut &= rgfOut;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*rgfInOut = 0;
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
|
||
|
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
|
||
|
{
|
||
|
HRESULT hres = E_INVALIDARG;
|
||
|
if (cidl==1 && IsMyPidl(apidl[0]))
|
||
|
{
|
||
|
PTIDL ptidl = (PTIDL)apidl[0];
|
||
|
hres = CTemplateUIObj::Create(ptidl->clsid, riid, ppvOut);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT _KeyNameFromCLSID(REFCLSID rclsid, LPTSTR pszKey, UINT cchMax)
|
||
|
{
|
||
|
ASSERT(cchMax - 6 >= GUIDSTR_MAX);
|
||
|
lstrcpyn(pszKey, TEXT("CLSID\\"), cchMax);
|
||
|
SHStringFromGUID(rclsid, pszKey + 6, cchMax - 6);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
|
||
|
{
|
||
|
LPCTSTR psz;
|
||
|
HRESULT hres;
|
||
|
|
||
|
hres = GetNameOf(pidl, &psz);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
#ifdef UNICODE
|
||
|
lpName->uType = STRRET_WSTR;
|
||
|
hres = SHStrDupW(psz, &lpName->pOleStr);
|
||
|
#else
|
||
|
lstrcpyn(lpName->cStr, psz, ARRAYSIZE(lpName->cStr));
|
||
|
hres = S_OK;
|
||
|
#endif
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
|
||
|
LPCOLESTR lpszName, DWORD uFlags,
|
||
|
LPITEMIDLIST * ppidlOut)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT __stdcall CTemplateFolder::GetClassID(LPCLSID lpClassID)
|
||
|
{
|
||
|
*lpClassID = CLSID_CTemplateFolder;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT __stdcall CTemplateFolder::Initialize(LPCITEMIDLIST pidl)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
CEnumTemplate::CEnumTemplate(DWORD grfFlags)
|
||
|
: _cRef(1), _grfFlags(grfFlags), _iCur(0), _hkeyCLSID(NULL)
|
||
|
{
|
||
|
DllAddRef();
|
||
|
}
|
||
|
|
||
|
CEnumTemplate::~CEnumTemplate()
|
||
|
{
|
||
|
if (_hkeyCLSID) {
|
||
|
RegCloseKey(_hkeyCLSID);
|
||
|
}
|
||
|
DllRelease();
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumTemplate::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IEnumIDList) || IsEqualIID(riid, IID_IUnknown))
|
||
|
{
|
||
|
*ppvObj = (IEnumIDList*)this;
|
||
|
_cRef++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
*ppvObj = NULL;
|
||
|
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
ULONG CEnumTemplate::AddRef()
|
||
|
{
|
||
|
_cRef++;
|
||
|
return _cRef;
|
||
|
}
|
||
|
|
||
|
ULONG CEnumTemplate::Release()
|
||
|
{
|
||
|
_cRef--;
|
||
|
if (_cRef > 0)
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumTemplate::Next(ULONG celt,
|
||
|
LPITEMIDLIST *rgelt,
|
||
|
ULONG *pceltFetched)
|
||
|
{
|
||
|
// Assume error
|
||
|
if (pceltFetched) {
|
||
|
*pceltFetched = 0;
|
||
|
}
|
||
|
|
||
|
if (!(_grfFlags & SHCONTF_NONFOLDERS)) {
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
if (!_hkeyCLSID)
|
||
|
{
|
||
|
if (RegOpenKey(HKEY_CLASSES_ROOT, c_szCLSID, &_hkeyCLSID) != ERROR_SUCCESS)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TCHAR szKeyBuf[128]; // enough for {CLSID} or "ProgId/XXX"
|
||
|
|
||
|
// Subtract 64 to allow room for the goo we append later on
|
||
|
while (RegEnumKey(HKEY_CLASSES_ROOT, _iCur++, szKeyBuf, ARRAYSIZE(szKeyBuf) - 64) == ERROR_SUCCESS)
|
||
|
{
|
||
|
TCHAR szT[128];
|
||
|
LONG dwRead;
|
||
|
int cchKey = lstrlen(szKeyBuf);
|
||
|
|
||
|
// Check for \NotInsertable.
|
||
|
lstrcpy(szKeyBuf+cchKey, TEXT("\\NotInsertable"));
|
||
|
dwRead = ARRAYSIZE(szT);
|
||
|
if (RegQueryValue(HKEY_CLASSES_ROOT, szKeyBuf, szT, &dwRead) == ERROR_SUCCESS) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
BOOL fInsertable = FALSE;
|
||
|
//
|
||
|
// Let's stop supporting OLE1 servers anymore.
|
||
|
//
|
||
|
#if 0
|
||
|
lstrcpy(szKeyBuf+cchKey, TEXT("\\protocol\\StdFileEditing\\server"));
|
||
|
dwRead = ARRAYSIZE(szT);
|
||
|
if (RegQueryValue(HKEY_CLASSES_ROOT, szKeyBuf, szT, &dwRead) == ERROR_SUCCESS)
|
||
|
{
|
||
|
fInsertable = TRUE;
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
lstrcpy(szKeyBuf+cchKey, TEXT("\\Insertable"));
|
||
|
dwRead = ARRAYSIZE(szT);
|
||
|
if (RegQueryValue(HKEY_CLASSES_ROOT, szKeyBuf, szT, &dwRead) == ERROR_SUCCESS)
|
||
|
{
|
||
|
fInsertable = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fInsertable)
|
||
|
{
|
||
|
lstrcpy(szKeyBuf+cchKey, TEXT("\\CLSID"));
|
||
|
dwRead = ARRAYSIZE(szT);
|
||
|
if (RegQueryValue(HKEY_CLASSES_ROOT, szKeyBuf, szT, &dwRead) == ERROR_SUCCESS)
|
||
|
{
|
||
|
TIDLCONS tidlCons;
|
||
|
CLSID clsid; // Aligned version
|
||
|
tidlCons.tidl.cb = sizeof(TIDL);
|
||
|
tidlCons.tidl.abID[0] = 'S';
|
||
|
tidlCons.tidl.abID[1] = 'N';
|
||
|
|
||
|
if (GUIDFromString(szT, &clsid))
|
||
|
{
|
||
|
tidlCons.tidl.clsid = clsid;
|
||
|
tidlCons.cbZero = 0;
|
||
|
rgelt[0] = ILClone((LPITEMIDLIST)&tidlCons);
|
||
|
*pceltFetched = 1;
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return S_FALSE; // no more element
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumTemplate::Skip(ULONG celt)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumTemplate::Reset()
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumTemplate::Clone(IEnumIDList **ppenum)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//==========================================================================
|
||
|
// CTemplateUIObj members (IUnknown override)
|
||
|
//==========================================================================
|
||
|
|
||
|
HRESULT CTemplateUIObj::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IExtractIcon) || IsEqualIID(riid, IID_IUnknown))
|
||
|
{
|
||
|
*ppvObj = (IExtractIcon*)this;
|
||
|
_cRef++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IDataObject))
|
||
|
{
|
||
|
*ppvObj = (IDataObject*)this;
|
||
|
_cRef++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IContextMenu))
|
||
|
{
|
||
|
*ppvObj = (IContextMenu*)this;
|
||
|
_cRef++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
*ppvObj = NULL;
|
||
|
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
ULONG CTemplateUIObj::AddRef()
|
||
|
{
|
||
|
_cRef++;
|
||
|
return _cRef;
|
||
|
}
|
||
|
|
||
|
ULONG CTemplateUIObj::Release()
|
||
|
{
|
||
|
_cRef--;
|
||
|
if (_cRef > 0)
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NOTES: This logic MUST be identical to the one in the shell.
|
||
|
//
|
||
|
int _ParseIconLocation(LPTSTR pszIconFile)
|
||
|
{
|
||
|
int iIndex = 0;
|
||
|
LPTSTR pszComma = StrChr(pszIconFile, TEXT(','));
|
||
|
|
||
|
if (pszComma) {
|
||
|
*pszComma++ = 0; // terminate the icon file name.
|
||
|
iIndex = StrToInt(pszComma);
|
||
|
}
|
||
|
PathRemoveBlanks(pszIconFile);
|
||
|
return iIndex;
|
||
|
}
|
||
|
|
||
|
|
||
|
//==========================================================================
|
||
|
// CTemplateUIObj members (IExtractIcon override)
|
||
|
//==========================================================================
|
||
|
|
||
|
//
|
||
|
// szClass -- Specifies either CLSID\{CLSID} or ProgID
|
||
|
//
|
||
|
HRESULT _GetDefaultIcon(LPCTSTR szClass, LPTSTR szIconFile, UINT cchMax, int *piIndex)
|
||
|
{
|
||
|
TCHAR szKey[256];
|
||
|
wsprintf(szKey, TEXT("%s\\DefaultIcon"), szClass);
|
||
|
TCHAR szValue[MAX_PATH+40];
|
||
|
LONG dwSize = ARRAYSIZE(szValue);
|
||
|
if (RegQueryValue(HKEY_CLASSES_ROOT, szKey, szValue, &dwSize) == ERROR_SUCCESS)
|
||
|
{
|
||
|
*piIndex = _ParseIconLocation(szValue);
|
||
|
lstrcpyn(szIconFile, szValue, cchMax);
|
||
|
return S_OK;
|
||
|
}
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::GetIconLocation(
|
||
|
UINT uFlags, LPTSTR szIconFile,
|
||
|
UINT cchMax, int * piIndex,
|
||
|
UINT * pwFlags)
|
||
|
{
|
||
|
*pwFlags = GIL_PERCLASS; // Always per-class
|
||
|
|
||
|
TCHAR szKey[128];
|
||
|
HRESULT hres = _KeyNameFromCLSID(_clsid, szKey, ARRAYSIZE(szKey));
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
//
|
||
|
// First, look at "CLSID\{CLSID}\DefautlIcon"
|
||
|
//
|
||
|
hres = _GetDefaultIcon(szKey, szIconFile, cchMax, piIndex);
|
||
|
if (FAILED(hres))
|
||
|
{
|
||
|
//
|
||
|
// Then, look at "ProgID\DefaultIcon" to work-around a bug
|
||
|
// of "Wave Sound".
|
||
|
//
|
||
|
lstrcat(szKey, TEXT("\\ProgID"));
|
||
|
TCHAR szValue[MAX_PATH+40];
|
||
|
LONG dwSize = ARRAYSIZE(szValue);
|
||
|
if (RegQueryValue(HKEY_CLASSES_ROOT, szKey, szValue, &dwSize) == ERROR_SUCCESS)
|
||
|
{
|
||
|
hres = _GetDefaultIcon(szValue, szIconFile, cchMax, piIndex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::Extract(
|
||
|
LPCTSTR pszFile, UINT nIconIndex,
|
||
|
HICON *phiconLarge, HICON *phiconSmall,
|
||
|
UINT nIconSize)
|
||
|
{
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::Create(REFCLSID rclsid, REFIID riid, LPVOID* ppvOut)
|
||
|
{
|
||
|
CTemplateUIObj *pti = new CTemplateUIObj(rclsid);
|
||
|
HRESULT hres;
|
||
|
if (pti) {
|
||
|
hres = pti->QueryInterface(riid, ppvOut);
|
||
|
pti->Release();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
*ppvOut=NULL;
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
//==========================================================================
|
||
|
// CTemplateUIObj members (IDataObject override)
|
||
|
//==========================================================================
|
||
|
|
||
|
HRESULT CTemplateUIObj::_CreateInstance(IStorage* pstg)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
IPersistStorage* pps = NULL;
|
||
|
hres = OleCreate(_clsid, IID_IPersistStorage, OLERENDER_DRAW,
|
||
|
NULL, NULL, pstg, (LPVOID*)&pps);
|
||
|
DebugMsg(DM_TRACE, TEXT("so TR - TUO:CI OleCreate returned (%x)"), hres);
|
||
|
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = OleSave(pps, pstg, TRUE);
|
||
|
DebugMsg(DM_TRACE, TEXT("so TR - TUO:CI OleSave returned (%x)"), hres);
|
||
|
pps->HandsOffStorage();
|
||
|
pps->Release();
|
||
|
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = pstg->Commit(STGC_OVERWRITE);
|
||
|
DebugMsg(DM_TRACE, TEXT("so TR - TUO:CI pstg->Commit returned (%x)"), hres);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
|
||
|
{
|
||
|
HRESULT hres = DATA_E_FORMATETC;
|
||
|
|
||
|
pmedium->pUnkForRelease = NULL;
|
||
|
pmedium->pstg = NULL;
|
||
|
|
||
|
//
|
||
|
// NOTES: We should avoid calling _OpenStorage if we don't support
|
||
|
// the format.
|
||
|
//
|
||
|
|
||
|
if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
|
||
|
&& pformatetcIn->tymed == TYMED_ISTORAGE)
|
||
|
{
|
||
|
IStorage* pstg = NULL;
|
||
|
hres = StgCreateDocfile(NULL, STGM_DIRECT | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pstg);
|
||
|
DebugMsg(DM_TRACE, TEXT("so TR - TUO:GD StgCreateDocfile returned (%x)"), hres);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = _CreateInstance(pstg);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
pmedium->tymed = TYMED_ISTORAGE;
|
||
|
pmedium->pstg = pstg;
|
||
|
} else {
|
||
|
pstg->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR
|
||
|
&& pformatetcIn->tymed == TYMED_HGLOBAL)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, TEXT("so TR - TUO:GD cfFormat==CF_OBJECTDESCRIPTOR"));
|
||
|
|
||
|
static WCHAR szUserTypeName[] = L"Foo"; // REARCHITECT: this code is really miss, and might end up returning Foo
|
||
|
static WCHAR szSrcOfCopy[] = L"Bar";
|
||
|
UINT cbUserTypeName = sizeof(szUserTypeName);
|
||
|
UINT cbSrcOfCopy = sizeof(szSrcOfCopy);
|
||
|
pmedium->hGlobal = GlobalAlloc(GPTR, sizeof(OBJECTDESCRIPTOR)+cbUserTypeName+cbSrcOfCopy);
|
||
|
if (pmedium->hGlobal)
|
||
|
{
|
||
|
OBJECTDESCRIPTOR* podsc = (OBJECTDESCRIPTOR*)pmedium->hGlobal;
|
||
|
podsc->cbSize = sizeof(OBJECTDESCRIPTOR);
|
||
|
podsc->clsid = _clsid;
|
||
|
podsc->dwDrawAspect = 0; // The source does not draw the object
|
||
|
// podsc->sizel = { 0, 0 }; // The source does not draw the object
|
||
|
// podsc->pointl = { 0, 0 };
|
||
|
podsc->dwStatus = 0; // FEATURE: read it from registry! CLSID/MiscStatus
|
||
|
podsc->dwFullUserTypeName = sizeof(OBJECTDESCRIPTOR);
|
||
|
podsc->dwSrcOfCopy = sizeof(OBJECTDESCRIPTOR)+cbUserTypeName;
|
||
|
LPBYTE pbT = (LPBYTE)(podsc+1);
|
||
|
lstrcpyW((LPWSTR)pbT, szUserTypeName);
|
||
|
lstrcpyW((LPWSTR)(pbT+cbUserTypeName), szSrcOfCopy);
|
||
|
Assert(pbT == ((LPBYTE)podsc)+podsc->dwFullUserTypeName);
|
||
|
Assert(pbT+cbUserTypeName == ((LPBYTE)podsc)+podsc->dwSrcOfCopy);
|
||
|
|
||
|
pmedium->tymed = TYMED_HGLOBAL;
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::GetDataHere(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
|
||
|
{
|
||
|
HRESULT hres = DATA_E_FORMATETC;
|
||
|
|
||
|
if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
|
||
|
&& pformatetcIn->tymed == TYMED_ISTORAGE && pmedium->tymed == TYMED_ISTORAGE)
|
||
|
{
|
||
|
hres = _CreateInstance(pmedium->pstg);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::QueryGetData(LPFORMATETC pformatetcIn)
|
||
|
{
|
||
|
if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
|
||
|
&& pformatetcIn->tymed == TYMED_ISTORAGE)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR
|
||
|
&& pformatetcIn->tymed == TYMED_HGLOBAL)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
return DATA_E_FORMATETC;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::GetCanonicalFormatEtc(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
|
||
|
{
|
||
|
//
|
||
|
// This is the simplest implemtation. It means we always return
|
||
|
// the data in the format requested.
|
||
|
//
|
||
|
return ResultFromScode(DATA_S_SAMEFORMATETC);
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::SetData(LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC * ppenumFormatEtc)
|
||
|
{
|
||
|
static FORMATETC s_afmt[] = { { (CLIPFORMAT)CF_EMBEDDEDOBJECT }, {(CLIPFORMAT)CF_OBJECTDESCRIPTOR} };
|
||
|
return SHCreateStdEnumFmtEtc(ARRAYSIZE(s_afmt), s_afmt, ppenumFormatEtc);
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::DAdvise(FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection)
|
||
|
{
|
||
|
return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::DUnadvise(DWORD dwConnection)
|
||
|
{
|
||
|
return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::EnumDAdvise(LPENUMSTATDATA * ppenumAdvise)
|
||
|
{
|
||
|
return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
|
||
|
}
|
||
|
|
||
|
#define TIDC_INVALID -1
|
||
|
#define TIDC_COPY 0
|
||
|
#define TIDC_MAX 1
|
||
|
|
||
|
HRESULT CTemplateUIObj::QueryContextMenu(
|
||
|
HMENU hmenu,
|
||
|
UINT indexMenu,
|
||
|
UINT idCmdFirst,
|
||
|
UINT idCmdLast,
|
||
|
UINT uFlags)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, TEXT("sc TR - CTUI::QCM called (uFlags=%x)"), uFlags);
|
||
|
|
||
|
//
|
||
|
// REVIEW: Checking CMF_DVFILE is subtle, need to be documented clearly!
|
||
|
//
|
||
|
if (!(uFlags & (CMF_VERBSONLY|CMF_DVFILE)))
|
||
|
{
|
||
|
MENUITEMINFO mii = {
|
||
|
sizeof(MENUITEMINFO),
|
||
|
MIIM_STATE|MIIM_ID|MIIM_TYPE,
|
||
|
MFT_STRING,
|
||
|
MFS_DEFAULT,
|
||
|
idCmdFirst+TIDC_COPY,
|
||
|
NULL, NULL, NULL, 0,
|
||
|
TEXT("&Copy"), // FEATURE: Support NLS, the Copy operation might have a different name in other languages
|
||
|
5
|
||
|
};
|
||
|
InsertMenuItem(hmenu, indexMenu++, TRUE, &mii);
|
||
|
}
|
||
|
return ResultFromShort(TIDC_MAX);
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::InvokeCommand(
|
||
|
LPCMINVOKECOMMANDINFO lpici)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
DebugMsg(DM_TRACE, TEXT("sc TR - CTUI::IC called (%x)"), lpici->lpVerb);
|
||
|
int idCmd = TIDC_INVALID;
|
||
|
|
||
|
if (HIWORD(lpici->lpVerb))
|
||
|
{
|
||
|
if (lstrcmpiA(lpici->lpVerb, "copy") == 0) {
|
||
|
idCmd = TIDC_COPY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
idCmd = LOWORD(lpici->lpVerb);
|
||
|
}
|
||
|
|
||
|
switch(idCmd)
|
||
|
{
|
||
|
case TIDC_COPY:
|
||
|
hres = OleSetClipboard(this);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
hres = E_INVALIDARG;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CTemplateUIObj::GetCommandString(
|
||
|
UINT idCmd,
|
||
|
UINT uType,
|
||
|
UINT * pwReserved,
|
||
|
LPSTR pszName,
|
||
|
UINT cchMax)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, TEXT("sc TR - CTUI::GCS called (%d, %x)"), idCmd, uType);
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
#endif // FEATURE_SHELLEXTENSION
|