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.

855 lines
17 KiB

  1. //*******************************************************************************************
  2. //
  3. // Filename : CabItms.cpp
  4. //
  5. // Implementation file for CMemFile, CCabEnum and CCabExtract
  6. //
  7. // Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
  8. //
  9. //*******************************************************************************************
  10. #include "pch.h"
  11. #include "ccstock.h"
  12. #include "thisdll.h"
  13. #include "resource.h"
  14. #include "fdi.h"
  15. #include "cabitms.h"
  16. class CMemFile
  17. {
  18. public:
  19. CMemFile(HGLOBAL *phMem, DWORD dwSize);
  20. ~CMemFile() {}
  21. BOOL Create(LPCTSTR pszFile);
  22. BOOL Open(LPCTSTR pszFile, int oflag);
  23. LONG Seek(LONG dist, int seektype);
  24. UINT Read(LPVOID pv, UINT cb);
  25. UINT Write(LPVOID pv, UINT cb);
  26. HANDLE Close();
  27. private:
  28. HANDLE m_hf;
  29. HGLOBAL *m_phMem;
  30. DWORD m_dwSize;
  31. LONG m_lLoc;
  32. } ;
  33. CMemFile::CMemFile(HGLOBAL *phMem, DWORD dwSize) : m_hf(INVALID_HANDLE_VALUE), m_lLoc(0)
  34. {
  35. m_phMem = phMem;
  36. m_dwSize = dwSize;
  37. if (phMem)
  38. {
  39. *phMem = NULL;
  40. }
  41. }
  42. BOOL CMemFile::Create(LPCTSTR pszFile)
  43. {
  44. if (m_phMem)
  45. {
  46. if (*m_phMem)
  47. {
  48. return(FALSE);
  49. }
  50. *m_phMem = GlobalAlloc(LMEM_FIXED, m_dwSize);
  51. return(*m_phMem != NULL);
  52. }
  53. else
  54. {
  55. if (m_hf != INVALID_HANDLE_VALUE)
  56. {
  57. return(FALSE);
  58. }
  59. m_hf = CreateFile(pszFile,
  60. GENERIC_READ | GENERIC_WRITE,
  61. FILE_SHARE_READ,
  62. NULL,
  63. CREATE_ALWAYS,
  64. FILE_ATTRIBUTE_NORMAL,
  65. NULL);
  66. return (m_hf != INVALID_HANDLE_VALUE);
  67. }
  68. }
  69. BOOL CMemFile::Open(LPCTSTR pszFile, int oflag)
  70. {
  71. if (m_phMem)
  72. {
  73. return(FALSE);
  74. }
  75. else
  76. {
  77. if (m_hf != INVALID_HANDLE_VALUE)
  78. {
  79. return(FALSE);
  80. }
  81. m_hf = CreateFile(pszFile,
  82. GENERIC_READ,
  83. FILE_SHARE_READ,
  84. NULL,
  85. OPEN_EXISTING,
  86. oflag,
  87. NULL);
  88. return (m_hf != INVALID_HANDLE_VALUE);
  89. }
  90. }
  91. LONG CMemFile::Seek(LONG dist, int seektype)
  92. {
  93. if (m_phMem)
  94. {
  95. if (!*m_phMem)
  96. {
  97. return -1;
  98. }
  99. switch (seektype)
  100. {
  101. case FILE_BEGIN:
  102. break;
  103. case FILE_CURRENT:
  104. dist += m_lLoc;
  105. break;
  106. case FILE_END:
  107. dist = m_dwSize - dist;
  108. break;
  109. default:
  110. return -1;
  111. }
  112. if (dist<0 || dist>(LONG)m_dwSize)
  113. {
  114. return -1;
  115. }
  116. m_lLoc = dist;
  117. return(dist);
  118. }
  119. else
  120. {
  121. return(_llseek((HFILE)HandleToUlong(m_hf), dist, seektype));
  122. }
  123. }
  124. UINT CMemFile::Read(LPVOID pv, UINT cb)
  125. {
  126. if (m_phMem)
  127. {
  128. if (!*m_phMem)
  129. {
  130. return -1;
  131. }
  132. if (cb > m_dwSize - m_lLoc)
  133. {
  134. cb = m_dwSize - m_lLoc;
  135. }
  136. hmemcpy(pv, (LPSTR)(*m_phMem)+m_lLoc, cb);
  137. m_lLoc += cb;
  138. return(cb);
  139. }
  140. else
  141. {
  142. return(_lread((HFILE)HandleToUlong(m_hf), pv, cb));
  143. }
  144. }
  145. UINT CMemFile::Write(LPVOID pv, UINT cb)
  146. {
  147. if (m_phMem)
  148. {
  149. if (!*m_phMem)
  150. {
  151. return -1;
  152. }
  153. if (cb > m_dwSize - m_lLoc)
  154. {
  155. cb = m_dwSize - m_lLoc;
  156. }
  157. hmemcpy((LPSTR)(*m_phMem)+m_lLoc, pv, cb);
  158. m_lLoc += cb;
  159. return(cb);
  160. }
  161. else
  162. {
  163. return(_lwrite((HFILE)HandleToUlong(m_hf), (LPCSTR)pv, cb));
  164. }
  165. }
  166. HANDLE CMemFile::Close()
  167. {
  168. HANDLE hRet;
  169. if (m_phMem)
  170. {
  171. hRet = *m_phMem ? 0 : INVALID_HANDLE_VALUE;
  172. }
  173. else
  174. {
  175. hRet = LongToHandle(_lclose((HFILE)HandleToUlong(m_hf)));
  176. }
  177. delete this;
  178. return(hRet);
  179. }
  180. //*****************************************************************************
  181. //
  182. // CCabEnum
  183. //
  184. // Purpose:
  185. //
  186. // Class encapsulating all the FDI operations
  187. //
  188. // Comments:
  189. //
  190. //*****************************************************************************
  191. class CCabEnum
  192. {
  193. public:
  194. CCabEnum() : m_hfdi(0) {}
  195. ~CCabEnum() {}
  196. protected:
  197. static void HUGE * FAR DIAMONDAPI CabAlloc(ULONG cb);
  198. static void FAR DIAMONDAPI CabFree(void HUGE *pv);
  199. static INT_PTR FAR DIAMONDAPI CabOpen(char FAR *pszFile, int oflag, int pmode);
  200. static UINT FAR DIAMONDAPI CabRead(INT_PTR hf, void FAR *pv, UINT cb);
  201. static UINT FAR DIAMONDAPI CabWrite(INT_PTR hf, void FAR *pv, UINT cb);
  202. static int FAR DIAMONDAPI CabClose(INT_PTR hf);
  203. static long FAR DIAMONDAPI CabSeek(INT_PTR hf, long dist, int seektype);
  204. BOOL StartEnum();
  205. BOOL SimpleEnum(LPCTSTR szCabFile, PFNFDINOTIFY pfnCallBack, LPVOID pv);
  206. void EndEnum();
  207. HFDI m_hfdi;
  208. ERF m_erf;
  209. private:
  210. static CMemFile * s_hSpill;
  211. } ;
  212. CMemFile * CCabEnum::s_hSpill = NULL;
  213. void HUGE * FAR DIAMONDAPI CCabEnum::CabAlloc(ULONG cb)
  214. {
  215. return(GlobalAllocPtr(GHND, cb));
  216. }
  217. void FAR DIAMONDAPI CCabEnum::CabFree(void HUGE *pv)
  218. {
  219. GlobalFreePtr(pv);
  220. }
  221. INT_PTR FAR DIAMONDAPI CCabEnum::CabOpen(char FAR *pszFile, int oflag, int pmode)
  222. {
  223. if(!pszFile)
  224. {
  225. return -1;
  226. }
  227. // See if we are opening the spill file.
  228. if( *pszFile=='*' )
  229. {
  230. TCHAR szSpillFile[MAX_PATH];
  231. TCHAR szTempPath[MAX_PATH];
  232. if(s_hSpill != NULL)
  233. return -1;
  234. GetTempPath(ARRAYSIZE(szTempPath), szTempPath);
  235. GetTempFileName(szTempPath, TEXT("fdi"), 0, szSpillFile);
  236. s_hSpill = new CMemFile(NULL, 0);
  237. if (!s_hSpill)
  238. {
  239. return(-1);
  240. }
  241. if (!s_hSpill->Create(szSpillFile))
  242. {
  243. delete s_hSpill;
  244. s_hSpill = NULL;
  245. return(-1);
  246. }
  247. // Set its extent.
  248. if( s_hSpill->Seek( ((FDISPILLFILE FAR *)pszFile)->cbFile-1, 0) == HFILE_ERROR)
  249. {
  250. s_hSpill->Close();
  251. s_hSpill = NULL;
  252. return -1;
  253. }
  254. s_hSpill->Write(szSpillFile, 1);
  255. return (INT_PTR)s_hSpill;
  256. }
  257. CMemFile *hFile = new CMemFile(NULL, 0);
  258. if (!hFile)
  259. {
  260. return(-1);
  261. }
  262. TCHAR szFile[MAX_PATH];
  263. SHAnsiToTChar(pszFile, szFile, ARRAYSIZE(szFile));
  264. while (!hFile->Open(szFile, oflag))
  265. {
  266. #if 1 // TODO: No UI for inserting a disk at this point
  267. delete hFile;
  268. return(-1);
  269. #else
  270. // Failed to open the source.
  271. if (!LoadString (g_hInst, IDS_DISKPROMPT, szText, MAX_STRTABLE_LEN))
  272. return -1;
  273. char szText[MAX_PATH];
  274. wsprintf (g_pErrorBuffer, (LPSTR)szText, (LPSTR)g_pCabName);
  275. // Use hwndIniting to have a parent window
  276. if ( MyMessageBox(g_hwndIniting, g_pErrorBuffer,
  277. MAKEINTRESOURCE(IDS_DISKPROMPT_TIT),
  278. MB_OKCANCEL|MB_ICONSTOP, 0) == IDOK )
  279. continue;
  280. else
  281. return -1;
  282. #endif
  283. }
  284. return((INT_PTR)hFile);
  285. }
  286. UINT FAR DIAMONDAPI CCabEnum::CabRead(INT_PTR hf, void FAR *pv, UINT cb)
  287. {
  288. CMemFile *hFile = (CMemFile *)hf;
  289. return(hFile->Read(pv,cb));
  290. }
  291. UINT FAR DIAMONDAPI CCabEnum::CabWrite(INT_PTR hf, void FAR *pv, UINT cb)
  292. {
  293. CMemFile *hFile = (CMemFile *)hf;
  294. return(hFile->Write(pv,cb));
  295. }
  296. int FAR DIAMONDAPI CCabEnum::CabClose(INT_PTR hf)
  297. {
  298. CMemFile *hFile = (CMemFile *)hf;
  299. // Special case for the deletion of the spill file.
  300. if(hFile == s_hSpill)
  301. {
  302. s_hSpill = NULL;
  303. }
  304. return (int)HandleToUlong(hFile->Close());
  305. }
  306. long FAR DIAMONDAPI CCabEnum::CabSeek(INT_PTR hf, long dist, int seektype)
  307. {
  308. CMemFile *hFile = (CMemFile *)hf;
  309. return(hFile->Seek(dist, seektype));
  310. }
  311. BOOL CCabEnum::StartEnum()
  312. {
  313. if (m_hfdi)
  314. {
  315. // We seem to already be enumerating
  316. return(FALSE);
  317. }
  318. m_hfdi = FDICreate(
  319. CabAlloc,
  320. CabFree,
  321. CabOpen,
  322. CabRead,
  323. CabWrite,
  324. CabClose,
  325. CabSeek,
  326. cpu80386,
  327. &m_erf);
  328. return(m_hfdi != NULL);
  329. }
  330. BOOL CCabEnum::SimpleEnum(LPCTSTR szCabFile, PFNFDINOTIFY pfnCallBack, LPVOID pv)
  331. {
  332. char szCabPath[MAX_PATH];
  333. char szCabName[MAX_PATH];
  334. // Path should be fully qualified
  335. char szFile[MAX_PATH];
  336. SHTCharToAnsi(szCabFile, szFile, ARRAYSIZE(szFile));
  337. lstrcpynA(szCabPath, szFile, sizeof(szCabPath));
  338. LPSTR pszName = PathFindFileNameA(szCabPath);
  339. if (!pszName)
  340. {
  341. return(FALSE);
  342. }
  343. lstrcpyA(szCabName, pszName);
  344. *pszName = '\0';
  345. if (!StartEnum())
  346. {
  347. return(FALSE);
  348. }
  349. BOOL bRet = FDICopy(
  350. m_hfdi,
  351. szCabName,
  352. szCabPath, // path to cabinet files
  353. 0, // flags
  354. pfnCallBack,
  355. NULL,
  356. pv);
  357. EndEnum();
  358. return(bRet);
  359. }
  360. void CCabEnum::EndEnum()
  361. {
  362. if (!m_hfdi)
  363. {
  364. return;
  365. }
  366. FDIDestroy(m_hfdi);
  367. m_hfdi = NULL;
  368. }
  369. class CCabItemsCB : private CCabEnum
  370. {
  371. public:
  372. CCabItemsCB(CCabItems::PFNCABITEM pfnCallBack, LPARAM lParam)
  373. {
  374. m_pfnCallBack = pfnCallBack;
  375. m_lParam = lParam;
  376. }
  377. ~CCabItemsCB() {}
  378. BOOL DoEnum(LPCTSTR szCabFile)
  379. {
  380. return(SimpleEnum(szCabFile, CabItemsNotify, this));
  381. }
  382. private:
  383. static INT_PTR FAR DIAMONDAPI CabItemsNotify(FDINOTIFICATIONTYPE fdint,
  384. PFDINOTIFICATION pfdin);
  385. CCabItems::PFNCABITEM m_pfnCallBack;
  386. LPARAM m_lParam;
  387. } ;
  388. INT_PTR FAR DIAMONDAPI CCabItemsCB::CabItemsNotify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
  389. {
  390. CCabItemsCB *pThis = (CCabItemsCB *)pfdin->pv;
  391. // uiYield( g_hwndSetup );
  392. TCHAR szFile[MAX_PATH];
  393. if (NULL != pfdin->psz1)
  394. {
  395. // NOTE: CP_UTF8 is not supported on Win9x!
  396. SHAnsiToTCharCP((_A_NAME_IS_UTF & pfdin->attribs) ? CP_UTF8 : CP_ACP,
  397. pfdin->psz1,
  398. szFile,
  399. ARRAYSIZE(szFile));
  400. }
  401. switch (fdint)
  402. {
  403. case fdintCOPY_FILE:
  404. pThis->m_pfnCallBack(pfdin->psz1 ? szFile : NULL,
  405. pfdin->cb,
  406. pfdin->date,
  407. pfdin->time,
  408. pfdin->attribs,
  409. pThis->m_lParam);
  410. break;
  411. default:
  412. break;
  413. } // end switch
  414. return 0;
  415. }
  416. //*****************************************************************************
  417. //
  418. // CCabItems::EnumItems
  419. //
  420. // Purpose:
  421. //
  422. // Enumerate the items in the cab file
  423. //
  424. //
  425. // Comments:
  426. //
  427. // lParam contains pointer to CCabFolder
  428. //
  429. //*****************************************************************************
  430. BOOL CCabItems::EnumItems(PFNCABITEM pfnCallBack, LPARAM lParam)
  431. {
  432. CCabItemsCB cItems(pfnCallBack, lParam);
  433. return(cItems.DoEnum(m_szCabFile));
  434. }
  435. //*****************************************************************************
  436. //
  437. // CCabExtractCB
  438. //
  439. // Purpose:
  440. //
  441. // handles the call back while extracting Cab files
  442. //
  443. //
  444. //*****************************************************************************
  445. class CCabExtractCB : private CCabEnum
  446. {
  447. public:
  448. CCabExtractCB(LPCTSTR szDir, HWND hwndOwner, CCabExtract::PFNCABEXTRACT pfnCallBack,
  449. LPARAM lParam)
  450. {
  451. m_szDir = szDir;
  452. m_hwndOwner = hwndOwner;
  453. m_pfnCallBack = pfnCallBack;
  454. m_lParam = lParam;
  455. m_bTryNextCab = FALSE;
  456. }
  457. ~CCabExtractCB() {}
  458. BOOL DoEnum(LPCTSTR szCabFile)
  459. {
  460. return(SimpleEnum(szCabFile, CabExtractNotify, this));
  461. }
  462. private:
  463. static INT_PTR FAR DIAMONDAPI CabExtractNotify(FDINOTIFICATIONTYPE fdint,
  464. PFDINOTIFICATION pfdin);
  465. static int CALLBACK CCabExtractCB::BrowseNotify(HWND hwnd, UINT uMsg, LPARAM lParam,
  466. LPARAM lpData);
  467. LPCTSTR m_szDir;
  468. HWND m_hwndOwner;
  469. CCabExtract::PFNCABEXTRACT m_pfnCallBack;
  470. LPARAM m_lParam;
  471. BOOL m_bTryNextCab;
  472. PFDINOTIFICATION m_pfdin;
  473. } ;
  474. int CALLBACK CCabExtractCB::BrowseNotify(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  475. {
  476. CCabExtractCB *pThis = (CCabExtractCB *)lpData;
  477. switch (uMsg)
  478. {
  479. case BFFM_INITIALIZED:
  480. {
  481. // Set initial folder
  482. LPSTR pszEnd = PathAddBackslashA(pThis->m_pfdin->psz3);
  483. if (pszEnd - pThis->m_pfdin->psz3 > 3)
  484. {
  485. // No problems if not drive root
  486. *(pszEnd - 1) = '\0';
  487. }
  488. SendMessage(hwnd, BFFM_SETSELECTION, 1, (LPARAM)pThis->m_pfdin->psz3);
  489. break;
  490. }
  491. default:
  492. return(0);
  493. }
  494. return(1);
  495. }
  496. INT_PTR FAR DIAMONDAPI CCabExtractCB::CabExtractNotify(FDINOTIFICATIONTYPE fdint,
  497. PFDINOTIFICATION pfdin)
  498. {
  499. CCabExtractCB *pThis = (CCabExtractCB *)pfdin->pv;
  500. // uiYield( g_hwndSetup );
  501. switch (fdint)
  502. {
  503. case fdintCABINET_INFO:
  504. pThis->m_bTryNextCab = TRUE;
  505. break;
  506. case fdintNEXT_CABINET:
  507. {
  508. if (pThis->m_bTryNextCab)
  509. {
  510. // Automatically open next cab if already in default dir
  511. pThis->m_bTryNextCab = FALSE;
  512. return(1);
  513. }
  514. pThis->m_pfdin = pfdin;
  515. TCHAR szFormat[80];
  516. TCHAR szTitle[80 + 2*MAX_PATH];
  517. if (pfdin->psz2[0] != '\0')
  518. {
  519. LoadString(g_ThisDll.GetInstance(), IDS_NEXTDISKBROWSE, szFormat, ARRAYSIZE(szFormat));
  520. }
  521. else
  522. {
  523. LoadString(g_ThisDll.GetInstance(), IDS_NEXTCABBROWSE, szFormat, ARRAYSIZE(szFormat));
  524. }
  525. wsprintf(szTitle, szFormat, (LPSTR) (pfdin->psz1), (LPSTR) (pfdin->psz2));
  526. BROWSEINFO bi;
  527. bi.hwndOwner = pThis->m_hwndOwner;
  528. bi.pidlRoot = NULL;
  529. bi.pszDisplayName = NULL;
  530. bi.lpszTitle = szTitle;
  531. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
  532. bi.lpfn = BrowseNotify;
  533. bi.lParam = (LPARAM)pThis;
  534. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  535. if (bi.pidlRoot)
  536. {
  537. ILFree((LPITEMIDLIST)bi.pidlRoot);
  538. }
  539. if (!pidl)
  540. {
  541. return(-1);
  542. }
  543. BOOL bSuccess = SHGetPathFromIDListA(pidl, pfdin->psz3);
  544. ILFree(pidl);
  545. if (bSuccess)
  546. {
  547. PathAddBackslashA(pfdin->psz3);
  548. return(1);
  549. }
  550. return(-1);
  551. }
  552. case fdintCOPY_FILE:
  553. {
  554. TCHAR szFile[MAX_PATH];
  555. if (NULL != pfdin->psz1)
  556. {
  557. // NOTE: CP_UTF8 is not supported on Win9x!
  558. SHAnsiToTCharCP((_A_NAME_IS_UTF & pfdin->attribs) ? CP_UTF8 : CP_ACP,
  559. pfdin->psz1,
  560. szFile,
  561. ARRAYSIZE(szFile));
  562. }
  563. else
  564. {
  565. szFile[0] = TEXT('\0');
  566. }
  567. HGLOBAL *phMem = pThis->m_pfnCallBack(pfdin->psz1 ? szFile : NULL,
  568. pfdin->cb,
  569. pfdin->date,
  570. pfdin->time,
  571. pfdin->attribs,
  572. pThis->m_lParam);
  573. if (!phMem)
  574. {
  575. break;
  576. }
  577. TCHAR szTemp[MAX_PATH];
  578. CMemFile *hFile;
  579. if (pThis->m_szDir == DIR_MEM)
  580. {
  581. *szTemp = '\0';
  582. hFile = new CMemFile(phMem, pfdin->cb);
  583. }
  584. else
  585. {
  586. PathCombine(szTemp, pThis->m_szDir, PathFindFileName(szFile));
  587. hFile = new CMemFile(NULL, 0);
  588. }
  589. if (!hFile)
  590. {
  591. break;
  592. }
  593. if (hFile->Create(szTemp))
  594. {
  595. return((INT_PTR)hFile);
  596. }
  597. delete hFile;
  598. break;
  599. }
  600. case fdintCLOSE_FILE_INFO:
  601. {
  602. CMemFile *hFile = (CMemFile *)pfdin->hf;
  603. return(hFile->Close() == 0);
  604. }
  605. default:
  606. break;
  607. } // end switch
  608. return 0;
  609. }
  610. HRESULT CCabExtract::_DoDragDrop(HWND hwnd, IDataObject* pdo, LPCITEMIDLIST pidlFolder)
  611. {
  612. IShellFolder *psf;
  613. HRESULT hres = SHBindToObject(NULL, IID_IShellFolder, pidlFolder, (LPVOID*)&psf);
  614. // This should always succeed because the caller (SHBrowseForFolder) should
  615. // have weeded out the non-folders.
  616. if (SUCCEEDED(hres))
  617. {
  618. IDropTarget *pdrop;
  619. hres = psf->CreateViewObject(NULL, IID_IDropTarget, (void**)&pdrop);
  620. if (SUCCEEDED(hres)) // Will fail for some targets. (Like Nethood->Entire Network)
  621. {
  622. // May fail if items aren't compatible for drag/drop. (Nethood is one example)
  623. // MK_CONTROL | MKLBUTTON is used to suggest a "copy":
  624. hres = SHSimulateDrop(pdrop, pdo, MK_CONTROL | MK_LBUTTON, NULL, NULL);
  625. pdrop->Release();
  626. }
  627. psf->Release();
  628. }
  629. return hres;
  630. }
  631. int BrowseCallback(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData)
  632. {
  633. switch (msg)
  634. {
  635. case BFFM_INITIALIZED:
  636. {
  637. // Set the caption. ('Select a destination')
  638. TCHAR szTitle[100];
  639. LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE_CAPTION, szTitle, ARRAYSIZE(szTitle));
  640. SetWindowText(hwnd, szTitle);
  641. // Set the text of the Ok Button.
  642. TCHAR szOK[100];
  643. LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE_EXTRACT, szOK, ARRAYSIZE(szOK));
  644. SendMessage(hwnd, BFFM_SETOKTEXT, 0, (LPARAM)szOK);
  645. }
  646. break;
  647. case BFFM_SELCHANGED:
  648. {
  649. LPITEMIDLIST pidl = (LPITEMIDLIST)lParam;
  650. BOOL bEnableOk = FALSE;
  651. IShellFolder *psf;
  652. LPCITEMIDLIST pidlChild;
  653. if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
  654. {
  655. DWORD dwAttributes = SFGAO_FILESYSTEM;
  656. psf->GetAttributesOf(1, &pidlChild, &dwAttributes);
  657. psf->Release();
  658. bEnableOk = dwAttributes & SFGAO_FILESYSTEM; // is FS?
  659. }
  660. SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM) 0, (LPARAM) bEnableOk);
  661. }
  662. break;
  663. }
  664. return 0;
  665. }
  666. BOOL CCabExtract::ExtractToFolder(HWND hwndOwner, IDataObject* pdo, PFNCABEXTRACT pfnCallBack, LPARAM lParam)
  667. {
  668. // ASSERT(pdo);
  669. TCHAR szTitle[120];
  670. LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE, szTitle, ARRAYSIZE(szTitle));
  671. BROWSEINFO bi;
  672. bi.hwndOwner = hwndOwner;
  673. bi.pidlRoot = NULL;
  674. bi.pszDisplayName = NULL;
  675. bi.lpszTitle = szTitle;
  676. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_UAHINT;
  677. bi.lpfn = BrowseCallback;
  678. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  679. if (!pidl)
  680. {
  681. return(FALSE);
  682. }
  683. BOOL bSuccess = SUCCEEDED(_DoDragDrop(hwndOwner, pdo, pidl));
  684. ILFree(pidl);
  685. return bSuccess;
  686. }
  687. BOOL CCabExtract::ExtractItems(HWND hwndOwner, LPCTSTR szDir, PFNCABEXTRACT pfnCallBack, LPARAM lParam)
  688. {
  689. // ASSERT(szDir);
  690. CCabExtractCB cExtract(szDir, hwndOwner, pfnCallBack, lParam);
  691. // Display Wait cursor until done copying
  692. CWaitCursor cWait;
  693. return(cExtract.DoEnum(m_szCabFile));
  694. }