#include "shole.h" #include "ids.h" #define INITGUID #include #include "scguid.h" #include // #define SAVE_OBJECTDESCRIPTOR extern "C" const WCHAR c_wszDescriptor[]; CLIPFORMAT _GetClipboardFormat(UINT id) { static UINT s_acf[CFID_MAX] = { 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"), TEXT("TargetCLSID"), TEXT("Rich Text Format"), }; if (!s_acf[id]) { s_acf[id] = RegisterClipboardFormat(c_aszFormat[id]); } return (CLIPFORMAT)s_acf[id]; } //=========================================================================== // CScrapData : Class definition //=========================================================================== class CScrapData : public IDataObject, public IPersistFile #ifdef FEATURE_SHELLEXTENSION , public IExtractIcon #ifdef UNICODE , public IExtractIconA #endif // UNICODE #endif // FEATURE_SHELLEXTENSION { 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); #ifdef FEATURE_SHELLEXTENSION // IExtractIcon 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); #ifdef UNICODE // IExtractIconA virtual HRESULT __stdcall GetIconLocation( UINT uFlags, LPSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags); virtual HRESULT __stdcall Extract( LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); #endif // UNICODE #endif // FEATURE_SHELLEXTENSION // 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; BOOL _fClsidTarget:1; #ifdef FIX_ROUNDTRIP BOOL _fRunObjectAlreadyCalled:1; LPDATAOBJECT _pdtobjItem; #endif // FIX_ROUNDTRIP LPSTORAGE _pstgDoc; LPSTORAGE _pstgItem; LPSTREAM _pstmObjDesc; TCHAR _szPath[MAX_PATH]; CLSID _clsidTarget; 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) { ASSERT(_pstgDoc == NULL); ASSERT(_pstgItem == NULL); ASSERT(_fDoc == FALSE); ASSERT(_fItem == FALSE); ASSERT(_fObjDesc == FALSE); ASSERT(_ccf == 0); ASSERT(_fClsidTarget == FALSE); #ifdef FIX_ROUNDTRIP ASSERT(_pdtobjItem == NULL); ASSERT(_fRunObjectAlreadyCalled == FALSE); #endif // FIX_ROUNDTRIP ASSERT(_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]; hres = StringCchCopy(wszFile, ARRAYSIZE(wszFile), _szPath); #ifdef DEBUG DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetStorage is called (%s)"), wszFile); #endif if (SUCCEEDED(hres)) { 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) { #ifdef DEBUG DebugMsg(DM_TRACE, TEXT("sc TR - CSD::CloseStorage")); #endif 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 HRESULT hres = _OpenStorage(); if (SUCCEEDED(hres) && _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. // TCHAR wszFormat[128]; MultiByteToWideChar(CP_ACP, 0, szFormat, -1, wszFormat, ARRAYSIZE(wszFormat)); DebugMsg(DM_TRACE, TEXT("sc TR _FillCFA Found Cached Format %s"), wszFormat); 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_IExtractIcon)) { *ppvObj = (IExtractIcon*)this; _cRef++; return S_OK; } #ifdef UNICODE else if (IsEqualIID(riid, IID_IExtractIconA)) { *ppvObj = (IExtractIconA*)this; _cRef++; return S_OK; } #endif 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)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->cfFormatcfFormat, 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. // // // APP COMPAT! Win95/NT4's shscrap.dll had a bug in that it checked // the pformatetcIn->tymed's wrong. The old scrap code accidentally // used an equality test instead of a bit test. YOU CANNOT FIX THIS // BUG! Micrografx Designer relies on it! // if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT && (pformatetcIn->tymed == TYMED_ISTORAGE) && _fItem) // INTENTIONAL BUG! (see above) { 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) // INTENTIONAL BUG! (see above) { 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) // INTENTIONAL BUG! (see above) { hres = _OpenStorage(); if (SUCCEEDED(hres)) { hres = _GetObjectDescriptor(pmedium, FALSE); } } #endif // SAVE_OBJECTDESCRIPTOR else if (pformatetcIn->cfFormat == CF_TARGETCLSID && (pformatetcIn->tymed & TYMED_HGLOBAL) && _fClsidTarget) { pmedium->hGlobal = GlobalAlloc(GPTR, sizeof(_clsidTarget)); if (pmedium->hGlobal) { CopyMemory(pmedium->hGlobal, &_clsidTarget, sizeof(_clsidTarget)); pmedium->tymed = TYMED_HGLOBAL; hres = S_OK; } else hres = E_OUTOFMEMORY; } 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 HRESULT _GetCacheStreamName(LPCTSTR pszFormat, LPWSTR wszStreamName, UINT cchMax); TCHAR szFormat[128]; if (pformatetcIn->cfFormat < CF_MAX) { hres = StringCchPrintf(szFormat, ARRAYSIZE(szFormat), TEXT("#%d"), pformatetcIn->cfFormat); } else { hres = S_OK; GetClipboardFormatName(pformatetcIn->cfFormat, szFormat, ARRAYSIZE(szFormat)); } if (SUCCEEDED(hres)) { WCHAR wszStreamName[256]; hres = _GetCacheStreamName(szFormat, wszStreamName, ARRAYSIZE(wszStreamName)); if (SUCCEEDED(hres)) { 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; 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); } } if (SUCCEEDED(hres)) { hres = pdtobj->GetData(pformatetcIn, pmedium); DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData pobj->GetData returned (%x)"), hres); pdtobj->Release(); } // Must defer HandsOffStorage until after GetData // or the GetData will fail! And in fact, even if we defer // it, the GetData *still* fails. And if we don't call // HandsOffStorage at all, THE GETDATA STILL FAILS. // Bug 314308, OLE regression. // I'm checking in at least this part of the fix so the OLE // folks can debug it on their side. if (ppstg) { ppstg->HandsOffStorage(); ppstg->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->cfFormatcfFormat, 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) { if (pformatetc->cfFormat == CF_TARGETCLSID && pmedium->tymed == TYMED_HGLOBAL) { CLSID *pclsid = (CLSID *)GlobalLock(pmedium->hGlobal); if (pclsid) { _clsidTarget = *pclsid; _fClsidTarget = TRUE; GlobalUnlock(pclsid); if (fRelease) { ReleaseStgMedium(pmedium); } /* * Whenever anybody sets a drop target, close our storage handles * so the drop target can move/delete us. All our methods will * reopen the storage as needed. */ _CloseStorage(FALSE); return S_OK; } } 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. // HRESULT hres = StringCchCopy(_szPath, ARRAYSIZE(_szPath), pwszFile); if (SUCCEEDED(hres)) { 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 } #ifdef FEATURE_SHELLEXTENSION HRESULT CScrapData::GetIconLocation( UINT uFlags, LPTSTR szIconFile, UINT cchMax, int * piIndex, UINT * pwFlags) { HRESULT hres = _OpenStorage(); DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL OpenStorage returned %x"), hres); if (SUCCEEDED(hres)) { STGMEDIUM medium; hres = _GetObjectDescriptor(&medium, FALSE); DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL _GetOD returned %x"), hres); if (SUCCEEDED(hres)) { LPOBJECTDESCRIPTOR pods = (LPOBJECTDESCRIPTOR)GlobalLock(medium.hGlobal); TCHAR szKey[128]; hres = _KeyNameFromCLSID(pods->clsid, szKey, ARRAYSIZE(szKey)); DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL _KNFC returned %x"), hres); if (SUCCEEDED(hres)) { lstrcatn(szKey, TEXT("\\DefaultIcon"), ARRAYSIZE(szKey)); TCHAR szValue[MAX_PATH+40]; LONG dwSize = sizeof(szValue); if (RegQueryValue(HKEY_CLASSES_ROOT, szKey, szValue, &dwSize) == ERROR_SUCCESS) { *pwFlags = GIL_PERINSTANCE | GIL_NOTFILENAME; *piIndex = _ParseIconLocation(szValue); TCHAR szT[MAX_PATH]; hres = StringCchPrintf(szT, ARRAYSIZE(szT), TEXT("shscrap.dll,%s"), szValue); if (SUCCEEDED(hres)) { hres = StringCchCopy(szIconFile, cchMax, szT); DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL Found Icon Location %s,%d"), szIconFile, *piIndex); } hres = S_OK; } else { DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL RegQueryValue for CLSID failed (%s)"), szKey); hres = E_FAIL; } } GlobalUnlock(medium.hGlobal); ReleaseStgMedium(&medium); } } // // If Getting CLSID failed, return a generic scrap icon as per-instance // icon to avoid re-opening this file again. // if (FAILED(hres)) { GetModuleFileName(HINST_THISDLL, szIconFile, cchMax); DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL Returning default icon (%s)"), szIconFile); *piIndex = -IDI_ICON; *pwFlags = GIL_PERINSTANCE; hres = S_OK; } return hres; // This value is always S_OK } #ifdef UNICODE HRESULT CScrapData::GetIconLocation( UINT uFlags, LPSTR szIconFile, UINT cchMax, int * piIndex, UINT * pwFlags) { WCHAR szPath[MAX_PATH]; HRESULT hr = GetIconLocation(uFlags, szPath, ARRAYSIZE(szPath), piIndex, pwFlags); if (SUCCEEDED(hr)) { SHUnicodeToAnsi(szPath, szIconFile, cchMax); } return hr; } #endif #endif // FEATURE_SHELLEXTENSION HICON _SimulateScrapIcon(HICON hiconClass, UINT cxIcon) { // // First load the template image. // HICON hiconTemplate = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_SCRAP), IMAGE_ICON, cxIcon, cxIcon, LR_DEFAULTCOLOR); if (!hiconTemplate) { return NULL; } ICONINFO ii; GetIconInfo(hiconTemplate, &ii); HDC hdc = GetDC(NULL); HDC hdcMem = CreateCompatibleDC(hdc); ReleaseDC(NULL, hdc); HBITMAP hbmT = (HBITMAP)SelectObject(hdcMem, ii.hbmColor); // This assumes the generic icon is white PatBlt(hdcMem, cxIcon/4-1, cxIcon/4-1, cxIcon/2+2, cxIcon/2+2, WHITENESS); DrawIconEx(hdcMem, cxIcon/4, cxIcon/4, hiconClass, cxIcon/2, cxIcon/2, 0, NULL, DI_NORMAL); SelectObject(hdcMem, hbmT); DeleteDC(hdcMem); // // Create the icon image to return // ii.fIcon = TRUE; ii.xHotspot = 0; ii.yHotspot = 0; HICON hicon = CreateIconIndirect(&ii); DeleteObject(ii.hbmColor); DeleteObject(ii.hbmMask); return hicon; } #ifdef FEATURE_SHELLEXTENSION HRESULT CScrapData::Extract( LPCTSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) { LPCTSTR pszComma = StrChr(pszFile, ','); if (pszComma++) { #if 1 HICON hiconSmall; UINT i = ExtractIconEx(pszComma, nIconIndex, NULL, &hiconSmall, 1); if (i != -1) { if (phiconLarge) { *phiconLarge = _SimulateScrapIcon(hiconSmall, LOWORD(nIconSize)); } if (phiconSmall) { *phiconSmall = _SimulateScrapIcon(hiconSmall, HIWORD(nIconSize)); } DestroyIcon(hiconSmall); } #else UINT i; // Assumes shell icon sizes are def icon sizes i = ExtractIconEx(pszComma, nIconIndex, phiconLarge, phiconSmall, 1); DebugMsg(DM_TRACE, TEXT("sc TR - CSD::Ext ExtractIconEx(%s) returns %d)"), pszComma, i); return S_OK; #endif } return E_INVALIDARG; } #ifdef UNICODE HRESULT CScrapData::Extract( LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) { WCHAR szPath[MAX_PATH]; SHAnsiToUnicode(pszFile, szPath, ARRAYSIZE(szPath)); return Extract(szPath, nIconIndex, phiconLarge, phiconSmall, nIconSize); } #endif #endif // FEATURE_SHELLEXTENSION 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; }