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.

1074 lines
27 KiB

  1. //*******************************************************************************************
  2. //
  3. // Filename : folder.cpp
  4. //
  5. // CAB Files Shell Extension
  6. //
  7. // Copyright (c) 1994 - 1997 Microsoft Corporation. All rights reserved
  8. //
  9. //*******************************************************************************************
  10. #include "pch.h"
  11. #include "ccstock.h"
  12. #include "thisdll.h"
  13. #include "thisguid.h"
  14. #include "ntquery.h"
  15. #include "varutil.h"
  16. #include "folder.h"
  17. #include "enum.h"
  18. #include "menu.h"
  19. #include "dataobj.h"
  20. #include "cabitms.h"
  21. #include "resource.h"
  22. STDAPI StringToStrRet(LPCTSTR pszName, STRRET *pStrRet)
  23. {
  24. #ifdef UNICODE
  25. pStrRet->uType = STRRET_WSTR;
  26. return SHStrDup(pszName, &pStrRet->pOleStr);
  27. #else
  28. pStrRet->uType = STRRET_CSTR;
  29. lstrcpyn(pStrRet->cStr, pszName, ARRAYSIZE(pStrRet->cStr));
  30. return NOERROR;
  31. #endif
  32. }
  33. STDMETHODIMP CCabFolder::QueryInterface(REFIID riid, void **ppv)
  34. {
  35. if (CLSID_CabFolder == riid)
  36. {
  37. // yuck - dataobject uses this when loading us from a stream:
  38. // NOTE: we are doing an AddRef() in this case
  39. *ppv = (CCabFolder*) this;
  40. AddRef();
  41. return S_OK;
  42. }
  43. else
  44. {
  45. static const QITAB qit[] = {
  46. QITABENT(CCabFolder, IShellFolder2),
  47. QITABENTMULTI(CCabFolder, IShellFolder, IShellFolder2),
  48. QITABENT(CCabFolder, IPersistFolder2),
  49. QITABENTMULTI(CCabFolder, IPersistFolder, IPersistFolder2),
  50. QITABENTMULTI(CCabFolder, IPersist, IPersistFolder2),
  51. QITABENT(CCabFolder, IShellFolderViewCB),
  52. { 0 },
  53. };
  54. return QISearch(this, qit, riid, ppv);
  55. }
  56. }
  57. STDMETHODIMP_(ULONG) CCabFolder::AddRef(void)
  58. {
  59. return(m_cRef.AddRef());
  60. }
  61. STDMETHODIMP_(ULONG) CCabFolder::Release(void)
  62. {
  63. if (!m_cRef.Release())
  64. {
  65. delete this;
  66. return(0);
  67. }
  68. return(m_cRef.GetRef());
  69. }
  70. STDMETHODIMP CCabFolder::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  71. {
  72. return E_NOTIMPL;
  73. }
  74. //**********************************************************************
  75. //
  76. // Purpose:
  77. //
  78. // Creates an item enumeration object
  79. // (an IEnumIDList interface) that can be used to
  80. // enumerate the contents of a folder.
  81. //
  82. // Parameters:
  83. //
  84. // HWND hwndOwner - handle to the owner window
  85. // DWORD grFlags - flags about which items to include
  86. // IEnumIDList **ppenumIDList - address that receives IEnumIDList
  87. // interface pointer
  88. //********************************************************************
  89. STDMETHODIMP CCabFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  90. {
  91. HRESULT hres;
  92. CEnumCabObjs *pce = new CEnumCabObjs(this, grfFlags);
  93. if (pce)
  94. {
  95. hres = pce->QueryInterface(IID_IEnumIDList, (void **)ppenumIDList);
  96. }
  97. else
  98. {
  99. *ppenumIDList = NULL;
  100. hres = E_OUTOFMEMORY;
  101. }
  102. return hres;
  103. }
  104. STDMETHODIMP CCabFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvObj)
  105. {
  106. return E_NOTIMPL;
  107. }
  108. STDMETHODIMP CCabFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void ** ppvObj)
  109. {
  110. return E_NOTIMPL;
  111. }
  112. //**********************************************************************
  113. //
  114. // CCabFolder::CompareIDs
  115. //
  116. // Purpose:
  117. //
  118. // Determines the relative ordering of two file
  119. // objects or folders, given their item identifier lists
  120. //
  121. // Parameters:
  122. //
  123. // LPARAM lParam - type of comparison
  124. // LPCITEMIDLIST pidl1 - address to ITEMIDLIST
  125. // LPCITEMIDLIST pidl2 - address to ITEMIDLIST
  126. //
  127. //
  128. // Comments:
  129. //
  130. //
  131. //********************************************************************
  132. STDMETHODIMP CCabFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  133. {
  134. LPCABITEM pit1 = (LPCABITEM)pidl1;
  135. LPCABITEM pit2 = (LPCABITEM)pidl2;
  136. short nCmp = 0;
  137. LPCWSTR pszName1, pszName2;
  138. WSTR_ALIGNED_STACK_COPY(&pszName1, pit1->szName);
  139. WSTR_ALIGNED_STACK_COPY(&pszName2, pit2->szName);
  140. switch (lParam)
  141. {
  142. case CV_COL_NAME:
  143. break;
  144. case CV_COL_SIZE:
  145. if (pit1->dwFileSize < pit2->dwFileSize)
  146. {
  147. nCmp = -1;
  148. }
  149. else if (pit1->dwFileSize > pit2->dwFileSize)
  150. {
  151. nCmp = 1;
  152. }
  153. break;
  154. case CV_COL_TYPE:
  155. {
  156. STRRET srName1, srName2;
  157. GetTypeOf(pit1, &srName1);
  158. GetTypeOf(pit2, &srName2);
  159. #ifdef UNICODE
  160. if (srName1.pOleStr && srName2.pOleStr)
  161. {
  162. nCmp = (SHORT)lstrcmp(srName1.pOleStr, srName2.pOleStr);
  163. }
  164. else
  165. {
  166. if (srName1.pOleStr)
  167. {
  168. nCmp = 1;
  169. }
  170. else
  171. {
  172. nCmp = -1;
  173. }
  174. }
  175. if (srName1.pOleStr)
  176. {
  177. CoTaskMemFree(srName1.pOleStr);
  178. }
  179. if (srName2.pOleStr)
  180. {
  181. CoTaskMemFree(srName2.pOleStr);
  182. }
  183. #else // UNICODE
  184. nCmp = (SHORT)lstrcmp(srName1.cStr, srName2.cStr);
  185. #endif // UNICODE
  186. break;
  187. }
  188. case CV_COL_MODIFIED:
  189. if (pit1->uFileDate < pit2->uFileDate)
  190. {
  191. nCmp = -1;
  192. }
  193. else if (pit1->uFileDate > pit2->uFileDate)
  194. {
  195. nCmp = 1;
  196. }
  197. else if (pit1->uFileTime < pit2->uFileTime)
  198. {
  199. nCmp = -1;
  200. }
  201. else if (pit1->uFileTime > pit2->uFileTime)
  202. {
  203. nCmp = 1;
  204. }
  205. break;
  206. case CV_COL_PATH:
  207. if (pit1->cPathChars == 0)
  208. {
  209. if (pit2->cPathChars != 0)
  210. {
  211. nCmp = -1;
  212. }
  213. }
  214. else if (pit2->cPathChars == 0)
  215. {
  216. nCmp = 1;
  217. }
  218. else if (pit1->cPathChars <= pit2->cPathChars)
  219. {
  220. nCmp = (short) StrCmpN(pszName1, pszName2, pit1->cPathChars-1);
  221. if ((nCmp == 0) && (pit1->cPathChars < pit2->cPathChars))
  222. {
  223. nCmp = -1;
  224. }
  225. }
  226. else
  227. {
  228. nCmp = (short) StrCmpN(pszName1, pszName2, pit2->cPathChars-1);
  229. if (nCmp == 0)
  230. {
  231. nCmp = 1;
  232. }
  233. }
  234. break;
  235. default:
  236. break;
  237. }
  238. if (nCmp != 0)
  239. {
  240. return ResultFromShort(nCmp);
  241. }
  242. return ResultFromShort(lstrcmpi(pszName1 + pit1->cPathChars, pszName2 + pit2->cPathChars));
  243. }
  244. STDMETHODIMP CCabFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
  245. {
  246. return E_NOTIMPL;
  247. }
  248. //**********************************************************************
  249. //
  250. // CCabFolder::CreateViewObject
  251. //
  252. // Purpose:
  253. //
  254. // IShellbrowser calls this to create a ShellView
  255. // object
  256. //
  257. // Parameters:
  258. //
  259. // HWND hwndOwner -
  260. //
  261. // REFIID riid - interface ID
  262. //
  263. // void ** ppvObj - pointer to the Shellview object
  264. //
  265. // Return Value:
  266. //
  267. // NOERROR
  268. // E_OUTOFMEMORY
  269. // E_NOINTERFACE
  270. //
  271. //
  272. // Comments:
  273. //
  274. // ShellBrowser interface calls this to request the ShellFolder
  275. // to create a ShellView object
  276. //
  277. //********************************************************************
  278. STDMETHODIMP CCabFolder::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppvObj)
  279. {
  280. HRESULT hr;
  281. if (riid == IID_IShellView)
  282. {
  283. SFV_CREATE sfvc = { 0 };
  284. sfvc.cbSize = sizeof(sfvc);
  285. sfvc.pshf = this;
  286. sfvc.psfvcb = this;
  287. hr = SHCreateShellFolderView(&sfvc, (IShellView **)ppvObj);
  288. }
  289. else
  290. {
  291. *ppvObj = NULL;
  292. hr = E_NOINTERFACE;
  293. }
  294. return hr;
  295. }
  296. // **************************************************************************************
  297. //
  298. // CCabFolder::GetAttributesOf
  299. //
  300. // Purpose
  301. //
  302. // Retrieves attributes of one of more file objects
  303. //
  304. // Parameters:
  305. //
  306. // UINT cidl - number of file objects
  307. // LPCITEMIDLIST *apidl - pointer to array of ITEMIDLIST
  308. // ULONG *rgfInOut - array of values that specify file object
  309. // attributes
  310. //
  311. //
  312. // Return Value:
  313. //
  314. // NOERROR
  315. //
  316. // Comments
  317. //
  318. // ***************************************************************************************
  319. STDMETHODIMP CCabFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut)
  320. {
  321. *rgfInOut &= SFGAO_CANCOPY;
  322. return NOERROR;
  323. }
  324. // **************************************************************************************
  325. //
  326. // CCabFolder::GetUIObjectOf
  327. //
  328. // Purpose
  329. //
  330. // Returns an interface that can be used to carry out actions on
  331. // the specified file objects or folders
  332. //
  333. // Parameters:
  334. //
  335. // HWND hwndOwner - handle of the Owner window
  336. //
  337. // UINT cidl - Number of file objects
  338. //
  339. // LPCITEMIDLIST *apidl - array of file object pidls
  340. //
  341. // REFIID - Identifier of interface to return
  342. //
  343. // UINT * prgfInOut - reserved
  344. //
  345. // void **ppvObj - address that receives interface pointer
  346. //
  347. // Return Value:
  348. //
  349. // E_INVALIDARG
  350. // E_NOINTERFACE
  351. // E_OUTOFMEMORY
  352. //
  353. // Comments
  354. // ***************************************************************************************
  355. STDMETHODIMP CCabFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
  356. REFIID riid, UINT *prgfInOut, void **ppv)
  357. {
  358. *ppv = NULL;
  359. HRESULT hr = E_OUTOFMEMORY;
  360. if (riid == IID_IExtractIcon)
  361. {
  362. if (cidl != 1)
  363. {
  364. hr = E_INVALIDARG;
  365. }
  366. else
  367. {
  368. LPCABITEM pci = (LPCABITEM)*apidl;
  369. LPCWSTR pszName;
  370. WSTR_ALIGNED_STACK_COPY(&pszName, pci->szName);
  371. hr = SHCreateFileExtractIconW(pszName, pci->uFileAttribs, riid, ppv);
  372. }
  373. }
  374. else if (riid == IID_IContextMenu)
  375. {
  376. if (cidl < 1)
  377. {
  378. hr = E_INVALIDARG;
  379. }
  380. else
  381. {
  382. CCabItemMenu *pcim = new CCabItemMenu(hwndOwner, this, (LPCABITEM *)apidl, cidl);
  383. if (pcim)
  384. {
  385. pcim->AddRef(); // weak 0-based refcount
  386. hr = pcim->QueryInterface(riid, ppv);
  387. pcim->Release();
  388. }
  389. }
  390. }
  391. else if (riid == IID_IDataObject)
  392. {
  393. if (cidl < 1)
  394. {
  395. hr = E_INVALIDARG;
  396. }
  397. else
  398. {
  399. CCabObj *pco = new CCabObj(hwndOwner, this, (LPCABITEM *)apidl, cidl);
  400. if (pco)
  401. {
  402. pco->AddRef(); // weak 0-based refcount
  403. hr = pco->QueryInterface(riid, ppv);
  404. pco->Release();
  405. }
  406. }
  407. }
  408. else
  409. {
  410. hr = E_NOINTERFACE;
  411. }
  412. return hr;
  413. }
  414. //*****************************************************************************
  415. //
  416. // CCabFolder::GetDisplayNameOf
  417. //
  418. // Purpose:
  419. // Retrieves the display name for the specified file object or
  420. // subfolder.
  421. //
  422. //
  423. // Parameters:
  424. //
  425. // LPCITEMIDLIST pidl - pidl of the file object
  426. // DWORD dwFlags - Flags of the type of display name to
  427. // return
  428. // LPSTRRET lpName - address holding the name returned
  429. //
  430. //
  431. // Comments:
  432. //
  433. //*****************************************************************************
  434. STDMETHODIMP CCabFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET lpName)
  435. {
  436. HRESULT hr;
  437. LPCABITEM pit = (LPCABITEM)pidl;
  438. if (pit)
  439. {
  440. TCHAR szTemp[MAX_PATH];
  441. if (dwFlags & SHGDN_FORPARSING)
  442. {
  443. if (dwFlags & SHGDN_INFOLDER)
  444. {
  445. ualstrcpyn(szTemp, pit->szName, ARRAYSIZE(szTemp)); // relative parse name
  446. }
  447. else
  448. {
  449. SHGetNameAndFlags(m_pidlHere, dwFlags, szTemp, ARRAYSIZE(szTemp), NULL);
  450. TCHAR szName[MAX_PATH];
  451. ualstrcpyn(szName, pit->szName, ARRAYSIZE(szName));
  452. PathAppend(szTemp, szName);
  453. }
  454. hr = StringToStrRetW(szTemp, lpName);
  455. }
  456. else
  457. {
  458. GetNameOf(pit, lpName);
  459. hr = S_OK;
  460. }
  461. }
  462. else
  463. hr = E_INVALIDARG;
  464. return hr;
  465. }
  466. STDMETHODIMP CCabFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwRes, LPITEMIDLIST *ppidlOut)
  467. {
  468. return E_NOTIMPL;
  469. }
  470. DEFINE_SCID(SCID_TYPE, PSGUID_STORAGE, PID_STG_STORAGETYPE);
  471. DEFINE_SCID(SCID_NAME, PSGUID_STORAGE, PID_STG_NAME);
  472. DEFINE_SCID(SCID_SIZE, PSGUID_STORAGE, PID_STG_SIZE);
  473. DEFINE_SCID(SCID_WRITETIME, PSGUID_STORAGE, PID_STG_WRITETIME);
  474. // the CV_COL_PATH column doesn't map to any well-known SCID types.
  475. // since nobody will need to get a hold of the data, just refer to a bogus
  476. // SCID. all this has to do is work within FindSCID.
  477. #define PSGUID_CabFolder {0x0CD7A5C0L, 0x9F37, 0x11CE, 0xAE, 0x65, 0x08, 0x00, 0x2B, 0x2E, 0x12, 0x62} // CLSID_CabFolder
  478. DEFINE_SCID(SCID_BOGUS, PSGUID_CabFolder, 0);
  479. struct _CVCOLINFO
  480. {
  481. UINT iColumn;
  482. UINT iTitle;
  483. UINT cchCol;
  484. UINT iFmt;
  485. const SHCOLUMNID* pscid;
  486. } s_aCVColInfo[] = {
  487. {CV_COL_NAME, IDS_CV_COL_NAME, 20, LVCFMT_LEFT, &SCID_NAME},
  488. {CV_COL_SIZE, IDS_CV_COL_SIZE, 10, LVCFMT_RIGHT, &SCID_SIZE},
  489. {CV_COL_TYPE, IDS_CV_COL_TYPE, 20, LVCFMT_LEFT, &SCID_TYPE},
  490. {CV_COL_MODIFIED, IDS_CV_COL_MODIFIED, 20, LVCFMT_LEFT, &SCID_WRITETIME},
  491. {CV_COL_PATH, IDS_CV_COL_PATH, 30, LVCFMT_LEFT, &SCID_BOGUS},
  492. };
  493. STDMETHODIMP CCabFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
  494. {
  495. LPCABITEM pit = (LPCABITEM)pidl;
  496. TCHAR szTemp[MAX_PATH];
  497. if (iColumn >= CV_COL_MAX)
  498. {
  499. return E_NOTIMPL;
  500. }
  501. psd->str.uType = STRRET_CSTR;
  502. psd->str.cStr[0] = '\0';
  503. if (!pit)
  504. {
  505. TCHAR szTitle[MAX_PATH];
  506. LoadString(g_ThisDll.GetInstance(), s_aCVColInfo[iColumn].iTitle, szTitle, ARRAYSIZE(szTitle));
  507. StringToStrRet(szTitle, &(psd->str));
  508. psd->fmt = s_aCVColInfo[iColumn].iFmt;
  509. psd->cxChar = s_aCVColInfo[iColumn].cchCol;
  510. return S_OK;
  511. }
  512. HRESULT hr = S_OK;
  513. switch (iColumn)
  514. {
  515. case CV_COL_NAME:
  516. GetNameOf(pit, &psd->str);
  517. break;
  518. case CV_COL_PATH:
  519. GetPathOf(pit, &psd->str);
  520. break;
  521. case CV_COL_SIZE:
  522. {
  523. ULARGE_INTEGER ullSize = {pit->dwFileSize, 0};
  524. StrFormatKBSize(ullSize.QuadPart, szTemp, ARRAYSIZE(szTemp));
  525. StringToStrRet(szTemp, &(psd->str));
  526. break;
  527. }
  528. case CV_COL_TYPE:
  529. GetTypeOf(pit, &psd->str);
  530. break;
  531. case CV_COL_MODIFIED:
  532. {
  533. FILETIME ft, uft;
  534. if (DosDateTimeToFileTime(pit->uFileDate, pit->uFileTime, &ft) &&
  535. LocalFileTimeToFileTime(&ft, &uft)) // Apply timezone
  536. {
  537. SHFormatDateTime(&uft, NULL, szTemp, ARRAYSIZE(szTemp));
  538. StringToStrRet(szTemp, &(psd->str));
  539. }
  540. else
  541. {
  542. hr = E_FAIL;
  543. }
  544. }
  545. break;
  546. }
  547. return hr;
  548. }
  549. STDMETHODIMP CCabFolder::MapColumnToSCID(UINT iCol, SHCOLUMNID *pscid)
  550. {
  551. HRESULT hr;
  552. ZeroMemory(pscid, sizeof(*pscid));
  553. if (iCol < ARRAYSIZE(s_aCVColInfo))
  554. {
  555. *pscid = *s_aCVColInfo[iCol].pscid;
  556. hr = S_OK;
  557. }
  558. else
  559. hr = E_INVALIDARG;
  560. return hr;
  561. }
  562. STDAPI_(int) FindSCID(const _CVCOLINFO* pcol, UINT nCols, const SHCOLUMNID* pscid)
  563. {
  564. for (UINT i = 0; i < nCols; i++)
  565. {
  566. if (IsEqualSCID(*pscid, *pcol[i].pscid))
  567. return (int)i;
  568. }
  569. return -1;
  570. }
  571. STDMETHODIMP CCabFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  572. {
  573. HRESULT hr = E_FAIL;
  574. LPCABITEM pit = (LPCABITEM)pidl;
  575. int iCol = FindSCID(s_aCVColInfo, ARRAYSIZE(s_aCVColInfo), pscid);
  576. if (iCol >= 0)
  577. {
  578. switch (iCol)
  579. {
  580. case CV_COL_SIZE:
  581. pv->ullVal = pit->dwFileSize;
  582. pv->vt = VT_UI8;
  583. hr = S_OK;
  584. break;
  585. case CV_COL_MODIFIED:
  586. if (DosDateTimeToVariantTime(pit->uFileDate, pit->uFileTime, &pv->date))
  587. {
  588. pv->vt = VT_DATE;
  589. hr = S_OK;
  590. }
  591. break;
  592. default:
  593. {
  594. SHELLDETAILS sd;
  595. // Note that GetDetailsOf expects a relative pidl, since it is passed the SF itself.
  596. // The columnid includes the absolute pidl, though.z
  597. hr = GetDetailsOf(pidl, iCol, &sd);
  598. if (SUCCEEDED(hr))
  599. {
  600. hr = InitVariantFromStrRet(&sd.str, pidl, pv);
  601. }
  602. }
  603. }
  604. }
  605. return hr;
  606. }
  607. // *** IPersist methods ***
  608. STDMETHODIMP CCabFolder::GetClassID(CLSID *pclsid)
  609. {
  610. *pclsid = CLSID_CabFolder;
  611. return NOERROR;
  612. }
  613. // IPersistFolder
  614. STDMETHODIMP CCabFolder::Initialize(LPCITEMIDLIST pidl)
  615. {
  616. if (m_pidlHere)
  617. {
  618. ILFree(m_pidlHere);
  619. }
  620. m_pidlHere = ILClone(pidl); // copy the pidl
  621. return m_pidlHere ? S_OK : E_OUTOFMEMORY;
  622. }
  623. HRESULT CCabFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  624. {
  625. if (m_pidlHere)
  626. {
  627. *ppidl = ILClone(m_pidlHere);
  628. return *ppidl ? NOERROR : E_OUTOFMEMORY;
  629. }
  630. *ppidl = NULL;
  631. return S_FALSE; // success but empty
  632. }
  633. //*****************************************************************************
  634. //
  635. // CCabFolder::CreateIDList
  636. //
  637. // Purpose:
  638. //
  639. // Creates an item identifier list for the objects in the namespace
  640. //
  641. //
  642. //*****************************************************************************
  643. LPITEMIDLIST CCabFolder::CreateIDList(LPCTSTR pszName, DWORD dwFileSize,
  644. UINT uFileDate, UINT uFileTime, UINT uFileAttribs)
  645. {
  646. // We'll assume no name is longer than MAX_PATH
  647. // Note the terminating NULL is already in the sizeof(CABITEM)
  648. BYTE bBuf[sizeof(CABITEM) + (sizeof(TCHAR) * MAX_PATH) + sizeof(WORD)];
  649. CABITEM *pci = (CABITEM*)bBuf;
  650. UINT uNameLen = lstrlen(pszName);
  651. if (uNameLen >= MAX_PATH)
  652. {
  653. uNameLen = MAX_PATH;
  654. }
  655. pci->wSize = (WORD)(sizeof(CABITEM) + (sizeof(TCHAR) * uNameLen));
  656. pci->dwFileSize = dwFileSize;
  657. pci->uFileDate = (USHORT)uFileDate;
  658. pci->uFileTime = (USHORT)uFileTime;
  659. pci->uFileAttribs = (USHORT)uFileAttribs & (FILE_ATTRIBUTE_READONLY|
  660. FILE_ATTRIBUTE_HIDDEN |
  661. FILE_ATTRIBUTE_SYSTEM |
  662. FILE_ATTRIBUTE_ARCHIVE);
  663. lstrcpynW(pci->szName, pszName, uNameLen+1);
  664. pci->cPathChars = 0;
  665. LPCTSTR psz = pszName;
  666. while (*psz)
  667. {
  668. if ((*psz == TEXT(':')) || (*psz == TEXT('/')) || (*psz == TEXT('\\')))
  669. {
  670. pci->cPathChars = (USHORT)(psz - pszName) + 1;
  671. }
  672. psz = CharNext(psz);
  673. }
  674. // Terminate the IDList
  675. *(WORD *)(((LPSTR)pci)+pci->wSize) = 0;
  676. return(ILClone((LPCITEMIDLIST)pci));
  677. }
  678. //*****************************************************************************
  679. //
  680. // CCabFolder::GetPath
  681. //
  682. // Purpose:
  683. //
  684. // Get the Path for the current pidl
  685. //
  686. // Parameters:
  687. //
  688. // LPSTR szPath - return pointer for path string
  689. //
  690. // Comments:
  691. //
  692. //*****************************************************************************
  693. BOOL CCabFolder::GetPath(LPTSTR szPath)
  694. {
  695. if (!m_pidlHere || !SHGetPathFromIDList(m_pidlHere, szPath))
  696. {
  697. *szPath = TEXT('\0');
  698. return FALSE;
  699. }
  700. #ifdef UNICODE
  701. // NOTE: we use GetShortPathName() to avoid losing characters during the
  702. // UNICODE->ANSI->UNICODE roundtrip while calling FDICopy()
  703. // NOTE: It is valid for GetShortPathName()'s src and dest pointers to be the same
  704. // If this fails, we'll just ignore the error and try to use the long path name
  705. GetShortPathName(szPath, szPath, MAX_PATH);
  706. #endif // UNICODE
  707. return(TRUE);
  708. }
  709. void CCabFolder::GetNameOf(LPCABITEM pit, LPSTRRET lpName)
  710. {
  711. #ifdef UNICODE
  712. lpName->uType = STRRET_WSTR;
  713. lpName->pOleStr = NULL;
  714. #else
  715. lpName->uType = STRRET_CSTR;
  716. lpName->cStr[0] = '\0';
  717. #endif
  718. LPCWSTR pszName;
  719. WSTR_ALIGNED_STACK_COPY(&pszName, pit->szName);
  720. SHFILEINFO sfi;
  721. if (SHGetFileInfo(pszName + pit->cPathChars, 0, &sfi, sizeof(sfi),
  722. SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME))
  723. {
  724. StringToStrRet(sfi.szDisplayName, lpName);
  725. }
  726. }
  727. void CCabFolder::GetPathOf(LPCABITEM pit, LPSTRRET lpName)
  728. {
  729. WCHAR szPath[MAX_PATH];
  730. ualstrcpynW(szPath, pit->szName, ARRAYSIZE(szPath));
  731. szPath[pit->cPathChars] = TEXT('\0');
  732. StringToStrRet(szPath, lpName);
  733. }
  734. void CCabFolder::GetTypeOf(LPCABITEM pit, LPSTRRET lpName)
  735. {
  736. #ifdef UNICODE
  737. lpName->uType = STRRET_WSTR;
  738. lpName->pOleStr = NULL;
  739. #else
  740. lpName->uType = STRRET_CSTR;
  741. lpName->cStr[0] = '\0';
  742. #endif
  743. LPCWSTR pszName;
  744. WSTR_ALIGNED_STACK_COPY(&pszName, pit->szName);
  745. SHFILEINFO sfi;
  746. if (SHGetFileInfo(pszName + pit->cPathChars, 0, &sfi, sizeof(sfi),
  747. SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME))
  748. {
  749. StringToStrRet(sfi.szTypeName, lpName);
  750. }
  751. }
  752. //*****************************************************************************
  753. //
  754. // CCabFolder::EnumToList
  755. //
  756. // Purpose:
  757. //
  758. // This notify callback is called by the FDI routines. It adds the
  759. // file object from the cab file to the list.
  760. //
  761. // Parameters:
  762. //
  763. //
  764. //
  765. // Comments:
  766. //
  767. //*****************************************************************************
  768. void CALLBACK CCabFolder::EnumToList(LPCTSTR pszFile, DWORD dwSize, UINT date,
  769. UINT time, UINT attribs, LPARAM lParam)
  770. {
  771. CCabFolder *pThis = (CCabFolder *)lParam;
  772. pThis->m_lItems.AddItem(pszFile, dwSize, date, time, attribs);
  773. }
  774. HRESULT CCabFolder::InitItems()
  775. {
  776. switch (m_lItems.GetState())
  777. {
  778. case CCabItemList::State_Init:
  779. return NOERROR;
  780. case CCabItemList::State_OutOfMem:
  781. return E_OUTOFMEMORY;
  782. case CCabItemList::State_UnInit:
  783. default:
  784. break;
  785. }
  786. // Force the list to initialize
  787. m_lItems.InitList();
  788. TCHAR szHere[MAX_PATH];
  789. // the m_pidl has been set to current dir
  790. // get the path to the current directory
  791. if (!GetPath(szHere))
  792. {
  793. return(E_UNEXPECTED);
  794. }
  795. CCabItems ciHere(szHere);
  796. if (!ciHere.EnumItems(EnumToList, (LPARAM)this))
  797. {
  798. return(E_UNEXPECTED);
  799. }
  800. return NOERROR;
  801. }
  802. HRESULT CabFolder_CreateInstance(REFIID riid, void **ppvObj)
  803. {
  804. HRESULT hres;
  805. *ppvObj = NULL;
  806. HINSTANCE hCabinetDll = LoadLibrary(TEXT("CABINET.DLL"));
  807. if (hCabinetDll)
  808. {
  809. FreeLibrary(hCabinetDll);
  810. CCabFolder *pfolder = new CCabFolder;
  811. if (pfolder)
  812. hres = pfolder->QueryInterface(riid, ppvObj);
  813. else
  814. hres = E_OUTOFMEMORY;
  815. }
  816. else
  817. hres = E_UNEXPECTED;
  818. return hres;
  819. }
  820. UINT CCabItemList::GetState()
  821. {
  822. if (m_uStep == 0)
  823. {
  824. if (m_dpaList)
  825. {
  826. return(State_Init);
  827. }
  828. return(State_OutOfMem);
  829. }
  830. return(State_UnInit);
  831. }
  832. BOOL CCabItemList::StoreItem(LPITEMIDLIST pidl)
  833. {
  834. if (pidl)
  835. {
  836. if (InitList() && DPA_InsertPtr(m_dpaList, 0x7fff, (LPSTR)pidl)>=0)
  837. {
  838. return(TRUE);
  839. }
  840. ILFree(pidl);
  841. }
  842. CleanList();
  843. return FALSE;
  844. }
  845. BOOL CCabItemList::AddItems(LPCABITEM *apit, UINT cpit)
  846. {
  847. for (UINT i=0; i<cpit; ++i)
  848. {
  849. if (!StoreItem(ILClone((LPCITEMIDLIST)apit[i])))
  850. {
  851. return FALSE;
  852. }
  853. }
  854. return(TRUE);
  855. }
  856. BOOL CCabItemList::AddItem(LPCTSTR pszName, DWORD dwFileSize,
  857. UINT uFileDate, UINT uFileTime, UINT uFileAttribs)
  858. {
  859. return(StoreItem(CCabFolder::CreateIDList(pszName, dwFileSize, uFileDate, uFileTime,
  860. uFileAttribs)));
  861. }
  862. int CCabItemList::FindInList(LPCTSTR pszName, DWORD dwFileSize,
  863. UINT uFileDate, UINT uFileTime, UINT uFileAttribs)
  864. {
  865. // TODO: Linear search for now; binary later
  866. for (int i=DPA_GetPtrCount(m_dpaList)-1; i>=0; --i)
  867. {
  868. LPCABITEM pcab = (*this)[i];
  869. // all guys in the dpa are WORD-aligned but copy out anyway.
  870. LPCWSTR pszNameCopy;
  871. WSTR_ALIGNED_STACK_COPY(&pszNameCopy, pcab->szName);
  872. if ((lstrcmpi(pszName, pszNameCopy) == 0) &&
  873. (pcab->dwFileSize == dwFileSize) &&
  874. (pcab->uFileDate == uFileDate) &&
  875. (pcab->uFileTime == uFileTime) &&
  876. (pcab->uFileAttribs == uFileAttribs))
  877. {
  878. break;
  879. }
  880. }
  881. return(i);
  882. }
  883. BOOL CCabItemList::InitList()
  884. {
  885. switch (GetState())
  886. {
  887. case State_Init:
  888. return(TRUE);
  889. case State_OutOfMem:
  890. return FALSE;
  891. case State_UnInit:
  892. default:
  893. m_dpaList = DPA_Create(m_uStep);
  894. m_uStep = 0;
  895. return(InitList());
  896. }
  897. }
  898. void CCabItemList::CleanList()
  899. {
  900. if (m_uStep != 0)
  901. {
  902. m_dpaList = NULL;
  903. m_uStep = 0;
  904. return;
  905. }
  906. if (!m_dpaList)
  907. {
  908. return;
  909. }
  910. for (int i=DPA_GetPtrCount(m_dpaList)-1; i>=0; --i)
  911. {
  912. ILFree((LPITEMIDLIST)((*this)[i]));
  913. }
  914. DPA_Destroy(m_dpaList);
  915. m_dpaList = NULL;
  916. }