windows-nt/Source/XPSP1/NT/shell/ext/shscrap/template.cpp
2020-09-26 16:20:57 +08:00

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