Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1023 lines
31 KiB

  1. #include "shole.h"
  2. #include "ids.h"
  3. #define INITGUID
  4. #ifndef WINNT
  5. #pragma data_seg(".text", "CODE")
  6. #endif
  7. #include <initguid.h>
  8. #include "scguid.h"
  9. #ifndef WINNT
  10. #pragma data_seg()
  11. #endif
  12. // #define SAVE_OBJECTDESCRIPTOR
  13. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  14. extern "C" const WCHAR c_wszDescriptor[];
  15. UINT _GetClipboardFormat(UINT id)
  16. {
  17. static UINT s_acf[CFID_MAX] = { 0, 0, 0, 0, 0 };
  18. static const TCHAR * const c_aszFormat[CFID_MAX] = {
  19. TEXT("Embedded Object"),
  20. TEXT("Object Descriptor"),
  21. TEXT("Link Source Descriptor"),
  22. TEXT("Rich Text Format"),
  23. TEXT("Shell Scrap Object")
  24. };
  25. if (!s_acf[id])
  26. {
  27. s_acf[id] = RegisterClipboardFormat(c_aszFormat[id]);
  28. }
  29. return s_acf[id];
  30. }
  31. //===========================================================================
  32. // CScrapData : Class definition
  33. //===========================================================================
  34. class CScrapData : public IDataObject, public IPersistFile
  35. {
  36. public:
  37. CScrapData();
  38. ~CScrapData();
  39. // IUnKnown
  40. virtual HRESULT __stdcall QueryInterface(REFIID,void **);
  41. virtual ULONG __stdcall AddRef(void);
  42. virtual ULONG __stdcall Release(void);
  43. // IDataObject
  44. virtual HRESULT __stdcall GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
  45. virtual HRESULT __stdcall GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
  46. virtual HRESULT __stdcall QueryGetData(FORMATETC *pformatetc);
  47. virtual HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut);
  48. virtual HRESULT __stdcall SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
  49. virtual HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
  50. virtual HRESULT __stdcall DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
  51. virtual HRESULT __stdcall DUnadvise(DWORD dwConnection);
  52. virtual HRESULT __stdcall EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
  53. virtual HRESULT __stdcall IsDirty(void);
  54. // IPersistFile
  55. virtual HRESULT __stdcall GetClassID(CLSID *pClassID);
  56. virtual HRESULT __stdcall Load(LPCOLESTR pszFileName, DWORD dwMode);
  57. virtual HRESULT __stdcall Save(LPCOLESTR pszFileName, BOOL fRemember);
  58. virtual HRESULT __stdcall SaveCompleted(LPCOLESTR pszFileName);
  59. virtual HRESULT __stdcall GetCurFile(LPOLESTR *ppszFileName);
  60. protected:
  61. HRESULT _OpenStorage(void);
  62. void _CloseStorage(BOOL fResetFlags);
  63. INT _GetFormatIndex(UINT cf);
  64. void _FillCFArray(void);
  65. #ifdef FIX_ROUNDTRIP
  66. HRESULT _RunObject(void);
  67. #endif // FIX_ROUNDTRIP
  68. #ifdef SAVE_OBJECTDESCRIPTOR
  69. HRESULT _GetObjectDescriptor(LPSTGMEDIUM pmedium, BOOL fGetHere);
  70. #endif // SAVE_OBJECTDESCRIPTOR
  71. UINT _cRef;
  72. BOOL _fDoc:1;
  73. BOOL _fItem:1;
  74. BOOL _fObjDesc:1;
  75. #ifdef FIX_ROUNDTRIP
  76. BOOL _fRunObjectAlreadyCalled:1;
  77. LPDATAOBJECT _pdtobjItem;
  78. #endif // FIX_ROUNDTRIP
  79. LPSTORAGE _pstgDoc;
  80. LPSTORAGE _pstgItem;
  81. LPSTREAM _pstmObjDesc;
  82. TCHAR _szPath[MAX_PATH];
  83. INT _ccf; // number of clipboard format.
  84. INT _icfCacheMax; // Max cache format index
  85. DWORD _acf[64]; // 64 must be enough!
  86. };
  87. //===========================================================================
  88. // CScrapData : Constructor
  89. //===========================================================================
  90. CScrapData::CScrapData(void) : _cRef(1), _pstgDoc(NULL), _pstgItem(NULL),
  91. _fDoc(FALSE), _fItem(FALSE), _fObjDesc(FALSE),
  92. _ccf(0),
  93. #ifdef FIX_ROUNDTRIP
  94. _pdtobjItem(NULL), _fRunObjectAlreadyCalled(FALSE),
  95. #endif // FIX_ROUNDTRIP
  96. _pstmObjDesc(NULL)
  97. {
  98. _szPath[0] = TEXT('\0');
  99. g_cRefThisDll++;
  100. }
  101. CScrapData::~CScrapData()
  102. {
  103. #ifdef FIX_ROUNDTRIP
  104. if (_pdtobjItem) {
  105. _pdtobjItem->Release();
  106. }
  107. #endif // FIX_ROUNDTRIP
  108. _CloseStorage(FALSE);
  109. g_cRefThisDll--;
  110. }
  111. //===========================================================================
  112. // CScrapData : Member functions (private)
  113. //===========================================================================
  114. //
  115. // private member CScrapData::_OpenStorage
  116. //
  117. HRESULT CScrapData::_OpenStorage(void)
  118. {
  119. if (_pstgItem) {
  120. return S_OK;
  121. }
  122. HRESULT hres;
  123. WCHAR wszFile[MAX_PATH];
  124. #ifdef UNICODE
  125. lstrcpyn(wszFile, _szPath, ARRAYSIZE(wszFile));
  126. #ifdef DEBUG
  127. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetStorage is called (%s)"), wszFile);
  128. #endif
  129. #else
  130. MultiByteToWideChar(CP_ACP, 0, _szPath, -1, wszFile, ARRAYSIZE(wszFile));
  131. #ifdef DEBUG
  132. TCHAR szFile[MAX_PATH];
  133. WideCharToMultiByte(CP_ACP, 0, wszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL);
  134. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetStorage is called (%s)"), szFile);
  135. #endif
  136. #endif
  137. hres = StgOpenStorage(wszFile, NULL,
  138. STGM_READ | STGM_SHARE_DENY_WRITE,
  139. NULL, 0, &_pstgDoc);
  140. if (SUCCEEDED(hres))
  141. {
  142. _fDoc = TRUE;
  143. hres = _pstgDoc->OpenStorage(c_wszContents, NULL,
  144. STGM_READ | STGM_SHARE_EXCLUSIVE,
  145. NULL, 0, &_pstgItem);
  146. if (SUCCEEDED(hres))
  147. {
  148. HRESULT hresT;
  149. _fItem = TRUE;
  150. #ifdef SAVE_OBJECTDESCRIPTOR
  151. hresT = _pstgDoc->OpenStream(c_wszDescriptor, 0,
  152. STGM_READ | STGM_SHARE_EXCLUSIVE,
  153. 0, &_pstmObjDesc);
  154. _fObjDesc = SUCCEEDED(hresT);
  155. #endif // SAVE_OBJECTDESCRIPTOR
  156. }
  157. else
  158. {
  159. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage _pstgDoc->OpenStorage failed (%x)"), hres);
  160. _pstgDoc->Release();
  161. _pstgDoc = NULL;
  162. }
  163. }
  164. else
  165. {
  166. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage StgOpenStorage failed (%x)"), hres);
  167. }
  168. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage _pstgDoc->OpenStorage returning (%x) %x"),
  169. hres, _pstmObjDesc);
  170. return hres;
  171. }
  172. void CScrapData::_CloseStorage(BOOL fResetFlags)
  173. {
  174. if (_pstgItem) {
  175. _pstgItem->Release();
  176. _pstgItem = NULL;
  177. }
  178. if (_pstmObjDesc) {
  179. _pstmObjDesc->Release();
  180. _pstmObjDesc = NULL;
  181. }
  182. if (_pstgDoc) {
  183. _pstgDoc->Release();
  184. _pstgDoc = NULL;
  185. }
  186. if (fResetFlags) {
  187. _fItem = FALSE;
  188. _fObjDesc = FALSE;
  189. _fDoc = FALSE;
  190. }
  191. }
  192. INT CScrapData::_GetFormatIndex(UINT cf)
  193. {
  194. for (INT i=0; i<_ccf; i++)
  195. {
  196. if (_acf[i] == cf)
  197. {
  198. return i;
  199. }
  200. }
  201. return -1;
  202. }
  203. #ifdef FIX_ROUNDTRIP
  204. extern "C" const TCHAR c_szRenderFMT[] = TEXT("DataFormats\\DelayRenderFormats");
  205. #endif // FIX_ROUNDTRIP
  206. extern "C" const WCHAR c_wszFormatNames[];
  207. //
  208. // This function filles the clipboard format array (_acf). Following
  209. // clipboard format may be added.
  210. //
  211. // Step 1. CF_EMBEEDEDOBJECT
  212. // Step 2. CF_OBJECTDESCRIPTOR
  213. // Step 3. CF_SCRAPOBJECT
  214. // Step 4. Cached clipboard formats (from a stream).
  215. // Step 5. Delay Rendered clipbaord formats (from registry).
  216. //
  217. void CScrapData::_FillCFArray(void)
  218. {
  219. _ccf=0;
  220. //
  221. // Step 1.
  222. //
  223. if (_fItem) {
  224. _acf[_ccf++] = CF_EMBEDDEDOBJECT;
  225. }
  226. //
  227. // Step 2.
  228. //
  229. if (_fObjDesc) {
  230. _acf[_ccf++] = CF_OBJECTDESCRIPTOR;
  231. }
  232. //
  233. // Step 3.
  234. //
  235. if (_fDoc)
  236. {
  237. _acf[_ccf++] = CF_SCRAPOBJECT;
  238. }
  239. #ifdef FIX_ROUNDTRIP
  240. if (_pstgItem)
  241. {
  242. //
  243. // Step 3. Cached clipboard formats
  244. //
  245. //
  246. // Open the stream which contains the names of cached formats.
  247. //
  248. LPSTREAM pstm;
  249. HRESULT hres = _pstgDoc->OpenStream(c_wszFormatNames, NULL,
  250. STGM_READ | STGM_SHARE_EXCLUSIVE,
  251. NULL, &pstm);
  252. if (SUCCEEDED(hres))
  253. {
  254. //
  255. // For each cached format...
  256. //
  257. USHORT cb;
  258. DWORD cbRead;
  259. while(SUCCEEDED(pstm->Read(&cb, sizeof(cb), &cbRead)) && cbRead==sizeof(cb)
  260. && cb && cb<128)
  261. {
  262. UINT cf = 0;
  263. //
  264. // Get the cached clipboard format name
  265. //
  266. CHAR szFormat[128];
  267. szFormat[cb] = '\0';
  268. hres = pstm->Read(szFormat, cb, &cbRead);
  269. if (SUCCEEDED(hres) && cbRead==cb && lstrlenA(szFormat)==cb)
  270. {
  271. //
  272. // Append it to the array.
  273. //
  274. #ifdef UNICODE
  275. TCHAR wszFormat[128];
  276. MultiByteToWideChar(CP_ACP, 0,
  277. szFormat, -1,
  278. wszFormat, ARRAYSIZE(wszFormat));
  279. DebugMsg(DM_TRACE, TEXT("sc TR _FillCFA Found Cached Format %s"), wszFormat);
  280. #else
  281. DebugMsg(DM_TRACE, TEXT("sc TR _FillCFA Found Cached Format %s"), szFormat);
  282. #endif
  283. cf = RegisterClipboardFormatA(szFormat);
  284. if (cf)
  285. {
  286. _acf[_ccf++] = cf;
  287. }
  288. }
  289. else
  290. {
  291. break;
  292. }
  293. }
  294. pstm->Release();
  295. }
  296. _icfCacheMax = _ccf;
  297. //
  298. // Step 4. Get the list of delay-rendered clipboard formats
  299. //
  300. LPPERSISTSTORAGE pps;
  301. hres = OleLoad(_pstgItem, IID_IPersistStorage, NULL, (LPVOID *)&pps);
  302. if (SUCCEEDED(hres))
  303. {
  304. //
  305. // Get the CLSID of embedding.
  306. //
  307. CLSID clsid;
  308. hres = pps->GetClassID(&clsid);
  309. if (SUCCEEDED(hres))
  310. {
  311. //
  312. // Open the key for delay-rendered format names.
  313. //
  314. extern HKEY _OpenCLSIDKey(REFCLSID rclsid, LPCTSTR pszSubKey);
  315. HKEY hkey = _OpenCLSIDKey(clsid, c_szRenderFMT);
  316. if (hkey)
  317. {
  318. TCHAR szValueName[128];
  319. //
  320. // For each delay-rendered clipboard format...
  321. //
  322. for(int iValue=0; ;iValue++)
  323. {
  324. //
  325. // Get the value name, which is the format name.
  326. //
  327. DWORD cchValueName = ARRAYSIZE(szValueName);
  328. DWORD dwType;
  329. if (RegEnumValue(hkey, iValue, szValueName, &cchValueName, NULL,
  330. &dwType, NULL, NULL)==ERROR_SUCCESS)
  331. {
  332. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_FillCFA RegEnumValue found %s, %x"), szValueName, dwType);
  333. UINT cf = RegisterClipboardFormat(szValueName);
  334. if (cf)
  335. {
  336. _acf[_ccf++] = cf;
  337. }
  338. }
  339. else
  340. {
  341. break;
  342. }
  343. }
  344. //
  345. // HACK: NT 3.5's regedit does not support named value...
  346. //
  347. for(iValue=0; ;iValue++)
  348. {
  349. TCHAR szKeyName[128];
  350. //
  351. // Get the value name, which is the format name.
  352. //
  353. if (RegEnumKey(hkey, iValue, szKeyName, ARRAYSIZE(szKeyName))==ERROR_SUCCESS)
  354. {
  355. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_FillCFA RegEnumValue found %s"), szValueName);
  356. LONG cbValue = ARRAYSIZE(szValueName);
  357. if ((RegQueryValue(hkey, szKeyName, szValueName, &cbValue)==ERROR_SUCCESS) && cbValue)
  358. {
  359. UINT cf = RegisterClipboardFormat(szValueName);
  360. if (cf)
  361. {
  362. _acf[_ccf++] = cf;
  363. }
  364. }
  365. }
  366. else
  367. {
  368. break;
  369. }
  370. }
  371. RegCloseKey(hkey);
  372. }
  373. }
  374. pps->Release();
  375. }
  376. }
  377. #endif // FIX_ROUNDTRIP
  378. }
  379. #ifdef FIX_ROUNDTRIP
  380. //
  381. // private member CScrapData::_RunObject
  382. //
  383. HRESULT CScrapData::_RunObject(void)
  384. {
  385. if (_pdtobjItem) {
  386. return S_OK;
  387. }
  388. if (_fRunObjectAlreadyCalled) {
  389. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject returning E_FAIL"));
  390. return E_FAIL;
  391. }
  392. _fRunObjectAlreadyCalled = TRUE;
  393. HRESULT hres = _OpenStorage();
  394. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject _OpenStorage returned %x"), hres);
  395. if (SUCCEEDED(hres) && _pstgItem)
  396. {
  397. LPOLEOBJECT pole;
  398. hres = OleLoad(_pstgItem, IID_IOleObject, NULL, (LPVOID *)&pole);
  399. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject OleLoad returned %x"), hres);
  400. if (SUCCEEDED(hres))
  401. {
  402. DWORD dw=GetCurrentTime();
  403. hres = OleRun(pole);
  404. dw = GetCurrentTime()-dw;
  405. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject OleRun returned %x (%d msec)"), hres, dw);
  406. if (SUCCEEDED(hres))
  407. {
  408. hres = pole->GetClipboardData(0, &_pdtobjItem);
  409. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject GetClipboardData returned %x"), hres);
  410. if (FAILED(hres))
  411. {
  412. hres = pole->QueryInterface(IID_IDataObject, (LPVOID*)&_pdtobjItem);
  413. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject QI(IID_IDataIbject) returned %x"), hres);
  414. }
  415. }
  416. pole->Release();
  417. }
  418. }
  419. return hres;
  420. }
  421. #endif // FIX_ROUNDTRIP
  422. //===========================================================================
  423. // CScrapData : Member functions (virtual IDataObject)
  424. //===========================================================================
  425. HRESULT CScrapData::QueryInterface(REFIID riid, LPVOID * ppvObj)
  426. {
  427. if (IsEqualIID(riid, IID_IDataObject) || IsEqualIID(riid, IID_IUnknown))
  428. {
  429. *ppvObj = (LPDATAOBJECT)this;
  430. _cRef++;
  431. return S_OK;
  432. }
  433. else if (IsEqualIID(riid, IID_IPersistFile))
  434. {
  435. *ppvObj = (LPPERSISTFILE)this;
  436. _cRef++;
  437. return S_OK;
  438. }
  439. *ppvObj = NULL;
  440. return E_NOINTERFACE;
  441. }
  442. ULONG CScrapData::AddRef()
  443. {
  444. _cRef++;
  445. return _cRef;
  446. }
  447. ULONG CScrapData::Release()
  448. {
  449. _cRef--;
  450. if (_cRef > 0)
  451. return _cRef;
  452. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::Release deleting this object"));
  453. delete this;
  454. return 0;
  455. }
  456. #ifdef SAVE_OBJECTDESCRIPTOR
  457. HRESULT CScrapData::_GetObjectDescriptor(LPSTGMEDIUM pmedium, BOOL fGetHere)
  458. {
  459. if (!_pstmObjDesc)
  460. return DATA_E_FORMATETC;
  461. LARGE_INTEGER dlib = { 0, 0 };
  462. HRESULT hres = _pstmObjDesc->Seek(dlib, STREAM_SEEK_SET, NULL);
  463. if (FAILED(hres))
  464. return hres;
  465. OBJECTDESCRIPTOR ods;
  466. ULONG cbRead;
  467. hres = _pstmObjDesc->Read(&ods.cbSize, sizeof(ods.cbSize), &cbRead);
  468. if (SUCCEEDED(hres) && cbRead == sizeof(ods.cbSize))
  469. {
  470. if (fGetHere)
  471. {
  472. if (GlobalSize(pmedium->hGlobal)<ods.cbSize) {
  473. hres = STG_E_MEDIUMFULL;
  474. }
  475. }
  476. else
  477. {
  478. pmedium->tymed = TYMED_HGLOBAL;
  479. pmedium->hGlobal = GlobalAlloc(GMEM_MOVEABLE, ods.cbSize);
  480. hres = pmedium->hGlobal ? S_OK : E_OUTOFMEMORY;
  481. }
  482. if (SUCCEEDED(hres))
  483. {
  484. LPOBJECTDESCRIPTOR pods = (LPOBJECTDESCRIPTOR)GlobalLock(pmedium->hGlobal);
  485. if (pods)
  486. {
  487. pods->cbSize = ods.cbSize;
  488. hres = _pstmObjDesc->Read(&pods->clsid, ods.cbSize-sizeof(ods.cbSize), NULL);
  489. GlobalUnlock(pmedium->hGlobal);
  490. }
  491. else
  492. {
  493. if (!fGetHere) {
  494. GlobalFree(pmedium->hGlobal);
  495. pmedium->hGlobal = NULL;
  496. }
  497. hres = E_OUTOFMEMORY;
  498. }
  499. }
  500. }
  501. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_GetObjectDescriptor returning (%x)"), hres);
  502. return hres;
  503. }
  504. #endif // SAVE_OBJECTDESCRIPTOR
  505. HRESULT CScrapData::GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
  506. {
  507. #ifdef DEBUG
  508. if (pformatetcIn->cfFormat<CF_MAX) {
  509. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %x,%x,%x"),
  510. pformatetcIn->cfFormat, pformatetcIn->tymed, pmedium->tymed);
  511. } else {
  512. TCHAR szName[256];
  513. GetClipboardFormatName(pformatetcIn->cfFormat, szName, ARRAYSIZE(szName));
  514. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %s,%x,%x"),
  515. szName, pformatetcIn->tymed, pmedium->tymed);
  516. }
  517. #endif
  518. HRESULT hres;
  519. pmedium->pUnkForRelease = NULL;
  520. pmedium->pstg = NULL;
  521. //
  522. // NOTES: We should avoid calling _OpenStorage if we don't support
  523. // the format.
  524. //
  525. if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
  526. && pformatetcIn->tymed == TYMED_ISTORAGE && _fItem)
  527. {
  528. hres = _OpenStorage();
  529. if (SUCCEEDED(hres))
  530. {
  531. pmedium->tymed = TYMED_ISTORAGE;
  532. _pstgItem->AddRef();
  533. pmedium->pstg = _pstgItem;
  534. }
  535. }
  536. else if (pformatetcIn->cfFormat == CF_SCRAPOBJECT
  537. && pformatetcIn->tymed == TYMED_ISTORAGE && _fItem)
  538. {
  539. hres = _OpenStorage();
  540. if (SUCCEEDED(hres))
  541. {
  542. pmedium->tymed = TYMED_ISTORAGE;
  543. _pstgDoc->AddRef();
  544. pmedium->pstg = _pstgDoc;
  545. }
  546. }
  547. #ifdef SAVE_OBJECTDESCRIPTOR
  548. else if (pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR
  549. && pformatetcIn->tymed == TYMED_HGLOBAL && _fObjDesc)
  550. {
  551. hres = _OpenStorage();
  552. if (SUCCEEDED(hres))
  553. {
  554. hres = _GetObjectDescriptor(pmedium, FALSE);
  555. }
  556. }
  557. #endif // SAVE_OBJECTDESCRIPTOR
  558. else
  559. {
  560. #ifdef FIX_ROUNDTRIP
  561. INT iFmt = _GetFormatIndex(pformatetcIn->cfFormat);
  562. if (iFmt != -1)
  563. {
  564. hres = _OpenStorage();
  565. if (FAILED(hres))
  566. {
  567. goto exit;
  568. }
  569. }
  570. if (iFmt>=_icfCacheMax)
  571. {
  572. //
  573. // Delayed Rendered format
  574. //
  575. if (SUCCEEDED(_RunObject()))
  576. {
  577. hres = _pdtobjItem->GetData(pformatetcIn, pmedium);
  578. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called _pdtobjItem->GetData %x"), hres);
  579. return hres;
  580. }
  581. }
  582. else if (iFmt >= 0)
  583. {
  584. //
  585. // Cached Format
  586. //
  587. extern void _GetCacheStreamName(LPCTSTR pszFormat, LPWSTR wszStreamName, UINT cchMax);
  588. TCHAR szFormat[128];
  589. if (pformatetcIn->cfFormat<CF_MAX) {
  590. wsprintf(szFormat, TEXT("#%d"), pformatetcIn->cfFormat);
  591. } else {
  592. GetClipboardFormatName(pformatetcIn->cfFormat, szFormat, ARRAYSIZE(szFormat));
  593. }
  594. WCHAR wszStreamName[256];
  595. _GetCacheStreamName(szFormat, wszStreamName, ARRAYSIZE(wszStreamName));
  596. if (pformatetcIn->cfFormat==CF_METAFILEPICT
  597. || pformatetcIn->cfFormat==CF_ENHMETAFILE
  598. || pformatetcIn->cfFormat==CF_BITMAP
  599. || pformatetcIn->cfFormat==CF_PALETTE
  600. )
  601. {
  602. LPSTORAGE pstg;
  603. hres = _pstgDoc->OpenStorage(wszStreamName, NULL,
  604. STGM_READ | STGM_SHARE_EXCLUSIVE,
  605. NULL, 0, &pstg);
  606. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData OpenStorage returned (%x)"), hres);
  607. if (SUCCEEDED(hres))
  608. {
  609. LPDATAOBJECT pdtobj;
  610. #if 0
  611. hres = OleLoad(pstg, IID_IDataObject, NULL, (LPVOID*)&pdtobj);
  612. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData OleLoad returned (%x)"), hres);
  613. #else
  614. const CLSID* pclsid = NULL;
  615. switch(pformatetcIn->cfFormat)
  616. {
  617. case CF_METAFILEPICT:
  618. pclsid = &CLSID_Picture_Metafile;
  619. break;
  620. case CF_ENHMETAFILE:
  621. pclsid = &CLSID_Picture_EnhMetafile;
  622. break;
  623. case CF_PALETTE:
  624. case CF_BITMAP:
  625. pclsid = &CLSID_Picture_Dib;
  626. break;
  627. }
  628. LPPERSISTSTORAGE ppstg;
  629. hres = OleCreateDefaultHandler(*pclsid, NULL, IID_IPersistStorage, (LPVOID *)&ppstg);
  630. DebugMsg(DM_TRACE, TEXT("sc TR Scrap_CacheOPF OleCreteDefHandler returned %x"), hres);
  631. if (SUCCEEDED(hres))
  632. {
  633. hres = ppstg->Load(pstg);
  634. DebugMsg(DM_TRACE, TEXT("sc TR Scrap_CacheOPF ppstg->Load returned %x"), hres);
  635. if (SUCCEEDED(hres))
  636. {
  637. hres = ppstg->QueryInterface(IID_IDataObject, (LPVOID*)&pdtobj);
  638. }
  639. ppstg->HandsOffStorage();
  640. ppstg->Release();
  641. }
  642. #endif
  643. if (SUCCEEDED(hres))
  644. {
  645. hres = pdtobj->GetData(pformatetcIn, pmedium);
  646. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData pobj->GetData returned (%x)"), hres);
  647. pdtobj->Release();
  648. }
  649. pstg->Release();
  650. return hres;
  651. }
  652. // fall through
  653. }
  654. else // if (pformatetcIn->cfFormat==CF_...)
  655. {
  656. LPSTREAM pstm;
  657. hres = _pstgDoc->OpenStream(wszStreamName, NULL,
  658. STGM_READ | STGM_SHARE_EXCLUSIVE,
  659. 0, &pstm);
  660. if (SUCCEEDED(hres))
  661. {
  662. UINT cbData;
  663. DWORD cbRead;
  664. hres = pstm->Read(&cbData, sizeof(cbData), &cbRead);
  665. if (SUCCEEDED(hres) && cbRead==sizeof(cbData))
  666. {
  667. LPBYTE pData = (LPBYTE)GlobalAlloc(GPTR, cbData);
  668. if (pData)
  669. {
  670. hres = pstm->Read(pData, cbData, &cbRead);
  671. if (SUCCEEDED(hres) && cbData==cbRead)
  672. {
  673. pmedium->tymed = TYMED_HGLOBAL;
  674. pmedium->hGlobal = (HGLOBAL)pData;
  675. }
  676. else
  677. {
  678. hres = E_UNEXPECTED;
  679. GlobalFree((HGLOBAL)pData);
  680. }
  681. }
  682. else
  683. {
  684. hres = E_OUTOFMEMORY;
  685. }
  686. }
  687. pstm->Release();
  688. DebugMsg(DM_TRACE, TEXT("CSD::GetData(%s) returning %x"), szFormat, hres);
  689. return hres;
  690. }
  691. }
  692. } // if (iFmt >= 0)
  693. #endif // FIX_ROUNDTRIP
  694. hres = DATA_E_FORMATETC;
  695. }
  696. exit:
  697. #ifdef DEBUG
  698. TCHAR szFormat[256];
  699. GetClipboardFormatName(pformatetcIn->cfFormat,
  700. szFormat, ARRAYSIZE(szFormat));
  701. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %x,%x,%s and returning %x"),
  702. pformatetcIn->cfFormat,
  703. pformatetcIn->tymed,
  704. szFormat, hres);
  705. #endif
  706. return hres;
  707. }
  708. HRESULT CScrapData::GetDataHere(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium )
  709. {
  710. HRESULT hres;
  711. #ifdef DEBUG
  712. if (pformatetcIn->cfFormat<CF_MAX) {
  713. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere called with %x,%x,%x"),
  714. pformatetcIn->cfFormat, pformatetcIn->tymed, pmedium->tymed);
  715. } else {
  716. TCHAR szName[256];
  717. GetClipboardFormatName(pformatetcIn->cfFormat, szName, ARRAYSIZE(szName));
  718. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere called with %s,%x,%x"),
  719. szName, pformatetcIn->tymed, pmedium->tymed);
  720. }
  721. #endif
  722. hres = _OpenStorage();
  723. if (FAILED(hres)) {
  724. return hres;
  725. }
  726. if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
  727. && pformatetcIn->tymed == TYMED_ISTORAGE && pmedium->tymed == TYMED_ISTORAGE)
  728. {
  729. hres = _pstgItem->CopyTo(0, NULL, NULL, pmedium->pstg);
  730. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere _pstgItem->CopyTo returned %x"), hres);
  731. }
  732. else if (pformatetcIn->cfFormat == CF_SCRAPOBJECT
  733. && pformatetcIn->tymed == TYMED_ISTORAGE && pmedium->tymed == TYMED_ISTORAGE)
  734. {
  735. hres = _pstgDoc->CopyTo(0, NULL, NULL, pmedium->pstg);
  736. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere _pstgItem->CopyTo returned %x"), hres);
  737. }
  738. #ifdef SAVE_OBJECTDESCRIPTOR
  739. else if ((pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR)
  740. && (pformatetcIn->tymed == TYMED_HGLOBAL) && _pstmObjDesc)
  741. {
  742. hres = _GetObjectDescriptor(pmedium, TRUE);
  743. }
  744. #endif // SAVE_OBJECTDESCRIPTOR
  745. else
  746. {
  747. #ifdef FIX_ROUNDTRIP
  748. if (_GetFormatIndex(pformatetcIn->cfFormat) >= 0 && SUCCEEDED(_RunObject()))
  749. {
  750. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere calling _pdtobjItem->GetDataHere"));
  751. return _pdtobjItem->GetDataHere(pformatetcIn, pmedium);
  752. }
  753. #endif // FIX_ROUNDTRIP
  754. hres = DATA_E_FORMATETC;
  755. }
  756. return hres;
  757. }
  758. HRESULT CScrapData::QueryGetData(LPFORMATETC pformatetcIn)
  759. {
  760. HRESULT hres;
  761. if (_GetFormatIndex(pformatetcIn->cfFormat) >= 0) {
  762. hres = S_OK;
  763. } else {
  764. hres = DATA_E_FORMATETC;
  765. }
  766. #ifdef DEBUG
  767. TCHAR szFormat[256] = TEXT("");
  768. GetClipboardFormatName(pformatetcIn->cfFormat, szFormat, ARRAYSIZE(szFormat));
  769. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::QueryGetData(%x,%s,%x) returning %x"),
  770. pformatetcIn->cfFormat, szFormat, pformatetcIn->tymed, hres);
  771. #endif
  772. return hres;
  773. }
  774. HRESULT CScrapData::GetCanonicalFormatEtc(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
  775. {
  776. //
  777. // This is the simplest implemtation. It means we always return
  778. // the data in the format requested.
  779. //
  780. return ResultFromScode(DATA_S_SAMEFORMATETC);
  781. }
  782. HRESULT CScrapData::SetData(LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
  783. {
  784. return E_FAIL;
  785. }
  786. HRESULT CScrapData::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC * ppenumFormatEtc)
  787. {
  788. if (dwDirection!=DATADIR_GET) {
  789. return E_NOTIMPL; // Not supported (as documented)
  790. }
  791. if (_ccf==0) {
  792. return E_UNEXPECTED;
  793. }
  794. FORMATETC * pfmt = (FORMATETC*)LocalAlloc(LPTR, sizeof(FORMATETC)*_ccf);
  795. if (!pfmt) {
  796. return E_OUTOFMEMORY;
  797. }
  798. static const FORMATETC s_fmteInit =
  799. {
  800. 0,
  801. (DVTARGETDEVICE __RPC_FAR *)NULL,
  802. DVASPECT_CONTENT,
  803. -1,
  804. TYMED_HGLOBAL // HGLOBAL except CF_EMBEDDEDOBJECT/SCRAPOBJECT
  805. };
  806. //
  807. // Fills FORMATETC for each clipboard format.
  808. //
  809. for (INT i=0; i<_ccf; i++)
  810. {
  811. pfmt[i] = s_fmteInit;
  812. pfmt[i].cfFormat = (CLIPFORMAT)_acf[i];
  813. if (_acf[i]==CF_EMBEDDEDOBJECT || _acf[i]==CF_SCRAPOBJECT) {
  814. pfmt[i].tymed = TYMED_ISTORAGE;
  815. } else {
  816. switch(_acf[i])
  817. {
  818. case CF_METAFILEPICT:
  819. pfmt[i].tymed = TYMED_MFPICT;
  820. break;
  821. case CF_ENHMETAFILE:
  822. pfmt[i].tymed = TYMED_ENHMF;
  823. break;
  824. case CF_BITMAP:
  825. case CF_PALETTE:
  826. pfmt[i].tymed = TYMED_GDI;
  827. break;
  828. }
  829. }
  830. }
  831. HRESULT hres = SHCreateStdEnumFmtEtc(_ccf, pfmt, ppenumFormatEtc);
  832. LocalFree((HLOCAL)pfmt);
  833. return hres;
  834. }
  835. HRESULT CScrapData::DAdvise(FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection)
  836. {
  837. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  838. }
  839. HRESULT CScrapData::DUnadvise(DWORD dwConnection)
  840. {
  841. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  842. }
  843. HRESULT CScrapData::EnumDAdvise(LPENUMSTATDATA * ppenumAdvise)
  844. {
  845. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  846. }
  847. //===========================================================================
  848. // CScrapData : Member functions (virtual IPersistFile)
  849. //===========================================================================
  850. HRESULT CScrapData::GetClassID(LPCLSID lpClassID)
  851. {
  852. *lpClassID = CLSID_CScrapData;
  853. return S_OK;
  854. }
  855. HRESULT CScrapData::IsDirty(void)
  856. {
  857. return S_FALSE; // meaningless (read only)
  858. }
  859. HRESULT CScrapData::Load(LPCOLESTR pwszFile, DWORD grfMode)
  860. {
  861. //
  862. // Close all the storage (if there is any) and reset flags.
  863. //
  864. _CloseStorage(TRUE);
  865. //
  866. // Copy the new file name and open storage to update the flags.
  867. //
  868. #ifdef UNICODE
  869. lstrcpyn(_szPath, pwszFile, ARRAYSIZE(_szPath));
  870. #else
  871. WideCharToMultiByte(CP_ACP, 0, pwszFile, -1, _szPath, ARRAYSIZE(_szPath), NULL, NULL);
  872. #endif
  873. HRESULT hres = _OpenStorage();
  874. _FillCFArray();
  875. //
  876. // Close all the storage, so that we can move/delete.
  877. //
  878. _CloseStorage(FALSE);
  879. return hres;
  880. }
  881. HRESULT CScrapData::Save(LPCOLESTR pwszFile, BOOL fRemember)
  882. {
  883. return E_FAIL; // read only
  884. }
  885. HRESULT CScrapData::SaveCompleted(LPCOLESTR pwszFile)
  886. {
  887. return S_OK;
  888. }
  889. HRESULT CScrapData::GetCurFile(LPOLESTR *lplpszFileName)
  890. {
  891. return E_NOTIMPL; // nobody needs it
  892. }
  893. HRESULT CScrapData_CreateInstance(LPUNKNOWN * ppunk)
  894. {
  895. //
  896. // This test code is unrelated to the scrap itself. It just verifies that
  897. // CLSID_ShellLink is correctly registered.
  898. //
  899. #ifdef DEBUG
  900. LPUNKNOWN punk = NULL;
  901. HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
  902. CLSCTX_INPROC, IID_IShellLink, (LPVOID*)&punk);
  903. DebugMsg(DM_TRACE, TEXT("###############################################"));
  904. DebugMsg(DM_TRACE, TEXT("CoCreateInstance returned %x"), hres);
  905. DebugMsg(DM_TRACE, TEXT("###############################################"));
  906. if (SUCCEEDED(hres)) {
  907. punk->Release();
  908. }
  909. #endif
  910. CScrapData* pscd = new CScrapData();
  911. if (pscd) {
  912. *ppunk = (LPDATAOBJECT)pscd;
  913. return S_OK;
  914. }
  915. return E_OUTOFMEMORY;
  916. }