Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1700 lines
48 KiB

  1. /*++
  2. Module Name:
  3. MmcRep.cpp
  4. Abstract:
  5. This module contains the implementation for CMmcDfsReplica. This is an class
  6. for MMC display related calls for the third level node(the Replica nodes)
  7. --*/
  8. #include "stdafx.h"
  9. #include "DfsGUI.h"
  10. #include "Utils.h" // For the LoadStringFromResource method
  11. #include "MenuEnum.h" // Contains the menu and toolbar command ids
  12. #include "resource.h" // For the Resource ID for strings, etc.
  13. #include "MmcRep.h"
  14. #include "DfsEnums.h"
  15. #include "DfsNodes.h" // For Node GUIDs
  16. #include "MmcRoot.h"
  17. #include "netutils.h"
  18. HRESULT GetReplicationText(
  19. IN BOOL i_bFRSMember,
  20. IN CAlternateReplicaInfo* i_pRepInfo,
  21. OUT BSTR* o_pbstrColumnText,
  22. OUT BSTR* o_pbstrStatusBarText
  23. );
  24. const int CMmcDfsReplica::m_iIMAGE_OFFSET = 20;
  25. //////////////////////////////////////////////////////////////////////////////////////////////////
  26. // Constructor For _DFS_REPLICA_LIST
  27. REP_LIST_NODE :: REP_LIST_NODE (CMmcDfsReplica* i_pMmcReplica)
  28. {
  29. pReplica = i_pMmcReplica;
  30. }
  31. //////////////////////////////////////////////////////////////////////////////////////////////////
  32. // destructor
  33. REP_LIST_NODE :: ~REP_LIST_NODE ()
  34. {
  35. SAFE_RELEASE(pReplica);
  36. }
  37. CMmcDfsReplica::CMmcDfsReplica(
  38. IN IDfsReplica* i_pReplicaObject,
  39. IN CMmcDfsJunctionPoint* i_pJPObject
  40. )
  41. {
  42. dfsDebugOut((_T("CMmcDfsReplica::CMmcDfsReplica this=%p\n"), this));
  43. MMC_DISP_CTOR_RETURN_INVALIDARG_IF_NULL(i_pReplicaObject);
  44. MMC_DISP_CTOR_RETURN_INVALIDARG_IF_NULL(i_pJPObject);
  45. m_pDfsReplicaObject = i_pReplicaObject;
  46. m_pDfsParentJP = i_pJPObject;
  47. m_pDfsParentRoot = NULL;
  48. m_pRepInfo = NULL;
  49. m_bFRSMember = FALSE;
  50. // Get the display name from the IDfsReplica
  51. HRESULT hr = m_pDfsReplicaObject->get_StorageServerName(&m_bstrServerName);
  52. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
  53. hr = m_pDfsReplicaObject->get_StorageShareName(&m_bstrShareName);
  54. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
  55. hr = GetDfsReplicaDisplayName(m_bstrServerName, m_bstrShareName, &m_bstrDisplayName);
  56. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
  57. m_lReplicaState = DFS_REPLICA_STATE_UNASSIGNED;
  58. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
  59. m_CLSIDNodeType = s_guidDfsReplicaNodeType;
  60. }
  61. CMmcDfsReplica::CMmcDfsReplica(
  62. IN IDfsReplica* i_pReplicaObject,
  63. IN CMmcDfsRoot* i_pRootObject
  64. )
  65. {
  66. dfsDebugOut((_T("CMmcDfsReplica::CMmcDfsReplica this=%p\n"), this));
  67. MMC_DISP_CTOR_RETURN_INVALIDARG_IF_NULL(i_pReplicaObject);
  68. MMC_DISP_CTOR_RETURN_INVALIDARG_IF_NULL(i_pRootObject);
  69. m_pDfsReplicaObject = i_pReplicaObject;
  70. m_pDfsParentRoot = i_pRootObject;
  71. m_pDfsParentJP = NULL;
  72. m_pRepInfo = NULL;
  73. m_bFRSMember = FALSE;
  74. // Get the display name from the IDfsReplica
  75. HRESULT hr = m_pDfsReplicaObject->get_StorageServerName(&m_bstrServerName);
  76. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
  77. hr = m_pDfsReplicaObject->get_StorageShareName(&m_bstrShareName);
  78. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
  79. hr = GetDfsReplicaDisplayName(m_bstrServerName, m_bstrShareName, &m_bstrDisplayName);
  80. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
  81. m_lReplicaState = DFS_REPLICA_STATE_UNASSIGNED;
  82. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
  83. m_CLSIDNodeType = s_guidDfsReplicaNodeType;
  84. m_bstrDNodeType = s_tchDfsReplicaNodeType;
  85. }
  86. CMmcDfsReplica::~CMmcDfsReplica(
  87. )
  88. {
  89. if (m_pRepInfo)
  90. delete m_pRepInfo;
  91. dfsDebugOut((_T("CMmcDfsReplica::~CMmcDfsReplica this=%p\n"), this));
  92. }
  93. STDMETHODIMP
  94. CMmcDfsReplica :: AddMenuItems(
  95. IN LPCONTEXTMENUCALLBACK i_lpContextMenuCallback,
  96. IN LPLONG i_lpInsertionAllowed
  97. )
  98. /*++
  99. Routine Description:
  100. This routine adds the context menu for Replica nodes using the ContextMenuCallback
  101. provided.
  102. Arguments:
  103. lpContextMenuCallback - A callback(function pointer) that is used to add the menu items
  104. lpInsertionAllowed - Specifies what menus can be added and where they can be added.
  105. --*/
  106. {
  107. RETURN_INVALIDARG_IF_NULL(i_lpContextMenuCallback);
  108. enum
  109. {
  110. IDM_CONTEXTMENU_COMMAND_MAX = IDM_REPLICA_MAX,
  111. IDM_CONTEXTMENU_COMMAND_MIN = IDM_REPLICA_MIN
  112. };
  113. LONG lInsertionPoints [IDM_CONTEXTMENU_COMMAND_MAX - IDM_CONTEXTMENU_COMMAND_MIN + 1] = {
  114. CCM_INSERTIONPOINTID_PRIMARY_TOP,
  115. CCM_INSERTIONPOINTID_PRIMARY_TOP,
  116. CCM_INSERTIONPOINTID_PRIMARY_TOP,
  117. CCM_INSERTIONPOINTID_PRIMARY_TOP,
  118. CCM_INSERTIONPOINTID_PRIMARY_TOP,
  119. CCM_INSERTIONPOINTID_PRIMARY_TOP
  120. };
  121. BOOL bShowFRS = FALSE;
  122. if (m_pDfsParentRoot)
  123. bShowFRS = m_pDfsParentRoot->get_ShowFRS();
  124. else
  125. bShowFRS = m_pDfsParentJP->get_ShowFRS();
  126. HRESULT hr = S_OK;
  127. for (int iCommandID = IDM_CONTEXTMENU_COMMAND_MIN, iMenuResource = IDS_MENUS_REPLICA_TOP_OPEN;
  128. iCommandID <= IDM_CONTEXTMENU_COMMAND_MAX;
  129. iCommandID++,iMenuResource++)
  130. {
  131. // No TakeOnlineOffline on root replicas
  132. if (m_pDfsParentRoot && IDM_REPLICA_TOP_TAKE_REPLICA_OFFLINE_ONLINE == iCommandID)
  133. continue;
  134. if (!bShowFRS &&
  135. (IDM_REPLICA_TOP_REPLICATE == iCommandID ||
  136. IDM_REPLICA_TOP_STOP_REPLICATION == iCommandID))
  137. {
  138. continue;
  139. }
  140. if (!m_pRepInfo)
  141. GetReplicationInfo();
  142. if (bShowFRS && FRSSHARE_TYPE_OK != m_pRepInfo->m_nFRSShareType &&
  143. (IDM_REPLICA_TOP_REPLICATE == iCommandID ||
  144. IDM_REPLICA_TOP_STOP_REPLICATION == iCommandID))
  145. {
  146. continue;
  147. }
  148. if (m_bFRSMember &&
  149. IDM_REPLICA_TOP_REPLICATE == iCommandID)
  150. {
  151. continue;
  152. }
  153. if (!m_bFRSMember &&
  154. IDM_REPLICA_TOP_STOP_REPLICATION == iCommandID)
  155. {
  156. continue;
  157. }
  158. CComBSTR bstrMenuText;
  159. CComBSTR bstrStatusBarText;
  160. hr = GetMenuResourceStrings(iMenuResource, &bstrMenuText, NULL, &bstrStatusBarText);
  161. RETURN_IF_FAILED(hr);
  162. CONTEXTMENUITEM ContextMenuItem; // The structure which contains menu information
  163. ZeroMemory(&ContextMenuItem, sizeof(ContextMenuItem));
  164. ContextMenuItem.strName = bstrMenuText;
  165. ContextMenuItem.strStatusBarText = bstrStatusBarText;
  166. ContextMenuItem.lInsertionPointID = lInsertionPoints[iCommandID - IDM_CONTEXTMENU_COMMAND_MIN];
  167. ContextMenuItem.lCommandID = iCommandID;
  168. LONG lInsertionFlag = 0;
  169. switch(ContextMenuItem.lInsertionPointID)
  170. {
  171. case CCM_INSERTIONPOINTID_PRIMARY_TOP:
  172. lInsertionFlag = CCM_INSERTIONALLOWED_TOP;
  173. break;
  174. case CCM_INSERTIONPOINTID_PRIMARY_NEW:
  175. lInsertionFlag = CCM_INSERTIONALLOWED_NEW;
  176. break;
  177. case CCM_INSERTIONPOINTID_PRIMARY_TASK:
  178. lInsertionFlag = CCM_INSERTIONALLOWED_TASK;
  179. break;
  180. case CCM_INSERTIONPOINTID_PRIMARY_VIEW:
  181. lInsertionFlag = CCM_INSERTIONALLOWED_VIEW;
  182. break;
  183. default:
  184. break;
  185. }
  186. if (*i_lpInsertionAllowed & lInsertionFlag)
  187. {
  188. hr = i_lpContextMenuCallback->AddItem(&ContextMenuItem);
  189. RETURN_IF_FAILED(hr);
  190. }
  191. } // for
  192. return hr;
  193. }
  194. STDMETHODIMP
  195. CMmcDfsReplica::Command(
  196. IN LONG i_lCommandID
  197. )
  198. /*++
  199. Routine Description:
  200. Action to be taken on a context menu selection or click is takes place.
  201. Arguments:
  202. lCommandID - The Command ID of the menu for which action has to be taken
  203. --*/
  204. {
  205. HRESULT hr = S_OK;
  206. switch (i_lCommandID)
  207. {
  208. case IDM_REPLICA_TOP_OPEN:
  209. hr = OnOpen();
  210. break;
  211. case IDM_REPLICA_TOP_REMOVE_FROM_DFS:
  212. hr = DoDelete();
  213. break;
  214. case IDM_REPLICA_TOP_CHECK_STATUS:
  215. {
  216. CWaitCursor WaitCursor;
  217. hr = OnCheckStatus ();
  218. break;
  219. }
  220. case IDM_REPLICA_TOP_TAKE_REPLICA_OFFLINE_ONLINE:
  221. hr = TakeReplicaOffline();
  222. break;
  223. case IDM_REPLICA_TOP_REPLICATE:
  224. {
  225. hr = m_pDfsReplicaObject->FindTarget();
  226. if (S_OK != hr)
  227. {
  228. //
  229. // the target has been deleted by others, refresh the root/link
  230. //
  231. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_TARGET);
  232. if (m_pDfsParentRoot)
  233. hr = m_pDfsParentRoot->OnRefresh();
  234. else
  235. hr = m_pDfsParentJP->OnRefresh();
  236. } else
  237. {
  238. hr = OnReplicate ();
  239. }
  240. break;
  241. }
  242. case IDM_REPLICA_TOP_STOP_REPLICATION:
  243. {
  244. hr = m_pDfsReplicaObject->FindTarget();
  245. if (S_OK != hr)
  246. {
  247. //
  248. // the target has been deleted by others, refresh the root/link
  249. //
  250. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_TARGET);
  251. if (m_pDfsParentRoot)
  252. hr = m_pDfsParentRoot->OnRefresh();
  253. else
  254. hr = m_pDfsParentJP->OnRefresh();
  255. } else
  256. {
  257. BOOL bRepSetExist = FALSE;
  258. hr = AllowFRSMemberDeletion(&bRepSetExist);
  259. if (bRepSetExist && S_OK == hr)
  260. hr = OnStopReplication(TRUE);
  261. else
  262. {
  263. if (m_pDfsParentRoot)
  264. hr = m_pDfsParentRoot->OnRefresh();
  265. else
  266. hr = m_pDfsParentJP->OnRefresh();
  267. }
  268. }
  269. break;
  270. }
  271. default:
  272. hr = E_INVALIDARG;
  273. break;
  274. }
  275. return hr;
  276. }
  277. STDMETHODIMP
  278. CMmcDfsReplica::SetColumnHeader(
  279. IN LPHEADERCTRL2 i_piHeaderControl
  280. )
  281. {
  282. return S_OK;
  283. }
  284. STDMETHODIMP
  285. CMmcDfsReplica::GetResultDisplayInfo(
  286. IN OUT LPRESULTDATAITEM io_pResultDataItem
  287. )
  288. /*++
  289. Routine Description:
  290. Returns the information required for MMC display for this item.
  291. Arguments:
  292. io_pResultDataItem - The ResultItem which specifies what display information is required
  293. --*/
  294. {
  295. RETURN_INVALIDARG_IF_NULL(io_pResultDataItem);
  296. if (RDI_IMAGE & io_pResultDataItem->mask)
  297. io_pResultDataItem->nImage = CMmcDfsReplica::m_iIMAGE_OFFSET + m_lReplicaState;
  298. if (RDI_STR & io_pResultDataItem->mask)
  299. {
  300. if (0 == io_pResultDataItem->nCol)
  301. io_pResultDataItem->str = m_bstrDisplayName;
  302. if (1 == io_pResultDataItem->nCol)
  303. io_pResultDataItem->str = m_bstrFRSColumnText;
  304. }
  305. return S_OK;
  306. }
  307. STDMETHODIMP
  308. CMmcDfsReplica::SetConsoleVerbs(
  309. IN LPCONSOLEVERB i_lpConsoleVerb
  310. )
  311. /*++
  312. Routine Description:
  313. Routine used to set the console verb settings.
  314. Sets all of them except Open off.
  315. For all scope pane items, default verb is "open'. For result items,
  316. it is "properties"
  317. Arguments:
  318. i_lpConsoleVerb - The callback used to handle console verbs
  319. --*/
  320. {
  321. RETURN_INVALIDARG_IF_NULL(i_lpConsoleVerb);
  322. i_lpConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, TRUE);
  323. i_lpConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, TRUE);
  324. i_lpConsoleVerb->SetVerbState(MMC_VERB_RENAME, HIDDEN, TRUE);
  325. i_lpConsoleVerb->SetVerbState(MMC_VERB_PRINT, HIDDEN, TRUE);
  326. i_lpConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, TRUE);
  327. i_lpConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, TRUE);
  328. i_lpConsoleVerb->SetVerbState(MMC_VERB_OPEN, HIDDEN, TRUE);
  329. i_lpConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, FALSE);
  330. return S_OK;
  331. }
  332. STDMETHODIMP
  333. CMmcDfsReplica::AddItemToResultPane (
  334. IResultData* i_lpResultData
  335. )
  336. /*++
  337. Routine Description:
  338. Adds an item (a replica result pane item) to the result pane.
  339. Arguments:
  340. i_lpResultData - The pointer to the IResultData interface on which InsertItem
  341. will be called.
  342. --*/
  343. {
  344. RESULTDATAITEM ReplicaResultDataItem;
  345. ZeroMemory(&ReplicaResultDataItem, sizeof(ReplicaResultDataItem));
  346. ReplicaResultDataItem.mask = RDI_PARAM | RDI_STR | RDI_IMAGE;
  347. ReplicaResultDataItem.lParam = reinterpret_cast<LPARAM> (this);
  348. ReplicaResultDataItem.str = MMC_CALLBACK;
  349. ReplicaResultDataItem.nImage = CMmcDfsReplica::m_iIMAGE_OFFSET + m_lReplicaState; // set the icon to the default status
  350. // i.e. no known status
  351. HRESULT hr = i_lpResultData -> InsertItem (&ReplicaResultDataItem);
  352. RETURN_IF_FAILED(hr);
  353. m_pResultData = i_lpResultData;
  354. m_hResultItem = ReplicaResultDataItem.itemID;
  355. return hr;
  356. }
  357. STDMETHODIMP
  358. CMmcDfsReplica :: RemoveReplica(
  359. )
  360. /*++
  361. Routine Description:
  362. Handles the removal of a replica from the replica set of a junction point.
  363. --*/
  364. {
  365. CWaitCursor WaitCursor;
  366. HRESULT hr = S_OK;
  367. if (m_pDfsParentRoot)
  368. {
  369. // This means that this is a root level replica.
  370. // The removal of Root level Replica is by tearing
  371. // down Dfs.
  372. //
  373. // delete it from replica set
  374. //
  375. hr = RemoveReplicaFromSet();
  376. RETURN_IF_FAILED(hr);
  377. CWaitCursor Wait;
  378. //
  379. // delete it from Dfs namespace
  380. //
  381. CComBSTR bstrFTDfsName;
  382. if (DFS_TYPE_FTDFS == m_pDfsParentRoot->m_lDfsRootType)
  383. {
  384. hr = m_pDfsParentRoot->m_DfsRoot->get_DfsName(&bstrFTDfsName);
  385. RETURN_IF_FAILED(hr);
  386. }
  387. hr = m_pDfsParentRoot->_DeleteDfsRoot(m_bstrServerName, m_bstrShareName, bstrFTDfsName);
  388. RETURN_IF_FAILED(hr);
  389. }
  390. else
  391. {
  392. //
  393. // delete it from replica set
  394. //
  395. hr = RemoveReplicaFromSet();
  396. RETURN_IF_FAILED(hr);
  397. CWaitCursor Wait;
  398. //
  399. // delete it from Dfs namespace
  400. //
  401. hr = m_pDfsParentJP->m_pDfsJPObject->RemoveReplica(m_bstrServerName, m_bstrShareName);
  402. RETURN_IF_FAILED(hr);
  403. }
  404. // Remove item from list and Re-display List.
  405. if (m_pDfsParentRoot)
  406. hr = m_pDfsParentRoot->RemoveResultPaneItem(this);
  407. else
  408. hr = m_pDfsParentJP->RemoveResultPaneItem(this);
  409. return hr;
  410. }
  411. //
  412. // Call the corresponding root/link's RemoveReplica() method to:
  413. // 1. refresh the root/link node to pick up possible namespace updates by others,
  414. // 2. then locate the appropriate target to actually perform the removal operation.
  415. //
  416. STDMETHODIMP
  417. CMmcDfsReplica::OnRemoveReplica(
  418. )
  419. {
  420. HRESULT hr = S_OK;
  421. if (m_pDfsParentRoot)
  422. hr = m_pDfsParentRoot->RemoveReplica(m_bstrDisplayName);
  423. else
  424. hr = m_pDfsParentJP->RemoveReplica(m_bstrDisplayName);
  425. return hr;
  426. }
  427. STDMETHODIMP
  428. CMmcDfsReplica :: ConfirmOperationOnDfsTarget(int idString)
  429. /*++
  430. Routine Description:
  431. Asks the user for confirmation of whether he really wants to remove the particular
  432. replica from the replica set.
  433. --*/
  434. {
  435. CComBSTR bstrAppName;
  436. HRESULT hr = LoadStringFromResource (IDS_APPLICATION_NAME, &bstrAppName);
  437. RETURN_IF_FAILED(hr);
  438. CComBSTR bstrFormattedMessage;
  439. hr = FormatResourceString (idString, m_bstrDisplayName, &bstrFormattedMessage);
  440. RETURN_IF_FAILED(hr);
  441. CThemeContextActivator activator;
  442. if (IDNO == ::MessageBox(::GetActiveWindow(), bstrFormattedMessage, bstrAppName, MB_YESNO | MB_ICONEXCLAMATION | MB_APPLMODAL))
  443. return S_FALSE;
  444. return S_OK;
  445. }
  446. STDMETHODIMP
  447. CMmcDfsReplica::DoDelete(
  448. )
  449. /*++
  450. Routine Description:
  451. This method allows the item to delete itself.
  452. Called when DEL key is pressed or when the "Delete" context menu
  453. item is selected.
  454. --*/
  455. {
  456. HRESULT hr = S_OK;
  457. if (NULL != m_pDfsParentRoot)
  458. hr = m_pDfsParentRoot->ClosePropertySheet(FALSE);
  459. else
  460. hr = m_pDfsParentJP->ClosePropertySheet(FALSE);
  461. if (S_OK != hr)
  462. return hr; // if property page found, discontinue
  463. hr = ConfirmOperationOnDfsTarget(NULL != m_pDfsParentRoot ? IDS_MSG_REMOVE_ROOT_REPLICA : IDS_MSG_REMOVE_REPLICA);
  464. if(S_OK != hr) // User decided to abort the operation
  465. return S_OK;
  466. CWaitCursor wait;
  467. BOOL bRepSetExist = FALSE;
  468. hr = AllowFRSMemberDeletion(&bRepSetExist);
  469. if (bRepSetExist && S_OK != hr) // not allowed on a hub or user cancelled the operation
  470. return S_OK;
  471. hr = OnRemoveReplica();
  472. if(FAILED(hr) && !m_pDfsParentRoot) // For Root level replica
  473. // Error message is already displayed.
  474. {
  475. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_MSG_WIZ_DELETE_REPLICA_FAILURE);
  476. }
  477. return hr;
  478. }
  479. HRESULT CMmcDfsReplica::OnReplicate()
  480. {
  481. CWaitCursor wait;
  482. HRESULT hr = S_OK;
  483. CComPtr<IReplicaSet> piReplicaSet;
  484. if (m_pDfsParentRoot)
  485. hr = m_pDfsParentRoot->GetIReplicaSetPtr(&piReplicaSet);
  486. else
  487. hr = m_pDfsParentJP->GetIReplicaSetPtr(&piReplicaSet);
  488. if (FAILED(hr))
  489. {
  490. DisplayMessageBoxForHR(hr);
  491. return hr;
  492. } else if (S_OK != hr) // no replica set on the corresponding link/root
  493. return hr;
  494. // refresh m_pRepInfo
  495. GetReplicationInfo();
  496. m_bFRSMember = FALSE;
  497. if (FRSSHARE_TYPE_OK != m_pRepInfo->m_nFRSShareType)
  498. {
  499. GetReplicationText(m_bFRSMember, m_pRepInfo, &m_bstrFRSColumnText, &m_bstrStatusText);
  500. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0,
  501. IDS_MSG_ADDFRSMEMBER_FAILED_EX, m_pRepInfo->m_bstrDisplayName, m_bstrStatusText);
  502. } else
  503. {
  504. (void) CreateAndHideStagingPath(m_pRepInfo->m_bstrDnsHostName, m_pRepInfo->m_bstrStagingPath);
  505. hr = ConfigAndStartNtfrs(m_pRepInfo->m_bstrDnsHostName);
  506. if (SUCCEEDED(hr) || IDYES == DisplayMessageBox(
  507. ::GetActiveWindow(),
  508. MB_YESNO,
  509. hr,
  510. IDS_MSG_FRS_BADSERVICE,
  511. m_pRepInfo->m_bstrDisplayName,
  512. m_pRepInfo->m_bstrDnsHostName))
  513. {
  514. hr = AddFRSMember(piReplicaSet, m_pRepInfo->m_bstrDnsHostName, m_pRepInfo->m_bstrRootPath, m_pRepInfo->m_bstrStagingPath);
  515. if (S_OK == hr)
  516. m_bFRSMember = TRUE;
  517. else if (S_FALSE == hr)
  518. {
  519. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_MSG_TARGETS_ONSAMECOMPUTER_1, m_pRepInfo->m_bstrDnsHostName);
  520. }
  521. GetReplicationText(m_bFRSMember, m_pRepInfo, &m_bstrFRSColumnText, &m_bstrStatusText);
  522. }
  523. }
  524. _UpdateThisItem();
  525. return hr;
  526. }
  527. HRESULT CMmcDfsReplica::OnStopReplication(BOOL bConfirm /* = FALSE */)
  528. {
  529. HRESULT hr = S_OK;
  530. if (bConfirm)
  531. {
  532. hr = ConfirmOperationOnDfsTarget(IDS_MSG_STOP_REPLICATION_TARGET);
  533. if (S_OK != hr)
  534. return hr;
  535. }
  536. CWaitCursor wait;
  537. CComPtr<IReplicaSet> piReplicaSet;
  538. if (m_pDfsParentRoot)
  539. hr = m_pDfsParentRoot->GetIReplicaSetPtr(&piReplicaSet);
  540. else
  541. hr = m_pDfsParentJP->GetIReplicaSetPtr(&piReplicaSet);
  542. if (S_OK != hr) // no replica set on the corresponding link/root
  543. hr = S_OK;
  544. else
  545. {
  546. if (!m_pRepInfo)
  547. GetReplicationInfoEx(&m_pRepInfo);
  548. if (!m_pRepInfo->m_bstrDnsHostName || !m_pRepInfo->m_bstrRootPath)
  549. {
  550. hr = DeleteBadFRSMember(piReplicaSet, m_pRepInfo->m_bstrDisplayName, m_pRepInfo->m_hrFRS);
  551. if (S_FALSE == hr) // operation cancelled
  552. return hr;
  553. } else
  554. {
  555. hr = DeleteFRSMember(piReplicaSet, m_pRepInfo->m_bstrDnsHostName, m_pRepInfo->m_bstrRootPath);
  556. }
  557. }
  558. if (SUCCEEDED(hr))
  559. {
  560. m_bFRSMember = FALSE;
  561. m_bstrFRSColumnText.Empty();
  562. m_bstrStatusText.Empty();
  563. LoadStringFromResource(IDS_REPLICATION_STATUS_DISABLED, &m_bstrFRSColumnText);
  564. LoadStringFromResource(IDS_REPLICATION_STATUSBAR_NONMEMBER, &m_bstrStatusText);
  565. _UpdateThisItem();
  566. }
  567. return hr;
  568. }
  569. STDMETHODIMP
  570. CMmcDfsReplica::OnCheckStatus(
  571. )
  572. /*++
  573. Routine Description:
  574. This method checks the state of the replica.
  575. --*/
  576. {
  577. CWaitCursor WaitCursor; // Display the wait cursor
  578. HRESULT hr = m_pDfsReplicaObject->get_State(&m_lReplicaState);
  579. if (S_OK == hr)
  580. {
  581. _UpdateThisItem();
  582. } else if (S_FALSE == hr)
  583. {
  584. //
  585. // this target has been deleted by other means, refresh the root/link,
  586. //
  587. m_lReplicaState = DFS_REPLICA_STATE_UNASSIGNED;
  588. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_TARGET);
  589. if (m_pDfsParentRoot)
  590. hr = m_pDfsParentRoot->OnRefresh();
  591. else
  592. hr = m_pDfsParentJP->OnRefresh();
  593. }
  594. return hr;
  595. }
  596. void CMmcDfsReplica::_UpdateThisItem()
  597. {
  598. if (m_pDfsParentRoot)
  599. {
  600. m_pDfsParentRoot->m_lpConsole->UpdateAllViews(
  601. (IDataObject*)m_pDfsParentRoot, // Parent object
  602. (LPARAM)((CMmcDisplay *)this),
  603. 1);
  604. }
  605. else
  606. {
  607. m_pDfsParentJP->m_pDfsParentRoot->m_lpConsole->UpdateAllViews(
  608. (IDataObject*)m_pDfsParentJP, // Parent object
  609. (LPARAM)((CMmcDisplay *)this),
  610. 1);
  611. }
  612. }
  613. HRESULT
  614. CMmcDfsReplica::ToolbarSelect(
  615. IN const LONG i_lArg,
  616. IN IToolbar* i_pToolBar
  617. )
  618. /*++
  619. Routine Description:
  620. Handle a select event for a toolbar
  621. Create a toolbar, it it doesn't exist.
  622. Attach the toolbar and enable the buttons, if the event for a selection.
  623. Disable the buttons, if the event was for a deselection
  624. Arguments:
  625. i_lArg - The argument passed to the actual method.
  626. o_pToolBar - The Toolbar pointer.
  627. the class exposed to MMC.
  628. --*/
  629. {
  630. RETURN_INVALIDARG_IF_NULL(i_pToolBar);
  631. BOOL bSelect = (BOOL) HIWORD(i_lArg);
  632. EnableToolbarButtons(i_pToolBar, IDT_REPLICA_MIN, IDT_REPLICA_MAX, bSelect);
  633. if (bSelect)
  634. {
  635. // No TakeOnlineOffline on root replicas
  636. if (m_pDfsParentRoot)
  637. {
  638. i_pToolBar->SetButtonState(IDT_REPLICA_TAKE_REPLICA_OFFLINE_ONLINE, ENABLED, FALSE);
  639. i_pToolBar->SetButtonState(IDT_REPLICA_TAKE_REPLICA_OFFLINE_ONLINE, HIDDEN, TRUE);
  640. }
  641. BOOL bShowFRS = FALSE;
  642. if (m_pDfsParentRoot)
  643. bShowFRS = m_pDfsParentRoot->get_ShowFRS();
  644. else
  645. bShowFRS = m_pDfsParentJP->get_ShowFRS();
  646. if (!m_pRepInfo)
  647. GetReplicationInfo();
  648. if (!bShowFRS ||
  649. FRSSHARE_TYPE_OK != m_pRepInfo->m_nFRSShareType)
  650. {
  651. i_pToolBar->SetButtonState(IDT_REPLICA_REPLICATE, ENABLED, FALSE);
  652. i_pToolBar->SetButtonState(IDT_REPLICA_REPLICATE, HIDDEN, TRUE);
  653. i_pToolBar->SetButtonState(IDT_REPLICA_STOP_REPLICATION, ENABLED, FALSE);
  654. i_pToolBar->SetButtonState(IDT_REPLICA_STOP_REPLICATION, HIDDEN, TRUE);
  655. } else if (m_bFRSMember)
  656. {
  657. i_pToolBar->SetButtonState(IDT_REPLICA_REPLICATE, ENABLED, FALSE);
  658. i_pToolBar->SetButtonState(IDT_REPLICA_REPLICATE, HIDDEN, TRUE);
  659. } else
  660. {
  661. i_pToolBar->SetButtonState(IDT_REPLICA_STOP_REPLICATION, ENABLED, FALSE);
  662. i_pToolBar->SetButtonState(IDT_REPLICA_STOP_REPLICATION, HIDDEN, TRUE);
  663. }
  664. }
  665. return S_OK;
  666. }
  667. HRESULT
  668. CMmcDfsReplica::CreateToolbar(
  669. IN const LPCONTROLBAR i_pControlbar,
  670. IN const LPEXTENDCONTROLBAR i_lExtendControlbar,
  671. OUT IToolbar** o_pToolBar
  672. )
  673. /*++
  674. Routine Description:
  675. Create the toolbar.
  676. Involves the actual toolbar creation call, creating the bitmap and adding it
  677. and finally adding the buttons to the toolbar
  678. Arguments:
  679. i_pControlbar - The controlbar used to create toolbar.
  680. i_lExtendControlbar - The object implementing IExtendControlbar. This is
  681. the class exposed to MMC.
  682. --*/
  683. {
  684. RETURN_INVALIDARG_IF_NULL(i_pControlbar);
  685. RETURN_INVALIDARG_IF_NULL(i_lExtendControlbar);
  686. RETURN_INVALIDARG_IF_NULL(o_pToolBar);
  687. // Create the toolbar
  688. HRESULT hr = i_pControlbar->Create(TOOLBAR, i_lExtendControlbar, reinterpret_cast<LPUNKNOWN*>(o_pToolBar));
  689. RETURN_IF_FAILED(hr);
  690. // Add the bitmap to the toolbar
  691. hr = AddBitmapToToolbar(*o_pToolBar, IDB_REPLICA_TOOLBAR);
  692. RETURN_IF_FAILED(hr);
  693. int iButtonPosition = 0; // The first button position
  694. for (int iCommandID = IDT_REPLICA_MIN, iMenuResource = IDS_MENUS_REPLICA_TOP_OPEN;
  695. iCommandID <= IDT_REPLICA_MAX;
  696. iCommandID++,iMenuResource++,iButtonPosition++)
  697. {
  698. CComBSTR bstrMenuText;
  699. CComBSTR bstrToolTipText;
  700. hr = GetMenuResourceStrings(iMenuResource, &bstrMenuText, &bstrToolTipText, NULL);
  701. RETURN_IF_FAILED(hr);
  702. MMCBUTTON ToolbarButton;
  703. ZeroMemory(&ToolbarButton, sizeof ToolbarButton);
  704. ToolbarButton.nBitmap = iButtonPosition;
  705. ToolbarButton.idCommand = iCommandID;
  706. ToolbarButton.fsState = TBSTATE_ENABLED;
  707. ToolbarButton.fsType = TBSTYLE_BUTTON;
  708. ToolbarButton.lpButtonText = bstrMenuText;
  709. ToolbarButton.lpTooltipText = bstrToolTipText;
  710. // Add the button to the toolbar
  711. hr = (*o_pToolBar)->InsertButton(iButtonPosition, &ToolbarButton);
  712. RETURN_IF_FAILED(hr);
  713. }
  714. return hr;
  715. }
  716. STDMETHODIMP
  717. CMmcDfsReplica::ToolbarClick(
  718. IN const LPCONTROLBAR i_pControlbar,
  719. IN const LPARAM i_lParam
  720. )
  721. /*++
  722. Routine Description:
  723. Action to take on a click on a toolbar
  724. Arguments:
  725. i_pControlbar - The controlbar used to create toolbar.
  726. i_lParam - The lparam to the actual notify. This is the command id of
  727. the button on which a click occurred.
  728. --*/
  729. {
  730. RETURN_INVALIDARG_IF_NULL(i_pControlbar);
  731. HRESULT hr = S_OK;
  732. switch(i_lParam) // What button did the user click on.
  733. {
  734. case IDT_REPLICA_REMOVE_FROM_DFS:
  735. hr = DoDelete();
  736. break;
  737. case IDT_REPLICA_TAKE_REPLICA_OFFLINE_ONLINE:
  738. hr = TakeReplicaOffline();
  739. break;
  740. case IDT_REPLICA_CHECK_STATUS:
  741. {
  742. CWaitCursor WaitCursor;
  743. hr = OnCheckStatus ();
  744. break;
  745. }
  746. case IDT_REPLICA_REPLICATE:
  747. {
  748. hr = m_pDfsReplicaObject->FindTarget();
  749. if (S_OK != hr)
  750. {
  751. //
  752. // the target has been deleted by others, refresh the root/link
  753. //
  754. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_TARGET);
  755. if (m_pDfsParentRoot)
  756. hr = m_pDfsParentRoot->OnRefresh();
  757. else
  758. hr = m_pDfsParentJP->OnRefresh();
  759. } else
  760. {
  761. hr = OnReplicate();
  762. }
  763. break;
  764. }
  765. case IDT_REPLICA_STOP_REPLICATION:
  766. {
  767. hr = m_pDfsReplicaObject->FindTarget();
  768. if (S_OK != hr)
  769. {
  770. //
  771. // the target has been deleted by others, refresh the root/link
  772. //
  773. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_TARGET);
  774. if (m_pDfsParentRoot)
  775. hr = m_pDfsParentRoot->OnRefresh();
  776. else
  777. hr = m_pDfsParentJP->OnRefresh();
  778. } else
  779. {
  780. BOOL bRepSetExist = FALSE;
  781. hr = AllowFRSMemberDeletion(&bRepSetExist);
  782. if (bRepSetExist && S_OK == hr)
  783. hr = OnStopReplication(TRUE);
  784. else
  785. {
  786. if (m_pDfsParentRoot)
  787. hr = m_pDfsParentRoot->OnRefresh();
  788. else
  789. hr = m_pDfsParentJP->OnRefresh();
  790. }
  791. }
  792. break;
  793. }
  794. case IDT_REPLICA_OPEN:
  795. hr = OnOpen();
  796. break;
  797. default:
  798. break;
  799. };
  800. return hr;
  801. }
  802. HRESULT
  803. CMmcDfsReplica::OnOpen(
  804. )
  805. /*++
  806. Routine Description:
  807. Open the display path for this replica
  808. --*/
  809. {
  810. CWaitCursor WaitCursor; // Display the wait cursor
  811. if (-1 == GetFileAttributes(m_bstrDisplayName) || // bug#96670
  812. 32 >= (INT_PTR) ShellExecute(
  813. NULL, // Handle to window
  814. _T("explore"), // Action to take
  815. m_bstrDisplayName, // Folder to explore
  816. NULL, // Parameters
  817. NULL, // Default directory
  818. SW_SHOWNORMAL // Show command
  819. ))
  820. {
  821. DisplayMessageBoxWithOK(IDS_MSG_EXPLORE_FAILURE, m_bstrDisplayName);
  822. return(S_FALSE);
  823. }
  824. return S_OK;
  825. }
  826. STDMETHODIMP
  827. CMmcDfsReplica::TakeReplicaOffline(
  828. )
  829. {
  830. /*++
  831. Routine Description:
  832. Take replica offline by calling put_State method of replica.
  833. --*/
  834. CWaitCursor WaitCursor; // Display the wait cursor
  835. HRESULT hr = m_pDfsReplicaObject->get_State(&m_lReplicaState);
  836. if (S_OK == hr)
  837. {
  838. long newVal = 0;
  839. switch (m_lReplicaState)
  840. {
  841. case DFS_REPLICA_STATE_ONLINE:
  842. newVal = DFS_REPLICA_STATE_OFFLINE;
  843. hr = m_pDfsReplicaObject->put_State(newVal);
  844. if (SUCCEEDED(hr))
  845. m_lReplicaState = newVal;
  846. break;
  847. case DFS_REPLICA_STATE_OFFLINE:
  848. newVal = DFS_REPLICA_STATE_ONLINE;
  849. hr = m_pDfsReplicaObject->put_State(newVal);
  850. if (SUCCEEDED(hr))
  851. m_lReplicaState = newVal;
  852. break;
  853. default:
  854. break;
  855. }
  856. }
  857. if (S_OK == hr)
  858. {
  859. _UpdateThisItem();
  860. } else if (S_FALSE == hr)
  861. {
  862. //
  863. // this target has been deleted by other means, refresh the root/link,
  864. //
  865. m_lReplicaState = DFS_REPLICA_STATE_UNASSIGNED;
  866. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_TARGET);
  867. if (m_pDfsParentRoot)
  868. hr = m_pDfsParentRoot->OnRefresh();
  869. else
  870. hr = m_pDfsParentJP->OnRefresh();
  871. } else
  872. {
  873. DisplayMessageBoxForHR(hr);
  874. }
  875. return hr;
  876. }
  877. STDMETHODIMP CMmcDfsReplica::ViewChange(
  878. IResultData* i_pResultData,
  879. LONG_PTR i_lHint
  880. )
  881. /*++
  882. Routine Description:
  883. This method handles the MMCN_VIEW_CHANGE notification.
  884. This updates the icon for the replica item as this is called
  885. when the state changes.
  886. i_lHint is ignored here.
  887. --*/
  888. {
  889. RETURN_INVALIDARG_IF_NULL(i_pResultData);
  890. HRESULT hr = S_OK;
  891. if (i_pResultData != NULL)
  892. {
  893. RESULTDATAITEM ResultDataItem;
  894. ZeroMemory(&ResultDataItem, sizeof(ResultDataItem));
  895. hr = i_pResultData->FindItemByLParam((LPARAM)(this), &(ResultDataItem.itemID));
  896. RETURN_IF_FAILED(hr);
  897. ResultDataItem.mask |= RDI_IMAGE;
  898. ResultDataItem.nCol = 0;
  899. ResultDataItem.nImage = CMmcDfsReplica::m_iIMAGE_OFFSET + m_lReplicaState;
  900. hr = i_pResultData->SetItem(&ResultDataItem);
  901. RETURN_IF_FAILED (hr);
  902. }
  903. return hr;
  904. }
  905. //
  906. // Set m_ReplicationState and m_hrFRS appropriately
  907. //
  908. // Return:
  909. // "No" if this alternate is not a Frs member
  910. // "N/A: <reason>" if this alternate is not eligible to join frs
  911. // hr: if we cannot get info on this alternate
  912. void CAlternateReplicaInfo::Reset()
  913. {
  914. m_bstrDisplayName.Empty();
  915. m_bstrDnsHostName.Empty();
  916. m_bstrRootPath.Empty();
  917. m_bstrStagingPath.Empty();
  918. m_nFRSShareType = FRSSHARE_TYPE_OK;
  919. m_hrFRS = S_OK;
  920. m_dwServiceStartType = SERVICE_AUTO_START;
  921. m_dwServiceState = SERVICE_RUNNING;
  922. }
  923. HRESULT PathOverlapped(LPCTSTR pszPath1, LPCTSTR pszPath2)
  924. {
  925. if (!pszPath1 || !*pszPath1 || !pszPath2 || !*pszPath2)
  926. return E_INVALIDARG;
  927. BOOL bOverlapped = FALSE;
  928. int len1 = lstrlen(pszPath1);
  929. int len2 = lstrlen(pszPath2);
  930. int minLen = min(len1, len2);
  931. if (len1 == len2)
  932. {
  933. if (!lstrcmpi(pszPath1, pszPath2))
  934. bOverlapped = TRUE;
  935. } else
  936. {
  937. LPCTSTR pszLongerOne = ((len1 < len2) ? pszPath2 : pszPath1);
  938. CComBSTR bstrShorterOne = ((len1 < len2) ? pszPath1 : pszPath2);
  939. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrShorterOne);
  940. BOOL bEndingSlash = (_T('\\') == *(bstrShorterOne + minLen - 1));
  941. if (!bEndingSlash)
  942. {
  943. bstrShorterOne += _T("\\");
  944. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrShorterOne);
  945. minLen++;
  946. }
  947. if (!mylstrncmpi(pszLongerOne, (BSTR)bstrShorterOne, minLen))
  948. bOverlapped = TRUE;
  949. }
  950. return bOverlapped ? S_OK : S_FALSE;
  951. }
  952. HRESULT CMmcDfsReplica::GetReplicationInfoEx(CAlternateReplicaInfo** o_ppInfo)
  953. {
  954. RETURN_INVALIDARG_IF_NULL(o_ppInfo);
  955. CAlternateReplicaInfo* pInfo = new CAlternateReplicaInfo;
  956. RETURN_OUTOFMEMORY_IF_NULL(pInfo);
  957. pInfo->m_bstrDisplayName = m_bstrDisplayName;
  958. if (!pInfo->m_bstrDisplayName)
  959. {
  960. delete pInfo;
  961. return E_OUTOFMEMORY;
  962. }
  963. HRESULT hr = S_OK;
  964. do {
  965. //
  966. // validate connectivity
  967. //
  968. if (-1 == GetFileAttributes(pInfo->m_bstrDisplayName))
  969. {
  970. hr = HRESULT_FROM_WIN32(GetLastError());
  971. break;
  972. }
  973. //
  974. // exclude non-Lanman share resources, e.g., webdav
  975. //
  976. hr = CheckResourceProvider(pInfo->m_bstrDisplayName);
  977. if (S_OK != hr)
  978. {
  979. pInfo->m_nFRSShareType = FRSSHARE_TYPE_NOTSMBDISK;
  980. hr = S_OK;
  981. break;
  982. }
  983. //
  984. // retrieve DnsHostName
  985. //
  986. CComBSTR bstrComputerGuid;
  987. SUBSCRIBERLIST FRSRootList;
  988. hr= GetServerInfo(
  989. m_bstrServerName,
  990. NULL, // Domain,
  991. NULL, // NetbiosServerName,
  992. NULL, // bValidComputerObject,
  993. &(pInfo->m_bstrDnsHostName),
  994. &bstrComputerGuid,
  995. NULL, // FQDN
  996. &FRSRootList);
  997. BREAK_IF_FAILED(hr);
  998. if (S_FALSE == hr)
  999. {
  1000. pInfo->m_nFRSShareType = FRSSHARE_TYPE_NODOMAIN;
  1001. break;
  1002. }
  1003. //
  1004. // retrieve RootPath
  1005. //
  1006. hr = GetFolderInfo(
  1007. m_bstrServerName,
  1008. m_bstrShareName,
  1009. &(pInfo->m_bstrRootPath));
  1010. BREAK_IF_FAILED(hr);
  1011. //
  1012. // calculate memberDN for this target
  1013. //
  1014. CComBSTR bstrReplicaSetDN;
  1015. if (m_pDfsParentRoot)
  1016. hr = m_pDfsParentRoot->m_DfsRoot->get_ReplicaSetDN(&bstrReplicaSetDN);
  1017. else
  1018. hr = m_pDfsParentJP->m_pDfsJPObject->get_ReplicaSetDN(&bstrReplicaSetDN);
  1019. BREAK_IF_FAILED(hr);
  1020. CComBSTR bstrDomainDN;
  1021. if (m_pDfsParentRoot)
  1022. hr = m_pDfsParentRoot->m_DfsRoot->get_DomainDN(&bstrDomainDN);
  1023. else
  1024. hr = m_pDfsParentJP->m_pDfsParentRoot->m_DfsRoot->get_DomainDN(&bstrDomainDN);
  1025. BREAK_IF_FAILED(hr);
  1026. CComBSTR bstrMemberDN = _T("CN=");
  1027. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  1028. bstrMemberDN += bstrComputerGuid;
  1029. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  1030. bstrMemberDN += _T(",");
  1031. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  1032. bstrMemberDN += bstrReplicaSetDN;
  1033. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  1034. bstrMemberDN += _T(",");
  1035. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  1036. bstrMemberDN += bstrDomainDN;
  1037. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  1038. //
  1039. // Detect if the current folder overlaps with an existing replicated folder that
  1040. // is not in the same replica set
  1041. //
  1042. for (SUBSCRIBERLIST::iterator i = FRSRootList.begin(); i != FRSRootList.end(); i++)
  1043. {
  1044. if (!lstrcmpi((*i)->bstrMemberDN, bstrMemberDN))
  1045. continue;
  1046. if (S_OK == PathOverlapped(pInfo->m_bstrRootPath, (*i)->bstrRootPath))
  1047. {
  1048. // overlapping detected
  1049. pInfo->m_nFRSShareType = FRSSHARE_TYPE_OVERLAPPING;
  1050. break;
  1051. }
  1052. }
  1053. FreeSubscriberList(&FRSRootList);
  1054. if (FRSSHARE_TYPE_OK != pInfo->m_nFRSShareType)
  1055. break;
  1056. //
  1057. // check if share is on non NTFS5.0 volume
  1058. //
  1059. hr = FRSShareCheck(
  1060. m_bstrServerName,
  1061. m_bstrShareName,
  1062. &(pInfo->m_nFRSShareType));
  1063. BREAK_IF_FAILED(hr);
  1064. if (FRSSHARE_TYPE_OK != pInfo->m_nFRSShareType)
  1065. break;
  1066. //
  1067. // retrieve StagingPath
  1068. //
  1069. TCHAR lpszDrive[2];
  1070. lpszDrive[0] = GetDiskForStagingPath(m_bstrServerName, *(pInfo->m_bstrRootPath));
  1071. lpszDrive[1] = NULL;
  1072. pInfo->m_bstrStagingPath = lpszDrive;
  1073. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pInfo->m_bstrStagingPath, &hr);
  1074. pInfo->m_bstrStagingPath += _T(":\\");
  1075. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pInfo->m_bstrStagingPath, &hr);
  1076. pInfo->m_bstrStagingPath += FRS_STAGE_PATH;
  1077. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pInfo->m_bstrStagingPath, &hr);
  1078. //
  1079. // ntfrs won't work if bstrSharePath points at the root directory of a volume
  1080. // and no other volumes on this computer are suitable to store temporary file
  1081. //
  1082. if (_tcslen(pInfo->m_bstrRootPath) == 3 &&
  1083. _toupper(*(pInfo->m_bstrRootPath)) == _toupper(*lpszDrive))
  1084. {
  1085. pInfo->m_nFRSShareType = FRSSHARE_TYPE_CONFLICTSTAGING;
  1086. }
  1087. } while (0);
  1088. if (FAILED(hr))
  1089. pInfo->m_nFRSShareType = FRSSHARE_TYPE_UNKNOWN;
  1090. pInfo->m_hrFRS = hr;
  1091. *o_ppInfo = pInfo;
  1092. return S_OK;
  1093. }
  1094. HRESULT CMmcDfsReplica::GetReplicationInfo()
  1095. {
  1096. if (m_pRepInfo)
  1097. delete m_pRepInfo;
  1098. return GetReplicationInfoEx(&m_pRepInfo);
  1099. }
  1100. HRESULT CMmcDfsReplica::ShowReplicationInfo(IReplicaSet* i_piReplicaSet)
  1101. {
  1102. HRESULT hr = S_OK;
  1103. m_bFRSMember = FALSE;
  1104. m_bstrStatusText.Empty();
  1105. m_bstrFRSColumnText.Empty();
  1106. if (i_piReplicaSet) // show FRS
  1107. {
  1108. hr = GetReplicationInfo(); // refresh m_pRepInfo
  1109. RETURN_IF_FAILED(hr);
  1110. if (FRSSHARE_TYPE_OK == m_pRepInfo->m_nFRSShareType)
  1111. {
  1112. hr = i_piReplicaSet->IsFRSMember(m_pRepInfo->m_bstrDnsHostName, m_pRepInfo->m_bstrRootPath);
  1113. m_bFRSMember = (S_OK == hr); // it is set to TRUE only when "Show Replication Info" and is a FRS member
  1114. }
  1115. GetReplicationText(m_bFRSMember, m_pRepInfo, &m_bstrFRSColumnText, &m_bstrStatusText);
  1116. }
  1117. return S_OK;
  1118. }
  1119. HRESULT CMmcDfsReplica::GetBadMemberInfo(
  1120. IN IReplicaSet* i_piReplicaSet,
  1121. IN BSTR i_bstrServerName,
  1122. OUT BSTR* o_pbstrDnsHostName,
  1123. OUT BSTR* o_pbstrRootPath
  1124. )
  1125. {
  1126. RETURN_INVALIDARG_IF_NULL(i_bstrServerName);
  1127. RETURN_INVALIDARG_IF_NULL(o_pbstrDnsHostName);
  1128. RETURN_INVALIDARG_IF_NULL(o_pbstrRootPath);
  1129. VARIANT var;
  1130. VariantInit(&var);
  1131. HRESULT hr = i_piReplicaSet->GetBadMemberInfo(i_bstrServerName, &var);
  1132. if (S_OK != hr)
  1133. return hr;
  1134. if (V_VT(&var) != (VT_ARRAY | VT_VARIANT))
  1135. return E_INVALIDARG;
  1136. SAFEARRAY *psa = V_ARRAY(&var);
  1137. if (!psa) // no such member at all
  1138. return S_FALSE;
  1139. long lLowerBound = 0;
  1140. long lUpperBound = 0;
  1141. long lCount = 0;
  1142. SafeArrayGetLBound(psa, 1, &lLowerBound);
  1143. SafeArrayGetUBound(psa, 1, &lUpperBound);
  1144. lCount = lUpperBound - lLowerBound + 1;
  1145. VARIANT HUGEP *pArray;
  1146. SafeArrayAccessData(psa, (void HUGEP **) &pArray);
  1147. *o_pbstrDnsHostName = SysAllocString(pArray[4].bstrVal);
  1148. *o_pbstrRootPath = SysAllocString(pArray[3].bstrVal);
  1149. SafeArrayUnaccessData(psa);
  1150. VariantClear(&var); // it will in turn call SafeArrayDestroy(psa);
  1151. RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrDnsHostName);
  1152. RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrRootPath);
  1153. return hr;
  1154. }
  1155. HRESULT CMmcDfsReplica::DeleteBadFRSMember(IReplicaSet* i_piReplicaSet, IN BSTR i_bstrDisplayName, IN HRESULT i_hres)
  1156. {
  1157. RETURN_INVALIDARG_IF_NULL((IReplicaSet *)i_piReplicaSet);
  1158. CComBSTR bstrServerName;
  1159. HRESULT hr = GetUNCPathComponent(i_bstrDisplayName, &bstrServerName, 2, 3);
  1160. long lNumOfMembers = 0;
  1161. hr = i_piReplicaSet->get_NumOfMembers(&lNumOfMembers);
  1162. RETURN_IF_FAILED(hr);
  1163. CComBSTR bstrDnsHostName;
  1164. CComBSTR bstrRootPath;
  1165. hr = GetBadMemberInfo(i_piReplicaSet, bstrServerName, &bstrDnsHostName, &bstrRootPath);
  1166. if (S_OK != hr)
  1167. return S_OK; // no such bad member, continue with other operations
  1168. int nRet = DisplayMessageBox(::GetActiveWindow(),
  1169. MB_YESNOCANCEL,
  1170. i_hres,
  1171. IDS_MSG_ERROR_BADFRSMEMBERDELETION,
  1172. i_bstrDisplayName,
  1173. bstrRootPath,
  1174. bstrDnsHostName);
  1175. if (IDNO == nRet)
  1176. return S_OK; // return immediately, continue with other operations
  1177. else if (IDCANCEL == nRet)
  1178. return S_FALSE; // do not proceed
  1179. CWaitCursor wait;
  1180. if (lNumOfMembers <= 2)
  1181. {
  1182. if (m_pDfsParentRoot)
  1183. hr = m_pDfsParentRoot->OnStopReplication();
  1184. else
  1185. hr = m_pDfsParentJP->OnStopReplication();
  1186. } else
  1187. hr = i_piReplicaSet->RemoveMemberEx(bstrDnsHostName, bstrRootPath);
  1188. return hr;
  1189. }
  1190. HRESULT CMmcDfsReplica::AddFRSMember(
  1191. IN IReplicaSet* i_piReplicaSet,
  1192. IN BSTR i_bstrDnsHostName,
  1193. IN BSTR i_bstrRootPath,
  1194. IN BSTR i_bstrStagingPath)
  1195. {
  1196. RETURN_INVALIDARG_IF_NULL((IReplicaSet *)i_piReplicaSet);
  1197. HRESULT hr = i_piReplicaSet->AddMember(i_bstrDnsHostName, i_bstrRootPath, i_bstrStagingPath, TRUE, NULL);
  1198. if (FAILED(hr))
  1199. {
  1200. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr,
  1201. IDS_MSG_ADDFRSMEMBER_FAILED, i_bstrDnsHostName);
  1202. } else if (S_OK == hr) // let S_FALSE drop through: computer is already a member
  1203. {
  1204. CComBSTR bstrTopologyPref;
  1205. hr = i_piReplicaSet->get_TopologyPref(&bstrTopologyPref);
  1206. if (SUCCEEDED(hr) && !lstrcmpi(bstrTopologyPref, FRS_RSTOPOLOGYPREF_CUSTOM))
  1207. {
  1208. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_MSG_ADDMEMBER_TO_CUSTOM);
  1209. }
  1210. }
  1211. return hr;
  1212. }
  1213. HRESULT CMmcDfsReplica::DeleteFRSMember(
  1214. IN IReplicaSet* i_piReplicaSet,
  1215. IN BSTR i_bstrDnsHostName,
  1216. IN BSTR i_bstrRootPath)
  1217. {
  1218. RETURN_INVALIDARG_IF_NULL((IReplicaSet *)i_piReplicaSet);
  1219. RETURN_INVALIDARG_IF_NULL(i_bstrDnsHostName);
  1220. RETURN_INVALIDARG_IF_NULL(i_bstrRootPath);
  1221. long lNumOfMembers = 0;
  1222. HRESULT hr = i_piReplicaSet->get_NumOfMembers(&lNumOfMembers);
  1223. RETURN_IF_FAILED(hr);
  1224. hr = i_piReplicaSet->IsFRSMember(i_bstrDnsHostName, i_bstrRootPath);
  1225. if (S_OK != hr)
  1226. return hr;
  1227. if (lNumOfMembers <= 2)
  1228. {
  1229. if (m_pDfsParentRoot)
  1230. hr = m_pDfsParentRoot->OnStopReplication();
  1231. else
  1232. hr = m_pDfsParentJP->OnStopReplication();
  1233. } else
  1234. hr = i_piReplicaSet->RemoveMemberEx(i_bstrDnsHostName, i_bstrRootPath);
  1235. return hr;
  1236. }
  1237. HRESULT CMmcDfsReplica::RemoveReplicaFromSet()
  1238. {
  1239. CWaitCursor wait;
  1240. HRESULT hr = S_OK;
  1241. CComPtr<IReplicaSet> piReplicaSet;
  1242. if (m_pDfsParentRoot)
  1243. hr = m_pDfsParentRoot->GetIReplicaSetPtr(&piReplicaSet);
  1244. else
  1245. hr = m_pDfsParentJP->GetIReplicaSetPtr(&piReplicaSet);
  1246. if (S_OK != hr) // no replica set on the corresponding link/root
  1247. return hr;
  1248. hr = GetReplicationInfo(); // fill in m_pRepInfo
  1249. RETURN_IF_FAILED(hr);
  1250. if (!m_pRepInfo->m_bstrDnsHostName)
  1251. return DeleteBadFRSMember(piReplicaSet, m_pRepInfo->m_bstrDisplayName, m_pRepInfo->m_hrFRS);
  1252. long lNumOfMembers = 0;
  1253. hr = piReplicaSet->get_NumOfMembers(&lNumOfMembers);
  1254. RETURN_IF_FAILED(hr);
  1255. hr = piReplicaSet->IsFRSMember(m_pRepInfo->m_bstrDnsHostName, m_pRepInfo->m_bstrRootPath);
  1256. if (S_OK != hr) // not a member
  1257. return hr;
  1258. if (lNumOfMembers <= 2)
  1259. {
  1260. if (m_pDfsParentRoot)
  1261. hr = m_pDfsParentRoot->OnStopReplication();
  1262. else
  1263. hr = m_pDfsParentJP->OnStopReplication();
  1264. } else
  1265. {
  1266. hr = piReplicaSet->RemoveMemberEx(m_pRepInfo->m_bstrDnsHostName, m_pRepInfo->m_bstrRootPath);
  1267. }
  1268. return hr;
  1269. }
  1270. //
  1271. // S_OK: either not the hub server or #Members is not more than 2,
  1272. // okay to proceed(e.g., remove the member from the set)
  1273. // S_FALSE: it is the hub server and #Members is more than 2,
  1274. // not safe to proceed
  1275. // others: error occurred
  1276. //
  1277. HRESULT CMmcDfsReplica::AllowFRSMemberDeletion(BOOL *pbRepSetExist)
  1278. {
  1279. RETURN_INVALIDARG_IF_NULL(pbRepSetExist);
  1280. *pbRepSetExist = FALSE;
  1281. HRESULT hr = S_OK;
  1282. CComPtr<IReplicaSet> piReplicaSet;
  1283. if (m_pDfsParentRoot)
  1284. hr = m_pDfsParentRoot->GetIReplicaSetPtr(&piReplicaSet);
  1285. else
  1286. hr = m_pDfsParentJP->GetIReplicaSetPtr(&piReplicaSet);
  1287. if (S_OK != hr) // no replica set on the corresponding link/root
  1288. return S_OK;
  1289. *pbRepSetExist = TRUE;
  1290. long lNumOfMembers = 0;
  1291. hr = piReplicaSet->get_NumOfMembers(&lNumOfMembers);
  1292. RETURN_IF_FAILED(hr);
  1293. if (lNumOfMembers <= 2) // removing this member will tear down the whole set
  1294. return S_OK; // no need to check if it's the hub or not
  1295. if (!m_pRepInfo)
  1296. {
  1297. hr = GetReplicationInfo();
  1298. RETURN_IF_FAILED(hr);
  1299. }
  1300. hr = piReplicaSet->IsHubMember(m_pRepInfo->m_bstrDnsHostName, m_pRepInfo->m_bstrRootPath);
  1301. if (S_OK == hr) // do not proceed, for it's the hub
  1302. {
  1303. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_MSG_CANNOT_DELETE_HUBMEMBER);
  1304. hr = S_FALSE; // do not proceed
  1305. } else if (S_FALSE == hr)
  1306. {
  1307. hr = S_OK; // not a hub, okay to proceed
  1308. } else if (FAILED(hr))
  1309. {
  1310. if (IDOK == DisplayMessageBox(::GetActiveWindow(), MB_OKCANCEL, hr, IDS_MSG_ERROR_ALLOWFRSMEMBERDELETION))
  1311. hr = S_OK; // okay to proceed
  1312. else
  1313. hr = S_FALSE; // do not proceed
  1314. }
  1315. return hr;
  1316. }
  1317. HRESULT GetReplicationText(
  1318. IN BOOL i_bFRSMember,
  1319. IN CAlternateReplicaInfo* i_pRepInfo,
  1320. OUT BSTR* o_pbstrColumnText,
  1321. OUT BSTR* o_pbstrStatusBarText
  1322. )
  1323. {
  1324. RETURN_INVALIDARG_IF_NULL(o_pbstrColumnText);
  1325. RETURN_INVALIDARG_IF_NULL(o_pbstrStatusBarText);
  1326. *o_pbstrColumnText = NULL;
  1327. *o_pbstrStatusBarText = NULL;
  1328. int nShortID = 0, nStatusID = 0;
  1329. switch (i_pRepInfo->m_nFRSShareType)
  1330. {
  1331. case FRSSHARE_TYPE_OK:
  1332. nShortID = (i_bFRSMember ? IDS_REPLICATION_STATUS_ENABLED : IDS_REPLICATION_STATUS_DISABLED);
  1333. nStatusID = (i_bFRSMember ? IDS_REPLICATION_STATUSBAR_MEMBER : IDS_REPLICATION_STATUSBAR_NONMEMBER);
  1334. break;
  1335. case FRSSHARE_TYPE_NONTFRS:
  1336. nShortID = IDS_REPLICATION_STATUS_NOTELIGIBLE;
  1337. nStatusID = IDS_REPLICATION_STATUSBAR_NONTFRS;
  1338. break;
  1339. case FRSSHARE_TYPE_NOTDISKTREE:
  1340. nShortID = IDS_REPLICATION_STATUS_NOTELIGIBLE;
  1341. nStatusID = IDS_REPLICATION_STATUSBAR_NOTDISKTREE;
  1342. break;
  1343. case FRSSHARE_TYPE_NOTNTFS:
  1344. nShortID = IDS_REPLICATION_STATUS_NOTELIGIBLE;
  1345. nStatusID = IDS_REPLICATION_STATUSBAR_NOTNTFS;
  1346. break;
  1347. case FRSSHARE_TYPE_CONFLICTSTAGING:
  1348. nShortID = IDS_REPLICATION_STATUS_NOTELIGIBLE;
  1349. nStatusID = IDS_REPLICATION_STATUSBAR_CONFLICTSTAGING;
  1350. break;
  1351. case FRSSHARE_TYPE_NODOMAIN:
  1352. nShortID = IDS_REPLICATION_STATUS_NOTELIGIBLE;
  1353. nStatusID = IDS_REPLICATION_STATUSBAR_NODOMAIN;
  1354. break;
  1355. case FRSSHARE_TYPE_NOTSMBDISK:
  1356. nShortID = IDS_REPLICATION_STATUS_NOTELIGIBLE;
  1357. nStatusID = IDS_REPLICATION_STATUSBAR_NOTSMBDISK;
  1358. break;
  1359. case FRSSHARE_TYPE_OVERLAPPING:
  1360. nShortID = IDS_REPLICATION_STATUS_NOTELIGIBLE;
  1361. nStatusID = IDS_REPLICATION_STATUSBAR_OVERLAPPING;
  1362. break;
  1363. default:
  1364. nShortID = IDS_REPLICATION_STATUS_UNKNOWN;
  1365. break;
  1366. }
  1367. if (nStatusID)
  1368. LoadStringFromResource(nStatusID, o_pbstrStatusBarText);
  1369. if (FRSSHARE_TYPE_UNKNOWN == i_pRepInfo->m_nFRSShareType)
  1370. GetErrorMessage(i_pRepInfo->m_hrFRS, o_pbstrStatusBarText);
  1371. LoadStringFromResource(nShortID, o_pbstrColumnText);
  1372. return S_OK;
  1373. }