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.

2237 lines
64 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: ibrfstg.c
  6. //
  7. // This files contains the IBriefcaseStg interface.
  8. //
  9. // History:
  10. // 02-02-94 ScottH Converted from iface.c
  11. //
  12. //---------------------------------------------------------------------------
  13. #include "brfprv.h" // common headers
  14. #undef LODWORD // (because they are redefined by configmg.h)
  15. #undef HIDWORD
  16. #include <brfcasep.h>
  17. #include "recact.h"
  18. #include "res.h"
  19. #include <help.h>
  20. // FEATURE - BobDay - We need some mechanism of determining dock state
  21. //---------------------------------------------------------------------------
  22. // BriefStg Class
  23. //---------------------------------------------------------------------------
  24. // An IBriefcaseStg interface instance is created for each
  25. // folder the caller (the Shell) binds to, where the folder
  26. // is known to be inside a briefcase storage. A briefcase
  27. // storage is the overall storage area (the database) that
  28. // starts at a given folder (called the "briefcase root")
  29. // and extends onwards and below in the file-system.
  30. //
  31. // Internally, the briefcase storage holds the path to the
  32. // folder that this instance is bound to, and it holds a
  33. // cached briefcase structure (CBS), which itself holds a
  34. // reference to the briefcase root.
  35. //
  36. typedef struct _BriefStg
  37. {
  38. IBriefcaseStg bs;
  39. UINT cRef; // reference count
  40. CBS * pcbs; // cached briefcase info
  41. TCHAR szFolder[MAX_PATH]; // canonical path
  42. HBRFCASEITER hbrfcaseiter; // handle to iterate briefcases
  43. DWORD dwFlags; // BSTG_* flags
  44. } BriefStg, * PBRIEFSTG;
  45. // Flags for BriefStg
  46. #define BSTG_SYNCFOLDER 0x00000001 // This folder has a sync copy
  47. //---------------------------------------------------------------------------
  48. // Supporting private code
  49. //---------------------------------------------------------------------------
  50. #ifdef DEBUG
  51. /*----------------------------------------------------------
  52. Purpose: Dump all the cache tables
  53. Returns: --
  54. Cond: --
  55. */
  56. void PUBLIC DumpTables()
  57. {
  58. Atom_DumpAll();
  59. CBS_DumpAll();
  60. CRL_DumpAll();
  61. }
  62. #endif
  63. /*----------------------------------------------------------
  64. Purpose: Initialize the cache tables
  65. Returns: --
  66. Cond: --
  67. */
  68. BOOL PRIVATE InitCacheTables()
  69. {
  70. ASSERT(Sync_IsEngineLoaded());
  71. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Initialize cache tables")); )
  72. if (!CBS_Init())
  73. goto Init_Fail;
  74. if (!CRL_Init())
  75. goto Init_Fail;
  76. return TRUE;
  77. Init_Fail:
  78. CRL_Term();
  79. CBS_Term(NULL);
  80. return FALSE;
  81. }
  82. /*----------------------------------------------------------
  83. Purpose: Terminate the cache tables
  84. Returns: --
  85. Cond: --
  86. */
  87. void PUBLIC TermCacheTables(void)
  88. {
  89. ASSERT(Sync_IsEngineLoaded());
  90. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Terminate cache tables")); )
  91. CRL_Term();
  92. CBS_Term(NULL);
  93. }
  94. /*----------------------------------------------------------
  95. Purpose: Returns TRUE if the path (a folder) has a sync copy.
  96. Returns: see above
  97. Cond: --
  98. */
  99. BOOL PRIVATE HasFolderSyncCopy(
  100. HBRFCASE hbrf,
  101. LPCTSTR pszPath)
  102. {
  103. ASSERT(pszPath);
  104. ASSERT(PathIsDirectory(pszPath));
  105. return (S_OK == Sync_IsTwin(hbrf, pszPath, SF_ISFOLDER) ||
  106. IsSubfolderTwin(hbrf, pszPath));
  107. }
  108. /*----------------------------------------------------------
  109. Purpose: Open a folder that belongs to a briefcase storage.
  110. The pszPath parameter is a folder, which is not necessarily
  111. the briefcase root.
  112. Returns: NOERROR on success
  113. Cond: --
  114. */
  115. HRESULT PRIVATE OpenBriefcaseStorage(
  116. LPCTSTR pszPath,
  117. CBS ** ppcbs,
  118. HWND hwndOwner)
  119. {
  120. HRESULT hres;
  121. UINT uLocality;
  122. int atomBrf;
  123. TCHAR szBrfPath[MAX_PATH];
  124. TCHAR szBrfCanon[MAX_PATH];
  125. ASSERT(pszPath);
  126. ASSERT(ppcbs);
  127. DBG_ENTER_SZ(TEXT("OpenBriefcaseStorage"), pszPath);
  128. DEBUG_CODE( DEBUG_BREAK(BF_ONOPEN); )
  129. // Get the root folder of the briefcase storage
  130. // Get strictly up to the briefcase portion of path
  131. //
  132. uLocality = PathGetLocality(pszPath, szBrfPath, ARRAYSIZE(szBrfPath));
  133. if (PL_FALSE == uLocality)
  134. {
  135. // The only time we get here is if the caller had a legitimate
  136. // reason to believe this folder was a briefcase storage,
  137. // but no database exists (yet). Just continue on as normal,
  138. // the database will get created later.
  139. BrfPathCanonicalize(pszPath, szBrfCanon, ARRAYSIZE(szBrfCanon));
  140. }
  141. else
  142. {
  143. BrfPathCanonicalize(szBrfPath, szBrfCanon, ARRAYSIZE(szBrfCanon));
  144. }
  145. // Add this path to the atom list and add it to the
  146. // cached briefcase structure table.
  147. // (Reference count decrement happens in CloseBriefcase)
  148. //
  149. atomBrf = Atom_Add(szBrfCanon);
  150. if (atomBrf != ATOM_ERR)
  151. {
  152. hres = CBS_Add(ppcbs, atomBrf, hwndOwner);
  153. }
  154. else
  155. {
  156. *ppcbs = NULL;
  157. hres = ResultFromScode(E_OUTOFMEMORY);
  158. }
  159. DEBUG_CODE( DumpTables(); )
  160. DBG_EXIT_HRES(TEXT("OpenBriefcaseStorage"), hres);
  161. return hres;
  162. }
  163. /*----------------------------------------------------------
  164. Purpose: Close a briefcase.
  165. Returns: NOERROR on success
  166. Cond: --
  167. */
  168. HRESULT PRIVATE CloseBriefcaseStorage(
  169. LPCTSTR pszPath)
  170. {
  171. int atomBrf;
  172. TCHAR szBrfPath[MAX_PATH];
  173. TCHAR szBrfCanon[MAX_PATH];
  174. UINT uLocality;
  175. ASSERT(pszPath);
  176. ASSERT(*pszPath); // Should not be an emptry string
  177. DBG_ENTER_SZ(TEXT("CloseBriefcaseStorage"), pszPath);
  178. DEBUG_CODE( DEBUG_BREAK(BF_ONCLOSE); )
  179. DEBUG_CODE( DumpTables(); )
  180. // Save the briefcase and remove it from the cache
  181. //
  182. // Get the root folder of the briefcase storage
  183. // Get strictly up to the briefcase portion of path
  184. //
  185. uLocality = PathGetLocality(pszPath, szBrfPath, ARRAYSIZE(szBrfPath));
  186. if (PL_FALSE == uLocality)
  187. {
  188. // The only time we get here is for a briefcase storage that
  189. // has no database yet. Just continue on as normal,
  190. // the database will get created very soon now.
  191. BrfPathCanonicalize(pszPath, szBrfCanon, ARRAYSIZE(szBrfCanon));
  192. }
  193. else
  194. {
  195. BrfPathCanonicalize(szBrfPath, szBrfCanon, ARRAYSIZE(szBrfCanon));
  196. }
  197. atomBrf = Atom_Find(szBrfCanon);
  198. ASSERT(atomBrf != ATOM_ERR);
  199. CBS_Delete(atomBrf, NULL);
  200. Atom_Delete(atomBrf); // for the Add in OpenBriefcaseStorage
  201. DBG_EXIT_HRES(TEXT("CloseBriefcaseStorage"), NOERROR);
  202. return NOERROR;
  203. }
  204. // Confirm button flags
  205. #define CBF_YES 0x0001
  206. #define CBF_NO 0x0002
  207. #define CBF_TOALL 0x0004
  208. #define CBF_CANCEL 0x0008
  209. /*----------------------------------------------------------
  210. Purpose: Checks to see if the given file/folder already exists
  211. in the given directory. Prompts the user to confirm
  212. replacing if this is true.
  213. Returns: TRUE if path exists
  214. confirm flag settings
  215. Cond: --
  216. */
  217. BOOL PRIVATE DoesPathAlreadyExist(
  218. CBS * pcbs,
  219. LPCTSTR pszPathOld,
  220. LPCTSTR pszPathNew,
  221. LPUINT puConfirmFlags, // CBF_*
  222. UINT uFlags, // SF_ISFOLDER or SF_ISFILE
  223. HWND hwndOwner,
  224. BOOL bMultiDrop)
  225. {
  226. BOOL bRet;
  227. BOOL bIsTwin;
  228. ASSERT(puConfirmFlags);
  229. // Retain settings of *puConfirmFlags coming in
  230. bIsTwin = (S_OK == Sync_IsTwin(pcbs->hbrf, pszPathOld, uFlags));
  231. if (bIsTwin)
  232. uFlags |= SF_ISTWIN;
  233. else
  234. uFlags |= SF_ISNOTTWIN;
  235. bRet = (FALSE != PathExists(pszPathOld));
  236. // Does the path already exist?
  237. if (!bRet)
  238. {
  239. // No; remove it from the database if it is in there so we
  240. // don't add duplicates.
  241. Sync_Split(pcbs->hbrf, pszPathOld, 1, hwndOwner, uFlags | SF_QUIET | SF_NOCONFIRM);
  242. }
  243. else
  244. {
  245. // Yes; has a "to all" previously been specified by the user?
  246. if (IsFlagSet(*puConfirmFlags, CBF_TOALL))
  247. {
  248. // Yes; keep flags as they are
  249. // (CBF_YES and CBF_NO flags are mutually exclusive)
  250. ASSERT(IsFlagSet(*puConfirmFlags, CBF_YES) &&
  251. IsFlagClear(*puConfirmFlags, CBF_NO | CBF_CANCEL) ||
  252. IsFlagSet(*puConfirmFlags, CBF_NO) &&
  253. IsFlagClear(*puConfirmFlags, CBF_YES | CBF_CANCEL));
  254. }
  255. else
  256. {
  257. // No; prompt the user
  258. UINT uFlagsCRF = bMultiDrop ? CRF_MULTI : CRF_DEFAULT;
  259. int id = ConfirmReplace_DoModal(hwndOwner, pszPathOld, pszPathNew, uFlagsCRF);
  260. *puConfirmFlags = 0;
  261. if (GetKeyState(VK_SHIFT) < 0)
  262. SetFlag(*puConfirmFlags, CBF_TOALL);
  263. if (IDYES == id)
  264. SetFlag(*puConfirmFlags, CBF_YES);
  265. else if (IDNO == id)
  266. SetFlag(*puConfirmFlags, CBF_NO);
  267. else if (IDC_YESTOALL == id)
  268. SetFlag(*puConfirmFlags, CBF_YES | CBF_TOALL);
  269. else
  270. {
  271. ASSERT(IDCANCEL == id);
  272. SetFlag(*puConfirmFlags, CBF_CANCEL);
  273. }
  274. }
  275. // Has the user chosen to replace the file?
  276. if (IsFlagSet(*puConfirmFlags, CBF_YES))
  277. {
  278. // Yes; is this an existing twin?
  279. if (bIsTwin)
  280. {
  281. // Yes; delete it from the database before we continue
  282. Sync_Split(pcbs->hbrf, pszPathOld, 1, hwndOwner, SF_QUIET | SF_NOCONFIRM);
  283. }
  284. // Some merge-handlers need the unwanted file to be deleted
  285. // first because they cannot tell the difference between
  286. // a newly added file (that is replacing an existing file)
  287. // and a one-way merge.
  288. if (!PathIsDirectory(pszPathOld))
  289. DeleteFile(pszPathOld);
  290. }
  291. }
  292. return bRet;
  293. }
  294. /*----------------------------------------------------------
  295. Purpose: Add the folder twin to the database, using the default
  296. *.* wildcard settings.
  297. Returns: standard result
  298. Cond: --
  299. */
  300. HRESULT PRIVATE AddDefaultFolderTwin(
  301. HWND hwndOwner,
  302. HBRFCASE hbrf,
  303. HDPA hdpa, // Return: twin handle in array
  304. LPCTSTR pszPathFrom, // Source path
  305. LPCTSTR pszPathTo) // Target path
  306. {
  307. HRESULT hres;
  308. int iTwin;
  309. // First make sure we can add another handle to hdpa (set to zero for now)
  310. if (DPA_ERR == (iTwin = DPA_InsertPtr(hdpa, DPA_APPEND, (LPVOID)NULL)))
  311. {
  312. hres = E_OUTOFMEMORY;
  313. }
  314. else
  315. {
  316. NEWFOLDERTWIN nft;
  317. TWINRESULT tr;
  318. HFOLDERTWIN hft;
  319. RETRY_BEGIN(FALSE)
  320. {
  321. ZeroInit(&nft, NEWFOLDERTWIN);
  322. nft.ulSize = sizeof(nft);
  323. nft.pcszFolder1 = pszPathFrom;
  324. nft.pcszFolder2 = pszPathTo;
  325. nft.pcszName = c_szAllFiles;
  326. nft.dwAttributes = OBJECT_TWIN_ATTRIBUTES;
  327. nft.dwFlags = NFT_FL_SUBTREE;
  328. // Add the twin
  329. tr = Sync_AddFolder(hbrf, &nft, &hft);
  330. hres = HRESULT_FROM_TR(tr);
  331. if (FAILED(hres))
  332. {
  333. DWORD dwError = GetLastError();
  334. int id;
  335. extern SETbl const c_rgseInfo[4];
  336. // Unavailable disk?
  337. if (ERROR_INVALID_DATA == dwError || ERROR_ACCESS_DENIED == dwError)
  338. {
  339. // Yes
  340. hres = E_TR_UNAVAILABLE_VOLUME;
  341. }
  342. id = SEMsgBox(hwndOwner, IDS_CAP_INFO, hres, c_rgseInfo, ARRAYSIZE(c_rgseInfo));
  343. if (IDRETRY == id)
  344. {
  345. // Try the operation again
  346. RETRY_SET();
  347. }
  348. }
  349. }
  350. RETRY_END()
  351. if (FAILED(hres))
  352. {
  353. DPA_DeletePtr(hdpa, iTwin);
  354. }
  355. else
  356. {
  357. // Success
  358. ASSERT(DPA_ERR != iTwin);
  359. ASSERT(NULL != hft);
  360. DPA_SetPtr(hdpa, iTwin, hft);
  361. }
  362. }
  363. return hres;
  364. }
  365. /*----------------------------------------------------------
  366. Purpose: Create a twin relationship between a folder and
  367. another folder.
  368. Returns: standard hresult
  369. handles to created twins in hdpa
  370. confirm flag settings
  371. Cond: --
  372. */
  373. HRESULT PRIVATE CreateTwinOfFolder(
  374. CBS * pcbs,
  375. LPTSTR pszPath, // Dragged folder path
  376. LPCTSTR pszDir, // Location to place twin
  377. HDPA hdpaTwin, // array of twin handles
  378. UINT uFlags, // AOF_*
  379. PUINT puConfirmFlags, // CBF_*
  380. HWND hwndOwner,
  381. BOOL bMultiDrop) // TRUE: more than 1 file/folder was dropped
  382. {
  383. HRESULT hres;
  384. TCHAR szPathB[MAX_PATH];
  385. LPTSTR pszFile;
  386. ASSERT(pszPath);
  387. ASSERT(pszDir);
  388. pszFile = PathFindFileName(pszPath);
  389. // Will the path name be too long?
  390. if (PathsTooLong(pszDir, pszFile))
  391. {
  392. // Yes; bail
  393. MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_ADDFOLDER_TOOLONG),
  394. MAKEINTRESOURCE(IDS_CAP_ADD), NULL, MB_ERROR, pszFile);
  395. hres = E_FAIL;
  396. }
  397. // Did the user drag another briefcase root into this briefcase?
  398. else if (PathIsBriefcase(pszPath))
  399. {
  400. // Yes; we don't allow nested briefcases! Tell the user.
  401. MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_CANTADDBRIEFCASE),
  402. MAKEINTRESOURCE(IDS_CAP_ADD), NULL, MB_WARNING);
  403. hres = E_FAIL;
  404. }
  405. else
  406. {
  407. // No; check for an existing folder in the target folder.
  408. BOOL bExists;
  409. PathCombine(szPathB, pszDir, pszFile);
  410. bExists = DoesPathAlreadyExist(pcbs, szPathB, pszPath, puConfirmFlags, SF_ISFOLDER, hwndOwner, bMultiDrop);
  411. if (!bExists || IsFlagSet(*puConfirmFlags, CBF_YES))
  412. {
  413. ASSERT(IsFlagClear(*puConfirmFlags, CBF_NO) &&
  414. IsFlagClear(*puConfirmFlags, CBF_CANCEL));
  415. // Show 'Add Folder' dialog?
  416. if (IsFlagSet(uFlags, AOF_FILTERPROMPT))
  417. {
  418. // Yes
  419. hres = Info_DoModal(hwndOwner, pszPath, szPathB, hdpaTwin,
  420. pcbs);
  421. }
  422. else
  423. {
  424. // No; just default to *.*
  425. hres = AddDefaultFolderTwin(hwndOwner, pcbs->hbrf, hdpaTwin,
  426. pszPath, szPathB);
  427. }
  428. }
  429. else if (IsFlagSet(*puConfirmFlags, CBF_NO))
  430. {
  431. // The user said NO
  432. ASSERT(IsFlagClear(*puConfirmFlags, CBF_YES) &&
  433. IsFlagClear(*puConfirmFlags, CBF_CANCEL));
  434. hres = NOERROR;
  435. }
  436. else
  437. {
  438. ASSERT(IsFlagSet(*puConfirmFlags, CBF_CANCEL));
  439. ASSERT(IsFlagClear(*puConfirmFlags, CBF_YES) &&
  440. IsFlagClear(*puConfirmFlags, CBF_NO));
  441. hres = E_ABORT;
  442. }
  443. }
  444. return hres;
  445. }
  446. /*----------------------------------------------------------
  447. Purpose: Create a twin of a file.
  448. Returns: standard result
  449. twin handle in hdpa
  450. Cond: --
  451. */
  452. HRESULT PRIVATE CreateTwinOfFile(
  453. CBS * pcbs,
  454. LPCTSTR pszPath, // ptr to path to twin
  455. LPCTSTR pszTargetDir, // ptr to dest dir
  456. HDPA hdpa, // Return: twin handle in array
  457. UINT uFlags, // AOF_*
  458. PUINT puConfirmFlags, // CBF_*
  459. HWND hwndOwner,
  460. BOOL bMultiDrop) // TRUE: more than 1 file/folder was dropped
  461. {
  462. HRESULT hres;
  463. int iTwin;
  464. TCHAR szPath[MAX_PATH];
  465. LPCTSTR pszFile;
  466. HTWINFAMILY htfam = NULL;
  467. ASSERT(pszPath);
  468. ASSERT(pszTargetDir);
  469. pszFile = PathFindFileName(pszPath);
  470. // Will the path name be too long?
  471. if (PathsTooLong(pszTargetDir, pszFile))
  472. {
  473. // Yes; bail
  474. MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_ADDFILE_TOOLONG),
  475. MAKEINTRESOURCE(IDS_CAP_ADD), NULL, MB_ERROR, pszFile);
  476. iTwin = DPA_ERR;
  477. hres = E_FAIL;
  478. }
  479. // First make sure we can add another handle to hdpa (set to zero for now)
  480. else if (DPA_ERR == (iTwin = DPA_InsertPtr(hdpa, DPA_APPEND, (LPVOID)NULL)))
  481. {
  482. hres = E_OUTOFMEMORY;
  483. }
  484. else
  485. {
  486. BOOL bExists;
  487. // Confirm the replace if a file with the same name already exists.
  488. //
  489. PathCombine(szPath, pszTargetDir, pszFile);
  490. bExists = DoesPathAlreadyExist(pcbs, szPath, pszPath, puConfirmFlags, SF_ISFILE, hwndOwner, bMultiDrop);
  491. if (!bExists ||
  492. IsFlagSet(*puConfirmFlags, CBF_YES))
  493. {
  494. NEWOBJECTTWIN not;
  495. TWINRESULT tr;
  496. DECLAREHOURGLASS;
  497. ASSERT(IsFlagClear(*puConfirmFlags, CBF_NO) &&
  498. IsFlagClear(*puConfirmFlags, CBF_CANCEL));
  499. lstrcpyn(szPath, pszPath, ARRAYSIZE(szPath));
  500. PathRemoveFileSpec(szPath);
  501. // User has either opted to continue adding this object to the
  502. // database, or it does not exist in the destination folder.
  503. RETRY_BEGIN(FALSE)
  504. {
  505. ZeroInit(&not, NEWOBJECTTWIN);
  506. not.ulSize = sizeof(NEWOBJECTTWIN);
  507. not.pcszFolder1 = szPath;
  508. not.pcszFolder2 = pszTargetDir;
  509. not.pcszName = pszFile;
  510. SetHourglass();
  511. Sync_Dump(&not, NEWOBJECTTWIN);
  512. tr = Sync_AddObject(pcbs->hbrf, &not, &htfam);
  513. ResetHourglass();
  514. hres = HRESULT_FROM_TR(tr);
  515. if (FAILED(hres))
  516. {
  517. DWORD dwError = GetLastError();
  518. // Unavailable disk?
  519. if (ERROR_INVALID_DATA == dwError || ERROR_ACCESS_DENIED == dwError)
  520. {
  521. // Yes; ask user to retry/cancel
  522. int id = MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_ADDFILE_UNAVAIL_VOL),
  523. MAKEINTRESOURCE(IDS_CAP_ADD), NULL, MB_RETRYCANCEL | MB_ICONWARNING);
  524. // Set specific error value
  525. hres = E_TR_UNAVAILABLE_VOLUME;
  526. if (IDRETRY == id)
  527. {
  528. RETRY_SET(); // Try again
  529. }
  530. }
  531. }
  532. }
  533. RETRY_END()
  534. }
  535. else if (IsFlagSet(*puConfirmFlags, CBF_NO))
  536. {
  537. // The user said NO
  538. ASSERT(IsFlagClear(*puConfirmFlags, CBF_YES) &&
  539. IsFlagClear(*puConfirmFlags, CBF_CANCEL));
  540. DPA_DeletePtr(hdpa, iTwin);
  541. hres = NOERROR;
  542. }
  543. else
  544. {
  545. ASSERT(IsFlagSet(*puConfirmFlags, CBF_CANCEL));
  546. ASSERT(IsFlagClear(*puConfirmFlags, CBF_YES) &&
  547. IsFlagClear(*puConfirmFlags, CBF_NO));
  548. hres = E_ABORT;
  549. }
  550. }
  551. if (FAILED(hres))
  552. {
  553. if (DPA_ERR != iTwin)
  554. {
  555. DPA_DeletePtr(hdpa, iTwin);
  556. }
  557. }
  558. else
  559. {
  560. // Success
  561. ASSERT(DPA_ERR != iTwin);
  562. if (htfam)
  563. DPA_SetPtr(hdpa, iTwin, htfam);
  564. }
  565. return hres;
  566. }
  567. /*----------------------------------------------------------
  568. Purpose: Deletes the new twins
  569. Returns: --
  570. Cond: --
  571. */
  572. void PRIVATE DeleteNewTwins(
  573. CBS * pcbs,
  574. HDPA hdpa)
  575. {
  576. int iItem;
  577. int cItems;
  578. ASSERT(pcbs);
  579. ASSERT(hdpa);
  580. cItems = DPA_GetPtrCount(hdpa);
  581. for (iItem = 0; iItem < cItems; iItem++)
  582. {
  583. HTWIN htwin = DPA_FastGetPtr(hdpa, iItem);
  584. if (htwin)
  585. Sync_DeleteTwin(htwin);
  586. }
  587. }
  588. /*----------------------------------------------------------
  589. Purpose: Releases the twin handles
  590. Returns: --
  591. Cond: --
  592. */
  593. void PRIVATE ReleaseNewTwins(
  594. HDPA hdpa)
  595. {
  596. int i;
  597. int cItems;
  598. ASSERT(hdpa);
  599. cItems = DPA_GetPtrCount(hdpa);
  600. for (i = 0; i < cItems; i++)
  601. {
  602. HTWIN htwin = DPA_FastGetPtr(hdpa, i);
  603. if (htwin)
  604. Sync_ReleaseTwin(htwin);
  605. }
  606. }
  607. /*----------------------------------------------------------
  608. Purpose: Returns the count of nodes that do not have FS_COND_UNAVAILABLE.
  609. Returns: see above
  610. Cond: --
  611. */
  612. UINT PRIVATE CountAvailableNodes(
  613. PRECITEM pri)
  614. {
  615. UINT ucNodes = 0;
  616. PRECNODE prn;
  617. for (prn = pri->prnFirst; prn; prn = prn->prnNext)
  618. {
  619. if (FS_COND_UNAVAILABLE != prn->fsCurrent.fscond)
  620. {
  621. ucNodes++;
  622. }
  623. }
  624. return ucNodes;
  625. }
  626. /*----------------------------------------------------------
  627. Purpose: Returns the count of nodes that require some sort of
  628. action.
  629. Returns: see above
  630. Cond: --
  631. */
  632. UINT PRIVATE CountActionItem(
  633. PRECLIST prl)
  634. {
  635. UINT uc = 0;
  636. PRECITEM pri;
  637. for (pri = prl->priFirst; pri; pri = pri->priNext)
  638. {
  639. if (RIA_NOTHING != pri->riaction)
  640. {
  641. uc++;
  642. }
  643. }
  644. return uc;
  645. }
  646. /*----------------------------------------------------------
  647. Purpose: Update the twins in the list
  648. Returns:
  649. Cond: --
  650. */
  651. HRESULT PRIVATE MassageReclist(
  652. CBS * pcbs,
  653. PRECLIST prl,
  654. LPCTSTR pszInsideDir,
  655. BOOL bCopyIn,
  656. HWND hwndOwner)
  657. {
  658. HRESULT hres = NOERROR;
  659. PRECITEM pri;
  660. BOOL bWarnUser = TRUE;
  661. PRECNODE prnInside;
  662. PRECNODE prnOutside;
  663. // Make sure the direction of the reconciliation coincides
  664. // with the direction of the user's action.
  665. for (pri = prl->priFirst; pri; pri = pri->priNext)
  666. {
  667. if (RIA_NOTHING != pri->riaction)
  668. {
  669. UINT cAvailableNodes = CountAvailableNodes(pri);
  670. // Is this a wierd multi-edged case (not including
  671. // Sneakernet)?
  672. if (2 < cAvailableNodes)
  673. {
  674. // Should never get here, but better safe than sorry
  675. ASSERT(0);
  676. }
  677. else
  678. {
  679. // No; get the pair of nodes that we just added to the
  680. // database.
  681. hres = Sync_GetNodePair(pri, Atom_GetName(pcbs->atomBrf),
  682. pszInsideDir, &prnInside, &prnOutside);
  683. if (SUCCEEDED(hres))
  684. {
  685. ASSERT(prnInside);
  686. ASSERT(prnOutside);
  687. if (bCopyIn)
  688. {
  689. switch (prnOutside->rnstate)
  690. {
  691. case RNS_UNAVAILABLE:
  692. case RNS_DOES_NOT_EXIST:
  693. case RNS_DELETED:
  694. break; // leave alone
  695. default:
  696. // Force the update to be a copy into the briefcase.
  697. pri->riaction = RIA_COPY;
  698. prnInside->rnaction = RNA_COPY_TO_ME;
  699. prnOutside->rnaction = RNA_COPY_FROM_ME;
  700. TRACE_MSG(TF_GENERAL, TEXT("Massaging reclist"));
  701. break;
  702. }
  703. }
  704. else
  705. {
  706. switch (prnInside->rnstate)
  707. {
  708. case RNS_UNAVAILABLE:
  709. case RNS_DOES_NOT_EXIST:
  710. case RNS_DELETED:
  711. break; // leave alone
  712. default:
  713. // Force the update to be a copy out of the briefcase.
  714. pri->riaction = RIA_COPY;
  715. prnInside->rnaction = RNA_COPY_FROM_ME;
  716. prnOutside->rnaction = RNA_COPY_TO_ME;
  717. TRACE_MSG(TF_GENERAL, TEXT("Massaging reclist"));
  718. break;
  719. }
  720. }
  721. }
  722. else
  723. break; // Error
  724. }
  725. }
  726. }
  727. return hres;
  728. }
  729. /*----------------------------------------------------------
  730. Purpose: Check for more than 2 available nodes in each recitem.
  731. Remove the associated twin if we find such a case,
  732. to prevent multiple sync copies.
  733. Returns: S_OK if everything looks ok
  734. S_FALSE if there were multiple sync copies introduced
  735. Cond: --
  736. */
  737. HRESULT PRIVATE VerifyTwins(
  738. CBS * pcbs,
  739. PRECLIST prl,
  740. LPCTSTR pszTargetDir,
  741. HWND hwndOwner)
  742. {
  743. HRESULT hres = NOERROR;
  744. PRECITEM pri;
  745. BOOL bWarnUser = TRUE;
  746. BOOL bWarnUserFolder = TRUE;
  747. TCHAR szPath[MAX_PATH];
  748. // Look thru the reclist and pick out recitems that have more than
  749. // 2 recnodes that are currently available.
  750. // Scenarios when this can happen:
  751. //
  752. // 1) Foo.txt --> BC
  753. // Foo.txt --> BC\Orphan Folder
  754. //
  755. // Expected result: delete BC\Orphan Folder\Foo.txt twin
  756. //
  757. // 2) Foo.txt --> BC\Orphan Folder
  758. // Orphan Folder --> BC
  759. //
  760. // Expected result: delete BC\Orphan Folder twin
  761. //
  762. // 3) Foo.txt --> BC\Orphan Folder
  763. // Foo.txt --> BC
  764. //
  765. // Expected result: delete BC\Foo.txt twin
  766. //
  767. for (pri = prl->priFirst; pri; pri = pri->priNext)
  768. {
  769. UINT cAvailableNodes = CountAvailableNodes(pri);
  770. PRECNODE prn;
  771. // Are there more than 2 available nodes?
  772. if (2 < cAvailableNodes && *pri->pcszName)
  773. {
  774. BOOL bLookForFolders = TRUE;
  775. // FIRST: Look for object twins that are not in folder twins.
  776. for (prn = pri->prnFirst; prn; prn = prn->prnNext)
  777. {
  778. // Is this file here because the file was dragged in?
  779. if (IsSzEqual(pszTargetDir, prn->pcszFolder))
  780. {
  781. // Yes; warn the user
  782. if (bWarnUser)
  783. {
  784. MsgBox(hwndOwner,
  785. MAKEINTRESOURCE(IDS_ERR_ADDFILE_TOOMANY),
  786. MAKEINTRESOURCE(IDS_CAP_ADD),
  787. NULL, MB_WARNING, pri->pcszName);
  788. if (0 > GetKeyState(VK_SHIFT))
  789. {
  790. bWarnUser = FALSE;
  791. }
  792. }
  793. // Try to remove the object twin
  794. PathCombine(szPath, prn->pcszFolder, pri->pcszName);
  795. hres = Sync_Split(pcbs->hbrf, szPath, 1, hwndOwner,
  796. SF_QUIET | SF_NOCONFIRM);
  797. TRACE_MSG(TF_GENERAL, TEXT("Deleted object twin for %s"), szPath);
  798. ASSERT(FAILED(hres) || S_OK == hres);
  799. bLookForFolders = FALSE;
  800. break;
  801. }
  802. }
  803. if (bLookForFolders)
  804. {
  805. // SECOND: Look for object twins that exist because of folder
  806. // twins.
  807. for (prn = pri->prnFirst; prn; prn = prn->prnNext)
  808. {
  809. lstrcpyn(szPath, prn->pcszFolder, ARRAYSIZE(szPath));
  810. PathRemoveFileSpec(szPath);
  811. // Is this file here because it is in a folder that was
  812. // dragged in?
  813. if (IsSzEqual(pszTargetDir, szPath))
  814. {
  815. // Yes; warn the user
  816. if (bWarnUserFolder && bWarnUser)
  817. {
  818. MsgBox(hwndOwner,
  819. MAKEINTRESOURCE(IDS_ERR_ADDFOLDER_TOOMANY),
  820. MAKEINTRESOURCE(IDS_CAP_ADD),
  821. NULL, MB_WARNING, PathFindFileName(prn->pcszFolder));
  822. // Hack: to prevent showing this messagebox for
  823. // every file in this folder, set this flag
  824. bWarnUserFolder = FALSE;
  825. if (0 > GetKeyState(VK_SHIFT))
  826. {
  827. bWarnUser = FALSE;
  828. }
  829. }
  830. // Remove the folder twin
  831. hres = Sync_Split(pcbs->hbrf, prn->pcszFolder, 1, hwndOwner,
  832. SF_ISFOLDER | SF_QUIET | SF_NOCONFIRM);
  833. TRACE_MSG(TF_GENERAL, TEXT("Deleted folder twin for %s"), prn->pcszFolder);
  834. ASSERT(FAILED(hres) || !bWarnUserFolder || S_OK == hres);
  835. break;
  836. }
  837. }
  838. }
  839. hres = S_FALSE;
  840. }
  841. }
  842. return hres;
  843. }
  844. #define STATE_VERIFY 0
  845. #define STATE_UPDATE 1
  846. #define STATE_STOP 2
  847. /*----------------------------------------------------------
  848. Purpose: This function updates the new files. Unlike the general
  849. update function, this strictly updates file pairs. All
  850. other incidental nodes are set to RNA_NOTHING.
  851. In addition, to be safe, we force the update to always
  852. perform a copy into the briefcase.
  853. This function releases the twin handles when it is finished.
  854. Returns: standard result
  855. Cond: --
  856. */
  857. HRESULT PRIVATE UpdateNewTwins(
  858. CBS * pcbs,
  859. LPCTSTR pszInsideDir,
  860. LPCTSTR pszTargetDir,
  861. BOOL bCopyIn,
  862. HDPA hdpa,
  863. HWND hwndOwner)
  864. {
  865. HRESULT hres = E_FAIL;
  866. int iItem;
  867. int cItems;
  868. ASSERT(pcbs);
  869. ASSERT(hdpa);
  870. cItems = DPA_GetPtrCount(hdpa);
  871. if (cItems > 0)
  872. {
  873. HTWINLIST htl;
  874. PRECLIST prl;
  875. TWINRESULT tr;
  876. tr = Sync_CreateTwinList(pcbs->hbrf, &htl);
  877. if (TR_SUCCESS != tr)
  878. {
  879. hres = HRESULT_FROM_TR(tr);
  880. }
  881. else
  882. {
  883. HWND hwndProgress;
  884. UINT nState = STATE_VERIFY;
  885. DEBUG_CODE( UINT nCount = 0; )
  886. // State progression is simple:
  887. // STATE_VERIFY --> STATE_UPDATE --> STATE_STOP
  888. // Any questions?
  889. hwndProgress = UpdBar_Show(hwndOwner, UB_CHECKING, DELAY_UPDBAR);
  890. for (iItem = 0; iItem < cItems; iItem++)
  891. {
  892. HTWIN htwin = DPA_FastGetPtr(hdpa, iItem);
  893. if (htwin)
  894. Sync_AddToTwinList(htl, htwin);
  895. }
  896. do
  897. {
  898. ASSERT(STATE_VERIFY == nState || STATE_UPDATE == nState);
  899. ASSERT(2 > nCount++); // Sanity check for infinite loop
  900. // Create the reclist
  901. hres = Sync_CreateRecListEx(htl, UpdBar_GetAbortEvt(hwndProgress), &prl);
  902. DEBUG_CODE( Sync_DumpRecList(GET_TR(hres), prl, TEXT("Adding new twins")); )
  903. if (SUCCEEDED(hres))
  904. {
  905. ASSERT(prl);
  906. switch (nState)
  907. {
  908. case STATE_VERIFY:
  909. hres = VerifyTwins(pcbs, prl, pszTargetDir, hwndOwner);
  910. if (S_FALSE == hres)
  911. nState = STATE_UPDATE;
  912. else if (S_OK == hres)
  913. goto Update;
  914. else
  915. nState = STATE_STOP;
  916. break;
  917. case STATE_UPDATE:
  918. // After recreating the reclist, is there anything
  919. // that needs updating?
  920. if (0 < CountActionItems(prl))
  921. {
  922. // Yes
  923. Update:
  924. UpdBar_SetAvi(hwndProgress, UB_UPDATEAVI);
  925. hres = MassageReclist(pcbs, prl, pszInsideDir, bCopyIn, hwndOwner);
  926. if (SUCCEEDED(hres))
  927. {
  928. // Update these files
  929. hres = Sync_ReconcileRecList(prl, Atom_GetName(pcbs->atomBrf),
  930. hwndProgress, RF_ONADD);
  931. }
  932. }
  933. nState = STATE_STOP;
  934. break;
  935. default:
  936. ASSERT(0);
  937. break;
  938. }
  939. Sync_DestroyRecList(prl);
  940. }
  941. } while (SUCCEEDED(hres) && STATE_UPDATE == nState);
  942. Sync_DestroyTwinList(htl);
  943. UpdBar_Kill(hwndProgress);
  944. }
  945. }
  946. return hres;
  947. }
  948. // FEATURE - BobDay - WinNT docking state determination code goes here.
  949. /*----------------------------------------------------------
  950. Purpose: Return TRUE if the machine is docked
  951. Returns: See above.
  952. Cond: --
  953. */
  954. BOOL PRIVATE IsMachineDocked(void)
  955. {
  956. return TRUE;
  957. }
  958. //---------------------------------------------------------------------------
  959. // IBriefcaseStg member functions
  960. //---------------------------------------------------------------------------
  961. /*----------------------------------------------------------
  962. Purpose: IBriefcaseStg::Release
  963. Returns: new reference count
  964. Cond: --
  965. */
  966. STDMETHODIMP_(UINT) BriefStg_Release(
  967. LPBRIEFCASESTG pstg)
  968. {
  969. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  970. DBG_ENTER(TEXT("BriefStg_Release"));
  971. if (--this->cRef)
  972. {
  973. DBG_EXIT_UL(TEXT("BriefStg_Release"), this->cRef);
  974. return this->cRef; // Return decremented reference count
  975. }
  976. if (this->pcbs)
  977. {
  978. // Release this briefcase storage instance
  979. CloseBriefcaseStorage(this->szFolder);
  980. }
  981. if (this->hbrfcaseiter)
  982. {
  983. Sync_FindClose(this->hbrfcaseiter);
  984. }
  985. GFree(this);
  986. ENTEREXCLUSIVE();
  987. {
  988. DecBriefSemaphore();
  989. if (IsLastBriefSemaphore())
  990. {
  991. CommitIniFile();
  992. DEBUG_CODE( DumpTables(); )
  993. TermCacheTables();
  994. }
  995. }
  996. LEAVEEXCLUSIVE();
  997. DBG_EXIT_UL(TEXT("BriefStg_Release"), 0);
  998. return 0;
  999. }
  1000. /*----------------------------------------------------------
  1001. Purpose: IBriefcaseStg::AddRef
  1002. Returns: new reference count
  1003. Cond: --
  1004. */
  1005. STDMETHODIMP_(UINT) BriefStg_AddRef(
  1006. LPBRIEFCASESTG pstg)
  1007. {
  1008. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1009. UINT cRef;
  1010. DBG_ENTER(TEXT("BriefStg_AddRef"));
  1011. cRef = ++this->cRef;
  1012. DBG_EXIT_UL(TEXT("BriefStg_AddRef"), cRef);
  1013. return cRef;
  1014. }
  1015. /*----------------------------------------------------------
  1016. Purpose: IBriefcaseStg::QueryInterface
  1017. Returns: standard
  1018. Cond: --
  1019. */
  1020. STDMETHODIMP BriefStg_QueryInterface(
  1021. LPBRIEFCASESTG pstg,
  1022. REFIID riid,
  1023. LPVOID * ppvOut)
  1024. {
  1025. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1026. HRESULT hres;
  1027. DBG_ENTER_RIID(TEXT("BriefStg_QueryInterface"), riid);
  1028. if (IsEqualIID(riid, &IID_IUnknown) ||
  1029. IsEqualIID(riid, &IID_IBriefcaseStg))
  1030. {
  1031. // We use the bs field as our IUnknown as well
  1032. *ppvOut = &this->bs;
  1033. this->cRef++;
  1034. hres = NOERROR;
  1035. }
  1036. else
  1037. {
  1038. *ppvOut = NULL;
  1039. hres = ResultFromScode(E_NOINTERFACE);
  1040. }
  1041. DBG_EXIT_HRES(TEXT("BriefStg_QueryInterface"), hres);
  1042. return hres;
  1043. }
  1044. /*----------------------------------------------------------
  1045. Purpose: IBriefcaseStg::Initialize
  1046. Called to initialize a briefcase storage instance.
  1047. The pszFolder indicates the folder we are binding to,
  1048. which is in the briefcase storage (somewhere).
  1049. Returns: standard
  1050. Cond: --
  1051. */
  1052. STDMETHODIMP BriefStg_Initialize(
  1053. LPBRIEFCASESTG pstg,
  1054. LPCTSTR pszPath,
  1055. HWND hwndOwner)
  1056. {
  1057. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1058. HRESULT hres = ResultFromScode(E_FAIL);
  1059. DBG_ENTER_SZ(TEXT("BriefStg_Initialize"), pszPath);
  1060. ASSERT(pszPath);
  1061. // Only initialize once per interface instance
  1062. //
  1063. if (pszPath && NULL == this->pcbs)
  1064. {
  1065. BOOL bCancel = FALSE;
  1066. RETRY_BEGIN(FALSE)
  1067. {
  1068. // Unavailable disk?
  1069. if (!PathExists(pszPath))
  1070. {
  1071. // Yes; ask user to retry/cancel
  1072. int id = MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_OPEN_UNAVAIL_VOL),
  1073. MAKEINTRESOURCE(IDS_CAP_OPEN), NULL, MB_RETRYCANCEL | MB_ICONWARNING);
  1074. if (IDRETRY == id)
  1075. RETRY_SET(); // Try again
  1076. else
  1077. bCancel = TRUE;
  1078. }
  1079. }
  1080. RETRY_END()
  1081. if (!bCancel)
  1082. {
  1083. BrfPathCanonicalize(pszPath, this->szFolder, ARRAYSIZE(this->szFolder));
  1084. if (PathExists(this->szFolder) && !PathIsDirectory(this->szFolder))
  1085. {
  1086. // (Store this as a path to a folder)
  1087. PathRemoveFileSpec(this->szFolder);
  1088. }
  1089. // Open the briefcase storage for this folder
  1090. //
  1091. hres = OpenBriefcaseStorage(this->szFolder, &this->pcbs, hwndOwner);
  1092. if (SUCCEEDED(hres))
  1093. {
  1094. // Is this folder a sync folder?
  1095. if (HasFolderSyncCopy(this->pcbs->hbrf, this->szFolder))
  1096. {
  1097. // Yes
  1098. SetFlag(this->dwFlags, BSTG_SYNCFOLDER);
  1099. }
  1100. else
  1101. {
  1102. // No (or error, in which case we default to no)
  1103. ClearFlag(this->dwFlags, BSTG_SYNCFOLDER);
  1104. }
  1105. }
  1106. }
  1107. }
  1108. hres = MapToOfficialHresult(hres);
  1109. DBG_EXIT_HRES(TEXT("BriefStg_Initialize"), hres);
  1110. return hres;
  1111. }
  1112. /*----------------------------------------------------------
  1113. Purpose: Add an object or objects to the briefcase storage.
  1114. This function does the real work for BriefStg_AddObject.
  1115. Returns: standard result
  1116. NOERROR if the object(s) were added
  1117. S_FALSE if the object(s) should be handled by the caller
  1118. Cond: --
  1119. */
  1120. HRESULT PRIVATE BriefStg_AddObjectPrivate(
  1121. LPBRIEFCASESTG pstg,
  1122. LPDATAOBJECT pdtobj,
  1123. LPCTSTR pszFolderEx, // optional (may be NULL)
  1124. UINT uFlags, // One of AOF_*
  1125. HWND hwndOwner)
  1126. {
  1127. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1128. HRESULT hres;
  1129. LPTSTR pszList;
  1130. LPTSTR psz;
  1131. UINT i;
  1132. UINT cFiles;
  1133. TCHAR szCanon[MAX_PATH];
  1134. HDPA hdpa;
  1135. LPCTSTR pszTarget;
  1136. BOOL bMultiFiles;
  1137. static SETbl const c_rgseAdd[] = {
  1138. { E_OUTOFMEMORY, IDS_OOM_ADD, MB_ERROR },
  1139. { E_TR_OUT_OF_MEMORY, IDS_OOM_ADD, MB_ERROR },
  1140. };
  1141. ASSERT(pdtobj);
  1142. // Verify that the folder of this briefcase storage is actually inside
  1143. // a briefcase. (szCanon is used as a dummy here.)
  1144. ASSERT( !PathExists(this->szFolder) || PL_FALSE != PathGetLocality(this->szFolder, szCanon, ARRAYSIZE(szCanon)) );
  1145. // Get list of files to add
  1146. hres = DataObj_QueryFileList(pdtobj, &pszList, &cFiles);
  1147. if (SUCCEEDED(hres))
  1148. {
  1149. // Grab the mutex to delay any further calculation in any
  1150. // Briefcase views' secondary threads until we're done
  1151. // processing here.
  1152. Delay_Own();
  1153. // Does the caller want to create sync copies of objects that are
  1154. // already in the briefcase to some other folder? (Sneakernet)
  1155. if (NULL != pszFolderEx)
  1156. {
  1157. // Yes
  1158. pszTarget = pszFolderEx;
  1159. }
  1160. else
  1161. {
  1162. // No
  1163. pszTarget = this->szFolder;
  1164. // Are the entities already in this briefcase?
  1165. //
  1166. // Based on the success return value of DataObj_QueryFileList,
  1167. // we can tell if the entities are already within a briefcase.
  1168. // Because of the nature of the shell, we assume the file
  1169. // list contains entities which all exist in the same folder,
  1170. // so we consider it an "all or nothing" sort of indicator.
  1171. // If the entities are indeed in a briefcase, we compare the
  1172. // roots of the source and destination briefcases, and BLOCK
  1173. // the addition if they are the same.
  1174. //
  1175. if (S_OK == hres)
  1176. {
  1177. // They are in *a* briefcase. Which one?
  1178. DataObj_QueryBriefPath(pdtobj, szCanon, ARRAYSIZE(szCanon));
  1179. if (IsSzEqual(szCanon, Atom_GetName(this->pcbs->atomBrf)))
  1180. {
  1181. // This same one! Don't do anything.
  1182. // display message box
  1183. hres = ResultFromScode(E_FAIL);
  1184. goto Error1;
  1185. }
  1186. }
  1187. }
  1188. bMultiFiles = (1 < cFiles);
  1189. // Create the temporary DPA list
  1190. if (NULL == (hdpa = DPA_Create(cFiles)))
  1191. {
  1192. hres = ResultFromScode(E_OUTOFMEMORY);
  1193. }
  1194. else
  1195. {
  1196. UINT uConfirmFlags = 0;
  1197. // Add all the objects to the briefcase storage
  1198. for (i = 0, psz = pszList; i < cFiles; i++)
  1199. {
  1200. // Get file/folder name that was dropped
  1201. BrfPathCanonicalize(psz, szCanon, ARRAYSIZE(szCanon));
  1202. if (PathIsDirectory(szCanon))
  1203. {
  1204. hres = CreateTwinOfFolder(this->pcbs, szCanon, pszTarget,
  1205. hdpa, uFlags, &uConfirmFlags,
  1206. hwndOwner, bMultiFiles);
  1207. }
  1208. else
  1209. {
  1210. hres = CreateTwinOfFile(this->pcbs, szCanon, pszTarget,
  1211. hdpa, uFlags, &uConfirmFlags,
  1212. hwndOwner, bMultiFiles);
  1213. }
  1214. if (FAILED(hres))
  1215. {
  1216. // An error occurred while attempting to add a twin
  1217. break;
  1218. }
  1219. DataObj_NextFile(psz); // Set psz to next file in list
  1220. }
  1221. if (FAILED(hres))
  1222. {
  1223. // Delete the twins that were added.
  1224. DeleteNewTwins(this->pcbs, hdpa);
  1225. }
  1226. else
  1227. {
  1228. // Update these new twins
  1229. hres = UpdateNewTwins(this->pcbs, this->szFolder, pszTarget, (NULL == pszFolderEx), hdpa, hwndOwner);
  1230. }
  1231. ReleaseNewTwins(hdpa);
  1232. DPA_Destroy(hdpa);
  1233. }
  1234. Error1:
  1235. DataObj_FreeList(pszList);
  1236. Delay_Release();
  1237. }
  1238. if (FAILED(hres))
  1239. {
  1240. SEMsgBox(hwndOwner, IDS_CAP_ADD, hres, c_rgseAdd, ARRAYSIZE(c_rgseAdd));
  1241. }
  1242. return hres;
  1243. }
  1244. /*----------------------------------------------------------
  1245. Purpose: IBriefcaseStg::AddObject
  1246. Add an object to the briefcase storage.
  1247. Returns: standard hresult
  1248. Cond: --
  1249. */
  1250. STDMETHODIMP BriefStg_AddObject(
  1251. LPBRIEFCASESTG pstg,
  1252. LPDATAOBJECT pdtobj,
  1253. LPCTSTR pszFolderEx, // optional
  1254. UINT uFlags,
  1255. HWND hwndOwner)
  1256. {
  1257. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1258. HRESULT hres = NOERROR;
  1259. LPCTSTR pszFolder;
  1260. UINT ids;
  1261. DEBUG_CODE( TCHAR szDbg[MAX_PATH]; )
  1262. DBG_ENTER_DTOBJ(TEXT("BriefStg_AddObject"), pdtobj, szDbg, ARRAYSIZE(szDbg));
  1263. ASSERT(pdtobj);
  1264. ASSERT(this->pcbs);
  1265. // Is this sneakernet?
  1266. // Is this folder a sync folder?
  1267. if (pszFolderEx)
  1268. {
  1269. // Yes; is the source a sync folder already?
  1270. if (HasFolderSyncCopy(this->pcbs->hbrf, pszFolderEx))
  1271. {
  1272. // Yes; don't allow other sync copies into (or out of) it
  1273. ids = IDS_ERR_ADD_SYNCFOLDER;
  1274. pszFolder = PathFindFileName(pszFolderEx);
  1275. hres = E_FAIL;
  1276. }
  1277. // Is the source folder a sync folder already?
  1278. else if (IsFlagSet(this->dwFlags, BSTG_SYNCFOLDER))
  1279. {
  1280. // Yes; don't allow other sync copies into (or out of) it
  1281. ids = IDS_ERR_ADD_SYNCFOLDER_SRC;
  1282. pszFolder = PathFindFileName(this->szFolder);
  1283. hres = E_FAIL;
  1284. }
  1285. }
  1286. else if (IsFlagSet(this->dwFlags, BSTG_SYNCFOLDER))
  1287. {
  1288. // Yes; don't allow other sync copies into (or out of) it
  1289. ids = IDS_ERR_ADD_SYNCFOLDER;
  1290. pszFolder = PathFindFileName(this->szFolder);
  1291. hres = E_FAIL;
  1292. }
  1293. if (SUCCEEDED(hres))
  1294. {
  1295. hres = BriefStg_AddObjectPrivate(pstg, pdtobj, pszFolderEx, uFlags, hwndOwner);
  1296. }
  1297. else
  1298. {
  1299. MsgBox(hwndOwner,
  1300. MAKEINTRESOURCE(ids),
  1301. MAKEINTRESOURCE(IDS_CAP_ADD),
  1302. NULL,
  1303. MB_WARNING,
  1304. pszFolder);
  1305. }
  1306. DEBUG_CODE( DumpTables(); )
  1307. hres = MapToOfficialHresult(hres);
  1308. DBG_EXIT_HRES(TEXT("BriefStg_AddObject"), hres);
  1309. return hres;
  1310. }
  1311. /*----------------------------------------------------------
  1312. Purpose: Removes an object or objects from the briefcase storage.
  1313. Returns: standard hresult
  1314. Cond: --
  1315. */
  1316. HRESULT PRIVATE ReleaseObject(
  1317. CBS * pcbs,
  1318. LPDATAOBJECT pdtobj,
  1319. HWND hwndOwner)
  1320. {
  1321. HRESULT hres;
  1322. LPTSTR pszList;
  1323. UINT cFiles;
  1324. ASSERT(pdtobj);
  1325. hres = DataObj_QueryFileList(pdtobj, &pszList, &cFiles);
  1326. if (SUCCEEDED(hres))
  1327. {
  1328. RETRY_BEGIN(FALSE)
  1329. {
  1330. hres = Sync_Split(pcbs->hbrf, pszList, cFiles, hwndOwner, 0);
  1331. // Unavailable disk?
  1332. if (E_TR_UNAVAILABLE_VOLUME == hres)
  1333. {
  1334. // Yes; ask user to retry/cancel
  1335. int id = MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_UNAVAIL_VOL),
  1336. MAKEINTRESOURCE(IDS_CAP_Split), NULL, MB_RETRYCANCEL | MB_ICONWARNING);
  1337. if (IDRETRY == id)
  1338. RETRY_SET(); // Try again
  1339. }
  1340. }
  1341. RETRY_END()
  1342. DataObj_FreeList(pszList);
  1343. }
  1344. return hres;
  1345. }
  1346. /*----------------------------------------------------------
  1347. Purpose: IBriefcaseStg::ReleaseObject
  1348. Release an object from the briefcase storage.
  1349. Returns: standard hresult
  1350. Cond: --
  1351. */
  1352. STDMETHODIMP BriefStg_ReleaseObject(
  1353. LPBRIEFCASESTG pstg,
  1354. LPDATAOBJECT pdtobj,
  1355. HWND hwndOwner)
  1356. {
  1357. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1358. HRESULT hres;
  1359. DEBUG_CODE( TCHAR szDbg[MAX_PATH]; )
  1360. DBG_ENTER_DTOBJ(TEXT("BriefStg_ReleaseObject"), pdtobj, szDbg, ARRAYSIZE(szDbg));
  1361. ASSERT(pdtobj);
  1362. ASSERT(this->pcbs);
  1363. hres = ReleaseObject(this->pcbs, pdtobj, hwndOwner);
  1364. DEBUG_CODE( DumpTables(); )
  1365. hres = MapToOfficialHresult(hres);
  1366. DBG_EXIT_HRES(TEXT("BriefStg_ReleaseObject"), hres);
  1367. return hres;
  1368. }
  1369. /*----------------------------------------------------------
  1370. Purpose: IBriefcaseStg::UpdateObject
  1371. Update an object in the briefcase storage.
  1372. Returns: standard hresult
  1373. Cond: --
  1374. */
  1375. STDMETHODIMP BriefStg_UpdateObject(
  1376. LPBRIEFCASESTG pstg,
  1377. LPDATAOBJECT pdtobj,
  1378. HWND hwndOwner)
  1379. {
  1380. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1381. HRESULT hres;
  1382. TCHAR szPath[MAX_PATH];
  1383. DEBUG_CODE( TCHAR szDbg[MAX_PATH]; )
  1384. DBG_ENTER_DTOBJ(TEXT("BriefStg_UpdateObject"), pdtobj, szDbg, ARRAYSIZE(szDbg));
  1385. ASSERT(pdtobj);
  1386. ASSERT(this->pcbs);
  1387. // Determine whether this is an Update Selection or Update All.
  1388. hres = DataObj_QueryPath(pdtobj, szPath, ARRAYSIZE(szPath));
  1389. if (SUCCEEDED(hres))
  1390. {
  1391. // Is this a briefcase root?
  1392. if (PathIsBriefcase(szPath))
  1393. {
  1394. // Yes; do an Update All
  1395. hres = Upd_DoModal(hwndOwner, this->pcbs, NULL, 0, UF_ALL);
  1396. }
  1397. else
  1398. {
  1399. // No; do an Update Selection
  1400. LPTSTR pszList;
  1401. UINT cFiles;
  1402. hres = DataObj_QueryFileList(pdtobj, &pszList, &cFiles);
  1403. if (SUCCEEDED(hres))
  1404. {
  1405. hres = Upd_DoModal(hwndOwner, this->pcbs, pszList, cFiles, UF_SELECTION);
  1406. DataObj_FreeList(pszList);
  1407. }
  1408. }
  1409. }
  1410. DEBUG_CODE( DumpTables(); )
  1411. hres = MapToOfficialHresult(hres);
  1412. DBG_EXIT_HRES(TEXT("BriefStg_UpdateObject"), hres);
  1413. return hres;
  1414. }
  1415. /*----------------------------------------------------------
  1416. Purpose: Update a briefcase based on events
  1417. Returns: standard hresult
  1418. Cond: --
  1419. */
  1420. HRESULT PRIVATE BriefStg_UpdateOnEvent(
  1421. LPBRIEFCASESTG pstg,
  1422. UINT uEvent,
  1423. HWND hwndOwner)
  1424. {
  1425. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1426. HRESULT hres = NOERROR;
  1427. DBG_ENTER(TEXT("BriefStg_UpdateOnEvent"));
  1428. switch (uEvent)
  1429. {
  1430. case UOE_CONFIGCHANGED:
  1431. case UOE_QUERYCHANGECONFIG:
  1432. // Is the machine docked?
  1433. if (IsMachineDocked())
  1434. {
  1435. // Yes; does the user want to update?
  1436. TCHAR sz[MAX_PATH];
  1437. int ids = (UOE_CONFIGCHANGED == uEvent) ? IDS_MSG_UpdateOnDock : IDS_MSG_UpdateBeforeUndock;
  1438. LPCTSTR pszBrf = Atom_GetName(this->pcbs->atomBrf);
  1439. int id = MsgBox(hwndOwner,
  1440. MAKEINTRESOURCE(ids),
  1441. MAKEINTRESOURCE(IDS_CAP_UPDATE),
  1442. LoadIcon(g_hinst, MAKEINTRESOURCE(IDI_UPDATE_DOCK)),
  1443. MB_QUESTION,
  1444. PathGetDisplayName(pszBrf, sz, ARRAYSIZE(sz)));
  1445. if (IDYES == id)
  1446. {
  1447. // Yes; do an Update All
  1448. hres = Upd_DoModal(hwndOwner, this->pcbs, NULL, 0, UF_ALL);
  1449. }
  1450. }
  1451. break;
  1452. default:
  1453. hres = ResultFromScode(E_INVALIDARG);
  1454. break;
  1455. }
  1456. DEBUG_CODE( DumpTables(); )
  1457. hres = MapToOfficialHresult(hres);
  1458. DBG_EXIT_HRES(TEXT("BriefStg_UpdateOnEvent"), hres);
  1459. return hres;
  1460. }
  1461. /*----------------------------------------------------------
  1462. Purpose: IBriefcaseStg::Notify
  1463. Marks the path dirty in the briefcase storage cache.
  1464. (The path may not exist in the cache, in which case this
  1465. function does nothing.)
  1466. Returns: S_OK to force a refresh
  1467. S_FALSE to not force a refresh
  1468. Cond: --
  1469. */
  1470. STDMETHODIMP BriefStg_Notify(
  1471. LPBRIEFCASESTG pstg,
  1472. LPCTSTR pszPath, // may be NULL
  1473. LONG lEvent, // one of NOE_ flags
  1474. UINT * puFlags, // returned NF_ flags
  1475. HWND hwndOwner)
  1476. {
  1477. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1478. HRESULT hres = ResultFromScode(E_OUTOFMEMORY);
  1479. TCHAR szCanon[MAX_PATH];
  1480. int atom;
  1481. DBG_ENTER_SZ(TEXT("BriefStg_Notify"), pszPath);
  1482. ASSERT(this->pcbs);
  1483. ASSERT(puFlags);
  1484. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Received event %lx for %s"), lEvent, Dbg_SafeStr(pszPath)); )
  1485. *puFlags = 0;
  1486. // Dirty the entire cache?
  1487. if (NOE_DIRTYALL == lEvent)
  1488. {
  1489. // Yes
  1490. TRACE_MSG(TF_GENERAL, TEXT("Marking everything"));
  1491. CRL_DirtyAll(this->pcbs->atomBrf);
  1492. Sync_ClearBriefcaseCache(this->pcbs->hbrf);
  1493. hres = NOERROR;
  1494. }
  1495. else if (pszPath && 0 < lEvent)
  1496. {
  1497. // No
  1498. BrfPathCanonicalize(pszPath, szCanon, ARRAYSIZE(szCanon));
  1499. atom = Atom_Add(szCanon);
  1500. if (ATOM_ERR != atom)
  1501. {
  1502. int atomCab = Atom_Add(this->szFolder);
  1503. if (ATOM_ERR != atomCab)
  1504. {
  1505. // There are two actions we must determine: what gets marked dirty?
  1506. // and does this specific window get forcibly refreshed?
  1507. BOOL bRefresh;
  1508. BOOL bMarked;
  1509. bMarked = CRL_Dirty(atom, atomCab, lEvent, &bRefresh);
  1510. hres = NOERROR;
  1511. if (bMarked)
  1512. {
  1513. SetFlag(*puFlags, NF_ITEMMARKED);
  1514. }
  1515. #ifdef DEBUG
  1516. if (bMarked && bRefresh)
  1517. {
  1518. TRACE_MSG(TF_GENERAL, TEXT("Marked and forcing refresh of window on %s"), (LPTSTR)this->szFolder);
  1519. }
  1520. else if (bMarked)
  1521. {
  1522. TRACE_MSG(TF_GENERAL, TEXT("Marked"));
  1523. }
  1524. #endif
  1525. Atom_Delete(atomCab);
  1526. }
  1527. Atom_Delete(atom);
  1528. }
  1529. }
  1530. DBG_EXIT_HRES(TEXT("BriefStg_Notify"), hres);
  1531. return hres;
  1532. }
  1533. /*----------------------------------------------------------
  1534. Purpose: Gets special info (status and origin) of a path.
  1535. Returns: --
  1536. Cond: --
  1537. */
  1538. HRESULT PRIVATE BriefStg_GetSpecialInfoOf(
  1539. PBRIEFSTG this,
  1540. LPCTSTR pszName,
  1541. UINT uFlag,
  1542. LPTSTR pszBuf,
  1543. int cchBuf)
  1544. {
  1545. HRESULT hres = E_OUTOFMEMORY;
  1546. TCHAR szPath[MAX_PATH];
  1547. TCHAR szCanon[MAX_PATH];
  1548. int atom;
  1549. ASSERT(this);
  1550. ASSERT(pszName);
  1551. ASSERT(pszBuf);
  1552. ASSERT(this->pcbs);
  1553. *pszBuf = TEXT('\0');
  1554. // Would the path be too long if combined?
  1555. if (PathsTooLong(this->szFolder, pszName))
  1556. {
  1557. // Yes
  1558. hres = E_FAIL;
  1559. }
  1560. else
  1561. {
  1562. PathCombine(szPath, this->szFolder, pszName);
  1563. BrfPathCanonicalize(szPath, szCanon, ARRAYSIZE(szCanon));
  1564. atom = Atom_Add(szCanon);
  1565. if (ATOM_ERR != atom)
  1566. {
  1567. CRL * pcrl;
  1568. // The first CRL_Get call will get the reclist from the cache
  1569. // or get a fresh reclist if the dirty bit is set. If the cache
  1570. // item doesn't exist, add it. We add orphans to the cache too
  1571. // but they have no reclist.
  1572. // Does the cached item already exist?
  1573. hres = CRL_Get(atom, &pcrl);
  1574. if (FAILED(hres))
  1575. {
  1576. // No; add it
  1577. hres = CRL_Add(this->pcbs, atom);
  1578. if (SUCCEEDED(hres))
  1579. {
  1580. // Do another 'get' to offset the CRL_Delete at the end of
  1581. // this function. This will leave this new reclist in the
  1582. // cache upon exit. (We don't want to create a new reclist
  1583. // everytime this functin is called.) It will all get
  1584. // cleaned up when the CBS is freed.
  1585. //
  1586. hres = CRL_Get(atom, &pcrl);
  1587. }
  1588. }
  1589. ASSERT(FAILED(hres) || pcrl);
  1590. // Do we have a cache reclist entry to work with?
  1591. if (pcrl)
  1592. {
  1593. // Yes
  1594. if (GEI_ORIGIN == uFlag)
  1595. {
  1596. lstrcpyn(pszBuf, Atom_GetName(pcrl->atomOutside), cchBuf);
  1597. PathRemoveFileSpec(pszBuf);
  1598. }
  1599. else
  1600. {
  1601. ASSERT(GEI_STATUS == uFlag);
  1602. SzFromIDS(pcrl->idsStatus, pszBuf, cchBuf);
  1603. }
  1604. CRL_Delete(atom); // Decrement count
  1605. }
  1606. Atom_Delete(atom);
  1607. }
  1608. }
  1609. return hres;
  1610. }
  1611. /*----------------------------------------------------------
  1612. Purpose: IBriefcaseStg::GetExtraInfo
  1613. Returns: standard hresult
  1614. Cond: --
  1615. */
  1616. STDMETHODIMP BriefStg_GetExtraInfo(
  1617. LPBRIEFCASESTG pstg,
  1618. LPCTSTR pszName,
  1619. UINT uInfo,
  1620. WPARAM wParam,
  1621. LPARAM lParam)
  1622. {
  1623. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1624. HRESULT hres;
  1625. DBG_ENTER_SZ(TEXT("BriefStg_GetExtraInfo"), pszName);
  1626. ASSERT(this->pcbs);
  1627. switch (uInfo)
  1628. {
  1629. case GEI_ORIGIN:
  1630. case GEI_STATUS: {
  1631. LPTSTR pszBuf = (LPTSTR)lParam;
  1632. int cchBuf = (int)wParam;
  1633. ASSERT(pszName);
  1634. ASSERT(pszBuf);
  1635. hres = BriefStg_GetSpecialInfoOf(this, pszName, uInfo, pszBuf, cchBuf);
  1636. }
  1637. break;
  1638. case GEI_DELAYHANDLE: {
  1639. HANDLE * phMutex = (HANDLE *)lParam;
  1640. ASSERT(phMutex);
  1641. *phMutex = g_hMutexDelay;
  1642. hres = NOERROR;
  1643. }
  1644. break;
  1645. case GEI_ROOT: {
  1646. LPTSTR pszBuf = (LPTSTR)lParam;
  1647. int cchBuf = (int)wParam;
  1648. ASSERT(pszBuf);
  1649. lstrcpyn(pszBuf, Atom_GetName(this->pcbs->atomBrf), cchBuf);
  1650. #ifdef DEBUG
  1651. if (IsFlagSet(g_uDumpFlags, DF_PATHS))
  1652. {
  1653. TRACE_MSG(TF_ALWAYS, TEXT("Root is \"%s\""), pszBuf);
  1654. }
  1655. #endif
  1656. hres = NOERROR;
  1657. }
  1658. break;
  1659. case GEI_DATABASENAME: {
  1660. LPTSTR pszBuf = (LPTSTR)lParam;
  1661. int cchBuf = (int)wParam;
  1662. LPCTSTR pszDBName;
  1663. ASSERT(pszBuf);
  1664. if (IsFlagSet(this->pcbs->uFlags, CBSF_LFNDRIVE))
  1665. pszDBName = g_szDBName;
  1666. else
  1667. pszDBName = g_szDBNameShort;
  1668. lstrcpyn(pszBuf, pszDBName, cchBuf);
  1669. hres = NOERROR;
  1670. }
  1671. break;
  1672. default:
  1673. hres = E_INVALIDARG;
  1674. break;
  1675. }
  1676. DBG_EXIT_HRES(TEXT("BriefStg_GetExtraInfo"), hres);
  1677. return hres;
  1678. }
  1679. /*----------------------------------------------------------
  1680. Purpose: IBriefcaseStg::FindFirst
  1681. Returns the location of the root of the first briefcase storage
  1682. in the system.
  1683. Returns: S_OK if a briefcase was found
  1684. S_FALSE to end enumeration
  1685. Cond: --
  1686. */
  1687. STDMETHODIMP BriefStg_FindFirst(
  1688. LPBRIEFCASESTG pstg,
  1689. LPTSTR pszName,
  1690. int cchMaxName)
  1691. {
  1692. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1693. HRESULT hres;
  1694. TWINRESULT tr;
  1695. BRFCASEINFO bcinfo;
  1696. DBG_ENTER(TEXT("BriefStg_FindFirst"));
  1697. ASSERT(pszName);
  1698. bcinfo.ulSize = sizeof(bcinfo);
  1699. tr = Sync_FindFirst(&this->hbrfcaseiter, &bcinfo);
  1700. switch (tr)
  1701. {
  1702. case TR_OUT_OF_MEMORY:
  1703. hres = ResultFromScode(E_OUTOFMEMORY);
  1704. break;
  1705. case TR_SUCCESS:
  1706. hres = ResultFromScode(S_OK);
  1707. lstrcpyn(pszName, bcinfo.rgchDatabasePath, cchMaxName);
  1708. break;
  1709. case TR_NO_MORE:
  1710. hres = ResultFromScode(S_FALSE);
  1711. break;
  1712. default:
  1713. hres = ResultFromScode(E_FAIL);
  1714. break;
  1715. }
  1716. DBG_EXIT_HRES(TEXT("BriefStg_FindFirst"), hres);
  1717. return hres;
  1718. }
  1719. /*----------------------------------------------------------
  1720. Purpose: IBriefcaseStg::FindNext
  1721. Returns the location of the root of the next briefcase storage
  1722. in the system.
  1723. Returns: S_OK if a briefcase was found
  1724. S_FALSE to end enumeration
  1725. Cond: --
  1726. */
  1727. STDMETHODIMP BriefStg_FindNext(
  1728. LPBRIEFCASESTG pstg,
  1729. LPTSTR pszName,
  1730. int cchMaxName)
  1731. {
  1732. PBRIEFSTG this = IToClass(BriefStg, bs, pstg);
  1733. HRESULT hres;
  1734. TWINRESULT tr;
  1735. BRFCASEINFO bcinfo;
  1736. DBG_ENTER(TEXT("BriefStg_FindNext"));
  1737. ASSERT(pszName);
  1738. bcinfo.ulSize = sizeof(bcinfo);
  1739. tr = Sync_FindNext(this->hbrfcaseiter, &bcinfo);
  1740. switch (tr)
  1741. {
  1742. case TR_OUT_OF_MEMORY:
  1743. hres = ResultFromScode(E_OUTOFMEMORY);
  1744. break;
  1745. case TR_SUCCESS:
  1746. hres = ResultFromScode(S_OK);
  1747. lstrcpyn(pszName, bcinfo.rgchDatabasePath, cchMaxName);
  1748. break;
  1749. case TR_NO_MORE:
  1750. hres = ResultFromScode(S_FALSE);
  1751. break;
  1752. default:
  1753. hres = ResultFromScode(E_FAIL);
  1754. break;
  1755. }
  1756. DBG_EXIT_HRES(TEXT("BriefStg_FindNext"), hres);
  1757. return hres;
  1758. }
  1759. //---------------------------------------------------------------------------
  1760. // BriefStg class : Vtables
  1761. //---------------------------------------------------------------------------
  1762. IBriefcaseStgVtbl c_BriefStg_BSVtbl =
  1763. {
  1764. BriefStg_QueryInterface,
  1765. BriefStg_AddRef,
  1766. BriefStg_Release,
  1767. BriefStg_Initialize,
  1768. BriefStg_AddObject,
  1769. BriefStg_ReleaseObject,
  1770. BriefStg_UpdateObject,
  1771. BriefStg_UpdateOnEvent,
  1772. BriefStg_GetExtraInfo,
  1773. BriefStg_Notify,
  1774. BriefStg_FindFirst,
  1775. BriefStg_FindNext,
  1776. };
  1777. /*----------------------------------------------------------
  1778. Purpose: This function is called back from within
  1779. IClassFactory::CreateInstance() of the default class
  1780. factory object, which is created by SHCreateClassObject.
  1781. Returns: standard
  1782. Cond: --
  1783. */
  1784. HRESULT CALLBACK BriefStg_CreateInstance(
  1785. LPUNKNOWN punkOuter, // Should be NULL for us
  1786. REFIID riid,
  1787. LPVOID * ppvOut)
  1788. {
  1789. HRESULT hres = E_FAIL;
  1790. PBRIEFSTG this;
  1791. DBG_ENTER_RIID(TEXT("BriefStg_CreateInstance"), riid);
  1792. // Briefcase storage does not support aggregation.
  1793. //
  1794. if (punkOuter)
  1795. {
  1796. hres = CLASS_E_NOAGGREGATION;
  1797. *ppvOut = NULL;
  1798. goto Leave;
  1799. }
  1800. this = GAlloc(sizeof(*this));
  1801. if (!this)
  1802. {
  1803. hres = E_OUTOFMEMORY;
  1804. *ppvOut = NULL;
  1805. goto Leave;
  1806. }
  1807. this->bs.lpVtbl = &c_BriefStg_BSVtbl;
  1808. this->cRef = 1;
  1809. this->pcbs = NULL;
  1810. this->dwFlags = 0;
  1811. // Load the engine if it hasn't already been loaded
  1812. // (this only returns FALSE if something went wrong)
  1813. if (Sync_QueryVTable())
  1814. {
  1815. ENTEREXCLUSIVE();
  1816. {
  1817. // The decrement is in BriefStg_Release()
  1818. IncBriefSemaphore();
  1819. if (IsFirstBriefSemaphore())
  1820. {
  1821. ProcessIniFile(); // Load settings first
  1822. // Initialize cache
  1823. if (InitCacheTables())
  1824. hres = NOERROR;
  1825. else
  1826. hres = E_OUTOFMEMORY;
  1827. }
  1828. else
  1829. {
  1830. hres = NOERROR;
  1831. }
  1832. }
  1833. LEAVEEXCLUSIVE();
  1834. }
  1835. if (SUCCEEDED(hres))
  1836. {
  1837. // Note that the Release member will free the object, if
  1838. // QueryInterface failed.
  1839. //
  1840. hres = this->bs.lpVtbl->QueryInterface(&this->bs, riid, ppvOut);
  1841. this->bs.lpVtbl->Release(&this->bs);
  1842. }
  1843. else
  1844. {
  1845. *ppvOut = NULL;
  1846. }
  1847. Leave:
  1848. DBG_EXIT_HRES(TEXT("BriefStg_CreateInstance"), hres);
  1849. return hres; // S_OK or E_NOINTERFACE
  1850. }