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.

510 lines
16 KiB

  1. /////////////////////////////////////////////////////////////////////
  2. // Chooser.cpp
  3. //
  4. // Copyright (c) 1998-1999 Microsoft Corporation
  5. //
  6. // Dialog to choose a machine name.
  7. //
  8. // PURPOSE
  9. // (Important -- Please Read)
  10. // This code was written for you to save you time.
  11. // What you have to do is to copy all the files from the
  12. // snapin\chooser\ directory into your project (you may add
  13. // \nt\private\admin\snapin\chooser\ to your include directory if
  14. // you prefer not copying the code).
  15. // If you decide to copy the code to your project, please send mail
  16. // to Dan Morin (T-DanM) and cc to Jon Newman (JonN) so we can
  17. // mail you when we have updates available. The next update will
  18. // be the "Browse" button to select a machine name.
  19. //
  20. // LIBRARY REQUIRED
  21. // $(BASEDIR)\public\sdk\lib\*\netapi32.lib // I_NetName*()
  22. // $(BASEDIR)\public\sdk\lib\*\shell32.lib // CommandLineToArgvW()
  23. //
  24. // EXTRA INFO
  25. // If you don't know how this works, take a look at the inheritance tree
  26. // in chooser.h. Then, take a look at the existing code that inherit and/or
  27. // uses CChooseMachinePropPage.
  28. //
  29. // HISTORY
  30. // 13-May-1997 t-danm Creation.
  31. // 23-May-1997 t-danm Checkin into public tree. Comments updates.
  32. // 25-May-1997 t-danm Added MMCPropPageCallback().
  33. //
  34. /////////////////////////////////////////////////////////////////////
  35. #include "StdAfx.h"
  36. // This needs to be included before chooserd.h so that its definition of
  37. // IDS_CHOOSER_INVALID_COMPUTERNAME is used rahter than chooserd's
  38. #include "Resource.h"
  39. #include "chooser.h"
  40. #include <lmcons.h> // NET_API_STATUS
  41. #include <lmerr.h> // NERR_Success
  42. // Unknown error with lmcons.h?
  43. #ifndef NET_API_STATUS
  44. #define NET_API_STATUS DWORD
  45. #define NET_API_FUNCTION __stdcall
  46. #endif
  47. #include <icanon.h> // I_NetNameValidate(), I_NetNameCanonicalize(). Found in \nt\private\net\inc.
  48. #ifdef _DEBUG
  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. NET_API_STATUS
  66. CanonicalizeComputername(
  67. INOUT CString& rstrMachineName,
  68. IN BOOL fAddWackWack = TRUE) // TRUE => Add the \\ at beginning of name
  69. {
  70. rstrMachineName.TrimLeft();
  71. rstrMachineName.TrimRight();
  72. if ( rstrMachineName.IsEmpty() )
  73. return NERR_Success;
  74. if ( 2 <= rstrMachineName.GetLength() &&
  75. _T('\\') == rstrMachineName[0] &&
  76. _T('\\') == rstrMachineName[1] )
  77. {
  78. // Remove the \\ at the beginning of name
  79. CString strShorter = rstrMachineName.Right(
  80. rstrMachineName.GetLength() - 2 );
  81. rstrMachineName = strShorter;
  82. }
  83. NET_API_STATUS err = I_NetNameValidate(
  84. NULL,
  85. const_cast<LPTSTR>((LPCTSTR)rstrMachineName),
  86. NAMETYPE_COMPUTER,
  87. 0L );
  88. if (NERR_Success != err)
  89. return err;
  90. ASSERT( MAX_PATH > rstrMachineName.GetLength() );
  91. LPTSTR pszTemp = (LPTSTR)alloca( MAX_PATH*sizeof(TCHAR) );
  92. ASSERT( NULL != pszTemp );
  93. err = I_NetNameCanonicalize(
  94. NULL,
  95. IN const_cast<LPTSTR>((LPCTSTR)rstrMachineName),
  96. OUT pszTemp,
  97. MAX_PATH*sizeof(TCHAR),
  98. NAMETYPE_COMPUTER,
  99. 0L );
  100. if (NERR_Success != err)
  101. return err;
  102. if (fAddWackWack && pszTemp[0] != '\0')
  103. {
  104. // Add the \\ at beginning of name
  105. rstrMachineName = _T("\\\\");
  106. rstrMachineName += pszTemp;
  107. }
  108. else
  109. {
  110. rstrMachineName = pszTemp;
  111. }
  112. return NERR_Success;
  113. } // CanonicalizeComputername()
  114. /////////////////////////////////////////////////
  115. // Machine name override
  116. const TCHAR szOverrideCommandLine[] = _T("/Computer="); // Not subject to localization
  117. const TCHAR szLocalMachine[] = _T("LocalMachine"); // Not subject to localization
  118. const int cchOverrideCommandLine = LENGTH(szOverrideCommandLine) - 1;
  119. static CString g_strOverrideMachineName;
  120. static LPCTSTR g_pszOverrideMachineName; // NULL => No override provided, "" => LocalMachine
  121. ///////////////////////////////////////////////////////////////////////////////
  122. // PchGetMachineNameOverride()
  123. //
  124. // Parse the command line arguments and return a pointer to the
  125. // machine name override if present.
  126. //
  127. // INTERFACE NOTES
  128. // If the machine name is other than local machine, the machine name
  129. // will have the \\ at the beginning of its name.
  130. //
  131. // RETURN
  132. // - Return NULL if no override (ie, no command line override)
  133. // - Return pointer to empty string if override is "local machine"
  134. // - Otherwise return pointer to machine name override with \\ at beginning.
  135. //
  136. LPCTSTR
  137. PchGetMachineNameOverride()
  138. {
  139. static BOOL fAlreadyInitialized = FALSE;
  140. if (fAlreadyInitialized)
  141. {
  142. // We already have parsed the command line
  143. return g_pszOverrideMachineName;
  144. }
  145. fAlreadyInitialized = TRUE;
  146. ASSERT(g_pszOverrideMachineName == NULL);
  147. LPCWSTR * lpServiceArgVectors; // Array of pointers to string
  148. int cArgs = 0; // Count of arguments
  149. lpServiceArgVectors = (LPCWSTR *)CommandLineToArgvW(GetCommandLineW(), OUT &cArgs);
  150. if (lpServiceArgVectors == NULL)
  151. return NULL;
  152. for (int i = 1; i < cArgs; i++)
  153. {
  154. Assert(lpServiceArgVectors[i] != NULL);
  155. CString str = lpServiceArgVectors[i]; // Copy the string
  156. str = str.Left(cchOverrideCommandLine);
  157. if (0 != str.CompareNoCase(szOverrideCommandLine))
  158. continue;
  159. str = lpServiceArgVectors[i] + cchOverrideCommandLine;
  160. if (0 == str.CompareNoCase(szLocalMachine))
  161. str.Empty();
  162. if (NERR_Success != CanonicalizeComputername(INOUT str))
  163. continue;
  164. g_strOverrideMachineName = str; // Copy the argument into the global string
  165. g_pszOverrideMachineName = g_strOverrideMachineName;
  166. }
  167. LocalFree(lpServiceArgVectors);
  168. return g_pszOverrideMachineName;
  169. } // PchGetMachineNameOverride()
  170. /////////////////////////////////////////////////////////////////////
  171. /////////////////////////////////////////////////////////////////////
  172. BEGIN_MESSAGE_MAP(CAutoDeletePropPage, CPropertyPage)
  173. //{{AFX_MSG_MAP(CAutoDeletePropPage)
  174. ON_MESSAGE(WM_HELP, OnHelp)
  175. ON_MESSAGE(WM_CONTEXTMENU, OnContextHelp)
  176. //}}AFX_MSG_MAP
  177. END_MESSAGE_MAP()
  178. /////////////////////////////////////////////////////////////////////
  179. // Constructor
  180. CAutoDeletePropPage::CAutoDeletePropPage(UINT uIDD) : CPropertyPage(uIDD)
  181. {
  182. m_prgzHelpIDs = NULL;
  183. m_autodeleteStuff.cWizPages = 1; // Number of pages in wizard
  184. m_autodeleteStuff.pfnOriginalPropSheetPageProc = m_psp.pfnCallback;
  185. m_psp.pfnCallback = S_PropSheetPageProc;
  186. m_psp.lParam = reinterpret_cast<LPARAM>(this);
  187. // The following line is to enable MFC property pages to run under MMC.
  188. MMCPropPageCallback(INOUT &m_psp);
  189. }
  190. CAutoDeletePropPage::~CAutoDeletePropPage()
  191. {
  192. }
  193. /////////////////////////////////////////////////////////////////////
  194. void CAutoDeletePropPage::SetCaption(LPCTSTR pszCaption)
  195. {
  196. m_strCaption = pszCaption; // Copy the caption
  197. m_psp.pszTitle = m_strCaption; // Set the title
  198. m_psp.dwFlags |= PSP_USETITLE;
  199. }
  200. /////////////////////////////////////////////////////////////////////
  201. void CAutoDeletePropPage::SetCaption(UINT uStringID)
  202. {
  203. VERIFY(m_strCaption.LoadString(uStringID));
  204. SetCaption(m_strCaption);
  205. }
  206. /////////////////////////////////////////////////////////////////////
  207. void CAutoDeletePropPage::SetHelp(LPCTSTR szHelpFile, const DWORD rgzHelpIDs[])
  208. {
  209. Endorse(szHelpFile == NULL); // TRUE => No help file supplied (meaning no help)
  210. Endorse(rgzHelpIDs == NULL); // TRUE => No help at all
  211. m_strHelpFile = szHelpFile;
  212. m_prgzHelpIDs = rgzHelpIDs;
  213. }
  214. /////////////////////////////////////////////////////////////////////
  215. void CAutoDeletePropPage::EnableDlgItem(INT nIdDlgItem, BOOL fEnable)
  216. {
  217. Assert(IsWindow(::GetDlgItem(m_hWnd, nIdDlgItem)));
  218. ::EnableWindow(::GetDlgItem(m_hWnd, nIdDlgItem), fEnable);
  219. }
  220. /////////////////////////////////////////////////////////////////////
  221. BOOL CAutoDeletePropPage::OnSetActive()
  222. {
  223. HWND hwndParent = ::GetParent(m_hWnd);
  224. HWND hwndBtn = ::GetDlgItem(hwndParent, IDOK);
  225. Assert(IsWindow(hwndParent));
  226. // Only set focus to finish if we're in wizard mode -
  227. // not when the okay and cancel buttons are present, otherwise
  228. // the cancel button becomes the default.
  229. if (!::IsWindowEnabled(hwndBtn))
  230. ::PropSheet_SetWizButtons(hwndParent, PSWIZB_FINISH);
  231. return CPropertyPage::OnSetActive();
  232. }
  233. /////////////////////////////////////////////////////////////////////
  234. BOOL CAutoDeletePropPage::OnHelp(WPARAM, LPARAM lParam)
  235. {
  236. if (m_prgzHelpIDs == NULL || m_strHelpFile.IsEmpty())
  237. return TRUE;
  238. const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  239. if (pHelpInfo != NULL && pHelpInfo->iContextType == HELPINFO_WINDOW)
  240. {
  241. // Display context help for a control
  242. ::WinHelp((HWND)pHelpInfo->hItemHandle, m_strHelpFile,
  243. HELP_WM_HELP, (ULONG_PTR)m_prgzHelpIDs);
  244. }
  245. return TRUE;
  246. }
  247. /////////////////////////////////////////////////////////////////////
  248. BOOL CAutoDeletePropPage::OnContextHelp(WPARAM wParam, LPARAM)
  249. {
  250. if (m_prgzHelpIDs == NULL || m_strHelpFile.IsEmpty())
  251. return TRUE;
  252. Assert(IsWindow((HWND)wParam));
  253. ::WinHelp((HWND)wParam, m_strHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)m_prgzHelpIDs);
  254. return TRUE;
  255. }
  256. /////////////////////////////////////////////////////////////////////
  257. // S_PropSheetPageProc()
  258. //
  259. // Static member function used to delete the CAutoDeletePropPage object
  260. // when wizard terminates
  261. //
  262. UINT CALLBACK CAutoDeletePropPage::S_PropSheetPageProc(
  263. HWND hwnd,
  264. UINT uMsg,
  265. LPPROPSHEETPAGE ppsp)
  266. {
  267. Assert(ppsp != NULL);
  268. CChooseMachinePropPage * pThis;
  269. pThis = reinterpret_cast<CChooseMachinePropPage*>(ppsp->lParam);
  270. Assert(pThis != NULL);
  271. switch (uMsg)
  272. {
  273. case PSPCB_RELEASE:
  274. if (--(pThis->m_autodeleteStuff.cWizPages) <= 0)
  275. {
  276. // Remember callback on stack since "this" will be deleted
  277. LPFNPSPCALLBACK pfnOrig = pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc;
  278. delete pThis;
  279. return (pfnOrig)(hwnd, uMsg, ppsp);
  280. }
  281. break;
  282. case PSPCB_CREATE:
  283. // do not increase refcount, PSPCB_CREATE may or may not be called
  284. // depending on whether the page was created. PSPCB_RELEASE can be
  285. // depended upon to be called exactly once per page however.
  286. break;
  287. } // switch
  288. return (pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc)(hwnd, uMsg, ppsp);
  289. } // CAutoDeletePropPage::S_PropSheetPageProc()
  290. /////////////////////////////////////////////////////////////////////
  291. /////////////////////////////////////////////////////////////////////
  292. BEGIN_MESSAGE_MAP(CChooseMachinePropPage, CAutoDeletePropPage)
  293. //{{AFX_MSG_MAP(CChooseMachinePropPage)
  294. ON_BN_CLICKED(IDC_CHOOSER_RADIO_LOCAL_MACHINE, OnRadioLocalMachine)
  295. ON_BN_CLICKED(IDC_CHOOSER_RADIO_SPECIFIC_MACHINE, OnRadioSpecificMachine)
  296. //}}AFX_MSG_MAP
  297. END_MESSAGE_MAP()
  298. #ifdef _DEBUG
  299. static void AssertValidDialogTemplate(HWND hwnd)
  300. {
  301. ASSERT(::IsWindow(hwnd));
  302. // Mandatory controls for a valid dialog template
  303. static const UINT rgzidDialogControl[] =
  304. {
  305. IDC_CHOOSER_RADIO_LOCAL_MACHINE,
  306. IDC_CHOOSER_RADIO_SPECIFIC_MACHINE,
  307. IDC_CHOOSER_EDIT_MACHINE_NAME,
  308. 0
  309. };
  310. for (int i = 0; rgzidDialogControl[i] != 0; i++)
  311. {
  312. ASSERT(NULL != GetDlgItem(hwnd, rgzidDialogControl[i]) &&
  313. "Control ID not found in dialog template.");
  314. }
  315. } // AssertValidDialogTemplate()
  316. #else
  317. #define AssertValidDialogTemplate(hwnd)
  318. #endif // ~_DEBUG
  319. /////////////////////////////////////////////////////////////////////
  320. // Constructor
  321. CChooseMachinePropPage::CChooseMachinePropPage(UINT uIDD)
  322. : CAutoDeletePropPage(uIDD)
  323. {
  324. m_fIsRadioLocalMachine = TRUE;
  325. m_fAllowOverrideMachineName = FALSE;
  326. m_pfAllowOverrideMachineNameOut = NULL;
  327. m_pstrMachineNameOut = NULL;
  328. m_pstrMachineNameEffectiveOut = NULL;
  329. }
  330. /////////////////////////////////////////////////////////////////////
  331. CChooseMachinePropPage::~CChooseMachinePropPage()
  332. {
  333. // CHECK: Is this the right place to free this?
  334. ::MMCFreeNotifyHandle(m_hNotify);
  335. }
  336. /////////////////////////////////////////////////////////////////////
  337. // Load the initial state of CChooseMachinePropPage
  338. void CChooseMachinePropPage::InitMachineName(LPCTSTR pszMachineName)
  339. {
  340. Endorse(pszMachineName == NULL);
  341. m_strMachineName = pszMachineName;
  342. m_fIsRadioLocalMachine = m_strMachineName.IsEmpty();
  343. }
  344. /////////////////////////////////////////////////////////////////////
  345. // SetOutputBuffers()
  346. //
  347. // - Set the pointer to the CString object to store the machine name.
  348. // - Set the pointer to the boolean flag for command line override.
  349. // - Set the pointer to store the overriden machine name.
  350. //
  351. void CChooseMachinePropPage::SetOutputBuffers(
  352. OUT CString * pstrMachineNamePersist, // Machine name the user typed. Empty string == local machine.
  353. OUT BOOL * pfAllowOverrideMachineName,
  354. OUT CString * pstrMachineNameEffective)
  355. {
  356. Assert(pstrMachineNamePersist != NULL && "Invalid output buffer");
  357. Endorse(pfAllowOverrideMachineName == NULL); // TRUE => Do not want to support override from command line
  358. Endorse(pstrMachineNameEffective == NULL); // TRUE => Don't care of override
  359. m_pstrMachineNameOut = pstrMachineNamePersist;
  360. m_pfAllowOverrideMachineNameOut = pfAllowOverrideMachineName;
  361. m_pstrMachineNameEffectiveOut = pstrMachineNameEffective;
  362. }
  363. /////////////////////////////////////////////////////////////////////
  364. void CChooseMachinePropPage::DoDataExchange(CDataExchange* pDX)
  365. {
  366. CAutoDeletePropPage::DoDataExchange(pDX);
  367. DDX_Text(pDX, IDC_CHOOSER_EDIT_MACHINE_NAME, m_strMachineName);
  368. DDV_MaxChars(pDX, m_strMachineName, MAX_PATH);
  369. if (NULL != m_hwndCheckboxOverride)
  370. {
  371. DDX_Check(pDX, IDC_CHOOSER_CHECK_OVERRIDE_MACHINE_NAME, m_fAllowOverrideMachineName);
  372. }
  373. if (pDX->m_bSaveAndValidate)
  374. {
  375. // User clicked on OK
  376. ASSERT(m_hNotify != NULL);
  377. if (m_hNotify != NULL)
  378. ::MMCPropertyChangeNotify(m_hNotify, 0);
  379. if (NERR_Success != CanonicalizeComputername(INOUT m_strMachineName) )
  380. {
  381. AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxGetMainWnd()
  382. CString strMessage, strTitle;
  383. strMessage.LoadString(IDS_CHOOSER_INVALID_COMPUTERNAME);
  384. strTitle.LoadString( IDS_DESCRIPTION);
  385. ::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strMessage, strTitle, MB_OK);
  386. pDX->Fail();
  387. Assert(FALSE && "Unreachable code");
  388. }
  389. } // if
  390. *m_pstrMachineNameOut = m_strMachineName;
  391. } // DoDataExchange()
  392. /////////////////////////////////////////////////////////////////////
  393. BOOL CChooseMachinePropPage::OnInitDialog()
  394. {
  395. AssertValidDialogTemplate(m_hWnd);
  396. CAutoDeletePropPage::OnInitDialog();
  397. InitRadioButtons();
  398. m_hwndCheckboxOverride = ::GetDlgItem(m_hWnd, IDC_CHOOSER_CHECK_OVERRIDE_MACHINE_NAME);
  399. if (m_pfAllowOverrideMachineNameOut == NULL && m_hwndCheckboxOverride != NULL)
  400. {
  401. // We are not interested with the command line override
  402. ::EnableWindow(m_hwndCheckboxOverride, FALSE); // Disable the window
  403. ::ShowWindow(m_hwndCheckboxOverride, SW_HIDE); // Hide the window
  404. }
  405. return TRUE;
  406. }
  407. /////////////////////////////////////////////////////////////////////
  408. BOOL CChooseMachinePropPage::OnWizardFinish()
  409. {
  410. if (!UpdateData()) return FALSE; // Do the data exchange to collect data
  411. if (m_fIsRadioLocalMachine)
  412. {
  413. m_strMachineName.Empty();
  414. }
  415. if (m_pstrMachineNameOut != NULL)
  416. {
  417. // Store the machine name into its output buffer
  418. *m_pstrMachineNameOut = m_strMachineName;
  419. if (m_pfAllowOverrideMachineNameOut != NULL)
  420. *m_pfAllowOverrideMachineNameOut = m_fAllowOverrideMachineName;
  421. if (m_pstrMachineNameEffectiveOut != NULL)
  422. {
  423. if (m_fAllowOverrideMachineName && PchGetMachineNameOverride())
  424. {
  425. *m_pstrMachineNameEffectiveOut = PchGetMachineNameOverride();
  426. }
  427. else
  428. {
  429. *m_pstrMachineNameEffectiveOut = m_strMachineName;
  430. }
  431. } // if
  432. }
  433. else
  434. {
  435. Assert(FALSE && "FYI: You have not specified any output buffer to store the machine name.");
  436. }
  437. return CAutoDeletePropPage::OnWizardFinish();
  438. }
  439. void CChooseMachinePropPage::InitRadioButtons()
  440. {
  441. SendDlgItemMessage(IDC_CHOOSER_RADIO_LOCAL_MACHINE, BM_SETCHECK, m_fIsRadioLocalMachine);
  442. SendDlgItemMessage(IDC_CHOOSER_RADIO_SPECIFIC_MACHINE, BM_SETCHECK, !m_fIsRadioLocalMachine);
  443. EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, !m_fIsRadioLocalMachine);
  444. }
  445. void CChooseMachinePropPage::OnRadioLocalMachine()
  446. {
  447. m_fIsRadioLocalMachine = TRUE;
  448. EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, FALSE);
  449. }
  450. void CChooseMachinePropPage::OnRadioSpecificMachine()
  451. {
  452. m_fIsRadioLocalMachine = FALSE;
  453. EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, TRUE);
  454. }