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.

1301 lines
39 KiB

  1. #include "shole.h"
  2. #include "ids.h"
  3. #define INITGUID
  4. #include <initguid.h>
  5. #include "scguid.h"
  6. // #define SAVE_OBJECTDESCRIPTOR
  7. extern "C" const WCHAR c_wszDescriptor[];
  8. CLIPFORMAT _GetClipboardFormat(UINT id)
  9. {
  10. static UINT s_acf[CFID_MAX] = { 0 };
  11. static const TCHAR * const c_aszFormat[CFID_MAX] = {
  12. TEXT("Embedded Object"),
  13. TEXT("Object Descriptor"),
  14. TEXT("Link Source Descriptor"),
  15. TEXT("Rich Text Format"),
  16. TEXT("Shell Scrap Object"),
  17. TEXT("TargetCLSID"),
  18. TEXT("Rich Text Format"),
  19. };
  20. if (!s_acf[id])
  21. {
  22. s_acf[id] = RegisterClipboardFormat(c_aszFormat[id]);
  23. }
  24. return (CLIPFORMAT)s_acf[id];
  25. }
  26. //===========================================================================
  27. // CScrapData : Class definition
  28. //===========================================================================
  29. class CScrapData : public IDataObject, public IPersistFile
  30. #ifdef FEATURE_SHELLEXTENSION
  31. , public IExtractIcon
  32. #ifdef UNICODE
  33. , public IExtractIconA
  34. #endif // UNICODE
  35. #endif // FEATURE_SHELLEXTENSION
  36. {
  37. public:
  38. CScrapData();
  39. ~CScrapData();
  40. // IUnKnown
  41. virtual HRESULT __stdcall QueryInterface(REFIID,void **);
  42. virtual ULONG __stdcall AddRef(void);
  43. virtual ULONG __stdcall Release(void);
  44. // IDataObject
  45. virtual HRESULT __stdcall GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
  46. virtual HRESULT __stdcall GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
  47. virtual HRESULT __stdcall QueryGetData(FORMATETC *pformatetc);
  48. virtual HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut);
  49. virtual HRESULT __stdcall SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
  50. virtual HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
  51. virtual HRESULT __stdcall DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
  52. virtual HRESULT __stdcall DUnadvise(DWORD dwConnection);
  53. virtual HRESULT __stdcall EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
  54. virtual HRESULT __stdcall IsDirty(void);
  55. #ifdef FEATURE_SHELLEXTENSION
  56. // IExtractIcon
  57. virtual HRESULT __stdcall GetIconLocation(
  58. UINT uFlags, LPTSTR szIconFile,
  59. UINT cchMax, int *piIndex, UINT *pwFlags);
  60. virtual HRESULT __stdcall Extract(
  61. LPCTSTR pszFile, UINT nIconIndex,
  62. HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize);
  63. #ifdef UNICODE
  64. // IExtractIconA
  65. virtual HRESULT __stdcall GetIconLocation(
  66. UINT uFlags, LPSTR szIconFile,
  67. UINT cchMax, int *piIndex, UINT *pwFlags);
  68. virtual HRESULT __stdcall Extract(
  69. LPCSTR pszFile, UINT nIconIndex,
  70. HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize);
  71. #endif // UNICODE
  72. #endif // FEATURE_SHELLEXTENSION
  73. // IPersistFile
  74. virtual HRESULT __stdcall GetClassID(CLSID *pClassID);
  75. virtual HRESULT __stdcall Load(LPCOLESTR pszFileName, DWORD dwMode);
  76. virtual HRESULT __stdcall Save(LPCOLESTR pszFileName, BOOL fRemember);
  77. virtual HRESULT __stdcall SaveCompleted(LPCOLESTR pszFileName);
  78. virtual HRESULT __stdcall GetCurFile(LPOLESTR *ppszFileName);
  79. protected:
  80. HRESULT _OpenStorage(void);
  81. void _CloseStorage(BOOL fResetFlags);
  82. INT _GetFormatIndex(UINT cf);
  83. void _FillCFArray(void);
  84. #ifdef FIX_ROUNDTRIP
  85. HRESULT _RunObject(void);
  86. #endif // FIX_ROUNDTRIP
  87. #ifdef SAVE_OBJECTDESCRIPTOR
  88. HRESULT _GetObjectDescriptor(LPSTGMEDIUM pmedium, BOOL fGetHere);
  89. #endif // SAVE_OBJECTDESCRIPTOR
  90. UINT _cRef;
  91. BOOL _fDoc:1;
  92. BOOL _fItem:1;
  93. BOOL _fObjDesc:1;
  94. BOOL _fClsidTarget:1;
  95. #ifdef FIX_ROUNDTRIP
  96. BOOL _fRunObjectAlreadyCalled:1;
  97. LPDATAOBJECT _pdtobjItem;
  98. #endif // FIX_ROUNDTRIP
  99. LPSTORAGE _pstgDoc;
  100. LPSTORAGE _pstgItem;
  101. LPSTREAM _pstmObjDesc;
  102. TCHAR _szPath[MAX_PATH];
  103. CLSID _clsidTarget;
  104. INT _ccf; // number of clipboard format.
  105. INT _icfCacheMax; // Max cache format index
  106. DWORD _acf[64]; // 64 must be enough!
  107. };
  108. //===========================================================================
  109. // CScrapData : Constructor
  110. //===========================================================================
  111. CScrapData::CScrapData(void) : _cRef(1)
  112. {
  113. ASSERT(_pstgDoc == NULL);
  114. ASSERT(_pstgItem == NULL);
  115. ASSERT(_fDoc == FALSE);
  116. ASSERT(_fItem == FALSE);
  117. ASSERT(_fObjDesc == FALSE);
  118. ASSERT(_ccf == 0);
  119. ASSERT(_fClsidTarget == FALSE);
  120. #ifdef FIX_ROUNDTRIP
  121. ASSERT(_pdtobjItem == NULL);
  122. ASSERT(_fRunObjectAlreadyCalled == FALSE);
  123. #endif // FIX_ROUNDTRIP
  124. ASSERT(_pstmObjDesc == NULL);
  125. _szPath[0] = TEXT('\0');
  126. g_cRefThisDll++;
  127. }
  128. CScrapData::~CScrapData()
  129. {
  130. #ifdef FIX_ROUNDTRIP
  131. if (_pdtobjItem) {
  132. _pdtobjItem->Release();
  133. }
  134. #endif // FIX_ROUNDTRIP
  135. _CloseStorage(FALSE);
  136. g_cRefThisDll--;
  137. }
  138. //===========================================================================
  139. // CScrapData : Member functions (private)
  140. //===========================================================================
  141. //
  142. // private member CScrapData::_OpenStorage
  143. //
  144. HRESULT CScrapData::_OpenStorage(void)
  145. {
  146. if (_pstgItem) {
  147. return S_OK;
  148. }
  149. HRESULT hres;
  150. WCHAR wszFile[MAX_PATH];
  151. #ifdef UNICODE
  152. lstrcpyn(wszFile, _szPath, ARRAYSIZE(wszFile));
  153. #ifdef DEBUG
  154. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetStorage is called (%s)"), wszFile);
  155. #endif
  156. #else
  157. MultiByteToWideChar(CP_ACP, 0, _szPath, -1, wszFile, ARRAYSIZE(wszFile));
  158. #ifdef DEBUG
  159. TCHAR szFile[MAX_PATH];
  160. WideCharToMultiByte(CP_ACP, 0, wszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL);
  161. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetStorage is called (%s)"), szFile);
  162. #endif
  163. #endif
  164. hres = StgOpenStorage(wszFile, NULL,
  165. STGM_READ | STGM_SHARE_DENY_WRITE,
  166. NULL, 0, &_pstgDoc);
  167. if (SUCCEEDED(hres))
  168. {
  169. _fDoc = TRUE;
  170. hres = _pstgDoc->OpenStorage(c_wszContents, NULL,
  171. STGM_READ | STGM_SHARE_EXCLUSIVE,
  172. NULL, 0, &_pstgItem);
  173. if (SUCCEEDED(hres))
  174. {
  175. HRESULT hresT;
  176. _fItem = TRUE;
  177. #ifdef SAVE_OBJECTDESCRIPTOR
  178. hresT = _pstgDoc->OpenStream(c_wszDescriptor, 0,
  179. STGM_READ | STGM_SHARE_EXCLUSIVE,
  180. 0, &_pstmObjDesc);
  181. _fObjDesc = SUCCEEDED(hresT);
  182. #endif // SAVE_OBJECTDESCRIPTOR
  183. }
  184. else
  185. {
  186. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage _pstgDoc->OpenStorage failed (%x)"), hres);
  187. _pstgDoc->Release();
  188. _pstgDoc = NULL;
  189. }
  190. }
  191. else
  192. {
  193. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage StgOpenStorage failed (%x)"), hres);
  194. }
  195. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_OpenStorage _pstgDoc->OpenStorage returning (%x) %x"),
  196. hres, _pstmObjDesc);
  197. return hres;
  198. }
  199. void CScrapData::_CloseStorage(BOOL fResetFlags)
  200. {
  201. #ifdef DEBUG
  202. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::CloseStorage"));
  203. #endif
  204. if (_pstgItem) {
  205. _pstgItem->Release();
  206. _pstgItem = NULL;
  207. }
  208. if (_pstmObjDesc) {
  209. _pstmObjDesc->Release();
  210. _pstmObjDesc = NULL;
  211. }
  212. if (_pstgDoc) {
  213. _pstgDoc->Release();
  214. _pstgDoc = NULL;
  215. }
  216. if (fResetFlags) {
  217. _fItem = FALSE;
  218. _fObjDesc = FALSE;
  219. _fDoc = FALSE;
  220. }
  221. }
  222. INT CScrapData::_GetFormatIndex(UINT cf)
  223. {
  224. for (INT i=0; i<_ccf; i++)
  225. {
  226. if (_acf[i] == cf)
  227. {
  228. return i;
  229. }
  230. }
  231. return -1;
  232. }
  233. #ifdef FIX_ROUNDTRIP
  234. extern "C" const TCHAR c_szRenderFMT[] = TEXT("DataFormats\\DelayRenderFormats");
  235. #endif // FIX_ROUNDTRIP
  236. extern "C" const WCHAR c_wszFormatNames[];
  237. //
  238. // This function filles the clipboard format array (_acf). Following
  239. // clipboard format may be added.
  240. //
  241. // Step 1. CF_EMBEEDEDOBJECT
  242. // Step 2. CF_OBJECTDESCRIPTOR
  243. // Step 3. CF_SCRAPOBJECT
  244. // Step 4. Cached clipboard formats (from a stream).
  245. // Step 5. Delay Rendered clipbaord formats (from registry).
  246. //
  247. void CScrapData::_FillCFArray(void)
  248. {
  249. _ccf=0;
  250. //
  251. // Step 1.
  252. //
  253. if (_fItem) {
  254. _acf[_ccf++] = CF_EMBEDDEDOBJECT;
  255. }
  256. //
  257. // Step 2.
  258. //
  259. if (_fObjDesc) {
  260. _acf[_ccf++] = CF_OBJECTDESCRIPTOR;
  261. }
  262. //
  263. // Step 3.
  264. //
  265. if (_fDoc)
  266. {
  267. _acf[_ccf++] = CF_SCRAPOBJECT;
  268. }
  269. #ifdef FIX_ROUNDTRIP
  270. HRESULT hres = _OpenStorage();
  271. if (SUCCEEDED(hres) && _pstgItem)
  272. {
  273. //
  274. // Step 3. Cached clipboard formats
  275. //
  276. //
  277. // Open the stream which contains the names of cached formats.
  278. //
  279. LPSTREAM pstm;
  280. HRESULT hres = _pstgDoc->OpenStream(c_wszFormatNames, NULL,
  281. STGM_READ | STGM_SHARE_EXCLUSIVE,
  282. NULL, &pstm);
  283. if (SUCCEEDED(hres))
  284. {
  285. //
  286. // For each cached format...
  287. //
  288. USHORT cb;
  289. DWORD cbRead;
  290. while(SUCCEEDED(pstm->Read(&cb, SIZEOF(cb), &cbRead)) && cbRead==SIZEOF(cb)
  291. && cb && cb<128)
  292. {
  293. UINT cf = 0;
  294. //
  295. // Get the cached clipboard format name
  296. //
  297. CHAR szFormat[128];
  298. szFormat[cb] = '\0';
  299. hres = pstm->Read(szFormat, cb, &cbRead);
  300. if (SUCCEEDED(hres) && cbRead==cb && lstrlenA(szFormat)==cb)
  301. {
  302. //
  303. // Append it to the array.
  304. //
  305. #ifdef UNICODE
  306. TCHAR wszFormat[128];
  307. MultiByteToWideChar(CP_ACP, 0,
  308. szFormat, -1,
  309. wszFormat, ARRAYSIZE(wszFormat));
  310. DebugMsg(DM_TRACE, TEXT("sc TR _FillCFA Found Cached Format %s"), wszFormat);
  311. #else
  312. DebugMsg(DM_TRACE, TEXT("sc TR _FillCFA Found Cached Format %s"), szFormat);
  313. #endif
  314. cf = RegisterClipboardFormatA(szFormat);
  315. if (cf)
  316. {
  317. _acf[_ccf++] = cf;
  318. }
  319. }
  320. else
  321. {
  322. break;
  323. }
  324. }
  325. pstm->Release();
  326. }
  327. _icfCacheMax = _ccf;
  328. //
  329. // Step 4. Get the list of delay-rendered clipboard formats
  330. //
  331. LPPERSISTSTORAGE pps;
  332. hres = OleLoad(_pstgItem, IID_IPersistStorage, NULL, (LPVOID *)&pps);
  333. if (SUCCEEDED(hres))
  334. {
  335. //
  336. // Get the CLSID of embedding.
  337. //
  338. CLSID clsid;
  339. hres = pps->GetClassID(&clsid);
  340. if (SUCCEEDED(hres))
  341. {
  342. //
  343. // Open the key for delay-rendered format names.
  344. //
  345. extern HKEY _OpenCLSIDKey(REFCLSID rclsid, LPCTSTR pszSubKey);
  346. HKEY hkey = _OpenCLSIDKey(clsid, c_szRenderFMT);
  347. if (hkey)
  348. {
  349. TCHAR szValueName[128];
  350. //
  351. // For each delay-rendered clipboard format...
  352. //
  353. for(int iValue=0; ;iValue++)
  354. {
  355. //
  356. // Get the value name, which is the format name.
  357. //
  358. DWORD cchValueName = ARRAYSIZE(szValueName);
  359. DWORD dwType;
  360. if (RegEnumValue(hkey, iValue, szValueName, &cchValueName, NULL,
  361. &dwType, NULL, NULL)==ERROR_SUCCESS)
  362. {
  363. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_FillCFA RegEnumValue found %s, %x"), szValueName, dwType);
  364. UINT cf = RegisterClipboardFormat(szValueName);
  365. if (cf)
  366. {
  367. _acf[_ccf++] = cf;
  368. }
  369. }
  370. else
  371. {
  372. break;
  373. }
  374. }
  375. //
  376. // HACK: NT 3.5's regedit does not support named value...
  377. //
  378. for(iValue=0; ;iValue++)
  379. {
  380. TCHAR szKeyName[128];
  381. //
  382. // Get the value name, which is the format name.
  383. //
  384. if (RegEnumKey(hkey, iValue, szKeyName, ARRAYSIZE(szKeyName))==ERROR_SUCCESS)
  385. {
  386. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_FillCFA RegEnumValue found %s"), szValueName);
  387. LONG cbValue = ARRAYSIZE(szValueName);
  388. if ((RegQueryValue(hkey, szKeyName, szValueName, &cbValue)==ERROR_SUCCESS) && cbValue)
  389. {
  390. UINT cf = RegisterClipboardFormat(szValueName);
  391. if (cf)
  392. {
  393. _acf[_ccf++] = cf;
  394. }
  395. }
  396. }
  397. else
  398. {
  399. break;
  400. }
  401. }
  402. RegCloseKey(hkey);
  403. }
  404. }
  405. pps->Release();
  406. }
  407. }
  408. #endif // FIX_ROUNDTRIP
  409. }
  410. #ifdef FIX_ROUNDTRIP
  411. //
  412. // private member CScrapData::_RunObject
  413. //
  414. HRESULT CScrapData::_RunObject(void)
  415. {
  416. if (_pdtobjItem) {
  417. return S_OK;
  418. }
  419. if (_fRunObjectAlreadyCalled) {
  420. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject returning E_FAIL"));
  421. return E_FAIL;
  422. }
  423. _fRunObjectAlreadyCalled = TRUE;
  424. HRESULT hres = _OpenStorage();
  425. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject _OpenStorage returned %x"), hres);
  426. if (SUCCEEDED(hres) && _pstgItem)
  427. {
  428. LPOLEOBJECT pole;
  429. hres = OleLoad(_pstgItem, IID_IOleObject, NULL, (LPVOID *)&pole);
  430. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject OleLoad returned %x"), hres);
  431. if (SUCCEEDED(hres))
  432. {
  433. DWORD dw=GetCurrentTime();
  434. hres = OleRun(pole);
  435. dw = GetCurrentTime()-dw;
  436. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject OleRun returned %x (%d msec)"), hres, dw);
  437. if (SUCCEEDED(hres))
  438. {
  439. hres = pole->GetClipboardData(0, &_pdtobjItem);
  440. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject GetClipboardData returned %x"), hres);
  441. if (FAILED(hres))
  442. {
  443. hres = pole->QueryInterface(IID_IDataObject, (LPVOID*)&_pdtobjItem);
  444. DebugMsg(DM_TRACE, TEXT("sc TR CSD::_RunObject QI(IID_IDataIbject) returned %x"), hres);
  445. }
  446. }
  447. pole->Release();
  448. }
  449. }
  450. return hres;
  451. }
  452. #endif // FIX_ROUNDTRIP
  453. //===========================================================================
  454. // CScrapData : Member functions (virtual IDataObject)
  455. //===========================================================================
  456. HRESULT CScrapData::QueryInterface(REFIID riid, LPVOID * ppvObj)
  457. {
  458. if (IsEqualIID(riid, IID_IDataObject) || IsEqualIID(riid, IID_IUnknown))
  459. {
  460. *ppvObj = (LPDATAOBJECT)this;
  461. _cRef++;
  462. return S_OK;
  463. }
  464. else if (IsEqualIID(riid, IID_IExtractIcon))
  465. {
  466. *ppvObj = (IExtractIcon*)this;
  467. _cRef++;
  468. return S_OK;
  469. }
  470. #ifdef UNICODE
  471. else if (IsEqualIID(riid, IID_IExtractIconA))
  472. {
  473. *ppvObj = (IExtractIconA*)this;
  474. _cRef++;
  475. return S_OK;
  476. }
  477. #endif
  478. else if (IsEqualIID(riid, IID_IPersistFile))
  479. {
  480. *ppvObj = (LPPERSISTFILE)this;
  481. _cRef++;
  482. return S_OK;
  483. }
  484. *ppvObj = NULL;
  485. return E_NOINTERFACE;
  486. }
  487. ULONG CScrapData::AddRef()
  488. {
  489. _cRef++;
  490. return _cRef;
  491. }
  492. ULONG CScrapData::Release()
  493. {
  494. _cRef--;
  495. if (_cRef > 0)
  496. return _cRef;
  497. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::Release deleting this object"));
  498. delete this;
  499. return 0;
  500. }
  501. #ifdef SAVE_OBJECTDESCRIPTOR
  502. HRESULT CScrapData::_GetObjectDescriptor(LPSTGMEDIUM pmedium, BOOL fGetHere)
  503. {
  504. if (!_pstmObjDesc)
  505. return DATA_E_FORMATETC;
  506. LARGE_INTEGER dlib = { 0, 0 };
  507. HRESULT hres = _pstmObjDesc->Seek(dlib, STREAM_SEEK_SET, NULL);
  508. if (FAILED(hres))
  509. return hres;
  510. OBJECTDESCRIPTOR ods;
  511. ULONG cbRead;
  512. hres = _pstmObjDesc->Read(&ods.cbSize, SIZEOF(ods.cbSize), &cbRead);
  513. if (SUCCEEDED(hres) && cbRead == SIZEOF(ods.cbSize))
  514. {
  515. if (fGetHere)
  516. {
  517. if (GlobalSize(pmedium->hGlobal)<ods.cbSize) {
  518. hres = STG_E_MEDIUMFULL;
  519. }
  520. }
  521. else
  522. {
  523. pmedium->tymed = TYMED_HGLOBAL;
  524. pmedium->hGlobal = GlobalAlloc(GMEM_MOVEABLE, ods.cbSize);
  525. hres = pmedium->hGlobal ? S_OK : E_OUTOFMEMORY;
  526. }
  527. if (SUCCEEDED(hres))
  528. {
  529. LPOBJECTDESCRIPTOR pods = (LPOBJECTDESCRIPTOR)GlobalLock(pmedium->hGlobal);
  530. if (pods)
  531. {
  532. pods->cbSize = ods.cbSize;
  533. hres = _pstmObjDesc->Read(&pods->clsid, ods.cbSize-SIZEOF(ods.cbSize), NULL);
  534. GlobalUnlock(pmedium->hGlobal);
  535. }
  536. else
  537. {
  538. if (!fGetHere) {
  539. GlobalFree(pmedium->hGlobal);
  540. pmedium->hGlobal = NULL;
  541. }
  542. hres = E_OUTOFMEMORY;
  543. }
  544. }
  545. }
  546. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::_GetObjectDescriptor returning (%x)"), hres);
  547. return hres;
  548. }
  549. #endif // SAVE_OBJECTDESCRIPTOR
  550. HRESULT CScrapData::GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
  551. {
  552. #ifdef DEBUG
  553. if (pformatetcIn->cfFormat<CF_MAX) {
  554. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %x,%x,%x"),
  555. pformatetcIn->cfFormat, pformatetcIn->tymed, pmedium->tymed);
  556. } else {
  557. TCHAR szName[256];
  558. GetClipboardFormatName(pformatetcIn->cfFormat, szName, ARRAYSIZE(szName));
  559. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %s,%x,%x"),
  560. szName, pformatetcIn->tymed, pmedium->tymed);
  561. }
  562. #endif
  563. HRESULT hres;
  564. pmedium->pUnkForRelease = NULL;
  565. pmedium->pstg = NULL;
  566. //
  567. // NOTES: We should avoid calling _OpenStorage if we don't support
  568. // the format.
  569. //
  570. //
  571. // APP COMPAT! Win95/NT4's shscrap.dll had a bug in that it checked
  572. // the pformatetcIn->tymed's wrong. The old scrap code accidentally
  573. // used an equality test instead of a bit test. YOU CANNOT FIX THIS
  574. // BUG! Micrografx Designer relies on it!
  575. //
  576. if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
  577. && (pformatetcIn->tymed == TYMED_ISTORAGE) && _fItem) // INTENTIONAL BUG! (see above)
  578. {
  579. hres = _OpenStorage();
  580. if (SUCCEEDED(hres))
  581. {
  582. pmedium->tymed = TYMED_ISTORAGE;
  583. _pstgItem->AddRef();
  584. pmedium->pstg = _pstgItem;
  585. }
  586. }
  587. else if (pformatetcIn->cfFormat == CF_SCRAPOBJECT
  588. && (pformatetcIn->tymed == TYMED_ISTORAGE) && _fItem) // INTENTIONAL BUG! (see above)
  589. {
  590. hres = _OpenStorage();
  591. if (SUCCEEDED(hres))
  592. {
  593. pmedium->tymed = TYMED_ISTORAGE;
  594. _pstgDoc->AddRef();
  595. pmedium->pstg = _pstgDoc;
  596. }
  597. }
  598. #ifdef SAVE_OBJECTDESCRIPTOR
  599. else if (pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR
  600. && (pformatetcIn->tymed == TYMED_HGLOBAL) && _fObjDesc) // INTENTIONAL BUG! (see above)
  601. {
  602. hres = _OpenStorage();
  603. if (SUCCEEDED(hres))
  604. {
  605. hres = _GetObjectDescriptor(pmedium, FALSE);
  606. }
  607. }
  608. #endif // SAVE_OBJECTDESCRIPTOR
  609. else if (pformatetcIn->cfFormat == CF_TARGETCLSID
  610. && (pformatetcIn->tymed & TYMED_HGLOBAL) && _fClsidTarget)
  611. {
  612. pmedium->hGlobal = GlobalAlloc(GPTR, sizeof(_clsidTarget));
  613. if (pmedium->hGlobal)
  614. {
  615. CopyMemory(pmedium->hGlobal, &_clsidTarget, sizeof(_clsidTarget));
  616. pmedium->tymed = TYMED_HGLOBAL;
  617. hres = S_OK;
  618. }
  619. else
  620. hres = E_OUTOFMEMORY;
  621. }
  622. else
  623. {
  624. #ifdef FIX_ROUNDTRIP
  625. INT iFmt = _GetFormatIndex(pformatetcIn->cfFormat);
  626. if (iFmt != -1)
  627. {
  628. hres = _OpenStorage();
  629. if (FAILED(hres))
  630. {
  631. goto exit;
  632. }
  633. }
  634. if (iFmt>=_icfCacheMax)
  635. {
  636. //
  637. // Delayed Rendered format
  638. //
  639. if (SUCCEEDED(_RunObject()))
  640. {
  641. hres = _pdtobjItem->GetData(pformatetcIn, pmedium);
  642. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called _pdtobjItem->GetData %x"), hres);
  643. return hres;
  644. }
  645. }
  646. else if (iFmt >= 0)
  647. {
  648. //
  649. // Cached Format
  650. //
  651. extern void _GetCacheStreamName(LPCTSTR pszFormat, LPWSTR wszStreamName, UINT cchMax);
  652. TCHAR szFormat[128];
  653. if (pformatetcIn->cfFormat<CF_MAX) {
  654. wsprintf(szFormat, TEXT("#%d"), pformatetcIn->cfFormat);
  655. } else {
  656. GetClipboardFormatName(pformatetcIn->cfFormat, szFormat, ARRAYSIZE(szFormat));
  657. }
  658. WCHAR wszStreamName[256];
  659. _GetCacheStreamName(szFormat, wszStreamName, ARRAYSIZE(wszStreamName));
  660. if (pformatetcIn->cfFormat==CF_METAFILEPICT
  661. || pformatetcIn->cfFormat==CF_ENHMETAFILE
  662. || pformatetcIn->cfFormat==CF_BITMAP
  663. || pformatetcIn->cfFormat==CF_PALETTE
  664. )
  665. {
  666. LPSTORAGE pstg;
  667. hres = _pstgDoc->OpenStorage(wszStreamName, NULL,
  668. STGM_READ | STGM_SHARE_EXCLUSIVE,
  669. NULL, 0, &pstg);
  670. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData OpenStorage returned (%x)"), hres);
  671. if (SUCCEEDED(hres))
  672. {
  673. LPDATAOBJECT pdtobj;
  674. #if 0
  675. hres = OleLoad(pstg, IID_IDataObject, NULL, (LPVOID*)&pdtobj);
  676. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData OleLoad returned (%x)"), hres);
  677. #else
  678. const CLSID* pclsid = NULL;
  679. switch(pformatetcIn->cfFormat)
  680. {
  681. case CF_METAFILEPICT:
  682. pclsid = &CLSID_Picture_Metafile;
  683. break;
  684. case CF_ENHMETAFILE:
  685. pclsid = &CLSID_Picture_EnhMetafile;
  686. break;
  687. case CF_PALETTE:
  688. case CF_BITMAP:
  689. pclsid = &CLSID_Picture_Dib;
  690. break;
  691. }
  692. LPPERSISTSTORAGE ppstg;
  693. hres = OleCreateDefaultHandler(*pclsid, NULL, IID_IPersistStorage, (LPVOID *)&ppstg);
  694. DebugMsg(DM_TRACE, TEXT("sc TR Scrap_CacheOPF OleCreteDefHandler returned %x"), hres);
  695. if (SUCCEEDED(hres))
  696. {
  697. hres = ppstg->Load(pstg);
  698. DebugMsg(DM_TRACE, TEXT("sc TR Scrap_CacheOPF ppstg->Load returned %x"), hres);
  699. if (SUCCEEDED(hres))
  700. {
  701. hres = ppstg->QueryInterface(IID_IDataObject, (LPVOID*)&pdtobj);
  702. }
  703. }
  704. #endif
  705. if (SUCCEEDED(hres))
  706. {
  707. hres = pdtobj->GetData(pformatetcIn, pmedium);
  708. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData pobj->GetData returned (%x)"), hres);
  709. pdtobj->Release();
  710. }
  711. // Must defer HandsOffStorage until after GetData
  712. // or the GetData will fail! And in fact, even if we defer
  713. // it, the GetData *still* fails. And if we don't call
  714. // HandsOffStorage at all, THE GETDATA STILL FAILS.
  715. // Bug 314308, OLE regression.
  716. // I'm checking in at least this part of the fix so the OLE
  717. // folks can debug it on their side.
  718. if (ppstg)
  719. {
  720. ppstg->HandsOffStorage();
  721. ppstg->Release();
  722. }
  723. pstg->Release();
  724. return hres;
  725. }
  726. // fall through
  727. }
  728. else // if (pformatetcIn->cfFormat==CF_...)
  729. {
  730. LPSTREAM pstm;
  731. hres = _pstgDoc->OpenStream(wszStreamName, NULL,
  732. STGM_READ | STGM_SHARE_EXCLUSIVE,
  733. 0, &pstm);
  734. if (SUCCEEDED(hres))
  735. {
  736. UINT cbData;
  737. DWORD cbRead;
  738. hres = pstm->Read(&cbData, SIZEOF(cbData), &cbRead);
  739. if (SUCCEEDED(hres) && cbRead==SIZEOF(cbData))
  740. {
  741. LPBYTE pData = (LPBYTE)GlobalAlloc(GPTR, cbData);
  742. if (pData)
  743. {
  744. hres = pstm->Read(pData, cbData, &cbRead);
  745. if (SUCCEEDED(hres) && cbData==cbRead)
  746. {
  747. pmedium->tymed = TYMED_HGLOBAL;
  748. pmedium->hGlobal = (HGLOBAL)pData;
  749. }
  750. else
  751. {
  752. hres = E_UNEXPECTED;
  753. GlobalFree((HGLOBAL)pData);
  754. }
  755. }
  756. else
  757. {
  758. hres = E_OUTOFMEMORY;
  759. }
  760. }
  761. pstm->Release();
  762. DebugMsg(DM_TRACE, TEXT("CSD::GetData(%s) returning %x"), szFormat, hres);
  763. return hres;
  764. }
  765. }
  766. } // if (iFmt >= 0)
  767. #endif // FIX_ROUNDTRIP
  768. hres = DATA_E_FORMATETC;
  769. }
  770. exit:
  771. #ifdef DEBUG
  772. TCHAR szFormat[256];
  773. GetClipboardFormatName(pformatetcIn->cfFormat,
  774. szFormat, ARRAYSIZE(szFormat));
  775. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetData called with %x,%x,%s and returning %x"),
  776. pformatetcIn->cfFormat,
  777. pformatetcIn->tymed,
  778. szFormat, hres);
  779. #endif
  780. return hres;
  781. }
  782. HRESULT CScrapData::GetDataHere(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium )
  783. {
  784. HRESULT hres;
  785. #ifdef DEBUG
  786. if (pformatetcIn->cfFormat<CF_MAX) {
  787. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere called with %x,%x,%x"),
  788. pformatetcIn->cfFormat, pformatetcIn->tymed, pmedium->tymed);
  789. } else {
  790. TCHAR szName[256];
  791. GetClipboardFormatName(pformatetcIn->cfFormat, szName, ARRAYSIZE(szName));
  792. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere called with %s,%x,%x"),
  793. szName, pformatetcIn->tymed, pmedium->tymed);
  794. }
  795. #endif
  796. hres = _OpenStorage();
  797. if (FAILED(hres)) {
  798. return hres;
  799. }
  800. if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
  801. && pformatetcIn->tymed == TYMED_ISTORAGE && pmedium->tymed == TYMED_ISTORAGE)
  802. {
  803. hres = _pstgItem->CopyTo(0, NULL, NULL, pmedium->pstg);
  804. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere _pstgItem->CopyTo returned %x"), hres);
  805. }
  806. else if (pformatetcIn->cfFormat == CF_SCRAPOBJECT
  807. && pformatetcIn->tymed == TYMED_ISTORAGE && pmedium->tymed == TYMED_ISTORAGE)
  808. {
  809. hres = _pstgDoc->CopyTo(0, NULL, NULL, pmedium->pstg);
  810. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere _pstgItem->CopyTo returned %x"), hres);
  811. }
  812. #ifdef SAVE_OBJECTDESCRIPTOR
  813. else if ((pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR)
  814. && (pformatetcIn->tymed == TYMED_HGLOBAL) && _pstmObjDesc)
  815. {
  816. hres = _GetObjectDescriptor(pmedium, TRUE);
  817. }
  818. #endif // SAVE_OBJECTDESCRIPTOR
  819. else
  820. {
  821. #ifdef FIX_ROUNDTRIP
  822. if (_GetFormatIndex(pformatetcIn->cfFormat) >= 0 && SUCCEEDED(_RunObject()))
  823. {
  824. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GetDataHere calling _pdtobjItem->GetDataHere"));
  825. return _pdtobjItem->GetDataHere(pformatetcIn, pmedium);
  826. }
  827. #endif // FIX_ROUNDTRIP
  828. hres = DATA_E_FORMATETC;
  829. }
  830. return hres;
  831. }
  832. HRESULT CScrapData::QueryGetData(LPFORMATETC pformatetcIn)
  833. {
  834. HRESULT hres;
  835. if (_GetFormatIndex(pformatetcIn->cfFormat) >= 0) {
  836. hres = S_OK;
  837. } else {
  838. hres = DATA_E_FORMATETC;
  839. }
  840. #ifdef DEBUG
  841. TCHAR szFormat[256] = TEXT("");
  842. GetClipboardFormatName(pformatetcIn->cfFormat, szFormat, ARRAYSIZE(szFormat));
  843. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::QueryGetData(%x,%s,%x) returning %x"),
  844. pformatetcIn->cfFormat, szFormat, pformatetcIn->tymed, hres);
  845. #endif
  846. return hres;
  847. }
  848. HRESULT CScrapData::GetCanonicalFormatEtc(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
  849. {
  850. //
  851. // This is the simplest implemtation. It means we always return
  852. // the data in the format requested.
  853. //
  854. return ResultFromScode(DATA_S_SAMEFORMATETC);
  855. }
  856. HRESULT CScrapData::SetData(LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
  857. {
  858. if (pformatetc->cfFormat == CF_TARGETCLSID && pmedium->tymed == TYMED_HGLOBAL)
  859. {
  860. CLSID *pclsid = (CLSID *)GlobalLock(pmedium->hGlobal);
  861. if (pclsid)
  862. {
  863. _clsidTarget = *pclsid;
  864. _fClsidTarget = TRUE;
  865. GlobalUnlock(pclsid);
  866. if (fRelease) {
  867. ReleaseStgMedium(pmedium);
  868. }
  869. /*
  870. * Whenever anybody sets a drop target, close our storage handles
  871. * so the drop target can move/delete us. All our methods will
  872. * reopen the storage as needed.
  873. */
  874. _CloseStorage(FALSE);
  875. return S_OK;
  876. }
  877. }
  878. return E_FAIL;
  879. }
  880. HRESULT CScrapData::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC * ppenumFormatEtc)
  881. {
  882. if (dwDirection!=DATADIR_GET) {
  883. return E_NOTIMPL; // Not supported (as documented)
  884. }
  885. if (_ccf==0) {
  886. return E_UNEXPECTED;
  887. }
  888. FORMATETC * pfmt = (FORMATETC*)LocalAlloc(LPTR, SIZEOF(FORMATETC)*_ccf);
  889. if (!pfmt) {
  890. return E_OUTOFMEMORY;
  891. }
  892. static const FORMATETC s_fmteInit =
  893. {
  894. 0,
  895. (DVTARGETDEVICE __RPC_FAR *)NULL,
  896. DVASPECT_CONTENT,
  897. -1,
  898. TYMED_HGLOBAL // HGLOBAL except CF_EMBEDDEDOBJECT/SCRAPOBJECT
  899. };
  900. //
  901. // Fills FORMATETC for each clipboard format.
  902. //
  903. for (INT i=0; i<_ccf; i++)
  904. {
  905. pfmt[i] = s_fmteInit;
  906. pfmt[i].cfFormat = (CLIPFORMAT)_acf[i];
  907. if (_acf[i]==CF_EMBEDDEDOBJECT || _acf[i]==CF_SCRAPOBJECT) {
  908. pfmt[i].tymed = TYMED_ISTORAGE;
  909. } else {
  910. switch(_acf[i])
  911. {
  912. case CF_METAFILEPICT:
  913. pfmt[i].tymed = TYMED_MFPICT;
  914. break;
  915. case CF_ENHMETAFILE:
  916. pfmt[i].tymed = TYMED_ENHMF;
  917. break;
  918. case CF_BITMAP:
  919. case CF_PALETTE:
  920. pfmt[i].tymed = TYMED_GDI;
  921. break;
  922. }
  923. }
  924. }
  925. HRESULT hres = SHCreateStdEnumFmtEtc(_ccf, pfmt, ppenumFormatEtc);
  926. LocalFree((HLOCAL)pfmt);
  927. return hres;
  928. }
  929. HRESULT CScrapData::DAdvise(FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection)
  930. {
  931. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  932. }
  933. HRESULT CScrapData::DUnadvise(DWORD dwConnection)
  934. {
  935. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  936. }
  937. HRESULT CScrapData::EnumDAdvise(LPENUMSTATDATA * ppenumAdvise)
  938. {
  939. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  940. }
  941. //===========================================================================
  942. // CScrapData : Member functions (virtual IPersistFile)
  943. //===========================================================================
  944. HRESULT CScrapData::GetClassID(LPCLSID lpClassID)
  945. {
  946. *lpClassID = CLSID_CScrapData;
  947. return S_OK;
  948. }
  949. HRESULT CScrapData::IsDirty(void)
  950. {
  951. return S_FALSE; // meaningless (read only)
  952. }
  953. HRESULT CScrapData::Load(LPCOLESTR pwszFile, DWORD grfMode)
  954. {
  955. //
  956. // Close all the storage (if there is any) and reset flags.
  957. //
  958. _CloseStorage(TRUE);
  959. //
  960. // Copy the new file name and open storage to update the flags.
  961. //
  962. #ifdef UNICODE
  963. lstrcpyn(_szPath, pwszFile, ARRAYSIZE(_szPath));
  964. #else
  965. WideCharToMultiByte(CP_ACP, 0, pwszFile, -1, _szPath, ARRAYSIZE(_szPath), NULL, NULL);
  966. #endif
  967. HRESULT hres = _OpenStorage();
  968. _FillCFArray();
  969. //
  970. // Close all the storage, so that we can move/delete.
  971. //
  972. _CloseStorage(FALSE);
  973. return hres;
  974. }
  975. HRESULT CScrapData::Save(LPCOLESTR pwszFile, BOOL fRemember)
  976. {
  977. return E_FAIL; // read only
  978. }
  979. HRESULT CScrapData::SaveCompleted(LPCOLESTR pwszFile)
  980. {
  981. return S_OK;
  982. }
  983. HRESULT CScrapData::GetCurFile(LPOLESTR *lplpszFileName)
  984. {
  985. return E_NOTIMPL; // nobody needs it
  986. }
  987. #ifdef FEATURE_SHELLEXTENSION
  988. HRESULT CScrapData::GetIconLocation(
  989. UINT uFlags, LPTSTR szIconFile,
  990. UINT cchMax, int * piIndex,
  991. UINT * pwFlags)
  992. {
  993. HRESULT hres = _OpenStorage();
  994. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL OpenStorage returned %x"), hres);
  995. if (SUCCEEDED(hres))
  996. {
  997. STGMEDIUM medium;
  998. hres = _GetObjectDescriptor(&medium, FALSE);
  999. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL _GetOD returned %x"), hres);
  1000. if (SUCCEEDED(hres))
  1001. {
  1002. LPOBJECTDESCRIPTOR pods = (LPOBJECTDESCRIPTOR)GlobalLock(medium.hGlobal);
  1003. TCHAR szKey[128];
  1004. hres = _KeyNameFromCLSID(pods->clsid, szKey, ARRAYSIZE(szKey));
  1005. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL _KNFC returned %x"), hres);
  1006. if (SUCCEEDED(hres))
  1007. {
  1008. lstrcatn(szKey, TEXT("\\DefaultIcon"), ARRAYSIZE(szKey));
  1009. TCHAR szValue[MAX_PATH+40];
  1010. LONG dwSize = sizeof(szValue);
  1011. if (RegQueryValue(HKEY_CLASSES_ROOT, szKey, szValue, &dwSize) == ERROR_SUCCESS)
  1012. {
  1013. *pwFlags = GIL_PERINSTANCE | GIL_NOTFILENAME;
  1014. *piIndex = _ParseIconLocation(szValue);
  1015. TCHAR szT[MAX_PATH];
  1016. wsprintf(szT, TEXT("shscrap.dll,%s"), szValue);
  1017. lstrcpyn(szIconFile, szT, cchMax);
  1018. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL Found Icon Location %s,%d"), szIconFile, *piIndex);
  1019. hres = S_OK;
  1020. }
  1021. else
  1022. {
  1023. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL RegQueryValue for CLSID failed (%s)"), szKey);
  1024. hres = E_FAIL;
  1025. }
  1026. }
  1027. GlobalUnlock(medium.hGlobal);
  1028. ReleaseStgMedium(&medium);
  1029. }
  1030. }
  1031. //
  1032. // If Getting CLSID failed, return a generic scrap icon as per-instance
  1033. // icon to avoid re-opening this file again.
  1034. //
  1035. if (FAILED(hres))
  1036. {
  1037. GetModuleFileName(HINST_THISDLL, szIconFile, cchMax);
  1038. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::GIL Returning default icon (%s)"), szIconFile);
  1039. *piIndex = -IDI_ICON;
  1040. *pwFlags = GIL_PERINSTANCE;
  1041. hres = S_OK;
  1042. }
  1043. return hres; // This value is always S_OK
  1044. }
  1045. #ifdef UNICODE
  1046. HRESULT CScrapData::GetIconLocation(
  1047. UINT uFlags, LPSTR szIconFile,
  1048. UINT cchMax, int * piIndex,
  1049. UINT * pwFlags)
  1050. {
  1051. WCHAR szPath[MAX_PATH];
  1052. HRESULT hr = GetIconLocation(uFlags, szPath, ARRAYSIZE(szPath), piIndex, pwFlags);
  1053. if (SUCCEEDED(hr)) {
  1054. SHUnicodeToAnsi(szPath, szIconFile, cchMax);
  1055. }
  1056. return hr;
  1057. }
  1058. #endif
  1059. #endif // FEATURE_SHELLEXTENSION
  1060. HICON _SimulateScrapIcon(HICON hiconClass, UINT cxIcon)
  1061. {
  1062. //
  1063. // First load the template image.
  1064. //
  1065. HICON hiconTemplate = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_SCRAP),
  1066. IMAGE_ICON, cxIcon, cxIcon, LR_DEFAULTCOLOR);
  1067. if (!hiconTemplate) {
  1068. return NULL;
  1069. }
  1070. ICONINFO ii;
  1071. GetIconInfo(hiconTemplate, &ii);
  1072. HDC hdc = GetDC(NULL);
  1073. HDC hdcMem = CreateCompatibleDC(hdc);
  1074. ReleaseDC(NULL, hdc);
  1075. HBITMAP hbmT = (HBITMAP)SelectObject(hdcMem, ii.hbmColor);
  1076. // This assumes the generic icon is white
  1077. PatBlt(hdcMem, cxIcon/4-1, cxIcon/4-1, cxIcon/2+2, cxIcon/2+2, WHITENESS);
  1078. DrawIconEx(hdcMem, cxIcon/4, cxIcon/4, hiconClass, cxIcon/2, cxIcon/2, 0, NULL, DI_NORMAL);
  1079. SelectObject(hdcMem, hbmT);
  1080. DeleteDC(hdcMem);
  1081. //
  1082. // Create the icon image to return
  1083. //
  1084. ii.fIcon = TRUE;
  1085. ii.xHotspot = 0;
  1086. ii.yHotspot = 0;
  1087. HICON hicon = CreateIconIndirect(&ii);
  1088. DeleteObject(ii.hbmColor);
  1089. DeleteObject(ii.hbmMask);
  1090. return hicon;
  1091. }
  1092. #ifdef FEATURE_SHELLEXTENSION
  1093. HRESULT CScrapData::Extract(
  1094. LPCTSTR pszFile, UINT nIconIndex,
  1095. HICON *phiconLarge, HICON *phiconSmall,
  1096. UINT nIconSize)
  1097. {
  1098. LPCTSTR pszComma = StrChr(pszFile, ',');
  1099. if (pszComma++)
  1100. {
  1101. #if 1
  1102. HICON hiconSmall;
  1103. UINT i = ExtractIconEx(pszComma, nIconIndex, NULL, &hiconSmall, 1);
  1104. if (i != -1)
  1105. {
  1106. if (phiconLarge) {
  1107. *phiconLarge = _SimulateScrapIcon(hiconSmall, LOWORD(nIconSize));
  1108. }
  1109. if (phiconSmall) {
  1110. *phiconSmall = _SimulateScrapIcon(hiconSmall, HIWORD(nIconSize));
  1111. }
  1112. DestroyIcon(hiconSmall);
  1113. }
  1114. #else
  1115. UINT i;
  1116. // Assumes shell icon sizes are def icon sizes
  1117. i = ExtractIconEx(pszComma, nIconIndex, phiconLarge, phiconSmall, 1);
  1118. DebugMsg(DM_TRACE, TEXT("sc TR - CSD::Ext ExtractIconEx(%s) returns %d)"), pszComma, i);
  1119. return S_OK;
  1120. #endif
  1121. }
  1122. return E_INVALIDARG;
  1123. }
  1124. #ifdef UNICODE
  1125. HRESULT CScrapData::Extract(
  1126. LPCSTR pszFile, UINT nIconIndex,
  1127. HICON *phiconLarge, HICON *phiconSmall,
  1128. UINT nIconSize)
  1129. {
  1130. WCHAR szPath[MAX_PATH];
  1131. SHAnsiToUnicode(pszFile, szPath, ARRAYSIZE(szPath));
  1132. return Extract(szPath, nIconIndex, phiconLarge, phiconSmall, nIconSize);
  1133. }
  1134. #endif
  1135. #endif // FEATURE_SHELLEXTENSION
  1136. HRESULT CScrapData_CreateInstance(LPUNKNOWN * ppunk)
  1137. {
  1138. //
  1139. // This test code is unrelated to the scrap itself. It just verifies that
  1140. // CLSID_ShellLink is correctly registered.
  1141. //
  1142. #ifdef DEBUG
  1143. LPUNKNOWN punk = NULL;
  1144. HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
  1145. CLSCTX_INPROC, IID_IShellLink, (LPVOID*)&punk);
  1146. DebugMsg(DM_TRACE, TEXT("###############################################"));
  1147. DebugMsg(DM_TRACE, TEXT("CoCreateInstance returned %x"), hres);
  1148. DebugMsg(DM_TRACE, TEXT("###############################################"));
  1149. if (SUCCEEDED(hres)) {
  1150. punk->Release();
  1151. }
  1152. #endif
  1153. CScrapData* pscd = new CScrapData();
  1154. if (pscd) {
  1155. *ppunk = (LPDATAOBJECT)pscd;
  1156. return S_OK;
  1157. }
  1158. return E_OUTOFMEMORY;
  1159. }