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.

837 lines
18 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. // TODO: No UI for inserting a disk at this point
  267. delete hFile;
  268. return(-1);
  269. }
  270. return((INT_PTR)hFile);
  271. }
  272. UINT FAR DIAMONDAPI CCabEnum::CabRead(INT_PTR hf, void FAR *pv, UINT cb)
  273. {
  274. CMemFile *hFile = (CMemFile *)hf;
  275. return(hFile->Read(pv,cb));
  276. }
  277. UINT FAR DIAMONDAPI CCabEnum::CabWrite(INT_PTR hf, void FAR *pv, UINT cb)
  278. {
  279. CMemFile *hFile = (CMemFile *)hf;
  280. return(hFile->Write(pv,cb));
  281. }
  282. int FAR DIAMONDAPI CCabEnum::CabClose(INT_PTR hf)
  283. {
  284. CMemFile *hFile = (CMemFile *)hf;
  285. // Special case for the deletion of the spill file.
  286. if(hFile == s_hSpill)
  287. {
  288. s_hSpill = NULL;
  289. }
  290. return (int)HandleToUlong(hFile->Close());
  291. }
  292. long FAR DIAMONDAPI CCabEnum::CabSeek(INT_PTR hf, long dist, int seektype)
  293. {
  294. CMemFile *hFile = (CMemFile *)hf;
  295. return(hFile->Seek(dist, seektype));
  296. }
  297. BOOL CCabEnum::StartEnum()
  298. {
  299. if (m_hfdi)
  300. {
  301. // We seem to already be enumerating
  302. return(FALSE);
  303. }
  304. m_hfdi = FDICreate(
  305. CabAlloc,
  306. CabFree,
  307. CabOpen,
  308. CabRead,
  309. CabWrite,
  310. CabClose,
  311. CabSeek,
  312. cpu80386,
  313. &m_erf);
  314. return(m_hfdi != NULL);
  315. }
  316. BOOL CCabEnum::SimpleEnum(LPCTSTR szCabFile, PFNFDINOTIFY pfnCallBack, LPVOID pv)
  317. {
  318. char szCabPath[MAX_PATH];
  319. char szCabName[MAX_PATH];
  320. // Path should be fully qualified
  321. char szFile[MAX_PATH];
  322. SHTCharToAnsi(szCabFile, szFile, ARRAYSIZE(szFile));
  323. lstrcpynA(szCabPath, szFile, ARRAYSIZE(szCabPath));
  324. LPSTR pszName = PathFindFileNameA(szCabPath);
  325. if (!pszName)
  326. {
  327. return(FALSE);
  328. }
  329. lstrcpynA(szCabName, pszName, ARRAYSIZE(szCabName));
  330. *pszName = '\0';
  331. if (!StartEnum())
  332. {
  333. return(FALSE);
  334. }
  335. BOOL bRet = FDICopy(
  336. m_hfdi,
  337. szCabName,
  338. szCabPath, // path to cabinet files
  339. 0, // flags
  340. pfnCallBack,
  341. NULL,
  342. pv);
  343. EndEnum();
  344. return(bRet);
  345. }
  346. void CCabEnum::EndEnum()
  347. {
  348. if (!m_hfdi)
  349. {
  350. return;
  351. }
  352. FDIDestroy(m_hfdi);
  353. m_hfdi = NULL;
  354. }
  355. class CCabItemsCB : private CCabEnum
  356. {
  357. public:
  358. CCabItemsCB(CCabItems::PFNCABITEM pfnCallBack, LPARAM lParam)
  359. {
  360. m_pfnCallBack = pfnCallBack;
  361. m_lParam = lParam;
  362. }
  363. ~CCabItemsCB() {}
  364. BOOL DoEnum(LPCTSTR szCabFile)
  365. {
  366. return(SimpleEnum(szCabFile, CabItemsNotify, this));
  367. }
  368. private:
  369. static INT_PTR FAR DIAMONDAPI CabItemsNotify(FDINOTIFICATIONTYPE fdint,
  370. PFDINOTIFICATION pfdin);
  371. CCabItems::PFNCABITEM m_pfnCallBack;
  372. LPARAM m_lParam;
  373. } ;
  374. INT_PTR FAR DIAMONDAPI CCabItemsCB::CabItemsNotify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
  375. {
  376. CCabItemsCB *pThis = (CCabItemsCB *)pfdin->pv;
  377. // uiYield( g_hwndSetup );
  378. TCHAR szFile[MAX_PATH];
  379. if (NULL != pfdin->psz1)
  380. {
  381. // NOTE: CP_UTF8 is not supported on Win9x!
  382. SHAnsiToTCharCP((_A_NAME_IS_UTF & pfdin->attribs) ? CP_UTF8 : CP_ACP,
  383. pfdin->psz1,
  384. szFile,
  385. ARRAYSIZE(szFile));
  386. }
  387. switch (fdint)
  388. {
  389. case fdintCOPY_FILE:
  390. pThis->m_pfnCallBack(pfdin->psz1 ? szFile : NULL,
  391. pfdin->cb,
  392. pfdin->date,
  393. pfdin->time,
  394. pfdin->attribs,
  395. pThis->m_lParam);
  396. break;
  397. default:
  398. break;
  399. } // end switch
  400. return 0;
  401. }
  402. //*****************************************************************************
  403. //
  404. // CCabItems::EnumItems
  405. //
  406. // Purpose:
  407. //
  408. // Enumerate the items in the cab file
  409. //
  410. //
  411. // Comments:
  412. //
  413. // lParam contains pointer to CCabFolder
  414. //
  415. //*****************************************************************************
  416. BOOL CCabItems::EnumItems(PFNCABITEM pfnCallBack, LPARAM lParam)
  417. {
  418. CCabItemsCB cItems(pfnCallBack, lParam);
  419. return(cItems.DoEnum(m_szCabFile));
  420. }
  421. //*****************************************************************************
  422. //
  423. // CCabExtractCB
  424. //
  425. // Purpose:
  426. //
  427. // handles the call back while extracting Cab files
  428. //
  429. //
  430. //*****************************************************************************
  431. class CCabExtractCB : private CCabEnum
  432. {
  433. public:
  434. CCabExtractCB(LPCTSTR szDir, HWND hwndOwner, CCabExtract::PFNCABEXTRACT pfnCallBack,
  435. LPARAM lParam)
  436. {
  437. m_szDir = szDir;
  438. m_hwndOwner = hwndOwner;
  439. m_pfnCallBack = pfnCallBack;
  440. m_lParam = lParam;
  441. m_bTryNextCab = FALSE;
  442. }
  443. ~CCabExtractCB() {}
  444. BOOL DoEnum(LPCTSTR szCabFile)
  445. {
  446. return(SimpleEnum(szCabFile, CabExtractNotify, this));
  447. }
  448. private:
  449. static INT_PTR FAR DIAMONDAPI CabExtractNotify(FDINOTIFICATIONTYPE fdint,
  450. PFDINOTIFICATION pfdin);
  451. static int CALLBACK CCabExtractCB::BrowseNotify(HWND hwnd, UINT uMsg, LPARAM lParam,
  452. LPARAM lpData);
  453. LPCTSTR m_szDir;
  454. HWND m_hwndOwner;
  455. CCabExtract::PFNCABEXTRACT m_pfnCallBack;
  456. LPARAM m_lParam;
  457. BOOL m_bTryNextCab;
  458. PFDINOTIFICATION m_pfdin;
  459. } ;
  460. int CALLBACK CCabExtractCB::BrowseNotify(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  461. {
  462. CCabExtractCB *pThis = (CCabExtractCB *)lpData;
  463. switch (uMsg)
  464. {
  465. case BFFM_INITIALIZED:
  466. {
  467. // Set initial folder
  468. if (lstrlenA(pThis->m_pfdin->psz3) < 3)
  469. {
  470. // append if drive root
  471. PathAddBackslashA(pThis->m_pfdin->psz3);
  472. }
  473. SendMessage(hwnd, BFFM_SETSELECTION, 1, (LPARAM)pThis->m_pfdin->psz3);
  474. break;
  475. }
  476. default:
  477. return(0);
  478. }
  479. return(1);
  480. }
  481. INT_PTR FAR DIAMONDAPI CCabExtractCB::CabExtractNotify(FDINOTIFICATIONTYPE fdint,
  482. PFDINOTIFICATION pfdin)
  483. {
  484. CCabExtractCB *pThis = (CCabExtractCB *)pfdin->pv;
  485. // uiYield( g_hwndSetup );
  486. switch (fdint)
  487. {
  488. case fdintCABINET_INFO:
  489. pThis->m_bTryNextCab = TRUE;
  490. break;
  491. case fdintNEXT_CABINET:
  492. {
  493. if (pThis->m_bTryNextCab)
  494. {
  495. // Automatically open next cab if already in default dir
  496. pThis->m_bTryNextCab = FALSE;
  497. return(1);
  498. }
  499. pThis->m_pfdin = pfdin;
  500. TCHAR szFormat[80];
  501. TCHAR szTitle[80 + 2*MAX_PATH];
  502. if (pfdin->psz2[0] != '\0')
  503. {
  504. LoadString(g_ThisDll.GetInstance(), IDS_NEXTDISKBROWSE, szFormat, ARRAYSIZE(szFormat));
  505. }
  506. else
  507. {
  508. LoadString(g_ThisDll.GetInstance(), IDS_NEXTCABBROWSE, szFormat, ARRAYSIZE(szFormat));
  509. }
  510. wnsprintf(szTitle, ARRAYSIZE(szTitle), szFormat, (LPSTR) (pfdin->psz1), (LPSTR) (pfdin->psz2));
  511. BROWSEINFO bi;
  512. bi.hwndOwner = pThis->m_hwndOwner;
  513. bi.pidlRoot = NULL;
  514. bi.pszDisplayName = NULL;
  515. bi.lpszTitle = szTitle;
  516. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
  517. bi.lpfn = BrowseNotify;
  518. bi.lParam = (LPARAM)pThis;
  519. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  520. if (bi.pidlRoot)
  521. {
  522. ILFree((LPITEMIDLIST)bi.pidlRoot);
  523. }
  524. if (!pidl)
  525. {
  526. return(-1);
  527. }
  528. CHAR szPath[MAX_PATH];
  529. BOOL bSuccess = SHGetPathFromIDListA(pidl, szPath);
  530. ILFree(pidl);
  531. if (bSuccess)
  532. {
  533. PathAddBackslashA(szPath);
  534. StrCpyNA(pfdin->psz3, szPath, 256); // psz3 is 256 bytes long...
  535. return(1);
  536. }
  537. return(-1);
  538. }
  539. case fdintCOPY_FILE:
  540. {
  541. TCHAR szFile[MAX_PATH];
  542. if (NULL != pfdin->psz1)
  543. {
  544. // NOTE: CP_UTF8 is not supported on Win9x!
  545. SHAnsiToTCharCP((_A_NAME_IS_UTF & pfdin->attribs) ? CP_UTF8 : CP_ACP,
  546. pfdin->psz1,
  547. szFile,
  548. ARRAYSIZE(szFile));
  549. }
  550. else
  551. {
  552. szFile[0] = TEXT('\0');
  553. }
  554. HGLOBAL *phMem = pThis->m_pfnCallBack(pfdin->psz1 ? szFile : NULL,
  555. pfdin->cb,
  556. pfdin->date,
  557. pfdin->time,
  558. pfdin->attribs,
  559. pThis->m_lParam);
  560. if (!phMem)
  561. {
  562. break;
  563. }
  564. TCHAR szTemp[MAX_PATH];
  565. CMemFile *hFile;
  566. if (pThis->m_szDir == DIR_MEM)
  567. {
  568. *szTemp = '\0';
  569. hFile = new CMemFile(phMem, pfdin->cb);
  570. }
  571. else
  572. {
  573. PathCombine(szTemp, pThis->m_szDir, PathFindFileName(szFile));
  574. hFile = new CMemFile(NULL, 0);
  575. }
  576. if (!hFile)
  577. {
  578. break;
  579. }
  580. if (hFile->Create(szTemp))
  581. {
  582. return((INT_PTR)hFile);
  583. }
  584. delete hFile;
  585. break;
  586. }
  587. case fdintCLOSE_FILE_INFO:
  588. {
  589. CMemFile *hFile = (CMemFile *)pfdin->hf;
  590. return(hFile->Close() == 0);
  591. }
  592. default:
  593. break;
  594. } // end switch
  595. return 0;
  596. }
  597. HRESULT CCabExtract::_DoDragDrop(HWND hwnd, IDataObject* pdo, LPCITEMIDLIST pidlFolder)
  598. {
  599. IShellFolder *psf;
  600. HRESULT hres = SHBindToObject(NULL, IID_IShellFolder, pidlFolder, (LPVOID*)&psf);
  601. // This should always succeed because the caller (SHBrowseForFolder) should
  602. // have weeded out the non-folders.
  603. if (SUCCEEDED(hres))
  604. {
  605. IDropTarget *pdrop;
  606. hres = psf->CreateViewObject(NULL, IID_IDropTarget, (void**)&pdrop);
  607. if (SUCCEEDED(hres)) // Will fail for some targets. (Like Nethood->Entire Network)
  608. {
  609. // May fail if items aren't compatible for drag/drop. (Nethood is one example)
  610. // MK_CONTROL | MKLBUTTON is used to suggest a "copy":
  611. hres = SHSimulateDrop(pdrop, pdo, MK_CONTROL | MK_LBUTTON, NULL, NULL);
  612. pdrop->Release();
  613. }
  614. psf->Release();
  615. }
  616. return hres;
  617. }
  618. int BrowseCallback(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData)
  619. {
  620. switch (msg)
  621. {
  622. case BFFM_INITIALIZED:
  623. {
  624. // Set the caption. ('Select a destination')
  625. TCHAR szTitle[100];
  626. LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE_CAPTION, szTitle, ARRAYSIZE(szTitle));
  627. SetWindowText(hwnd, szTitle);
  628. // Set the text of the Ok Button.
  629. TCHAR szOK[100];
  630. LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE_EXTRACT, szOK, ARRAYSIZE(szOK));
  631. SendMessage(hwnd, BFFM_SETOKTEXT, 0, (LPARAM)szOK);
  632. }
  633. break;
  634. case BFFM_SELCHANGED:
  635. {
  636. LPITEMIDLIST pidl = (LPITEMIDLIST)lParam;
  637. BOOL bEnableOk = FALSE;
  638. IShellFolder *psf;
  639. LPCITEMIDLIST pidlChild;
  640. if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
  641. {
  642. DWORD dwAttributes = SFGAO_FILESYSTEM;
  643. psf->GetAttributesOf(1, &pidlChild, &dwAttributes);
  644. psf->Release();
  645. bEnableOk = dwAttributes & SFGAO_FILESYSTEM; // is FS?
  646. }
  647. SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM) 0, (LPARAM) bEnableOk);
  648. }
  649. break;
  650. }
  651. return 0;
  652. }
  653. BOOL CCabExtract::ExtractToFolder(HWND hwndOwner, IDataObject* pdo, PFNCABEXTRACT pfnCallBack, LPARAM lParam)
  654. {
  655. // ASSERT(pdo);
  656. TCHAR szTitle[120];
  657. LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE, szTitle, ARRAYSIZE(szTitle));
  658. BROWSEINFO bi;
  659. bi.hwndOwner = hwndOwner;
  660. bi.pidlRoot = NULL;
  661. bi.pszDisplayName = NULL;
  662. bi.lpszTitle = szTitle;
  663. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_UAHINT;
  664. bi.lpfn = BrowseCallback;
  665. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  666. if (!pidl)
  667. {
  668. return(FALSE);
  669. }
  670. BOOL bSuccess = SUCCEEDED(_DoDragDrop(hwndOwner, pdo, pidl));
  671. ILFree(pidl);
  672. return bSuccess;
  673. }
  674. BOOL CCabExtract::ExtractItems(HWND hwndOwner, LPCTSTR szDir, PFNCABEXTRACT pfnCallBack, LPARAM lParam)
  675. {
  676. // ASSERT(szDir);
  677. CCabExtractCB cExtract(szDir, hwndOwner, pfnCallBack, lParam);
  678. // Display Wait cursor until done copying
  679. CWaitCursor cWait;
  680. return(cExtract.DoEnum(m_szCabFile));
  681. }