Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3295 lines
86 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, 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. PTSTR lpszShare = _tcschr(lpszServer, _T('\\'));
  693. if (!lpszShare)
  694. break;
  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[0] )
  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. DWORD dwPathType = 0;
  780. DWORD dwStatus = I_NetPathType(
  781. NULL,
  782. const_cast<LPTSTR>(lpszPath),
  783. &dwPathType,
  784. 0);
  785. if (dwStatus)
  786. return FALSE;
  787. if (dwPathType ^ ITYPE_PATH_ABSD)
  788. return FALSE;
  789. return TRUE;
  790. }
  791. //
  792. // This function will return the full path with the \\?\ prefix.
  793. // That is, \\?\X:\a\b\c if local, or \\?\UNC\server\X$\a\b\c if remote.
  794. //
  795. HRESULT
  796. GetFullPath(
  797. IN LPCTSTR lpszServer,
  798. IN LPCTSTR lpszPath,
  799. OUT BSTR *o_pbstrFullPath
  800. )
  801. {
  802. _ASSERT(IsValidLocalAbsolutePath(lpszPath));
  803. CComBSTR bstrFullPath;
  804. if (S_OK == IsComputerLocal(lpszServer))
  805. {
  806. bstrFullPath = _T("\\\\?\\");
  807. bstrFullPath += lpszPath;
  808. } else
  809. {
  810. bstrFullPath = _T("\\\\?\\UNC\\");
  811. if (mylstrncmpi(_T("\\\\"), lpszServer, 2))
  812. {
  813. bstrFullPath += lpszServer;
  814. } else
  815. {
  816. bstrFullPath += lpszServer + 2;
  817. }
  818. bstrFullPath += _T("\\");
  819. bstrFullPath += lpszPath;
  820. TCHAR *p = _tcschr(bstrFullPath, _T(':'));
  821. if (p)
  822. {
  823. *p = _T('$');
  824. }
  825. }
  826. *o_pbstrFullPath = bstrFullPath.Detach();
  827. return S_OK;
  828. }
  829. // Purpose: verify if the specified drive belongs to a list of disk drives on the server
  830. // Return:
  831. // S_OK: yes
  832. // S_FALSE: no
  833. // hr: some error happened
  834. HRESULT
  835. VerifyDriveLetter(
  836. IN LPCTSTR lpszServer,
  837. IN LPCTSTR lpszPath
  838. )
  839. {
  840. _ASSERT(IsValidLocalAbsolutePath(lpszPath));
  841. HRESULT hr = S_FALSE;
  842. LPBYTE pBuffer = NULL;
  843. DWORD dwEntriesRead = 0;
  844. DWORD dwTotalEntries = 0;
  845. DWORD dwRet = NetServerDiskEnum(
  846. const_cast<LPTSTR>(lpszServer),
  847. 0,
  848. &pBuffer,
  849. (DWORD)-1,
  850. &dwEntriesRead,
  851. &dwTotalEntries,
  852. NULL);
  853. if (NERR_Success == dwRet)
  854. {
  855. LPTSTR pDrive = (LPTSTR)pBuffer;
  856. for (UINT i=0; i<dwEntriesRead; i++)
  857. {
  858. if (!mylstrncmpi(pDrive, lpszPath, 1))
  859. {
  860. hr = S_OK;
  861. break;
  862. }
  863. pDrive += 3;
  864. }
  865. NetApiBufferFree(pBuffer);
  866. } else
  867. {
  868. hr = HRESULT_FROM_WIN32(dwRet);
  869. }
  870. return hr;
  871. }
  872. // Purpose: is there a related admin $ share
  873. // Return:
  874. // S_OK: yes
  875. // S_FALSE: no
  876. // hr: some error happened
  877. HRESULT
  878. IsAdminShare(
  879. IN LPCTSTR lpszServer,
  880. IN LPCTSTR lpszPath
  881. )
  882. {
  883. _ASSERT(S_OK != IsComputerLocal(lpszServer));
  884. _ASSERT(IsValidLocalAbsolutePath(lpszPath));
  885. HRESULT hr = S_FALSE;
  886. LPBYTE pBuffer = NULL;
  887. DWORD dwEntriesRead = 0;
  888. DWORD dwTotalEntries = 0;
  889. DWORD dwRet = NetShareEnum(
  890. const_cast<LPTSTR>(lpszServer),
  891. 1,
  892. &pBuffer,
  893. (DWORD)-1,
  894. &dwEntriesRead,
  895. &dwTotalEntries,
  896. NULL);
  897. if (NERR_Success == dwRet)
  898. {
  899. PSHARE_INFO_1 pShareInfo = (PSHARE_INFO_1)pBuffer;
  900. for (UINT i=0; i<dwEntriesRead; i++)
  901. {
  902. if ( (pShareInfo->shi1_type & STYPE_SPECIAL) &&
  903. _tcslen(pShareInfo->shi1_netname) == 2 &&
  904. *(pShareInfo->shi1_netname + 1) == _T('$') &&
  905. !mylstrncmpi(pShareInfo->shi1_netname, lpszPath, 1) )
  906. {
  907. hr = S_OK;
  908. break;
  909. }
  910. pShareInfo++;
  911. }
  912. NetApiBufferFree(pBuffer);
  913. } else
  914. {
  915. hr = HRESULT_FROM_WIN32(dwRet);
  916. }
  917. return hr;
  918. }
  919. //+---------------------------------------------------------------------------
  920. //
  921. // Function: IsAnExistingFolder
  922. //
  923. // Synopsis: Check if pszPath is pointing at an existing folder.
  924. //
  925. // S_OK: The specified path points to an existing folder.
  926. // S_FALSE: The specified path doesn't point to an existing folder.
  927. // hr: Failed to get info on the specified path, or
  928. // the path exists but doesn't point to a folder.
  929. // The function reports error msg for both failures if desired.
  930. //----------------------------------------------------------------------------
  931. HRESULT
  932. IsAnExistingFolder(
  933. IN HWND hwnd,
  934. IN LPCTSTR pszPath // points to path with "\\?\" prefix
  935. )
  936. {
  937. if (!hwnd)
  938. hwnd = GetActiveWindow();
  939. HRESULT hr = S_OK;
  940. WIN32_FILE_ATTRIBUTE_DATA fad = {0};
  941. if (!GetFileAttributesEx(pszPath, GetFileExInfoStandard, &fad))
  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. DisplayMessageBox(hwnd, MB_OK, dwErr, IDS_FAILED_TO_GETINFO_FOLDER, pszPath);
  952. hr = HRESULT_FROM_WIN32(dwErr);
  953. }
  954. } else if ( 0 == (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
  955. {
  956. // the specified path is not pointing to a folder
  957. DisplayMessageBox(hwnd, MB_OK, 0, IDS_PATH_NOT_FOLDER, pszPath);
  958. hr = E_FAIL;
  959. }
  960. return hr;
  961. }
  962. // create the directories layer by layer
  963. HRESULT
  964. CreateLayeredDirectory(
  965. IN LPCTSTR lpszServer,
  966. IN LPCTSTR lpszPath
  967. )
  968. {
  969. _ASSERT(IsValidLocalAbsolutePath(lpszPath));
  970. //
  971. // get the full path with \\?\ prefix, such that CreateDirectory
  972. // will turn off path parsing in case our path is longer than MAX_PATH
  973. //
  974. CComBSTR bstrFullPath;
  975. GetFullPath(lpszServer, lpszPath, &bstrFullPath);
  976. LPTSTR p = _tcschr(bstrFullPath,
  977. (S_OK == IsComputerLocal(lpszServer)) ? _T(':') : _T('$'));
  978. //
  979. // bstrFullPath is either "\\?\C:\a\b\c\d" or "\\?\UNC\server\C$\a\b\c\d"
  980. // move p to point at "a\b\c\d"
  981. //
  982. p += 2;
  983. BOOL bRet = TRUE;
  984. while (p && *p)
  985. {
  986. p = _tcschr(p, _T('\\'));
  987. if (p)
  988. *p = _T('\0');
  989. bRet = CreateDirectory(bstrFullPath, NULL);
  990. if (!bRet)
  991. {
  992. DWORD dwErr = GetLastError();
  993. if (dwErr != ERROR_ALREADY_EXISTS)
  994. return HRESULT_FROM_WIN32(dwErr);
  995. }
  996. if (p)
  997. *p++ = _T('\\'); // restore the backslash, move p to point at the char after the backslash
  998. }
  999. return S_OK;
  1000. }
  1001. HRESULT
  1002. BrowseNetworkPath(
  1003. IN HWND hwndParent,
  1004. OUT BSTR *o_pbstrPath
  1005. )
  1006. {
  1007. _ASSERT(o_pbstrPath);
  1008. HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  1009. if (SUCCEEDED(hr))
  1010. {
  1011. do
  1012. {
  1013. CComPtr<IMalloc> pMalloc;
  1014. hr = SHGetMalloc(&pMalloc);
  1015. if (FAILED(hr))
  1016. break;
  1017. CComBSTR bstrDlgLabel;
  1018. hr = LoadStringFromResource(IDS_BROWSE_NET_DLG, &bstrDlgLabel);
  1019. if (FAILED(hr))
  1020. break;
  1021. LPITEMIDLIST pItemIdList = NULL;
  1022. hr = SHGetSpecialFolderLocation(NULL, CSIDL_NETWORK, &pItemIdList);
  1023. if (FAILED(hr))
  1024. break;
  1025. BROWSEINFO bi = {hwndParent,
  1026. pItemIdList,
  1027. 0,
  1028. bstrDlgLabel,
  1029. BIF_RETURNONLYFSDIRS,
  1030. NULL,
  1031. NULL,
  1032. 0};
  1033. LPITEMIDLIST pItemIdListBr = SHBrowseForFolder(&bi);
  1034. if (!pItemIdListBr)
  1035. {
  1036. hr = S_FALSE; // user clicked Cancel
  1037. } else
  1038. {
  1039. CComBSTR bstrPath;
  1040. TCHAR szPath[MAX_PATH] = _T("\0");
  1041. SHGetPathFromIDList(pItemIdListBr, szPath);
  1042. //
  1043. // try to use Dns server name
  1044. //
  1045. if (CheckRegKey() &&
  1046. S_OK == CheckUNCPath(szPath))
  1047. {
  1048. PTSTR lpszServer = szPath + 2; // skip the first "\\"
  1049. PTSTR lpszShare = _tcschr(lpszServer, _T('\\'));
  1050. CComBSTR bstrServer = CComBSTR(lpszShare - lpszServer, lpszServer);
  1051. CComBSTR bstrDnsServer;
  1052. hr = GetServerInfo(bstrServer,
  1053. NULL, // Domain
  1054. NULL, // NetbiosName
  1055. NULL, // bValidDSObject
  1056. &bstrDnsServer);
  1057. if (S_OK == hr)
  1058. {
  1059. bstrPath = _T("\\\\");
  1060. bstrPath += bstrDnsServer;
  1061. bstrPath += lpszShare;
  1062. } else
  1063. {
  1064. hr = S_OK; // reset hr
  1065. bstrPath = szPath;
  1066. }
  1067. } else
  1068. {
  1069. bstrPath = szPath;
  1070. }
  1071. *o_pbstrPath = bstrPath.Detach();
  1072. pMalloc->Free(pItemIdListBr);
  1073. }
  1074. pMalloc->Free(pItemIdList);
  1075. } while (0);
  1076. CoUninitialize();
  1077. }
  1078. if (FAILED(hr))
  1079. DisplayMessageBox(hwndParent, MB_OK, hr, IDS_FAILED_TO_BROWSE_NETWORKPATH);
  1080. return hr;
  1081. }
  1082. #define MAX_DFS_REFERRAL_TIME 0xFFFFFFFF
  1083. BOOL
  1084. ValidateTimeout(
  1085. IN LPCTSTR lpszTimeout,
  1086. OUT ULONG *pulTimeout
  1087. )
  1088. {
  1089. BOOL bReturn = FALSE;
  1090. if (pulTimeout)
  1091. {
  1092. *pulTimeout = 0;
  1093. __int64 i64Timeout = _wtoi64(lpszTimeout);
  1094. if (i64Timeout <= MAX_DFS_REFERRAL_TIME)
  1095. {
  1096. bReturn = TRUE;
  1097. *pulTimeout = (ULONG)i64Timeout;
  1098. }
  1099. }
  1100. return bReturn;
  1101. }
  1102. #include "winnetp.h"
  1103. // retrieve system drive letter on the specified machine
  1104. HRESULT GetSystemDrive(IN LPCTSTR lpszComputer, OUT TCHAR *ptch)
  1105. {
  1106. _ASSERT(ptch);
  1107. HRESULT hr = S_OK;
  1108. SHARE_INFO_2* pShareInfo = NULL;
  1109. NET_API_STATUS nstatRetVal = NetShareGetInfo(
  1110. const_cast<LPTSTR>(lpszComputer),
  1111. _T("Admin$"),
  1112. 2,
  1113. (LPBYTE *)&pShareInfo);
  1114. if (nstatRetVal == NERR_Success)
  1115. {
  1116. _ASSERT(_T(':') == *(pShareInfo->shi2_path + 1));
  1117. *ptch = *(pShareInfo->shi2_path);
  1118. } else
  1119. {
  1120. hr = HRESULT_FROM_WIN32(nstatRetVal);
  1121. }
  1122. return hr;
  1123. }
  1124. //
  1125. // return a drive letter X, the staging path will be created at <X>:\FRS-Staging
  1126. // Try to exclude the following drives for performance consideration:
  1127. // 1. system drive: because the jet database ntfrs uses resides on system drive
  1128. // 2. the drive the replica folder sits on
  1129. // Will try to return a drive with the most free space
  1130. //
  1131. TCHAR
  1132. GetDiskForStagingPath(
  1133. IN LPCTSTR i_lpszServer,
  1134. IN TCHAR i_tch
  1135. )
  1136. {
  1137. _ASSERT(i_lpszServer && *i_lpszServer);
  1138. _ASSERT(_istalpha(i_tch));
  1139. TCHAR tchDrive = i_tch;
  1140. //
  1141. // retrieve the system drive letter on the specified machine
  1142. //
  1143. TCHAR tchSystemDrive;
  1144. if (S_OK != GetSystemDrive(i_lpszServer, &tchSystemDrive))
  1145. return tchDrive;
  1146. //
  1147. // enumerate all shareable disks, e.g., \\server\C$, \\server\D$, etc.
  1148. //
  1149. CComBSTR bstrServer;
  1150. if (mylstrncmpi(i_lpszServer, _T("\\\\"), 2))
  1151. {
  1152. bstrServer = _T("\\\\");
  1153. bstrServer += i_lpszServer;
  1154. } else
  1155. bstrServer = i_lpszServer;
  1156. NETRESOURCE nr;
  1157. nr.dwScope = RESOURCE_SHAREABLE;
  1158. nr.dwType = RESOURCETYPE_ANY;
  1159. nr.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  1160. nr.dwUsage = RESOURCEUSAGE_CONTAINER;
  1161. nr.lpLocalName = _T("");
  1162. nr.lpRemoteName = bstrServer;
  1163. nr.lpComment = _T("");
  1164. nr.lpProvider = _T("");
  1165. HANDLE hEnum = NULL;
  1166. DWORD dwResult = WNetOpenEnum (
  1167. RESOURCE_SHAREABLE,
  1168. RESOURCETYPE_ANY,
  1169. RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER,
  1170. &nr,
  1171. &hEnum);
  1172. if (dwResult == NO_ERROR)
  1173. {
  1174. NETRESOURCE nrBuffer[26];
  1175. DWORD dwBufferSize = 26 * sizeof(NETRESOURCE);
  1176. DWORD dwNumEntries = 0xFFFFFFFF; // Enumerate all possible entries.
  1177. dwResult = WNetEnumResource (
  1178. hEnum,
  1179. &dwNumEntries,
  1180. nrBuffer,
  1181. &dwBufferSize);
  1182. if (dwResult == NO_ERROR)
  1183. {
  1184. ULONGLONG ullFreeSpace = 0;
  1185. for (DWORD dwIndex = 0; dwIndex < dwNumEntries; dwIndex++)
  1186. {
  1187. //
  1188. // lpRemoteName contains string in the form of \\server\C$
  1189. //
  1190. TCHAR *p = nrBuffer[dwIndex].lpRemoteName;
  1191. TCHAR tchCurrent = *(p + _tcslen(p) - 2);
  1192. //
  1193. // exclude the current drive specified in i_tch
  1194. //
  1195. if ( _totupper(i_tch) == _totupper(tchCurrent) )
  1196. continue;
  1197. //
  1198. // skip if it's not a NTFS file system that supports object identifiers
  1199. //
  1200. TCHAR szFileSystemName[MAX_PATH + 1];
  1201. DWORD dwMaxCompLength = 0, dwFileSystemFlags = 0;
  1202. CComBSTR bstrRootPath = p;
  1203. if (_T('\\') != *(p + _tcslen(p) - 1))
  1204. bstrRootPath += _T("\\");
  1205. if (FALSE == GetVolumeInformation(bstrRootPath, NULL, 0, NULL, &dwMaxCompLength,
  1206. &dwFileSystemFlags, szFileSystemName, MAX_PATH))
  1207. continue;
  1208. if (CSTR_EQUAL != CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, _T("NTFS"), -1, szFileSystemName, -1) ||
  1209. !(FILE_SUPPORTS_OBJECT_IDS & dwFileSystemFlags))
  1210. continue;
  1211. //
  1212. // 1. when i_tch is on a non-system drive and system drive is NTFS,
  1213. // change default to system drive
  1214. // 2. when other NTFS drives present, exclude system drive
  1215. //
  1216. if ( _totupper(tchSystemDrive) == _totupper(tchCurrent) )
  1217. {
  1218. if ( 0 == ullFreeSpace )
  1219. tchDrive = tchSystemDrive;
  1220. continue;
  1221. }
  1222. //
  1223. // find out the drive that has the most free space
  1224. //
  1225. ULARGE_INTEGER ulgiFreeBytesAvailableToCaller;
  1226. ULARGE_INTEGER ulgiTotalNumberOfBytes;
  1227. if (GetDiskFreeSpaceEx(p,
  1228. &ulgiFreeBytesAvailableToCaller,
  1229. &ulgiTotalNumberOfBytes,
  1230. NULL))
  1231. {
  1232. if (ulgiFreeBytesAvailableToCaller.QuadPart > ullFreeSpace)
  1233. {
  1234. tchDrive = tchCurrent;
  1235. ullFreeSpace = ulgiFreeBytesAvailableToCaller.QuadPart;
  1236. }
  1237. }
  1238. }
  1239. }
  1240. WNetCloseEnum (hEnum);
  1241. }
  1242. return tchDrive;
  1243. }
  1244. HRESULT GetUNCPath
  1245. (
  1246. IN BSTR i_bstrServerName,
  1247. IN BSTR i_bstrShareName,
  1248. OUT BSTR* o_pbstrUNCPath
  1249. )
  1250. {
  1251. RETURN_INVALIDARG_IF_NULL(i_bstrServerName);
  1252. RETURN_INVALIDARG_IF_NULL(i_bstrShareName);
  1253. RETURN_INVALIDARG_IF_NULL(o_pbstrUNCPath);
  1254. CComBSTR bstrUNCPath;
  1255. bstrUNCPath = _T("\\\\");
  1256. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
  1257. bstrUNCPath += i_bstrServerName;
  1258. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
  1259. bstrUNCPath += _T("\\");
  1260. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
  1261. bstrUNCPath += i_bstrShareName;
  1262. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
  1263. *o_pbstrUNCPath = bstrUNCPath.Detach();
  1264. return S_OK;
  1265. }
  1266. HRESULT GetDfsRootDisplayName
  1267. (
  1268. IN BSTR i_bstrScopeName,
  1269. IN BSTR i_bstrDfsName,
  1270. OUT BSTR* o_pbstrDisplayName
  1271. )
  1272. {
  1273. return GetUNCPath(i_bstrScopeName, i_bstrDfsName, o_pbstrDisplayName);
  1274. }
  1275. HRESULT GetDfsReplicaDisplayName
  1276. (
  1277. IN BSTR i_bstrServerName,
  1278. IN BSTR i_bstrShareName,
  1279. OUT BSTR* o_pbstrDisplayName
  1280. )
  1281. {
  1282. return GetUNCPath(i_bstrServerName, i_bstrShareName, o_pbstrDisplayName);
  1283. }
  1284. HRESULT
  1285. AddLVColumns(
  1286. IN const HWND hwndListBox,
  1287. IN const INT iStartingResourceID,
  1288. IN const UINT uiColumns
  1289. )
  1290. {
  1291. //
  1292. // calculate the listview column width
  1293. //
  1294. RECT rect;
  1295. ZeroMemory(&rect, sizeof(rect));
  1296. ::GetWindowRect(hwndListBox, &rect);
  1297. int nControlWidth = rect.right - rect.left;
  1298. int nVScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL);
  1299. int nBorderWidth = GetSystemMetrics(SM_CXBORDER);
  1300. int nControlNetWidth = nControlWidth - 4 * nBorderWidth;
  1301. int nWidth = nControlNetWidth / uiColumns;
  1302. LVCOLUMN lvColumn;
  1303. ZeroMemory(&lvColumn, sizeof(lvColumn));
  1304. lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  1305. lvColumn.fmt = LVCFMT_LEFT;
  1306. lvColumn.cx = nWidth;
  1307. for (UINT i = 0; i < uiColumns; i++)
  1308. {
  1309. CComBSTR bstrColumnText;
  1310. LoadStringFromResource(iStartingResourceID + i, &bstrColumnText);
  1311. lvColumn.pszText = bstrColumnText;
  1312. lvColumn.iSubItem = i;
  1313. ListView_InsertColumn(hwndListBox, i, &lvColumn);
  1314. }
  1315. return S_OK;
  1316. }
  1317. LPARAM GetListViewItemData(
  1318. IN HWND hwndList,
  1319. IN int index
  1320. )
  1321. {
  1322. if (-1 == index)
  1323. return NULL;
  1324. LVITEM lvItem;
  1325. ZeroMemory(&lvItem, sizeof(lvItem));
  1326. lvItem.mask = LVIF_PARAM;
  1327. lvItem.iItem = index;
  1328. if (ListView_GetItem(hwndList, &lvItem))
  1329. return lvItem.lParam;
  1330. return NULL;
  1331. }
  1332. HRESULT CreateAndHideStagingPath(
  1333. IN BSTR i_bstrServer,
  1334. IN BSTR i_bstrStagingPath
  1335. )
  1336. {
  1337. RETURN_INVALIDARG_IF_NULL(i_bstrServer);
  1338. RETURN_INVALIDARG_IF_NULL(i_bstrStagingPath);
  1339. //
  1340. // Create the directory
  1341. //
  1342. HRESULT hr = CreateLayeredDirectory(i_bstrServer, i_bstrStagingPath);
  1343. if (FAILED(hr))
  1344. return hr;
  1345. //
  1346. // try to hide the staging directory, ignore errors
  1347. //
  1348. CComBSTR bstrFullPath;
  1349. GetFullPath(i_bstrServer, i_bstrStagingPath, &bstrFullPath);
  1350. WIN32_FILE_ATTRIBUTE_DATA fad = {0};
  1351. if (GetFileAttributesEx(bstrFullPath, GetFileExInfoStandard, &fad))
  1352. {
  1353. (void) SetFileAttributes(bstrFullPath, fad.dwFileAttributes | FILE_ATTRIBUTE_HIDDEN);
  1354. }
  1355. return S_OK;
  1356. }
  1357. //+-------------------------------------------------------------------------
  1358. //
  1359. // Function: ConfigAndStartNtfrs
  1360. //
  1361. // Synopsis: Config ntfrs to be AUTO_START, and start the service.
  1362. //
  1363. //--------------------------------------------------------------------------
  1364. HRESULT
  1365. ConfigAndStartNtfrs
  1366. (
  1367. BSTR i_bstrServer
  1368. )
  1369. {
  1370. HRESULT hr = S_OK;
  1371. SC_HANDLE hScManager = NULL;
  1372. SC_HANDLE hService = NULL;
  1373. SERVICE_STATUS svcStatus;
  1374. DWORD dwDesiredAccess = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_START;
  1375. do
  1376. {
  1377. if ((hScManager = ::OpenSCManager(i_bstrServer, NULL, SC_MANAGER_CONNECT )) == NULL ||
  1378. (hService = ::OpenService(hScManager, _T("ntfrs"), dwDesiredAccess)) == NULL ||
  1379. !ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE,
  1380. NULL, NULL, NULL, NULL, NULL, NULL, NULL) ||
  1381. !::QueryServiceStatus(hService, &svcStatus) )
  1382. {
  1383. hr = HRESULT_FROM_WIN32(GetLastError());
  1384. break;
  1385. }
  1386. if (SERVICE_RUNNING != svcStatus.dwCurrentState)
  1387. {
  1388. if (!StartService(hService, 0, NULL))
  1389. {
  1390. hr = HRESULT_FROM_WIN32(GetLastError());
  1391. break;
  1392. }
  1393. // The following is a cut&paste from MSDN article
  1394. // Check the status until the service is no longer start pending.
  1395. if (!QueryServiceStatus(hService,&svcStatus))
  1396. {
  1397. hr = HRESULT_FROM_WIN32(GetLastError());
  1398. break;
  1399. }
  1400. // Get the tick count before entering the loop.
  1401. DWORD dwStartTickCount = GetTickCount();
  1402. DWORD dwOldCheckPoint = svcStatus.dwCheckPoint;
  1403. DWORD dwWaitTime;
  1404. while (svcStatus.dwCurrentState == SERVICE_START_PENDING)
  1405. {
  1406. // Do not wait longer than the wait hint. A good interval is
  1407. // one tenth the wait hint, but no less than 1 second and no
  1408. // more than 10 seconds.
  1409. dwWaitTime = svcStatus.dwWaitHint / 10;
  1410. if ( dwWaitTime < 1000 )
  1411. dwWaitTime = 1000;
  1412. else if ( dwWaitTime > 10000 )
  1413. dwWaitTime = 10000;
  1414. Sleep( dwWaitTime );
  1415. // Check the status again.
  1416. if (!QueryServiceStatus(hService, &svcStatus))
  1417. break;
  1418. if (svcStatus.dwCheckPoint > dwOldCheckPoint)
  1419. {
  1420. // The service is making progress
  1421. dwStartTickCount = GetTickCount();
  1422. dwOldCheckPoint = svcStatus.dwCheckPoint;
  1423. }
  1424. else
  1425. {
  1426. if (GetTickCount() - dwStartTickCount > svcStatus.dwWaitHint)
  1427. {
  1428. // No progress made within the wait hint
  1429. break;
  1430. }
  1431. }
  1432. }
  1433. if (svcStatus.dwCurrentState == SERVICE_RUNNING)
  1434. hr = S_OK;
  1435. else
  1436. hr = HRESULT_FROM_WIN32(GetLastError());
  1437. }
  1438. } while ( FALSE );
  1439. if (hService)
  1440. CloseServiceHandle(hService);
  1441. if (hScManager)
  1442. CloseServiceHandle(hScManager);
  1443. return(hr);
  1444. }
  1445. //+-------------------------------------------------------------------------
  1446. //
  1447. // Function: CheckResourceProvider
  1448. //
  1449. // Synopsis: see if pszResource is provided by "Microsoft Windows Network".
  1450. //
  1451. //--------------------------------------------------------------------------
  1452. HRESULT
  1453. CheckResourceProvider(LPCTSTR pszResource)
  1454. {
  1455. DWORD dwError = 0;
  1456. NETRESOURCE nr = {0};
  1457. NETRESOURCE nrOut = {0};
  1458. LPTSTR pszSystem = NULL; // pointer to variable-length strings
  1459. NETRESOURCE *pBuffer = &nrOut; // buffer
  1460. DWORD cbResult = sizeof(nrOut); // buffer size
  1461. nr.dwScope = RESOURCE_GLOBALNET;
  1462. nr.dwType = RESOURCETYPE_DISK;
  1463. nr.lpRemoteName = (LPTSTR)pszResource;
  1464. //
  1465. // Find the right provider string for "Microsoft Windows Network".
  1466. //
  1467. // Network provider string is localizable. In order to support localized
  1468. // system or MUI on ENG system, we need to retrieve the name from system
  1469. // instead of load the string from a resource file.
  1470. //
  1471. TCHAR szProviderName[MAX_PATH];
  1472. DWORD dwNumOfChars = MAX_PATH;
  1473. PTSTR pszProviderName = szProviderName;
  1474. dwError = WNetGetProviderName(WNNC_NET_LANMAN, pszProviderName, &dwNumOfChars);
  1475. if (dwError == ERROR_MORE_DATA)
  1476. {
  1477. pszProviderName = (PTSTR)LocalAlloc(LMEM_FIXED, dwNumOfChars * sizeof(TCHAR));
  1478. if (!pszProviderName)
  1479. {
  1480. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1481. }
  1482. else
  1483. {
  1484. dwError = WNetGetProviderName(WNNC_NET_LANMAN, pszProviderName, &dwNumOfChars);
  1485. }
  1486. }
  1487. if (dwError == NO_ERROR)
  1488. {
  1489. nr.lpProvider = pszProviderName;
  1490. //
  1491. // First call the WNetGetResourceInformation function with
  1492. // memory allocated to hold only a NETRESOURCE structure. This
  1493. // method can succeed if all the NETRESOURCE pointers are NULL.
  1494. //
  1495. dwError = WNetGetResourceInformation(&nr, (LPBYTE)pBuffer, &cbResult, &pszSystem);
  1496. //
  1497. // If the call fails because the buffer is too small,
  1498. // call the LocalAlloc function to allocate a larger buffer.
  1499. //
  1500. if (dwError == ERROR_MORE_DATA)
  1501. {
  1502. pBuffer = (NETRESOURCE *)LocalAlloc(LMEM_FIXED, cbResult);
  1503. if (!pBuffer)
  1504. {
  1505. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1506. } else
  1507. {
  1508. // Call WNetGetResourceInformation again with the larger buffer.
  1509. dwError = WNetGetResourceInformation(&nr, (LPBYTE)pBuffer, &cbResult, &pszSystem);
  1510. }
  1511. }
  1512. if (dwError == NO_ERROR)
  1513. {
  1514. // If the call succeeds, process the contents of the
  1515. // returned NETRESOURCE structure and the variable-length
  1516. // strings in lpBuffer. Then free the memory.
  1517. //
  1518. if (pBuffer != &nrOut)
  1519. {
  1520. LocalFree(pBuffer);
  1521. }
  1522. }
  1523. }
  1524. if (pszProviderName && pszProviderName != szProviderName)
  1525. {
  1526. LocalFree(pszProviderName);
  1527. }
  1528. return (dwError == NO_ERROR ? S_OK : HRESULT_FROM_WIN32(dwError));
  1529. }
  1530. HRESULT FRSShareCheck
  1531. (
  1532. BSTR i_bstrServer,
  1533. BSTR i_bstrFolder,
  1534. OUT FRSSHARE_TYPE *pFRSShareType
  1535. )
  1536. /*++
  1537. Routine Description:
  1538. Performs FRS checks for the share to be able particiapte in a FRS set.
  1539. Arguments:
  1540. i_bstrServer - The server hosting the share
  1541. i_bstrFolder - The share path.
  1542. --*/
  1543. {
  1544. _ASSERT(i_bstrServer && *i_bstrServer && i_bstrFolder && *i_bstrFolder && pFRSShareType);
  1545. // Is the server a NT 5.0 server with FRS?
  1546. HRESULT hr = S_FALSE;
  1547. hr = FRSIsNTFRSInstalled(i_bstrServer);
  1548. if (S_FALSE == hr)
  1549. {
  1550. *pFRSShareType = FRSSHARE_TYPE_NONTFRS;
  1551. return hr;
  1552. } else if (FAILED(hr))
  1553. {
  1554. *pFRSShareType = FRSSHARE_TYPE_UNKNOWN;
  1555. return hr;
  1556. }
  1557. // Is the path on a valid disktree share?
  1558. hr = GetFolderInfo(i_bstrServer, i_bstrFolder);
  1559. if (STG_E_NOTFILEBASEDSTORAGE == hr)
  1560. {
  1561. *pFRSShareType = FRSSHARE_TYPE_NOTDISKTREE;
  1562. return S_FALSE;
  1563. } else if (FAILED(hr))
  1564. {
  1565. *pFRSShareType = FRSSHARE_TYPE_UNKNOWN;
  1566. return hr;
  1567. }
  1568. // Get root path as \\server\share
  1569. CComBSTR bstrRootPath = _T("\\\\");
  1570. bstrRootPath+= i_bstrServer;
  1571. bstrRootPath+= _T("\\");
  1572. TCHAR *p = _tcschr(i_bstrFolder, _T('\\'));
  1573. if (p)
  1574. {
  1575. bstrRootPath += CComBSTR(p - i_bstrFolder + 1, i_bstrFolder);
  1576. } else
  1577. {
  1578. bstrRootPath += i_bstrFolder;
  1579. bstrRootPath+= _T("\\");
  1580. }
  1581. TCHAR szFileSystemName[MAX_PATH];
  1582. DWORD dwMaxCompLength = 0, dwFileSystemFlags = 0;
  1583. _ASSERT(bstrRootPath);
  1584. // on NTFS file system that supports object identifiers?
  1585. if (0 == GetVolumeInformation(
  1586. bstrRootPath, // Volume path
  1587. NULL, // Volume name not required
  1588. 0, // Size of volume name buffer
  1589. NULL, // Serial number not required.
  1590. &dwMaxCompLength,
  1591. &dwFileSystemFlags,
  1592. szFileSystemName,
  1593. MAX_PATH
  1594. ))
  1595. {
  1596. *pFRSShareType = FRSSHARE_TYPE_UNKNOWN;
  1597. return HRESULT_FROM_WIN32(GetLastError());
  1598. }
  1599. if (CSTR_EQUAL != CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, _T("NTFS"), -1, szFileSystemName, -1) || !(FILE_SUPPORTS_OBJECT_IDS & dwFileSystemFlags))
  1600. {
  1601. *pFRSShareType = FRSSHARE_TYPE_NOTNTFS;
  1602. return S_FALSE;
  1603. }
  1604. *pFRSShareType = FRSSHARE_TYPE_OK;
  1605. return S_OK;
  1606. }
  1607. HRESULT FRSIsNTFRSInstalled
  1608. (
  1609. BSTR i_bstrServer
  1610. )
  1611. /*++
  1612. Routine Description:
  1613. Checks if the computer has ntfrs service.
  1614. Arguments:
  1615. i_bstrServer - The name of the server.
  1616. Return value:
  1617. S_OK, if server has ntfrs service.
  1618. S_FALSE, if server does not have ntfrs service installed.
  1619. --*/
  1620. {
  1621. if (!i_bstrServer)
  1622. return(E_INVALIDARG);
  1623. SC_HANDLE SCMHandle = NULL, NTFRSHandle = NULL;
  1624. HRESULT hr = S_FALSE;
  1625. SCMHandle = OpenSCManager (i_bstrServer, NULL, SC_MANAGER_CONNECT);
  1626. if (!SCMHandle)
  1627. return(HRESULT_FROM_WIN32(GetLastError()));
  1628. NTFRSHandle = OpenService (
  1629. SCMHandle,
  1630. _T("ntfrs"),
  1631. SERVICE_QUERY_STATUS
  1632. );
  1633. if (!NTFRSHandle)
  1634. {
  1635. DWORD dwError = GetLastError();
  1636. if (ERROR_SERVICE_DOES_NOT_EXIST == dwError)
  1637. hr = S_FALSE;
  1638. else
  1639. hr = HRESULT_FROM_WIN32(dwError);
  1640. CloseServiceHandle(SCMHandle);
  1641. return(hr);
  1642. } else
  1643. hr = S_OK;
  1644. CloseServiceHandle(NTFRSHandle);
  1645. CloseServiceHandle(SCMHandle);
  1646. return(hr);
  1647. }
  1648. typedef HRESULT (*pfnReplicationScheduleDialogEx)
  1649. (
  1650. HWND hwndParent, // parent window
  1651. BYTE ** pprgbData, // pointer to pointer to array of 84 bytes
  1652. LPCTSTR pszTitle, // dialog title
  1653. DWORD dwFlags // option flags
  1654. );
  1655. static HINSTANCE g_hDllSchedule = NULL;
  1656. static pfnReplicationScheduleDialogEx g_hProcSchedule = NULL;
  1657. //
  1658. // S_OK: button OK is clicked and the new schedule is returned in io_pSchedule
  1659. // S_FALSE: button Cancle is clicked, io_pSchedule is not touched
  1660. //
  1661. HRESULT InvokeScheduleDlg(
  1662. IN HWND i_hwndParent,
  1663. IN OUT SCHEDULE* io_pSchedule
  1664. )
  1665. {
  1666. CComBSTR bstrTitle;
  1667. HRESULT hr = LoadStringFromResource(IDS_SCHEDULE, &bstrTitle);
  1668. RETURN_IF_FAILED(hr);
  1669. //
  1670. // LoadLibrary
  1671. //
  1672. if (!g_hDllSchedule)
  1673. {
  1674. if (!(g_hDllSchedule = LoadLibrary(_T("loghours.dll"))) ||
  1675. !(g_hProcSchedule = (pfnReplicationScheduleDialogEx)GetProcAddress(g_hDllSchedule, "ReplicationScheduleDialogEx")) )
  1676. {
  1677. hr = HRESULT_FROM_WIN32(GetLastError());
  1678. if (g_hDllSchedule)
  1679. {
  1680. FreeLibrary(g_hDllSchedule);
  1681. g_hDllSchedule = NULL;
  1682. }
  1683. return hr;
  1684. }
  1685. }
  1686. //
  1687. // invoke the schedule dialog
  1688. //
  1689. BYTE* pbScheduleData = (BYTE *)io_pSchedule + io_pSchedule->Schedules->Offset;
  1690. hr = (*g_hProcSchedule)(i_hwndParent, &pbScheduleData, bstrTitle, 0);
  1691. return hr;
  1692. }
  1693. HRESULT TranslateManagedBy(
  1694. IN PCTSTR i_pszDC,
  1695. IN PCTSTR i_pszIn,
  1696. OUT BSTR* o_pbstrOut,
  1697. IN DS_NAME_FORMAT i_formatIn,
  1698. IN DS_NAME_FORMAT i_formatOut
  1699. )
  1700. {
  1701. RETURN_INVALIDARG_IF_NULL(o_pbstrOut);
  1702. *o_pbstrOut = NULL;
  1703. HRESULT hr = S_OK;
  1704. if (!i_pszIn || !*i_pszIn)
  1705. return hr;
  1706. CComBSTR bstr;
  1707. HANDLE hDS = NULL;
  1708. DWORD dwErr = DsBind(i_pszDC, NULL, &hDS);
  1709. if (ERROR_SUCCESS != dwErr)
  1710. {
  1711. hr = HRESULT_FROM_WIN32(dwErr);
  1712. } else
  1713. {
  1714. hr = CrackName( hDS,
  1715. (PTSTR)i_pszIn,
  1716. i_formatIn,
  1717. i_formatOut,
  1718. &bstr
  1719. );
  1720. DsUnBind(&hDS);
  1721. }
  1722. if (SUCCEEDED(hr))
  1723. *o_pbstrOut = bstr.Detach();
  1724. return hr;
  1725. }
  1726. HRESULT GetFTDfsObjectDN(
  1727. IN PCTSTR i_pszDomainName,
  1728. IN PCTSTR i_pszRootName,
  1729. OUT BSTR* o_pbstrFTDfsObjectDN
  1730. )
  1731. {
  1732. CComBSTR bstrDomainDN;
  1733. HRESULT hr = GetDomainInfo(
  1734. i_pszDomainName,
  1735. NULL, // return DC's Dns name
  1736. NULL, // return Domain's Dns name
  1737. &bstrDomainDN // return DC=nttest,DC=micr
  1738. );
  1739. RETURN_IF_FAILED(hr);
  1740. CComBSTR bstrFTDfsObjectDN = _T("CN=");
  1741. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1742. bstrFTDfsObjectDN += i_pszRootName;
  1743. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1744. bstrFTDfsObjectDN += _T(",");
  1745. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1746. bstrFTDfsObjectDN += _T("CN=Dfs-Configuration,CN=System,");
  1747. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1748. bstrFTDfsObjectDN += bstrDomainDN;
  1749. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
  1750. *o_pbstrFTDfsObjectDN = bstrFTDfsObjectDN.Detach();
  1751. return hr;
  1752. }
  1753. HRESULT ReadSharePublishInfoHelper(
  1754. PLDAP i_pldap,
  1755. LPCTSTR i_pszDN,
  1756. LPCTSTR i_pszSearchFilter,
  1757. OUT BOOL* o_pbPublish,
  1758. OUT BSTR* o_pbstrUNCPath,
  1759. OUT BSTR* o_pbstrDescription,
  1760. OUT BSTR* o_pbstrKeywords,
  1761. OUT BSTR* o_pbstrManagedBy)
  1762. {
  1763. dfsDebugOut((_T("ReadSharePublishInfoHelper %s %s\n"),
  1764. i_pszDN, i_pszSearchFilter));
  1765. *o_pbPublish = FALSE;
  1766. HRESULT hr = S_OK;
  1767. hr = IsValidObject(i_pldap, (PTSTR)i_pszDN);
  1768. if (S_OK != hr)
  1769. return hr;
  1770. LListElem* pElem = NULL;
  1771. do {
  1772. PCTSTR ppszAttributes[] = {
  1773. ATTR_SHRPUB_UNCNAME,
  1774. ATTR_SHRPUB_DESCRIPTION,
  1775. ATTR_SHRPUB_KEYWORDS,
  1776. ATTR_SHRPUB_MANAGEDBY,
  1777. 0
  1778. };
  1779. hr = GetValuesEx(
  1780. i_pldap,
  1781. i_pszDN,
  1782. LDAP_SCOPE_BASE,
  1783. i_pszSearchFilter,
  1784. ppszAttributes,
  1785. &pElem);
  1786. RETURN_IF_FAILED(hr);
  1787. if (!pElem || !pElem->pppszAttrValues)
  1788. return hr;
  1789. PTSTR** pppszValues = pElem->pppszAttrValues;
  1790. if (pppszValues[0] && *(pppszValues[0]))
  1791. {
  1792. *o_pbstrUNCPath = SysAllocString(*(pppszValues[0]));
  1793. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrUNCPath, &hr);
  1794. *o_pbPublish = TRUE;
  1795. }
  1796. if (pppszValues[1] && *(pppszValues[1]))
  1797. {
  1798. *o_pbstrDescription = SysAllocString(*(pppszValues[1]));
  1799. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrDescription, &hr);
  1800. }
  1801. if (pppszValues[2] && *(pppszValues[2]))
  1802. {
  1803. CComBSTR bstrKeywords;
  1804. PTSTR *ppszStrings = pppszValues[2];
  1805. while (*ppszStrings)
  1806. {
  1807. if (!bstrKeywords)
  1808. {
  1809. bstrKeywords = *ppszStrings;
  1810. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr);
  1811. } else
  1812. {
  1813. bstrKeywords += _T(";");
  1814. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr);
  1815. bstrKeywords += *ppszStrings;
  1816. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr);
  1817. }
  1818. ppszStrings++;
  1819. }
  1820. *o_pbstrKeywords = bstrKeywords.Detach();
  1821. }
  1822. if (pppszValues[3] && *(pppszValues[3]))
  1823. {
  1824. *o_pbstrManagedBy = SysAllocString(*(pppszValues[3]));
  1825. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrManagedBy, &hr);
  1826. }
  1827. } while (0);
  1828. if (pElem)
  1829. FreeLListElem(pElem);
  1830. return hr;
  1831. }
  1832. HRESULT ReadSharePublishInfoOnFTRoot(
  1833. LPCTSTR i_pszDomainName,
  1834. LPCTSTR i_pszRootName,
  1835. OUT BOOL* o_pbPublish,
  1836. OUT BSTR* o_pbstrUNCPath,
  1837. OUT BSTR* o_pbstrDescription,
  1838. OUT BSTR* o_pbstrKeywords,
  1839. OUT BSTR* o_pbstrManagedBy)
  1840. {
  1841. HRESULT hr = S_OK;
  1842. CComBSTR bstrFTDfsObjectDN;
  1843. hr = GetFTDfsObjectDN(i_pszDomainName, i_pszRootName, &bstrFTDfsObjectDN);
  1844. if (FAILED(hr))
  1845. return hr;
  1846. CComBSTR bstrDC;
  1847. PLDAP pldap = NULL;
  1848. hr = ConnectToDS(i_pszDomainName, &pldap, &bstrDC); // PDC is preferred
  1849. if (SUCCEEDED(hr))
  1850. {
  1851. CComBSTR bstrManagedByFQDN;
  1852. hr = ReadSharePublishInfoHelper(
  1853. pldap,
  1854. bstrFTDfsObjectDN,
  1855. OBJCLASS_SF_FTDFS,
  1856. o_pbPublish,
  1857. o_pbstrUNCPath,
  1858. o_pbstrDescription,
  1859. o_pbstrKeywords,
  1860. &bstrManagedByFQDN);
  1861. if (SUCCEEDED(hr))
  1862. {
  1863. hr = TranslateManagedBy(bstrDC,
  1864. bstrManagedByFQDN,
  1865. o_pbstrManagedBy,
  1866. DS_FQDN_1779_NAME,
  1867. DS_USER_PRINCIPAL_NAME);
  1868. if (FAILED(hr))
  1869. hr = TranslateManagedBy(bstrDC,
  1870. bstrManagedByFQDN,
  1871. o_pbstrManagedBy,
  1872. DS_FQDN_1779_NAME,
  1873. DS_NT4_ACCOUNT_NAME);
  1874. }
  1875. CloseConnectionToDS(pldap);
  1876. }
  1877. return hr;
  1878. }
  1879. HRESULT ReadSharePublishInfoOnSARoot(
  1880. LPCTSTR i_pszServerName,
  1881. LPCTSTR i_pszShareName,
  1882. OUT BOOL* o_pbPublish,
  1883. OUT BSTR* o_pbstrUNCPath,
  1884. OUT BSTR* o_pbstrDescription,
  1885. OUT BSTR* o_pbstrKeywords,
  1886. OUT BSTR* o_pbstrManagedBy)
  1887. {
  1888. RETURN_INVALIDARG_IF_NULL(i_pszServerName);
  1889. RETURN_INVALIDARG_IF_NULL(i_pszShareName);
  1890. RETURN_INVALIDARG_IF_NULL(o_pbPublish);
  1891. RETURN_INVALIDARG_IF_NULL(o_pbstrUNCPath);
  1892. RETURN_INVALIDARG_IF_NULL(o_pbstrDescription);
  1893. RETURN_INVALIDARG_IF_NULL(o_pbstrKeywords);
  1894. RETURN_INVALIDARG_IF_NULL(o_pbstrManagedBy);
  1895. *o_pbPublish = FALSE;
  1896. *o_pbstrUNCPath = NULL;
  1897. *o_pbstrDescription = NULL;
  1898. *o_pbstrKeywords = NULL;
  1899. *o_pbstrManagedBy = NULL;
  1900. CComBSTR bstrDomainName, bstrFQDN;
  1901. HRESULT hr = GetServerInfo(
  1902. (PTSTR)i_pszServerName,
  1903. &bstrDomainName,
  1904. NULL, //NetbiosName
  1905. NULL, //ValidDSObject
  1906. NULL, //DnsName,
  1907. NULL, //Guid,
  1908. &bstrFQDN);
  1909. if (S_OK != hr)
  1910. return hr;
  1911. CComBSTR bstrVolumeObjectDN = _T("CN=");
  1912. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  1913. bstrVolumeObjectDN += i_pszShareName;
  1914. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  1915. bstrVolumeObjectDN += _T(",");
  1916. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  1917. bstrVolumeObjectDN += bstrFQDN;
  1918. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  1919. CComBSTR bstrDC;
  1920. PLDAP pldap = NULL;
  1921. hr = ConnectToDS(bstrDomainName, &pldap, &bstrDC);
  1922. if (SUCCEEDED(hr))
  1923. {
  1924. CComBSTR bstrManagedByFQDN;
  1925. hr = ReadSharePublishInfoHelper(
  1926. pldap,
  1927. bstrVolumeObjectDN,
  1928. OBJCLASS_SF_VOLUME,
  1929. o_pbPublish,
  1930. o_pbstrUNCPath,
  1931. o_pbstrDescription,
  1932. o_pbstrKeywords,
  1933. &bstrManagedByFQDN);
  1934. if (SUCCEEDED(hr))
  1935. {
  1936. hr = TranslateManagedBy(bstrDC,
  1937. bstrManagedByFQDN,
  1938. o_pbstrManagedBy,
  1939. DS_FQDN_1779_NAME,
  1940. DS_USER_PRINCIPAL_NAME);
  1941. if (FAILED(hr))
  1942. hr = TranslateManagedBy(bstrDC,
  1943. bstrManagedByFQDN,
  1944. o_pbstrManagedBy,
  1945. DS_FQDN_1779_NAME,
  1946. DS_NT4_ACCOUNT_NAME);
  1947. }
  1948. CloseConnectionToDS(pldap);
  1949. }
  1950. return hr;
  1951. }
  1952. HRESULT CreateVolumeObject(
  1953. PLDAP i_pldap,
  1954. PCTSTR i_pszDN,
  1955. PCTSTR i_pszUNCPath,
  1956. PCTSTR i_pszDescription,
  1957. PCTSTR i_pszKeywords,
  1958. PCTSTR i_pszManagedBy)
  1959. {
  1960. HRESULT hr = S_OK;
  1961. LDAP_ATTR_VALUE pAttrVals[5];
  1962. int i =0;
  1963. pAttrVals[i].bstrAttribute = OBJCLASS_ATTRIBUTENAME;
  1964. pAttrVals[i].vpValue = (void *)OBJCLASS_VOLUME;
  1965. pAttrVals[i].bBerValue = false;
  1966. i++;
  1967. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME;
  1968. pAttrVals[i].vpValue = (void *)i_pszUNCPath;
  1969. pAttrVals[i].bBerValue = false;
  1970. i++;
  1971. if (i_pszDescription && *i_pszDescription)
  1972. {
  1973. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION;
  1974. pAttrVals[i].vpValue = (void *)i_pszDescription;
  1975. pAttrVals[i].bBerValue = false;
  1976. i++;
  1977. }
  1978. LDAP_ATTR_VALUE *pHead = NULL;
  1979. if (i_pszKeywords && *i_pszKeywords)
  1980. {
  1981. hr = PutMultiValuesIntoAttrValList(i_pszKeywords, &pHead);
  1982. if (S_OK == hr)
  1983. {
  1984. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS;
  1985. pAttrVals[i].vpValue = (void *)pHead->vpValue; // multi-valued
  1986. pAttrVals[i].bBerValue = false;
  1987. pAttrVals[i].Next = pHead->Next;
  1988. i++;
  1989. }
  1990. }
  1991. if (i_pszManagedBy && *i_pszManagedBy)
  1992. {
  1993. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY;
  1994. pAttrVals[i].vpValue = (void *)i_pszManagedBy;
  1995. pAttrVals[i].bBerValue = false;
  1996. i++;
  1997. }
  1998. hr = AddValues(i_pldap, i_pszDN, i, pAttrVals);
  1999. if (pHead)
  2000. FreeAttrValList(pHead);
  2001. return hr;
  2002. }
  2003. HRESULT ModifyShareObject(
  2004. PLDAP i_pldap,
  2005. PCTSTR i_pszDN,
  2006. PCTSTR i_pszUNCPath,
  2007. PCTSTR i_pszDescription,
  2008. PCTSTR i_pszKeywords,
  2009. PCTSTR i_pszManagedBy)
  2010. {
  2011. HRESULT hr = S_OK;
  2012. hr = IsValidObject(i_pldap, (PTSTR)i_pszDN);
  2013. if (S_OK != hr)
  2014. return hr;
  2015. LDAP_ATTR_VALUE pAttrVals[4];
  2016. ZeroMemory(pAttrVals, sizeof(pAttrVals));
  2017. //
  2018. // modify values if any
  2019. //
  2020. int i =0;
  2021. if (i_pszUNCPath && *i_pszUNCPath)
  2022. {
  2023. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME;
  2024. pAttrVals[i].vpValue = (void *)i_pszUNCPath;
  2025. pAttrVals[i].bBerValue = false;
  2026. i++;
  2027. }
  2028. if (i_pszDescription && *i_pszDescription)
  2029. {
  2030. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION;
  2031. pAttrVals[i].vpValue = (void *)i_pszDescription;
  2032. pAttrVals[i].bBerValue = false;
  2033. i++;
  2034. }
  2035. LDAP_ATTR_VALUE *pHead = NULL;
  2036. if (i_pszKeywords && *i_pszKeywords)
  2037. {
  2038. hr = PutMultiValuesIntoAttrValList(i_pszKeywords, &pHead);
  2039. if (S_OK == hr)
  2040. {
  2041. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS;
  2042. pAttrVals[i].vpValue = (void *)pHead->vpValue; // multi-valued
  2043. pAttrVals[i].bBerValue = false;
  2044. pAttrVals[i].Next = pHead->Next;
  2045. i++;
  2046. }
  2047. }
  2048. if (i_pszManagedBy && *i_pszManagedBy)
  2049. {
  2050. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY;
  2051. pAttrVals[i].vpValue = (void *)i_pszManagedBy;
  2052. pAttrVals[i].bBerValue = false;
  2053. i++;
  2054. }
  2055. if (i > 0)
  2056. {
  2057. hr = ModifyValues(i_pldap, i_pszDN, i, pAttrVals);
  2058. dfsDebugOut((_T("ModifyValues i=%d, hr=%x\n"), i, hr));
  2059. }
  2060. if (pHead)
  2061. FreeAttrValList(pHead);
  2062. RETURN_IF_FAILED(hr);
  2063. //
  2064. // delete values if any
  2065. //
  2066. i =0;
  2067. ZeroMemory(pAttrVals, sizeof(pAttrVals));
  2068. if (!i_pszUNCPath || !*i_pszUNCPath)
  2069. {
  2070. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME;
  2071. pAttrVals[i].vpValue = NULL;
  2072. pAttrVals[i].bBerValue = false;
  2073. i++;
  2074. }
  2075. if (!i_pszDescription || !*i_pszDescription)
  2076. {
  2077. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION;
  2078. pAttrVals[i].vpValue = NULL;
  2079. pAttrVals[i].bBerValue = false;
  2080. i++;
  2081. }
  2082. if (!i_pszKeywords || !*i_pszKeywords)
  2083. {
  2084. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS;
  2085. pAttrVals[i].vpValue = NULL;
  2086. pAttrVals[i].bBerValue = false;
  2087. i++;
  2088. }
  2089. if (!i_pszManagedBy || !*i_pszManagedBy)
  2090. {
  2091. pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY;
  2092. pAttrVals[i].vpValue = NULL;
  2093. pAttrVals[i].bBerValue = false;
  2094. i++;
  2095. }
  2096. if (i > 0)
  2097. {
  2098. hr = DeleteValues(i_pldap, i_pszDN, i, pAttrVals);
  2099. dfsDebugOut((_T("DeleteValues i=%d, hr=%x\n"), i, hr));
  2100. }
  2101. return hr;
  2102. }
  2103. HRESULT ModifySharePublishInfoOnFTRoot(
  2104. IN PCTSTR i_pszDomainName,
  2105. IN PCTSTR i_pszRootName,
  2106. IN BOOL i_bPublish,
  2107. IN PCTSTR i_pszUNCPath,
  2108. IN PCTSTR i_pszDescription,
  2109. IN PCTSTR i_pszKeywords,
  2110. IN PCTSTR i_pszManagedBy
  2111. )
  2112. {
  2113. dfsDebugOut((_T("ModifySharePublishInfoOnFTRoot %s, %s, %d, %s, %s, %s, %s\n"),
  2114. i_pszDomainName,
  2115. i_pszRootName,
  2116. i_bPublish,
  2117. i_pszUNCPath,
  2118. i_pszDescription,
  2119. i_pszKeywords,
  2120. i_pszManagedBy
  2121. ));
  2122. CComBSTR bstrFTDfsObjectDN;
  2123. HRESULT hr = GetFTDfsObjectDN(i_pszDomainName, i_pszRootName, &bstrFTDfsObjectDN);
  2124. if (FAILED(hr))
  2125. return hr;
  2126. CComBSTR bstrDC;
  2127. PLDAP pldap = NULL;
  2128. hr = ConnectToDS(i_pszDomainName, &pldap, &bstrDC); // PDC is preferred
  2129. if (SUCCEEDED(hr))
  2130. {
  2131. if (i_bPublish)
  2132. {
  2133. CComBSTR bstrManagedByFQDN;
  2134. if (i_pszManagedBy && *i_pszManagedBy)
  2135. {
  2136. hr = TranslateManagedBy(bstrDC,
  2137. i_pszManagedBy,
  2138. &bstrManagedByFQDN,
  2139. (_tcschr(i_pszManagedBy, _T('@')) ? DS_USER_PRINCIPAL_NAME : DS_NT4_ACCOUNT_NAME),
  2140. DS_FQDN_1779_NAME);
  2141. }
  2142. if (SUCCEEDED(hr))
  2143. hr = ModifyShareObject(
  2144. pldap,
  2145. bstrFTDfsObjectDN,
  2146. i_pszUNCPath,
  2147. i_pszDescription,
  2148. i_pszKeywords,
  2149. bstrManagedByFQDN);
  2150. } else {
  2151. hr = ModifyShareObject(
  2152. pldap,
  2153. bstrFTDfsObjectDN,
  2154. NULL,
  2155. NULL,
  2156. NULL,
  2157. NULL);
  2158. if (S_FALSE == hr)
  2159. hr = S_OK; // ignore non-existing object
  2160. }
  2161. CloseConnectionToDS(pldap);
  2162. }
  2163. dfsDebugOut((_T("ModifySharePublishInfoOnFTRoot hr=%x\n"), hr));
  2164. return hr;
  2165. }
  2166. HRESULT ModifySharePublishInfoOnSARoot(
  2167. IN PCTSTR i_pszServerName,
  2168. IN PCTSTR i_pszShareName,
  2169. IN BOOL i_bPublish,
  2170. IN PCTSTR i_pszUNCPath,
  2171. IN PCTSTR i_pszDescription,
  2172. IN PCTSTR i_pszKeywords,
  2173. IN PCTSTR i_pszManagedBy
  2174. )
  2175. {
  2176. dfsDebugOut((_T("ModifySharePublishInfoOnSARoot %s, %s, %d, %s, %s, %s, %s\n"),
  2177. i_pszServerName,
  2178. i_pszShareName,
  2179. i_bPublish,
  2180. i_pszUNCPath,
  2181. i_pszDescription,
  2182. i_pszKeywords,
  2183. i_pszManagedBy
  2184. ));
  2185. CComBSTR bstrDomainName, bstrFQDN;
  2186. HRESULT hr = GetServerInfo(
  2187. (PTSTR)i_pszServerName,
  2188. &bstrDomainName,
  2189. NULL, //NetbiosName
  2190. NULL, //ValidDSObject
  2191. NULL, //DnsName,
  2192. NULL, //Guid,
  2193. &bstrFQDN);
  2194. if (S_OK != hr)
  2195. return hr;
  2196. CComBSTR bstrVolumeObjectDN = _T("CN=");
  2197. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  2198. bstrVolumeObjectDN += i_pszShareName;
  2199. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  2200. bstrVolumeObjectDN += _T(",");
  2201. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  2202. bstrVolumeObjectDN += bstrFQDN;
  2203. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
  2204. CComBSTR bstrDC;
  2205. PLDAP pldap = NULL;
  2206. hr = ConnectToDS(bstrDomainName, &pldap, &bstrDC);
  2207. if (SUCCEEDED(hr))
  2208. {
  2209. if (i_bPublish)
  2210. {
  2211. CComBSTR bstrManagedByFQDN;
  2212. if (i_pszManagedBy && *i_pszManagedBy)
  2213. {
  2214. hr = TranslateManagedBy(bstrDC,
  2215. i_pszManagedBy,
  2216. &bstrManagedByFQDN,
  2217. (_tcschr(i_pszManagedBy, _T('@')) ? DS_USER_PRINCIPAL_NAME : DS_NT4_ACCOUNT_NAME),
  2218. DS_FQDN_1779_NAME);
  2219. }
  2220. if (SUCCEEDED(hr))
  2221. {
  2222. hr = IsValidObject(pldap, bstrVolumeObjectDN);
  2223. if (S_OK == hr)
  2224. {
  2225. hr = ModifyShareObject(
  2226. pldap,
  2227. bstrVolumeObjectDN,
  2228. i_pszUNCPath,
  2229. i_pszDescription,
  2230. i_pszKeywords,
  2231. bstrManagedByFQDN);
  2232. } else
  2233. {
  2234. hr = CreateVolumeObject(
  2235. pldap,
  2236. bstrVolumeObjectDN,
  2237. i_pszUNCPath,
  2238. i_pszDescription,
  2239. i_pszKeywords,
  2240. bstrManagedByFQDN);
  2241. }
  2242. }
  2243. } else
  2244. {
  2245. hr = DeleteDSObject(pldap, bstrVolumeObjectDN, TRUE);
  2246. if (S_FALSE == hr)
  2247. hr = S_OK; // ignore non-existing object
  2248. }
  2249. CloseConnectionToDS(pldap);
  2250. }
  2251. dfsDebugOut((_T("ModifySharePublishInfoOnSARoot hr=%x\n"), hr));
  2252. return hr;
  2253. }
  2254. HRESULT PutMultiValuesIntoAttrValList(
  2255. IN PCTSTR i_pszValues,
  2256. OUT LDAP_ATTR_VALUE** o_pVal
  2257. )
  2258. {
  2259. if (!i_pszValues || !o_pVal)
  2260. return E_INVALIDARG;
  2261. LDAP_ATTR_VALUE* pHead = NULL;
  2262. LDAP_ATTR_VALUE* pCurrent = NULL;
  2263. int index = 0;
  2264. CComBSTR bstrToken;
  2265. HRESULT hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);
  2266. while (SUCCEEDED(hr) && (BSTR)bstrToken)
  2267. {
  2268. TrimBSTR(bstrToken);
  2269. if (*bstrToken)
  2270. {
  2271. LDAP_ATTR_VALUE* pNew = new LDAP_ATTR_VALUE;
  2272. RETURN_OUTOFMEMORY_IF_NULL(pNew);
  2273. pNew->vpValue = _tcsdup(bstrToken);
  2274. if (!(pNew->vpValue))
  2275. {
  2276. delete pNew;
  2277. hr = E_OUTOFMEMORY;
  2278. break;
  2279. }
  2280. if (!pHead)
  2281. {
  2282. pHead = pCurrent = pNew;
  2283. } else
  2284. {
  2285. pCurrent->Next = pNew;
  2286. pCurrent = pNew;
  2287. }
  2288. }
  2289. bstrToken.Empty();
  2290. hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);
  2291. }
  2292. if (FAILED(hr))
  2293. {
  2294. FreeAttrValList(pHead);
  2295. return hr;
  2296. }
  2297. int nCount = 0;
  2298. pCurrent = pHead;
  2299. while (pCurrent)
  2300. {
  2301. nCount++;
  2302. pCurrent = pCurrent->Next;
  2303. }
  2304. if (!nCount)
  2305. return S_FALSE; // no token
  2306. *o_pVal = pHead;
  2307. return S_OK;
  2308. }
  2309. HRESULT PutMultiValuesIntoStringArray(
  2310. IN PCTSTR i_pszValues,
  2311. OUT PTSTR** o_pVal
  2312. )
  2313. {
  2314. if (!i_pszValues || !o_pVal)
  2315. return E_INVALIDARG;
  2316. int nCount = 0;
  2317. CComBSTR bstrToken;
  2318. int index = 0;
  2319. HRESULT hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);
  2320. while (SUCCEEDED(hr) && (BSTR)bstrToken)
  2321. {
  2322. nCount++;
  2323. bstrToken.Empty();
  2324. hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);;
  2325. }
  2326. if (!nCount)
  2327. return E_INVALIDARG;
  2328. PTSTR* ppszStrings = (PTSTR *)calloc(nCount + 1, sizeof(PTSTR *));
  2329. RETURN_OUTOFMEMORY_IF_NULL(ppszStrings);
  2330. nCount = 0;
  2331. index = 0;
  2332. bstrToken.Empty();
  2333. hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);
  2334. while (SUCCEEDED(hr) && (BSTR)bstrToken)
  2335. {
  2336. TrimBSTR(bstrToken);
  2337. if (*bstrToken)
  2338. {
  2339. ppszStrings[nCount] = _tcsdup(bstrToken);
  2340. BREAK_OUTOFMEMORY_IF_NULL(ppszStrings[nCount], &hr);
  2341. nCount++;
  2342. }
  2343. bstrToken.Empty();
  2344. hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);;
  2345. }
  2346. if (FAILED(hr))
  2347. FreeStringArray(ppszStrings);
  2348. else
  2349. *o_pVal = ppszStrings;
  2350. return hr;
  2351. }
  2352. //
  2353. // free a null-terminated array of strings
  2354. //
  2355. void FreeStringArray(PTSTR* i_ppszStrings)
  2356. {
  2357. if (i_ppszStrings)
  2358. {
  2359. PTSTR* ppszString = i_ppszStrings;
  2360. while (*ppszString)
  2361. {
  2362. free(*ppszString);
  2363. ppszString++;
  2364. }
  2365. free(i_ppszStrings);
  2366. }
  2367. }
  2368. HRESULT mystrtok(
  2369. IN PCTSTR i_pszString,
  2370. IN OUT int* io_pnIndex, // start from 0
  2371. IN PCTSTR i_pszCharSet,
  2372. OUT BSTR* o_pbstrToken
  2373. )
  2374. {
  2375. if (!i_pszString || !*i_pszString ||
  2376. !i_pszCharSet || !io_pnIndex ||
  2377. !o_pbstrToken)
  2378. return E_INVALIDARG;
  2379. *o_pbstrToken = NULL;
  2380. HRESULT hr = S_OK;
  2381. if (*io_pnIndex >= lstrlen(i_pszString))
  2382. {
  2383. return hr; // no more tokens
  2384. }
  2385. TCHAR *ptchStart = (PTSTR)i_pszString + *io_pnIndex;
  2386. if (!*i_pszCharSet)
  2387. {
  2388. *o_pbstrToken = SysAllocString(ptchStart);
  2389. if (!*o_pbstrToken)
  2390. hr = E_OUTOFMEMORY;
  2391. return hr;
  2392. }
  2393. //
  2394. // move p to the 1st char of the token
  2395. //
  2396. TCHAR *p = ptchStart;
  2397. while (*p)
  2398. {
  2399. if (_tcschr(i_pszCharSet, *p))
  2400. p++;
  2401. else
  2402. break;
  2403. }
  2404. ptchStart = p; // adjust ptchStart to point at the 1st char of the token
  2405. //
  2406. // move p to the char after the last char of the token
  2407. //
  2408. while (*p)
  2409. {
  2410. if (_tcschr(i_pszCharSet, *p))
  2411. break;
  2412. else
  2413. p++;
  2414. }
  2415. //
  2416. // ptchStart: points at the 1st char of the token
  2417. // p: points at the char after the last char of the token
  2418. //
  2419. if (ptchStart != p)
  2420. {
  2421. *o_pbstrToken = SysAllocStringLen(ptchStart, (int)(p - ptchStart));
  2422. if (!*o_pbstrToken)
  2423. hr = E_OUTOFMEMORY;
  2424. *io_pnIndex = (int)(p - i_pszString);
  2425. }
  2426. return hr;
  2427. }
  2428. //
  2429. // trim off space chars at the beginning and at the end of the string
  2430. //
  2431. void TrimBSTR(BSTR bstr)
  2432. {
  2433. if (!bstr)
  2434. return;
  2435. TCHAR* p = bstr;
  2436. //
  2437. // trim off space chars at the beginning
  2438. //
  2439. while (*p)
  2440. {
  2441. if (_istspace(*p))
  2442. p++;
  2443. else
  2444. break;
  2445. }
  2446. if (p > bstr)
  2447. _tcscpy(bstr, p);
  2448. int len = _tcslen(bstr);
  2449. if (len > 0)
  2450. {
  2451. //
  2452. // trim off space chars at the end
  2453. //
  2454. p = bstr + len - 1; // the char before the ending '\0'
  2455. while (p > bstr)
  2456. {
  2457. if (_istspace(*p))
  2458. p--;
  2459. else
  2460. {
  2461. *(p+1) = _T('\0');
  2462. break;
  2463. }
  2464. }
  2465. }
  2466. }
  2467. BOOL CheckPolicyOnSharePublish()
  2468. {
  2469. //
  2470. // check group policy
  2471. //
  2472. BOOL bAddPublishPage = TRUE; // by default, we display the share publish page
  2473. HKEY hKey = NULL;
  2474. DWORD dwType = 0;
  2475. DWORD dwData = 0;
  2476. DWORD cbData = sizeof(dwData);
  2477. LONG lErr = RegOpenKeyEx(
  2478. HKEY_CURRENT_USER,
  2479. _T("Software\\Policies\\Microsoft\\Windows NT\\SharedFolders"),
  2480. 0,
  2481. KEY_QUERY_VALUE,
  2482. &hKey);
  2483. if (ERROR_SUCCESS == lErr)
  2484. {
  2485. lErr = RegQueryValueEx(hKey, _T("PublishDfsRoots"), 0, &dwType, (LPBYTE)&dwData, &cbData);
  2486. if (ERROR_SUCCESS == lErr &&
  2487. REG_DWORD == dwType &&
  2488. 0 == dwData) // policy is disabled
  2489. bAddPublishPage = FALSE;
  2490. RegCloseKey(hKey);
  2491. }
  2492. return bAddPublishPage;
  2493. }
  2494. BOOL CheckPolicyOnDisplayingInitialMaster()
  2495. {
  2496. BOOL bShowInitialMaster = FALSE; // by default, we hide the initial master on property page
  2497. HKEY hKey = NULL;
  2498. DWORD dwType = 0;
  2499. DWORD dwData = 0;
  2500. DWORD cbData = sizeof(dwData);
  2501. LONG lErr = RegOpenKeyEx(
  2502. HKEY_LOCAL_MACHINE,
  2503. _T("Software\\Microsoft\\DfsGui"),
  2504. 0,
  2505. KEY_QUERY_VALUE,
  2506. &hKey);
  2507. if (ERROR_SUCCESS == lErr)
  2508. {
  2509. lErr = RegQueryValueEx(hKey, _T("ShowInitialMaster"), 0, &dwType, (LPBYTE)&dwData, &cbData);
  2510. if (ERROR_SUCCESS == lErr &&
  2511. REG_DWORD == dwType &&
  2512. 1 == dwData)
  2513. bShowInitialMaster = TRUE;
  2514. RegCloseKey(hKey);
  2515. }
  2516. return bShowInitialMaster;
  2517. }
  2518. HRESULT GetMenuResourceStrings(
  2519. IN int i_iStringID,
  2520. OUT BSTR* o_pbstrMenuText,
  2521. OUT BSTR* o_pbstrToolTipText,
  2522. OUT BSTR* o_pbstrStatusBarText
  2523. )
  2524. {
  2525. if (!i_iStringID)
  2526. return E_INVALIDARG;
  2527. if (o_pbstrMenuText)
  2528. *o_pbstrMenuText = NULL;
  2529. if (o_pbstrToolTipText)
  2530. *o_pbstrToolTipText = NULL;
  2531. if (o_pbstrStatusBarText)
  2532. *o_pbstrStatusBarText = NULL;
  2533. TCHAR *pszMenuText = NULL;
  2534. TCHAR *pszToolTipText = NULL;
  2535. TCHAR *pszStatusBarText = NULL;
  2536. TCHAR *p = NULL;
  2537. CComBSTR bstr;
  2538. HRESULT hr = LoadStringFromResource(i_iStringID, &bstr);
  2539. RETURN_IF_FAILED(hr);
  2540. pszMenuText = (BSTR)bstr;
  2541. p = _tcschr(pszMenuText, _T('|'));
  2542. RETURN_INVALIDARG_IF_NULL(p);
  2543. *p++ = _T('\0');
  2544. pszToolTipText = p;
  2545. p = _tcschr(pszToolTipText, _T('|'));
  2546. RETURN_INVALIDARG_IF_NULL(p);
  2547. *p++ = _T('\0');
  2548. pszStatusBarText = p;
  2549. do {
  2550. if (o_pbstrMenuText)
  2551. {
  2552. *o_pbstrMenuText = SysAllocString(pszMenuText);
  2553. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrMenuText, &hr);
  2554. }
  2555. if (o_pbstrToolTipText)
  2556. {
  2557. *o_pbstrToolTipText = SysAllocString(pszToolTipText);
  2558. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrToolTipText, &hr);
  2559. }
  2560. if (o_pbstrStatusBarText)
  2561. {
  2562. *o_pbstrStatusBarText = SysAllocString(pszStatusBarText);
  2563. BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrStatusBarText, &hr);
  2564. }
  2565. } while (0);
  2566. if (FAILED(hr))
  2567. {
  2568. if (o_pbstrMenuText && *o_pbstrMenuText)
  2569. SysFreeString(*o_pbstrMenuText);
  2570. if (o_pbstrToolTipText && *o_pbstrToolTipText)
  2571. SysFreeString(*o_pbstrToolTipText);
  2572. if (o_pbstrStatusBarText && *o_pbstrStatusBarText)
  2573. SysFreeString(*o_pbstrStatusBarText);
  2574. }
  2575. return hr;
  2576. }
  2577. WNDPROC g_fnOldEditCtrlProc;
  2578. //+----------------------------------------------------------------------------
  2579. //
  2580. // Function: NoPasteEditCtrlProc
  2581. //
  2582. // Synopsis: The subclassed edit control callback procedure.
  2583. // The paste of this edit control is disabled.
  2584. //
  2585. //-----------------------------------------------------------------------------
  2586. LRESULT CALLBACK
  2587. NoPasteEditCtrlProc(
  2588. HWND hwnd,
  2589. UINT uMsg,
  2590. WPARAM wParam,
  2591. LPARAM lParam
  2592. )
  2593. {
  2594. if (WM_PASTE == uMsg)
  2595. {
  2596. ::MessageBeep (0);
  2597. return TRUE;
  2598. }
  2599. return CallWindowProc(g_fnOldEditCtrlProc, hwnd, uMsg, wParam, lParam);
  2600. }
  2601. void SetActivePropertyPage(IN HWND i_hwndParent, IN HWND i_hwndPage)
  2602. {
  2603. int index = ::SendMessage(i_hwndParent, PSM_HWNDTOINDEX, (WPARAM)i_hwndPage, 0);
  2604. if (-1 != index)
  2605. ::SendMessage(i_hwndParent, PSM_SETCURSEL, (WPARAM)index, 0);
  2606. }
  2607. void MyShowWindow(HWND hwnd, BOOL bShow)
  2608. {
  2609. ::ShowWindow(hwnd, (bShow ? SW_NORMAL : SW_HIDE));
  2610. ::EnableWindow(hwnd, (bShow ? TRUE : FALSE));
  2611. }
  2612. //
  2613. // 7/11/2001 LinanT bug#426953
  2614. // Since connection made by Terminal Service may bring some client side resources
  2615. // (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
  2616. // the OK button when browsing to a non-local folder. We don't have this problem
  2617. // when browsing a remote machine.
  2618. //
  2619. typedef struct _LOCAL_DISKS
  2620. {
  2621. LPTSTR pszDisks;
  2622. DWORD dwNumOfDisks;
  2623. } LOCAL_DISKS;
  2624. #define DISK_ENTRY_LENGTH 3 // Drive letter, colon, NULL
  2625. #define DISK_NAME_LENGTH 2 // Drive letter, colon
  2626. BOOL InDiskList(IN LPCTSTR pszDir, IN LOCAL_DISKS *pDisks)
  2627. {
  2628. if (!pszDir || !pDisks)
  2629. return FALSE;
  2630. DWORD i = 0;
  2631. PTSTR pszDisk = pDisks->pszDisks;
  2632. for (; pszDisk && i < pDisks->dwNumOfDisks; i++)
  2633. {
  2634. if (!_tcsnicmp(pszDisk, pszDir, DISK_NAME_LENGTH))
  2635. return TRUE;
  2636. pszDisk += DISK_ENTRY_LENGTH;
  2637. }
  2638. return FALSE;
  2639. }
  2640. int CALLBACK
  2641. BrowseCallbackProc(
  2642. IN HWND hwnd,
  2643. IN UINT uMsg,
  2644. IN LPARAM lp,
  2645. IN LPARAM pData
  2646. )
  2647. {
  2648. switch(uMsg) {
  2649. case BFFM_SELCHANGED:
  2650. {
  2651. // enable the OK button if the selected path is local to that computer.
  2652. BOOL bEnableOK = FALSE;
  2653. TCHAR szDir[MAX_PATH];
  2654. if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir))
  2655. {
  2656. if (pData)
  2657. {
  2658. // we're looking at a local computer, verify if szDir is on a local disk
  2659. bEnableOK = InDiskList(szDir, (LOCAL_DISKS *)pData);
  2660. } else
  2661. {
  2662. // no such problem when browsing at a remote computer, always enable OK button.
  2663. bEnableOK = TRUE;
  2664. }
  2665. }
  2666. SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)bEnableOK);
  2667. break;
  2668. }
  2669. case BFFM_VALIDATEFAILED:
  2670. {
  2671. DisplayMessageBox(hwnd, MB_OK, 0, IDS_BROWSE_FOLDER_INVALID);
  2672. return 1;
  2673. }
  2674. default:
  2675. break;
  2676. }
  2677. return 0;
  2678. }
  2679. void OpenBrowseDialog(
  2680. IN HWND hwndParent,
  2681. IN int idLabel,
  2682. IN BOOL bLocalComputer,
  2683. IN LPCTSTR lpszComputer,
  2684. OUT LPTSTR lpszDir)
  2685. {
  2686. _ASSERT(lpszComputer && *lpszComputer);
  2687. LOCAL_DISKS localDisks = {0};
  2688. CComBSTR bstrComputer;
  2689. if (*lpszComputer != _T('\\') || *(lpszComputer + 1) != _T('\\'))
  2690. {
  2691. bstrComputer = _T("\\\\");
  2692. bstrComputer += lpszComputer;
  2693. } else
  2694. {
  2695. bstrComputer = lpszComputer;
  2696. }
  2697. HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  2698. if (SUCCEEDED(hr))
  2699. {
  2700. LPMALLOC pMalloc;
  2701. hr = SHGetMalloc(&pMalloc);
  2702. if (SUCCEEDED(hr))
  2703. {
  2704. LPSHELLFOLDER pDesktopFolder;
  2705. hr = SHGetDesktopFolder(&pDesktopFolder);
  2706. if (SUCCEEDED(hr))
  2707. {
  2708. LPITEMIDLIST pidlRoot;
  2709. if (bLocalComputer)
  2710. {
  2711. hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlRoot);
  2712. if (SUCCEEDED(hr))
  2713. {
  2714. //
  2715. // 7/11/2001 LinanT bug#426953
  2716. // Since connection made by Terminal Service may bring some client side resources
  2717. // (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
  2718. // the OK button when browsing to a non-local folder. We don't have this problem
  2719. // when browsing a remote machine.
  2720. //
  2721. //
  2722. // Get an array of local disk names, this information is later used
  2723. // in the browse dialog to disable OK button if non-local path is selected.
  2724. //
  2725. DWORD dwTotalEntries = 0;
  2726. DWORD nStatus = NetServerDiskEnum(
  2727. NULL, // local computer
  2728. 0, // level must be zero
  2729. (LPBYTE *)&(localDisks.pszDisks),
  2730. -1, // dwPrefMaxLen,
  2731. &(localDisks.dwNumOfDisks),
  2732. &dwTotalEntries,
  2733. NULL);
  2734. if (NERR_Success != nStatus)
  2735. {
  2736. hr = HRESULT_FROM_WIN32(nStatus);
  2737. }
  2738. }
  2739. } else
  2740. {
  2741. hr = pDesktopFolder->ParseDisplayName(hwndParent, NULL, bstrComputer, NULL, &pidlRoot, NULL);
  2742. }
  2743. if (SUCCEEDED(hr))
  2744. {
  2745. CComBSTR bstrLabel;
  2746. LoadStringFromResource(idLabel, &bstrLabel);
  2747. BROWSEINFO bi;
  2748. ZeroMemory(&bi,sizeof(bi));
  2749. bi.hwndOwner = hwndParent;
  2750. bi.pszDisplayName = 0;
  2751. bi.lpszTitle = bstrLabel;
  2752. bi.pidlRoot = pidlRoot;
  2753. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_SHAREABLE | BIF_USENEWUI | BIF_VALIDATE;
  2754. bi.lpfn = BrowseCallbackProc;
  2755. if (localDisks.pszDisks)
  2756. bi.lParam = (LPARAM)&localDisks; // pass the structure to the browse dialog
  2757. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  2758. if (pidl) {
  2759. SHGetPathFromIDList(pidl, lpszDir);
  2760. pMalloc->Free(pidl);
  2761. }
  2762. pMalloc->Free(pidlRoot);
  2763. }
  2764. pDesktopFolder->Release();
  2765. }
  2766. pMalloc->Release();
  2767. }
  2768. CoUninitialize();
  2769. }
  2770. if (localDisks.pszDisks)
  2771. NetApiBufferFree(localDisks.pszDisks);
  2772. if (FAILED(hr))
  2773. DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_CANNOT_BROWSE_FOLDER, lpszComputer);
  2774. }