Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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