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.

903 lines
26 KiB

  1. /*
  2. * merge.c - File merge handler module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "stub.h"
  9. #include "oleutil.h"
  10. #include "irecinit.h"
  11. /* Module Variables
  12. *******************/
  13. /* lock count for reconciliation handler cache */
  14. PRIVATE_DATA ULONG MulcRecHandlerCacheLock = 0;
  15. /* handle to reconciliation handler cache */
  16. PRIVATE_DATA HCLSIFACECACHE MhcicRecHandlerCache = NULL;
  17. /***************************** Private Functions *****************************/
  18. /* Module Prototypes
  19. ********************/
  20. PRIVATE_CODE HRESULT CreateRecHandlerCache(void);
  21. PRIVATE_CODE void DestroyRecHandlerCache(void);
  22. PRIVATE_CODE HRESULT OLEMerge(PRECNODE, RECSTATUSPROC, LPARAM, DWORD, HWND, HWND, PRECNODE *);
  23. PRIVATE_CODE BOOL GetRecNodeByIndex(PCRECITEM, LONG, PRECNODE *);
  24. PRIVATE_CODE HRESULT CreateMergeSourceMonikers(PRECNODE, PULONG, PIMoniker **);
  25. PRIVATE_CODE HRESULT CreateCopyDestinationMonikers(PCRECITEM, PULONG, PIMoniker **);
  26. #ifdef DEBUG
  27. PRIVATE_CODE BOOL RecHandlerCacheIsOk(void);
  28. PRIVATE_CODE BOOL VerifyRECITEMAndDestRECNODE(PCRECNODE);
  29. #endif
  30. /*
  31. ** CreateRecHandlerCache()
  32. **
  33. **
  34. **
  35. ** Arguments:
  36. **
  37. ** Returns:
  38. **
  39. ** Side Effects: none
  40. */
  41. PRIVATE_CODE HRESULT CreateRecHandlerCache(void)
  42. {
  43. HRESULT hr;
  44. ASSERT(RecHandlerCacheIsOk());
  45. /* Has the merge handler cache already been created? */
  46. if (MhcicRecHandlerCache)
  47. /* Yes. */
  48. hr = S_OK;
  49. else
  50. {
  51. /* No. Create it. */
  52. if (CreateClassInterfaceCache(&MhcicRecHandlerCache))
  53. {
  54. hr = S_OK;
  55. TRACE_OUT((TEXT("CreateRecHandlerCache(): Merge handler cache created.")));
  56. }
  57. else
  58. hr = E_OUTOFMEMORY;
  59. }
  60. ASSERT(RecHandlerCacheIsOk());
  61. return(hr);
  62. }
  63. /*
  64. ** DestroyRecHandlerCache()
  65. **
  66. **
  67. **
  68. ** Arguments:
  69. **
  70. ** Returns:
  71. **
  72. ** Side Effects: none
  73. */
  74. PRIVATE_CODE void DestroyRecHandlerCache(void)
  75. {
  76. ASSERT(RecHandlerCacheIsOk());
  77. /* Has the merge handler cache already been created? */
  78. if (MhcicRecHandlerCache)
  79. {
  80. /* Yes. Destroy it. */
  81. DestroyClassInterfaceCache(MhcicRecHandlerCache);
  82. MhcicRecHandlerCache = NULL;
  83. TRACE_OUT((TEXT("DestroyRecHandlerCache(): Merge handler cache destroyed.")));
  84. }
  85. ASSERT(RecHandlerCacheIsOk());
  86. return;
  87. }
  88. /*
  89. ** OLEMerge()
  90. **
  91. **
  92. **
  93. ** Arguments:
  94. **
  95. ** Returns:
  96. **
  97. ** Side Effects: none
  98. */
  99. PRIVATE_CODE HRESULT OLEMerge(PRECNODE prnDest, RECSTATUSPROC rsp,
  100. LPARAM lpCallbackData, DWORD dwInFlags,
  101. HWND hwndOwner, HWND hwndProgressFeedback,
  102. PRECNODE *pprnMergedResult)
  103. {
  104. HRESULT hr;
  105. TCHAR rgchMergeDestPath[MAX_PATH_LEN];
  106. CLSID clsidReconcilableObject;
  107. /* lpCallbackData may be any value. */
  108. ASSERT(IS_VALID_STRUCT_PTR(prnDest, CRECNODE));
  109. ASSERT(! rsp ||
  110. IS_VALID_CODE_PTR(rsp, RECSTATUSPROC));
  111. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_RI_FLAGS));
  112. ASSERT(IS_FLAG_CLEAR(dwInFlags, RI_FL_ALLOW_UI) ||
  113. IS_VALID_HANDLE(hwndOwner, WND));
  114. ASSERT(IS_FLAG_CLEAR(dwInFlags, RI_FL_FEEDBACK_WINDOW_VALID) ||
  115. IS_VALID_HANDLE(hwndProgressFeedback, WND));
  116. ASSERT(IS_VALID_WRITE_PTR(pprnMergedResult, PRECNODE));
  117. ComposePath(rgchMergeDestPath, prnDest->pcszFolder, prnDest->priParent->pcszName,
  118. ARRAYSIZE(rgchMergeDestPath));
  119. ASSERT(lstrlen(rgchMergeDestPath) < ARRAYSIZE(rgchMergeDestPath));
  120. hr = GetReconcilerClassID(rgchMergeDestPath, &clsidReconcilableObject);
  121. if (SUCCEEDED(hr))
  122. {
  123. PIReconcilableObject piro;
  124. hr = GetClassInterface(MhcicRecHandlerCache, &clsidReconcilableObject,
  125. &IID_IReconcilableObject, &piro);
  126. if (SUCCEEDED(hr))
  127. {
  128. HSTGIFACE hstgi;
  129. hr = GetStorageInterface((PIUnknown)piro, &hstgi);
  130. if (SUCCEEDED(hr))
  131. {
  132. hr = LoadFromStorage(hstgi, rgchMergeDestPath);
  133. if (SUCCEEDED(hr))
  134. {
  135. PIReconcileInitiator pirecinit;
  136. hr = IReconcileInitiator_Constructor(
  137. GetTwinBriefcase((HTWIN)(prnDest->hObjectTwin)), rsp,
  138. lpCallbackData, &pirecinit);
  139. if (SUCCEEDED(hr))
  140. {
  141. ULONG ulcMergeSources;
  142. PIMoniker *ppimkMergeSources;
  143. hr = CreateMergeSourceMonikers(prnDest, &ulcMergeSources,
  144. &ppimkMergeSources);
  145. if (SUCCEEDED(hr))
  146. {
  147. DWORD dwOLEFlags;
  148. LONG liMergedResult;
  149. dwOLEFlags = (RECONCILEF_NORESIDUESOK |
  150. RECONCILEF_OMITSELFRESIDUE |
  151. RECONCILEF_YOUMAYDOTHEUPDATES);
  152. if (IS_FLAG_SET(dwInFlags, RI_FL_ALLOW_UI))
  153. SET_FLAG(dwOLEFlags, RECONCILEF_MAYBOTHERUSER);
  154. if (IS_FLAG_SET(dwInFlags, RI_FL_FEEDBACK_WINDOW_VALID))
  155. SET_FLAG(dwOLEFlags, RECONCILEF_FEEDBACKWINDOWVALID);
  156. hr = piro->lpVtbl->Reconcile(piro, pirecinit, dwOLEFlags,
  157. hwndOwner,
  158. hwndProgressFeedback,
  159. ulcMergeSources,
  160. ppimkMergeSources,
  161. &liMergedResult, NULL, NULL);
  162. if (SUCCEEDED(hr))
  163. {
  164. if (hr == REC_S_IDIDTHEUPDATES)
  165. {
  166. /* Return original merge destination RECNODE. */
  167. *pprnMergedResult = prnDest;
  168. TRACE_OUT((TEXT("OLEMerge(): IReconcilableObject::Reconcile() returned %s. Not saving merged result to %s\\%s."),
  169. GetHRESULTString(hr),
  170. prnDest->pcszFolder,
  171. prnDest->priParent->pcszName));
  172. }
  173. else
  174. {
  175. /*
  176. * Only save the merged result if it's different
  177. * than all of the replicas.
  178. */
  179. if (liMergedResult < 0)
  180. {
  181. ASSERT(liMergedResult == -1);
  182. hr = SaveToStorage(hstgi);
  183. if (SUCCEEDED(hr))
  184. {
  185. *pprnMergedResult = prnDest;
  186. TRACE_OUT((TEXT("OLEMerge(): Merge into %s completed successfully."),
  187. rgchMergeDestPath));
  188. }
  189. else
  190. WARNING_OUT((TEXT("OLEMerge(): Failed to save merged result to %s."),
  191. rgchMergeDestPath));
  192. }
  193. else if (! liMergedResult)
  194. {
  195. *pprnMergedResult = prnDest;
  196. TRACE_OUT((TEXT("OLEMerge(): Merged result identical to %s."),
  197. rgchMergeDestPath));
  198. }
  199. else
  200. {
  201. if (GetRecNodeByIndex(prnDest->priParent,
  202. liMergedResult,
  203. pprnMergedResult))
  204. TRACE_OUT((TEXT("OLEMerge(): Merged result identical to %s\\%s."),
  205. (*pprnMergedResult)->pcszFolder,
  206. (*pprnMergedResult)->priParent->pcszName));
  207. else
  208. {
  209. hr = E_UNEXPECTED;
  210. WARNING_OUT((TEXT("OLEMerge(): Merge handler returned bad merge result index %ld. No such RECNODE for %s."),
  211. liMergedResult,
  212. prnDest->priParent->pcszName));
  213. }
  214. }
  215. }
  216. }
  217. else
  218. WARNING_OUT((TEXT("OLEMerge(): Merge to %s failed."),
  219. rgchMergeDestPath));
  220. ReleaseIUnknowns(ulcMergeSources,
  221. (PIUnknown *)ppimkMergeSources);
  222. }
  223. else
  224. WARNING_OUT((TEXT("OLEMerge(): Failed to create merge source monikers for merge destination %s."),
  225. rgchMergeDestPath));
  226. EVAL(! pirecinit->lpVtbl->Release(pirecinit));
  227. }
  228. else
  229. WARNING_OUT((TEXT("OLEMerge(): Failed to create ReconcileInitiator for merge destination %s."),
  230. rgchMergeDestPath));
  231. }
  232. else
  233. WARNING_OUT((TEXT("OLEMerge(): Failed to load replica %s from storage."),
  234. rgchMergeDestPath));
  235. ReleaseStorageInterface(hstgi);
  236. }
  237. else
  238. WARNING_OUT((TEXT("OLEMerge(): Failed to get storage interface for replica %s."),
  239. rgchMergeDestPath));
  240. }
  241. else
  242. TRACE_OUT((TEXT("OLEMerge(): Failed to get IReconcilableObject for replica %s."),
  243. rgchMergeDestPath));
  244. }
  245. else
  246. TRACE_OUT((TEXT("OLEMerge(): Failed to get reconciliation handler class ID for replica %s."),
  247. rgchMergeDestPath));
  248. ASSERT(FAILED(hr) ||
  249. (IS_VALID_STRUCT_PTR(*pprnMergedResult, CRECNODE) &&
  250. (*pprnMergedResult)->priParent == prnDest->priParent));
  251. return(hr);
  252. }
  253. /*
  254. ** GetRecNodeByIndex()
  255. **
  256. **
  257. **
  258. ** Arguments:
  259. **
  260. ** Returns:
  261. **
  262. ** Side Effects: none
  263. **
  264. ** The first RECNODE in the RECITEM's list of RECNODEs is index 1, the second
  265. ** RECNODE is index 2, etc.
  266. */
  267. PRIVATE_CODE BOOL GetRecNodeByIndex(PCRECITEM pcri, LONG li, PRECNODE *pprn)
  268. {
  269. BOOL bFound;
  270. ASSERT(IS_VALID_STRUCT_PTR(pcri, CRECITEM));
  271. ASSERT(IS_VALID_WRITE_PTR(pprn, PRECNODE));
  272. if (EVAL(li > 0))
  273. {
  274. PRECNODE prn;
  275. for (prn = pcri->prnFirst; prn && --li > 0; prn = prn->prnNext)
  276. ;
  277. bFound = EVAL(prn && ! li);
  278. if (bFound)
  279. *pprn = prn;
  280. }
  281. else
  282. bFound = FALSE;
  283. ASSERT(! bFound ||
  284. (IS_VALID_STRUCT_PTR(*pprn, CRECNODE) &&
  285. (*pprn)->priParent == pcri));
  286. return(bFound);
  287. }
  288. /*
  289. ** CreateMergeSourceMonikers()
  290. **
  291. **
  292. **
  293. ** Arguments:
  294. **
  295. ** Returns:
  296. **
  297. ** Side Effects: none
  298. */
  299. PRIVATE_CODE HRESULT CreateMergeSourceMonikers(PRECNODE prnDest,
  300. PULONG pulcMergeSources,
  301. PIMoniker **pppimk)
  302. {
  303. HRESULT hr;
  304. ULONG ulcMergeSources;
  305. PCRECNODE pcrn;
  306. ASSERT(IS_VALID_STRUCT_PTR(prnDest, CRECNODE));
  307. ASSERT(IS_VALID_WRITE_PTR(pulcMergeSources, ULONG));
  308. ASSERT(IS_VALID_WRITE_PTR(pppimk, PIMoniker *));
  309. ulcMergeSources = 0;
  310. for (pcrn = prnDest->priParent->prnFirst; pcrn; pcrn = pcrn->prnNext)
  311. {
  312. if (pcrn->rnaction == RNA_MERGE_ME &&
  313. pcrn != prnDest)
  314. ulcMergeSources++;
  315. }
  316. if (AllocateMemory(ulcMergeSources * sizeof(**pppimk), (PVOID *)pppimk))
  317. {
  318. hr = S_OK;
  319. *pulcMergeSources = 0;
  320. for (pcrn = prnDest->priParent->prnFirst; pcrn; pcrn = pcrn->prnNext)
  321. {
  322. if (pcrn->rnaction == RNA_MERGE_ME &&
  323. pcrn != prnDest)
  324. {
  325. hr = MyCreateFileMoniker(pcrn->pcszFolder,
  326. pcrn->priParent->pcszName,
  327. &((*pppimk)[*pulcMergeSources]));
  328. if (SUCCEEDED(hr))
  329. {
  330. ASSERT(*pulcMergeSources < ulcMergeSources);
  331. (*pulcMergeSources)++;
  332. }
  333. else
  334. break;
  335. }
  336. }
  337. if (FAILED(hr))
  338. ReleaseIUnknowns(*pulcMergeSources, *(PIUnknown **)pppimk);
  339. }
  340. else
  341. hr = E_OUTOFMEMORY;
  342. return(hr);
  343. }
  344. /*
  345. ** CreateCopyDestinationMonikers()
  346. **
  347. **
  348. **
  349. ** Arguments:
  350. **
  351. ** Returns:
  352. **
  353. ** Side Effects: none
  354. */
  355. PRIVATE_CODE HRESULT CreateCopyDestinationMonikers(PCRECITEM pcri,
  356. PULONG pulcCopyDestinations,
  357. PIMoniker **pppimk)
  358. {
  359. HRESULT hr;
  360. ULONG ulcCopyDestinations;
  361. PCRECNODE pcrn;
  362. ASSERT(IS_VALID_STRUCT_PTR(pcri, CRECITEM));
  363. ASSERT(IS_VALID_WRITE_PTR(pulcCopyDestinations, ULONG));
  364. ASSERT(IS_VALID_WRITE_PTR(pppimk, PIMoniker *));
  365. ulcCopyDestinations = 0;
  366. for (pcrn = pcri->prnFirst; pcrn; pcrn = pcrn->prnNext)
  367. {
  368. if (pcrn->rnaction == RNA_COPY_TO_ME)
  369. ulcCopyDestinations++;
  370. }
  371. if (AllocateMemory(ulcCopyDestinations * sizeof(**pppimk), (PVOID *)pppimk))
  372. {
  373. hr = S_OK;
  374. *pulcCopyDestinations = 0;
  375. for (pcrn = pcri->prnFirst; pcrn; pcrn = pcrn->prnNext)
  376. {
  377. if (pcrn->rnaction == RNA_COPY_TO_ME)
  378. {
  379. ASSERT(pcrn->priParent == pcri);
  380. hr = MyCreateFileMoniker(pcrn->pcszFolder,
  381. pcrn->priParent->pcszName,
  382. &((*pppimk)[*pulcCopyDestinations]));
  383. if (SUCCEEDED(hr))
  384. {
  385. ASSERT(*pulcCopyDestinations < ulcCopyDestinations);
  386. (*pulcCopyDestinations)++;
  387. }
  388. else
  389. break;
  390. }
  391. }
  392. if (FAILED(hr))
  393. ReleaseIUnknowns(*pulcCopyDestinations, *(PIUnknown **)pppimk);
  394. }
  395. else
  396. hr = E_OUTOFMEMORY;
  397. return(hr);
  398. }
  399. #ifdef DEBUG
  400. /*
  401. ** RecHandlerCacheIsOk()
  402. **
  403. **
  404. **
  405. ** Arguments:
  406. **
  407. ** Returns:
  408. **
  409. ** Side Effects: none
  410. */
  411. PRIVATE_CODE BOOL RecHandlerCacheIsOk(void)
  412. {
  413. /* Are the module merge handler cache variables in a correct state? */
  414. return(! MhcicRecHandlerCache ||
  415. IS_VALID_HANDLE(MhcicRecHandlerCache, CLSIFACECACHE));
  416. }
  417. /*
  418. ** VerifyRECITEMAndDestRECNODE()
  419. **
  420. **
  421. **
  422. ** Arguments:
  423. **
  424. ** Returns:
  425. **
  426. ** Side Effects: none
  427. */
  428. PRIVATE_CODE BOOL VerifyRECITEMAndDestRECNODE(PCRECNODE pcrnSrc)
  429. {
  430. /* Do the RECITEM and source RECNODE actions match? */
  431. return(pcrnSrc->priParent->riaction == RIA_MERGE &&
  432. pcrnSrc->rnaction == RNA_MERGE_ME);
  433. }
  434. #endif
  435. /****************************** Public Functions *****************************/
  436. /*
  437. ** BeginMerge()
  438. **
  439. **
  440. **
  441. ** Arguments:
  442. **
  443. ** Returns:
  444. **
  445. ** Side Effects: none
  446. */
  447. PUBLIC_CODE void BeginMerge(void)
  448. {
  449. ASSERT(RecHandlerCacheIsOk());
  450. ASSERT(MulcRecHandlerCacheLock < ULONG_MAX);
  451. MulcRecHandlerCacheLock++;
  452. ASSERT(RecHandlerCacheIsOk());
  453. return;
  454. }
  455. /*
  456. ** EndMerge()
  457. **
  458. **
  459. **
  460. ** Arguments:
  461. **
  462. ** Returns:
  463. **
  464. ** Side Effects: none
  465. */
  466. PUBLIC_CODE void EndMerge(void)
  467. {
  468. ASSERT(RecHandlerCacheIsOk());
  469. /* Is the merge handler cache still locked? */
  470. if (! --MulcRecHandlerCacheLock)
  471. DestroyRecHandlerCache();
  472. ASSERT(RecHandlerCacheIsOk());
  473. return;
  474. }
  475. /*
  476. ** MergeHandler()
  477. **
  478. **
  479. **
  480. ** Arguments:
  481. **
  482. ** Returns:
  483. **
  484. ** Side Effects: none
  485. */
  486. PUBLIC_CODE HRESULT MergeHandler(PRECNODE prnDest, RECSTATUSPROC rsp,
  487. LPARAM lpCallbackData, DWORD dwInFlags,
  488. HWND hwndOwner, HWND hwndProgressFeedback,
  489. PRECNODE *pprnMergedResult)
  490. {
  491. HRESULT hr;
  492. /* lpCallbackData may be any value. */
  493. ASSERT(IS_VALID_STRUCT_PTR(prnDest, CRECNODE));
  494. ASSERT(! rsp ||
  495. IS_VALID_CODE_PTR(rsp, RECSTATUSPROC));
  496. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_RI_FLAGS));
  497. ASSERT(IS_FLAG_CLEAR(dwInFlags, RI_FL_ALLOW_UI) ||
  498. IS_VALID_HANDLE(hwndOwner, WND));
  499. ASSERT(IS_FLAG_CLEAR(dwInFlags, RI_FL_FEEDBACK_WINDOW_VALID) ||
  500. IS_VALID_HANDLE(hwndProgressFeedback, WND));
  501. ASSERT(IS_VALID_WRITE_PTR(pprnMergedResult, PRECNODE));
  502. ASSERT(VerifyRECITEMAndDestRECNODE(prnDest));
  503. BeginMerge();
  504. /* Make sure the merge handler cache has been created. */
  505. hr = CreateRecHandlerCache();
  506. if (SUCCEEDED(hr))
  507. {
  508. RECSTATUSUPDATE rsu;
  509. /* 0% complete. */
  510. rsu.ulScale = 1;
  511. rsu.ulProgress = 0;
  512. if (NotifyReconciliationStatus(rsp, RS_BEGIN_MERGE, (LPARAM)&rsu,
  513. lpCallbackData))
  514. {
  515. hr = OLEMerge(prnDest, rsp, lpCallbackData, dwInFlags, hwndOwner,
  516. hwndProgressFeedback, pprnMergedResult);
  517. if (SUCCEEDED(hr))
  518. {
  519. /* 100% complete. */
  520. rsu.ulScale = 1;
  521. rsu.ulProgress = 1;
  522. /* Don't allow abort. */
  523. NotifyReconciliationStatus(rsp, RS_END_MERGE, (LPARAM)&rsu,
  524. lpCallbackData);
  525. }
  526. }
  527. else
  528. hr = E_ABORT;
  529. }
  530. EndMerge();
  531. ASSERT(FAILED(hr) ||
  532. (IS_VALID_STRUCT_PTR(*pprnMergedResult, CRECNODE) &&
  533. (*pprnMergedResult)->priParent == prnDest->priParent));
  534. return(hr);
  535. }
  536. /*
  537. ** MyCreateFileMoniker()
  538. **
  539. **
  540. **
  541. ** Arguments:
  542. **
  543. ** Returns:
  544. **
  545. ** Side Effects: none
  546. */
  547. PUBLIC_CODE HRESULT MyCreateFileMoniker(LPCTSTR pcszPath, LPCTSTR pcszSubPath,
  548. PIMoniker *ppimk)
  549. {
  550. HRESULT hr;
  551. TCHAR rgchPath[MAX_PATH_LEN];
  552. WCHAR rgwchUnicodePath[MAX_PATH_LEN];
  553. ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  554. ASSERT(IS_VALID_WRITE_PTR(ppimk, PIMoniker));
  555. ComposePath(rgchPath, pcszPath, pcszSubPath, ARRAYSIZE(rgchPath));
  556. ASSERT(lstrlen(rgchPath) < ARRAYSIZE(rgchPath));
  557. #ifdef UNICODE
  558. hr = CreateFileMoniker(rgchPath, ppimk);
  559. #else
  560. /* Translate ANSI string into Unicode for OLE. */
  561. if (MultiByteToWideChar(CP_ACP, 0, rgchPath, -1, rgwchUnicodePath,
  562. ARRAY_ELEMENTS(rgwchUnicodePath)))
  563. {
  564. hr = CreateFileMoniker(rgwchUnicodePath, ppimk);
  565. }
  566. else
  567. {
  568. hr = MAKE_SCODE(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  569. }
  570. #endif
  571. if (FAILED(hr))
  572. WARNING_OUT((TEXT("MyCreateFileMoniker(): CreateFileMoniker() on %s failed, returning %s."),
  573. pcszPath,
  574. GetHRESULTString(hr)));
  575. return(hr);
  576. }
  577. /*
  578. ** ReleaseIUnknowns()
  579. **
  580. **
  581. **
  582. ** Arguments:
  583. **
  584. ** Returns:
  585. **
  586. ** Side Effects: none
  587. */
  588. PUBLIC_CODE void ReleaseIUnknowns(ULONG ulcIUnknowns, PIUnknown *ppiunk)
  589. {
  590. ULONG uli;
  591. /* ulcIUnknowns may be any value. */
  592. ASSERT(IS_VALID_READ_BUFFER_PTR(ppiunk, PIUnknown, ulcIUnknowns * sizeof(*ppiunk)));
  593. for (uli = 0; uli < ulcIUnknowns; uli++)
  594. {
  595. ASSERT(IS_VALID_STRUCT_PTR(ppiunk[uli], CIUnknown));
  596. ppiunk[uli]->lpVtbl->Release(ppiunk[uli]);
  597. }
  598. FreeMemory(ppiunk);
  599. return;
  600. }
  601. /*
  602. ** OLECopy()
  603. **
  604. **
  605. **
  606. ** Arguments:
  607. **
  608. ** Returns:
  609. **
  610. ** Side Effects: none
  611. */
  612. PUBLIC_CODE HRESULT OLECopy(PRECNODE prnSrc, PCCLSID pcclsidReconcilableObject,
  613. RECSTATUSPROC rsp, LPARAM lpCallbackData,
  614. DWORD dwFlags, HWND hwndOwner,
  615. HWND hwndProgressFeedback)
  616. {
  617. HRESULT hr;
  618. /* lpCallbackData may be any value. */
  619. ASSERT(IS_VALID_STRUCT_PTR(prnSrc, CRECNODE));
  620. ASSERT(IS_VALID_STRUCT_PTR(pcclsidReconcilableObject, CCLSID));
  621. ASSERT(! rsp ||
  622. IS_VALID_CODE_PTR(rsp, RECSTATUSPROC));
  623. ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_RI_FLAGS));
  624. ASSERT(IS_FLAG_CLEAR(dwFlags, RI_FL_ALLOW_UI) ||
  625. IS_VALID_HANDLE(hwndOwner, WND));
  626. ASSERT(IS_FLAG_CLEAR(dwFlags, RI_FL_FEEDBACK_WINDOW_VALID) ||
  627. IS_VALID_HANDLE(hwndProgressFeedback, WND));
  628. BeginMerge();
  629. /* Make sure the merge handler cache has been created. */
  630. hr = CreateRecHandlerCache();
  631. if (SUCCEEDED(hr))
  632. {
  633. TCHAR rgchCopySrcPath[MAX_PATH_LEN];
  634. PIReconcilableObject piro;
  635. ComposePath(rgchCopySrcPath, prnSrc->pcszFolder, prnSrc->priParent->pcszName,
  636. ARRAYSIZE(rgchCopySrcPath));
  637. ASSERT(lstrlen(rgchCopySrcPath) < ARRAYSIZE(rgchCopySrcPath));
  638. hr = GetClassInterface(MhcicRecHandlerCache, pcclsidReconcilableObject,
  639. &IID_IReconcilableObject, &piro);
  640. if (SUCCEEDED(hr))
  641. {
  642. HSTGIFACE hstgi;
  643. hr = GetStorageInterface((PIUnknown)piro, &hstgi);
  644. if (SUCCEEDED(hr))
  645. {
  646. hr = LoadFromStorage(hstgi, rgchCopySrcPath);
  647. if (SUCCEEDED(hr))
  648. {
  649. PIReconcileInitiator pirecinit;
  650. hr = IReconcileInitiator_Constructor(
  651. GetTwinBriefcase((HTWIN)(prnSrc->hObjectTwin)), rsp,
  652. lpCallbackData, &pirecinit);
  653. if (SUCCEEDED(hr))
  654. {
  655. ULONG ulcCopyDestinations;
  656. PIMoniker *ppimkCopyDestinations;
  657. hr = CreateCopyDestinationMonikers(prnSrc->priParent,
  658. &ulcCopyDestinations,
  659. &ppimkCopyDestinations);
  660. if (SUCCEEDED(hr))
  661. {
  662. DWORD dwOLEFlags;
  663. LONG liMergedResult;
  664. dwOLEFlags = (RECONCILEF_YOUMAYDOTHEUPDATES |
  665. RECONCILEF_ONLYYOUWERECHANGED);
  666. if (IS_FLAG_SET(dwFlags, RI_FL_ALLOW_UI))
  667. SET_FLAG(dwOLEFlags, RECONCILEF_MAYBOTHERUSER);
  668. if (IS_FLAG_SET(dwFlags, RI_FL_FEEDBACK_WINDOW_VALID))
  669. SET_FLAG(dwOLEFlags, RECONCILEF_FEEDBACKWINDOWVALID);
  670. hr = piro->lpVtbl->Reconcile(piro, pirecinit, dwOLEFlags,
  671. hwndOwner,
  672. hwndProgressFeedback,
  673. ulcCopyDestinations,
  674. ppimkCopyDestinations,
  675. &liMergedResult, NULL, NULL);
  676. if (SUCCEEDED(hr))
  677. {
  678. ASSERT(liMergedResult == -1);
  679. if (hr == S_FALSE)
  680. /* Release storage for internal copy routine. */
  681. HandsOffStorage(hstgi);
  682. else
  683. ASSERT(hr == REC_S_IDIDTHEUPDATES);
  684. }
  685. else
  686. WARNING_OUT((TEXT("OLECopy(): Copy from %s failed."),
  687. rgchCopySrcPath));
  688. ReleaseIUnknowns(ulcCopyDestinations,
  689. (PIUnknown *)ppimkCopyDestinations);
  690. }
  691. else
  692. WARNING_OUT((TEXT("OLECopy(): Failed to create copy destination monikers for copy source %s."),
  693. rgchCopySrcPath));
  694. EVAL(! pirecinit->lpVtbl->Release(pirecinit));
  695. }
  696. else
  697. WARNING_OUT((TEXT("OLECopy(): Failed to create ReconcileInitiator for copy source %s."),
  698. rgchCopySrcPath));
  699. }
  700. else
  701. WARNING_OUT((TEXT("OLECopy(): Failed to load copy source %s from storage."),
  702. rgchCopySrcPath));
  703. ReleaseStorageInterface(hstgi);
  704. }
  705. else
  706. WARNING_OUT((TEXT("OLECopy(): Failed to get storage interface for copy source %s."),
  707. rgchCopySrcPath));
  708. }
  709. else
  710. TRACE_OUT((TEXT("OLECopy(): Failed to get reconciliation handler class ID for replica %s."),
  711. rgchCopySrcPath));
  712. }
  713. EndMerge();
  714. return(hr);
  715. }