1023 lines
29 KiB
C
1023 lines
29 KiB
C
#include "shole.h"
|
|
#include "ids.h"
|
|
|
|
#define INITGUID
|
|
#ifndef WINNT
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
#include <initguid.h>
|
|
#include "scguid.h"
|
|
#ifndef WINNT
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
// #define SAVE_OBJECTDESCRIPTOR
|
|
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
extern "C" const WCHAR c_wszDescriptor[];
|
|
|
|
UINT _GetClipboardFormat(UINT id)
|
|
{
|
|
static UINT s_acf[CFID_MAX] = { 0, 0, 0, 0, 0 };
|
|
static const TCHAR * const c_aszFormat[CFID_MAX] = {
|
|
TEXT("Embedded Object"),
|
|
TEXT("Object Descriptor"),
|
|
TEXT("Link Source Descriptor"),
|
|
TEXT("Rich Text Format"),
|
|
TEXT("Shell Scrap Object")
|
|
};
|
|
if (!s_acf[id])
|
|
{
|
|
s_acf[id] = RegisterClipboardFormat(c_aszFormat[id]);
|
|
}
|
|
return s_acf[id];
|
|
}
|
|
|
|
|
|
// CScrapData : Class definition
|
|
|
|
|
|
class CScrapData : public IDataObject, public IPersistFile
|
|
{
|
|
public:
|
|
CScrapData();
|
|
~CScrapData();
|
|
|
|
// IUnKnown
|
|
virtual HRESULT __stdcall QueryInterface(REFIID,void **);
|
|
virtual ULONG __stdcall AddRef(void);
|
|
virtual ULONG __stdcall Release(void);
|
|
|
|
// 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);
|
|
virtual HRESULT __stdcall IsDirty(void);
|
|
|
|
// IPersistFile
|
|
virtual HRESULT __stdcall GetClassID(CLSID *pClassID);
|
|
virtual HRESULT __stdcall Load(LPCOLESTR pszFileName, DWORD dwMode);
|
|
virtual HRESULT __stdcall Save(LPCOLESTR pszFileName, BOOL fRemember);
|
|
virtual HRESULT __stdcall SaveCompleted(LPCOLESTR pszFileName);
|
|
virtual HRESULT __stdcall GetCurFile(LPOLESTR *ppszFileName);
|
|
|
|
protected:
|
|
HRESULT _OpenStorage(void);
|
|
void _CloseStorage(BOOL fResetFlags);
|
|
INT _GetFormatIndex(UINT cf);
|
|
void _FillCFArray(void);
|
|
#ifdef FIX_ROUNDTRIP
|
|
HRESULT _RunObject(void);
|
|
#endif // FIX_ROUNDTRIP
|
|
|
|
#ifdef SAVE_OBJECTDESCRIPTOR
|
|
HRESULT _GetObjectDescriptor(LPSTGMEDIUM pmedium, BOOL fGetHere);
|
|
#endif // SAVE_OBJECTDESCRIPTOR
|
|
|
|
UINT _cRef;
|
|
BOOL _fDoc:1;
|
|
BOOL _fItem:1;
|
|
BOOL _fObjDesc:1;
|
|
#ifdef FIX_ROUNDTRIP
|
|
BOOL _fRunObjectAlreadyCalled:1;
|
|
LPDATAOBJECT _pdtobjItem;
|
|
#endif // FIX_ROUNDTRIP
|
|
LPSTORAGE _pstgDoc;
|
|
LPSTORAGE _pstgItem;
|
|
LPSTREAM _pstmObjDesc;
|
|
TCHAR _szPath[MAX_PATH];
|
|
INT _ccf; // number of clipboard format.
|
|
INT _icfCacheMax; // Max cache format index
|
|
DWORD _acf[64]; // 64 must be enough!
|
|
};
|
|
|
|
|
|
// CScrapData : Constructor
|
|
|
|
CScrapData::CScrapData(void) : _cRef(1), _pstgDoc(NULL), _pstgItem(NULL),
|
|
_fDoc(FALSE), _fItem(FALSE), _fObjDesc(FALSE),
|
|
_ccf(0),
|
|
#ifdef FIX_ROUNDTRIP
|
|
_pdtobjItem(NULL), _fRunObjectAlreadyCalled(FALSE),
|
|
#endif // FIX_ROUNDTRIP
|
|
_pstmObjDesc(NULL)
|
|
{
|
|
_szPath[0] = TEXT('\0');
|
|
g_cRefThisDll++;
|
|
}
|
|
|
|
CScrapData::~CScrapData()
|
|
{
|
|
#ifdef FIX_ROUNDTRIP
|
|
if (_pdtobjItem) {
|
|
_pdtobjItem->Release();
|
|
}
|
|
#endif // FIX_ROUNDTRIP
|
|
_CloseStorage(FALSE);
|
|
g_cRefThisDll--;
|
|
}
|
|
|
|
// CScrapData : Member functions (private)
|
|
|
|
|
|
// private member CScrapData::_OpenStorage
|
|
|
|
HRESULT CScrapData::_OpenStorage(void)
|
|
{
|
|
if (_pstgItem) {
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT hres;
|
|
WCHAR wszFile[MAX_PATH];
|
|
|
|
#ifdef UNICODE
|
|
lstrcpyn(wszFile, _szPath, ARRAYSIZE(wszFile));
|
|
#ifdef DEBUG
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetStorage is called (%s)"), wszFile);
|
|
#endif
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, _szPath, -1, wszFile, ARRAYSIZE(wszFile));
|
|
|
|
#ifdef DEBUG
|
|
TCHAR szFile[MAX_PATH];
|
|
WideCharToMultiByte(CP_ACP, 0, wszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetStorage is called (%s)"), szFile);
|
|
#endif
|
|
#endif
|
|
|
|
hres = StgOpenStorage(wszFile, NULL,
|
|
STGM_READ | STGM_SHARE_DENY_WRITE,
|
|
NULL, 0, &_pstgDoc);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
_fDoc = TRUE;
|
|
hres = _pstgDoc->OpenStorage(c_wszContents, NULL,
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
NULL, 0, &_pstgItem);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
HRESULT hresT;
|
|
_fItem = TRUE;
|
|
#ifdef SAVE_OBJECTDESCRIPTOR
|
|
hresT = _pstgDoc->OpenStream(c_wszDescriptor, 0,
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
0, &_pstmObjDesc);
|
|
_fObjDesc = SUCCEEDED(hresT);
|
|
#endif // SAVE_OBJECTDESCRIPTOR
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage _pstgDoc->OpenStorage failed (%x)"), hres);
|
|
_pstgDoc->Release();
|
|
_pstgDoc = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage StgOpenStorage failed (%x)"), hres);
|
|
}
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage _pstgDoc->OpenStorage returning (%x) %x"),
|
|
hres, _pstmObjDesc);
|
|
return hres;
|
|
}
|
|
|
|
void CScrapData::_CloseStorage(BOOL fResetFlags)
|
|
{
|
|
if (_pstgItem) {
|
|
_pstgItem->Release();
|
|
_pstgItem = NULL;
|
|
}
|
|
if (_pstmObjDesc) {
|
|
_pstmObjDesc->Release();
|
|
_pstmObjDesc = NULL;
|
|
}
|
|
if (_pstgDoc) {
|
|
_pstgDoc->Release();
|
|
_pstgDoc = NULL;
|
|
}
|
|
|
|
if (fResetFlags) {
|
|
_fItem = FALSE;
|
|
_fObjDesc = FALSE;
|
|
_fDoc = FALSE;
|
|
}
|
|
}
|
|
|
|
INT CScrapData::_GetFormatIndex(UINT cf)
|
|
{
|
|
for (INT i=0; i<_ccf; i++)
|
|
{
|
|
if (_acf[i] == cf)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#ifdef FIX_ROUNDTRIP
|
|
extern "C" const TCHAR c_szRenderFMT[] = TEXT("DataFormats\\DelayRenderFormats");
|
|
#endif // FIX_ROUNDTRIP
|
|
|
|
extern "C" const WCHAR c_wszFormatNames[];
|
|
|
|
|
|
// This function filles the clipboard format array (_acf). Following
|
|
// clipboard format may be added.
|
|
|
|
// Step 1. CF_EMBEEDEDOBJECT
|
|
// Step 2. CF_OBJECTDESCRIPTOR
|
|
// Step 3. CF_SCRAPOBJECT
|
|
// Step 4. Cached clipboard formats (from a stream).
|
|
// Step 5. Delay Rendered clipbaord formats (from registry).
|
|
|
|
void CScrapData::_FillCFArray(void)
|
|
{
|
|
_ccf=0;
|
|
|
|
// Step 1.
|
|
|
|
if (_fItem) {
|
|
_acf[_ccf++] = CF_EMBEDDEDOBJECT;
|
|
}
|
|
|
|
|
|
// Step 2.
|
|
|
|
if (_fObjDesc) {
|
|
_acf[_ccf++] = CF_OBJECTDESCRIPTOR;
|
|
}
|
|
|
|
|
|
// Step 3.
|
|
|
|
if (_fDoc)
|
|
{
|
|
_acf[_ccf++] = CF_SCRAPOBJECT;
|
|
}
|
|
|
|
#ifdef FIX_ROUNDTRIP
|
|
if (_pstgItem)
|
|
{
|
|
|
|
// Step 3. Cached clipboard formats
|
|
|
|
|
|
// Open the stream which contains the names of cached formats.
|
|
|
|
LPSTREAM pstm;
|
|
HRESULT hres = _pstgDoc->OpenStream(c_wszFormatNames, NULL,
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
NULL, &pstm);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
|
|
// For each cached format...
|
|
|
|
USHORT cb;
|
|
DWORD cbRead;
|
|
while(SUCCEEDED(pstm->Read(&cb, sizeof(cb), &cbRead)) && cbRead==sizeof(cb)
|
|
&& cb && cb<128)
|
|
{
|
|
UINT cf = 0;
|
|
|
|
|
|
// Get the cached clipboard format name
|
|
|
|
CHAR szFormat[128];
|
|
szFormat[cb] = '\0';
|
|
hres = pstm->Read(szFormat, cb, &cbRead);
|
|
if (SUCCEEDED(hres) && cbRead==cb && lstrlenA(szFormat)==cb)
|
|
{
|
|
|
|
// Append it to the array.
|
|
|
|
#ifdef UNICODE
|
|
TCHAR wszFormat[128];
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
szFormat, -1,
|
|
wszFormat, ARRAYSIZE(wszFormat));
|
|
DebugMsg(DM_TRACE, TEXT("sc TR _FillCFA Found Cached Format %s"), wszFormat);
|
|
#else
|
|
DebugMsg(DM_TRACE, TEXT("sc TR _FillCFA Found Cached Format %s"), szFormat);
|
|
#endif
|
|
cf = RegisterClipboardFormatA(szFormat);
|
|
|
|
if (cf)
|
|
{
|
|
_acf[_ccf++] = cf;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
pstm->Release();
|
|
}
|
|
|
|
_icfCacheMax = _ccf;
|
|
|
|
|
|
// Step 4. Get the list of delay-rendered clipboard formats
|
|
|
|
LPPERSISTSTORAGE pps;
|
|
hres = OleLoad(_pstgItem, IID_IPersistStorage, NULL, (LPVOID *)&pps);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
|
|
// Get the CLSID of embedding.
|
|
|
|
CLSID clsid;
|
|
hres = pps->GetClassID(&clsid);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
|
|
// Open the key for delay-rendered format names.
|
|
|
|
extern HKEY _OpenCLSIDKey(REFCLSID rclsid, LPCTSTR pszSubKey);
|
|
HKEY hkey = _OpenCLSIDKey(clsid, c_szRenderFMT);
|
|
if (hkey)
|
|
{
|
|
TCHAR szValueName[128];
|
|
|
|
// For each delay-rendered clipboard format...
|
|
|
|
for(int iValue=0; ;iValue++)
|
|
{
|
|
|
|
// Get the value name, which is the format name.
|
|
|
|
DWORD cchValueName = ARRAYSIZE(szValueName);
|
|
DWORD dwType;
|
|
if (RegEnumValue(hkey, iValue, szValueName, &cchValueName, NULL,
|
|
&dwType, NULL, NULL)==ERROR_SUCCESS)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_FillCFA RegEnumValue found %s, %x"), szValueName, dwType);
|
|
UINT cf = RegisterClipboardFormat(szValueName);
|
|
|
|
if (cf)
|
|
{
|
|
_acf[_ccf++] = cf;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// HACK: NT 3.5's regedit does not support named value...
|
|
|
|
for(iValue=0; ;iValue++)
|
|
{
|
|
TCHAR szKeyName[128];
|
|
|
|
// Get the value name, which is the format name.
|
|
|
|
if (RegEnumKey(hkey, iValue, szKeyName, ARRAYSIZE(szKeyName))==ERROR_SUCCESS)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_FillCFA RegEnumValue found %s"), szValueName);
|
|
LONG cbValue = ARRAYSIZE(szValueName);
|
|
if ((RegQueryValue(hkey, szKeyName, szValueName, &cbValue)==ERROR_SUCCESS) && cbValue)
|
|
{
|
|
UINT cf = RegisterClipboardFormat(szValueName);
|
|
|
|
if (cf)
|
|
{
|
|
_acf[_ccf++] = cf;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
pps->Release();
|
|
}
|
|
}
|
|
#endif // FIX_ROUNDTRIP
|
|
}
|
|
|
|
#ifdef FIX_ROUNDTRIP
|
|
|
|
// private member CScrapData::_RunObject
|
|
|
|
HRESULT CScrapData::_RunObject(void)
|
|
{
|
|
if (_pdtobjItem) {
|
|
return S_OK;
|
|
}
|
|
|
|
if (_fRunObjectAlreadyCalled) {
|
|
DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject returning E_FAIL"));
|
|
return E_FAIL;
|
|
}
|
|
_fRunObjectAlreadyCalled = TRUE;
|
|
|
|
HRESULT hres = _OpenStorage();
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject _OpenStorage returned %x"), hres);
|
|
|
|
if (SUCCEEDED(hres) && _pstgItem)
|
|
{
|
|
LPOLEOBJECT pole;
|
|
hres = OleLoad(_pstgItem, IID_IOleObject, NULL, (LPVOID *)&pole);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject OleLoad returned %x"), hres);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
DWORD dw=GetCurrentTime();
|
|
hres = OleRun(pole);
|
|
dw = GetCurrentTime()-dw;
|
|
DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject OleRun returned %x (%d msec)"), hres, dw);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pole->GetClipboardData(0, &_pdtobjItem);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject GetClipboardData returned %x"), hres);
|
|
if (FAILED(hres))
|
|
{
|
|
hres = pole->QueryInterface(IID_IDataObject, (LPVOID*)&_pdtobjItem);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject QI(IID_IDataIbject) returned %x"), hres);
|
|
}
|
|
}
|
|
pole->Release();
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
#endif // FIX_ROUNDTRIP
|
|
|
|
|
|
// CScrapData : Member functions (virtual IDataObject)
|
|
|
|
HRESULT CScrapData::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IDataObject) || IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppvObj = (LPDATAOBJECT)this;
|
|
_cRef++;
|
|
return S_OK;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IPersistFile))
|
|
{
|
|
*ppvObj = (LPPERSISTFILE)this;
|
|
_cRef++;
|
|
return S_OK;
|
|
}
|
|
*ppvObj = NULL;
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG CScrapData::AddRef()
|
|
{
|
|
_cRef++;
|
|
return _cRef;
|
|
}
|
|
|
|
ULONG CScrapData::Release()
|
|
{
|
|
_cRef--;
|
|
if (_cRef > 0)
|
|
return _cRef;
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::Release deleting this object"));
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef SAVE_OBJECTDESCRIPTOR
|
|
HRESULT CScrapData::_GetObjectDescriptor(LPSTGMEDIUM pmedium, BOOL fGetHere)
|
|
{
|
|
if (!_pstmObjDesc)
|
|
return DATA_E_FORMATETC;
|
|
|
|
LARGE_INTEGER dlib = { 0, 0 };
|
|
HRESULT hres = _pstmObjDesc->Seek(dlib, STREAM_SEEK_SET, NULL);
|
|
if (FAILED(hres))
|
|
return hres;
|
|
|
|
OBJECTDESCRIPTOR ods;
|
|
ULONG cbRead;
|
|
hres = _pstmObjDesc->Read(&ods.cbSize, sizeof(ods.cbSize), &cbRead);
|
|
if (SUCCEEDED(hres) && cbRead == sizeof(ods.cbSize))
|
|
{
|
|
if (fGetHere)
|
|
{
|
|
if (GlobalSize(pmedium->hGlobal)<ods.cbSize) {
|
|
hres = STG_E_MEDIUMFULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pmedium->tymed = TYMED_HGLOBAL;
|
|
pmedium->hGlobal = GlobalAlloc(GMEM_MOVEABLE, ods.cbSize);
|
|
hres = pmedium->hGlobal ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
LPOBJECTDESCRIPTOR pods = (LPOBJECTDESCRIPTOR)GlobalLock(pmedium->hGlobal);
|
|
if (pods)
|
|
{
|
|
pods->cbSize = ods.cbSize;
|
|
hres = _pstmObjDesc->Read(&pods->clsid, ods.cbSize-sizeof(ods.cbSize), NULL);
|
|
GlobalUnlock(pmedium->hGlobal);
|
|
}
|
|
else
|
|
{
|
|
if (!fGetHere) {
|
|
GlobalFree(pmedium->hGlobal);
|
|
pmedium->hGlobal = NULL;
|
|
}
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_GetObjectDescriptor returning (%x)"), hres);
|
|
return hres;
|
|
}
|
|
#endif // SAVE_OBJECTDESCRIPTOR
|
|
|
|
|
|
HRESULT CScrapData::GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
|
|
{
|
|
#ifdef DEBUG
|
|
if (pformatetcIn->cfFormat<CF_MAX) {
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %x,%x,%x"),
|
|
pformatetcIn->cfFormat, pformatetcIn->tymed, pmedium->tymed);
|
|
} else {
|
|
TCHAR szName[256];
|
|
GetClipboardFormatName(pformatetcIn->cfFormat, szName, ARRAYSIZE(szName));
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %s,%x,%x"),
|
|
szName, pformatetcIn->tymed, pmedium->tymed);
|
|
}
|
|
#endif
|
|
|
|
HRESULT hres;
|
|
|
|
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 && _fItem)
|
|
{
|
|
hres = _OpenStorage();
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
pmedium->tymed = TYMED_ISTORAGE;
|
|
_pstgItem->AddRef();
|
|
pmedium->pstg = _pstgItem;
|
|
}
|
|
}
|
|
else if (pformatetcIn->cfFormat == CF_SCRAPOBJECT
|
|
&& pformatetcIn->tymed == TYMED_ISTORAGE && _fItem)
|
|
{
|
|
hres = _OpenStorage();
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
pmedium->tymed = TYMED_ISTORAGE;
|
|
_pstgDoc->AddRef();
|
|
pmedium->pstg = _pstgDoc;
|
|
}
|
|
}
|
|
#ifdef SAVE_OBJECTDESCRIPTOR
|
|
else if (pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR
|
|
&& pformatetcIn->tymed == TYMED_HGLOBAL && _fObjDesc)
|
|
{
|
|
hres = _OpenStorage();
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = _GetObjectDescriptor(pmedium, FALSE);
|
|
}
|
|
}
|
|
#endif // SAVE_OBJECTDESCRIPTOR
|
|
else
|
|
{
|
|
#ifdef FIX_ROUNDTRIP
|
|
INT iFmt = _GetFormatIndex(pformatetcIn->cfFormat);
|
|
|
|
if (iFmt != -1)
|
|
{
|
|
hres = _OpenStorage();
|
|
if (FAILED(hres))
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (iFmt>=_icfCacheMax)
|
|
{
|
|
|
|
// Delayed Rendered format
|
|
|
|
if (SUCCEEDED(_RunObject()))
|
|
{
|
|
hres = _pdtobjItem->GetData(pformatetcIn, pmedium);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called _pdtobjItem->GetData %x"), hres);
|
|
return hres;
|
|
}
|
|
}
|
|
else if (iFmt >= 0)
|
|
{
|
|
|
|
// Cached Format
|
|
|
|
extern void _GetCacheStreamName(LPCTSTR pszFormat, LPWSTR wszStreamName, UINT cchMax);
|
|
TCHAR szFormat[128];
|
|
if (pformatetcIn->cfFormat<CF_MAX) {
|
|
wsprintf(szFormat, TEXT("#%d"), pformatetcIn->cfFormat);
|
|
} else {
|
|
GetClipboardFormatName(pformatetcIn->cfFormat, szFormat, ARRAYSIZE(szFormat));
|
|
}
|
|
|
|
WCHAR wszStreamName[256];
|
|
_GetCacheStreamName(szFormat, wszStreamName, ARRAYSIZE(wszStreamName));
|
|
|
|
if (pformatetcIn->cfFormat==CF_METAFILEPICT
|
|
|| pformatetcIn->cfFormat==CF_ENHMETAFILE
|
|
|| pformatetcIn->cfFormat==CF_BITMAP
|
|
|| pformatetcIn->cfFormat==CF_PALETTE
|
|
)
|
|
{
|
|
LPSTORAGE pstg;
|
|
hres = _pstgDoc->OpenStorage(wszStreamName, NULL,
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
NULL, 0, &pstg);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData OpenStorage returned (%x)"), hres);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
LPDATAOBJECT pdtobj;
|
|
#if 0
|
|
hres = OleLoad(pstg, IID_IDataObject, NULL, (LPVOID*)&pdtobj);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData OleLoad returned (%x)"), hres);
|
|
#else
|
|
const CLSID* pclsid = NULL;
|
|
switch(pformatetcIn->cfFormat)
|
|
{
|
|
case CF_METAFILEPICT:
|
|
pclsid = &CLSID_Picture_Metafile;
|
|
break;
|
|
|
|
case CF_ENHMETAFILE:
|
|
pclsid = &CLSID_Picture_EnhMetafile;
|
|
break;
|
|
|
|
case CF_PALETTE:
|
|
case CF_BITMAP:
|
|
pclsid = &CLSID_Picture_Dib;
|
|
break;
|
|
}
|
|
|
|
LPPERSISTSTORAGE ppstg;
|
|
hres = OleCreateDefaultHandler(*pclsid, NULL, IID_IPersistStorage, (LPVOID *)&ppstg);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR Scrap_CacheOPF OleCreteDefHandler returned %x"), hres);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = ppstg->Load(pstg);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR Scrap_CacheOPF ppstg->Load returned %x"), hres);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = ppstg->QueryInterface(IID_IDataObject, (LPVOID*)&pdtobj);
|
|
}
|
|
ppstg->HandsOffStorage();
|
|
ppstg->Release();
|
|
}
|
|
#endif
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pdtobj->GetData(pformatetcIn, pmedium);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData pobj->GetData returned (%x)"), hres);
|
|
pdtobj->Release();
|
|
}
|
|
pstg->Release();
|
|
return hres;
|
|
}
|
|
// fall through
|
|
}
|
|
else // if (pformatetcIn->cfFormat==CF_...)
|
|
{
|
|
LPSTREAM pstm;
|
|
hres = _pstgDoc->OpenStream(wszStreamName, NULL,
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
0, &pstm);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
UINT cbData;
|
|
DWORD cbRead;
|
|
hres = pstm->Read(&cbData, sizeof(cbData), &cbRead);
|
|
if (SUCCEEDED(hres) && cbRead==sizeof(cbData))
|
|
{
|
|
LPBYTE pData = (LPBYTE)GlobalAlloc(GPTR, cbData);
|
|
if (pData)
|
|
{
|
|
hres = pstm->Read(pData, cbData, &cbRead);
|
|
if (SUCCEEDED(hres) && cbData==cbRead)
|
|
{
|
|
pmedium->tymed = TYMED_HGLOBAL;
|
|
pmedium->hGlobal = (HGLOBAL)pData;
|
|
}
|
|
else
|
|
{
|
|
hres = E_UNEXPECTED;
|
|
GlobalFree((HGLOBAL)pData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
pstm->Release();
|
|
|
|
DebugMsg(DM_TRACE, TEXT("CSD::GetData(%s) returning %x"), szFormat, hres);
|
|
return hres;
|
|
}
|
|
}
|
|
} // if (iFmt >= 0)
|
|
#endif // FIX_ROUNDTRIP
|
|
hres = DATA_E_FORMATETC;
|
|
}
|
|
|
|
exit:
|
|
|
|
#ifdef DEBUG
|
|
TCHAR szFormat[256];
|
|
GetClipboardFormatName(pformatetcIn->cfFormat,
|
|
szFormat, ARRAYSIZE(szFormat));
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %x,%x,%s and returning %x"),
|
|
pformatetcIn->cfFormat,
|
|
pformatetcIn->tymed,
|
|
szFormat, hres);
|
|
#endif
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CScrapData::GetDataHere(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium )
|
|
{
|
|
HRESULT hres;
|
|
|
|
#ifdef DEBUG
|
|
if (pformatetcIn->cfFormat<CF_MAX) {
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere called with %x,%x,%x"),
|
|
pformatetcIn->cfFormat, pformatetcIn->tymed, pmedium->tymed);
|
|
} else {
|
|
TCHAR szName[256];
|
|
GetClipboardFormatName(pformatetcIn->cfFormat, szName, ARRAYSIZE(szName));
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere called with %s,%x,%x"),
|
|
szName, pformatetcIn->tymed, pmedium->tymed);
|
|
}
|
|
#endif
|
|
|
|
hres = _OpenStorage();
|
|
if (FAILED(hres)) {
|
|
return hres;
|
|
}
|
|
|
|
if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
|
|
&& pformatetcIn->tymed == TYMED_ISTORAGE && pmedium->tymed == TYMED_ISTORAGE)
|
|
{
|
|
hres = _pstgItem->CopyTo(0, NULL, NULL, pmedium->pstg);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere _pstgItem->CopyTo returned %x"), hres);
|
|
}
|
|
else if (pformatetcIn->cfFormat == CF_SCRAPOBJECT
|
|
&& pformatetcIn->tymed == TYMED_ISTORAGE && pmedium->tymed == TYMED_ISTORAGE)
|
|
{
|
|
hres = _pstgDoc->CopyTo(0, NULL, NULL, pmedium->pstg);
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere _pstgItem->CopyTo returned %x"), hres);
|
|
}
|
|
#ifdef SAVE_OBJECTDESCRIPTOR
|
|
else if ((pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR)
|
|
&& (pformatetcIn->tymed == TYMED_HGLOBAL) && _pstmObjDesc)
|
|
{
|
|
hres = _GetObjectDescriptor(pmedium, TRUE);
|
|
}
|
|
#endif // SAVE_OBJECTDESCRIPTOR
|
|
else
|
|
{
|
|
#ifdef FIX_ROUNDTRIP
|
|
if (_GetFormatIndex(pformatetcIn->cfFormat) >= 0 && SUCCEEDED(_RunObject()))
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere calling _pdtobjItem->GetDataHere"));
|
|
return _pdtobjItem->GetDataHere(pformatetcIn, pmedium);
|
|
}
|
|
#endif // FIX_ROUNDTRIP
|
|
hres = DATA_E_FORMATETC;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CScrapData::QueryGetData(LPFORMATETC pformatetcIn)
|
|
{
|
|
HRESULT hres;
|
|
if (_GetFormatIndex(pformatetcIn->cfFormat) >= 0) {
|
|
hres = S_OK;
|
|
} else {
|
|
hres = DATA_E_FORMATETC;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
TCHAR szFormat[256] = TEXT("");
|
|
GetClipboardFormatName(pformatetcIn->cfFormat, szFormat, ARRAYSIZE(szFormat));
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSD::QueryGetData(%x,%s,%x) returning %x"),
|
|
pformatetcIn->cfFormat, szFormat, pformatetcIn->tymed, hres);
|
|
#endif
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CScrapData::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 CScrapData::SetData(LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CScrapData::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC * ppenumFormatEtc)
|
|
{
|
|
if (dwDirection!=DATADIR_GET) {
|
|
return E_NOTIMPL; // Not supported (as documented)
|
|
}
|
|
|
|
if (_ccf==0) {
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
FORMATETC * pfmt = (FORMATETC*)LocalAlloc(LPTR, sizeof(FORMATETC)*_ccf);
|
|
if (!pfmt) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
static const FORMATETC s_fmteInit =
|
|
{
|
|
0,
|
|
(DVTARGETDEVICE __RPC_FAR *)NULL,
|
|
DVASPECT_CONTENT,
|
|
-1,
|
|
TYMED_HGLOBAL // HGLOBAL except CF_EMBEDDEDOBJECT/SCRAPOBJECT
|
|
};
|
|
|
|
|
|
// Fills FORMATETC for each clipboard format.
|
|
|
|
for (INT i=0; i<_ccf; i++)
|
|
{
|
|
pfmt[i] = s_fmteInit;
|
|
pfmt[i].cfFormat = (CLIPFORMAT)_acf[i];
|
|
|
|
if (_acf[i]==CF_EMBEDDEDOBJECT || _acf[i]==CF_SCRAPOBJECT) {
|
|
pfmt[i].tymed = TYMED_ISTORAGE;
|
|
} else {
|
|
switch(_acf[i])
|
|
{
|
|
case CF_METAFILEPICT:
|
|
pfmt[i].tymed = TYMED_MFPICT;
|
|
break;
|
|
|
|
case CF_ENHMETAFILE:
|
|
pfmt[i].tymed = TYMED_ENHMF;
|
|
break;
|
|
|
|
case CF_BITMAP:
|
|
case CF_PALETTE:
|
|
pfmt[i].tymed = TYMED_GDI;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT hres = SHCreateStdEnumFmtEtc(_ccf, pfmt, ppenumFormatEtc);
|
|
LocalFree((HLOCAL)pfmt);
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CScrapData::DAdvise(FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection)
|
|
{
|
|
return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
|
|
}
|
|
|
|
HRESULT CScrapData::DUnadvise(DWORD dwConnection)
|
|
{
|
|
return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
|
|
}
|
|
|
|
HRESULT CScrapData::EnumDAdvise(LPENUMSTATDATA * ppenumAdvise)
|
|
{
|
|
return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
|
|
}
|
|
|
|
|
|
|
|
// CScrapData : Member functions (virtual IPersistFile)
|
|
|
|
|
|
HRESULT CScrapData::GetClassID(LPCLSID lpClassID)
|
|
{
|
|
*lpClassID = CLSID_CScrapData;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CScrapData::IsDirty(void)
|
|
{
|
|
return S_FALSE; // meaningless (read only)
|
|
}
|
|
|
|
HRESULT CScrapData::Load(LPCOLESTR pwszFile, DWORD grfMode)
|
|
{
|
|
|
|
// Close all the storage (if there is any) and reset flags.
|
|
|
|
_CloseStorage(TRUE);
|
|
|
|
|
|
// Copy the new file name and open storage to update the flags.
|
|
|
|
#ifdef UNICODE
|
|
lstrcpyn(_szPath, pwszFile, ARRAYSIZE(_szPath));
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, pwszFile, -1, _szPath, ARRAYSIZE(_szPath), NULL, NULL);
|
|
#endif
|
|
HRESULT hres = _OpenStorage();
|
|
_FillCFArray();
|
|
|
|
|
|
// Close all the storage, so that we can move/delete.
|
|
|
|
_CloseStorage(FALSE);
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CScrapData::Save(LPCOLESTR pwszFile, BOOL fRemember)
|
|
{
|
|
return E_FAIL; // read only
|
|
}
|
|
|
|
HRESULT CScrapData::SaveCompleted(LPCOLESTR pwszFile)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CScrapData::GetCurFile(LPOLESTR *lplpszFileName)
|
|
{
|
|
return E_NOTIMPL; // nobody needs it
|
|
}
|
|
|
|
HRESULT CScrapData_CreateInstance(LPUNKNOWN * ppunk)
|
|
{
|
|
|
|
// This test code is unrelated to the scrap itself. It just verifies that
|
|
// CLSID_ShellLink is correctly registered.
|
|
|
|
#ifdef DEBUG
|
|
LPUNKNOWN punk = NULL;
|
|
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC, IID_IShellLink, (LPVOID*)&punk);
|
|
DebugMsg(DM_TRACE, TEXT("###############################################"));
|
|
DebugMsg(DM_TRACE, TEXT("CoCreateInstance returned %x"), hres);
|
|
DebugMsg(DM_TRACE, TEXT("###############################################"));
|
|
if (SUCCEEDED(hres)) {
|
|
punk->Release();
|
|
}
|
|
#endif
|
|
|
|
CScrapData* pscd = new CScrapData();
|
|
if (pscd) {
|
|
*ppunk = (LPDATAOBJECT)pscd;
|
|
return S_OK;
|
|
}
|
|
return E_OUTOFMEMORY;
|
|
}
|