Leaked source code of windows server 2003
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.

1297 lines
41 KiB

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