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.

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