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.

1116 lines
35 KiB

  1. #include "stdafx.h"
  2. #include "PageBootIni.h"
  3. #include "MSConfigState.h"
  4. #include "BootAdv.h"
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #undef THIS_FILE
  8. static char THIS_FILE[] = __FILE__;
  9. #endif
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CPageBootIni property page
  12. IMPLEMENT_DYNCREATE(CPageBootIni, CPropertyPage)
  13. CPageBootIni::CPageBootIni() : CPropertyPage(CPageBootIni::IDD)
  14. {
  15. //{{AFX_DATA_INIT(CPageBootIni)
  16. // NOTE: the ClassWizard will add member initialization here
  17. //}}AFX_DATA_INIT
  18. m_fIgnoreEdit = FALSE;
  19. m_strFileName = BOOT_INI;
  20. m_fModified = FALSE;
  21. }
  22. CPageBootIni::~CPageBootIni()
  23. {
  24. }
  25. void CPageBootIni::DoDataExchange(CDataExchange* pDX)
  26. {
  27. CPropertyPage::DoDataExchange(pDX);
  28. //{{AFX_DATA_MAP(CPageBootIni)
  29. // NOTE: the ClassWizard will add DDX and DDV calls here
  30. //}}AFX_DATA_MAP
  31. }
  32. BEGIN_MESSAGE_MAP(CPageBootIni, CPropertyPage)
  33. //{{AFX_MSG_MAP(CPageBootIni)
  34. ON_BN_CLICKED(IDC_BOOTMOVEDOWN, OnBootMoveDown)
  35. ON_BN_CLICKED(IDC_BOOTMOVEUP, OnBootMoveUp)
  36. ON_LBN_SELCHANGE(IDC_LISTBOOTINI, OnSelChangeList)
  37. ON_BN_CLICKED(IDC_BASEVIDEO, OnClickedBase)
  38. ON_BN_CLICKED(IDC_BOOTLOG, OnClickedBootLog)
  39. ON_BN_CLICKED(IDC_NOGUIBOOT, OnClickedNoGUIBoot)
  40. ON_BN_CLICKED(IDC_SOS, OnClickedSOS)
  41. ON_BN_CLICKED(IDC_SAFEBOOT, OnClickedSafeBoot)
  42. ON_BN_CLICKED(IDC_SBDSREPAIR, OnClickedSBDSRepair)
  43. ON_BN_CLICKED(IDC_SBMINIMAL, OnClickedSBMinimal)
  44. ON_BN_CLICKED(IDC_SBMINIMALALT, OnClickedSBMinimalAlt)
  45. ON_BN_CLICKED(IDC_SBNETWORK, OnClickedSBNetwork)
  46. ON_EN_CHANGE(IDC_EDITTIMEOUT, OnChangeEditTimeOut)
  47. ON_EN_KILLFOCUS(IDC_EDITTIMEOUT, OnKillFocusEditTimeOut)
  48. ON_BN_CLICKED(IDC_BOOTADVANCED, OnClickedBootAdvanced)
  49. ON_BN_CLICKED(IDC_SETASDEFAULT, OnClickedSetAsDefault)
  50. ON_BN_CLICKED(IDC_CHECKBOOTPATHS, OnClickedCheckBootPaths)
  51. ON_WM_DESTROY()
  52. //}}AFX_MSG_MAP
  53. END_MESSAGE_MAP()
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CPageBootIni message handlers
  56. //-------------------------------------------------------------------------
  57. // Initialize this page by reading the contents of the boot.ini file.
  58. //-------------------------------------------------------------------------
  59. void CPageBootIni::InitializePage()
  60. {
  61. if (LoadBootIni() && m_nMinOSIndex != -1)
  62. {
  63. SyncControlsToIni();
  64. if (m_nMinOSIndex != -1)
  65. {
  66. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, m_nMinOSIndex, 0);
  67. SelectLine(m_nMinOSIndex);
  68. }
  69. }
  70. else
  71. {
  72. // Failed to load the boot.ini file (or it was empty). Disable all controls.
  73. ::EnableWindow(GetDlgItemHWND(IDC_BOOTMOVEUP), FALSE);
  74. ::EnableWindow(GetDlgItemHWND(IDC_BOOTMOVEDOWN), FALSE);
  75. ::EnableWindow(GetDlgItemHWND(IDC_SAFEBOOT), FALSE);
  76. ::EnableWindow(GetDlgItemHWND(IDC_NOGUIBOOT), FALSE);
  77. ::EnableWindow(GetDlgItemHWND(IDC_BOOTLOG), FALSE);
  78. ::EnableWindow(GetDlgItemHWND(IDC_BASEVIDEO), FALSE);
  79. ::EnableWindow(GetDlgItemHWND(IDC_SOS), FALSE);
  80. ::EnableWindow(GetDlgItemHWND(IDC_BOOTADVANCED), FALSE);
  81. ::EnableWindow(GetDlgItemHWND(IDC_SBNETWORK), FALSE);
  82. ::EnableWindow(GetDlgItemHWND(IDC_SBDSREPAIR), FALSE);
  83. ::EnableWindow(GetDlgItemHWND(IDC_SBMINIMAL), FALSE);
  84. ::EnableWindow(GetDlgItemHWND(IDC_SBMINIMALALT), FALSE);
  85. ::EnableWindow(GetDlgItemHWND(IDC_SETASDEFAULT), FALSE);
  86. ::EnableWindow(GetDlgItemHWND(IDC_CHECKBOOTPATHS), FALSE);
  87. ::EnableWindow(GetDlgItemHWND(IDC_EDITTIMEOUT), FALSE);
  88. }
  89. m_stateCurrent = CPageBase::GetAppliedTabState();
  90. }
  91. //-------------------------------------------------------------------------
  92. // Load the contents of the BOOT.INI file into our local structures.
  93. //-------------------------------------------------------------------------
  94. BOOL CPageBootIni::LoadBootIni(CString strFileName)
  95. {
  96. if (strFileName.IsEmpty())
  97. strFileName = m_strFileName;
  98. // Read the contents of the boot.ini file into a string.
  99. HANDLE h = ::CreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  100. if (INVALID_HANDLE_VALUE == h)
  101. return FALSE;
  102. CString strContents;
  103. DWORD dwNumberBytesRead, dwNumberBytesToRead = ::GetFileSize(h, NULL);
  104. // The BOOT.INI file is ANSI, so we should read it and convert to Unicode.
  105. char * szBuffer = new char[dwNumberBytesToRead + 1];
  106. ::ZeroMemory((PVOID)szBuffer, dwNumberBytesToRead + 1);
  107. if (!::ReadFile(h, (LPVOID)szBuffer, dwNumberBytesToRead, &dwNumberBytesRead, NULL))
  108. *szBuffer = _T('\0');
  109. ::CloseHandle(h);
  110. // Do the conversion.
  111. USES_CONVERSION;
  112. LPTSTR szConverted = A2T(szBuffer);
  113. strContents = szConverted;
  114. delete [] szBuffer;
  115. if (dwNumberBytesToRead != dwNumberBytesRead || strContents.IsEmpty())
  116. return FALSE;
  117. // Save the original contents of the file.
  118. m_strOriginalContents = strContents;
  119. // Parse the contents of the string into an array of strings (one for each line
  120. // of the file).
  121. m_arrayIniLines.RemoveAll();
  122. m_arrayIniLines.SetSize(10, 10);
  123. CString strLine;
  124. int nIndex = 0;
  125. while (!strContents.IsEmpty())
  126. {
  127. strLine = strContents.SpanExcluding(_T("\r\n"));
  128. if (!strLine.IsEmpty())
  129. {
  130. m_arrayIniLines.SetAtGrow(nIndex, strLine);
  131. nIndex += 1;
  132. }
  133. strContents = strContents.Mid(strLine.GetLength());
  134. strContents.TrimLeft(_T("\r\n"));
  135. }
  136. // Look through the lines read from the INI file, searching for particular
  137. // ones we'll want to make a note of.
  138. m_nTimeoutIndex = m_nDefaultIndex = m_nMinOSIndex = m_nMaxOSIndex = -1;
  139. for (int i = 0; i <= m_arrayIniLines.GetUpperBound(); i++)
  140. {
  141. CString strScanLine = m_arrayIniLines[i];
  142. strScanLine.MakeLower();
  143. strScanLine.Replace(_T(" "), _T(""));
  144. if (strScanLine.Find(_T("timeout=")) != -1)
  145. m_nTimeoutIndex = i;
  146. else if (strScanLine.Find(_T("default=")) != -1)
  147. m_nDefaultIndex = i;
  148. if (m_nMinOSIndex != -1 && m_nMaxOSIndex == -1 && (strScanLine.IsEmpty() || strScanLine[0] == _T('[')))
  149. m_nMaxOSIndex = i - 1;
  150. else if (strScanLine.Find(_T("[operatingsystems]")) != -1)
  151. m_nMinOSIndex = i + 1;
  152. }
  153. if (m_nMinOSIndex != -1 && m_nMaxOSIndex == -1)
  154. m_nMaxOSIndex = i - 1;
  155. return TRUE;
  156. }
  157. //----------------------------------------------------------------------------
  158. // Update the state of the controls on this tab to match the contents of the
  159. // internal representation of the INI file.
  160. //----------------------------------------------------------------------------
  161. void CPageBootIni::SyncControlsToIni(BOOL fSyncEditField)
  162. {
  163. // We need to keep track of the extent of the strings in the list box
  164. // (to handle a horizontal scroll bar). Code from MSDN.
  165. DWORD dwExtent, dwMaxExtent = 0;
  166. TEXTMETRIC tm;
  167. HDC hDCListBox = ::GetDC(GetDlgItemHWND(IDC_LISTBOOTINI));
  168. HFONT hFontNew = (HFONT)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), WM_GETFONT, NULL, NULL);
  169. HFONT hFontOld = (HFONT)::SelectObject(hDCListBox, hFontNew);
  170. ::GetTextMetrics(hDCListBox, (LPTEXTMETRIC)&tm);
  171. CDC dc;
  172. dc.Attach(hDCListBox);
  173. for (int i = 0; i <= m_arrayIniLines.GetUpperBound(); i++)
  174. if (!m_arrayIniLines[i].IsEmpty())
  175. {
  176. CSize size = dc.GetTextExtent(m_arrayIniLines[i]);
  177. dwExtent = size.cx + tm.tmAveCharWidth;
  178. if (dwExtent > dwMaxExtent)
  179. dwMaxExtent = dwExtent;
  180. }
  181. dc.Detach();
  182. ::SelectObject(hDCListBox, hFontOld);
  183. ::ReleaseDC(GetDlgItemHWND(IDC_LISTBOOTINI), hDCListBox);
  184. // Set the extent for the list box.
  185. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETHORIZONTALEXTENT, (WPARAM)dwMaxExtent, 0);
  186. // First, add the lines from the boot ini into the list control.
  187. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_RESETCONTENT, 0, 0);
  188. for (int j = 0; j <= m_arrayIniLines.GetUpperBound(); j++)
  189. if (!m_arrayIniLines[j].IsEmpty())
  190. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)m_arrayIniLines[j]);
  191. // Set the timeout value based on the boot.ini.
  192. if (m_nTimeoutIndex != -1 && fSyncEditField)
  193. {
  194. CString strTimeout = m_arrayIniLines[m_nTimeoutIndex];
  195. strTimeout.TrimLeft(_T("timeout= "));
  196. m_fIgnoreEdit = TRUE;
  197. SetDlgItemText(IDC_EDITTIMEOUT, strTimeout);
  198. m_fIgnoreEdit = FALSE;
  199. }
  200. }
  201. //----------------------------------------------------------------------------
  202. // Update the controls based on the user's selection of a line.
  203. //----------------------------------------------------------------------------
  204. void CPageBootIni::SelectLine(int index)
  205. {
  206. if (index < m_nMinOSIndex)
  207. {
  208. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, m_nMinOSIndex, 0);
  209. SelectLine(m_nMinOSIndex);
  210. return;
  211. }
  212. if (index > m_nMaxOSIndex)
  213. {
  214. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, m_nMaxOSIndex, 0);
  215. SelectLine(m_nMaxOSIndex);
  216. return;
  217. }
  218. HWND hwndFocus = ::GetFocus();
  219. ::EnableWindow(GetDlgItemHWND(IDC_BOOTMOVEUP), (index > m_nMinOSIndex));
  220. ::EnableWindow(GetDlgItemHWND(IDC_BOOTMOVEDOWN), (index < m_nMaxOSIndex));
  221. if ((index <= m_nMinOSIndex) && hwndFocus == GetDlgItemHWND(IDC_BOOTMOVEUP))
  222. NextDlgCtrl();
  223. if ((index >= m_nMaxOSIndex) && hwndFocus == GetDlgItemHWND(IDC_BOOTMOVEDOWN))
  224. PrevDlgCtrl();
  225. CString strOS = m_arrayIniLines[index];
  226. strOS.MakeLower();
  227. CheckDlgButton(IDC_SAFEBOOT, (strOS.Find(_T("/safeboot")) != -1));
  228. CheckDlgButton(IDC_NOGUIBOOT, (strOS.Find(_T("/noguiboot")) != -1));
  229. CheckDlgButton(IDC_BOOTLOG, (strOS.Find(_T("/bootlog")) != -1));
  230. CheckDlgButton(IDC_BASEVIDEO, (strOS.Find(_T("/basevideo")) != -1));
  231. CheckDlgButton(IDC_SOS, (strOS.Find(_T("/sos")) != -1));
  232. // If the line selected isn't for Whistler, then disable the controls.
  233. // If the line is for Whistler or W2K, but it has the string "CMDCONS" in
  234. // it, we shouldn't enable the controls.
  235. BOOL fEnableControls = ((strOS.Find(_T("whistler")) != -1) || (strOS.Find(_T("windows 2000")) != -1));
  236. fEnableControls |= ((strOS.Find(_T("windowsxp")) != -1) || (strOS.Find(_T("windows xp")) != -1));
  237. fEnableControls |= (strOS.Find(_T("windows server 2003")) != -1);
  238. fEnableControls = fEnableControls && (strOS.Find(_T("cmdcons")) == -1);
  239. ::EnableWindow(GetDlgItemHWND(IDC_SAFEBOOT), fEnableControls);
  240. ::EnableWindow(GetDlgItemHWND(IDC_NOGUIBOOT), fEnableControls);
  241. ::EnableWindow(GetDlgItemHWND(IDC_BOOTLOG), fEnableControls);
  242. ::EnableWindow(GetDlgItemHWND(IDC_BASEVIDEO), fEnableControls);
  243. ::EnableWindow(GetDlgItemHWND(IDC_SOS), fEnableControls);
  244. ::EnableWindow(GetDlgItemHWND(IDC_BOOTADVANCED), fEnableControls);
  245. BOOL fSafeboot = (strOS.Find(_T("/safeboot")) != -1);
  246. ::EnableWindow(GetDlgItemHWND(IDC_SBNETWORK), fSafeboot && fEnableControls);
  247. ::EnableWindow(GetDlgItemHWND(IDC_SBDSREPAIR), fSafeboot && fEnableControls);
  248. ::EnableWindow(GetDlgItemHWND(IDC_SBMINIMAL), fSafeboot && fEnableControls);
  249. ::EnableWindow(GetDlgItemHWND(IDC_SBMINIMALALT), fSafeboot && fEnableControls);
  250. if (fSafeboot)
  251. {
  252. CheckDlgButton(IDC_SBNETWORK, (strOS.Find(_T("/safeboot:network")) != -1));
  253. CheckDlgButton(IDC_SBDSREPAIR, (strOS.Find(_T("/safeboot:dsrepair")) != -1));
  254. if (strOS.Find(_T("/safeboot:minimal")) != -1)
  255. {
  256. BOOL fAlternateShell = (strOS.Find(_T("/safeboot:minimal(alternateshell)")) != -1);
  257. CheckDlgButton(IDC_SBMINIMAL, !fAlternateShell);
  258. CheckDlgButton(IDC_SBMINIMALALT, fAlternateShell);
  259. }
  260. else
  261. {
  262. CheckDlgButton(IDC_SBMINIMAL, FALSE);
  263. CheckDlgButton(IDC_SBMINIMALALT, FALSE);
  264. }
  265. int iSafeboot = strOS.Find(_T("/safeboot"));
  266. if (iSafeboot != -1)
  267. {
  268. m_strSafeBoot = strOS.Mid(iSafeboot + 1);
  269. m_strSafeBoot = m_strSafeBoot.SpanExcluding(_T(" /"));
  270. m_strSafeBoot = CString(_T("/")) + m_strSafeBoot;
  271. }
  272. }
  273. // Check to see if the selected operating system is the default.
  274. // Then enable the button accordingly.
  275. BOOL fEnableDefault = FALSE;
  276. if (m_nDefaultIndex >= 0)
  277. {
  278. CString strDefault = m_arrayIniLines[m_nDefaultIndex];
  279. int iEquals = strDefault.Find(_T('='));
  280. if (iEquals != -1)
  281. {
  282. strDefault = strDefault.Mid(iEquals + 1);
  283. strDefault.MakeLower();
  284. CString strCurrent = strOS.SpanExcluding(_T("="));
  285. strDefault.TrimLeft();
  286. strCurrent.TrimRight();
  287. if (strDefault != strCurrent || index > m_nMinOSIndex)
  288. fEnableDefault = TRUE;
  289. }
  290. }
  291. ::EnableWindow(GetDlgItemHWND(IDC_SETASDEFAULT), fEnableDefault);
  292. if (!fEnableDefault && hwndFocus == GetDlgItemHWND(IDC_SETASDEFAULT))
  293. NextDlgCtrl();
  294. }
  295. //-------------------------------------------------------------------------
  296. // Add or remove the specified flag from the currently selected OS line.
  297. //-------------------------------------------------------------------------
  298. void CPageBootIni::ChangeCurrentOSFlag(BOOL fAdd, LPCTSTR szFlag)
  299. {
  300. int iSelection = (int)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_GETCURSEL, 0, 0);
  301. CString strFlagPlusSpace = CString(_T(" ")) + szFlag;
  302. CString strNewLine;
  303. if (iSelection == -1)
  304. return;
  305. if (fAdd)
  306. {
  307. if (m_arrayIniLines[iSelection].Find(szFlag) != -1)
  308. {
  309. ASSERT(0 && "the flag is already there");
  310. return;
  311. }
  312. strNewLine = m_arrayIniLines[iSelection] + strFlagPlusSpace;
  313. }
  314. else
  315. {
  316. int iIndex = m_arrayIniLines[iSelection].Find(strFlagPlusSpace);
  317. if (iIndex == -1)
  318. {
  319. ASSERT(0 && "there is no flag");
  320. return;
  321. }
  322. strNewLine = m_arrayIniLines[iSelection].Left(iIndex);
  323. strNewLine += m_arrayIniLines[iSelection].Mid(iIndex + strFlagPlusSpace.GetLength());
  324. }
  325. m_arrayIniLines.SetAt(iSelection, strNewLine);
  326. UserMadeChange();
  327. SyncControlsToIni();
  328. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, iSelection, 0);
  329. }
  330. //-------------------------------------------------------------------------
  331. // Sets the "default=" line in the boot.ini.
  332. //-------------------------------------------------------------------------
  333. void CPageBootIni::SetDefaultOS(int iIndex)
  334. {
  335. if (m_nDefaultIndex == -1)
  336. return;
  337. // Get the current string "default=xxxx". Locate the location of the
  338. // '=' so we can replace the later half of the line.
  339. CString strDefault = m_arrayIniLines[m_nDefaultIndex];
  340. int iEquals = strDefault.Find(_T('='));
  341. if (iEquals == -1)
  342. return;
  343. CString strValue = m_arrayIniLines[iIndex].SpanExcluding(_T("="));
  344. strValue.TrimRight();
  345. CString strNewDefault = strDefault.Left(iEquals + 1) + strValue;
  346. m_arrayIniLines.SetAt(m_nDefaultIndex, strNewDefault);
  347. }
  348. //-------------------------------------------------------------------------
  349. // Write new contents to the BOOT.INI file.
  350. //-------------------------------------------------------------------------
  351. BOOL CPageBootIni::SetBootIniContents(const CString & strNewContents, const CString & strAddedExtension)
  352. {
  353. // Extra safety code.
  354. if ((LPCTSTR)strNewContents == NULL || *((LPCTSTR)strNewContents) == _T('\0'))
  355. return FALSE;
  356. // To write to the BOOT.INI file, we need to set it to have normal
  357. // attributes. Save the attribute settings so we can restore them.
  358. DWORD dwWritten, dwAttribs = ::GetFileAttributes(m_strFileName);
  359. ::SetFileAttributes(m_strFileName, FILE_ATTRIBUTE_NORMAL);
  360. HANDLE h = ::CreateFile(m_strFileName, GENERIC_WRITE, 0, NULL, TRUNCATE_EXISTING, 0, NULL);
  361. if (INVALID_HANDLE_VALUE == h)
  362. {
  363. ::SetFileAttributes(m_strFileName, dwAttribs);
  364. return FALSE;
  365. }
  366. // Convert the internal BOOT.INI representation (Unicode) to ANSI for writing.
  367. USES_CONVERSION;
  368. LPSTR szBuffer = T2A((LPTSTR)(LPCTSTR)strNewContents);
  369. // CreateFile with TRUNCATE_EXISTING seems to SOMETIMES not set the file length to
  370. // zero, but to overwrite the existing file with zeroes and leave the pointer at
  371. // the end of the file.
  372. ::SetFilePointer(h, 0, NULL, FILE_BEGIN);
  373. ::WriteFile(h, (void *)szBuffer, strNewContents.GetLength(), &dwWritten, NULL);
  374. ::SetEndOfFile(h);
  375. ::CloseHandle(h);
  376. ::SetFileAttributes(m_strFileName, dwAttribs);
  377. return TRUE;
  378. }
  379. //-------------------------------------------------------------------------
  380. // We need to subclass the edit control to catch the enter key, so we
  381. // can validate the data and not close MSConfig.
  382. //-------------------------------------------------------------------------
  383. CPageBootIni * pBootIniPage = NULL; // pointer to the page, so we can call member functions
  384. WNDPROC pOldBootIniEditProc = NULL; // save old wndproc when we subclass edit control
  385. LRESULT BootIniEditSubclassProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
  386. {
  387. switch (wm)
  388. {
  389. case WM_GETDLGCODE:
  390. return DLGC_WANTALLKEYS;
  391. case WM_CHAR:
  392. if (wp == VK_ESCAPE || wp == VK_RETURN)
  393. {
  394. if (pBootIniPage != NULL)
  395. {
  396. pBootIniPage->NextDlgCtrl();
  397. return 0;
  398. }
  399. }
  400. else if (wp == VK_TAB)
  401. {
  402. if (pBootIniPage != NULL)
  403. {
  404. if (::GetAsyncKeyState(VK_SHIFT) == 0)
  405. pBootIniPage->NextDlgCtrl();
  406. else
  407. pBootIniPage->PrevDlgCtrl();
  408. return 0;
  409. }
  410. }
  411. break;
  412. }
  413. if (pOldBootIniEditProc != NULL) // better not be null
  414. return CallWindowProc(pOldBootIniEditProc, hwnd, wm, wp, lp);
  415. return 0;
  416. }
  417. //-------------------------------------------------------------------------
  418. // Initialize the boot.ini page. Read in the INI file, set up internal
  419. // structures to represent the file, and update the controls to reflect
  420. // the internal structures.
  421. //-------------------------------------------------------------------------
  422. extern BOOL fBasicControls;
  423. BOOL CPageBootIni::OnInitDialog()
  424. {
  425. CPropertyPage::OnInitDialog();
  426. // Check the registry for a testing flag (which would mean we aren't
  427. // operating on the real BOOT.INI file). Removed for release.
  428. //
  429. // CRegKey regkey;
  430. // if (ERROR_SUCCESS == regkey.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSConfig")))
  431. // {
  432. // TCHAR szBoot[MAX_PATH];
  433. // DWORD dwCount = MAX_PATH;
  434. //
  435. // if (ERROR_SUCCESS == regkey.QueryValue(szBoot, _T("boot.ini"), &dwCount))
  436. // m_strFileName = szBoot;
  437. // }
  438. InitializePage();
  439. if (fBasicControls)
  440. ::ShowWindow(GetDlgItemHWND(IDC_BOOTADVANCED), SW_HIDE);
  441. // Subclass the edit control (to catch the enter key).
  442. HWND hWndEdit = GetDlgItemHWND(IDC_EDITTIMEOUT);
  443. if (hWndEdit)
  444. {
  445. pOldBootIniEditProc = (WNDPROC)::GetWindowLongPtr(hWndEdit, GWLP_WNDPROC);
  446. pBootIniPage = this;
  447. ::SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (ULONG_PTR)(WNDPROC)&BootIniEditSubclassProc);
  448. }
  449. m_fInitialized = TRUE;
  450. return TRUE; // return TRUE unless you set the focus to a control
  451. }
  452. //-------------------------------------------------------------------------
  453. // Called when the user clicks move up or down.
  454. //-------------------------------------------------------------------------
  455. void CPageBootIni::OnBootMoveDown()
  456. {
  457. int iSelection = (int)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_GETCURSEL, 0, 0);
  458. ASSERT(iSelection >= m_nMinOSIndex && iSelection < m_nMaxOSIndex);
  459. if (iSelection >= m_nMinOSIndex && iSelection < m_nMaxOSIndex)
  460. {
  461. CString strTemp = m_arrayIniLines[iSelection + 1];
  462. m_arrayIniLines.SetAt(iSelection + 1, m_arrayIniLines[iSelection]);
  463. m_arrayIniLines.SetAt(iSelection, strTemp);
  464. UserMadeChange();
  465. SyncControlsToIni();
  466. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, iSelection + 1, 0);
  467. SelectLine(iSelection + 1);
  468. }
  469. }
  470. void CPageBootIni::OnBootMoveUp()
  471. {
  472. int iSelection = (int)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_GETCURSEL, 0, 0);
  473. ASSERT(iSelection > m_nMinOSIndex && iSelection <= m_nMaxOSIndex);
  474. if (iSelection > m_nMinOSIndex && iSelection <= m_nMaxOSIndex)
  475. {
  476. CString strTemp = m_arrayIniLines[iSelection - 1];
  477. m_arrayIniLines.SetAt(iSelection - 1, m_arrayIniLines[iSelection]);
  478. m_arrayIniLines.SetAt(iSelection, strTemp);
  479. UserMadeChange();
  480. SyncControlsToIni();
  481. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, iSelection - 1, 0);
  482. SelectLine(iSelection - 1);
  483. }
  484. }
  485. //-------------------------------------------------------------------------
  486. // Called when the user clicks on a line in the list view.
  487. //-------------------------------------------------------------------------
  488. void CPageBootIni::OnSelChangeList()
  489. {
  490. SelectLine((int)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_GETCURSEL, 0, 0));
  491. }
  492. //-------------------------------------------------------------------------
  493. // The check boxes are handled uniformly - adding or removing a flag from
  494. // the currently selected OS line.
  495. //-------------------------------------------------------------------------
  496. void CPageBootIni::OnClickedBase()
  497. {
  498. ChangeCurrentOSFlag(IsDlgButtonChecked(IDC_BASEVIDEO), _T("/basevideo"));
  499. }
  500. void CPageBootIni::OnClickedBootLog()
  501. {
  502. ChangeCurrentOSFlag(IsDlgButtonChecked(IDC_BOOTLOG), _T("/bootlog"));
  503. }
  504. void CPageBootIni::OnClickedNoGUIBoot()
  505. {
  506. ChangeCurrentOSFlag(IsDlgButtonChecked(IDC_NOGUIBOOT), _T("/noguiboot"));
  507. }
  508. void CPageBootIni::OnClickedSOS()
  509. {
  510. ChangeCurrentOSFlag(IsDlgButtonChecked(IDC_SOS), _T("/sos"));
  511. }
  512. //-------------------------------------------------------------------------
  513. // The safeboot flag is a little more complicated, since it has an extra
  514. // portion (from the radio buttons).
  515. //-------------------------------------------------------------------------
  516. void CPageBootIni::OnClickedSafeBoot()
  517. {
  518. CString strFlag(_T("/safeboot"));
  519. if (IsDlgButtonChecked(IDC_SBNETWORK))
  520. strFlag += _T(":network");
  521. else if (IsDlgButtonChecked(IDC_SBDSREPAIR))
  522. strFlag += _T(":dsrepair");
  523. else if (IsDlgButtonChecked(IDC_SBMINIMALALT))
  524. strFlag += _T(":minimal(alternateshell)");
  525. else
  526. {
  527. strFlag += _T(":minimal");
  528. CheckDlgButton(IDC_SBMINIMAL, 1);
  529. }
  530. BOOL fSafeBoot = IsDlgButtonChecked(IDC_SAFEBOOT);
  531. ChangeCurrentOSFlag(fSafeBoot, strFlag);
  532. m_strSafeBoot = strFlag;
  533. ::EnableWindow(GetDlgItemHWND(IDC_SBNETWORK), fSafeBoot);
  534. ::EnableWindow(GetDlgItemHWND(IDC_SBDSREPAIR), fSafeBoot);
  535. ::EnableWindow(GetDlgItemHWND(IDC_SBMINIMAL), fSafeBoot);
  536. ::EnableWindow(GetDlgItemHWND(IDC_SBMINIMALALT), fSafeBoot);
  537. }
  538. //-------------------------------------------------------------------------
  539. // Clicking on one of the safeboot radio buttons requires a little extra
  540. // processing, to remove the existing flag and add the new one.
  541. //-------------------------------------------------------------------------
  542. void CPageBootIni::OnClickedSBDSRepair()
  543. {
  544. ChangeCurrentOSFlag(FALSE, m_strSafeBoot);
  545. m_strSafeBoot = _T("/safeboot:dsrepair");
  546. ChangeCurrentOSFlag(TRUE, m_strSafeBoot);
  547. }
  548. void CPageBootIni::OnClickedSBMinimal()
  549. {
  550. ChangeCurrentOSFlag(FALSE, m_strSafeBoot);
  551. m_strSafeBoot = _T("/safeboot:minimal");
  552. ChangeCurrentOSFlag(TRUE, m_strSafeBoot);
  553. }
  554. void CPageBootIni::OnClickedSBMinimalAlt()
  555. {
  556. ChangeCurrentOSFlag(FALSE, m_strSafeBoot);
  557. m_strSafeBoot = _T("/safeboot:minimal(alternateshell)");
  558. ChangeCurrentOSFlag(TRUE, m_strSafeBoot);
  559. }
  560. void CPageBootIni::OnClickedSBNetwork()
  561. {
  562. ChangeCurrentOSFlag(FALSE, m_strSafeBoot);
  563. m_strSafeBoot = _T("/safeboot:network");
  564. ChangeCurrentOSFlag(TRUE, m_strSafeBoot);
  565. }
  566. //-------------------------------------------------------------------------
  567. // As the user enters text in the timeout field, update the line in the
  568. // ini file list box.
  569. //-------------------------------------------------------------------------
  570. void CPageBootIni::OnChangeEditTimeOut()
  571. {
  572. if (m_fIgnoreEdit)
  573. return;
  574. if (m_nTimeoutIndex == -1)
  575. return;
  576. CString strTimeout = m_arrayIniLines[m_nTimeoutIndex];
  577. int iEquals = strTimeout.Find(_T('='));
  578. if (iEquals == -1)
  579. return;
  580. while (strTimeout[iEquals + 1] == _T(' ') && (iEquals + 1) < strTimeout.GetLength())
  581. iEquals++;
  582. TCHAR szValue[MAX_PATH];
  583. GetDlgItemText(IDC_EDITTIMEOUT, szValue, MAX_PATH);
  584. CString strNewTimeout = strTimeout.Left(iEquals + 1) + szValue;
  585. m_arrayIniLines.SetAt(m_nTimeoutIndex, strNewTimeout);
  586. UserMadeChange();
  587. int iSelection = (int)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_GETCURSEL, 0, 0);
  588. SyncControlsToIni(FALSE);
  589. if (iSelection != -1)
  590. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, iSelection, 0);
  591. }
  592. void CPageBootIni::OnKillFocusEditTimeOut()
  593. {
  594. TCHAR szValue[MAX_PATH];
  595. GetDlgItemText(IDC_EDITTIMEOUT, szValue, MAX_PATH);
  596. CString strNewValue(_T(""));
  597. BOOL fGiveUpFocus = FALSE;
  598. int iTimeout = _ttoi(szValue);
  599. if (iTimeout < 3 || iTimeout > 999)
  600. {
  601. CString strMessage, strCaption;
  602. strMessage.LoadString(IDS_TIMEOUTVALUE);
  603. strCaption.LoadString(IDS_APPCAPTION);
  604. MessageBox(strMessage, strCaption);
  605. if (iTimeout < 3)
  606. strNewValue = _T("3");
  607. else if (iTimeout > 999)
  608. strNewValue = _T("999");
  609. }
  610. else if (szValue[0] == _T('0'))
  611. {
  612. // Remove leading zeros.
  613. strNewValue.Format(_T("%d"), iTimeout);
  614. fGiveUpFocus = TRUE;
  615. }
  616. if (!strNewValue.IsEmpty() && m_nTimeoutIndex != -1)
  617. {
  618. CString strTimeout = m_arrayIniLines[m_nTimeoutIndex];
  619. int iEquals = strTimeout.Find(_T('='));
  620. if (iEquals != -1)
  621. {
  622. while (strTimeout[iEquals + 1] == _T(' ') && (iEquals + 1) < strTimeout.GetLength())
  623. iEquals++;
  624. CString strNewTimeout = strTimeout.Left(iEquals + 1) + strNewValue;
  625. m_arrayIniLines.SetAt(m_nTimeoutIndex, strNewTimeout);
  626. UserMadeChange();
  627. }
  628. SetDlgItemText(IDC_EDITTIMEOUT, strNewValue);
  629. ::SendMessage(GetDlgItemHWND(IDC_EDITTIMEOUT), EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  630. if (!fGiveUpFocus)
  631. GotoDlgCtrl(GetDlgItem(IDC_EDITTIMEOUT));
  632. }
  633. }
  634. //-------------------------------------------------------------------------
  635. // Show the advanced options dialog box.
  636. //-------------------------------------------------------------------------
  637. void CPageBootIni::OnClickedBootAdvanced()
  638. {
  639. int iSelection = (int)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_GETCURSEL, 0, 0);
  640. if (iSelection > 0)
  641. {
  642. CString strLine(m_arrayIniLines[iSelection]);
  643. CBootIniAdvancedDlg dlg;
  644. if (dlg.ShowAdvancedOptions(strLine))
  645. {
  646. m_arrayIniLines.SetAt(iSelection, strLine);
  647. UserMadeChange();
  648. SyncControlsToIni();
  649. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, iSelection, 0);
  650. }
  651. }
  652. }
  653. //-------------------------------------------------------------------------
  654. // If the user clicks "Set as Default", use the path information from the
  655. // currently selected line to set the new "default=" line.
  656. //-------------------------------------------------------------------------
  657. void CPageBootIni::OnClickedSetAsDefault()
  658. {
  659. if (m_fIgnoreEdit)
  660. return;
  661. // Move the currently selected line to the top of the [operating systems]
  662. // section.
  663. int iSelection = (int)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_GETCURSEL, 0, 0);
  664. if (iSelection < m_nMinOSIndex || iSelection > m_nMaxOSIndex)
  665. return;
  666. while (iSelection > m_nMinOSIndex)
  667. {
  668. CString strTemp = m_arrayIniLines[iSelection - 1];
  669. m_arrayIniLines.SetAt(iSelection - 1, m_arrayIniLines[iSelection]);
  670. m_arrayIniLines.SetAt(iSelection, strTemp);
  671. iSelection -= 1;
  672. }
  673. // Get the string from the selected line. Strip off everything after the '='.
  674. SetDefaultOS(iSelection);
  675. UserMadeChange();
  676. SyncControlsToIni(FALSE);
  677. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, iSelection, 0);
  678. SelectLine(iSelection);
  679. }
  680. //-------------------------------------------------------------------------
  681. // This attempts to programmatically check if each of the boot paths is
  682. // valid. If an invalid path is found, the user is given the opportunity
  683. // to remove it from the boot.ini file.
  684. //-------------------------------------------------------------------------
  685. void CPageBootIni::OnClickedCheckBootPaths()
  686. {
  687. BOOL fFoundBadLine = FALSE;
  688. BOOL fChangedFile = FALSE;
  689. BOOL fWinNTType, fWin9xType;
  690. CString strCaption;
  691. strCaption.LoadString(IDS_APPCAPTION);
  692. struct { LPCTSTR m_szSearch; BOOL * m_pType; } aOSType[] =
  693. {
  694. { _T("windows xp"), &fWinNTType },
  695. { _T("windowsxp"), &fWinNTType },
  696. { _T("windows nt"), &fWinNTType },
  697. { _T("whistler"), &fWinNTType },
  698. { _T("windows 2000"), &fWinNTType },
  699. { _T("windows server 2003"), &fWinNTType },
  700. { _T("microsoft windows"), &fWin9xType },
  701. { NULL, NULL }
  702. };
  703. // Scan through each of the operating system lines in the boot.ini file.
  704. for (int i = m_nMinOSIndex; i <= m_nMaxOSIndex; i++)
  705. {
  706. CString strLine = m_arrayIniLines[i];
  707. strLine.MakeLower();
  708. // Try to figure out the type of the operating system line.
  709. fWinNTType = FALSE;
  710. fWin9xType = FALSE;
  711. for (int iType = 0; aOSType[iType].m_szSearch != NULL; iType++)
  712. if (strLine.Find(aOSType[iType].m_szSearch) != -1)
  713. {
  714. (*aOSType[iType].m_pType) = TRUE;
  715. break;
  716. }
  717. // Strip off the '=' and everything after it in the boot line.
  718. int iEquals = strLine.Find(_T('='));
  719. if (iEquals == -1)
  720. continue;
  721. strLine = strLine.Left(iEquals);
  722. strLine.TrimRight();
  723. if (strLine.IsEmpty())
  724. continue;
  725. // Depending on the type of the OS, we need to verify that it's
  726. // installed differently.
  727. if (fWin9xType)
  728. {
  729. // Look for the bootsect.dos file to see if this is a good drive.
  730. CString strCheck(strLine);
  731. if (strCheck.Right(1) != CString(_T("\\")))
  732. strCheck += CString(_T("\\"));
  733. strCheck += CString(_T("bootsect.dos"));
  734. if (FileExists(strCheck))
  735. continue;
  736. }
  737. else if (fWinNTType)
  738. {
  739. // If this line is for a recovery console (i.e. the line as "bootsect.dat"
  740. // in it), then look for the existence of that file.
  741. if (strLine.Find(_T("bootsect.dat")) != -1)
  742. {
  743. if (FileExists(strLine))
  744. continue;
  745. }
  746. else
  747. {
  748. // Look for the SYSTEM registry hive.
  749. CString strCheck(strLine);
  750. if (strCheck.Right(1) != CString(_T("\\")))
  751. strCheck += CString(_T("\\"));
  752. strCheck += CString(_T("system32\\config\\SYSTEM"));
  753. // Add the prefix to attempt to open an ARC path.
  754. strCheck = CString(_T("\\\\?\\GLOBALROOT\\ArcName\\")) + strCheck;
  755. if (FileExists(strCheck))
  756. continue;
  757. }
  758. }
  759. else // this is not an OS type we can check
  760. continue;
  761. // If execution falls through to here, then the line in question was an OS
  762. // we care about, and it looks like it's invalid. Give the user the opportunity
  763. // to remove it from the BOOT.INI file.
  764. CString strMessage;
  765. strMessage.Format(IDS_BADBOOTLINE, m_arrayIniLines[i]);
  766. if (IDYES == MessageBox(strMessage, strCaption, MB_YESNO | MB_ICONQUESTION))
  767. {
  768. m_arrayIniLines.RemoveAt(i);
  769. m_nMaxOSIndex -= 1;
  770. // Check to see if the line we just removed is the default
  771. // operating system.
  772. CString strDefault = m_arrayIniLines[m_nDefaultIndex];
  773. iEquals = strDefault.Find(_T('='));
  774. if (iEquals != -1)
  775. {
  776. strDefault = strDefault.Mid(iEquals + 1);
  777. strDefault.TrimLeft();
  778. if (strDefault.CompareNoCase(strLine) == 0)
  779. SetDefaultOS(m_nMinOSIndex);
  780. }
  781. i -= 1; // so we look at the next line when the for loop increments i
  782. fChangedFile = TRUE;
  783. }
  784. fFoundBadLine = TRUE;
  785. }
  786. if (!fFoundBadLine)
  787. Message(IDS_NOBADBOOTLINES);
  788. else if (fChangedFile)
  789. {
  790. UserMadeChange();
  791. SyncControlsToIni();
  792. if (m_nMinOSIndex != -1)
  793. {
  794. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, m_nMinOSIndex, 0);
  795. SelectLine(m_nMinOSIndex);
  796. }
  797. }
  798. }
  799. //-------------------------------------------------------------------------
  800. // Return the current state of the tab.
  801. //-------------------------------------------------------------------------
  802. CPageBase::TabState CPageBootIni::GetCurrentTabState()
  803. {
  804. if (!m_fInitialized)
  805. return GetAppliedTabState();
  806. return m_stateCurrent;
  807. }
  808. //-------------------------------------------------------------------------
  809. // Applying the changes for the boot.ini tab means writing out the new
  810. // file contents.
  811. //
  812. // The base class implementation is called to maintain the applied
  813. // tab state.
  814. //-------------------------------------------------------------------------
  815. BOOL CPageBootIni::OnApply()
  816. {
  817. if (!m_fModified)
  818. return TRUE;
  819. // Build up the new contents of the boot.ini file from the
  820. // list. If there is no backup of the boot.ini file, make
  821. // one (so the original can be restored). Then write the
  822. // contents out to the file.
  823. CString strNewContents;
  824. for (int i = 0; i <= m_arrayIniLines.GetUpperBound(); i++)
  825. if (!m_arrayIniLines[i].IsEmpty())
  826. {
  827. if (m_nTimeoutIndex == i)
  828. {
  829. CString strTimeoutValue(m_arrayIniLines[i]);
  830. strTimeoutValue.TrimLeft(_T("TIMEOUTtimeout ="));
  831. int iTimeout = _ttoi(strTimeoutValue);
  832. if (iTimeout < 3 || iTimeout > 999)
  833. {
  834. if (iTimeout < 3)
  835. strTimeoutValue = _T("3");
  836. else if (iTimeout > 999)
  837. strTimeoutValue = _T("999");
  838. int iEquals = m_arrayIniLines[i].Find(_T('='));
  839. if (iEquals != -1)
  840. {
  841. CString strNewTimeout = m_arrayIniLines[i].Left(iEquals + 1) + strTimeoutValue;
  842. m_arrayIniLines.SetAt(i, strNewTimeout);
  843. }
  844. }
  845. }
  846. strNewContents += m_arrayIniLines[i] + _T("\r\n");
  847. }
  848. // If we are currently in a "NORMAL" state, then we want to make a new
  849. // backup file (overwriting an existing one, if necessary). Otherwise,
  850. // only make a backup if there isn't already one. This preserves a good
  851. // backup when the user is making incremental changes.
  852. HRESULT hr = BackupFile(m_strFileName, _T(".backup"), (GetAppliedTabState() == NORMAL));
  853. if (FAILED(hr))
  854. return FALSE;
  855. SetBootIniContents(strNewContents);
  856. CPageBase::SetAppliedState(GetCurrentTabState());
  857. m_fMadeChange = TRUE;
  858. return TRUE;
  859. }
  860. //-------------------------------------------------------------------------
  861. // Committing the changes means applying changes, then saving the current
  862. // values to the registry with the commit flag. Refill the list.
  863. //
  864. // Then call the base class implementation.
  865. //-------------------------------------------------------------------------
  866. void CPageBootIni::CommitChanges()
  867. {
  868. OnApply();
  869. m_stateCurrent = NORMAL;
  870. ::DeleteFile(GetBackupName(m_strFileName, _T(".backup")));
  871. CPageBase::CommitChanges();
  872. }
  873. //-------------------------------------------------------------------------
  874. // Set the overall state of the tab to normal or diagnostic.
  875. //-------------------------------------------------------------------------
  876. void CPageBootIni::SetNormal()
  877. {
  878. // Setting the BOOT.INI tab state to normal means that the original
  879. // BOOT.INI file contents should be restored to the UI (not actually
  880. // saved until the changes are applied). If a BOOT.INI backup file
  881. // exists, we should reload the contents of it. If it doesn't exists,
  882. // reload the contents of the real BOOT.INI.
  883. //
  884. // Note - if the state is already NORMAL, don't do anything.
  885. if (m_stateCurrent == NORMAL)
  886. return;
  887. CString strBackup = GetBackupName(m_strFileName, _T(".backup"));
  888. if (FileExists(strBackup))
  889. LoadBootIni(strBackup);
  890. else
  891. LoadBootIni();
  892. int iSelection = (int)::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_GETCURSEL, 0, 0);
  893. SyncControlsToIni();
  894. if (iSelection > 0)
  895. {
  896. SelectLine(iSelection);
  897. ::SendMessage(GetDlgItemHWND(IDC_LISTBOOTINI), LB_SETCURSEL, iSelection, 0);
  898. }
  899. UserMadeChange();
  900. m_stateCurrent = NORMAL;
  901. }
  902. void CPageBootIni::SetDiagnostic()
  903. {
  904. // Don't do anything.
  905. }
  906. void CPageBootIni::OnDestroy()
  907. {
  908. // Undo the subclass
  909. pBootIniPage = NULL;
  910. HWND hWndEdit = GetDlgItemHWND(IDC_EDITTIMEOUT);
  911. if (pOldBootIniEditProc != NULL && hWndEdit)
  912. ::SetWindowLongPtr(hWndEdit, GWLP_WNDPROC, (ULONG_PTR)(WNDPROC)pOldBootIniEditProc);
  913. CPropertyPage::OnDestroy();
  914. }