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.

877 lines
27 KiB

  1. /////////////////////////////////////////////////////////////////////
  2. // Chooser.cpp
  3. //
  4. // Microsoft Windows
  5. // Copyright (C) Microsoft Corporation, 1997-1998
  6. //
  7. //
  8. // Dialog to choose a machine name.
  9. //
  10. // PURPOSE
  11. // (Important -- Please Read)
  12. // This code was written for you to save you time.
  13. // What you have to do is to copy all the files from the
  14. // snapin\chooser\ directory into your project (you may add
  15. // \nt\private\admin\snapin\chooser\ to your include directory if
  16. // you prefer not copying the code).
  17. // If you decide to copy the code to your project, please send mail
  18. // to Dan Morin (T-DanM) and cc to Jon Newman (JonN) so we can
  19. // mail you when we have updates available. The next update will
  20. // be the "Browse" button to select a machine name.
  21. //
  22. //
  23. // DYNALOADED LIBRARIES
  24. // $(SDK_LIB_PATH)\shell32.lib // CommandLineToArgvW()
  25. // $(SDK_LIB_PATH)\netapi32.lib // I_NetName*()
  26. //
  27. // EXTRA INFO
  28. // If you don't know how this works, take a look at the inheritance tree
  29. // in chooser.h. Then, take a look at the existing code that inherit and/or
  30. // uses CChooseMachinePropPage.
  31. //
  32. // HISTORY
  33. // 13-May-1997 t-danm Creation.
  34. // 23-May-1997 t-danm Checkin into public tree. Comments updates.
  35. // 25-May-1997 t-danm Added MMCPropPageCallback().
  36. // 31-Oct-1997 mattt Added dynaload, fixed user <CANCEL> logic
  37. //
  38. /////////////////////////////////////////////////////////////////////
  39. #include "chooser.h"
  40. #include <lmcons.h> // NET_API_STATUS
  41. #include <lmerr.h> // NERR_Success
  42. #include <icanon.h> // I_NetNameValidate(), I_NetNameCanonicalize(). Found in \nt\private\net\inc.
  43. #include <objsel.h>
  44. #include "stdutils.h" // IsLocalComputername
  45. #include <lmserver.h> // NetServerGetInfo JonN 2002/04/08 585301
  46. #include <lmapibuf.h> // NetApiBufferFree JonN 2002/04/08 585301
  47. #ifdef _DEBUG
  48. #define new DEBUG_NEW
  49. #undef THIS_FILE
  50. #define THIS_FILE __FILE__
  51. #endif
  52. #ifndef INOUT
  53. // The following defines are found in \nt\private\admin\snapin\filemgmt\stdafx.h
  54. #define INOUT
  55. #define Endorse(f) // Dummy macro
  56. #define LENGTH(x) (sizeof(x)/sizeof(x[0]))
  57. #define Assert(f) ASSERT(f)
  58. #endif
  59. /////////////////////////////////////////////////////////////////////
  60. // CanonicalizeComputername()
  61. //
  62. // Function to validate the computer name and optionally
  63. // add the \\ at beginning of machine name.
  64. //
  65. typedef
  66. NET_API_STATUS
  67. NET_API_FUNCTION
  68. INETNAMEVALIDATE(
  69. LPTSTR ServerName,
  70. LPTSTR Name,
  71. DWORD NameType,
  72. DWORD Flags);
  73. typedef
  74. NET_API_STATUS
  75. NET_API_FUNCTION
  76. INETNAMECANONICALIZE(
  77. LPTSTR ServerName,
  78. LPTSTR Name,
  79. LPTSTR Outbuf,
  80. DWORD OutbufLen,
  81. DWORD NameType,
  82. DWORD Flags);
  83. NET_API_STATUS
  84. CanonicalizeComputername(
  85. INOUT CString& rstrMachineName,
  86. IN BOOL fAddWackWack = TRUE) // TRUE => Add the \\ at beginning of name
  87. {
  88. NET_API_STATUS err;
  89. LPTSTR pszTemp;
  90. rstrMachineName.TrimLeft();
  91. rstrMachineName.TrimRight();
  92. if ( rstrMachineName.IsEmpty() )
  93. return NERR_Success;
  94. if ( 2 <= rstrMachineName.GetLength() &&
  95. _T('\\') == rstrMachineName[0] &&
  96. _T('\\') == rstrMachineName[1] )
  97. {
  98. // Remove the \\ at the beginning of name
  99. CString strShorter = rstrMachineName.Right(
  100. rstrMachineName.GetLength() - 2 );
  101. rstrMachineName = strShorter;
  102. }
  103. // DYNALOAD NETAPI32.dll
  104. HINSTANCE hNetApiDll = NULL;
  105. INETNAMEVALIDATE *pfnValidate;
  106. INETNAMECANONICALIZE *pfnCanonicalize;
  107. if (NULL == (hNetApiDll = LoadLibrary(L"netapi32.dll")))
  108. return GetLastError();
  109. if (NULL == (pfnValidate = (INETNAMEVALIDATE*)GetProcAddress(hNetApiDll, "I_NetNameValidate")) )
  110. {
  111. err = GetLastError();
  112. goto Ret;
  113. }
  114. if (NULL == (pfnCanonicalize = (INETNAMECANONICALIZE*)GetProcAddress(hNetApiDll, "I_NetNameCanonicalize")) )
  115. {
  116. err = GetLastError();
  117. goto Ret;
  118. }
  119. err = pfnValidate(
  120. NULL,
  121. const_cast<LPTSTR>((LPCTSTR)rstrMachineName),
  122. NAMETYPE_COMPUTER,
  123. 0L );
  124. if (NERR_Success != err)
  125. goto Ret;
  126. if ( MAX_PATH <= rstrMachineName.GetLength() )
  127. {
  128. err = ERROR_INVALID_NAME;
  129. goto Ret;
  130. }
  131. pszTemp = (LPTSTR)alloca( MAX_PATH*sizeof(TCHAR) );
  132. ASSERT( NULL != pszTemp );
  133. // 2002/03/28-JonN CliffV confirms that this API takes a bytecount
  134. err = pfnCanonicalize(
  135. NULL,
  136. IN const_cast<LPTSTR>((LPCTSTR)rstrMachineName),
  137. OUT pszTemp,
  138. MAX_PATH*sizeof(TCHAR),
  139. NAMETYPE_COMPUTER,
  140. 0L );
  141. if (NERR_Success != err)
  142. goto Ret;
  143. if (fAddWackWack && pszTemp[0] != '\0')
  144. {
  145. // Add the \\ at beginning of name
  146. rstrMachineName = _T("\\\\");
  147. rstrMachineName += pszTemp;
  148. }
  149. else
  150. {
  151. rstrMachineName = pszTemp;
  152. }
  153. err = NERR_Success;
  154. Ret:
  155. if (hNetApiDll)
  156. FreeLibrary(hNetApiDll);
  157. return err;
  158. } // CanonicalizeComputername()
  159. /////////////////////////////////////////////////
  160. // Machine name override
  161. const TCHAR szOverrideCommandLineEquals[] = _T("/Computer="); // Not subject to localization
  162. const TCHAR szOverrideCommandLineColon[] = _T("/Computer:"); // Not subject to localization
  163. const TCHAR szLocalMachine[] = _T("LocalMachine"); // Not subject to localization
  164. const int cchOverrideCommandLine = LENGTH(szOverrideCommandLineEquals) - 1;
  165. // Assumption: both command line strings are the same length
  166. static CString g_strOverrideMachineName;
  167. static LPCTSTR g_pszOverrideMachineName; // NULL => No override provided, "" => LocalMachine
  168. ///////////////////////////////////////////////////////////////////////////////
  169. // PchGetMachineNameOverride()
  170. //
  171. // Parse the command line arguments and return a pointer to the
  172. // machine name override if present.
  173. //
  174. // INTERFACE NOTES
  175. // If the machine name is other than local machine, the machine name
  176. // will have the \\ at the beginning of its name.
  177. //
  178. // RETURN
  179. // - Return NULL if no override (ie, no command line override)
  180. // - Return pointer to empty string if override is "local machine"
  181. // - Otherwise return pointer to machine name override with \\ at beginning.
  182. //
  183. typedef
  184. LPWSTR * COMMANDLINETOARGVW(
  185. LPCWSTR lpCmdLine, // pointer to a command-line string
  186. int *pNumArgs); // pointer to a variable that receives the argument count
  187. LPCTSTR PchGetMachineNameOverride ()
  188. {
  189. static BOOL fAlreadyInitialized = FALSE;
  190. if (fAlreadyInitialized)
  191. {
  192. // We already have parsed the command line
  193. return g_pszOverrideMachineName;
  194. }
  195. fAlreadyInitialized = TRUE;
  196. ASSERT(g_pszOverrideMachineName == NULL);
  197. LPCWSTR * lpServiceArgVectors = 0; // Array of pointers to string
  198. int cArgs = 0; // Count of arguments
  199. // DYNALOAD Shell32
  200. {
  201. HINSTANCE hShellDll = LoadLibrary (L"shell32.dll");
  202. if ( !hShellDll )
  203. return NULL;
  204. COMMANDLINETOARGVW *pfnCmdToArgs = (COMMANDLINETOARGVW*) GetProcAddress (hShellDll, "CommandLineToArgvW");
  205. if ( !pfnCmdToArgs )
  206. {
  207. VERIFY (FreeLibrary (hShellDll));
  208. return NULL;
  209. }
  210. lpServiceArgVectors = (LPCWSTR *) pfnCmdToArgs (GetCommandLineW (), OUT &cArgs);
  211. VERIFY (FreeLibrary (hShellDll));
  212. pfnCmdToArgs = NULL;
  213. }
  214. if (lpServiceArgVectors == NULL)
  215. return NULL;
  216. // ISSUE-2002/03/28-JonN I wouldn't mind being a little more cautious here
  217. // by checking the overall length of lpServiceArgVectors and the string-ness
  218. // of its components.
  219. for (int i = 1; i < cArgs; i++)
  220. {
  221. Assert(lpServiceArgVectors[i] != NULL);
  222. CString str = lpServiceArgVectors[i]; // Copy the string
  223. str = str.Left(cchOverrideCommandLine);
  224. if (0 != str.CompareNoCase(szOverrideCommandLineEquals) &&
  225. 0 != str.CompareNoCase(szOverrideCommandLineColon) )
  226. {
  227. continue;
  228. }
  229. str = lpServiceArgVectors[i] + cchOverrideCommandLine;
  230. if (0 == str.CompareNoCase(szLocalMachine))
  231. str.Empty();
  232. if (NERR_Success != CanonicalizeComputername(INOUT str))
  233. continue;
  234. g_strOverrideMachineName = str; // Copy the argument into the global string
  235. g_pszOverrideMachineName = g_strOverrideMachineName;
  236. }
  237. LocalFree(lpServiceArgVectors);
  238. return g_pszOverrideMachineName;
  239. } // PchGetMachineNameOverride()
  240. /////////////////////////////////////////////////////////////////////
  241. /////////////////////////////////////////////////////////////////////
  242. BEGIN_MESSAGE_MAP(CAutoDeletePropPage, CPropertyPage)
  243. //{{AFX_MSG_MAP(CAutoDeletePropPage)
  244. ON_MESSAGE(WM_HELP, OnHelp)
  245. ON_MESSAGE(WM_CONTEXTMENU, OnContextHelp)
  246. //}}AFX_MSG_MAP
  247. END_MESSAGE_MAP()
  248. /////////////////////////////////////////////////////////////////////
  249. // Constructor
  250. CAutoDeletePropPage::CAutoDeletePropPage(UINT uIDD) : CPropertyPage(uIDD)
  251. {
  252. m_prgzHelpIDs = NULL;
  253. m_autodeleteStuff.cWizPages = 1; // Number of pages in wizard
  254. m_autodeleteStuff.pfnOriginalPropSheetPageProc = m_psp.pfnCallback;
  255. m_psp.pfnCallback = S_PropSheetPageProc;
  256. m_psp.lParam = reinterpret_cast<LPARAM>(this);
  257. // The following line is to enable MFC property pages to run under MMC.
  258. MMCPropPageCallback(INOUT &m_psp);
  259. }
  260. CAutoDeletePropPage::~CAutoDeletePropPage()
  261. {
  262. }
  263. /////////////////////////////////////////////////////////////////////
  264. void CAutoDeletePropPage::SetCaption(LPCTSTR pszCaption)
  265. {
  266. m_strCaption = pszCaption; // Copy the caption
  267. m_psp.pszTitle = m_strCaption; // Set the title
  268. m_psp.dwFlags |= PSP_USETITLE;
  269. }
  270. /////////////////////////////////////////////////////////////////////
  271. void CAutoDeletePropPage::SetCaption(UINT uStringID)
  272. {
  273. VERIFY(m_strCaption.LoadString(uStringID));
  274. SetCaption(m_strCaption);
  275. }
  276. /////////////////////////////////////////////////////////////////////
  277. void CAutoDeletePropPage::SetHelp(LPCTSTR szHelpFile, const DWORD rgzHelpIDs[])
  278. {
  279. Endorse(szHelpFile == NULL); // TRUE => No help file supplied (meaning no help)
  280. Endorse(rgzHelpIDs == NULL); // TRUE => No help at all
  281. m_strHelpFile = szHelpFile;
  282. m_prgzHelpIDs = rgzHelpIDs;
  283. }
  284. /////////////////////////////////////////////////////////////////////
  285. void CAutoDeletePropPage::EnableDlgItem(INT nIdDlgItem, BOOL fEnable)
  286. {
  287. Assert(IsWindow(::GetDlgItem(m_hWnd, nIdDlgItem)));
  288. ::EnableWindow(::GetDlgItem(m_hWnd, nIdDlgItem), fEnable);
  289. }
  290. /////////////////////////////////////////////////////////////////////
  291. BOOL CAutoDeletePropPage::OnSetActive()
  292. {
  293. HWND hwndParent = ::GetParent(m_hWnd);
  294. Assert(IsWindow(hwndParent));
  295. ::PropSheet_SetWizButtons(hwndParent, PSWIZB_FINISH);
  296. return CPropertyPage::OnSetActive();
  297. }
  298. /////////////////////////////////////////////////////////////////////
  299. BOOL CAutoDeletePropPage::OnHelp(WPARAM /*wParam*/, LPARAM lParam)
  300. {
  301. if (m_prgzHelpIDs == NULL || m_strHelpFile.IsEmpty())
  302. return TRUE;
  303. const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  304. if (pHelpInfo != NULL && pHelpInfo->iContextType == HELPINFO_WINDOW)
  305. {
  306. // Display context help for a control
  307. ::WinHelp((HWND)pHelpInfo->hItemHandle, m_strHelpFile,
  308. HELP_WM_HELP, (DWORD_PTR)m_prgzHelpIDs);
  309. }
  310. return TRUE;
  311. }
  312. /////////////////////////////////////////////////////////////////////
  313. BOOL CAutoDeletePropPage::OnContextHelp(WPARAM wParam, LPARAM /*lParam*/)
  314. {
  315. if (m_prgzHelpIDs == NULL || m_strHelpFile.IsEmpty())
  316. return TRUE;
  317. Assert(IsWindow((HWND)wParam));
  318. ::WinHelp((HWND)wParam, m_strHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)m_prgzHelpIDs);
  319. return TRUE;
  320. }
  321. /////////////////////////////////////////////////////////////////////
  322. // S_PropSheetPageProc()
  323. //
  324. // Static member function used to delete the CAutoDeletePropPage object
  325. // when wizard terminates
  326. //
  327. UINT CALLBACK CAutoDeletePropPage::S_PropSheetPageProc(
  328. HWND hwnd,
  329. UINT uMsg,
  330. LPPROPSHEETPAGE ppsp)
  331. {
  332. Assert(ppsp != NULL);
  333. CChooseMachinePropPage * pThis;
  334. pThis = reinterpret_cast<CChooseMachinePropPage*>(ppsp->lParam);
  335. Assert(pThis != NULL);
  336. switch (uMsg)
  337. {
  338. case PSPCB_RELEASE:
  339. if (--(pThis->m_autodeleteStuff.cWizPages) <= 0)
  340. {
  341. // Remember callback on stack since "this" will be deleted
  342. LPFNPSPCALLBACK pfnOrig = pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc;
  343. delete pThis;
  344. return (pfnOrig)(hwnd, uMsg, ppsp);
  345. }
  346. break;
  347. case PSPCB_CREATE:
  348. // do not increase refcount, PSPCB_CREATE may or may not be called
  349. // depending on whether the page was created. PSPCB_RELEASE can be
  350. // depended upon to be called exactly once per page however.
  351. break;
  352. } // switch
  353. return (pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc)(hwnd, uMsg, ppsp);
  354. } // CAutoDeletePropPage::S_PropSheetPageProc()
  355. /////////////////////////////////////////////////////////////////////
  356. /////////////////////////////////////////////////////////////////////
  357. BEGIN_MESSAGE_MAP(CChooseMachinePropPage, CAutoDeletePropPage)
  358. //{{AFX_MSG_MAP(CChooseMachinePropPage)
  359. ON_BN_CLICKED(IDC_CHOOSER_RADIO_LOCAL_MACHINE, OnRadioLocalMachine)
  360. ON_BN_CLICKED(IDC_CHOOSER_RADIO_SPECIFIC_MACHINE, OnRadioSpecificMachine)
  361. ON_BN_CLICKED(IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, OnChooserButtonBrowseMachinenames)
  362. //}}AFX_MSG_MAP
  363. END_MESSAGE_MAP()
  364. #ifdef _DEBUG
  365. static void AssertValidDialogTemplate(HWND hwnd)
  366. {
  367. ASSERT(::IsWindow(hwnd));
  368. // Mandatory controls for a valid dialog template
  369. static const UINT rgzidDialogControl[] =
  370. {
  371. IDC_CHOOSER_RADIO_LOCAL_MACHINE,
  372. IDC_CHOOSER_RADIO_SPECIFIC_MACHINE,
  373. IDC_CHOOSER_EDIT_MACHINE_NAME,
  374. 0
  375. };
  376. for (int i = 0; rgzidDialogControl[i] != 0; i++)
  377. {
  378. ASSERT(NULL != GetDlgItem(hwnd, rgzidDialogControl[i]) &&
  379. "Control ID not found in dialog template.");
  380. }
  381. } // AssertValidDialogTemplate()
  382. #else
  383. #define AssertValidDialogTemplate(hwnd)
  384. #endif // ~_DEBUG
  385. /////////////////////////////////////////////////////////////////////
  386. // Constructor
  387. CChooseMachinePropPage::CChooseMachinePropPage(UINT uIDD) : CAutoDeletePropPage(uIDD)
  388. {
  389. // ISSUE-2002/03/28-JonN initialize m_hwndCheckboxOverride
  390. m_fIsRadioLocalMachine = TRUE;
  391. m_fAllowOverrideMachineName = FALSE;
  392. m_pfAllowOverrideMachineNameOut = NULL;
  393. m_pstrMachineNameOut = NULL;
  394. m_pstrMachineNameEffectiveOut = NULL;
  395. }
  396. /////////////////////////////////////////////////////////////////////
  397. CChooseMachinePropPage::~CChooseMachinePropPage()
  398. {
  399. }
  400. /////////////////////////////////////////////////////////////////////
  401. // Load the initial state of CChooseMachinePropPage
  402. void CChooseMachinePropPage::InitMachineName(LPCTSTR pszMachineName)
  403. {
  404. Endorse(pszMachineName == NULL);
  405. m_strMachineName = pszMachineName;
  406. m_fIsRadioLocalMachine = m_strMachineName.IsEmpty();
  407. }
  408. /////////////////////////////////////////////////////////////////////
  409. // SetOutputBuffers()
  410. //
  411. // - Set the pointer to the CString object to store the machine name.
  412. // - Set the pointer to the boolean flag for command line override.
  413. // - Set the pointer pointer to store the overriden machine name.
  414. //
  415. void CChooseMachinePropPage::SetOutputBuffers(
  416. OUT CString * pstrMachineNamePersist, // Machine name the user typed. Empty string == local machine.
  417. OUT BOOL * pfAllowOverrideMachineName,
  418. OUT CString * pstrMachineNameEffective)
  419. {
  420. Assert(pstrMachineNamePersist != NULL && "Invalid output buffer");
  421. Endorse(pfAllowOverrideMachineName == NULL); // TRUE => Do not want to support override from command line
  422. Endorse(pstrMachineNameEffective == NULL); // TRUE => Don't care of override
  423. m_pstrMachineNameOut = pstrMachineNamePersist;
  424. m_pfAllowOverrideMachineNameOut = pfAllowOverrideMachineName;
  425. m_pstrMachineNameEffectiveOut = pstrMachineNameEffective;
  426. }
  427. /////////////////////////////////////////////////////////////////////
  428. void CChooseMachinePropPage::DoDataExchange(CDataExchange* pDX)
  429. {
  430. CAutoDeletePropPage::DoDataExchange(pDX);
  431. //{{AFX_DATA_MAP(CChooseMachinePropPage)
  432. //}}AFX_DATA_MAP
  433. DDX_Text(pDX, IDC_CHOOSER_EDIT_MACHINE_NAME, m_strMachineName);
  434. DDV_MaxChars(pDX, m_strMachineName, MAX_PATH);
  435. if (NULL != m_hwndCheckboxOverride)
  436. {
  437. DDX_Check(pDX, IDC_CHOOSER_CHECK_OVERRIDE_MACHINE_NAME, m_fAllowOverrideMachineName);
  438. }
  439. // JonN 10/25/01 485853
  440. if (pDX->m_bSaveAndValidate && !m_fIsRadioLocalMachine)
  441. {
  442. // User clicked on OK
  443. if (NERR_Success != CanonicalizeComputername(INOUT m_strMachineName) )
  444. {
  445. // AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxMessageBox()
  446. // AfxMessageBox(IDS_CHOOSER_INVALID_COMPUTERNAME);
  447. CString text;
  448. CString caption;
  449. text.LoadString (IDS_CHOOSER_INVALID_COMPUTERNAME);
  450. caption.LoadString (IDS_SELECT_COMPUTER);
  451. ::MessageBox (m_hWnd, text, caption, MB_ICONEXCLAMATION | MB_OK);
  452. //::SetFocus(::GetDlgItem(m_hWnd,IDC_CHOOSER_EDIT_MACHINE_NAME));
  453. pDX->Fail();
  454. Assert(FALSE && "Unreachable code");
  455. }
  456. } // if
  457. } // DoDataExchange()
  458. /////////////////////////////////////////////////////////////////////
  459. BOOL CChooseMachinePropPage::OnInitDialog()
  460. {
  461. // ISSUE-2002/03/28-JonN chooser2 calls Edit_LimitText(MAX_PATH+2)
  462. AssertValidDialogTemplate(m_hWnd);
  463. CAutoDeletePropPage::OnInitDialog();
  464. InitRadioButtons();
  465. m_hwndCheckboxOverride = ::GetDlgItem(m_hWnd, IDC_CHOOSER_CHECK_OVERRIDE_MACHINE_NAME);
  466. if (m_pfAllowOverrideMachineNameOut == NULL && m_hwndCheckboxOverride != NULL)
  467. {
  468. // We are not interested with the command line override
  469. ::EnableWindow(m_hwndCheckboxOverride, FALSE); // Disable the window
  470. ::ShowWindow(m_hwndCheckboxOverride, SW_HIDE); // Hide the window
  471. }
  472. return TRUE;
  473. }
  474. /////////////////////////////////////////////////////////////////////
  475. BOOL CChooseMachinePropPage::OnWizardFinish()
  476. {
  477. if (!UpdateData()) // Do the data exchange to collect data
  478. return FALSE; // don't destroy on error
  479. if (m_fIsRadioLocalMachine)
  480. m_strMachineName.Empty();
  481. if (m_pstrMachineNameOut != NULL)
  482. {
  483. // Store the machine name into its output buffer
  484. *m_pstrMachineNameOut = m_strMachineName;
  485. if (m_pfAllowOverrideMachineNameOut != NULL)
  486. *m_pfAllowOverrideMachineNameOut = m_fAllowOverrideMachineName;
  487. if (m_pstrMachineNameEffectiveOut != NULL)
  488. {
  489. if (m_fAllowOverrideMachineName && PchGetMachineNameOverride())
  490. *m_pstrMachineNameEffectiveOut = PchGetMachineNameOverride();
  491. else
  492. *m_pstrMachineNameEffectiveOut = m_strMachineName;
  493. // JonN 1/27/99: If the persisted name is the local computername,
  494. // leave the persisted name alone but make the effective name (Local).
  495. if ( IsLocalComputername( *m_pstrMachineNameEffectiveOut ) )
  496. m_pstrMachineNameEffectiveOut->Empty();
  497. } // if
  498. }
  499. else
  500. Assert(FALSE && "FYI: You have not specified any output buffer to store the machine name.");
  501. return CAutoDeletePropPage::OnWizardFinish();
  502. }
  503. void CChooseMachinePropPage::InitRadioButtons()
  504. {
  505. SendDlgItemMessage(IDC_CHOOSER_RADIO_LOCAL_MACHINE, BM_SETCHECK, m_fIsRadioLocalMachine);
  506. SendDlgItemMessage(IDC_CHOOSER_RADIO_SPECIFIC_MACHINE, BM_SETCHECK, !m_fIsRadioLocalMachine);
  507. SendDlgItemMessage(IDC_CHOOSER_EDIT_MACHINE_NAME, MAX_PATH-1);
  508. EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, !m_fIsRadioLocalMachine);
  509. EnableDlgItem (IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, !m_fIsRadioLocalMachine);
  510. }
  511. void CChooseMachinePropPage::OnRadioLocalMachine()
  512. {
  513. m_fIsRadioLocalMachine = TRUE;
  514. EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, FALSE);
  515. EnableDlgItem (IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, FALSE);
  516. }
  517. void CChooseMachinePropPage::OnRadioSpecificMachine()
  518. {
  519. m_fIsRadioLocalMachine = FALSE;
  520. EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, TRUE);
  521. EnableDlgItem (IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, TRUE);
  522. }
  523. void CChooseMachinePropPage::OnChooserButtonBrowseMachinenames()
  524. {
  525. CString computerName;
  526. HRESULT hr = ComputerNameFromObjectPicker (m_hWnd, computerName);
  527. if ( S_OK == hr ) // S_FALSE means user pressed "Cancel"
  528. {
  529. SetDlgItemText (IDC_CHOOSER_EDIT_MACHINE_NAME, computerName);
  530. }
  531. else if ( FAILED (hr) )
  532. {
  533. CString text;
  534. CString caption;
  535. text.LoadString (IDS_UNABLE_TO_OPEN_COMPUTER_SELECTOR);
  536. caption.LoadString (IDS_SELECT_COMPUTER);
  537. MessageBox (text, caption, MB_ICONEXCLAMATION | MB_OK);
  538. }
  539. }
  540. ///////////////////////////////////////////////////////////////////////////////
  541. ///////////////////////////////////////////////////////////////////////////////
  542. // Generic Computer Picker
  543. ///////////////////////////////////////////////////////////////////////////////
  544. //+--------------------------------------------------------------------------
  545. //
  546. // Function: InitObjectPickerForComputers
  547. //
  548. // Synopsis: Call IDsObjectPicker::Initialize with arguments that will
  549. // set it to allow the user to pick a single computer object.
  550. //
  551. // Arguments: [pDsObjectPicker] - object picker interface instance
  552. //
  553. // Returns: Result of calling IDsObjectPicker::Initialize.
  554. //
  555. // History: 10-14-1998 DavidMun Created
  556. //
  557. //---------------------------------------------------------------------------
  558. HRESULT InitObjectPickerForComputers(IDsObjectPicker *pDsObjectPicker)
  559. {
  560. if ( !pDsObjectPicker )
  561. return E_POINTER;
  562. //
  563. // Prepare to initialize the object picker.
  564. // Set up the array of scope initializer structures.
  565. //
  566. static const int SCOPE_INIT_COUNT = 2;
  567. DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
  568. ZeroMemory(aScopeInit, sizeof(aScopeInit)); // JonN 3/28/02
  569. //
  570. // 127399: JonN 10/30/00 JOINED_DOMAIN should be starting scope
  571. //
  572. aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  573. aScopeInit[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
  574. | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
  575. aScopeInit[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE;
  576. aScopeInit[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS;
  577. aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
  578. aScopeInit[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  579. aScopeInit[1].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN
  580. | DSOP_SCOPE_TYPE_GLOBAL_CATALOG
  581. | DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN
  582. | DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN
  583. | DSOP_SCOPE_TYPE_WORKGROUP
  584. | DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE
  585. | DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE;
  586. aScopeInit[1].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS;
  587. aScopeInit[1].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
  588. //
  589. // Put the scope init array into the object picker init array
  590. //
  591. DSOP_INIT_INFO initInfo;
  592. ZeroMemory(&initInfo, sizeof(initInfo));
  593. initInfo.cbSize = sizeof(initInfo);
  594. initInfo.pwzTargetComputer = NULL; // NULL == local machine
  595. initInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
  596. initInfo.aDsScopeInfos = aScopeInit;
  597. initInfo.cAttributesToFetch = 1;
  598. static PCWSTR pwszDnsHostName = L"dNSHostName";
  599. initInfo.apwzAttributeNames = &pwszDnsHostName;
  600. //
  601. // Note object picker makes its own copy of initInfo. Also note
  602. // that Initialize may be called multiple times, last call wins.
  603. //
  604. return pDsObjectPicker->Initialize(&initInfo);
  605. }
  606. //+--------------------------------------------------------------------------
  607. //
  608. // Function: ProcessSelectedObjects
  609. //
  610. // Synopsis: Retrieve the list of selected items from the data object
  611. // created by the object picker and print out each one.
  612. //
  613. // Arguments: [pdo] - data object returned by object picker
  614. //
  615. // History: 10-14-1998 DavidMun Created
  616. //
  617. //---------------------------------------------------------------------------
  618. HRESULT ProcessSelectedObjects(IDataObject *pdo, CString& computerName)
  619. {
  620. if ( !pdo )
  621. return E_POINTER;
  622. HRESULT hr = S_OK;
  623. static UINT g_cfDsObjectPicker =
  624. RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
  625. STGMEDIUM stgmedium =
  626. {
  627. TYMED_HGLOBAL,
  628. NULL,
  629. NULL
  630. };
  631. FORMATETC formatetc =
  632. {
  633. (CLIPFORMAT)g_cfDsObjectPicker,
  634. NULL,
  635. DVASPECT_CONTENT,
  636. -1,
  637. TYMED_HGLOBAL
  638. };
  639. bool fGotStgMedium = false;
  640. do
  641. {
  642. hr = pdo->GetData(&formatetc, &stgmedium);
  643. if ( SUCCEEDED (hr) )
  644. {
  645. fGotStgMedium = true;
  646. PDS_SELECTION_LIST pDsSelList =
  647. (PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
  648. if (!pDsSelList)
  649. {
  650. hr = HRESULT_FROM_WIN32 (GetLastError());
  651. break;
  652. }
  653. ASSERT (1 == pDsSelList->cItems);
  654. if ( 1 == pDsSelList->cItems )
  655. {
  656. PDS_SELECTION psel = &(pDsSelList->aDsSelection[0]);
  657. // ISSUE-2002/03/28-JonN check for NULL == psel
  658. VARIANT* pvarDnsName = &(psel->pvarFetchedAttributes[0]);
  659. if ( NULL == pvarDnsName
  660. || VT_BSTR != pvarDnsName->vt
  661. || NULL == pvarDnsName->bstrVal
  662. || L'\0' == (pvarDnsName->bstrVal)[0] )
  663. {
  664. computerName = psel->pwzName;
  665. } else {
  666. computerName = pvarDnsName->bstrVal;
  667. //
  668. // JonN 2002/04/08 585301
  669. // Computer management snapin only attempts to use the DnsHostName
  670. // to connect to a remote computer, even when the dns name
  671. // is not valid
  672. //
  673. // Bank of America encounters a problem because they
  674. // set RegisterDnsARecord to 1, turning off client DNS
  675. // records. The dnsHostName is therefore not a valid
  676. // binding name. The fix is to test the dnsHostName.
  677. //
  678. LPBYTE pbDummy = NULL;
  679. NET_API_STATUS err = NetServerGetInfo(
  680. (LPTSTR)(LPCTSTR)computerName, 101, &pbDummy );
  681. if (pbDummy)
  682. {
  683. NetApiBufferFree( pbDummy );
  684. pbDummy = NULL;
  685. }
  686. if (NERR_Success != err)
  687. {
  688. err = NetServerGetInfo( psel->pwzName, 101, &pbDummy );
  689. if (pbDummy)
  690. {
  691. NetApiBufferFree( pbDummy );
  692. pbDummy = NULL;
  693. }
  694. if (NERR_Success == err)
  695. computerName = psel->pwzName;
  696. }
  697. // end new code: JonN 2002/04/08 585301
  698. }
  699. }
  700. else
  701. hr = E_UNEXPECTED;
  702. GlobalUnlock(stgmedium.hGlobal);
  703. }
  704. } while (0);
  705. if (fGotStgMedium)
  706. {
  707. ReleaseStgMedium(&stgmedium);
  708. }
  709. return hr;
  710. }
  711. ///////////////////////////////////////////////////////////////////////////////
  712. // Generic method for launching a single-select computer picker
  713. //
  714. // Paremeters:
  715. // hwndParent (IN) - window handle of parent window
  716. // computerName (OUT) - computer name returned
  717. //
  718. // Returns S_OK if everything succeeded, S_FALSE if user pressed "Cancel"
  719. //
  720. //////////////////////////////////////////////////////////////////////////////
  721. HRESULT ComputerNameFromObjectPicker (HWND hwndParent, CString& computerName)
  722. {
  723. //
  724. // Create an instance of the object picker. The implementation in
  725. // objsel.dll is apartment model.
  726. //
  727. CComPtr<IDsObjectPicker> spDsObjectPicker;
  728. HRESULT hr = CoCreateInstance(CLSID_DsObjectPicker,
  729. NULL,
  730. CLSCTX_INPROC_SERVER,
  731. IID_IDsObjectPicker,
  732. (void **) &spDsObjectPicker);
  733. if ( SUCCEEDED (hr) )
  734. {
  735. ASSERT(!!spDsObjectPicker);
  736. //
  737. // Initialize the object picker to choose computers
  738. //
  739. hr = InitObjectPickerForComputers(spDsObjectPicker);
  740. if ( SUCCEEDED (hr) )
  741. {
  742. //
  743. // Now pick a computer
  744. //
  745. CComPtr<IDataObject> spDataObject;
  746. hr = spDsObjectPicker->InvokeDialog(hwndParent, &spDataObject);
  747. if ( S_OK == hr )
  748. {
  749. ASSERT(!!spDataObject);
  750. hr = ProcessSelectedObjects(spDataObject, computerName);
  751. }
  752. }
  753. }
  754. return hr;
  755. }