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.

3145 lines
78 KiB

  1. /*++
  2. Module Name:
  3. Utils.cpp
  4. Abstract:
  5. This module contains the declaration for CWaitCursor class.
  6. Contains utility methods which are used throughout the project.
  7. --*/
  8. #include "stdafx.h"
  9. #include "resource.h"
  10. #include "Utils.h"
  11. #include "netutils.h"
  12. #include <dns.h>
  13. HRESULT
  14. CWaitCursor::SetStandardCursor(
  15. IN LPCTSTR i_lpCursorName
  16. )
  17. /*++
  18. Routine Description:
  19. This method sets the cursor to the standard cursor specified.
  20. Usage: SetStandardCursor(IDC_WAIT)
  21. Arguments:
  22. i_lpCursorName - The name of a standard cursor, IDC_WAIT, IDC_ARROW.
  23. --*/
  24. {
  25. RETURN_INVALIDARG_IF_NULL(i_lpCursorName);
  26. HCURSOR m_hcur = ::LoadCursor(NULL, i_lpCursorName);
  27. if (!m_hcur)
  28. return HRESULT_FROM_WIN32(GetLastError());
  29. ::ShowCursor(FALSE);
  30. SetCursor(m_hcur);
  31. ::ShowCursor(TRUE);
  32. return S_OK;
  33. }
  34. BOOL
  35. Is256ColorSupported(
  36. VOID
  37. )
  38. {
  39. /*++
  40. Routine Description:
  41. Determines whether the display supports 256 colors.
  42. Arguments:
  43. None
  44. Return value:
  45. TRUE if display supports 256 colors
  46. FALSE if not.
  47. --*/
  48. BOOL bRetval = FALSE;
  49. HDC hdc = ::GetDC(NULL);
  50. if( hdc )
  51. {
  52. if( ::GetDeviceCaps( hdc, BITSPIXEL ) >= 8 )
  53. {
  54. bRetval = TRUE;
  55. }
  56. ::ReleaseDC(NULL, hdc);
  57. }
  58. return bRetval;
  59. }
  60. VOID
  61. SetControlFont(
  62. IN HFONT hFont,
  63. IN HWND hwnd,
  64. IN INT nId
  65. )
  66. {
  67. /*++
  68. Routine Description:
  69. Sets the text font of a dialog control to the input font.
  70. Arguments:
  71. hFont - The font to use.
  72. hwnd - The parent dialog window.
  73. nId - The control Id.
  74. Return value:
  75. None
  76. --*/
  77. if( hFont )
  78. {
  79. HWND hwndControl = ::GetDlgItem(hwnd, nId);
  80. if( hwndControl )
  81. ::SendMessage(hwndControl, WM_SETFONT, (WPARAM) hFont, MAKELPARAM(TRUE, 0));
  82. }
  83. }
  84. VOID
  85. SetupFonts(
  86. IN HINSTANCE hInstance,
  87. IN HWND hwnd,
  88. IN HFONT *pBigBoldFont,
  89. IN HFONT *pBoldFont
  90. )
  91. {
  92. /*++
  93. Routine Description:
  94. Creates fonts for Wizard Titles.
  95. Arguments:
  96. hInstance - The module instance.
  97. hwnd - The dialog window.
  98. pBigBoldFont- The font for large title.
  99. pBoldFont - The font for small title.
  100. Return value:
  101. None
  102. --*/
  103. NONCLIENTMETRICS ncm = {0};
  104. ncm.cbSize = sizeof(ncm);
  105. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
  106. LOGFONT BigBoldLogFont = ncm.lfMessageFont;
  107. LOGFONT BoldLogFont = ncm.lfMessageFont;
  108. // Create Big Bold Font and Bold Font
  109. BigBoldLogFont.lfWeight = FW_BOLD;
  110. BoldLogFont.lfWeight = FW_BOLD;
  111. TCHAR FontSizeString[24];
  112. INT FontSize;
  113. // Load size and name from resources, since these may change
  114. // from locale to locale based on the size of the system font, etc.
  115. if(!LoadString(hInstance,IDS_LARGEFONTNAME,BigBoldLogFont.lfFaceName,LF_FACESIZE))
  116. {
  117. lstrcpy(BigBoldLogFont.lfFaceName,TEXT("MS Shell Dlg"));
  118. }
  119. if(LoadString(hInstance,IDS_LARGEFONTSIZE,FontSizeString,sizeof(FontSizeString)/sizeof(TCHAR)))
  120. {
  121. FontSize = _tcstoul( FontSizeString, NULL, 10 );
  122. }
  123. else
  124. {
  125. FontSize = 18;
  126. }
  127. HDC hdc = ::GetDC( hwnd );
  128. if( hdc )
  129. {
  130. BigBoldLogFont.lfHeight = 0 - (GetDeviceCaps(hdc,LOGPIXELSY) * FontSize / 72);
  131. if (pBigBoldFont)
  132. *pBigBoldFont = CreateFontIndirect(&BigBoldLogFont);
  133. if (pBoldFont)
  134. *pBoldFont = CreateFontIndirect(&BoldLogFont);
  135. ::ReleaseDC(hwnd,hdc);
  136. }
  137. }
  138. VOID
  139. DestroyFonts(
  140. IN HFONT hBigBoldFont,
  141. IN HFONT hBoldFont
  142. )
  143. {
  144. /*++
  145. Routine Description:
  146. Creates fonts for Wizard Titles.
  147. Arguments:
  148. hBigBoldFont- The font for large title.
  149. hBoldFont - The font for small title.
  150. Return value:
  151. None
  152. --*/
  153. if( hBigBoldFont )
  154. {
  155. DeleteObject( hBigBoldFont );
  156. }
  157. if( hBoldFont )
  158. {
  159. DeleteObject( hBoldFont );
  160. }
  161. }
  162. HRESULT
  163. LoadStringFromResource(
  164. IN const UINT i_uResourceID,
  165. OUT BSTR* o_pbstrReadValue
  166. )
  167. /*++
  168. Routine Description:
  169. This method returns a resource string.
  170. The method no longer uses a fixed string to read the resource.
  171. Inspiration from MFC's CString::LoadString.
  172. Arguments:
  173. i_uResourceID - The resource id
  174. o_pbstrReadValue - The BSTR* into which the value is copied
  175. --*/
  176. {
  177. RETURN_INVALIDARG_IF_NULL(o_pbstrReadValue);
  178. TCHAR szResString[1024];
  179. ULONG uCopiedLen = 0;
  180. szResString[0] = NULL;
  181. // Read the string from the resource
  182. uCopiedLen = ::LoadString(_Module.GetModuleInstance(), i_uResourceID, szResString, 1024);
  183. // If nothing was copied it is flagged as an error
  184. if(uCopiedLen <= 0)
  185. {
  186. return HRESULT_FROM_WIN32(::GetLastError());
  187. }
  188. else
  189. {
  190. *o_pbstrReadValue = ::SysAllocString(szResString);
  191. if (!*o_pbstrReadValue)
  192. return E_OUTOFMEMORY;
  193. }
  194. return S_OK;
  195. }
  196. HRESULT
  197. FormatResourceString(
  198. IN const UINT i_uResourceID,
  199. IN LPCTSTR i_szFirstArg,
  200. OUT BSTR* o_pbstrReadString
  201. )
  202. /*++
  203. Routine Description:
  204. Reads a string from resource, puts the argument into this string and
  205. returns it.
  206. The returned string should be freed using SysFreeString.
  207. Arguments:
  208. i_uResourceID - The resource id of the string to be read. This string
  209. should contain a %1 to allow us to insert the argument
  210. i_szFirstArg - The argument to be inserted
  211. o_pbstrReadString - The string that is returned by the method after processing
  212. --*/
  213. {
  214. RETURN_INVALIDARG_IF_NULL(i_szFirstArg);
  215. RETURN_INVALIDARG_IF_NULL(o_pbstrReadString);
  216. CComBSTR bstrResString;
  217. LPTSTR lpszFormatedMessage = NULL;
  218. HRESULT hr = LoadStringFromResource(i_uResourceID, &bstrResString);
  219. RETURN_IF_FAILED(hr);
  220. // Create a new string using the argument and the res string
  221. int iBytes = ::FormatMessage(
  222. FORMAT_MESSAGE_FROM_STRING |
  223. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  224. FORMAT_MESSAGE_ALLOCATE_BUFFER, // Format a string with %1, %2, etc
  225. bstrResString, // Input buffer with a %1
  226. 0, // Message id. None
  227. 0, // Language id. Nothing particular
  228. (LPTSTR)&lpszFormatedMessage, // Output buffer
  229. 0,
  230. (va_list*)&i_szFirstArg // List of arguments. Only 1 right now
  231. );
  232. if (0 == iBytes)
  233. {
  234. return HRESULT_FROM_WIN32(GetLastError());
  235. }
  236. else
  237. {
  238. CComBSTR bstrRet(lpszFormatedMessage);
  239. *o_pbstrReadString = bstrRet.Copy();
  240. LocalFree(lpszFormatedMessage);
  241. return S_OK;
  242. }
  243. }
  244. HRESULT
  245. GetMessage(
  246. OUT BSTR* o_pbstrMsg,
  247. IN DWORD dwErr,
  248. IN UINT iStringId, // OPTIONAL: String resource Id
  249. ...) // Optional arguments
  250. {
  251. RETURN_INVALIDARG_IF_NULL(o_pbstrMsg);
  252. _ASSERT(dwErr != 0 || iStringId != 0); // One of the parameter must be non-zero
  253. HRESULT hr = S_OK;
  254. TCHAR szString[1024];
  255. CComBSTR bstrErrorMsg, bstrResourceString, bstrMsg;
  256. if (dwErr)
  257. hr = GetErrorMessage(dwErr, &bstrErrorMsg);
  258. if (SUCCEEDED(hr))
  259. {
  260. if (iStringId == 0)
  261. {
  262. bstrMsg = bstrErrorMsg;
  263. }
  264. else
  265. {
  266. ::LoadString(_Module.GetModuleInstance(), iStringId,
  267. szString, sizeof(szString)/sizeof(TCHAR));
  268. va_list arglist;
  269. va_start(arglist, iStringId);
  270. LPTSTR lpBuffer = NULL;
  271. DWORD dwRet = ::FormatMessage(
  272. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  273. szString,
  274. 0, // dwMessageId
  275. 0, // dwLanguageId, ignored
  276. (LPTSTR)&lpBuffer,
  277. 0, // nSize
  278. &arglist);
  279. va_end(arglist);
  280. if (dwRet == 0)
  281. {
  282. hr = HRESULT_FROM_WIN32(GetLastError());
  283. }
  284. else
  285. {
  286. bstrMsg = lpBuffer;
  287. if (dwErr)
  288. bstrMsg += bstrErrorMsg;
  289. LocalFree(lpBuffer);
  290. }
  291. }
  292. }
  293. if (FAILED(hr))
  294. {
  295. // Failed to retrieve the proper message, report the failure directly to user
  296. _stprintf(szString, _T("0x%x"), hr);
  297. bstrMsg = szString;
  298. }
  299. *o_pbstrMsg = bstrMsg.Copy();
  300. if (!*o_pbstrMsg)
  301. return E_OUTOFMEMORY;
  302. return S_OK;
  303. }
  304. int
  305. DisplayMessageBox(
  306. IN HWND hwndParent,
  307. IN UINT uType, // style of message box
  308. IN DWORD dwErr,
  309. IN UINT iStringId, // OPTIONAL: String resource Id
  310. ...) // Optional arguments
  311. {
  312. _ASSERT(dwErr != 0 || iStringId != 0); // One of the parameter must be non-zero
  313. HRESULT hr = S_OK;
  314. TCHAR szCaption[1024], szString[1024];
  315. CComBSTR bstrErrorMsg, bstrResourceString, bstrMsg;
  316. ::LoadString(_Module.GetModuleInstance(), IDS_APPLICATION_NAME,
  317. szCaption, sizeof(szCaption)/sizeof(TCHAR));
  318. if (dwErr)
  319. hr = GetErrorMessage(dwErr, &bstrErrorMsg);
  320. if (SUCCEEDED(hr))
  321. {
  322. if (iStringId == 0)
  323. {
  324. bstrMsg = bstrErrorMsg;
  325. }
  326. else
  327. {
  328. ::LoadString(_Module.GetModuleInstance(), iStringId,
  329. szString, sizeof(szString)/sizeof(TCHAR));
  330. va_list arglist;
  331. va_start(arglist, iStringId);
  332. LPTSTR lpBuffer = NULL;
  333. DWORD dwRet = ::FormatMessage(
  334. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  335. szString,
  336. 0, // dwMessageId
  337. 0, // dwLanguageId, ignored
  338. (LPTSTR)&lpBuffer,
  339. 0, // nSize
  340. &arglist);
  341. va_end(arglist);
  342. if (dwRet == 0)
  343. {
  344. hr = HRESULT_FROM_WIN32(GetLastError());
  345. }
  346. else
  347. {
  348. bstrMsg = lpBuffer;
  349. if (dwErr)
  350. bstrMsg += bstrErrorMsg;
  351. LocalFree(lpBuffer);
  352. }
  353. }
  354. }
  355. if (FAILED(hr))
  356. {
  357. // Failed to retrieve the proper message, report the failure directly to user
  358. _stprintf(szString, _T("0x%x"), hr);
  359. bstrMsg = szString;
  360. }
  361. CThemeContextActivator activator;
  362. return ::MessageBox(hwndParent, bstrMsg, szCaption, uType);
  363. }
  364. HRESULT
  365. DisplayMessageBoxWithOK(
  366. IN const int i_iMessageResID,
  367. IN const BSTR i_bstrArgument/* = NULL*/
  368. )
  369. {
  370. if (i_bstrArgument)
  371. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, i_iMessageResID, i_bstrArgument);
  372. else
  373. DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, i_iMessageResID);
  374. return S_OK;
  375. }
  376. HRESULT
  377. DisplayMessageBoxForHR(
  378. IN HRESULT i_hr
  379. )
  380. {
  381. DisplayMessageBox(::GetActiveWindow(), MB_OK, i_hr, 0);
  382. return S_OK;
  383. }
  384. HRESULT CreateSmallImageList(
  385. IN HINSTANCE i_hInstance,
  386. IN int* i_pIconID,
  387. IN const int i_nNumOfIcons,
  388. OUT HIMAGELIST* o_phImageList
  389. )
  390. {
  391. RETURN_INVALIDARG_IF_NULL(i_hInstance);
  392. HRESULT hr = S_OK;
  393. HIMAGELIST hImageList = ImageList_Create(
  394. GetSystemMetrics(SM_CXSMICON),
  395. GetSystemMetrics(SM_CYSMICON),
  396. ILC_COLORDDB | ILC_MASK,
  397. i_nNumOfIcons,
  398. 0);
  399. if (!hImageList)
  400. {
  401. hr = HRESULT_FROM_WIN32(GetLastError());
  402. return hr;
  403. }
  404. int i = 0;
  405. for (i = 0; i < i_nNumOfIcons; i++)
  406. {
  407. HICON hIcon = LoadIcon(i_hInstance, MAKEINTRESOURCE(i_pIconID[i]));
  408. if (!hIcon)
  409. {
  410. hr = HRESULT_FROM_WIN32(GetLastError());
  411. break;
  412. }
  413. if (-1 == ImageList_AddIcon(hImageList, hIcon))
  414. {
  415. hr = HRESULT_FROM_WIN32(GetLastError());
  416. break;
  417. }
  418. }
  419. if (FAILED(hr))
  420. {
  421. if (hImageList)
  422. ImageList_Destroy(hImageList);
  423. } else
  424. {
  425. if (o_phImageList)
  426. *o_phImageList = hImageList;
  427. }
  428. return hr;
  429. }
  430. HRESULT
  431. InsertIntoListView(
  432. IN HWND i_hwndList,
  433. IN LPCTSTR i_szItemText,
  434. IN int i_iImageIndex /*= 0*/
  435. )
  436. /*++
  437. Routine Description:
  438. Insert and item into the listview. The image index for the item is optional
  439. while the item text is necessary
  440. Arguments:
  441. i_hwndList - HWND of the list view
  442. i_szItemText - The text for the item
  443. i_iImageIndex - The image index for the item. Default is 0.
  444. --*/
  445. {
  446. RETURN_INVALIDARG_IF_NULL(i_hwndList);
  447. RETURN_INVALIDARG_IF_NULL(i_szItemText);
  448. LVITEM lvi;
  449. ZeroMemory(&lvi, sizeof(lvi));
  450. lvi.mask = LVIF_TEXT | LVIF_IMAGE;
  451. lvi.pszText = (LPTSTR)i_szItemText;
  452. lvi.iImage = i_iImageIndex;
  453. int iItemIndex = ListView_InsertItem(i_hwndList, &lvi); // Insert the item into the list view
  454. if ( -1 == iItemIndex)
  455. return E_FAIL;
  456. return S_OK;
  457. }
  458. HRESULT
  459. GetListViewItemText(
  460. IN HWND i_hwndListView,
  461. IN int i_iItemID,
  462. OUT BSTR* o_pbstrItemText
  463. )
  464. /*++
  465. Routine Description:
  466. Needed to write a method as the standard one has a slight problem.
  467. Here, we make sure that string allocated is of proper length.
  468. Arguments:
  469. i_hwndList - HWND of the list view
  470. i_iItemID - The ID of the item to be read
  471. o_pbstrItemText - The item text returned by this method
  472. --*/
  473. {
  474. RETURN_INVALIDARG_IF_NULL(i_hwndListView);
  475. RETURN_INVALIDARG_IF_NULL(o_pbstrItemText);
  476. *o_pbstrItemText = NULL;
  477. if (-1 == i_iItemID)
  478. return S_FALSE; // not a valid item index
  479. LRESULT iReadTextLen = 0;
  480. TCHAR szText[1024];
  481. LVITEM lvItem;
  482. ZeroMemory(&lvItem, sizeof(lvItem));
  483. lvItem.mask = LVIF_TEXT; // Initialize the LV item
  484. lvItem.iItem = i_iItemID;
  485. lvItem.pszText = szText;
  486. lvItem.cchTextMax = 1024;
  487. // Get the LV item text
  488. iReadTextLen = SendMessage(i_hwndListView, LVM_GETITEMTEXT, lvItem.iItem, (LPARAM)&lvItem);
  489. if(iReadTextLen <= 0)
  490. {
  491. return HRESULT_FROM_WIN32(::GetLastError());
  492. }
  493. else
  494. {
  495. *o_pbstrItemText = SysAllocString(szText);
  496. if (!*o_pbstrItemText)
  497. return E_OUTOFMEMORY;
  498. }
  499. return S_OK;
  500. }
  501. HRESULT GetComboBoxText(
  502. IN HWND i_hwndCombo,
  503. OUT BSTR* o_pbstrText
  504. )
  505. {
  506. RETURN_INVALIDARG_IF_NULL(o_pbstrText);
  507. int index = ::SendMessage(i_hwndCombo, CB_GETCURSEL, 0, 0);
  508. int len = ::SendMessage(i_hwndCombo, CB_GETLBTEXTLEN, index, 0);
  509. if (!len)
  510. return S_FALSE; // no text
  511. PTSTR pszText = (PTSTR)calloc(len + 1, sizeof(TCHAR));
  512. RETURN_OUTOFMEMORY_IF_NULL(pszText);
  513. ::SendMessage(i_hwndCombo, CB_GETLBTEXT, index, (LPARAM)pszText);
  514. *o_pbstrText = SysAllocString(pszText);
  515. free(pszText);
  516. RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrText);
  517. return S_OK;
  518. }
  519. HRESULT
  520. EnableToolbarButtons(
  521. IN const LPTOOLBAR i_lpToolbar,
  522. IN const INT i_iFirstButtonID,
  523. IN const INT i_iLastButtonID,
  524. IN const BOOL i_bEnableState
  525. )
  526. /*++
  527. Routine Description:
  528. Enable or disable the toolbar buttons
  529. Arguments:
  530. i_lpToolbar - Callback used to do toolbar related operations
  531. i_iFirstButtonID - The ID of the first button to be operated on.
  532. i_iLastButtonID - The ID of the last button to be operated on.
  533. i_bEnableState - The new state for enabled. Can be TRUE or FALSE
  534. --*/
  535. {
  536. RETURN_INVALIDARG_IF_NULL(i_lpToolbar);
  537. RETURN_INVALIDARG_IF_TRUE((i_iLastButtonID - i_iFirstButtonID) < 0);
  538. for (int iCommandID = i_iFirstButtonID; iCommandID <= i_iLastButtonID; iCommandID++ )
  539. {
  540. i_lpToolbar->SetButtonState(iCommandID, ENABLED, i_bEnableState);
  541. i_lpToolbar->SetButtonState(iCommandID, HIDDEN, !i_bEnableState);
  542. }
  543. return S_OK;
  544. }
  545. HRESULT
  546. AddBitmapToToolbar(
  547. IN const LPTOOLBAR i_lpToolbar,
  548. IN const INT i_iBitmapResource
  549. )
  550. /*++
  551. Routine Description:
  552. Creates and adds the bitmap to the toolbar.
  553. This bitmap is used by the toolbar buttons.
  554. Arguments:
  555. i_lpToolbar - Callback used to do toolbar related operations
  556. i_iBitmapResource - The resource id of the bitmap.
  557. --*/
  558. {
  559. RETURN_INVALIDARG_IF_NULL(i_lpToolbar);
  560. // Load the bitmap from resource
  561. HBITMAP hBitmap = (HBITMAP)LoadImage(_Module.GetModuleInstance(), MAKEINTRESOURCE(i_iBitmapResource),
  562. IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
  563. if(!hBitmap)
  564. return HRESULT_FROM_WIN32(GetLastError());
  565. HRESULT hr = S_FALSE;
  566. BITMAP bmpRec;
  567. if (GetObject(hBitmap, sizeof(bmpRec), &bmpRec))
  568. {
  569. if (bmpRec.bmHeight > 0)
  570. {
  571. int icyBitmap = bmpRec.bmHeight;
  572. int icxBitmap = icyBitmap; // Since the bitmaps are squares
  573. int iNoOfBitmaps = bmpRec.bmWidth / bmpRec.bmHeight;
  574. hr = i_lpToolbar->AddBitmap(iNoOfBitmaps, hBitmap, icxBitmap, icyBitmap,
  575. RGB(255, 0, 255) // Pink is the mask color
  576. );
  577. }
  578. }
  579. else
  580. {
  581. hr = HRESULT_FROM_WIN32(GetLastError());
  582. }
  583. DeleteObject(hBitmap);
  584. return hr;
  585. }
  586. HRESULT GetInputText(
  587. IN HWND hwnd,
  588. OUT BSTR* o_pbstrText,
  589. OUT DWORD* o_pdwTextLength
  590. )
  591. {
  592. _ASSERT(hwnd);
  593. _ASSERT(o_pbstrText);
  594. _ASSERT(o_pdwTextLength);
  595. *o_pdwTextLength = 0;
  596. *o_pbstrText = NULL;
  597. HRESULT hr = S_OK;
  598. int nLength = GetWindowTextLength(hwnd);
  599. if (nLength == 0)
  600. {
  601. *o_pbstrText = SysAllocString(_T(""));
  602. } else
  603. {
  604. PTSTR ptszText = (PTSTR)calloc(nLength+1, sizeof(TCHAR));
  605. if (ptszText)
  606. {
  607. nLength = GetWindowText(hwnd, ptszText, nLength+1);
  608. // trim right
  609. PTSTR p = NULL;
  610. for (p = ptszText + nLength - 1; p >= ptszText && _istspace(*p); p--)
  611. {
  612. *p = _T('\0');
  613. }
  614. // trim left
  615. for (p = ptszText; *p && _istspace(*p); p++)
  616. ;
  617. *o_pdwTextLength = _tcslen(p);
  618. *o_pbstrText = SysAllocString(p);
  619. free(ptszText);
  620. }
  621. }
  622. if (!*o_pbstrText)
  623. hr = E_OUTOFMEMORY;
  624. return hr;
  625. }
  626. // return FALSE, if value is not present or 0
  627. // return TRUE, if value is present and non-zero
  628. BOOL CheckRegKey()
  629. {
  630. BOOL bReturn = FALSE;
  631. LONG lErr = ERROR_SUCCESS;
  632. HKEY hKey = 0;
  633. lErr = RegOpenKeyEx(
  634. HKEY_LOCAL_MACHINE,
  635. _T("System\\CurrentControlSet\\Services\\Dfs"),
  636. 0,
  637. KEY_QUERY_VALUE,
  638. &hKey);
  639. if (ERROR_SUCCESS == lErr)
  640. {
  641. DWORD dwType;
  642. DWORD dwData = 0;
  643. DWORD dwSize = sizeof(DWORD);
  644. lErr = RegQueryValueEx(hKey, _T("DfsDnsConfig"), 0, &dwType, (LPBYTE)&dwData, &dwSize);
  645. if (ERROR_SUCCESS == lErr && REG_DWORD == dwType && 0 != (dwData & 0x1))
  646. bReturn = TRUE;
  647. RegCloseKey(hKey);
  648. }
  649. return bReturn;
  650. }
  651. // called when adding a new junction point or adding a new replica member
  652. BOOL
  653. ValidateNetPath(
  654. IN BSTR i_bstrNetPath,
  655. OUT BSTR *o_pbstrServer,
  656. OUT BSTR *o_pbstrShare
  657. )
  658. {
  659. HRESULT hr = S_OK;
  660. BOOL bReturn = FALSE;
  661. CComBSTR bstrServer;
  662. CComBSTR bstrShare;
  663. HWND hwnd = ::GetActiveWindow();
  664. do {
  665. // Check UNC path
  666. hr = CheckUNCPath(i_bstrNetPath);
  667. if (S_OK != hr)
  668. {
  669. DisplayMessageBox(hwnd, MB_OK | MB_ICONSTOP, 0, IDS_NOT_UNC_PATH, i_bstrNetPath);
  670. break;
  671. }
  672. CComBSTR bstrNetPath = i_bstrNetPath; // make a copy
  673. // remove the ending backslash if any
  674. TCHAR *p = bstrNetPath + lstrlen(bstrNetPath) - 1;
  675. if (*p == _T('\\'))
  676. *p = _T('\0');
  677. /*
  678. LinanT 6/2/2000:
  679. a) add "check if path is contactable", warn user
  680. */
  681. DWORD dwRet = GetFileAttributes(bstrNetPath);
  682. if (-1 == dwRet)
  683. {
  684. if (IDYES != DisplayMessageBox(hwnd, MB_YESNO, GetLastError(), IDS_NETPATH_ADD_ANYWAY, i_bstrNetPath))
  685. break;
  686. } else if (!(dwRet & FILE_ATTRIBUTE_DIRECTORY))
  687. {
  688. DisplayMessageBox(hwnd, MB_OK, 0, IDS_PATH_NOT_FOLDER, i_bstrNetPath);
  689. break;
  690. }
  691. PTSTR lpszServer = bstrNetPath + 2; // skip the first "\\"
  692. RETURN_INVALIDARG_IF_NULL(lpszServer);
  693. PTSTR lpszShare = _tcschr(lpszServer, _T('\\'));
  694. RETURN_INVALIDARG_IF_NULL(lpszShare);
  695. *lpszShare++ = _T('\0');
  696. bstrShare = lpszShare;
  697. /*
  698. LinanT 3/19/99:
  699. a) remove "check if path is contactable", leave it to dfs API
  700. b) remove "get dns server name":
  701. c) add code to do simple check for dots, if non-dns-look, pop up dialog for confirmation
  702. */
  703. bstrServer = lpszServer;
  704. if ( CheckRegKey() &&
  705. NULL == _tcschr(bstrServer, _T('.')) &&
  706. IDYES != DisplayMessageBox(hwnd, MB_YESNO, 0,
  707. IDS_NON_DNSNAME_ADD_ANYWAY, i_bstrNetPath) )
  708. {
  709. break;
  710. }
  711. bReturn = TRUE;
  712. } while (0);
  713. if (bReturn)
  714. {
  715. if ( !(*o_pbstrServer = bstrServer.Copy()) ||
  716. !(*o_pbstrShare = bstrShare.Copy()) )
  717. {
  718. bReturn = FALSE;
  719. DisplayMessageBox(hwnd, MB_OK | MB_ICONSTOP, (DWORD)E_OUTOFMEMORY, 0);
  720. }
  721. }
  722. return bReturn;
  723. }
  724. /////////////////////////////////////////////////////////////////////
  725. // IsLocalComputername(): cut & pasted from ..\..\framewrk\islocal.cpp
  726. //
  727. TCHAR g_achComputerName[ MAX_COMPUTERNAME_LENGTH+1 ] = _T("");
  728. TCHAR g_achDnsComputerName[DNS_MAX_NAME_BUFFER_LENGTH] = _T("");
  729. BOOL
  730. IsLocalComputername( IN LPCTSTR pszMachineName )
  731. {
  732. if ( NULL == pszMachineName || _T('\0') == pszMachineName[0] )
  733. return TRUE;
  734. if ( _T('\\') == pszMachineName[0] && _T('\\') == pszMachineName[1] )
  735. pszMachineName += 2;
  736. // compare with the local computer netbios name
  737. if ( _T('\0') == g_achComputerName[0] )
  738. {
  739. DWORD dwSize = sizeof(g_achComputerName)/sizeof(TCHAR);
  740. GetComputerName( g_achComputerName, &dwSize );
  741. _ASSERT(_T('\0') != g_achComputerName[0]);
  742. }
  743. if ( 0 == lstrcmpi( pszMachineName, g_achComputerName ) )
  744. {
  745. return TRUE;
  746. }
  747. // compare with the local DNS name
  748. // SKwan confirms that ComputerNameDnsFullyQualified is the right name to use
  749. // when clustering is taken into account
  750. if ( _T('\0') == g_achDnsComputerName )
  751. {
  752. DWORD dwSize = sizeof(g_achDnsComputerName)/sizeof(TCHAR);
  753. GetComputerNameEx(
  754. ComputerNameDnsFullyQualified,
  755. g_achDnsComputerName,
  756. &dwSize );
  757. _ASSERT( _T('\0') != g_achDnsComputerName[0] );
  758. }
  759. if ( 0 == lstrcmpi( pszMachineName, g_achDnsComputerName ) )
  760. {
  761. return TRUE;
  762. }
  763. return FALSE;
  764. } // IsLocalComputername()
  765. // S_OK: a local computer
  766. // S_FALSE: not a local computer
  767. HRESULT
  768. IsComputerLocal(
  769. IN LPCTSTR lpszServer
  770. )
  771. {
  772. return (IsLocalComputername(lpszServer) ? S_OK : S_FALSE);
  773. }
  774. BOOL
  775. IsValidLocalAbsolutePath(
  776. IN LPCTSTR lpszPath
  777. )
  778. {
  779. if (!lpszPath ||
  780. _tcslen(lpszPath) < 3 ||
  781. lpszPath[1] != _T(':') ||
  782. lpszPath[2] != _T('\\') ||
  783. !(*lpszPath >= _T('a') && *lpszPath <= _T('z') || *lpszPath >= _T('A') && *lpszPath <= _T('Z')))
  784. {
  785. return FALSE;
  786. }
  787. return TRUE;
  788. }
  789. HRESULT
  790. GetFullPath(
  791. IN LPCTSTR lpszServer,
  792. IN LPCTSTR lpszPath,
  793. OUT BSTR *o_pbstrFullPath
  794. )
  795. {
  796. _ASSERT(IsValidLocalAbsolutePath(lpszPath));
  797. HRESULT hr = IsComputerLocal(lpszServer);
  798. if (FAILED(hr))
  799. return hr;
  800. BOOL bLocal = (S_OK == hr);
  801. CComBSTR bstrTemp;
  802. if (bLocal)
  803. {
  804. bstrTemp = lpszPath;
  805. } else
  806. {
  807. if (mylstrncmpi(_T("\\\\"), lpszServer, 2))
  808. {
  809. bstrTemp = _T("\\\\");
  810. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrTemp);
  811. bstrTemp += lpszServer;
  812. } else
  813. {
  814. bstrTemp = lpszServer;
  815. }
  816. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrTemp);
  817. bstrTemp += _T("\\");
  818. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrTemp);
  819. bstrTemp += lpszPath;
  820. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrTemp);
  821. LPTSTR p = _tcschr(bstrTemp, _T(':'));
  822. RETURN_INVALIDARG_IF_NULL(p);
  823. *p = _T('$');
  824. }
  825. *o_pbstrFullPath = bstrTemp.Detach();
  826. return hr;
  827. }
  828. // Purpose: verify if the specified drive belongs to a list of disk drives on the server
  829. // Return:
  830. // S_OK: yes
  831. // S_FALSE: no
  832. // hr: some error happened
  833. HRESULT
  834. VerifyDriveLetter(
  835. IN LPCTSTR lpszServer,
  836. IN LPCTSTR lpszPath
  837. )
  838. {
  839. _ASSERT(IsValidLocalAbsolutePath(lpszPath));
  840. HRESULT hr = S_FALSE;
  841. LPBYTE pBuffer = NULL;
  842. DWORD dwEntriesRead = 0;
  843. DWORD dwTotalEntries = 0;
  844. DWORD dwRet = NetServerDiskEnum(
  845. const_cast<LPTSTR>(lpszServer),
  846. 0,
  847. &pBuffer,
  848. (DWORD)-1,
  849. &dwEntriesRead,
  850. &dwTotalEntries,
  851. NULL);
  852. if (NERR_Success == dwRet)
  853. {
  854. LPTSTR pDrive = (LPTSTR)pBuffer;
  855. for (UINT i=0; i<dwEntriesRead; i++)
  856. {
  857. if (!mylstrncmpi(pDrive, lpszPath, 1))
  858. {
  859. hr = S_OK;
  860. break;
  861. }
  862. pDrive += 3;
  863. }
  864. NetApiBufferFree(pBuffer);
  865. } else
  866. {
  867. hr = HRESULT_FROM_WIN32(dwRet);
  868. }
  869. return hr;
  870. }
  871. // Purpose: is there a related admin $ share
  872. // Return:
  873. // S_OK: yes
  874. // S_FALSE: no
  875. // hr: some error happened
  876. HRESULT
  877. IsAdminShare(
  878. IN LPCTSTR lpszServer,
  879. IN LPCTSTR lpszPath
  880. )
  881. {
  882. _ASSERT(S_OK != IsComputerLocal(lpszServer));
  883. _ASSERT(IsValidLocalAbsolutePath(lpszPath));
  884. HRESULT hr = S_FALSE;
  885. LPBYTE pBuffer = NULL;
  886. DWORD dwEntriesRead = 0;
  887. DWORD dwTotalEntries = 0;
  888. DWORD dwRet = NetShareEnum(
  889. const_cast<LPTSTR>(lpszServer),
  890. 1,
  891. &pBuffer,
  892. (DWORD)-1,
  893. &dwEntriesRead,
  894. &dwTotalEntries,
  895. NULL);
  896. if (NERR_Success == dwRet)
  897. {
  898. PSHARE_INFO_1 pShareInfo = (PSHARE_INFO_1)pBuffer;
  899. for (UINT i=0; i<dwEntriesRead; i++)
  900. {
  901. if ( (pShareInfo->shi1_type & STYPE_SPECIAL) &&
  902. _tcslen(pShareInfo->shi1_netname) == 2 &&
  903. *(pShareInfo->shi1_netname + 1) == _T('$') &&
  904. !mylstrncmpi(pShareInfo->shi1_netname, lpszPath, 1) )
  905. {
  906. hr = S_OK;
  907. break;
  908. }
  909. pShareInfo++;
  910. }
  911. NetApiBufferFree(pBuffer);
  912. } else
  913. {
  914. hr = HRESULT_FROM_WIN32(dwRet);
  915. }
  916. return hr;
  917. }
  918. //+---------------------------------------------------------------------------
  919. //
  920. // Function: IsAnExistingFolder
  921. //
  922. // Synopsis: Check if pszPath is pointing at an existing folder.
  923. //
  924. // S_OK: The specified path points to an existing folder.
  925. // S_FALSE: The specified path doesn't point to an existing folder.
  926. // hr: Failed to get info on the specified path, or
  927. // the path exists but doesn't point to a folder.
  928. // The function reports error msg for both failures if desired.
  929. //----------------------------------------------------------------------------
  930. HRESULT
  931. IsAnExistingFolder(
  932. IN HWND hwnd,
  933. IN LPCTSTR pszPath,
  934. IN BOOL bDisplayErrorMsg
  935. )
  936. {
  937. if (!hwnd)
  938. hwnd = GetActiveWindow();
  939. HRESULT hr = S_OK;
  940. DWORD dwRet = GetFileAttributes(pszPath);
  941. if (-1 == dwRet)
  942. {
  943. DWORD dwErr = GetLastError();
  944. if (ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr)
  945. {
  946. // the specified path doesn't exist
  947. hr = S_FALSE;
  948. }
  949. else
  950. {
  951. if (bDisplayErrorMsg)
  952. DisplayMessageBox(hwnd, MB_OK, dwErr, IDS_FAILED_TO_GETINFO_FOLDER, pszPath);
  953. hr = HRESULT_FROM_WIN32(dwErr);
  954. }
  955. } else if ( 0 == (dwRet & FILE_ATTRIBUTE_DIRECTORY) )
  956. {
  957. // the specified path is not pointing to a folder
  958. if (bDisplayErrorMsg)
  959. DisplayMessageBox(hwnd, MB_OK, 0, IDS_PATH_NOT_FOLDER, pszPath);
  960. hr = E_FAIL;
  961. }
  962. return hr;
  963. }
  964. // create the directories layer by layer
  965. HRESULT
  966. CreateLayeredDirectory(
  967. IN LPCTSTR lpszServer,
  968. IN LPCTSTR lpszPath
  969. )
  970. {
  971. _ASSERT(IsValidLocalAbsolutePath(lpszPath));
  972. HRESULT hr = IsComputerLocal(lpszServer);
  973. if (FAILED(hr))
  974. return hr;
  975. BOOL bLocal = (S_OK == hr);
  976. CComBSTR bstrFullPath;
  977. hr = GetFullPath(lpszServer, lpszPath, &bstrFullPath);
  978. if (FAILED(hr))
  979. return hr;
  980. hr = IsAnExistingFolder(NULL, bstrFullPath, FALSE);
  981. _ASSERT(S_FALSE == hr);
  982. LPTSTR pch = _tcschr(bstrFullPath, (bLocal ? _T(':') : _T('$')));
  983. _ASSERT(pch);
  984. LPTSTR pszPath = bstrFullPath; // e.g., "C:\a\b\c\d" or "\\server\share\a\b\c\d"
  985. LPTSTR pszLeft = pch + 2; // e.g., "a\b\c\d"
  986. LPTSTR pszRight = NULL;
  987. _ASSERT(pszLeft && *pszLeft);
  988. //
  989. // this loop will find out the 1st non-existing sub-dir to create, and
  990. // the rest of non-existing sub-dirs
  991. //
  992. while (pch = _tcsrchr(pszLeft, _T('\\'))) // backwards search for _T('\\')
  993. {
  994. *pch = _T('\0');
  995. hr = IsAnExistingFolder(NULL, pszPath);
  996. if (FAILED(hr))
  997. return S_FALSE; // errormsg has already been reported by IsAnExistingFolder().
  998. if (S_OK == hr)
  999. {
  1000. //
  1001. // pszPath is pointing to the parent dir of the 1st non-existing sub-dir.
  1002. // Once we restore the _T('\\'), pszPath will point at the 1st non-existing subdir.
  1003. //
  1004. *pch = _T('\\');
  1005. break;
  1006. } else
  1007. {
  1008. //
  1009. // pszPath is pointing to a non-existing folder, continue with the loop.
  1010. //
  1011. if (pszRight)
  1012. *(pszRight - 1) = _T('\\');
  1013. pszRight = pch + 1;
  1014. }
  1015. }
  1016. // We're ready to create directories:
  1017. // pszPath points to the 1st non-existing dir, e.g., "C:\a\b" or "\\server\share\a\b"
  1018. // pszRight points to the rest of non-existing sub dirs, e.g., "c\d"
  1019. //
  1020. do
  1021. {
  1022. if (!CreateDirectory(pszPath, NULL))
  1023. return HRESULT_FROM_WIN32(GetLastError());
  1024. if (!pszRight || !*pszRight)
  1025. break;
  1026. *(pszRight - 1) = _T('\\');
  1027. if (pch = _tcschr(pszRight, _T('\\'))) // forward search for _T('\\')
  1028. {
  1029. *pch = _T('\0');
  1030. pszRight = pch + 1;
  1031. } else
  1032. {
  1033. pszRight = NULL;
  1034. }
  1035. } while (1);
  1036. return S_OK;
  1037. }
  1038. HRESULT
  1039. BrowseNetworkPath(
  1040. IN HWND hwndParent,
  1041. OUT BSTR *o_pbstrPath
  1042. )
  1043. {
  1044. _ASSERT(o_pbstrPath);
  1045. HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  1046. if (SUCCEEDED(hr))
  1047. {
  1048. do
  1049. {
  1050. CComPtr<IMalloc> pMalloc;
  1051. hr = SHGetMalloc(&pMalloc);
  1052. if (FAILED(hr))
  1053. break;
  1054. CComBSTR bstrDlgLabel;
  1055. hr = LoadStringFromResource(IDS_BROWSE_NET_DLG, &bstrDlgLabel);
  1056. if (FAILED(hr))
  1057. break;
  1058. LPITEMIDLIST pItemIdList = NULL;
  1059. hr = SHGetSpecialFolderLocation(NULL, CSIDL_NETWORK, &pItemIdList);
  1060. if (FAILED(hr))
  1061. break;
  1062. BROWSEINFO bi = {hwndParent,
  1063. pItemIdList,
  1064. 0,
  1065. bstrDlgLabel,
  1066. BIF_RETURNONLYFSDIRS,
  1067. NULL,
  1068. NULL,
  1069. 0};
  1070. LPITEMIDLIST pItemIdListBr = SHBrowseForFolder(&bi);
  1071. if (!pItemIdListBr)
  1072. {
  1073. hr = S_FALSE; // user clicked Cancel
  1074. } else
  1075. {
  1076. CComBSTR bstrPath;
  1077. TCHAR szPath[MAX_PATH] = _T("\0");
  1078. SHGetPathFromIDList(pItemIdListBr, szPath);
  1079. //
  1080. // try to use Dns server name
  1081. //
  1082. if (CheckRegKey() &&
  1083. S_OK == CheckUNCPath(szPath))
  1084. {
  1085. PTSTR lpszServer = szPath + 2; // skip the first "\\"
  1086. PTSTR lpszShare = _tcschr(lpszServer, _T('\\'));
  1087. CComBSTR bstrServer = CComBSTR(lpszShare - lpszServer, lpszServer);
  1088. CComBSTR bstrDnsServer;
  1089. hr = GetServerInfo(bstrServer,
  1090. NULL, // Domain
  1091. NULL, // NetbiosName
  1092. NULL, // bValidDSObject
  1093. &bstrDnsServer);
  1094. if (S_OK == hr)
  1095. {
  1096. bstrPath = _T("\\\\");
  1097. bstrPath += bstrDnsServer;
  1098. bstrPath += lpszShare;
  1099. } else
  1100. {
  1101. hr = S_OK; // reset hr
  1102. bstrPath = szPath;
  1103. }
  1104. } else
  1105. {
  1106. bstrPath = szPath;
  1107. }
  1108. *o_pbstrPath = bstrPath.Detach();
  1109. pMalloc->Free(pItemIdListBr);
  1110. }
  1111. pMalloc->Free(pItemIdList);
  1112. } while (0);
  1113. CoUninitialize();
  1114. }
  1115. if (FAILED(hr))
  1116. DisplayMessageBox(hwndParent, MB_OK | MB_ICONSTOP, hr, IDS_FAILED_TO_BROWSE_NETWORKPATH);
  1117. return hr;
  1118. }
  1119. #define MAX_DFS_REFERRAL_TIME 0xFFFFFFFF
  1120. BOOL
  1121. ValidateTimeout(
  1122. IN LPCTSTR lpszTimeout,
  1123. OUT ULONG *pulTimeout
  1124. )
  1125. {
  1126. BOOL bReturn = FALSE;
  1127. if (pulTimeout)
  1128. {
  1129. *pulTimeout = 0;
  1130. __int64 i64Timeout = _wtoi64(lpszTimeout);
  1131. if (i64Timeout <= MAX_DFS_REFERRAL_TIME)
  1132. {
  1133. bReturn = TRUE;
  1134. *pulTimeout = (ULONG)i64Timeout;
  1135. }
  1136. }
  1137. return bReturn;
  1138. }
  1139. #include "winnetp.h"
  1140. // retrieve system drive letter on the specified machine
  1141. HRESULT GetSystemDrive(IN LPCTSTR lpszComputer, OUT TCHAR *ptch)
  1142. {
  1143. _ASSERT(ptch);
  1144. HRESULT hr = S_OK;
  1145. SHARE_INFO_2* pShareInfo = NULL;
  1146. NET_API_STATUS nstatRetVal = NetShareGetInfo(
  1147. const_cast<LPTSTR>(lpszComputer),
  1148. _T("Admin$"),
  1149. 2,
  1150. (LPBYTE *)&pShareInfo);
  1151. if (nstatRetVal == NERR_Success)
  1152. {
  1153. _ASSERT(_T(':') == *(pShareInfo->shi2_path + 1));
  1154. *ptch = *(pShareInfo->shi2_path);
  1155. } else
  1156. {
  1157. hr = HRESULT_FROM_WIN32(nstatRetVal);
  1158. }
  1159. return hr;
  1160. }
  1161. //
  1162. // return a drive letter X, the staging path will be created at <X>:\FRS-Staging
  1163. // Try to exclude the following drives for performance consideration:
  1164. // 1. system drive: because the jet database ntfrs uses resides on system drive
  1165. // 2. the drive the replica folder sits on
  1166. // Will try to return a drive with the most free space
  1167. //
  1168. TCHAR
  1169. GetDiskForStagingPath(
  1170. IN LPCTSTR i_lpszServer,
  1171. IN TCHAR i_tch
  1172. )
  1173. {
  1174. _ASSERT(i_lpszServer && *i_lpszServer);
  1175. _ASSERT(_istalpha(i_tch));
  1176. TCHAR tchDrive = i_tch;
  1177. //
  1178. // retrieve the system drive letter on the specified machine
  1179. //
  1180. TCHAR tchSystemDrive;
  1181. if (S_OK != GetSystemDrive(i_lpszServer, &tchSystemDrive))
  1182. return tchDrive;
  1183. //
  1184. // enumerate all shareable disks, e.g., \\server\C$, \\server\D$, etc.
  1185. //
  1186. CComBSTR bstrServer;
  1187. if (mylstrncmpi(i_lpszServer, _T("\\\\"), 2))
  1188. {
  1189. bstrServer = _T("\\\\");
  1190. bstrServer += i_lpszServer;
  1191. } else
  1192. bstrServer = i_lpszServer;
  1193. NETRESOURCE nr;
  1194. nr.dwScope = RESOURCE_SHAREABLE;
  1195. nr.dwType = RESOURCETYPE_ANY;
  1196. nr.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  1197. nr.dwUsage = RESOURCEUSAGE_CONTAINER;
  1198. nr.lpLocalName = _T("");
  1199. nr.lpRemoteName = bstrServer;
  1200. nr.lpComment = _T("");
  1201. nr.lpProvider = _T("");
  1202. HANDLE hEnum = NULL;
  1203. DWORD dwResult = WNetOpenEnum (
  1204. RESOURCE_SHAREABLE,
  1205. RESOURCETYPE_ANY,
  1206. RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER,
  1207. &nr,
  1208. &hEnum);
  1209. if (dwResult == NO_ERROR)
  1210. {
  1211. NETRESOURCE nrBuffer[26];
  1212. DWORD dwBufferSize = 26 * sizeof(NETRESOURCE);
  1213. DWORD dwNumEntries = 0xFFFFFFFF; // Enumerate all possible entries.
  1214. dwResult = WNetEnumResource (
  1215. hEnum,
  1216. &dwNumEntries,
  1217. nrBuffer,
  1218. &dwBufferSize);
  1219. if (dwResult == NO_ERROR)
  1220. {
  1221. ULONGLONG ullFreeSpace = 0;
  1222. for (DWORD dwIndex = 0; dwIndex < dwNumEntries; dwIndex++)
  1223. {
  1224. //
  1225. // lpRemoteName contains string in the form of \\server\C$
  1226. //
  1227. TCHAR *p = nrBuffer[dwIndex].lpRemoteName;
  1228. TCHAR tchCurrent = *(p + _tcslen(p) - 2);
  1229. //
  1230. // exclude the current drive specified in i_tch
  1231. //
  1232. if ( _toupper(i_tch) == _toupper(tchCurrent) )
  1233. continue;
  1234. //
  1235. // skip if it's not a NTFS file system
  1236. //
  1237. TCHAR szFileSystemName[MAX_PATH + 1];
  1238. DWORD dwMaxCompLength = 0, dwFileSystemFlags = 0;
  1239. CComBSTR bstrRootPath = p;
  1240. if (_T('\\') != *(p + _tcslen(p) - 1))
  1241. bstrRootPath += _T("\\");
  1242. if (FALSE == GetVolumeInformation(bstrRootPath, NULL, 0, NULL, &dwMaxCompLength,
  1243. &dwFileSystemFlags, szFileSystemName, MAX_PATH))
  1244. continue;
  1245. if (lstrcmpi(_T("NTFS"), szFileSystemName))
  1246. continue;
  1247. //
  1248. // 1. when i_tch is on a non-system drive and system drive is NTFS,
  1249. // change default to system drive
  1250. // 2. when other NTFS drives present, exclude system drive
  1251. //
  1252. if ( _toupper(tchSystemDrive) == _toupper(tchCurrent) )
  1253. {
  1254. if ( 0 == ullFreeSpace )
  1255. tchDrive = tchSystemDrive;
  1256. continue;
  1257. }
  1258. //
  1259. // find out the drive that has the most free space
  1260. //
  1261. ULARGE_INTEGER ulgiFreeBytesAvailableToCaller;
  1262. ULARGE_INTEGER ulgiTotalNumberOfBytes;
  1263. if (GetDiskFreeSpaceEx(p,
  1264. &ulgiFreeBytesAvailableToCaller,
  1265. &ulgiTotalNumberOfBytes,
  1266. NULL))
  1267. {
  1268. if (ulgiFreeBytesAvailableToCaller.QuadPart > ullFreeSpace)
  1269. {
  1270. tchDrive = tchCurrent;
  1271. ullFreeSpace = ulgiFreeBytesAvailableToCaller.QuadPart;
  1272. }
  1273. }
  1274. }
  1275. }
  1276. WNetCloseEnum (hEnum);
  1277. }
  1278. return tchDrive;
  1279. }
  1280. HRESULT GetUNCPath
  1281. (
  1282. IN BSTR i_bstrServerName,
  1283. IN BSTR i_bstrShareName,
  1284. OUT BSTR* o_pbstrUNCPath
  1285. )
  1286. {
  1287. RETURN_INVALIDARG_IF_NULL(i_bstrServerName);
  1288. RETURN_INVALIDARG_IF_NULL(i_bstrShareName);
  1289. RETURN_INVALIDARG_IF_NULL(o_pbstrUNCPath);
  1290. CComBSTR bstrUNCPath;
  1291. bstrUNCPath = _T("\\\\");
  1292. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
  1293. bstrUNCPath += i_bstrServerName;
  1294. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
  1295. bstrUNCPath += _T("\\");
  1296. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
  1297. bstrUNCPath += i_bstrShareName;
  1298. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
  1299. *o_pbstrUNCPath = bstrUNCPath.Detach();
  1300. return S_OK;
  1301. }
  1302. HRESULT GetDfsRootDisplayName
  1303. (
  1304. IN BSTR i_bstrScopeName,
  1305. IN BSTR i_bstrDfsName,
  1306. OUT BSTR* o_pbstrDisplayName
  1307. )
  1308. {
  1309. return GetUNCPath(i_bstrScopeName, i_bstrDfsName, o_pbstrDisplayName);
  1310. }
  1311. HRESULT GetDfsReplicaDisplayName
  1312. (
  1313. IN BSTR i_bstrServerName,
  1314. IN BSTR i_bstrShareName,
  1315. OUT BSTR* o_pbstrDisplayName
  1316. )
  1317. {
  1318. return GetUNCPath(i_bstrServerName, i_bstrShareName, o_pbstrDisplayName);
  1319. }
  1320. HRESULT
  1321. AddLVColumns(
  1322. IN const HWND hwndListBox,
  1323. IN const INT iStartingResourceID,
  1324. IN const UINT uiColumns
  1325. )
  1326. {
  1327. //
  1328. // calculate the listview column width
  1329. //
  1330. RECT rect;
  1331. ZeroMemory(&rect, sizeof(rect));
  1332. ::GetWindowRect(hwndListBox, &rect);
  1333. int nControlWidth = rect.right - rect.left;
  1334. int nVScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL);
  1335. int nBorderWidth = GetSystemMetrics(SM_CXBORDER);
  1336. int nControlNetWidth = nControlWidth - 4 * nBorderWidth;
  1337. int nWidth = nControlNetWidth / uiColumns;
  1338. LVCOLUMN lvColumn;
  1339. ZeroMemory(&lvColumn, sizeof(lvColumn));
  1340. lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  1341. lvColumn.fmt = LVCFMT_LEFT;
  1342. lvColumn.cx = nWidth;
  1343. for (UINT i = 0; i < uiColumns; i++)
  1344. {
  1345. CComBSTR bstrColumnText;
  1346. LoadStringFromResource(iStartingResourceID + i, &bstrColumnText);
  1347. lvColumn.pszText = bstrColumnText;
  1348. lvColumn.iSubItem = i;
  1349. ListView_InsertColumn(hwndListBox, i, &lvColumn);
  1350. }
  1351. return S_OK;
  1352. }
  1353. LPARAM GetListViewItemData(
  1354. IN HWND hwndList,
  1355. IN int index
  1356. )
  1357. {
  1358. if (-1 == index)
  1359. return NULL;
  1360. LVITEM lvItem;
  1361. ZeroMemory(&lvItem, sizeof(lvItem));
  1362. lvItem.mask = LVIF_PARAM;
  1363. lvItem.iItem = index;
  1364. if (ListView_GetItem(hwndList, &lvItem))
  1365. return lvItem.lParam;
  1366. return NULL;
  1367. }
  1368. HRESULT CreateAndHideStagingPath(
  1369. IN BSTR i_bstrServer,
  1370. IN BSTR i_bstrStagingPath
  1371. )
  1372. {
  1373. RETURN_INVALIDARG_IF_NULL(i_bstrServer);
  1374. RETURN_INVALIDARG_IF_NULL(i_bstrStagingPath);
  1375. CComBSTR bstrStagingPath;
  1376. if (!mylstrncmpi(i_bstrServer, _T("\\\\"), 2))
  1377. {
  1378. bstrStagingPath = i_bstrServer;
  1379. } else
  1380. {
  1381. bstrStagingPath = _T("\\\\");
  1382. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrStagingPath);
  1383. bstrStagingPath += i_bstrServer;
  1384. }
  1385. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrStagingPath);
  1386. bstrStagingPath += _T("\\");
  1387. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrStagingPath);
  1388. bstrStagingPath += i_bstrStagingPath;
  1389. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrStagingPath);
  1390. TCHAR* p = _tcschr(bstrStagingPath, _T(':'));
  1391. RETURN_INVALIDARG_IF_NULL(p);
  1392. *p = _T('$');
  1393. //
  1394. // Create the directory
  1395. //
  1396. if (!CreateDirectory(bstrStagingPath,NULL))
  1397. {
  1398. DWORD dwErr = GetLastError();
  1399. if (ERROR_ALREADY_EXISTS != dwErr)
  1400. return (HRESULT_FROM_WIN32(dwErr));
  1401. }
  1402. //
  1403. // try to hide the staging directory, ignore errors
  1404. //
  1405. DWORD dwRet = GetFileAttributes(bstrStagingPath);
  1406. if (-1 != dwRet)
  1407. {
  1408. dwRet |= FILE_ATTRIBUTE_HIDDEN;
  1409. (void) SetFileAttributes(bstrStagingPath, dwRet);
  1410. }
  1411. return S_OK;
  1412. }
  1413. //+-------------------------------------------------------------------------
  1414. //
  1415. // Function: ConfigAndStartNtfrs
  1416. //
  1417. // Synopsis: Config ntfrs to be AUTO_START, and start the service.
  1418. //
  1419. //--------------------------------------------------------------------------
  1420. HRESULT
  1421. ConfigAndStartNtfrs
  1422. (
  1423. BSTR i_bstrServer
  1424. )
  1425. {
  1426. HRESULT hr = S_OK;
  1427. SC_HANDLE hScManager = NULL;
  1428. SC_HANDLE hService = NULL;
  1429. SERVICE_STATUS svcStatus;
  1430. DWORD dwDesiredAccess = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_START;
  1431. do
  1432. {
  1433. if ((hScManager = ::OpenSCManager(i_bstrServer, NULL, SC_MANAGER_CONNECT )) == NULL ||
  1434. (hService = ::OpenService(hScManager, _T("ntfrs"), dwDesiredAccess)) == NULL ||
  1435. !ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE,
  1436. NULL, NULL, NULL, NULL, NULL, NULL, NULL) ||
  1437. !::QueryServiceStatus(hService, &svcStatus) )
  1438. {
  1439. hr = HRESULT_FROM_WIN32(GetLastError());
  1440. break;
  1441. }
  1442. if (SERVICE_RUNNING != svcStatus.dwCurrentState)
  1443. {
  1444. if (!StartService(hService, 0, NULL))
  1445. {
  1446. hr = HRESULT_FROM_WIN32(GetLastError());
  1447. break;
  1448. }
  1449. // The following is a cut&paste from MSDN article
  1450. // Check the status until the service is no longer start pending.
  1451. if (!QueryServiceStatus(hService,&svcStatus))
  1452. {
  1453. hr = HRESULT_FROM_WIN32(GetLastError());
  1454. break;
  1455. }
  1456. // Get the tick count before entering the loop.
  1457. DWORD dwStartTickCount = GetTickCount();
  1458. DWORD dwOldCheckPoint = svcStatus.dwCheckPoint;
  1459. DWORD dwWaitTime;
  1460. while (svcStatus.dwCurrentState == SERVICE_START_PENDING)
  1461. {
  1462. // Do not wait longer than the wait hint. A good interval is
  1463. // one tenth the wait hint, but no less than 1 second and no
  1464. // more than 10 seconds.
  1465. dwWaitTime = svcStatus.dwWaitHint / 10;
  1466. if ( dwWaitTime < 1000 )
  1467. dwWaitTime = 1000;
  1468. else if ( dwWaitTime > 10000 )
  1469. dwWaitTime = 10000;
  1470. Sleep( dwWaitTime );
  1471. // Check the status again.
  1472. if (!QueryServiceStatus(hService, &svcStatus))
  1473. break;
  1474. if (svcStatus.dwCheckPoint > dwOldCheckPoint)
  1475. {
  1476. // The service is making progress
  1477. dwStartTickCount = GetTickCount();
  1478. dwOldCheckPoint = svcStatus.dwCheckPoint;
  1479. }
  1480. else
  1481. {
  1482. if (GetTickCount() - dwStartTickCount > svcStatus.dwWaitHint)
  1483. {
  1484. // No progress made within the wait hint
  1485. break;
  1486. }
  1487. }
  1488. }
  1489. if (svcStatus.dwCurrentState == SERVICE_RUNNING)
  1490. hr = S_OK;
  1491. else
  1492. hr = HRESULT_FROM_WIN32(GetLastError());
  1493. }
  1494. } while ( FALSE );
  1495. if (hService)
  1496. CloseServiceHandle(hService);
  1497. if (hScManager)
  1498. CloseServiceHandle(hScManager);
  1499. return(hr);
  1500. }
  1501. //+-------------------------------------------------------------------------
  1502. //
  1503. // Function: CheckResourceProvider
  1504. //
  1505. // Synopsis: see if pszResource is provided by "Microsoft Windows Network".
  1506. //
  1507. //--------------------------------------------------------------------------
  1508. HRESULT
  1509. CheckResourceProvider(LPCTSTR pszResource)
  1510. {
  1511. DWORD dwError = 0;
  1512. NETRESOURCE nr = {0};
  1513. NETRESOURCE nrOut = {0};
  1514. LPTSTR pszSystem = NULL; // pointer to variable-length strings
  1515. NETRESOURCE *pBuffer = &nrOut; // buffer
  1516. DWORD cbResult = sizeof(nrOut); // buffer size
  1517. nr.dwScope = RESOURCE_GLOBALNET;
  1518. nr.dwType = RESOURCETYPE_DISK;
  1519. nr.lpRemoteName = (LPTSTR)pszResource;
  1520. CComBSTR bstrProvider;
  1521. HRESULT hr = LoadStringFromResource(IDS_SMB_PROVIDER, &bstrProvider);
  1522. RETURN_IF_FAILED(hr);
  1523. nr.lpProvider = (BSTR)bstrProvider;
  1524. //
  1525. // First call the WNetGetResourceInformation function with
  1526. // memory allocated to hold only a NETRESOURCE structure. This
  1527. // method can succeed if all the NETRESOURCE pointers are NULL.
  1528. //
  1529. dwError = WNetGetResourceInformation(&nr, (LPBYTE)pBuffer, &cbResult, &pszSystem);
  1530. //
  1531. // If the call fails because the buffer is too small,
  1532. // call the LocalAlloc function to allocate a larger buffer.
  1533. //
  1534. if (dwError == ERROR_MORE_DATA)
  1535. {
  1536. pBuffer = (NETRESOURCE *)LocalAlloc(LMEM_FIXED, cbResult);
  1537. if (!pBuffer)
  1538. {
  1539. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1540. } else
  1541. {
  1542. // Call WNetGetResourceInformation again with the larger buffer.
  1543. dwError = WNetGetResourceInformation(&nr, (LPBYTE)pBuffer, &cbResult, &pszSystem);
  1544. }
  1545. }
  1546. if (dwError == NO_ERROR)
  1547. {
  1548. // If the call succeeds, process the contents of the
  1549. // returned NETRESOURCE structure and the variable-length
  1550. // strings in lpBuffer. Then free the memory.
  1551. //
  1552. if (pBuffer != &nrOut)
  1553. {
  1554. LocalFree(pBuffer);
  1555. }
  1556. }
  1557. return (dwError == NO_ERROR ? S_OK : HRESULT_FROM_WIN32(dwError));
  1558. }
  1559. HRESULT FRSShareCheck
  1560. (
  1561. BSTR i_bstrServer,
  1562. BSTR i_bstrFolder,
  1563. OUT FRSSHARE_TYPE *pFRSShareType
  1564. )
  1565. /*++
  1566. Routine Description:
  1567. Performs FRS checks for the share to be able particiapte in a FRS set.
  1568. Arguments:
  1569. i_bstrServer - The server hosting the share
  1570. i_bstrFolder - The share path.
  1571. --*/
  1572. {
  1573. _ASSERT(i_bstrServer && *i_bstrServer && i_bstrFolder && *i_bstrFolder && pFRSShareType);
  1574. // Is the server a NT 5.0 server with FRS?
  1575. HRESULT hr = S_FALSE;
  1576. hr = FRSIsNTFRSInstalled(i_bstrServer);
  1577. if (S_FALSE == hr)
  1578. {
  1579. *pFRSShareType = FRSSHARE_TYPE_NONTFRS;
  1580. return hr;
  1581. } else if (FAILED(hr))
  1582. {
  1583. *pFRSShareType = FRSSHARE_TYPE_UNKNOWN;
  1584. return hr;
  1585. }
  1586. // Is the path on a valid disktree share?
  1587. hr = GetFolderInfo(i_bstrServer, i_bstrFolder);
  1588. if (STG_E_NOTFILEBASEDSTORAGE == hr)
  1589. {
  1590. *pFRSShareType = FRSSHARE_TYPE_NOTDISKTREE;
  1591. return S_FALSE;
  1592. } else if (FAILED(hr))
  1593. {
  1594. *pFRSShareType = FRSSHARE_TYPE_UNKNOWN;
  1595. return hr;
  1596. }
  1597. // Get root path as \\server\share
  1598. CComBSTR bstrRootPath = _T("\\\\");
  1599. bstrRootPath+= i_bstrServer;
  1600. bstrRootPath+= _T("\\");
  1601. TCHAR *p = _tcschr(i_bstrFolder, _T('\\'));
  1602. if (p)
  1603. {
  1604. bstrRootPath += CComBSTR(p - i_bstrFolder + 1, i_bstrFolder);
  1605. } else
  1606. {
  1607. bstrRootPath += i_bstrFolder;
  1608. bstrRootPath+= _T("\\");
  1609. }
  1610. TCHAR szFileSystemName[MAX_PATH + 1];
  1611. DWORD dwMaxCompLength = 0, dwFileSystemFlags = 0;
  1612. _ASSERT(bstrRootPath);
  1613. // Is File System NTFS 5.0?
  1614. if (0 == GetVolumeInformation(
  1615. bstrRootPath, // Volume path
  1616. NULL, // Volume name not required
  1617. 0, // Size of volume name buffer
  1618. NULL, // Serial number not required.
  1619. &dwMaxCompLength,
  1620. &dwFileSystemFlags,
  1621. szFileSystemName,
  1622. MAX_PATH
  1623. ))
  1624. {
  1625. *pFRSShareType = FRSSHARE_TYPE_UNKNOWN;
  1626. return HRESULT_FROM_WIN32(GetLastError());
  1627. }
  1628. if (0 != lstrcmpi(_T("NTFS"), szFileSystemName) || !(FILE_SUPPORTS_OBJECT_IDS & dwFileSystemFlags))
  1629. {
  1630. *pFRSShareType = FRSSHARE_TYPE_NOTNTFS;
  1631. return S_FALSE;
  1632. }
  1633. *pFRSShareType = FRSSHARE_TYPE_OK;
  1634. return S_OK;
  1635. }
  1636. HRESULT FRSIsNTFRSInstalled
  1637. (
  1638. BSTR i_bstrServer
  1639. )
  1640. /*++
  1641. Routine Description:
  1642. Checks if the computer has ntfrs service.
  1643. Arguments:
  1644. i_bstrServer - The name of the server.
  1645. Return value:
  1646. S_OK, if server has ntfrs service.
  1647. S_FALSE, if server does not have ntfrs service installed.
  1648. --*/
  1649. {
  1650. if (!i_bstrServer)
  1651. return(E_INVALIDARG);
  1652. SC_HANDLE SCMHandle = NULL, NTFRSHandle = NULL;
  1653. HRESULT hr = S_FALSE;
  1654. SCMHandle = OpenSCManager (i_bstrServer, NULL, SC_MANAGER_CONNECT);
  1655. if (!SCMHandle)
  1656. return(HRESULT_FROM_WIN32(GetLastError()));
  1657. NTFRSHandle = OpenService (
  1658. SCMHandle,
  1659. _T("ntfrs"),
  1660. SERVICE_QUERY_STATUS
  1661. );
  1662. if (!NTFRSHandle)
  1663. {
  1664. DWORD dwError = GetLastError();
  1665. if (ERROR_SERVICE_DOES_NOT_EXIST == dwError)
  1666. hr = S_FALSE;
  1667. else
  1668. hr = HRESULT_FROM_WIN32(dwError);
  1669. CloseServiceHandle(SCMHandle);
  1670. return(hr);
  1671. } else
  1672. hr = S_OK;
  1673. CloseServiceHandle(NTFRSHandle);
  1674. CloseServiceHandle(SCMHandle);
  1675. return(hr);
  1676. }
  1677. typedef HRESULT (*pfnReplicationScheduleDialogEx)
  1678. (
  1679. HWND hwndParent, // parent window
  1680. BYTE ** pprgbData, // pointer to pointer to array of 84 bytes
  1681. LPCTSTR pszTitle, // dialog title
  1682. DWORD dwFlags // option flags
  1683. );
  1684. static HINSTANCE g_hDllSchedule = NULL;
  1685. static pfnReplicationScheduleDialogEx g_hProcSchedule = NULL;
  1686. //
  1687. // S_OK: button OK is clicked and the new schedule is returned in io_pSchedule
  1688. // S_FALSE: button Cancle is clicked, io_pSchedule is not touched
  1689. //
  1690. HRESULT InvokeScheduleDlg(
  1691. IN HWND i_hwndParent,
  1692. IN OUT SCHEDULE* io_pSchedule
  1693. )
  1694. {
  1695. CComBSTR bstrTitle;
  1696. HRESULT hr = LoadStringFromResource(IDS_SCHEDULE, &bstrTitle);
  1697. RETURN_IF_FAILED(hr);
  1698. //
  1699. // LoadLibrary
  1700. //
  1701. if (!g_hDllSchedule)
  1702. {
  1703. if (!(g_hDllSchedule = LoadLibrary(_T("loghours.dll"))) ||
  1704. !(g_hProcSchedule = (pfnReplicationScheduleDialogEx)GetProcAddress(g_hDllSchedule, "ReplicationScheduleDialogEx")) )
  1705. {
  1706. hr = HRESULT_FROM_WIN32(GetLastError());
  1707. if (g_hDllSchedule)
  1708. {
  1709. FreeLibrary(g_hDllSchedule);
  1710. g_hDllSchedule = NULL;
  1711. }
  1712. return hr;
  1713. }
  1714. }
  1715. //
  1716. // invoke the schedule dialog
  1717. //
  1718. BYTE* pbScheduleData = (BYTE *)io_pSchedule + io_pSchedule->Schedules->Offset;
  1719. hr = (*g_hProcSchedule)(i_hwndParent, &pbScheduleData, bstrTitle, 0);
  1720. return hr;
  1721. }
  1722. HRESULT TranslateManagedBy(
  1723. IN PCTSTR i_pszDC,
  1724. IN PCTSTR i_pszIn,
  1725. OUT BSTR* o_pbstrOut,
  1726. IN DS_NAME_FORMAT i_formatIn,
  1727. IN DS_NAME_FORMAT i_formatOut
  1728. )
  1729. {
  1730. RETURN_INVALIDARG_IF_NULL(o_pbstrOut);
  1731. *o_pbstrOut = NULL;
  1732. HRESULT hr = S_OK;
  1733. if (!i_pszIn || !*i_pszIn)
  1734. return hr;
  1735. CComBSTR bstr;
  1736. HANDLE hDS = NULL;
  1737. DWORD dwErr = DsBind(i_pszDC, NULL, &hDS);
  1738. if (ERROR_SUCCESS != dwErr)
  1739. {
  1740. hr = HRESULT_FROM_WIN32(dwErr);
  1741. } else
  1742. {
  1743. hr = CrackName( hDS,
  1744. (PTSTR)i_pszIn,
  1745. i_formatIn,
  1746. i_formatOut,
  1747. &bstr
  1748. );
  1749. DsUnBind(&hDS);
  1750. }
  1751. if (SUCCEEDED(hr))
  1752. *o_pbstrOut = bstr.Detach();
  1753. return hr;
  1754. }
  1755. HRESULT GetFTDfsObjectDN(
  1756. IN PCTSTR i_pszDomainName,
  1757. IN PCTSTR i_pszRootName,
  1758. OUT BSTR* o_pbstrFTDfsObjectDN
  1759. )
  1760. {
  1761. CComBSTR bstrDomainDN;
  1762. HRESULT hr = GetDomainInfo(
  1763. i_pszDomainName,
  1764. NULL, // return DC's Dns name
  1765. NULL, // return Domain's Dns name
  1766. &bstrDomainDN // return DC=nttest,DC=micr
  1767. );
  1768. RETURN_IF_FAILED(hr);
  1769. CComBSTR bstrFTDfsObjectDN = _T("CN=");
  1770. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1771. bstrFTDfsObjectDN += i_pszRootName;
  1772. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1773. bstrFTDfsObjectDN += _T(",");
  1774. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1775. bstrFTDfsObjectDN += _T("CN=Dfs-Configuration,CN=System,");
  1776. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1777. bstrFTDfsObjectDN += bstrDomainDN;
  1778. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1779. *o_pbstrFTDfsObjectDN = bstrFTDfsObjectDN.Detach();
  1780. return hr;
  1781. }
  1782. HRESULT ReadSharePublishInfoHelper(
  1783. PLDAP i_pldap,
  1784. LPCTSTR i_pszDN,
  1785. LPCTSTR i_pszSearchFilter,
  1786. OUT BOOL* o_pbPublish,
  1787. OUT BSTR* o_pbstrUNCPath,
  1788. OUT BSTR* o_pbstrDescription,
  1789. OUT BSTR* o_pbstrKeywords,
  1790. OUT BSTR* o_pbstrManagedBy)
  1791. {
  1792. dfsDebugOut((_T("ReadSharePublishInfoHelper %s %s\n"),
  1793. i_pszDN, i_pszSearchFilter));
  1794. *o_pbPublish = FALSE;
  1795. HRESULT hr = S_OK;
  1796. hr = IsValidObject(i_pldap, (PTSTR)i_pszDN);
  1797. if (S_OK != hr)
  1798. return hr;
  1799. LListElem* pElem = NULL;
  1800. do {
  1801. PCTSTR ppszAttributes[] = {
  1802. ATTR_SHRPUB_UNCNAME,
  1803. ATTR_SHRPUB_DESCRIPTION,
  1804. ATTR_SHRPUB_KEYWORDS,
  1805. ATTR_SHRPUB_MANAGEDBY,
  1806. 0
  1807. };
  1808. HRESULT hr = GetValuesEx(
  1809. i_pldap,
  1810. i_pszDN,
  1811. LDAP_SCOPE_BASE,
  1812. i_pszSearchFilter,
  1813. ppszAttributes,
  1814. &pElem);
  1815. RETURN_IF_FAILED(hr);
  1816. if (!pElem || !pElem->pppszAttrValues)
  1817. return hr;
  1818. PTSTR** pppszValues = pElem->pppszAttrValues;
  1819. if (pppszValues[0] && *(pppszValues[0]))
  1820. {
  1821. *o_pbstrUNCPath = SysAllocString(*(pppszValues[0]));
  1822. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrUNCPath, &hr);
  1823. *o_pbPublish = TRUE;
  1824. }
  1825. if (pppszValues[1] && *(pppszValues[1]))
  1826. {
  1827. *o_pbstrDescription = SysAllocString(*(pppszValues[1]));
  1828. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrDescription, &hr);
  1829. }
  1830. if (pppszValues[2] && *(pppszValues[2]))
  1831. {
  1832. CComBSTR bstrKeywords;
  1833. PTSTR *ppszStrings = pppszValues[2];
  1834. while (*ppszStrings)
  1835. {
  1836. if (!bstrKeywords)
  1837. {
  1838. bstrKeywords = *ppszStrings;
  1839. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr);
  1840. } else
  1841. {
  1842. bstrKeywords += _T(";");
  1843. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr);
  1844. bstrKeywords += *ppszStrings;
  1845. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr);
  1846. }
  1847. ppszStrings++;
  1848. }
  1849. *o_pbstrKeywords = bstrKeywords.Detach();
  1850. }
  1851. if (pppszValues[3] && *(pppszValues[3]))
  1852. {
  1853. *o_pbstrManagedBy = SysAllocString(*(pppszValues[3]));
  1854. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrManagedBy, &hr);
  1855. }
  1856. } while (0);
  1857. if (pElem)
  1858. FreeLListElem(pElem);
  1859. return hr;
  1860. }
  1861. HRESULT ReadSharePublishInfoOnFTRoot(
  1862. LPCTSTR i_pszDomainName,
  1863. LPCTSTR i_pszRootName,
  1864. OUT BOOL* o_pbPublish,
  1865. OUT BSTR* o_pbstrUNCPath,
  1866. OUT BSTR* o_pbstrDescription,
  1867. OUT BSTR* o_pbstrKeywords,
  1868. OUT BSTR* o_pbstrManagedBy)
  1869. {
  1870. HRESULT hr = S_OK;
  1871. CComBSTR bstrFTDfsObjectDN;
  1872. hr = GetFTDfsObjectDN(i_pszDomainName, i_pszRootName, &bstrFTDfsObjectDN);
  1873. if (FAILED(hr))
  1874. return hr;
  1875. CComBSTR bstrDC;
  1876. PLDAP pldap = NULL;
  1877. hr = ConnectToDS(i_pszDomainName, &pldap, &bstrDC); // PDC is preferred
  1878. if (SUCCEEDED(hr))
  1879. {
  1880. CComBSTR bstrManagedByFQDN;
  1881. hr = ReadSharePublishInfoHelper(
  1882. pldap,
  1883. bstrFTDfsObjectDN,
  1884. OBJCLASS_SF_FTDFS,
  1885. o_pbPublish,
  1886. o_pbstrUNCPath,
  1887. o_pbstrDescription,
  1888. o_pbstrKeywords,
  1889. &bstrManagedByFQDN);
  1890. if (SUCCEEDED(hr))
  1891. {
  1892. hr = TranslateManagedBy(bstrDC,
  1893. bstrManagedByFQDN,
  1894. o_pbstrManagedBy,
  1895. DS_FQDN_1779_NAME,
  1896. DS_USER_PRINCIPAL_NAME);
  1897. if (FAILED(hr))
  1898. hr = TranslateManagedBy(bstrDC,
  1899. bstrManagedByFQDN,
  1900. o_pbstrManagedBy,
  1901. DS_FQDN_1779_NAME,
  1902. DS_NT4_ACCOUNT_NAME);
  1903. }
  1904. CloseConnectionToDS(pldap);
  1905. }
  1906. return hr;
  1907. }
  1908. HRESULT ReadSharePublishInfoOnSARoot(
  1909. LPCTSTR i_pszServerName,
  1910. LPCTSTR i_pszShareName,
  1911. OUT BOOL* o_pbPublish,
  1912. OUT BSTR* o_pbstrUNCPath,
  1913. OUT BSTR* o_pbstrDescription,
  1914. OUT BSTR* o_pbstrKeywords,
  1915. OUT BSTR* o_pbstrManagedBy)
  1916. {
  1917. RETURN_INVALIDARG_IF_NULL(i_pszServerName);
  1918. RETURN_INVALIDARG_IF_NULL(i_pszShareName);
  1919. RETURN_INVALIDARG_IF_NULL(o_pbPublish);
  1920. RETURN_INVALIDARG_IF_NULL(o_pbstrUNCPath);
  1921. RETURN_INVALIDARG_IF_NULL(o_pbstrDescription);
  1922. RETURN_INVALIDARG_IF_NULL(o_pbstrKeywords);
  1923. RETURN_INVALIDARG_IF_NULL(o_pbstrManagedBy);
  1924. *o_pbPublish = FALSE;
  1925. *o_pbstrUNCPath = NULL;
  1926. *o_pbstrDescription = NULL;
  1927. *o_pbstrKeywords = NULL;
  1928. *o_pbstrManagedBy = NULL;
  1929. CComBSTR bstrDomainName, bstrFQDN;
  1930. HRESULT hr = GetServerInfo(
  1931. (PTSTR)i_pszServerName,
  1932. &bstrDomainName,
  1933. NULL, //NetbiosName
  1934. NULL, //ValidDSObject
  1935. NULL, //DnsName,
  1936. NULL, //Guid,
  1937. &bstrFQDN);
  1938. if (S_OK != hr)
  1939. return hr;
  1940. CComBSTR bstrVolumeObjectDN = _T("CN=");
  1941. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  1942. bstrVolumeObjectDN += i_pszShareName;
  1943. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  1944. bstrVolumeObjectDN += _T(",");
  1945. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  1946. bstrVolumeObjectDN += bstrFQDN;
  1947. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  1948. CComBSTR bstrDC;
  1949. PLDAP pldap = NULL;
  1950. hr = ConnectToDS(bstrDomainName, &pldap, &bstrDC);
  1951. if (SUCCEEDED(hr))
  1952. {
  1953. CComBSTR bstrManagedByFQDN;
  1954. hr = ReadSharePublishInfoHelper(
  1955. pldap,
  1956. bstrVolumeObjectDN,
  1957. OBJCLASS_SF_VOLUME,
  1958. o_pbPublish,
  1959. o_pbstrUNCPath,
  1960. o_pbstrDescription,
  1961. o_pbstrKeywords,
  1962. &bstrManagedByFQDN);
  1963. if (SUCCEEDED(hr))
  1964. {
  1965. hr = TranslateManagedBy(bstrDC,
  1966. bstrManagedByFQDN,
  1967. o_pbstrManagedBy,
  1968. DS_FQDN_1779_NAME,
  1969. DS_USER_PRINCIPAL_NAME);
  1970. if (FAILED(hr))
  1971. hr = TranslateManagedBy(bstrDC,
  1972. bstrManagedByFQDN,
  1973. o_pbstrManagedBy,
  1974. DS_FQDN_1779_NAME,
  1975. DS_NT4_ACCOUNT_NAME);
  1976. }
  1977. CloseConnectionToDS(pldap);
  1978. }
  1979. return hr;
  1980. }
  1981. HRESULT CreateVolumeObject(
  1982. PLDAP i_pldap,
  1983. PCTSTR i_pszDN,
  1984. PCTSTR i_pszUNCPath,
  1985. PCTSTR i_pszDescription,
  1986. PCTSTR i_pszKeywords,
  1987. PCTSTR i_pszManagedBy)
  1988. {
  1989. HRESULT hr = S_OK;
  1990. LDAP_ATTR_VALUE pAttrVals[5];
  1991. int i =0;
  1992. pAttrVals[i].bstrAttribute = OBJCLASS_ATTRIBUTENAME;
  1993. pAttrVals[i].vpValue = (void *)OBJCLASS_VOLUME;
  1994. pAttrVals[i].bBerValue = false;
  1995. i++;
  1996. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME;
  1997. pAttrVals[i].vpValue = (void *)i_pszUNCPath;
  1998. pAttrVals[i].bBerValue = false;
  1999. i++;
  2000. if (i_pszDescription && *i_pszDescription)
  2001. {
  2002. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION;
  2003. pAttrVals[i].vpValue = (void *)i_pszDescription;
  2004. pAttrVals[i].bBerValue = false;
  2005. i++;
  2006. }
  2007. LDAP_ATTR_VALUE *pHead = NULL;
  2008. if (i_pszKeywords && *i_pszKeywords)
  2009. {
  2010. hr = PutMultiValuesIntoAttrValList(i_pszKeywords, &pHead);
  2011. if (S_OK == hr)
  2012. {
  2013. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS;
  2014. pAttrVals[i].vpValue = (void *)pHead->vpValue; // multi-valued
  2015. pAttrVals[i].bBerValue = false;
  2016. pAttrVals[i].Next = pHead->Next;
  2017. i++;
  2018. }
  2019. }
  2020. if (i_pszManagedBy && *i_pszManagedBy)
  2021. {
  2022. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY;
  2023. pAttrVals[i].vpValue = (void *)i_pszManagedBy;
  2024. pAttrVals[i].bBerValue = false;
  2025. i++;
  2026. }
  2027. hr = AddValues(i_pldap, i_pszDN, i, pAttrVals);
  2028. if (pHead)
  2029. FreeAttrValList(pHead);
  2030. return hr;
  2031. }
  2032. HRESULT ModifyShareObject(
  2033. PLDAP i_pldap,
  2034. PCTSTR i_pszDN,
  2035. PCTSTR i_pszUNCPath,
  2036. PCTSTR i_pszDescription,
  2037. PCTSTR i_pszKeywords,
  2038. PCTSTR i_pszManagedBy)
  2039. {
  2040. HRESULT hr = S_OK;
  2041. hr = IsValidObject(i_pldap, (PTSTR)i_pszDN);
  2042. if (S_OK != hr)
  2043. return hr;
  2044. LDAP_ATTR_VALUE pAttrVals[4];
  2045. ZeroMemory(pAttrVals, sizeof(pAttrVals));
  2046. //
  2047. // modify values if any
  2048. //
  2049. int i =0;
  2050. if (i_pszUNCPath && *i_pszUNCPath)
  2051. {
  2052. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME;
  2053. pAttrVals[i].vpValue = (void *)i_pszUNCPath;
  2054. pAttrVals[i].bBerValue = false;
  2055. i++;
  2056. }
  2057. if (i_pszDescription && *i_pszDescription)
  2058. {
  2059. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION;
  2060. pAttrVals[i].vpValue = (void *)i_pszDescription;
  2061. pAttrVals[i].bBerValue = false;
  2062. i++;
  2063. }
  2064. LDAP_ATTR_VALUE *pHead = NULL;
  2065. if (i_pszKeywords && *i_pszKeywords)
  2066. {
  2067. hr = PutMultiValuesIntoAttrValList(i_pszKeywords, &pHead);
  2068. if (S_OK == hr)
  2069. {
  2070. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS;
  2071. pAttrVals[i].vpValue = (void *)pHead->vpValue; // multi-valued
  2072. pAttrVals[i].bBerValue = false;
  2073. pAttrVals[i].Next = pHead->Next;
  2074. i++;
  2075. }
  2076. }
  2077. if (i_pszManagedBy && *i_pszManagedBy)
  2078. {
  2079. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY;
  2080. pAttrVals[i].vpValue = (void *)i_pszManagedBy;
  2081. pAttrVals[i].bBerValue = false;
  2082. i++;
  2083. }
  2084. if (i > 0)
  2085. {
  2086. hr = ModifyValues(i_pldap, i_pszDN, i, pAttrVals);
  2087. dfsDebugOut((_T("ModifyValues i=%d, hr=%x\n"), i, hr));
  2088. RETURN_IF_FAILED(hr);
  2089. }
  2090. if (pHead)
  2091. FreeAttrValList(pHead);
  2092. //
  2093. // delete values if any
  2094. //
  2095. i =0;
  2096. ZeroMemory(pAttrVals, sizeof(pAttrVals));
  2097. if (!i_pszUNCPath || !*i_pszUNCPath)
  2098. {
  2099. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME;
  2100. pAttrVals[i].vpValue = NULL;
  2101. pAttrVals[i].bBerValue = false;
  2102. i++;
  2103. }
  2104. if (!i_pszDescription || !*i_pszDescription)
  2105. {
  2106. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION;
  2107. pAttrVals[i].vpValue = NULL;
  2108. pAttrVals[i].bBerValue = false;
  2109. i++;
  2110. }
  2111. if (!i_pszKeywords || !*i_pszKeywords)
  2112. {
  2113. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS;
  2114. pAttrVals[i].vpValue = NULL;
  2115. pAttrVals[i].bBerValue = false;
  2116. i++;
  2117. }
  2118. if (!i_pszManagedBy || !*i_pszManagedBy)
  2119. {
  2120. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY;
  2121. pAttrVals[i].vpValue = NULL;
  2122. pAttrVals[i].bBerValue = false;
  2123. i++;
  2124. }
  2125. if (i > 0)
  2126. {
  2127. hr = DeleteValues(i_pldap, i_pszDN, i, pAttrVals);
  2128. dfsDebugOut((_T("DeleteValues i=%d, hr=%x\n"), i, hr));
  2129. }
  2130. return hr;
  2131. }
  2132. HRESULT ModifySharePublishInfoOnFTRoot(
  2133. IN PCTSTR i_pszDomainName,
  2134. IN PCTSTR i_pszRootName,
  2135. IN BOOL i_bPublish,
  2136. IN PCTSTR i_pszUNCPath,
  2137. IN PCTSTR i_pszDescription,
  2138. IN PCTSTR i_pszKeywords,
  2139. IN PCTSTR i_pszManagedBy
  2140. )
  2141. {
  2142. dfsDebugOut((_T("ModifySharePublishInfoOnFTRoot %s, %s, %d, %s, %s, %s, %s\n"),
  2143. i_pszDomainName,
  2144. i_pszRootName,
  2145. i_bPublish,
  2146. i_pszUNCPath,
  2147. i_pszDescription,
  2148. i_pszKeywords,
  2149. i_pszManagedBy
  2150. ));
  2151. CComBSTR bstrFTDfsObjectDN;
  2152. HRESULT hr = GetFTDfsObjectDN(i_pszDomainName, i_pszRootName, &bstrFTDfsObjectDN);
  2153. if (FAILED(hr))
  2154. return hr;
  2155. CComBSTR bstrDC;
  2156. PLDAP pldap = NULL;
  2157. hr = ConnectToDS(i_pszDomainName, &pldap, &bstrDC); // PDC is preferred
  2158. if (SUCCEEDED(hr))
  2159. {
  2160. if (i_bPublish)
  2161. {
  2162. CComBSTR bstrManagedByFQDN;
  2163. if (i_pszManagedBy && *i_pszManagedBy)
  2164. {
  2165. hr = TranslateManagedBy(bstrDC,
  2166. i_pszManagedBy,
  2167. &bstrManagedByFQDN,
  2168. (_tcschr(i_pszManagedBy, _T('@')) ? DS_USER_PRINCIPAL_NAME : DS_NT4_ACCOUNT_NAME),
  2169. DS_FQDN_1779_NAME);
  2170. }
  2171. if (SUCCEEDED(hr))
  2172. hr = ModifyShareObject(
  2173. pldap,
  2174. bstrFTDfsObjectDN,
  2175. i_pszUNCPath,
  2176. i_pszDescription,
  2177. i_pszKeywords,
  2178. bstrManagedByFQDN);
  2179. } else {
  2180. hr = ModifyShareObject(
  2181. pldap,
  2182. bstrFTDfsObjectDN,
  2183. NULL,
  2184. NULL,
  2185. NULL,
  2186. NULL);
  2187. if (S_FALSE == hr)
  2188. hr = S_OK; // ignore non-existing object
  2189. }
  2190. CloseConnectionToDS(pldap);
  2191. }
  2192. dfsDebugOut((_T("ModifySharePublishInfoOnFTRoot hr=%x\n"), hr));
  2193. return hr;
  2194. }
  2195. HRESULT ModifySharePublishInfoOnSARoot(
  2196. IN PCTSTR i_pszServerName,
  2197. IN PCTSTR i_pszShareName,
  2198. IN BOOL i_bPublish,
  2199. IN PCTSTR i_pszUNCPath,
  2200. IN PCTSTR i_pszDescription,
  2201. IN PCTSTR i_pszKeywords,
  2202. IN PCTSTR i_pszManagedBy
  2203. )
  2204. {
  2205. dfsDebugOut((_T("ModifySharePublishInfoOnSARoot %s, %s, %d, %s, %s, %s, %s\n"),
  2206. i_pszServerName,
  2207. i_pszShareName,
  2208. i_bPublish,
  2209. i_pszUNCPath,
  2210. i_pszDescription,
  2211. i_pszKeywords,
  2212. i_pszManagedBy
  2213. ));
  2214. CComBSTR bstrDomainName, bstrFQDN;
  2215. HRESULT hr = GetServerInfo(
  2216. (PTSTR)i_pszServerName,
  2217. &bstrDomainName,
  2218. NULL, //NetbiosName
  2219. NULL, //ValidDSObject
  2220. NULL, //DnsName,
  2221. NULL, //Guid,
  2222. &bstrFQDN);
  2223. if (S_OK != hr)
  2224. return hr;
  2225. CComBSTR bstrVolumeObjectDN = _T("CN=");
  2226. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  2227. bstrVolumeObjectDN += i_pszShareName;
  2228. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  2229. bstrVolumeObjectDN += _T(",");
  2230. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  2231. bstrVolumeObjectDN += bstrFQDN;
  2232. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  2233. CComBSTR bstrDC;
  2234. PLDAP pldap = NULL;
  2235. hr = ConnectToDS(bstrDomainName, &pldap, &bstrDC);
  2236. if (SUCCEEDED(hr))
  2237. {
  2238. if (i_bPublish)
  2239. {
  2240. CComBSTR bstrManagedByFQDN;
  2241. if (i_pszManagedBy && *i_pszManagedBy)
  2242. {
  2243. hr = TranslateManagedBy(bstrDC,
  2244. i_pszManagedBy,
  2245. &bstrManagedByFQDN,
  2246. (_tcschr(i_pszManagedBy, _T('@')) ? DS_USER_PRINCIPAL_NAME : DS_NT4_ACCOUNT_NAME),
  2247. DS_FQDN_1779_NAME);
  2248. }
  2249. if (SUCCEEDED(hr))
  2250. {
  2251. hr = IsValidObject(pldap, bstrVolumeObjectDN);
  2252. if (S_OK == hr)
  2253. {
  2254. hr = ModifyShareObject(
  2255. pldap,
  2256. bstrVolumeObjectDN,
  2257. i_pszUNCPath,
  2258. i_pszDescription,
  2259. i_pszKeywords,
  2260. bstrManagedByFQDN);
  2261. } else
  2262. {
  2263. hr = CreateVolumeObject(
  2264. pldap,
  2265. bstrVolumeObjectDN,
  2266. i_pszUNCPath,
  2267. i_pszDescription,
  2268. i_pszKeywords,
  2269. bstrManagedByFQDN);
  2270. }
  2271. }
  2272. } else
  2273. {
  2274. hr = DeleteDSObject(pldap, bstrVolumeObjectDN, TRUE);
  2275. if (S_FALSE == hr)
  2276. hr = S_OK; // ignore non-existing object
  2277. }
  2278. CloseConnectionToDS(pldap);
  2279. }
  2280. dfsDebugOut((_T("ModifySharePublishInfoOnSARoot hr=%x\n"), hr));
  2281. return hr;
  2282. }
  2283. HRESULT PutMultiValuesIntoAttrValList(
  2284. IN PCTSTR i_pszValues,
  2285. OUT LDAP_ATTR_VALUE** o_pVal
  2286. )
  2287. {
  2288. if (!i_pszValues || !o_pVal)
  2289. return E_INVALIDARG;
  2290. LDAP_ATTR_VALUE* pHead = NULL;
  2291. LDAP_ATTR_VALUE* pCurrent = NULL;
  2292. int index = 0;
  2293. CComBSTR bstrToken;
  2294. HRESULT hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);
  2295. while (SUCCEEDED(hr) && (BSTR)bstrToken)
  2296. {
  2297. TrimBSTR(bstrToken);
  2298. if (*bstrToken)
  2299. {
  2300. LDAP_ATTR_VALUE* pNew = new LDAP_ATTR_VALUE;
  2301. RETURN_OUTOFMEMORY_IF_NULL(pNew);
  2302. pNew->vpValue = _tcsdup(bstrToken);
  2303. if (!(pNew->vpValue))
  2304. {
  2305. delete pNew;
  2306. hr = E_OUTOFMEMORY;
  2307. break;
  2308. }
  2309. if (!pHead)
  2310. {
  2311. pHead = pCurrent = pNew;
  2312. } else
  2313. {
  2314. pCurrent->Next = pNew;
  2315. pCurrent = pNew;
  2316. }
  2317. }
  2318. bstrToken.Empty();
  2319. hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);
  2320. }
  2321. if (FAILED(hr))
  2322. {
  2323. FreeAttrValList(pHead);
  2324. return hr;
  2325. }
  2326. int nCount = 0;
  2327. pCurrent = pHead;
  2328. while (pCurrent)
  2329. {
  2330. nCount++;
  2331. pCurrent = pCurrent->Next;
  2332. }
  2333. if (!nCount)
  2334. return S_FALSE; // no token
  2335. *o_pVal = pHead;
  2336. return S_OK;
  2337. }
  2338. HRESULT PutMultiValuesIntoStringArray(
  2339. IN PCTSTR i_pszValues,
  2340. OUT PTSTR** o_pVal
  2341. )
  2342. {
  2343. if (!i_pszValues || !o_pVal)
  2344. return E_INVALIDARG;
  2345. int nCount = 0;
  2346. CComBSTR bstrToken;
  2347. int index = 0;
  2348. HRESULT hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);
  2349. while (SUCCEEDED(hr) && (BSTR)bstrToken)
  2350. {
  2351. nCount++;
  2352. bstrToken.Empty();
  2353. hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);;
  2354. }
  2355. if (!nCount)
  2356. return E_INVALIDARG;
  2357. PTSTR* ppszStrings = (PTSTR *)calloc(nCount + 1, sizeof(PTSTR *));
  2358. RETURN_OUTOFMEMORY_IF_NULL(ppszStrings);
  2359. nCount = 0;
  2360. index = 0;
  2361. bstrToken.Empty();
  2362. hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);
  2363. while (SUCCEEDED(hr) && (BSTR)bstrToken)
  2364. {
  2365. TrimBSTR(bstrToken);
  2366. if (*bstrToken)
  2367. {
  2368. ppszStrings[nCount] = _tcsdup(bstrToken);
  2369. BREAK_OUTOFMEMORY_IF_NULL(ppszStrings[nCount], &hr);
  2370. nCount++;
  2371. }
  2372. bstrToken.Empty();
  2373. hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);;
  2374. }
  2375. if (FAILED(hr))
  2376. FreeStringArray(ppszStrings);
  2377. else
  2378. *o_pVal = ppszStrings;
  2379. return hr;
  2380. }
  2381. //
  2382. // free a null-terminated array of strings
  2383. //
  2384. void FreeStringArray(PTSTR* i_ppszStrings)
  2385. {
  2386. if (i_ppszStrings)
  2387. {
  2388. PTSTR* ppszString = i_ppszStrings;
  2389. while (*ppszString)
  2390. {
  2391. free(*ppszString);
  2392. ppszString++;
  2393. }
  2394. free(i_ppszStrings);
  2395. }
  2396. }
  2397. HRESULT mystrtok(
  2398. IN PCTSTR i_pszString,
  2399. IN OUT int* io_pnIndex, // start from 0
  2400. IN PCTSTR i_pszCharSet,
  2401. OUT BSTR* o_pbstrToken
  2402. )
  2403. {
  2404. if (!i_pszString || !*i_pszString ||
  2405. !i_pszCharSet || !io_pnIndex ||
  2406. !o_pbstrToken)
  2407. return E_INVALIDARG;
  2408. *o_pbstrToken = NULL;
  2409. HRESULT hr = S_OK;
  2410. if (*io_pnIndex >= lstrlen(i_pszString))
  2411. {
  2412. return hr; // no more tokens
  2413. }
  2414. TCHAR *ptchStart = (PTSTR)i_pszString + *io_pnIndex;
  2415. if (!*i_pszCharSet)
  2416. {
  2417. *o_pbstrToken = SysAllocString(ptchStart);
  2418. if (!*o_pbstrToken)
  2419. hr = E_OUTOFMEMORY;
  2420. return hr;
  2421. }
  2422. //
  2423. // move p to the 1st char of the token
  2424. //
  2425. TCHAR *p = ptchStart;
  2426. while (*p)
  2427. {
  2428. if (_tcschr(i_pszCharSet, *p))
  2429. p++;
  2430. else
  2431. break;
  2432. }
  2433. ptchStart = p; // adjust ptchStart to point at the 1st char of the token
  2434. //
  2435. // move p to the char after the last char of the token
  2436. //
  2437. while (*p)
  2438. {
  2439. if (_tcschr(i_pszCharSet, *p))
  2440. break;
  2441. else
  2442. p++;
  2443. }
  2444. //
  2445. // ptchStart: points at the 1st char of the token
  2446. // p: points at the char after the last char of the token
  2447. //
  2448. if (ptchStart != p)
  2449. {
  2450. *o_pbstrToken = SysAllocStringLen(ptchStart, (int)(p - ptchStart));
  2451. if (!*o_pbstrToken)
  2452. hr = E_OUTOFMEMORY;
  2453. *io_pnIndex = (int)(p - i_pszString);
  2454. }
  2455. return hr;
  2456. }
  2457. //
  2458. // trim off space chars at the beginning and at the end of the string
  2459. //
  2460. void TrimBSTR(BSTR bstr)
  2461. {
  2462. if (!bstr)
  2463. return;
  2464. TCHAR* p = bstr;
  2465. //
  2466. // trim off space chars at the beginning
  2467. //
  2468. while (*p)
  2469. {
  2470. if (_istspace(*p))
  2471. p++;
  2472. else
  2473. break;
  2474. }
  2475. if (p > bstr)
  2476. _tcscpy(bstr, p);
  2477. int len = _tcslen(bstr);
  2478. if (len > 0)
  2479. {
  2480. //
  2481. // trim off space chars at the end
  2482. //
  2483. p = bstr + len - 1; // the char before the ending '\0'
  2484. while (p > bstr)
  2485. {
  2486. if (_istspace(*p))
  2487. p--;
  2488. else
  2489. {
  2490. *(p+1) = _T('\0');
  2491. break;
  2492. }
  2493. }
  2494. }
  2495. }
  2496. BOOL CheckPolicyOnSharePublish()
  2497. {
  2498. //
  2499. // check group policy
  2500. //
  2501. BOOL bAddPublishPage = TRUE; // by default, we display the share publish page
  2502. HKEY hKey = NULL;
  2503. DWORD dwType = 0;
  2504. DWORD dwData = 0;
  2505. DWORD cbData = sizeof(dwData);
  2506. LONG lErr = RegOpenKeyEx(
  2507. HKEY_CURRENT_USER,
  2508. _T("Software\\Policies\\Microsoft\\Windows NT\\SharedFolders"),
  2509. 0,
  2510. KEY_QUERY_VALUE,
  2511. &hKey);
  2512. if (ERROR_SUCCESS == lErr)
  2513. {
  2514. lErr = RegQueryValueEx(hKey, _T("PublishDfsRoots"), 0, &dwType, (LPBYTE)&dwData, &cbData);
  2515. if (ERROR_SUCCESS == lErr &&
  2516. REG_DWORD == dwType &&
  2517. 0 == dwData) // policy is disabled
  2518. bAddPublishPage = FALSE;
  2519. RegCloseKey(hKey);
  2520. }
  2521. return bAddPublishPage;
  2522. }
  2523. BOOL CheckPolicyOnDisplayingInitialMaster()
  2524. {
  2525. BOOL bShowInitialMaster = FALSE; // by default, we hide the initial master on property page
  2526. HKEY hKey = NULL;
  2527. DWORD dwType = 0;
  2528. DWORD dwData = 0;
  2529. DWORD cbData = sizeof(dwData);
  2530. LONG lErr = RegOpenKeyEx(
  2531. HKEY_LOCAL_MACHINE,
  2532. _T("Software\\Microsoft\\DfsGui"),
  2533. 0,
  2534. KEY_QUERY_VALUE,
  2535. &hKey);
  2536. if (ERROR_SUCCESS == lErr)
  2537. {
  2538. lErr = RegQueryValueEx(hKey, _T("ShowInitialMaster"), 0, &dwType, (LPBYTE)&dwData, &cbData);
  2539. if (ERROR_SUCCESS == lErr &&
  2540. REG_DWORD == dwType &&
  2541. 1 == dwData)
  2542. bShowInitialMaster = TRUE;
  2543. RegCloseKey(hKey);
  2544. }
  2545. return bShowInitialMaster;
  2546. }
  2547. HRESULT GetMenuResourceStrings(
  2548. IN int i_iStringID,
  2549. OUT BSTR* o_pbstrMenuText,
  2550. OUT BSTR* o_pbstrToolTipText,
  2551. OUT BSTR* o_pbstrStatusBarText
  2552. )
  2553. {
  2554. if (!i_iStringID)
  2555. return E_INVALIDARG;
  2556. if (o_pbstrMenuText)
  2557. *o_pbstrMenuText = NULL;
  2558. if (o_pbstrToolTipText)
  2559. *o_pbstrToolTipText = NULL;
  2560. if (o_pbstrStatusBarText)
  2561. *o_pbstrStatusBarText = NULL;
  2562. TCHAR *pszMenuText = NULL;
  2563. TCHAR *pszToolTipText = NULL;
  2564. TCHAR *pszStatusBarText = NULL;
  2565. TCHAR *p = NULL;
  2566. CComBSTR bstr;
  2567. HRESULT hr = LoadStringFromResource(i_iStringID, &bstr);
  2568. RETURN_IF_FAILED(hr);
  2569. pszMenuText = (BSTR)bstr;
  2570. p = _tcschr(pszMenuText, _T('|'));
  2571. RETURN_INVALIDARG_IF_NULL(p);
  2572. *p++ = _T('\0');
  2573. pszToolTipText = p;
  2574. p = _tcschr(pszToolTipText, _T('|'));
  2575. RETURN_INVALIDARG_IF_NULL(p);
  2576. *p++ = _T('\0');
  2577. pszStatusBarText = p;
  2578. do {
  2579. if (o_pbstrMenuText)
  2580. {
  2581. *o_pbstrMenuText = SysAllocString(pszMenuText);
  2582. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrMenuText, &hr);
  2583. }
  2584. if (o_pbstrToolTipText)
  2585. {
  2586. *o_pbstrToolTipText = SysAllocString(pszToolTipText);
  2587. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrToolTipText, &hr);
  2588. }
  2589. if (o_pbstrStatusBarText)
  2590. {
  2591. *o_pbstrStatusBarText = SysAllocString(pszStatusBarText);
  2592. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrStatusBarText, &hr);
  2593. }
  2594. } while (0);
  2595. if (FAILED(hr))
  2596. {
  2597. if (o_pbstrMenuText && *o_pbstrMenuText)
  2598. SysFreeString(*o_pbstrMenuText);
  2599. if (o_pbstrToolTipText && *o_pbstrToolTipText)
  2600. SysFreeString(*o_pbstrToolTipText);
  2601. if (o_pbstrStatusBarText && *o_pbstrStatusBarText)
  2602. SysFreeString(*o_pbstrStatusBarText);
  2603. }
  2604. return hr;
  2605. }
  2606. WNDPROC g_fnOldEditCtrlProc;
  2607. //+----------------------------------------------------------------------------
  2608. //
  2609. // Function: NoPasteEditCtrlProc
  2610. //
  2611. // Synopsis: The subclassed edit control callback procedure.
  2612. // The paste of this edit control is disabled.
  2613. //
  2614. //-----------------------------------------------------------------------------
  2615. LRESULT CALLBACK
  2616. NoPasteEditCtrlProc(
  2617. HWND hwnd,
  2618. UINT uMsg,
  2619. WPARAM wParam,
  2620. LPARAM lParam
  2621. )
  2622. {
  2623. if (WM_PASTE == uMsg)
  2624. {
  2625. ::MessageBeep (0);
  2626. return TRUE;
  2627. }
  2628. return CallWindowProc(g_fnOldEditCtrlProc, hwnd, uMsg, wParam, lParam);
  2629. }
  2630. void SetActivePropertyPage(IN HWND i_hwndParent, IN HWND i_hwndPage)
  2631. {
  2632. int index = ::SendMessage(i_hwndParent, PSM_HWNDTOINDEX, (WPARAM)i_hwndPage, 0);
  2633. if (-1 != index)
  2634. ::SendMessage(i_hwndParent, PSM_SETCURSEL, (WPARAM)index, 0);
  2635. }
  2636. void MyShowWindow(HWND hwnd, BOOL bShow)
  2637. {
  2638. ::ShowWindow(hwnd, (bShow ? SW_NORMAL : SW_HIDE));
  2639. ::EnableWindow(hwnd, (bShow ? TRUE : FALSE));
  2640. }