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.

2215 lines
50 KiB

  1. /*++
  2. Module Name:
  3. DfsWiz.cpp
  4. Abstract:
  5. This module contains the implementation for CCreateDfsRootWizPage1, 2, 3, 4, 5, 6.
  6. These classes implement pages in the CreateDfs Root wizard.
  7. --*/
  8. #include "stdafx.h"
  9. #include "resource.h" // To be able to use the resource symbols
  10. #include "DfsEnums.h" // for common enums, typedefs, etc
  11. #include "NetUtils.h"
  12. #include "ldaputils.h"
  13. #include "Utils.h" // For the LoadStringFromResource method
  14. #include "dfswiz.h" // For Ds Query Dialog
  15. #include <shlobj.h>
  16. #include <dsclient.h>
  17. #include <initguid.h>
  18. #include <cmnquery.h>
  19. #include <dsquery.h>
  20. #include <lmdfs.h>
  21. #include <iads.h>
  22. #include <icanon.h>
  23. #include <dns.h>
  24. HRESULT
  25. ValidateFolderPath(
  26. IN LPCTSTR lpszServer,
  27. IN LPCTSTR lpszPath
  28. );
  29. // ----------------------------------------------------------------------------
  30. // CCreateDfsRootWizPage1: Welcome page
  31. // Has a watermark bitmap and no controls except the next and cancel buttons
  32. CCreateDfsRootWizPage1::CCreateDfsRootWizPage1(
  33. IN LPCREATEDFSROOTWIZINFO i_lpWizInfo
  34. )
  35. : CQWizardPageImpl<CCreateDfsRootWizPage1> (false), m_lpWizInfo(i_lpWizInfo)
  36. /*++
  37. Routine Description:
  38. The ctor for CCreateDfsRootWizPage1. Calls the parent ctor asking it to
  39. display the watermark bitmap
  40. Arguments:
  41. i_lpWizInfo - The wizard information structure. Contains details like
  42. domain name, server name, etc
  43. Return value:
  44. None
  45. --*/
  46. {
  47. }
  48. BOOL
  49. CCreateDfsRootWizPage1::OnSetActive()
  50. /*++
  51. Routine Description:
  52. Called when the page is being showed. Sets the buttons to be shown
  53. Arguments:
  54. None
  55. Return value:
  56. TRUE. Since we handle the message
  57. --*/
  58. {
  59. ::PropSheet_SetWizButtons(GetParent(), PSWIZB_NEXT);
  60. ::SetControlFont(m_lpWizInfo->hBigBoldFont, m_hWnd, IDC_WELCOME_BIG_TITLE);
  61. ::SetControlFont(m_lpWizInfo->hBoldFont, m_hWnd, IDC_WELCOME_SMALL_TITLE);
  62. return TRUE;
  63. }
  64. // ----------------------------------------------------------------------------
  65. // CCreateDfsRootWizPage2: Dfsroot type selection
  66. // Used to decide the type of dfsroot to be created. Fault tolerant or standalone
  67. CCreateDfsRootWizPage2::CCreateDfsRootWizPage2(
  68. IN LPCREATEDFSROOTWIZINFO i_lpWizInfo
  69. )
  70. :m_lpWizInfo(i_lpWizInfo), CQWizardPageImpl<CCreateDfsRootWizPage2>(true)
  71. /*++
  72. Routine Description:
  73. The ctor for CCreateDfsRootWizPage2. Calls the parent ctor and stores
  74. the Wizard info struct.
  75. Arguments:
  76. i_lpWizInfo - The wizard information structure. Contains details like
  77. domain name, server name, etc
  78. Return value:
  79. None
  80. --*/
  81. {
  82. CComBSTR bstrTitle;
  83. CComBSTR bstrSubTitle;
  84. HRESULT hr = LoadStringFromResource(IDS_WIZ_PAGE2_TITLE, &bstrTitle);
  85. _ASSERTE(S_OK == hr);
  86. _ASSERTE(NULL != bstrTitle.m_str);
  87. SetHeaderTitle(bstrTitle);
  88. hr = LoadStringFromResource(IDS_WIZ_PAGE2_SUBTITLE, &bstrSubTitle);
  89. _ASSERTE(S_OK == hr);
  90. _ASSERTE(NULL != bstrSubTitle.m_str);
  91. SetHeaderSubTitle(bstrSubTitle);
  92. }
  93. BOOL
  94. CCreateDfsRootWizPage2::OnSetActive()
  95. /*++
  96. Routine Description:
  97. Called when the page is being showed. Sets the buttons to be shown.
  98. Also, sets the Dfsroot type to be fault tolerant.
  99. Arguments:
  100. None
  101. Return value:
  102. TRUE. Since we handle the message
  103. --*/
  104. {
  105. ::PropSheet_SetWizButtons(GetParent(), PSWIZB_BACK | PSWIZB_NEXT);
  106. SetDefaultValues(); // Update the controls to show default values
  107. return TRUE;
  108. }
  109. HRESULT
  110. CCreateDfsRootWizPage2::SetDefaultValues(
  111. )
  112. /*++
  113. Routine Description:
  114. Sets the default values for controls in the dialog box
  115. Arguments:
  116. None
  117. Return value:
  118. S_OK
  119. --*/
  120. {
  121. // Fault Tolerant dfsroot is the default.
  122. if (DFS_TYPE_UNASSIGNED == m_lpWizInfo->DfsType)
  123. { // Set the variable and the radio button
  124. CheckRadioButton(IDC_RADIO_FTDFSROOT, IDC_RADIO_STANDALONE_DFSROOT, IDC_RADIO_FTDFSROOT);
  125. m_lpWizInfo->DfsType = DFS_TYPE_FTDFS;
  126. }
  127. return S_OK;
  128. }
  129. BOOL
  130. CCreateDfsRootWizPage2::OnWizardNext()
  131. /*++
  132. Routine Description:
  133. Called when the "Next" button is pressed. Gets the values from the page.
  134. Arguments:
  135. None
  136. Return value:
  137. TRUE. to let the user continue to the next page
  138. FALSE, to not let the user continue ahead.
  139. --*/
  140. {
  141. if (IsDlgButtonChecked(IDC_RADIO_FTDFSROOT)) // Use the radio buttons to set the variable
  142. {
  143. m_lpWizInfo->DfsType = DFS_TYPE_FTDFS;
  144. }
  145. else
  146. {
  147. m_lpWizInfo->DfsType = DFS_TYPE_STANDALONE;
  148. }
  149. return TRUE;
  150. }
  151. BOOL
  152. CCreateDfsRootWizPage2::OnWizardBack()
  153. /*++
  154. Routine Description:
  155. Called when the "Back" button on the pressed. Sets the buttons to be shown
  156. Arguments:
  157. None
  158. Return value:
  159. TRUE. Since we handle the message
  160. --*/
  161. {
  162. return OnReset();
  163. }
  164. BOOL
  165. CCreateDfsRootWizPage2::OnReset()
  166. /*++
  167. Routine Description:
  168. Called when the page is being released. Can be on "Back" or "Cancel"
  169. Arguments:
  170. None
  171. Return value:
  172. TRUE. Since we handle the message
  173. --*/
  174. {
  175. m_lpWizInfo->DfsType = DFS_TYPE_UNASSIGNED; // Reset the dfsroot type
  176. return TRUE;
  177. }
  178. // ----------------------------------------------------------------------------
  179. // CCreateDfsRootWizPage3: Domain selection
  180. // Use to select a NT 5.0 domain
  181. CCreateDfsRootWizPage3::CCreateDfsRootWizPage3(
  182. IN LPCREATEDFSROOTWIZINFO i_lpWizInfo
  183. )
  184. : m_lpWizInfo(i_lpWizInfo), m_hImgListSmall(NULL),
  185. CQWizardPageImpl<CCreateDfsRootWizPage3>(true)
  186. /*++
  187. Routine Description:
  188. The ctor for CCreateDfsRootWizPage3. Calls the parent ctor and stores
  189. the Wizard info struct.
  190. Arguments:
  191. i_lpWizInfo - The wizard information structure. Contains details like
  192. domain name, server name, etc
  193. Return value:
  194. None
  195. --*/
  196. {
  197. CComBSTR bstrTitle;
  198. CComBSTR bstrSubTitle;
  199. HRESULT hr = LoadStringFromResource(IDS_WIZ_PAGE3_TITLE, &bstrTitle);
  200. _ASSERTE(S_OK == hr);
  201. _ASSERTE(NULL != bstrTitle.m_str);
  202. SetHeaderTitle(bstrTitle);
  203. hr = LoadStringFromResource(IDS_WIZ_PAGE3_SUBTITLE, &bstrSubTitle);
  204. _ASSERTE(S_OK == hr);
  205. _ASSERTE(NULL != bstrSubTitle.m_str);
  206. SetHeaderSubTitle(bstrSubTitle);
  207. }
  208. CCreateDfsRootWizPage3::~CCreateDfsRootWizPage3(
  209. )
  210. /*++
  211. Routine Description:
  212. The dtor for CCreateDfsRootWizPage3.
  213. Arguments:
  214. None
  215. Return value:
  216. None
  217. --*/
  218. {
  219. }
  220. BOOL
  221. CCreateDfsRootWizPage3::OnSetActive()
  222. /*++
  223. Routine Description:
  224. Called when the page is being showed. Sets the buttons to be shown.
  225. Also, if the Dfsroot type is standalone, this page is skipped. Before
  226. this the user domain name is specified
  227. Arguments:
  228. None
  229. Return value:
  230. TRUE. Since we handle the message
  231. --*/
  232. {
  233. CWaitCursor WaitCursor; // Set cursor to wait
  234. // if (NULL != m_lpWizInfo->bstrSelectedDomain)
  235. // {
  236. // OnReset();
  237. // }
  238. // Skip this page for standalone dfs roots
  239. if (DFS_TYPE_STANDALONE == m_lpWizInfo->DfsType)
  240. {
  241. return FALSE;
  242. }
  243. SetDefaultValues(); // Update the controls to show default values
  244. ::PropSheet_SetWizButtons(GetParent(), PSWIZB_BACK | PSWIZB_NEXT);
  245. return TRUE;
  246. }
  247. HRESULT
  248. CCreateDfsRootWizPage3::SetDefaultValues(
  249. )
  250. /*++
  251. Routine Description:
  252. Sets the default values for controls in the dialog box
  253. Sets the edit box to the current domain. No check to see, if it has
  254. been already done as Standalone skips this page
  255. Arguments:
  256. None
  257. Return value:
  258. S_OK
  259. --*/
  260. {
  261. if (NULL == m_lpWizInfo->bstrSelectedDomain)
  262. {
  263. // Page is displayed for the first time, Set domain to current domain
  264. CComBSTR bstrDomain;
  265. HRESULT hr = GetServerInfo(NULL, &bstrDomain);
  266. if (S_OK == hr && S_OK == Is50Domain(bstrDomain))
  267. {
  268. m_lpWizInfo->bstrSelectedDomain = bstrDomain.Detach();
  269. }
  270. }
  271. SetDlgItemText(IDC_EDIT_SELECTED_DOMAIN,
  272. m_lpWizInfo->bstrSelectedDomain ? m_lpWizInfo->bstrSelectedDomain : _T(""));
  273. // select the matching item in the listbox
  274. HWND hwndList = GetDlgItem(IDC_LIST_DOMAINS);
  275. if ( ListView_GetItemCount(hwndList) > 0)
  276. {
  277. int nIndex = -1;
  278. if (m_lpWizInfo->bstrSelectedDomain)
  279. {
  280. TCHAR szText[DNS_MAX_NAME_BUFFER_LENGTH];
  281. while (-1 != (nIndex = ListView_GetNextItem(hwndList, nIndex, LVNI_ALL)))
  282. {
  283. ListView_GetItemText(hwndList, nIndex, 0, szText, DNS_MAX_NAME_BUFFER_LENGTH);
  284. if (!lstrcmpi(m_lpWizInfo->bstrSelectedDomain, szText))
  285. {
  286. ListView_SetItemState(hwndList, nIndex, LVIS_SELECTED | LVIS_FOCUSED, 0xffffffff);
  287. ListView_Update(hwndList, nIndex);
  288. break;
  289. }
  290. }
  291. }
  292. if (-1 == nIndex)
  293. {
  294. ListView_SetItemState(hwndList, 0, LVIS_SELECTED | LVIS_FOCUSED, 0xffffffff);
  295. ListView_Update(hwndList, 0);
  296. }
  297. }
  298. return S_OK;
  299. }
  300. BOOL
  301. CCreateDfsRootWizPage3::OnWizardNext()
  302. /*++
  303. Routine Description:
  304. Called when the "Next" button is pressed. Gets the values from the page.
  305. Displays an error message, if an incorrect value has been specified
  306. Arguments:
  307. None
  308. Return value:
  309. TRUE. to let the user continue to the next page
  310. FALSE, to not let the user continue ahead.
  311. --*/
  312. {
  313. CWaitCursor WaitCursor; // Set cursor to wait
  314. // Get the value entered by the user
  315. DWORD dwTextLength = 0;
  316. CComBSTR bstrCurrentText;
  317. HRESULT hr = GetInputText(GetDlgItem(IDC_EDIT_SELECTED_DOMAIN), &bstrCurrentText, &dwTextLength);
  318. if (FAILED(hr))
  319. {
  320. DisplayMessageBoxForHR(hr);
  321. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_DOMAIN));
  322. return FALSE;
  323. } else if (0 == dwTextLength)
  324. {
  325. DisplayMessageBoxWithOK(IDS_MSG_EMPTY_FIELD);
  326. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_DOMAIN));
  327. return FALSE;
  328. }
  329. CComBSTR bstrDnsDomain;
  330. hr = CheckUserEnteredValues(bstrCurrentText, &bstrDnsDomain);
  331. if (S_OK != hr)
  332. { // Error message on incorrect domain.
  333. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_MSG_INCORRECT_DOMAIN, bstrCurrentText);
  334. return FALSE;
  335. }
  336. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrSelectedDomain);
  337. m_lpWizInfo->bstrSelectedDomain = bstrDnsDomain.Detach();
  338. return TRUE;
  339. }
  340. HRESULT
  341. CCreateDfsRootWizPage3::CheckUserEnteredValues(
  342. IN LPCTSTR i_szDomainName,
  343. OUT BSTR* o_pbstrDnsDomainName
  344. )
  345. /*++
  346. Routine Description:
  347. Checks the value that user has given for this page.
  348. This is done typically on "Next" key being pressed.
  349. Check, if the domain is NT 5.0 and contactable
  350. --*/
  351. {
  352. RETURN_INVALIDARG_IF_NULL(i_szDomainName);
  353. // Check if it is NT 5.0 domain and is contactable
  354. return Is50Domain(const_cast<LPTSTR>(i_szDomainName), o_pbstrDnsDomainName);
  355. }
  356. BOOL
  357. CCreateDfsRootWizPage3::OnWizardBack()
  358. /*++
  359. Routine Description:
  360. Called when the "Back" button is pressed. Resets the values
  361. Arguments:
  362. None
  363. Return value:
  364. TRUE. to let the user continue to the previous page
  365. FALSE, to not let the user continue.
  366. --*/
  367. {
  368. SetDlgItemText(IDC_EDIT_SELECTED_DOMAIN, _T("")); // Set edit box to empty
  369. return OnReset(); // Simulate a reset.
  370. }
  371. BOOL
  372. CCreateDfsRootWizPage3::OnReset()
  373. /*++
  374. Routine Description:
  375. Called when the page is being released. Can be on "Back" or "Cancel"
  376. Arguments:
  377. None
  378. Return value:
  379. TRUE. Since we handle the message
  380. --*/
  381. {
  382. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrSelectedDomain);
  383. return TRUE;
  384. }
  385. LRESULT
  386. CCreateDfsRootWizPage3::OnNotify(
  387. IN UINT i_uMsg,
  388. IN WPARAM i_wParam,
  389. IN LPARAM i_lParam,
  390. IN OUT BOOL& io_bHandled
  391. )
  392. /*++
  393. Routine Description:
  394. Notify message for user actions. We handle only the mouse click right now
  395. Arguments:
  396. i_lParam - Details about the control sending the notify
  397. io_bHandled - Whether we handled this message or not.
  398. Return value:
  399. TRUE
  400. --*/
  401. {
  402. io_bHandled = FALSE; // So that the base class gets this notify too
  403. NMHDR* pNMHDR = (NMHDR*)i_lParam;
  404. if (NULL == pNMHDR)
  405. return TRUE;
  406. if (IDC_LIST_DOMAINS != pNMHDR->idFrom) // We need to handle notifies only to the LV
  407. {
  408. return TRUE;
  409. }
  410. switch(pNMHDR->code)
  411. {
  412. case LVN_ITEMCHANGED:
  413. case NM_CLICK:
  414. // On item changed
  415. {
  416. if (NULL != ((NM_LISTVIEW *)i_lParam))
  417. OnItemChanged(((NM_LISTVIEW *)i_lParam)->iItem);
  418. return 0; // Should be returning 0
  419. }
  420. case NM_DBLCLK: // Double click event
  421. {
  422. // Simulate a double click
  423. if (NULL != ((NM_LISTVIEW *)i_lParam))
  424. OnItemChanged(((NM_LISTVIEW *)i_lParam)->iItem);
  425. if (0 <= ((NM_LISTVIEW *)i_lParam)->iItem)
  426. ::PropSheet_PressButton(GetParent(), PSBTN_NEXT);
  427. break;
  428. }
  429. default:
  430. break;
  431. }
  432. return TRUE;
  433. }
  434. BOOL
  435. CCreateDfsRootWizPage3::OnItemChanged(
  436. IN INT i_iItem
  437. )
  438. /*++
  439. Routine Description:
  440. Handles item change notify. Change the edit box content to the current LV
  441. selection
  442. Arguments:
  443. i_iItem - Selected Item number of the LV.
  444. Return value:
  445. TRUE
  446. --*/
  447. {
  448. HWND hwndDomainLV = GetDlgItem(IDC_LIST_DOMAINS);
  449. CComBSTR bstrDomain;
  450. if (NULL == hwndDomainLV)
  451. {
  452. return FALSE;
  453. }
  454. // Get the LV item text
  455. HRESULT hr = GetListViewItemText(hwndDomainLV, i_iItem, &bstrDomain);
  456. if ((S_OK == hr) && (bstrDomain != NULL) )
  457. {
  458. LRESULT lr = SetDlgItemText(IDC_EDIT_SELECTED_DOMAIN, bstrDomain);
  459. return lr;
  460. }
  461. return TRUE;
  462. }
  463. LRESULT
  464. CCreateDfsRootWizPage3::OnInitDialog(
  465. IN UINT i_uMsg,
  466. IN WPARAM i_wParam,
  467. IN LPARAM i_lParam,
  468. IN OUT BOOL& io_bHandled
  469. )
  470. /*++
  471. Routine Description:
  472. Called at the dialog creation time. We get the domain list here.
  473. Also, set the imagelist for the LV.
  474. Arguments:
  475. None used
  476. Return value:
  477. TRUE - Nothing to do with errors. Just lets the dialog set the focus to a control
  478. --*/
  479. {
  480. CWaitCursor WaitCursor; // Set cursor to wait
  481. ::SendMessage(GetDlgItem(IDC_EDIT_SELECTED_DOMAIN), EM_LIMITTEXT, DNSNAMELIMIT, 0);
  482. HWND hwndDomainList = GetDlgItem(IDC_LIST_DOMAINS); // The imagelist
  483. // Assign the image lists to the list view control.
  484. HIMAGELIST hImageList = NULL;
  485. int nIconIDs[] = {IDI_16x16_DOMAIN};
  486. HRESULT hr = CreateSmallImageList(
  487. _Module.GetResourceInstance(),
  488. nIconIDs,
  489. sizeof(nIconIDs) / sizeof(nIconIDs[0]),
  490. &hImageList);
  491. if (SUCCEEDED(hr))
  492. {
  493. ListView_SetImageList(hwndDomainList, hImageList, LVSIL_SMALL);
  494. hr = AddDomainsToList(hwndDomainList); // Add the domains to the list view
  495. }
  496. return TRUE;
  497. }
  498. HRESULT
  499. CCreateDfsRootWizPage3::AddDomainsToList(
  500. IN HWND i_hImageList
  501. )
  502. /*++
  503. Routine Description:
  504. Add all the NT 5.0 domains to the list view
  505. Arguments:
  506. i_hImageList - The hwnd of the LV.
  507. Return value:
  508. S_OK - On success
  509. E_FAIL - On failure
  510. E_INVALID_ARG - On any argument being null
  511. E_UNEXPECTED - Some unexpected error. If an image loading fails, etc
  512. Value other than S_OK returned by called methods
  513. --*/
  514. {
  515. RETURN_INVALIDARG_IF_NULL(i_hImageList);
  516. HRESULT hr = S_FALSE;
  517. NETNAMELIST ListOf50Domains; // Pointer to the first domain information
  518. hr = Get50Domains(&ListOf50Domains); // Get the NT 5.0 domains
  519. if (S_OK != hr)
  520. {
  521. return hr;
  522. }
  523. // Add the NT 5.0 domains to the LV
  524. for(NETNAMELIST::iterator i = ListOf50Domains.begin(); i != ListOf50Domains.end(); i++)
  525. {
  526. if ((*i)->bstrNetName)
  527. {
  528. InsertIntoListView(i_hImageList, (*i)->bstrNetName);
  529. }
  530. }
  531. if (!ListOf50Domains.empty())
  532. {
  533. for (NETNAMELIST::iterator i = ListOf50Domains.begin(); i != ListOf50Domains.end(); i++)
  534. {
  535. delete (*i);
  536. }
  537. ListOf50Domains.erase(ListOf50Domains.begin(), ListOf50Domains.end());
  538. }
  539. return S_OK;
  540. }
  541. // ----------------------------------------------------------------------------
  542. // CCreateDfsRootWizPage4: Server selection
  543. // Displays a list of Servers and allows the user to select one.
  544. CCreateDfsRootWizPage4::CCreateDfsRootWizPage4(
  545. IN LPCREATEDFSROOTWIZINFO i_lpWizInfo
  546. )
  547. : m_lpWizInfo(i_lpWizInfo),
  548. m_cfDsObjectNames(NULL),
  549. CQWizardPageImpl<CCreateDfsRootWizPage4>(true)
  550. /*++
  551. Routine Description:
  552. The ctor for CCreateDfsRootWizPage4. Calls the parent ctor and stores
  553. the Wizard info struct.
  554. Arguments:
  555. i_lpWizInfo - The wizard information structure. Contains details like
  556. domain name, server name, etc
  557. Return value:
  558. None
  559. --*/
  560. {
  561. CComBSTR bstrTitle;
  562. CComBSTR bstrSubTitle;
  563. HRESULT hr = LoadStringFromResource(IDS_WIZ_PAGE4_TITLE, &bstrTitle);
  564. _ASSERTE(S_OK == hr);
  565. _ASSERTE(NULL != bstrTitle.m_str);
  566. SetHeaderTitle(bstrTitle);
  567. hr = LoadStringFromResource(IDS_WIZ_PAGE4_SUBTITLE, &bstrSubTitle);
  568. _ASSERTE(S_OK == hr);
  569. _ASSERTE(NULL != bstrSubTitle.m_str);
  570. SetHeaderSubTitle(bstrSubTitle);
  571. }
  572. CCreateDfsRootWizPage4::~CCreateDfsRootWizPage4(
  573. )
  574. /*++
  575. Routine Description:
  576. The dtor for CCreateDfsRootWizPage4.
  577. Arguments:
  578. None
  579. Return value:
  580. None
  581. --*/
  582. {
  583. }
  584. BOOL
  585. CCreateDfsRootWizPage4::OnSetActive()
  586. /*++
  587. Routine Description:
  588. Called when the page is being showed. Sets the buttons to be shown.
  589. Arguments:
  590. None
  591. Return value:
  592. TRUE. Since we handle the message
  593. --*/
  594. {
  595. CWaitCursor WaitCursor; // Set cursor to wait
  596. ::SendMessage(GetDlgItem(IDC_EDIT_SELECTED_SERVER), EM_LIMITTEXT, DNSNAMELIMIT, 0);
  597. HRESULT hr = S_OK;
  598. dfsDebugOut((_T("WizPage4::OnSetActive bstrSelectedDomain=%s\n"), m_lpWizInfo->bstrSelectedDomain));
  599. if (DFS_TYPE_STANDALONE== m_lpWizInfo->DfsType)
  600. {
  601. // Standalone Setup, set domain to current domain.
  602. CComBSTR bstrDomain;
  603. hr = GetServerInfo(NULL, &bstrDomain);
  604. if (S_OK == hr)
  605. m_lpWizInfo->bstrSelectedDomain = bstrDomain.Detach();
  606. }
  607. ::EnableWindow(GetDlgItem(IDCSERVERS_BROWSE), m_lpWizInfo->bstrSelectedDomain && S_OK == Is50Domain(m_lpWizInfo->bstrSelectedDomain));
  608. if (NULL == m_lpWizInfo->bstrSelectedServer) // If selected server is null
  609. {
  610. SetDefaultValues(); // Update the controls to show default values
  611. }
  612. if (m_lpWizInfo->bRootReplica) // If a root replica is being added
  613. {
  614. ::PropSheet_SetWizButtons(GetParent(), PSWIZB_NEXT);
  615. ::ShowWindow(GetDlgItem(IDC_SERVER_SHARE_LABEL), SW_NORMAL);
  616. ::ShowWindow(GetDlgItem(IDC_SERVER_SHARE), SW_NORMAL);
  617. SetDlgItemText(IDC_SERVER_SHARE, m_lpWizInfo->bstrDfsRootName);
  618. } else
  619. ::PropSheet_SetWizButtons(GetParent(), PSWIZB_BACK | PSWIZB_NEXT);
  620. return TRUE;
  621. }
  622. HRESULT
  623. CCreateDfsRootWizPage4::SetDefaultValues(
  624. )
  625. /*++
  626. Routine Description:
  627. Sets the default values for controls in the dialog box
  628. Sets the edit box to the current server.
  629. Arguments:
  630. None
  631. Return value:
  632. S_OK
  633. --*/
  634. {
  635. if (NULL == m_lpWizInfo->bstrSelectedServer)
  636. {
  637. // Page is displayed for the first time, Set to local server
  638. CComBSTR bstrServer;
  639. HRESULT hr = GetLocalComputerName(&bstrServer);
  640. if (SUCCEEDED(hr) &&
  641. S_FALSE == IsHostingDfsRoot(bstrServer) &&
  642. S_OK == IsServerInDomain(bstrServer) )
  643. {
  644. m_lpWizInfo->bstrSelectedServer = bstrServer.Detach();
  645. }
  646. }
  647. SetDlgItemText(IDC_EDIT_SELECTED_SERVER,
  648. m_lpWizInfo->bstrSelectedServer ? m_lpWizInfo->bstrSelectedServer : _T(""));
  649. return S_OK;
  650. }
  651. BOOL
  652. CCreateDfsRootWizPage4::OnWizardNext()
  653. /*++
  654. Routine Description:
  655. Called when the "Next" button is pressed. Gets the values from the page.
  656. Displays an error message, if an incorrect value has been specified
  657. Arguments:
  658. None
  659. Return value:
  660. TRUE. to let the user continue to the next page
  661. FALSE, to not let the user continue ahead.
  662. --*/
  663. {
  664. CWaitCursor WaitCursor; // Set cursor to wait
  665. HRESULT hr = S_OK;
  666. DWORD dwTextLength = 0;
  667. CComBSTR bstrCurrentText;
  668. hr = GetInputText(GetDlgItem(IDC_EDIT_SELECTED_SERVER), &bstrCurrentText, &dwTextLength);
  669. if (FAILED(hr))
  670. {
  671. DisplayMessageBoxForHR(hr);
  672. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_SERVER));
  673. return FALSE;
  674. } else if (0 == dwTextLength)
  675. {
  676. DisplayMessageBoxWithOK(IDS_MSG_EMPTY_FIELD);
  677. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_SERVER));
  678. return FALSE;
  679. }
  680. if (I_NetNameValidate(0, bstrCurrentText, NAMETYPE_COMPUTER, 0))
  681. {
  682. DisplayMessageBoxWithOK(IDS_MSG_INVALID_SERVER_NAME, bstrCurrentText);
  683. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_SERVER));
  684. return FALSE;
  685. }
  686. CComBSTR bstrComputerName;
  687. hr = CheckUserEnteredValues(bstrCurrentText, &bstrComputerName);
  688. if (S_OK != hr) // If server is not a valid one. The above function has already displayed the message
  689. {
  690. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_SERVER));
  691. return FALSE;
  692. }
  693. if (m_lpWizInfo->bRootReplica)
  694. {
  695. hr = CheckShare(bstrCurrentText, m_lpWizInfo->bstrDfsRootName, &m_lpWizInfo->bShareExists);
  696. if (FAILED(hr))
  697. {
  698. DisplayMessageBoxForHR(hr);
  699. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_SERVER));
  700. return FALSE;
  701. } else if (S_FALSE == hr)
  702. {
  703. DisplayMessageBoxWithOK(IDS_MSG_ROOTSHARE_NOGOOD, m_lpWizInfo->bstrDfsRootName);
  704. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_SERVER));
  705. return FALSE;
  706. }
  707. if (m_lpWizInfo->bPostW2KVersion && m_lpWizInfo->bShareExists && !CheckReparsePoint(bstrCurrentText, m_lpWizInfo->bstrDfsRootName))
  708. {
  709. DisplayMessageBoxWithOK(IDS_MSG_ROOTSHARE_NOTNTFS5, m_lpWizInfo->bstrDfsRootName);
  710. ::SetFocus(GetDlgItem(IDC_EDIT_SELECTED_SERVER));
  711. return FALSE;
  712. }
  713. }
  714. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrSelectedServer);
  715. m_lpWizInfo->bstrSelectedServer = bstrComputerName.Detach();
  716. return TRUE;
  717. }
  718. // S_OK: Yes, it belongs to the selected domain
  719. // S_FALSE: No, it does not belong to the selected domain
  720. // hr: other errors
  721. HRESULT
  722. CCreateDfsRootWizPage4::IsServerInDomain(IN LPCTSTR lpszServer)
  723. {
  724. if (DFS_TYPE_FTDFS != m_lpWizInfo->DfsType)
  725. return S_OK;
  726. HRESULT hr = S_FALSE;
  727. CComBSTR bstrActualDomain;
  728. hr = GetServerInfo((LPTSTR)lpszServer, &bstrActualDomain);
  729. if (S_OK == hr)
  730. {
  731. if (!lstrcmpi(bstrActualDomain, m_lpWizInfo->bstrSelectedDomain))
  732. hr = S_OK;
  733. else
  734. hr = S_FALSE;
  735. }
  736. return hr;
  737. }
  738. HRESULT
  739. CCreateDfsRootWizPage4::CheckUserEnteredValues(
  740. IN LPCTSTR i_szMachineName,
  741. OUT BSTR* o_pbstrComputerName
  742. )
  743. /*++
  744. Routine Description:
  745. Checks the value that user has given for this page.
  746. This is done typically on "Next" key being pressed.
  747. Check, if the machine name is a server that is NT 5.0, belongs to
  748. the domain previously selected and is running dfs service.
  749. Arguments:
  750. i_szMachineName - Machine name given by the user
  751. --*/
  752. {
  753. RETURN_INVALIDARG_IF_NULL(i_szMachineName);
  754. RETURN_INVALIDARG_IF_NULL(o_pbstrComputerName);
  755. HRESULT hr = S_OK;
  756. LONG lMajorVer = 0;
  757. LONG lMinorVer = 0;
  758. hr = GetServerInfo(
  759. (LPTSTR)i_szMachineName,
  760. NULL, // &bstrActualDomain,
  761. NULL, // &bstrNetbiosComputerName, // Netbios
  762. NULL, // ValidDSObject
  763. NULL, // Dns
  764. NULL, // Guid
  765. NULL, // FQDN
  766. NULL, // pSubscriberList
  767. &lMajorVer,
  768. &lMinorVer
  769. );
  770. if(FAILED(hr))
  771. {
  772. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_MSG_INCORRECT_SERVER, i_szMachineName);
  773. return hr;
  774. }
  775. if (lMajorVer < 5)
  776. {
  777. DisplayMessageBoxWithOK(IDS_MSG_NOT_50, (BSTR)i_szMachineName);
  778. return S_FALSE;
  779. }
  780. /* LinanT 3/19/99: remove "check registry, if set, get dns server"
  781. CComBSTR bstrDnsComputerName;
  782. (void)GetServerInfo(
  783. (LPTSTR)i_szMachineName,
  784. NULL, // domain
  785. NULL, // Netbios
  786. NULL, // ValidDSObject
  787. &bstrDnsComputerName, // Dns
  788. NULL, // Guid
  789. NULL, // FQDN
  790. NULL, // lMajorVer
  791. NULL //lMinorVer
  792. );
  793. *o_pbstrComputerName = SysAllocString(bstrDnsComputerName ? bstrDnsComputerName : bstrNetbiosComputerName);
  794. */
  795. if ( !mylstrncmpi(i_szMachineName, _T("\\\\"), 2) )
  796. *o_pbstrComputerName = SysAllocString(i_szMachineName + 2);
  797. else
  798. *o_pbstrComputerName = SysAllocString(i_szMachineName);
  799. if (!*o_pbstrComputerName)
  800. {
  801. hr = E_OUTOFMEMORY;
  802. DisplayMessageBoxForHR(hr);
  803. return hr;
  804. }
  805. /*
  806. //
  807. // don't check, let DFS API handle it.
  808. // This way, we have space to handle new DFS service if introduced in the future.
  809. //
  810. hr = IsServerRunningDfs(*o_pbstrComputerName);
  811. if(S_OK != hr)
  812. {
  813. DisplayMessageBoxWithOK(IDS_MSG_NOT_RUNNING_DFS, *o_pbstrComputerName);
  814. return hr;
  815. }
  816. */
  817. hr = IsServerInDomain(*o_pbstrComputerName);
  818. if (FAILED(hr))
  819. {
  820. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_MSG_INCORRECT_SERVER, *o_pbstrComputerName);
  821. return hr;
  822. } else if (S_FALSE == hr)
  823. {
  824. DisplayMessageBoxWithOK(IDS_MSG_SERVER_FROM_ANOTHER_DOMAIN, *o_pbstrComputerName);
  825. return hr;
  826. }
  827. //
  828. // for W2K, check if server already has a dfs root set up
  829. // do not check for Whistler (in which case the lMinorVer == 1).
  830. //
  831. if (lMajorVer == 5 && lMinorVer < 1 && S_OK == IsHostingDfsRoot(*o_pbstrComputerName))
  832. {
  833. DisplayMessageBoxWithOK(IDS_MSG_WIZ_DFS_ALREADY_PRESENT,NULL);
  834. return S_FALSE;
  835. }
  836. m_lpWizInfo->bPostW2KVersion = (lMajorVer >= 5 && lMinorVer >= 1);
  837. return S_OK;
  838. }
  839. BOOL
  840. CCreateDfsRootWizPage4::OnWizardBack()
  841. /*++
  842. Routine Description:
  843. Called when the "Back" button is pressed. Resets the values.
  844. Empties the LV
  845. Arguments:
  846. None
  847. Return value:
  848. TRUE. to let the user continue to the next page
  849. FALSE, to not let the user continue ahead.
  850. --*/
  851. {
  852. SetDlgItemText(IDC_EDIT_SELECTED_SERVER, _T("")); // Set edit box to empty
  853. return OnReset();
  854. }
  855. BOOL
  856. CCreateDfsRootWizPage4::OnReset()
  857. /*++
  858. Routine Description:
  859. Called when the page is being released. Can be on "Back" or "Cancel"
  860. Arguments:
  861. None
  862. Return value:
  863. TRUE. Since we handle the message
  864. --*/
  865. {
  866. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrSelectedServer);
  867. return TRUE;
  868. }
  869. HRESULT
  870. GetComputerDnsNameFromLDAP(
  871. IN LPCTSTR lpszLDAPPath,
  872. OUT BSTR *o_pbstrName
  873. )
  874. {
  875. HRESULT hr = S_OK;
  876. CComPtr<IADs> spIADs;
  877. hr = ADsGetObject(const_cast<LPTSTR>(lpszLDAPPath), IID_IADs, (void**)&spIADs);
  878. if (SUCCEEDED(hr))
  879. {
  880. VARIANT var;
  881. VariantInit(&var);
  882. hr = spIADs->Get(_T("dnsHostName"), &var);
  883. if (SUCCEEDED(hr))
  884. {
  885. CComBSTR bstrComputer = V_BSTR(&var);
  886. *o_pbstrName = bstrComputer.Detach();
  887. VariantClear(&var);
  888. }
  889. }
  890. return hr;
  891. }
  892. HRESULT
  893. GetComputerNetbiosNameFromLDAP(
  894. IN LPCTSTR lpszLDAPPath,
  895. OUT BSTR *o_pbstrName
  896. )
  897. {
  898. HRESULT hr = S_OK;
  899. CComPtr<IADsPathname> spIAdsPath;
  900. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (void**)&spIAdsPath);
  901. if (SUCCEEDED(hr))
  902. {
  903. hr = spIAdsPath->Set(const_cast<LPTSTR>(lpszLDAPPath), ADS_SETTYPE_FULL);
  904. if (SUCCEEDED(hr))
  905. {
  906. hr = spIAdsPath->SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  907. if (SUCCEEDED(hr))
  908. {
  909. // Get first Component which is computer's Netbios name.
  910. CComBSTR bstrComputer;
  911. hr = spIAdsPath->GetElement(0, &bstrComputer);
  912. if (SUCCEEDED(hr))
  913. *o_pbstrName = bstrComputer.Detach();
  914. }
  915. }
  916. }
  917. return hr;
  918. }
  919. BOOL
  920. CCreateDfsRootWizPage4::OnBrowse(
  921. IN WORD wNotifyCode,
  922. IN WORD wID,
  923. IN HWND hWndCtl,
  924. IN BOOL& bHandled
  925. )
  926. /*++
  927. Routine Description:
  928. Handles the mouse click of the Browse button.
  929. Display the Computer Query Dialog.
  930. --*/
  931. {
  932. CWaitCursor WaitCursor;
  933. DSQUERYINITPARAMS dqip;
  934. OPENQUERYWINDOW oqw;
  935. CComPtr<ICommonQuery> pCommonQuery;
  936. CComPtr<IDataObject> pDataObject;
  937. HRESULT hr = S_OK;
  938. do {
  939. CComBSTR bstrDCName;
  940. CComBSTR bstrLDAPDomainPath;
  941. hr = GetDomainInfo(
  942. m_lpWizInfo->bstrSelectedDomain,
  943. &bstrDCName,
  944. NULL, // domainDns
  945. NULL, // domainDN
  946. &bstrLDAPDomainPath);
  947. if (FAILED(hr))
  948. break;
  949. dfsDebugOut((_T("OnBrowse bstrDCName=%s, bstrLDAPDomainPath=%s\n"),
  950. bstrDCName, bstrLDAPDomainPath));
  951. hr = CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER, IID_ICommonQuery, (void **)&pCommonQuery);
  952. if (FAILED(hr)) break;
  953. // Parameters for Query Dialog.
  954. ZeroMemory(&dqip, sizeof(dqip));
  955. dqip.cbStruct = sizeof(dqip);
  956. dqip.dwFlags = DSQPF_HASCREDENTIALS;
  957. dqip.pDefaultScope = bstrLDAPDomainPath;
  958. dqip.pServer = bstrDCName;
  959. ZeroMemory(&oqw, sizeof(oqw));
  960. oqw.cbStruct = sizeof(oqw);
  961. oqw.clsidHandler = CLSID_DsQuery; // Handler is Ds Query.
  962. oqw.pHandlerParameters = &dqip;
  963. oqw.clsidDefaultForm = CLSID_DsFindComputer; // Show Find Computers Query Dialog
  964. oqw.dwFlags = OQWF_OKCANCEL |
  965. OQWF_SINGLESELECT |
  966. OQWF_DEFAULTFORM |
  967. OQWF_REMOVEFORMS |
  968. OQWF_ISSUEONOPEN |
  969. OQWF_REMOVESCOPES ;
  970. hr = pCommonQuery->OpenQueryWindow(m_hWnd, &oqw, &pDataObject);
  971. if (S_OK != hr) break;
  972. if (NULL == m_cfDsObjectNames )
  973. {
  974. m_cfDsObjectNames = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES);
  975. }
  976. FORMATETC fmte = {
  977. CF_HDROP,
  978. NULL,
  979. DVASPECT_CONTENT,
  980. -1,
  981. TYMED_HGLOBAL
  982. };
  983. STGMEDIUM medium = {
  984. TYMED_NULL,
  985. NULL,
  986. NULL
  987. };
  988. fmte.cfFormat = m_cfDsObjectNames;
  989. hr = pDataObject->GetData(&fmte, &medium);
  990. if (FAILED(hr)) break;
  991. LPDSOBJECTNAMES pDsObjects = (LPDSOBJECTNAMES)medium.hGlobal;
  992. if (!pDsObjects || pDsObjects->cItems <= 0)
  993. {
  994. hr = S_FALSE;
  995. break;
  996. }
  997. // retrieve the full LDAP path to the computer
  998. LPTSTR lpszTemp =
  999. (LPTSTR)(((LPBYTE)pDsObjects)+(pDsObjects->aObjects[0].offsetName));
  1000. // try to retrieve its Dns name
  1001. CComBSTR bstrComputer;
  1002. hr = GetComputerDnsNameFromLDAP(lpszTemp, &bstrComputer);
  1003. // if failed, try to retrieve its Netbios name
  1004. if (FAILED(hr))
  1005. hr = GetComputerNetbiosNameFromLDAP(lpszTemp, &bstrComputer);
  1006. if (FAILED(hr)) break;
  1007. SetDlgItemText(IDC_EDIT_SELECTED_SERVER, bstrComputer);
  1008. } while (0);
  1009. if (FAILED(hr))
  1010. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_FAILED_TO_BROWSE_SERVER);
  1011. return (S_OK == hr);
  1012. }
  1013. // ----------------------------------------------------------------------------
  1014. // CCreateDfsRootWizPage5: Share selection
  1015. // Displays the shares given a server. Allows choosing from this list or
  1016. // creating a new one.
  1017. CCreateDfsRootWizPage5::CCreateDfsRootWizPage5(
  1018. IN LPCREATEDFSROOTWIZINFO i_lpWizInfo
  1019. )
  1020. :m_lpWizInfo(i_lpWizInfo), CQWizardPageImpl<CCreateDfsRootWizPage5>(true)
  1021. {
  1022. CComBSTR bstrTitle;
  1023. CComBSTR bstrSubTitle;
  1024. HRESULT hr = LoadStringFromResource(IDS_WIZ_PAGE5_TITLE, &bstrTitle);
  1025. _ASSERTE(S_OK == hr);
  1026. _ASSERTE(NULL != bstrTitle.m_str);
  1027. SetHeaderTitle(bstrTitle);
  1028. hr = LoadStringFromResource(IDS_WIZ_PAGE5_SUBTITLE, &bstrSubTitle);
  1029. _ASSERTE(S_OK == hr);
  1030. _ASSERTE(NULL != bstrSubTitle.m_str);
  1031. SetHeaderSubTitle(bstrSubTitle);
  1032. }
  1033. BOOL
  1034. CCreateDfsRootWizPage5::OnSetActive()
  1035. {
  1036. if (m_lpWizInfo->bShareExists)
  1037. return FALSE; // root share exists, skip this page
  1038. CComBSTR bstrText;
  1039. FormatResourceString(IDS_ROOTSHARE_NEEDED, m_lpWizInfo->bstrDfsRootName, &bstrText);
  1040. SetDlgItemText(IDC_ROOTSHARE_NEEDED, bstrText);
  1041. ::PropSheet_SetWizButtons(GetParent(), PSWIZB_BACK | PSWIZB_NEXT);
  1042. return TRUE;
  1043. }
  1044. BOOL
  1045. CCreateDfsRootWizPage5::OnWizardNext()
  1046. {
  1047. CWaitCursor WaitCursor;
  1048. CComBSTR bstrCurrentText;
  1049. DWORD dwTextLength = 0;
  1050. // get share path
  1051. HRESULT hr = GetInputText(GetDlgItem(IDC_EDIT_SHARE_PATH), &bstrCurrentText, &dwTextLength);
  1052. if (FAILED(hr))
  1053. {
  1054. DisplayMessageBoxForHR(hr);
  1055. ::SetFocus(GetDlgItem(IDC_EDIT_SHARE_PATH));
  1056. return FALSE;
  1057. } else if (0 == dwTextLength)
  1058. {
  1059. DisplayMessageBoxWithOK(IDS_MSG_EMPTY_FIELD);
  1060. ::SetFocus(GetDlgItem(IDC_EDIT_SHARE_PATH));
  1061. return FALSE;
  1062. }
  1063. // Removing the ending backslash, otherwise, GetFileAttribute/NetShareAdd will fail.
  1064. TCHAR *p = bstrCurrentText + _tcslen(bstrCurrentText) - 1;
  1065. if (IsValidLocalAbsolutePath(bstrCurrentText) && *p == _T('\\') && *(p-1) != _T(':'))
  1066. *p = _T('\0');
  1067. if (S_OK != ValidateFolderPath(m_lpWizInfo->bstrSelectedServer, bstrCurrentText))
  1068. {
  1069. ::SetFocus(GetDlgItem(IDC_EDIT_SHARE_PATH));
  1070. return FALSE;
  1071. }
  1072. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrSharePath);
  1073. m_lpWizInfo->bstrSharePath = bstrCurrentText.Detach();
  1074. // Create the share.
  1075. hr = CreateShare(
  1076. m_lpWizInfo->bstrSelectedServer,
  1077. m_lpWizInfo->bstrDfsRootName,
  1078. _T(""), // Blank Comment
  1079. m_lpWizInfo->bstrSharePath
  1080. );
  1081. if (FAILED(hr))
  1082. {
  1083. DisplayMessageBoxForHR(hr);
  1084. return FALSE;
  1085. }
  1086. if (m_lpWizInfo->bPostW2KVersion && !CheckReparsePoint(m_lpWizInfo->bstrSelectedServer, m_lpWizInfo->bstrDfsRootName))
  1087. {
  1088. DisplayMessageBoxWithOK(IDS_MSG_ROOTSHARE_NOTNTFS5, m_lpWizInfo->bstrDfsRootName);
  1089. NetShareDel(m_lpWizInfo->bstrSelectedServer, m_lpWizInfo->bstrDfsRootName, 0);
  1090. ::SetFocus(GetDlgItem(IDC_EDIT_SHARE_PATH));
  1091. return FALSE;
  1092. }
  1093. SetDlgItemText(IDC_EDIT_SHARE_PATH, _T(""));
  1094. SetDlgItemText(IDC_EDIT_SHARE_NAME, _T(""));
  1095. return TRUE;
  1096. }
  1097. BOOL
  1098. CCreateDfsRootWizPage5::OnWizardBack()
  1099. {
  1100. // Set the edit boxes to empty
  1101. SetDlgItemText(IDC_EDIT_SHARE_PATH, _T(""));
  1102. SetDlgItemText(IDC_EDIT_SHARE_NAME, _T(""));
  1103. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrSharePath);
  1104. return TRUE;
  1105. }
  1106. /*
  1107. BOOL
  1108. CCreateDfsRootWizPage5::OnWizardFinish(
  1109. )
  1110. {
  1111. if (!OnWizardNext())
  1112. return(FALSE);
  1113. return (S_OK == _SetUpDfs(m_lpWizInfo));
  1114. }
  1115. */
  1116. LRESULT CCreateDfsRootWizPage5::OnInitDialog(
  1117. IN UINT i_uMsg,
  1118. IN WPARAM i_wParam,
  1119. IN LPARAM i_lParam,
  1120. IN OUT BOOL& io_bHandled
  1121. )
  1122. {
  1123. ::SendMessage(GetDlgItem(IDC_EDIT_SHARE_PATH), EM_LIMITTEXT, _MAX_DIR - 1, 0);
  1124. return TRUE;
  1125. }
  1126. // ----------------------------------------------------------------------------
  1127. // CCreateDfsRootWizPage6: DfsRoot name selection
  1128. // The final page, here the user specifies the dfsroot name.
  1129. CCreateDfsRootWizPage6::CCreateDfsRootWizPage6(
  1130. IN LPCREATEDFSROOTWIZINFO i_lpWizInfo
  1131. )
  1132. : m_lpWizInfo(i_lpWizInfo), CQWizardPageImpl<CCreateDfsRootWizPage6>(true)
  1133. /*++
  1134. Routine Description:
  1135. The ctor for CCreateDfsRootWizPage6. Calls the parent ctor and stores
  1136. the Wizard info struct.
  1137. Arguments:
  1138. i_lpWizInfo - The wizard information structure. Contains details like
  1139. domain name, server name, etc
  1140. Return value:
  1141. None
  1142. --*/
  1143. {
  1144. CComBSTR bstrTitle;
  1145. CComBSTR bstrSubTitle;
  1146. HRESULT hr = LoadStringFromResource(IDS_WIZ_PAGE6_TITLE, &bstrTitle);
  1147. _ASSERTE(S_OK == hr);
  1148. _ASSERTE(NULL != bstrTitle.m_str);
  1149. SetHeaderTitle(bstrTitle);
  1150. hr = LoadStringFromResource(IDS_WIZ_PAGE6_SUBTITLE, &bstrSubTitle);
  1151. _ASSERTE(S_OK == hr);
  1152. _ASSERTE(NULL != bstrSubTitle.m_str);
  1153. SetHeaderSubTitle(bstrSubTitle);
  1154. }
  1155. BOOL
  1156. CCreateDfsRootWizPage6::OnSetActive()
  1157. /*++
  1158. Routine Description:
  1159. Called when the page is being showed. Sets the buttons to be shown.
  1160. Set the default value of dfsroot name
  1161. Arguments:
  1162. None
  1163. Return value:
  1164. TRUE. Since we handle the message
  1165. --*/
  1166. {
  1167. if (m_lpWizInfo->bRootReplica)
  1168. return FALSE; // we skip this page in case of creating new root target
  1169. SetDefaultValues(); // Update the controls to contain the default values
  1170. UpdateLabels(); // Change the labels
  1171. ::PropSheet_SetWizButtons(GetParent(), PSWIZB_BACK | PSWIZB_NEXT);
  1172. return TRUE;
  1173. }
  1174. HRESULT
  1175. CCreateDfsRootWizPage6::SetDefaultValues(
  1176. )
  1177. /*++
  1178. Routine Description:
  1179. Sets the default values for controls in the dialog box.
  1180. Sets the default dfsroot name to the share name
  1181. Arguments:
  1182. None
  1183. Return value:
  1184. S_OK
  1185. --*/
  1186. {
  1187. HWND hwndDfsRoot = GetDlgItem(IDC_EDIT_DFSROOT_NAME);
  1188. if (DFS_TYPE_FTDFS == m_lpWizInfo->DfsType)
  1189. {
  1190. ::SendMessage(hwndDfsRoot,
  1191. EM_LIMITTEXT, MAX_RDN_KEY_SIZE, 0);
  1192. }
  1193. if (NULL != m_lpWizInfo->bstrDfsRootName) // Set the default dfsroot name
  1194. {
  1195. SetDlgItemText(IDC_EDIT_DFSROOT_NAME, m_lpWizInfo->bstrDfsRootName);
  1196. }
  1197. ::SendMessage(GetDlgItem(IDC_EDIT_DFSROOT_COMMENT), EM_LIMITTEXT, MAXCOMMENTSZ, 0);
  1198. return S_OK;
  1199. }
  1200. HRESULT
  1201. CCreateDfsRootWizPage6::UpdateLabels(
  1202. )
  1203. /*++
  1204. Routine Description:
  1205. Change the text labels to show previous selections
  1206. --*/
  1207. {
  1208. CComBSTR bstrDfsRootName;
  1209. DWORD dwTextLength = 0;
  1210. (void)GetInputText(GetDlgItem(IDC_EDIT_DFSROOT_NAME), &bstrDfsRootName, &dwTextLength);
  1211. SetDlgItemText(IDC_ROOT_SHARE, bstrDfsRootName);
  1212. CComBSTR bstrFullPath = _T("\\\\");
  1213. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFullPath);
  1214. if (DFS_TYPE_FTDFS == m_lpWizInfo->DfsType)
  1215. bstrFullPath += m_lpWizInfo->bstrSelectedDomain;
  1216. else
  1217. bstrFullPath += m_lpWizInfo->bstrSelectedServer;
  1218. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFullPath);
  1219. bstrFullPath += _T("\\");
  1220. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFullPath);
  1221. bstrFullPath += bstrDfsRootName;
  1222. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFullPath);
  1223. SetDlgItemText(IDC_TEXT_DFSROOT_PREFIX, bstrFullPath);
  1224. ::SendMessage(GetDlgItem(IDC_TEXT_DFSROOT_PREFIX), EM_SETSEL, 0, (LPARAM)-1);
  1225. ::SendMessage(GetDlgItem(IDC_TEXT_DFSROOT_PREFIX), EM_SETSEL, (WPARAM)-1, 0);
  1226. ::SendMessage(GetDlgItem(IDC_TEXT_DFSROOT_PREFIX), EM_SCROLLCARET, 0, 0);
  1227. return S_OK;
  1228. }
  1229. LRESULT
  1230. CCreateDfsRootWizPage6::OnChangeDfsRoot(
  1231. WORD wNotifyCode,
  1232. WORD wID,
  1233. HWND hWndCtl,
  1234. BOOL& bHandled)
  1235. {
  1236. UpdateLabels();
  1237. return TRUE;
  1238. }
  1239. BOOL
  1240. CCreateDfsRootWizPage6::OnWizardNext(
  1241. )
  1242. /*++
  1243. Routine Description:
  1244. Called when the user presses the next button.
  1245. We get the user specified values here and take action on these.
  1246. Arguments:
  1247. None
  1248. Return value:
  1249. TRUE. to let the user continue to the next page
  1250. FALSE, to not let the user continue ahead.
  1251. --*/
  1252. {
  1253. CWaitCursor WaitCursor; // Set cursor to wait
  1254. HRESULT hr = S_OK;
  1255. CComBSTR bstrCurrentText;
  1256. DWORD dwTextLength = 0;
  1257. // get dfsroot name
  1258. hr = GetInputText(GetDlgItem(IDC_EDIT_DFSROOT_NAME), &bstrCurrentText, &dwTextLength);
  1259. if (FAILED(hr))
  1260. {
  1261. DisplayMessageBoxForHR(hr);
  1262. ::SetFocus(GetDlgItem(IDC_EDIT_DFSROOT_NAME));
  1263. return FALSE;
  1264. } else if (0 == dwTextLength)
  1265. {
  1266. DisplayMessageBoxWithOK(IDS_MSG_EMPTY_FIELD);
  1267. ::SetFocus(GetDlgItem(IDC_EDIT_DFSROOT_NAME));
  1268. return FALSE;
  1269. }
  1270. // See if the Dfs Name has illegal Characters.
  1271. if (_tcscspn(bstrCurrentText, _T("\\/@")) != _tcslen(bstrCurrentText) ||
  1272. (DFS_TYPE_FTDFS == m_lpWizInfo->DfsType && I_NetNameValidate(NULL, bstrCurrentText, NAMETYPE_SHARE, 0)) )
  1273. {
  1274. DisplayMessageBoxWithOK(IDS_MSG_WIZ_BAD_DFS_NAME,NULL);
  1275. ::SetFocus(GetDlgItem(IDC_EDIT_DFSROOT_NAME));
  1276. return FALSE;
  1277. }
  1278. // domain DFS only: See if the Dfs Name exists.
  1279. if (DFS_TYPE_FTDFS == m_lpWizInfo->DfsType)
  1280. {
  1281. BOOL bRootAlreadyExist = FALSE;
  1282. NETNAMELIST DfsRootList;
  1283. if (S_OK == GetDomainDfsRoots(&DfsRootList, m_lpWizInfo->bstrSelectedDomain))
  1284. {
  1285. for (NETNAMELIST::iterator i = DfsRootList.begin(); i != DfsRootList.end(); i++)
  1286. {
  1287. if (!lstrcmpi((*i)->bstrNetName, bstrCurrentText))
  1288. {
  1289. bRootAlreadyExist = TRUE;
  1290. break;
  1291. }
  1292. }
  1293. FreeNetNameList(&DfsRootList);
  1294. }
  1295. if (bRootAlreadyExist)
  1296. {
  1297. DisplayMessageBoxWithOK(IDS_MSG_ROOT_ALREADY_EXISTS, bstrCurrentText);
  1298. ::SetFocus(GetDlgItem(IDC_EDIT_DFSROOT_NAME));
  1299. return FALSE;
  1300. }
  1301. }
  1302. hr = CheckShare(m_lpWizInfo->bstrSelectedServer, bstrCurrentText, &m_lpWizInfo->bShareExists);
  1303. if (FAILED(hr))
  1304. {
  1305. DisplayMessageBoxForHR(hr);
  1306. ::SetFocus(GetDlgItem(IDC_EDIT_DFSROOT_NAME));
  1307. return FALSE;
  1308. } else if (S_FALSE == hr)
  1309. {
  1310. DisplayMessageBoxWithOK(IDS_MSG_ROOTSHARE_NOGOOD, bstrCurrentText);
  1311. ::SetFocus(GetDlgItem(IDC_EDIT_DFSROOT_NAME));
  1312. return FALSE;
  1313. }
  1314. if (m_lpWizInfo->bPostW2KVersion && m_lpWizInfo->bShareExists && !CheckReparsePoint(m_lpWizInfo->bstrSelectedServer, bstrCurrentText))
  1315. {
  1316. DisplayMessageBoxWithOK(IDS_MSG_ROOTSHARE_NOTNTFS5, bstrCurrentText);
  1317. ::SetFocus(GetDlgItem(IDC_EDIT_DFSROOT_NAME));
  1318. return FALSE;
  1319. }
  1320. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrDfsRootName);
  1321. m_lpWizInfo->bstrDfsRootName = bstrCurrentText.Detach();
  1322. // get dfsroot comment
  1323. hr = GetInputText(GetDlgItem(IDC_EDIT_DFSROOT_COMMENT), &bstrCurrentText, &dwTextLength);
  1324. if (FAILED(hr))
  1325. {
  1326. DisplayMessageBoxForHR(hr);
  1327. ::SetFocus(GetDlgItem(IDC_EDIT_DFSROOT_COMMENT));
  1328. return FALSE;
  1329. }
  1330. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrDfsRootComment);
  1331. m_lpWizInfo->bstrDfsRootComment = bstrCurrentText.Detach();
  1332. return TRUE;
  1333. }
  1334. BOOL
  1335. CCreateDfsRootWizPage6::OnWizardBack(
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. Called when the "Back" button is pressed. Resets the values
  1340. Arguments:
  1341. None
  1342. Return value:
  1343. TRUE. to let the user continue to the next page
  1344. FALSE, to not let the user continue ahead.
  1345. --*/
  1346. {
  1347. SAFE_SYSFREESTRING(&m_lpWizInfo->bstrDfsRootName);
  1348. return TRUE;
  1349. }
  1350. // ----------------------------------------------------------------------------
  1351. // CCreateDfsRootWizPage7: Completion page
  1352. // The final page. Just displays a message
  1353. CCreateDfsRootWizPage7::CCreateDfsRootWizPage7(
  1354. IN LPCREATEDFSROOTWIZINFO i_lpWizInfo /* = NULL */
  1355. )
  1356. :m_lpWizInfo(i_lpWizInfo), CQWizardPageImpl<CCreateDfsRootWizPage7> (false)
  1357. /*++
  1358. Routine Description:
  1359. The ctor for CCreateDfsRootWizPage7. Calls the parent ctor and ignores
  1360. the wizard struct.
  1361. Arguments:
  1362. i_lpWizInfo - The wizard information structure. Contains details like
  1363. domain name, server name, etc
  1364. Return value:
  1365. None
  1366. --*/
  1367. {
  1368. }
  1369. BOOL
  1370. CCreateDfsRootWizPage7::OnSetActive()
  1371. /*++
  1372. Routine Description:
  1373. Called when the page is being showed. Sets the buttons to be shown.
  1374. Set the default value of dfsroot name
  1375. Arguments:
  1376. None
  1377. Return value:
  1378. TRUE. Since we handle the message
  1379. --*/
  1380. {
  1381. CWaitCursor wait;
  1382. UpdateLabels(); // Change the labels
  1383. ::PropSheet_SetWizButtons(GetParent(), PSWIZB_FINISH | PSWIZB_BACK);
  1384. ::SetControlFont(m_lpWizInfo->hBigBoldFont, m_hWnd, IDC_COMPLETE_BIG_TITLE);
  1385. ::SetControlFont(m_lpWizInfo->hBoldFont, m_hWnd, IDC_COMPLETE_SMALL_TITLE);
  1386. return TRUE;
  1387. }
  1388. HRESULT
  1389. CCreateDfsRootWizPage7::UpdateLabels(
  1390. )
  1391. /*++
  1392. Routine Description:
  1393. Change the text labels to show previous selections
  1394. Arguments:
  1395. None
  1396. Return value:
  1397. S_OK, on success
  1398. --*/
  1399. {
  1400. /* bug#217602 Remove the Publish checkbox from the New Root Wizard final page (for all types of root)
  1401. if (S_OK == GetSchemaVersionEx(m_lpWizInfo->bstrSelectedServer) &&
  1402. CheckPolicyOnSharePublish())
  1403. {
  1404. CheckDlgButton(IDC_DFSWIZ_PUBLISH, BST_CHECKED);
  1405. } else
  1406. {
  1407. m_lpWizInfo->bPublish = false;
  1408. MyShowWindow(GetDlgItem(IDC_DFSWIZ_PUBLISH), FALSE);
  1409. }
  1410. */
  1411. CComBSTR bstrText;
  1412. if (DFS_TYPE_FTDFS == m_lpWizInfo->DfsType)
  1413. {
  1414. FormatMessageString(&bstrText, 0, IDS_DFSWIZ_TEXT_FTDFS,
  1415. m_lpWizInfo->bstrSelectedDomain,
  1416. m_lpWizInfo->bstrSelectedServer,
  1417. m_lpWizInfo->bstrDfsRootName,
  1418. m_lpWizInfo->bstrDfsRootName);
  1419. } else
  1420. {
  1421. FormatMessageString(&bstrText, 0, IDS_DFSWIZ_TEXT_SADFS,
  1422. m_lpWizInfo->bstrSelectedServer,
  1423. m_lpWizInfo->bstrDfsRootName,
  1424. m_lpWizInfo->bstrDfsRootName);
  1425. }
  1426. SetDlgItemText(IDC_DFSWIZ_TEXT, bstrText);
  1427. return S_OK;
  1428. }
  1429. BOOL
  1430. CCreateDfsRootWizPage7::OnWizardFinish(
  1431. )
  1432. /*++
  1433. Routine Description:
  1434. Called when the user presses the finish button. This is the
  1435. last page in the wizard.
  1436. Arguments:
  1437. None
  1438. Return value:
  1439. TRUE. to let the user continue to the next page
  1440. FALSE, to not let the user continue ahead.
  1441. --*/
  1442. {
  1443. /* bug#217602 Remove the Publish checkbox from the New Root Wizard final page (for all types of root)
  1444. m_lpWizInfo->bPublish = (BST_CHECKED == IsDlgButtonChecked(IDC_DFSWIZ_PUBLISH));
  1445. */
  1446. return (S_OK == _SetUpDfs(m_lpWizInfo));
  1447. }
  1448. BOOL
  1449. CCreateDfsRootWizPage7::OnWizardBack()
  1450. {
  1451. //
  1452. // if share was created by the previous page, blow it away when we go back
  1453. //
  1454. if (!m_lpWizInfo->bShareExists)
  1455. NetShareDel(m_lpWizInfo->bstrSelectedServer, m_lpWizInfo->bstrDfsRootName, 0);
  1456. return TRUE;
  1457. }
  1458. BOOL CCreateDfsRootWizPage7::OnQueryCancel()
  1459. {
  1460. //
  1461. // if share was created by the previous page, blow it away when we cancel the wizard
  1462. //
  1463. if (!m_lpWizInfo->bShareExists)
  1464. NetShareDel(m_lpWizInfo->bstrSelectedServer, m_lpWizInfo->bstrDfsRootName, 0);
  1465. return TRUE; // ok to cancel
  1466. }
  1467. HRESULT _SetUpDfs(
  1468. LPCREATEDFSROOTWIZINFO i_lpWizInfo
  1469. )
  1470. /*++
  1471. Routine Description:
  1472. Helper Function to Setup Dfs, called from wizard and new root replica,
  1473. Finish() method of Page5 if root level replca is created and Next() method of Page6
  1474. for Create New Dfs Root Wizard.
  1475. Arguments:
  1476. i_lpWizInfo - Wizard data.
  1477. Return value:
  1478. S_OK, on success
  1479. --*/
  1480. {
  1481. if (!i_lpWizInfo ||
  1482. !(i_lpWizInfo->bstrSelectedServer) ||
  1483. !(i_lpWizInfo->bstrDfsRootName))
  1484. return(E_INVALIDARG);
  1485. CWaitCursor WaitCursor; // Set cursor to wait
  1486. HRESULT hr = S_OK;
  1487. NET_API_STATUS nstatRetVal = 0;
  1488. // Set up the dfs, based on type.
  1489. if (DFS_TYPE_FTDFS == i_lpWizInfo->DfsType)
  1490. {
  1491. nstatRetVal = NetDfsAddFtRoot(
  1492. i_lpWizInfo->bstrSelectedServer, // Remote Server
  1493. i_lpWizInfo->bstrDfsRootName, // Root Share
  1494. i_lpWizInfo->bstrDfsRootName, // FtDfs Name
  1495. i_lpWizInfo->bstrDfsRootComment, // Comment
  1496. 0 // No Flags.
  1497. );
  1498. } else
  1499. {
  1500. nstatRetVal = NetDfsAddStdRoot(
  1501. i_lpWizInfo->bstrSelectedServer, // Remote Server
  1502. i_lpWizInfo->bstrDfsRootName, // Root Share
  1503. i_lpWizInfo->bstrDfsRootComment, // Comment
  1504. 0 // No Flags.
  1505. );
  1506. }
  1507. if (NERR_Success != nstatRetVal)
  1508. {
  1509. hr = HRESULT_FROM_WIN32(nstatRetVal);
  1510. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_FAILED_TO_CREATE_DFSROOT, i_lpWizInfo->bstrSelectedServer);
  1511. hr = S_FALSE; // failed to create dfsroot, wizard cannot be closed
  1512. } else
  1513. {
  1514. i_lpWizInfo->bDfsSetupSuccess = true;
  1515. /* bug#217602 Remove the Publish checkbox from the New Root Wizard final page (for all types of root)
  1516. if (i_lpWizInfo->bPublish)
  1517. {
  1518. CComBSTR bstrUNCPath = _T("\\\\");
  1519. if (DFS_TYPE_FTDFS == i_lpWizInfo->DfsType)
  1520. {
  1521. bstrUNCPath += i_lpWizInfo->bstrSelectedDomain;
  1522. bstrUNCPath += _T("\\");
  1523. bstrUNCPath += i_lpWizInfo->bstrDfsRootName;
  1524. hr = ModifySharePublishInfoOnFTRoot(
  1525. i_lpWizInfo->bstrSelectedDomain,
  1526. i_lpWizInfo->bstrDfsRootName,
  1527. TRUE,
  1528. bstrUNCPath,
  1529. NULL,
  1530. NULL,
  1531. NULL
  1532. );
  1533. } else
  1534. {
  1535. bstrUNCPath += i_lpWizInfo->bstrSelectedServer;
  1536. bstrUNCPath += _T("\\");
  1537. bstrUNCPath += i_lpWizInfo->bstrSelectedShare;
  1538. hr = ModifySharePublishInfoOnSARoot(
  1539. i_lpWizInfo->bstrSelectedServer,
  1540. i_lpWizInfo->bstrSelectedShare,
  1541. TRUE,
  1542. bstrUNCPath,
  1543. NULL,
  1544. NULL,
  1545. NULL
  1546. );
  1547. if (S_FALSE == hr)
  1548. hr = S_OK; // ignore non-existing object
  1549. }
  1550. if (FAILED(hr))
  1551. {
  1552. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_FAILED_TO_PUBLISH_DFSROOT, bstrUNCPath);
  1553. hr = S_OK; // let wizard finish and close, ignore this error
  1554. } else if (S_FALSE == hr) // no such object
  1555. {
  1556. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_FAILED_TO_PUBLISH_NOROOTOBJ);
  1557. hr = S_OK; // let wizard finish and close, ignore this error
  1558. }
  1559. } */
  1560. }
  1561. return hr;
  1562. }
  1563. HRESULT
  1564. ValidateFolderPath(
  1565. IN LPCTSTR lpszServer,
  1566. IN LPCTSTR lpszPath
  1567. )
  1568. {
  1569. if (!lpszPath || !*lpszPath)
  1570. return E_INVALIDARG;
  1571. HWND hwnd = ::GetActiveWindow();
  1572. HRESULT hr = S_FALSE;
  1573. do {
  1574. if (!IsValidLocalAbsolutePath(lpszPath))
  1575. {
  1576. DisplayMessageBox(hwnd, MB_OK, 0, IDS_INVALID_FOLDER);
  1577. break;
  1578. }
  1579. hr = IsComputerLocal(lpszServer);
  1580. if (FAILED(hr))
  1581. {
  1582. DisplayMessageBox(hwnd, MB_OK, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszPath);
  1583. break;
  1584. }
  1585. BOOL bLocal = (S_OK == hr);
  1586. hr = VerifyDriveLetter(lpszServer, lpszPath);
  1587. if (FAILED(hr))
  1588. {
  1589. DisplayMessageBox(hwnd, MB_OK, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszPath);
  1590. break;
  1591. } else if (S_OK != hr)
  1592. {
  1593. DisplayMessageBox(hwnd, MB_OK, 0, IDS_INVALID_FOLDER);
  1594. break;
  1595. }
  1596. if (!bLocal)
  1597. {
  1598. hr = IsAdminShare(lpszServer, lpszPath);
  1599. if (FAILED(hr))
  1600. {
  1601. DisplayMessageBox(hwnd, MB_OK, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszPath);
  1602. break;
  1603. } else if (S_OK != hr)
  1604. {
  1605. // there is no matching $ shares, hence, no need to call GetFileAttribute, CreateDirectory,
  1606. // assume lpszDir points to an existing directory
  1607. hr = S_OK;
  1608. break;
  1609. }
  1610. }
  1611. CComBSTR bstrFullPath;
  1612. hr = GetFullPath(lpszServer, lpszPath, &bstrFullPath);
  1613. if (FAILED(hr))
  1614. {
  1615. DisplayMessageBox(hwnd, MB_OK, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszPath);
  1616. break;
  1617. }
  1618. hr = IsAnExistingFolder(hwnd, bstrFullPath);
  1619. if (FAILED(hr) || S_OK == hr)
  1620. break;
  1621. if ( IDYES != DisplayMessageBox(hwnd, MB_YESNO, 0, IDS_CREATE_FOLDER, bstrFullPath) )
  1622. {
  1623. hr = S_FALSE;
  1624. break;
  1625. }
  1626. // create the directories layer by layer
  1627. hr = CreateLayeredDirectory(lpszServer, lpszPath);
  1628. if (FAILED(hr))
  1629. {
  1630. DisplayMessageBox(hwnd, MB_OK, hr, IDS_FAILED_TO_CREATE_FOLDER, bstrFullPath);
  1631. break;
  1632. }
  1633. } while (0);
  1634. return hr;
  1635. }