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.

640 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: items.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include <shlwapip.h> // QITAB, QISearch
  13. #include <shsemip.h> // ILFree(), etc
  14. #include "folder.h"
  15. #include "items.h"
  16. #include "strings.h"
  17. CLIPFORMAT COfflineItemsData::m_cfHDROP;
  18. CLIPFORMAT COfflineItemsData::m_cfFileContents;
  19. CLIPFORMAT COfflineItemsData::m_cfFileDesc;
  20. CLIPFORMAT COfflineItemsData::m_cfPreferedEffect;
  21. CLIPFORMAT COfflineItemsData::m_cfPerformedEffect;
  22. CLIPFORMAT COfflineItemsData::m_cfLogicalPerformedEffect;
  23. CLIPFORMAT COfflineItemsData::m_cfDataSrcClsid;
  24. COfflineItemsData::COfflineItemsData(
  25. LPCITEMIDLIST pidlFolder,
  26. UINT cidl,
  27. LPCITEMIDLIST *apidl,
  28. HWND hwndParent,
  29. IShellFolder *psfOwner, // Optional. Default is NULL.
  30. IDataObject *pdtInner // Optional. Default is NULL.
  31. ) : CIDLData(pidlFolder,
  32. cidl,
  33. apidl,
  34. psfOwner,
  35. pdtInner),
  36. m_hwndParent(hwndParent),
  37. m_rgpolid(NULL),
  38. m_hrCtor(NOERROR),
  39. m_dwPreferredEffect(DROPEFFECT_COPY),
  40. m_dwPerformedEffect(DROPEFFECT_NONE),
  41. m_dwLogicalPerformedEffect(DROPEFFECT_NONE),
  42. m_cItems(0)
  43. {
  44. if (0 == m_cfHDROP)
  45. {
  46. m_cfHDROP = CF_HDROP;
  47. m_cfFileContents = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS);
  48. m_cfFileDesc = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
  49. m_cfPreferedEffect = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
  50. m_cfPerformedEffect = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
  51. m_cfLogicalPerformedEffect = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT);
  52. m_cfDataSrcClsid = (CLIPFORMAT)RegisterClipboardFormat(c_szCFDataSrcClsid);
  53. }
  54. m_hrCtor = CIDLData::CtorResult();
  55. if (SUCCEEDED(m_hrCtor))
  56. {
  57. m_rgpolid = new LPCOLID[cidl];
  58. if (m_rgpolid)
  59. {
  60. ZeroMemory(m_rgpolid, sizeof(LPCOLID) * cidl);
  61. m_cItems = cidl;
  62. for (UINT i = 0; i < cidl; i++)
  63. {
  64. m_rgpolid[i] = (LPCOLID)ILClone(apidl[i]);
  65. if (!m_rgpolid[i])
  66. {
  67. m_hrCtor = E_OUTOFMEMORY;
  68. break;
  69. }
  70. }
  71. }
  72. else
  73. m_hrCtor = E_OUTOFMEMORY;
  74. }
  75. }
  76. COfflineItemsData::~COfflineItemsData(
  77. void
  78. )
  79. {
  80. delete[] m_rgpolid;
  81. }
  82. HRESULT
  83. COfflineItemsData::CreateInstance(
  84. COfflineItemsData **ppOut,
  85. LPCITEMIDLIST pidlFolder,
  86. UINT cidl,
  87. LPCITEMIDLIST *apidl,
  88. HWND hwndParent,
  89. IShellFolder *psfOwner,
  90. IDataObject *pdtInner
  91. )
  92. {
  93. HRESULT hr = E_OUTOFMEMORY;
  94. COfflineItemsData *pNew = new COfflineItemsData(pidlFolder,
  95. cidl,
  96. apidl,
  97. hwndParent,
  98. psfOwner,
  99. pdtInner);
  100. if (NULL != pNew)
  101. {
  102. hr = pNew->CtorResult();
  103. if (SUCCEEDED(hr))
  104. *ppOut = pNew;
  105. else
  106. delete pNew;
  107. }
  108. return hr;
  109. }
  110. HRESULT
  111. COfflineItemsData::CreateInstance(
  112. IDataObject **ppOut,
  113. LPCITEMIDLIST pidlFolder,
  114. UINT cidl,
  115. LPCITEMIDLIST *apidl,
  116. HWND hwndParent,
  117. IShellFolder *psfOwner,
  118. IDataObject *pdtInner
  119. )
  120. {
  121. COfflineItemsData *poid;
  122. HRESULT hr = CreateInstance(&poid,
  123. pidlFolder,
  124. cidl,
  125. apidl,
  126. hwndParent,
  127. psfOwner,
  128. pdtInner);
  129. if (SUCCEEDED(hr))
  130. {
  131. poid->AddRef();
  132. hr = poid->QueryInterface(IID_IDataObject, (void **)ppOut);
  133. poid->Release();
  134. }
  135. return hr;
  136. }
  137. HRESULT
  138. COfflineItemsData::GetData(
  139. FORMATETC *pFEIn,
  140. STGMEDIUM *pstm
  141. )
  142. {
  143. HRESULT hr;
  144. pstm->hGlobal = NULL;
  145. pstm->pUnkForRelease = NULL;
  146. if ((pFEIn->cfFormat == m_cfHDROP) && (pFEIn->tymed & TYMED_HGLOBAL))
  147. hr = CreateHDROP(pstm);
  148. else if ((pFEIn->cfFormat == m_cfFileDesc) && (pFEIn->tymed & TYMED_HGLOBAL))
  149. hr = CreateFileDescriptor(pstm);
  150. else if ((pFEIn->cfFormat == m_cfFileContents) && (pFEIn->tymed & TYMED_ISTREAM))
  151. hr = CreateFileContents(pstm, pFEIn->lindex);
  152. else if ((pFEIn->cfFormat == m_cfPreferedEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
  153. hr = CreatePrefDropEffect(pstm);
  154. else if ((pFEIn->cfFormat == m_cfPerformedEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
  155. hr = CreatePerformedDropEffect(pstm);
  156. else if ((pFEIn->cfFormat == m_cfLogicalPerformedEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
  157. hr = CreateLogicalPerformedDropEffect(pstm);
  158. else if ((pFEIn->cfFormat == m_cfDataSrcClsid) && (pFEIn->tymed & TYMED_HGLOBAL))
  159. hr = CreateDataSrcClsid(pstm);
  160. else
  161. hr = CIDLData::GetData(pFEIn, pstm);
  162. return hr;
  163. }
  164. DWORD COfflineItemsData::GetDataDWORD(
  165. FORMATETC *pfe,
  166. STGMEDIUM *pstm,
  167. DWORD *pdwOut
  168. )
  169. {
  170. if (pfe->tymed == TYMED_HGLOBAL)
  171. {
  172. DWORD *pdw = (DWORD *)GlobalLock(pstm->hGlobal);
  173. if (pdw)
  174. {
  175. *pdwOut = *pdw;
  176. GlobalUnlock(pstm->hGlobal);
  177. }
  178. }
  179. return *pdwOut;
  180. }
  181. HRESULT
  182. COfflineItemsData::SetData(
  183. FORMATETC *pFEIn,
  184. STGMEDIUM *pstm,
  185. BOOL fRelease
  186. )
  187. {
  188. if (pFEIn->cfFormat == g_cfPerformedDropEffect)
  189. {
  190. GetDataDWORD(pFEIn, pstm, &m_dwPerformedEffect);
  191. }
  192. else if (pFEIn->cfFormat == g_cfLogicalPerformedDropEffect)
  193. {
  194. GetDataDWORD(pFEIn, pstm, &m_dwLogicalPerformedEffect);
  195. }
  196. else if (pFEIn->cfFormat == g_cfPreferredDropEffect)
  197. {
  198. GetDataDWORD(pFEIn, pstm, &m_dwPreferredEffect);
  199. }
  200. return CIDLData::SetData(pFEIn, pstm, fRelease);
  201. }
  202. HRESULT
  203. COfflineItemsData::QueryGetData(
  204. FORMATETC *pFEIn
  205. )
  206. {
  207. if (pFEIn->cfFormat == m_cfHDROP ||
  208. pFEIn->cfFormat == m_cfFileDesc ||
  209. pFEIn->cfFormat == m_cfFileContents ||
  210. pFEIn->cfFormat == m_cfPreferedEffect ||
  211. pFEIn->cfFormat == m_cfPerformedEffect ||
  212. pFEIn->cfFormat == m_cfLogicalPerformedEffect ||
  213. pFEIn->cfFormat == m_cfDataSrcClsid)
  214. {
  215. return S_OK;
  216. }
  217. return CIDLData::QueryGetData(pFEIn);
  218. }
  219. HRESULT
  220. COfflineItemsData::ProvideFormats(
  221. CEnumFormatEtc *pEnumFmtEtc
  222. )
  223. {
  224. FORMATETC rgFmtEtc[] = {
  225. { m_cfHDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  226. { m_cfFileContents, NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM },
  227. { m_cfFileDesc, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  228. { m_cfPreferedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  229. { m_cfPerformedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  230. { m_cfLogicalPerformedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  231. { m_cfDataSrcClsid, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }
  232. };
  233. //
  234. // Add our formats to the CIDLData format enumerator.
  235. //
  236. return pEnumFmtEtc->AddFormats(ARRAYSIZE(rgFmtEtc), rgFmtEtc);
  237. }
  238. HRESULT
  239. COfflineItemsData::CreateFileDescriptor(
  240. STGMEDIUM *pstm
  241. )
  242. {
  243. HRESULT hr;
  244. pstm->tymed = TYMED_HGLOBAL;
  245. pstm->pUnkForRelease = NULL;
  246. // render the file descriptor
  247. // we only allocate for m_cItems-1 file descriptors because the filegroup
  248. // descriptor has already allocated space for 1.
  249. FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR) + (m_cItems - 1) * sizeof(FILEDESCRIPTOR));
  250. if (pfgd)
  251. {
  252. pfgd->cItems = m_cItems; // set the number of items
  253. pfgd->fgd[0].dwFlags = FD_PROGRESSUI; // turn on progress UI
  254. for (int i = 0; i < m_cItems; i++)
  255. {
  256. FILEDESCRIPTOR *pfd = &(pfgd->fgd[i]);
  257. TCHAR szName[MAX_PATH];
  258. StrCpyN(pfd->cFileName,
  259. COfflineFilesFolder::OLID_GetFileName(m_rgpolid[i], szName, ARRAYSIZE(szName)),
  260. ARRAYSIZE(pfd->cFileName));
  261. }
  262. pstm->hGlobal = pfgd;
  263. hr = S_OK;
  264. }
  265. else
  266. hr = E_OUTOFMEMORY;
  267. return hr;
  268. }
  269. HRESULT
  270. COfflineItemsData::CreatePrefDropEffect(
  271. STGMEDIUM *pstm
  272. )
  273. {
  274. return CreateDWORD(pstm, m_dwPreferredEffect);
  275. }
  276. HRESULT
  277. COfflineItemsData::CreatePerformedDropEffect(
  278. STGMEDIUM *pstm
  279. )
  280. {
  281. return CreateDWORD(pstm, m_dwPerformedEffect);
  282. }
  283. HRESULT
  284. COfflineItemsData::CreateLogicalPerformedDropEffect(
  285. STGMEDIUM *pstm
  286. )
  287. {
  288. return CreateDWORD(pstm, m_dwLogicalPerformedEffect);
  289. }
  290. HRESULT
  291. COfflineItemsData::CreateDWORD(
  292. STGMEDIUM *pstm,
  293. DWORD dwEffect
  294. )
  295. {
  296. pstm->tymed = TYMED_HGLOBAL;
  297. pstm->pUnkForRelease = NULL;
  298. pstm->hGlobal = GlobalAlloc(GPTR, sizeof(DWORD));
  299. if (pstm->hGlobal)
  300. {
  301. *((DWORD *)pstm->hGlobal) = dwEffect;
  302. return S_OK;
  303. }
  304. return E_OUTOFMEMORY;
  305. }
  306. HRESULT
  307. COfflineItemsData::CreateFileContents(
  308. STGMEDIUM *pstm,
  309. LONG lindex
  310. )
  311. {
  312. HRESULT hr;
  313. // here's a partial fix for when ole sometimes passes in -1 for lindex
  314. if (lindex == -1)
  315. {
  316. if (m_cItems == 1)
  317. lindex = 0;
  318. else
  319. return E_FAIL;
  320. }
  321. pstm->tymed = TYMED_ISTREAM;
  322. pstm->pUnkForRelease = NULL;
  323. TCHAR szPath[MAX_PATH];
  324. COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[lindex], szPath, ARRAYSIZE(szPath));
  325. hr = SHCreateStreamOnFile(szPath, STGM_READ, &pstm->pstm);
  326. return hr;
  327. }
  328. HRESULT
  329. COfflineItemsData::CreateHDROP(
  330. STGMEDIUM *pstm
  331. )
  332. {
  333. HRESULT hr = E_OUTOFMEMORY;
  334. int i;
  335. //
  336. // The extra MAX_PATH is so that the damned SHLWAPI functions (i.e.
  337. // PathAppend) won't complain about a too-small buffer. They require
  338. // that the destination buffer be AT LEAST MAX_PATH. So much for letting
  339. // code being smart about buffer sizes.
  340. //
  341. int cbHdrop = sizeof(DROPFILES) + (MAX_PATH * sizeof(TCHAR)) + sizeof(TEXT('\0'));
  342. TCHAR szPath[MAX_PATH];
  343. pstm->tymed = TYMED_HGLOBAL;
  344. pstm->pUnkForRelease = NULL;
  345. //
  346. // Calculate required buffer size.
  347. //
  348. for (i = 0; i < m_cItems; i++)
  349. {
  350. szPath[0] = TEXT('\0');
  351. COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[i], szPath, ARRAYSIZE(szPath));
  352. cbHdrop += (lstrlen(szPath) + 1) * sizeof(TCHAR);
  353. }
  354. pstm->hGlobal = GlobalAlloc(GPTR, cbHdrop);
  355. if (NULL != pstm->hGlobal)
  356. {
  357. //
  358. // Fill out the header and append the file paths in a
  359. // double-nul term list.
  360. //
  361. LPDROPFILES pdfHdr = (LPDROPFILES)pstm->hGlobal;
  362. pdfHdr->pFiles = sizeof(DROPFILES);
  363. pdfHdr->fWide = TRUE;
  364. LPTSTR pszWrite = (LPTSTR)((LPBYTE)pdfHdr + sizeof(DROPFILES));
  365. LPTSTR pszEnd = (LPTSTR)((LPBYTE)pstm->hGlobal + cbHdrop - sizeof(TCHAR));
  366. for (i = 0; i < m_cItems; i++)
  367. {
  368. COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[i], pszWrite, (UINT)(pszEnd - pszWrite));
  369. pszWrite += lstrlen(pszWrite) + 1;
  370. }
  371. hr = S_OK;
  372. }
  373. return hr;
  374. }
  375. HRESULT
  376. COfflineItemsData::CreateDataSrcClsid(
  377. STGMEDIUM *pstm
  378. )
  379. {
  380. HRESULT hr = E_OUTOFMEMORY;
  381. pstm->tymed = TYMED_HGLOBAL;
  382. pstm->pUnkForRelease = NULL;
  383. pstm->hGlobal = GlobalAlloc(GPTR, sizeof(CLSID));
  384. if (pstm->hGlobal)
  385. {
  386. *((CLSID *)pstm->hGlobal) = CLSID_OfflineFilesFolder;
  387. return S_OK;
  388. }
  389. return E_OUTOFMEMORY;
  390. }
  391. COfflineItems::COfflineItems(
  392. COfflineFilesFolder *pFolder,
  393. HWND hwnd
  394. ) : m_cRef(1),
  395. m_hwndBrowser(hwnd),
  396. m_pFolder(pFolder),
  397. m_ppolid(NULL),
  398. m_cItems(0)
  399. {
  400. DllAddRef();
  401. if (m_pFolder)
  402. m_pFolder->AddRef();
  403. }
  404. COfflineItems::~COfflineItems()
  405. {
  406. if (m_pFolder)
  407. m_pFolder->Release();
  408. if (m_ppolid)
  409. {
  410. for (UINT i = 0; i < m_cItems; i++)
  411. {
  412. if (m_ppolid[i])
  413. ILFree((LPITEMIDLIST)m_ppolid[i]);
  414. }
  415. LocalFree((HLOCAL)m_ppolid);
  416. }
  417. DllRelease();
  418. }
  419. HRESULT
  420. COfflineItems::Initialize(
  421. UINT cidl,
  422. LPCITEMIDLIST *ppidl
  423. )
  424. {
  425. HRESULT hr;
  426. m_ppolid = (LPCOLID *)LocalAlloc(LPTR, cidl * sizeof(LPCOLID));
  427. if (m_ppolid)
  428. {
  429. m_cItems = cidl;
  430. hr = S_OK;
  431. for (UINT i = 0; i < cidl; i++)
  432. {
  433. m_ppolid[i] = (LPCOLID)ILClone(ppidl[i]);
  434. if (!m_ppolid[i])
  435. {
  436. hr = E_OUTOFMEMORY;
  437. break;
  438. }
  439. }
  440. }
  441. else
  442. hr = E_OUTOFMEMORY;
  443. return hr;
  444. }
  445. HRESULT
  446. COfflineItems::CreateInstance(
  447. COfflineFilesFolder *pfolder,
  448. HWND hwnd,
  449. UINT cidl,
  450. LPCITEMIDLIST *ppidl,
  451. REFIID riid,
  452. void **ppv)
  453. {
  454. HRESULT hr;
  455. *ppv = NULL; // null the out param
  456. COfflineItems *pitems = new COfflineItems(pfolder, hwnd);
  457. if (pitems)
  458. {
  459. hr = pitems->Initialize(cidl, ppidl);
  460. if (SUCCEEDED(hr))
  461. {
  462. hr = pitems->QueryInterface(riid, ppv);
  463. }
  464. pitems->Release();
  465. }
  466. else
  467. hr = E_OUTOFMEMORY;
  468. return hr;
  469. }
  470. HRESULT
  471. COfflineItems::QueryInterface(
  472. REFIID iid,
  473. void **ppv
  474. )
  475. {
  476. static const QITAB qit[] = {
  477. QITABENT(COfflineItems, IContextMenu),
  478. QITABENT(COfflineItems, IQueryInfo),
  479. { 0 },
  480. };
  481. return QISearch(this, qit, iid, ppv);
  482. }
  483. ULONG
  484. COfflineItems::AddRef(
  485. void
  486. )
  487. {
  488. return InterlockedIncrement(&m_cRef);
  489. }
  490. ULONG
  491. COfflineItems::Release(
  492. void
  493. )
  494. {
  495. if (InterlockedDecrement(&m_cRef))
  496. return m_cRef;
  497. delete this;
  498. return 0;
  499. }
  500. //
  501. // IQueryInfo Methods -------------------------------------------------------
  502. //
  503. HRESULT
  504. COfflineItems::GetInfoTip(
  505. DWORD dwFlags,
  506. WCHAR **ppwszTip
  507. )
  508. {
  509. TCHAR szPath[MAX_PATH];
  510. return SHStrDup(COfflineFilesFolder::OLID_GetFullPath(m_ppolid[0], szPath, ARRAYSIZE(szPath)), ppwszTip);
  511. }
  512. HRESULT
  513. COfflineItems::GetInfoFlags(
  514. DWORD *pdwFlags
  515. )
  516. {
  517. *pdwFlags = 0;
  518. return S_OK;
  519. }
  520. //
  521. // IContextMenu Methods -------------------------------------------------------
  522. //
  523. HRESULT
  524. COfflineItems::QueryContextMenu(
  525. HMENU hmenu,
  526. UINT indexMenu,
  527. UINT idCmdFirst,
  528. UINT idCmdLast,
  529. UINT uFlags
  530. )
  531. {
  532. USHORT cItems = 0;
  533. return ResultFromShort(cItems); // number of menu items
  534. }
  535. HRESULT
  536. COfflineItems::InvokeCommand(
  537. LPCMINVOKECOMMANDINFO pici
  538. )
  539. {
  540. HRESULT hr = S_OK;
  541. return hr;
  542. }
  543. HRESULT
  544. COfflineItems::GetCommandString(
  545. UINT_PTR idCmd,
  546. UINT uFlags,
  547. UINT *pwReserved,
  548. LPSTR pszName,
  549. UINT cchMax
  550. )
  551. {
  552. HRESULT hr = E_FAIL;
  553. return hr;
  554. }