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.

676 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: idldata.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include "fmtetc.h"
  13. #include "idldata.h"
  14. #include "shsemip.h"
  15. CLIPFORMAT CIDLData::m_rgcfGlobal[ICF_MAX] = { CF_HDROP, 0 };
  16. const LARGE_INTEGER CIDLData::m_LargeIntZero;
  17. //
  18. // For those who prefer a function (rather than a ctor) to create an object,
  19. // this static function will return a pointer to the IDataObject interface.
  20. // If the function fails, no object is created.
  21. //
  22. HRESULT
  23. CIDLData::CreateInstance(
  24. IDataObject **ppOut,
  25. LPCITEMIDLIST pidlFolder,
  26. UINT cidl,
  27. LPCITEMIDLIST *apidl,
  28. IShellFolder *psfOwner,
  29. IDataObject *pdtInner
  30. )
  31. {
  32. CIDLData *pidlData;
  33. HRESULT hr = CreateInstance(&pidlData, pidlFolder, cidl, apidl, psfOwner, pdtInner);
  34. if (SUCCEEDED(hr))
  35. {
  36. pidlData->AddRef();
  37. hr = pidlData->QueryInterface(IID_IDataObject, (void **)ppOut);
  38. pidlData->Release();
  39. }
  40. else
  41. {
  42. *ppOut = NULL;
  43. }
  44. return hr;
  45. }
  46. //
  47. // For those who prefer a function (rather than a ctor) to create an object,
  48. // this static function will return a pointer to the CIDLData object.
  49. // If the function fails, no object is created. Note that the returned object
  50. // has a ref count of 0. Therefore, it acts as a normal C++ object. If you
  51. // want it to participate as a COM object, QI for IDataObject or use the
  52. // IDataObject version of CreateInstance() above.
  53. //
  54. HRESULT
  55. CIDLData::CreateInstance(
  56. CIDLData **ppOut,
  57. LPCITEMIDLIST pidlFolder,
  58. UINT cidl,
  59. LPCITEMIDLIST *apidl,
  60. IShellFolder *psfOwner,
  61. IDataObject *pdtInner
  62. )
  63. {
  64. HRESULT hr = E_OUTOFMEMORY;
  65. CIDLData *pidlData = new CIDLData(pidlFolder, cidl, apidl, psfOwner, pdtInner);
  66. if (NULL != pidlData)
  67. {
  68. hr = pidlData->CtorResult();
  69. if (SUCCEEDED(hr))
  70. {
  71. *ppOut = pidlData;
  72. }
  73. else
  74. {
  75. delete pidlData;
  76. }
  77. }
  78. return hr;
  79. }
  80. CIDLData::CIDLData(
  81. LPCITEMIDLIST pidlFolder,
  82. UINT cidl,
  83. LPCITEMIDLIST *apidl,
  84. IShellFolder *psfOwner, // Optional. Default is NULL.
  85. IDataObject *pdtobjInner // Optional. Default is NULL.
  86. ) : m_cRef(0),
  87. m_hrCtor(NOERROR),
  88. m_psfOwner(NULL),
  89. m_dwOwnerData(0),
  90. m_pdtobjInner(pdtobjInner),
  91. m_bEnumFormatCalled(false)
  92. {
  93. //
  94. // Initialize the global clipboard formats.
  95. //
  96. InitializeClipboardFormats();
  97. ZeroMemory(m_rgMedium, sizeof(m_rgMedium));
  98. ZeroMemory(m_rgFmtEtc, sizeof(m_rgFmtEtc));
  99. if (NULL != m_pdtobjInner)
  100. m_pdtobjInner->AddRef();
  101. //
  102. // Empty array is valid input.
  103. //
  104. if (NULL != apidl)
  105. {
  106. HIDA hida = HIDA_Create(pidlFolder, cidl, apidl);
  107. if (NULL != hida)
  108. {
  109. m_hrCtor = DataObject_SetGlobal(static_cast<IDataObject *>(this), g_cfHIDA, hida);
  110. if (SUCCEEDED(m_hrCtor))
  111. {
  112. if (NULL != psfOwner)
  113. {
  114. m_psfOwner = psfOwner;
  115. m_psfOwner->AddRef();
  116. }
  117. }
  118. }
  119. else
  120. {
  121. m_hrCtor = E_OUTOFMEMORY;
  122. }
  123. }
  124. }
  125. CIDLData::~CIDLData(
  126. void
  127. )
  128. {
  129. for (int i = 0; i < ARRAYSIZE(m_rgMedium); i++)
  130. {
  131. if (m_rgMedium[i].hGlobal)
  132. ReleaseStgMedium(&(m_rgMedium[i]));
  133. }
  134. if (NULL != m_psfOwner)
  135. m_psfOwner->Release();
  136. if (NULL != m_pdtobjInner)
  137. m_pdtobjInner->Release();
  138. }
  139. STDMETHODIMP
  140. CIDLData::QueryInterface(
  141. REFIID riid,
  142. void **ppv
  143. )
  144. {
  145. static const QITAB qit[] = {
  146. QITABENT(CIDLData, IDataObject),
  147. { 0 },
  148. };
  149. return QISearch(this, qit, riid, ppv);
  150. }
  151. STDMETHODIMP_(ULONG)
  152. CIDLData::AddRef(
  153. void
  154. )
  155. {
  156. return InterlockedIncrement(&m_cRef);
  157. }
  158. STDMETHODIMP_(ULONG)
  159. CIDLData::Release(
  160. void
  161. )
  162. {
  163. if (InterlockedDecrement(&m_cRef))
  164. return m_cRef;
  165. delete this;
  166. return 0;
  167. }
  168. HRESULT
  169. CIDLData::GetData(
  170. FORMATETC *pFmtEtc,
  171. STGMEDIUM *pMedium
  172. )
  173. {
  174. HRESULT hr = E_INVALIDARG;
  175. pMedium->hGlobal = NULL;
  176. pMedium->pUnkForRelease = NULL;
  177. for (int i = 0; i < ARRAYSIZE(m_rgFmtEtc); i++)
  178. {
  179. if ((m_rgFmtEtc[i].cfFormat == pFmtEtc->cfFormat) &&
  180. (m_rgFmtEtc[i].tymed & pFmtEtc->tymed) &&
  181. (m_rgFmtEtc[i].dwAspect == pFmtEtc->dwAspect))
  182. {
  183. *pMedium = m_rgMedium[i];
  184. if (NULL != pMedium->hGlobal)
  185. {
  186. //
  187. // Indicate that the caller should not release hmem.
  188. //
  189. if (TYMED_HGLOBAL == pMedium->tymed)
  190. {
  191. InterlockedIncrement(&m_cRef);
  192. pMedium->pUnkForRelease = static_cast<IUnknown *>(this);
  193. return S_OK;
  194. }
  195. //
  196. // If the type is stream then clone the stream.
  197. //
  198. if (TYMED_ISTREAM == pMedium->tymed)
  199. {
  200. hr = CreateStreamOnHGlobal(NULL, TRUE, &(pMedium->pstm));
  201. if (SUCCEEDED(hr))
  202. {
  203. STGMEDIUM& medium = m_rgMedium[i];
  204. STATSTG stat;
  205. //
  206. // Get the Current Stream size
  207. //
  208. hr = medium.pstm->Stat(&stat, STATFLAG_NONAME);
  209. if (SUCCEEDED(hr))
  210. {
  211. //
  212. // Seek the source stream to the beginning.
  213. //
  214. medium.pstm->Seek(m_LargeIntZero, STREAM_SEEK_SET, NULL);
  215. //
  216. // Copy the entire source into the destination.
  217. // Since the destination stream is created using CreateStreamOnHGlobal,
  218. // it seek pointer is at the beginning.
  219. //
  220. hr = medium.pstm->CopyTo(pMedium->pstm, stat.cbSize, NULL, NULL);
  221. //
  222. // Before returning Set the destination seek pointer back at the beginning.
  223. //
  224. pMedium->pstm->Seek(m_LargeIntZero, STREAM_SEEK_SET, NULL);
  225. return hr;
  226. }
  227. else
  228. {
  229. hr = E_OUTOFMEMORY;
  230. }
  231. }
  232. }
  233. }
  234. }
  235. }
  236. if (E_INVALIDARG == hr && NULL != m_pdtobjInner)
  237. {
  238. hr = m_pdtobjInner->GetData(pFmtEtc, pMedium);
  239. }
  240. return hr;
  241. }
  242. STDMETHODIMP
  243. CIDLData::GetDataHere(
  244. FORMATETC *pFmtEtc,
  245. STGMEDIUM *pMedium
  246. )
  247. {
  248. HRESULT hr = E_NOTIMPL;
  249. if (NULL != m_pdtobjInner)
  250. {
  251. hr = m_pdtobjInner->GetDataHere(pFmtEtc, pMedium);
  252. }
  253. return hr;
  254. }
  255. HRESULT
  256. CIDLData::QueryGetData(
  257. FORMATETC *pFmtEtc
  258. )
  259. {
  260. HRESULT hr = S_FALSE;
  261. for (int i = 0; i < ARRAYSIZE(m_rgFmtEtc); i++)
  262. {
  263. if ((m_rgFmtEtc[i].cfFormat == pFmtEtc->cfFormat) &&
  264. (m_rgFmtEtc[i].tymed & pFmtEtc->tymed) &&
  265. (m_rgFmtEtc[i].dwAspect == pFmtEtc->dwAspect))
  266. {
  267. return S_OK;
  268. }
  269. }
  270. if (NULL != m_pdtobjInner)
  271. {
  272. hr = m_pdtobjInner->QueryGetData(pFmtEtc);
  273. }
  274. return hr;
  275. }
  276. STDMETHODIMP
  277. CIDLData::GetCanonicalFormatEtc(
  278. FORMATETC *pFmtEtcIn,
  279. FORMATETC *pFmtEtcOut
  280. )
  281. {
  282. //
  283. // This is the simplest implemtation. It means we always return
  284. // the data in the format requested.
  285. //
  286. return DATA_S_SAMEFORMATETC;
  287. }
  288. STDMETHODIMP
  289. CIDLData::SetData(
  290. FORMATETC *pFmtEtc,
  291. STGMEDIUM *pMedium,
  292. BOOL fRelease
  293. )
  294. {
  295. HRESULT hr;
  296. TraceAssert(pFmtEtc->tymed == pMedium->tymed);
  297. if (fRelease)
  298. {
  299. int i;
  300. //
  301. // First add it if that format is already present
  302. // on a NULL medium (render on demand)
  303. //
  304. for (i = 0; i < ARRAYSIZE(m_rgFmtEtc); i++)
  305. {
  306. if ((m_rgFmtEtc[i].cfFormat == pFmtEtc->cfFormat) &&
  307. (m_rgFmtEtc[i].tymed == pFmtEtc->tymed) &&
  308. (m_rgFmtEtc[i].dwAspect == pFmtEtc->dwAspect))
  309. {
  310. //
  311. // We are simply adding a format, ignore.
  312. //
  313. if (NULL == pMedium->hGlobal)
  314. {
  315. return S_OK;
  316. }
  317. //
  318. // If we are set twice on the same object
  319. //
  320. if (NULL != m_rgMedium[i].hGlobal)
  321. ReleaseStgMedium(&m_rgMedium[i]);
  322. m_rgMedium[i] = *pMedium;
  323. return S_OK;
  324. }
  325. }
  326. //
  327. // now look for a free slot
  328. //
  329. for (i = 0; i < ARRAYSIZE(m_rgFmtEtc); i++)
  330. {
  331. if (0 == m_rgFmtEtc[i].cfFormat)
  332. {
  333. //
  334. // found a free slot
  335. //
  336. m_rgMedium[i] = *pMedium;
  337. m_rgFmtEtc[i] = *pFmtEtc;
  338. return S_OK;
  339. }
  340. }
  341. //
  342. // fixed size table
  343. //
  344. hr = E_OUTOFMEMORY;
  345. }
  346. else
  347. hr = E_INVALIDARG;
  348. return hr;
  349. }
  350. STDMETHODIMP
  351. CIDLData::EnumFormatEtc(
  352. DWORD dwDirection,
  353. LPENUMFORMATETC *ppenumFormatEtc
  354. )
  355. {
  356. HRESULT hr = NOERROR;
  357. //
  358. // If this is the first time, build the format list by calling
  359. // QueryGetData with each clipboard format.
  360. //
  361. if (!m_bEnumFormatCalled)
  362. {
  363. FORMATETC fmte = { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  364. STGMEDIUM medium = { TYMED_HGLOBAL, NULL, NULL };
  365. for (int i = 0; i < ARRAYSIZE(m_rgcfGlobal); i++)
  366. {
  367. fmte.cfFormat = m_rgcfGlobal[i];
  368. if (S_OK == QueryGetData(&fmte))
  369. {
  370. SetData(&fmte, &medium, TRUE);
  371. }
  372. }
  373. m_bEnumFormatCalled = true;
  374. }
  375. //
  376. // Get the number of formatetc
  377. //
  378. UINT cfmt;
  379. for (cfmt = 0; cfmt < ARRAYSIZE(m_rgFmtEtc); cfmt++)
  380. {
  381. if (0 == m_rgFmtEtc[cfmt].cfFormat)
  382. break;
  383. }
  384. /*
  385. return SHCreateStdEnumFmtEtcEx(cfmt, m_rgFmtEtc, m_pdtobjInner, ppenumFormatEtc);
  386. */
  387. CEnumFormatEtc *pEnumFmtEtc = new CEnumFormatEtc(cfmt, m_rgFmtEtc);
  388. if (NULL != pEnumFmtEtc)
  389. {
  390. pEnumFmtEtc->AddRef();
  391. //
  392. // Ask derived classes to add their formats.
  393. //
  394. hr = ProvideFormats(pEnumFmtEtc);
  395. if (SUCCEEDED(hr))
  396. {
  397. hr = pEnumFmtEtc->QueryInterface(IID_IEnumFORMATETC, (void **)ppenumFormatEtc);
  398. }
  399. pEnumFmtEtc->Release();
  400. }
  401. else
  402. hr = E_OUTOFMEMORY;
  403. return hr;
  404. }
  405. HRESULT
  406. CIDLData::ProvideFormats(
  407. CEnumFormatEtc *pEnumFmtEtc
  408. )
  409. {
  410. //
  411. // Base class default does nothing. Our formats are added to the enumerator
  412. // in EnumFormatEtc().
  413. //
  414. return NOERROR;
  415. }
  416. STDMETHODIMP
  417. CIDLData::DAdvise(
  418. FORMATETC *pFmtEtc,
  419. DWORD advf,
  420. LPADVISESINK pAdvSink,
  421. DWORD *pdwConnection
  422. )
  423. {
  424. return OLE_E_ADVISENOTSUPPORTED;
  425. }
  426. STDMETHODIMP
  427. CIDLData::DUnadvise(
  428. DWORD dwConnection
  429. )
  430. {
  431. return OLE_E_ADVISENOTSUPPORTED;
  432. }
  433. STDMETHODIMP
  434. CIDLData::EnumDAdvise(
  435. LPENUMSTATDATA *ppenumAdvise
  436. )
  437. {
  438. return OLE_E_ADVISENOTSUPPORTED;
  439. }
  440. IShellFolder *
  441. CIDLData::GetFolder(
  442. void
  443. ) const
  444. {
  445. return m_psfOwner;
  446. }
  447. //
  448. // Clone DataObject only for MOVE/COPY operation
  449. //
  450. HRESULT
  451. CIDLData::Clone(
  452. UINT *acf,
  453. UINT ccf,
  454. IDataObject **ppdtobjOut
  455. )
  456. {
  457. HRESULT hr = NOERROR;
  458. CIDLData *pidlData = new CIDLData(NULL, 0, NULL);
  459. if (NULL == pidlData)
  460. {
  461. hr = E_OUTOFMEMORY;
  462. }
  463. else
  464. {
  465. FORMATETC fmte = { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  466. for (UINT i = 0; i < ccf; i++)
  467. {
  468. HRESULT hrT;
  469. STGMEDIUM medium;
  470. fmte.cfFormat = (CLIPFORMAT) acf[i];
  471. hrT = GetData(&fmte, &medium);
  472. if (SUCCEEDED(hrT))
  473. {
  474. HGLOBAL hmem;
  475. if (NULL != medium.pUnkForRelease)
  476. {
  477. //
  478. // We need to clone the hGlobal.
  479. //
  480. SIZE_T cbMem = GlobalSize(medium.hGlobal);
  481. hmem = GlobalAlloc(GPTR, cbMem);
  482. if (NULL != hmem)
  483. {
  484. hmemcpy((LPVOID)hmem, GlobalLock(medium.hGlobal), cbMem);
  485. GlobalUnlock(medium.hGlobal);
  486. }
  487. ReleaseStgMedium(&medium);
  488. }
  489. else
  490. {
  491. //
  492. // We don't need to clone the hGlobal.
  493. //
  494. hmem = medium.hGlobal;
  495. }
  496. if (hmem)
  497. DataObject_SetGlobal(*ppdtobjOut, (CLIPFORMAT)acf[i], hmem);
  498. }
  499. }
  500. }
  501. return hr;
  502. }
  503. HRESULT
  504. CIDLData::CloneForMoveCopy(
  505. IDataObject **ppdtobjOut
  506. )
  507. {
  508. return E_NOTIMPL;
  509. /*
  510. UINT acf[] = { g_cfHIDA, g_cfOFFSETS, CF_HDROP, g_cfFileNameMapW, g_cfFileNameMap };
  511. return Clone(acf, ARRAYSIZE(acf), ppdtobjOut);
  512. */
  513. }
  514. #define RCF(x) (CLIPFORMAT) RegisterClipboardFormat(x)
  515. void
  516. CIDLData::InitializeClipboardFormats(
  517. void
  518. )
  519. {
  520. if (g_cfHIDA == 0)
  521. {
  522. g_cfHIDA = RCF(CFSTR_SHELLIDLIST);
  523. g_cfOFFSETS = RCF(CFSTR_SHELLIDLISTOFFSET);
  524. g_cfNetResource = RCF(CFSTR_NETRESOURCES);
  525. g_cfFileContents = RCF(CFSTR_FILECONTENTS); // "FileContents"
  526. g_cfFileGroupDescriptorA = RCF(CFSTR_FILEDESCRIPTORA); // "FileGroupDescriptor"
  527. g_cfFileGroupDescriptorW = RCF(CFSTR_FILEDESCRIPTORW); // "FileGroupDescriptor"
  528. g_cfPrivateShellData = RCF(CFSTR_SHELLIDLISTP);
  529. g_cfFileName = RCF(CFSTR_FILENAMEA); // "FileName"
  530. g_cfFileNameW = RCF(CFSTR_FILENAMEW); // "FileNameW"
  531. g_cfFileNameMap = RCF(CFSTR_FILENAMEMAP); // "FileNameMap"
  532. g_cfFileNameMapW = RCF(CFSTR_FILENAMEMAPW); // "FileNameMapW"
  533. g_cfPrinterFriendlyName = RCF(CFSTR_PRINTERGROUP);
  534. g_cfHTML = RCF(TEXT("HTML Format"));
  535. g_cfPreferredDropEffect = RCF(CFSTR_PREFERREDDROPEFFECT); // "Preferred DropEffect"
  536. g_cfPerformedDropEffect = RCF(CFSTR_PERFORMEDDROPEFFECT); // "Performed DropEffect"
  537. g_cfLogicalPerformedDropEffect = RCF(CFSTR_LOGICALPERFORMEDDROPEFFECT);
  538. g_cfShellURL = RCF(CFSTR_SHELLURL); // "Uniform Resource Locator"
  539. g_cfInDragLoop = RCF(CFSTR_INDRAGLOOP); // "InShellDragLoop"
  540. g_cfDragContext = RCF(CFSTR_DRAGCONTEXT); // "DragContext"
  541. g_cfTargetCLSID = RCF(TEXT("TargetCLSID")); // who the drag drop went to
  542. }
  543. }
  544. //
  545. // This is normally a private shell function.
  546. //
  547. #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
  548. CIDLData::HIDA
  549. CIDLData::HIDA_Create(
  550. LPCITEMIDLIST pidlFolder,
  551. UINT cidl,
  552. LPCITEMIDLIST *apidl
  553. )
  554. {
  555. HIDA hida;
  556. #if _MSC_VER == 1100
  557. // Workaround code generate bug in VC5 X86 compiler (12/30 version).
  558. volatile
  559. #endif
  560. UINT i;
  561. UINT offset = sizeof(CIDA) + sizeof(UINT)*cidl;
  562. UINT cbTotal = offset + ILGetSize(pidlFolder);
  563. for (i=0; i<cidl ; i++) {
  564. cbTotal += ILGetSize(apidl[i]);
  565. }
  566. hida = GlobalAlloc(GPTR, cbTotal); // This MUST be GlobalAlloc!!!
  567. if (hida)
  568. {
  569. LPIDA pida = (LPIDA)hida; // no need to lock
  570. LPCITEMIDLIST pidlNext;
  571. pida->cidl = cidl;
  572. for (i=0, pidlNext=pidlFolder; ; pidlNext=apidl[i++])
  573. {
  574. UINT cbSize = ILGetSize(pidlNext);
  575. pida->aoffset[i] = offset;
  576. MoveMemory(((LPBYTE)pida)+offset, pidlNext, cbSize);
  577. offset += cbSize;
  578. TraceAssert(ILGetSize(HIDA_GetPIDLItem(pida,i-1)) == cbSize);
  579. if (i==cidl)
  580. break;
  581. }
  582. TraceAssert(offset == cbTotal);
  583. }
  584. return hida;
  585. }