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.

1220 lines
30 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1999 Microsoft Corporation
  4. // All rights reserved.
  5. //
  6. // File Name:
  7. // makebt32.c
  8. //
  9. // Description:
  10. // This program copies the images of the 4 Windows NT setup disks to
  11. // floppy disk so the user can boot their system with them.
  12. //
  13. // All characters and strings are wide (UNICODE). This file needs to be
  14. // compiled with UNICODE and _UNICODE defined.
  15. //
  16. // Assumptions:
  17. // This program will only run on NT 3.51 or later. This is a result of
  18. // the CreateFile function call. It is not available on DOS, Windows 3.1
  19. // or Windows 9x.
  20. //
  21. // The floppy disk images are in the current dir and named CDBOOT1.IMG,
  22. // CDBOOT2.IMG, CDBOOT3.IMG and CDBOOT4.IMG.
  23. //
  24. // Please note that there are a lot of places where I call exit() without
  25. // freeing memory for strings I have allocated. This version of the
  26. // program only runs on NT so when the process exits it frees all its
  27. // memory so it is not a concern that I may not call free() on some memory.
  28. //
  29. //----------------------------------------------------------------------------
  30. #include <windows.h>
  31. #include <setupapi.h>
  32. #include <winioctl.h>
  33. #include <conio.h>
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include "resource.h"
  37. //
  38. // Constants
  39. //
  40. #define MAKEBOOT_MAX_STRING_LEN 1024
  41. #define BYTES_PER_SECTOR 512
  42. #define SECTORS_PER_TRACK 18
  43. #define TRACK_SIZE SECTORS_PER_TRACK * BYTES_PER_SECTOR
  44. #define TRACKS_ON_DISK 80 * 2 // * 2 because it is double-sided
  45. #define MAX_DISK_LABEL_LENGTH 256
  46. #define MAX_INILINE_LENGTH 1023
  47. #define ENTER_KEY 13
  48. #define ESC_KEY 27
  49. #define NT_IMAGE_1_NAME L"CDBOOT1.IMG"
  50. #define NT_IMAGE_2_NAME L"CDBOOT2.IMG"
  51. #define NT_IMAGE_3_NAME L"CDBOOT3.IMG"
  52. #define NT_IMAGE_4_NAME L"CDBOOT4.IMG"
  53. #define NT_IMAGE_5_NAME L"CDBOOT5.IMG"
  54. #define NT_IMAGE_6_NAME L"CDBOOT6.IMG"
  55. #define NUMBER_OF_ASCII_WHEEL_SYMBOLS 4
  56. const WCHAR rgAsciiWheel[NUMBER_OF_ASCII_WHEEL_SYMBOLS] = { '|', '/', '-', '\\' };
  57. //
  58. // Function prototypes
  59. //
  60. BOOL WriteImageToFloppy( WCHAR *szFileName, WCHAR *DrivePath );
  61. VOID PrintErrorMessage( VOID );
  62. VOID PrintErrorWrongDriveType( UINT iDriveType );
  63. BOOL IsDriveLargeEnough( WCHAR *DrivePath );
  64. VOID FreeStrings( VOID );
  65. VOID LoadStrings( VOID );
  66. INT DoImageFilesExist( VOID ) ;
  67. VOID CleanUp( HANDLE *hFloppyDrive, HANDLE *hFloppyImage );
  68. BOOL DoesUserWantToTryCopyAgain( VOID );
  69. LPWSTR MyLoadString( UINT StringId );
  70. VOID print( WCHAR *szFirstString, ... );
  71. BOOL DoesFileExist( LPWSTR lpFileName );
  72. VOID PressAnyKeyToContinue( VOID );
  73. void SetFarEastThread();
  74. void ConsolePrint( WCHAR *szFirstString, ... );
  75. //
  76. // Global Strings
  77. //
  78. WCHAR *StrOutOfMemory = NULL;
  79. WCHAR *StrComplete = NULL;
  80. WCHAR *StrNtVersionName = NULL;
  81. WCHAR *StrCanNotFindFile = NULL;
  82. WCHAR *StrDiskLabel1 = NULL;
  83. WCHAR *StrDiskLabel2 = NULL;
  84. WCHAR *StrDiskLabel3 = NULL;
  85. WCHAR *StrDiskLabel4 = NULL;
  86. WCHAR *StrDiskLabel5 = NULL;
  87. WCHAR *StrDiskLabel6 = NULL;
  88. WCHAR *StrStars = NULL;
  89. WCHAR *StrExplanationLine1 = NULL;
  90. WCHAR *StrExplanationLine2 = NULL;
  91. WCHAR *StrExplanationLine3 = NULL;
  92. WCHAR *StrExplanationLine4 = NULL;
  93. WCHAR *StrInsertFirstDiskLine1 = NULL;
  94. WCHAR *StrInsertFirstDiskLine2 = NULL;
  95. WCHAR *StrInsertAnotherDiskLine1 = NULL;
  96. WCHAR *StrInsertAnotherDiskLine2 = NULL;
  97. WCHAR *StrPressAnyKeyWhenReady = NULL;
  98. WCHAR *StrCompletedSuccessfully = NULL;
  99. //----------------------------------------------------------------------------
  100. //
  101. // Function: wmain
  102. //
  103. // Purpose: Instructs user to insert floppy disks to be copied and performs
  104. // the copy.
  105. //
  106. // Arguments: int argc - standard program argument, count of the command line args
  107. // char *argv[] - standard program argument, the 2nd argument is the
  108. // floppy drive to copy the images to.
  109. //
  110. // Returns: INT - zero on successful program completion
  111. // - non-zero on unsuccessful program completion, program
  112. // terminated because of an error
  113. //
  114. //----------------------------------------------------------------------------
  115. INT __cdecl
  116. wmain( INT argc, WCHAR *argv[] )
  117. {
  118. WCHAR *szOsName;
  119. WCHAR DriveLetter;
  120. WCHAR Drive[10];
  121. WCHAR DrivePath[10];
  122. UINT iDriveType;
  123. BOOL bTryAgain;
  124. szOsName = _wgetenv( L"OS" );
  125. //
  126. // Make sure we are on NT.
  127. //
  128. if( ( szOsName == NULL ) || ( _wcsicmp( szOsName, L"Windows_NT" ) != 0 ) )
  129. {
  130. // ******
  131. // This string cannot be localized because if we are not on NT then
  132. // we don't have wide chars.
  133. //
  134. printf( "This program only runs on Windows NT, Windows 2000 and Windows XP.\n" );
  135. exit( 1 );
  136. }
  137. SetFarEastThread();
  138. //
  139. // Load all of the strings from the resource file
  140. //
  141. LoadStrings();
  142. //
  143. // Don't allow the system to do any pop-ups. We will handle all
  144. // error messages
  145. //
  146. SetErrorMode( SEM_FAILCRITICALERRORS );
  147. print( L"" );
  148. print( StrStars );
  149. print( StrExplanationLine1 );
  150. print( StrExplanationLine2, StrNtVersionName );
  151. print( StrExplanationLine3 );
  152. print( StrExplanationLine4 );
  153. print( L"" );
  154. //
  155. // If they didn't specified the floppy drive on the command line then
  156. // prompt them for it.
  157. //
  158. if( argc == 1 )
  159. {
  160. WCHAR *StrSpecifyFloppyDrive = MyLoadString( IDS_SPECIFY_FLOPPY_DRIVE );
  161. ConsolePrint( L"%s", StrSpecifyFloppyDrive );
  162. DriveLetter = (WCHAR)_getche();
  163. ConsolePrint( L"\n\n" );
  164. free( StrSpecifyFloppyDrive );
  165. }
  166. else
  167. {
  168. DriveLetter = argv[1][0];
  169. }
  170. //
  171. // Make sure the character they entered is a possible drive letter
  172. //
  173. if( ! isalpha( DriveLetter ) )
  174. {
  175. WCHAR *StrInvalidDriveLetter = MyLoadString( IDS_INVALID_DRIVE_LETTER );
  176. ConsolePrint( L"%s\n", StrInvalidDriveLetter );
  177. free( StrInvalidDriveLetter );
  178. exit( 1 );
  179. }
  180. //
  181. // Make sure all the image files are in the current directory.
  182. //
  183. if( ! DoImageFilesExist() )
  184. {
  185. exit( 1 );
  186. }
  187. //
  188. // Make the char DriveLetter into a string
  189. //
  190. Drive[0] = DriveLetter;
  191. Drive[1] = L'\0';
  192. //
  193. // Build the drive path. For example the a: drive looks like \\.\a:
  194. //
  195. swprintf( DrivePath, L"\\\\.\\%c:", DriveLetter );
  196. //
  197. // Make sure the drive is a floppy drive
  198. //
  199. iDriveType = GetDriveType( wcscat( Drive, L":\\" ) );
  200. if( iDriveType != DRIVE_REMOVABLE )
  201. {
  202. PrintErrorWrongDriveType( iDriveType );
  203. exit( 1 );
  204. }
  205. //
  206. // Make sure the drive can hold at least 1.44 MB
  207. //
  208. if( ! IsDriveLargeEnough( DrivePath ) )
  209. {
  210. WCHAR *Str144NotSupported = MyLoadString( IDS_144_NOT_SUPPORTED );
  211. ConsolePrint( L"%s\n", Str144NotSupported );
  212. free( Str144NotSupported );
  213. exit( 1 );
  214. }
  215. print( StrInsertFirstDiskLine1, DriveLetter );
  216. print( StrInsertFirstDiskLine2, StrDiskLabel1 );
  217. PressAnyKeyToContinue();
  218. while( ! WriteImageToFloppy( NT_IMAGE_1_NAME, DrivePath ) )
  219. {
  220. bTryAgain = DoesUserWantToTryCopyAgain();
  221. if( ! bTryAgain )
  222. {
  223. exit( 1 );
  224. }
  225. }
  226. print( L"" );
  227. print( StrInsertAnotherDiskLine1, DriveLetter );
  228. print( StrInsertAnotherDiskLine2, StrDiskLabel2 );
  229. PressAnyKeyToContinue();
  230. while( ! WriteImageToFloppy( NT_IMAGE_2_NAME, DrivePath ) )
  231. {
  232. bTryAgain = DoesUserWantToTryCopyAgain();
  233. if( ! bTryAgain )
  234. {
  235. exit( 1 );
  236. }
  237. }
  238. print( L"" );
  239. print( StrInsertAnotherDiskLine1, DriveLetter );
  240. print( StrInsertAnotherDiskLine2, StrDiskLabel3 );
  241. PressAnyKeyToContinue();
  242. while( ! WriteImageToFloppy( NT_IMAGE_3_NAME, DrivePath ) )
  243. {
  244. bTryAgain = DoesUserWantToTryCopyAgain();
  245. if( ! bTryAgain )
  246. {
  247. exit( 1 );
  248. }
  249. }
  250. print( L"" );
  251. print( StrInsertAnotherDiskLine1, DriveLetter );
  252. print( StrInsertAnotherDiskLine2, StrDiskLabel4 );
  253. PressAnyKeyToContinue();
  254. while( ! WriteImageToFloppy( NT_IMAGE_4_NAME, DrivePath ) )
  255. {
  256. bTryAgain = DoesUserWantToTryCopyAgain();
  257. if( ! bTryAgain )
  258. {
  259. exit( 1 );
  260. }
  261. }
  262. print( L"" );
  263. print( StrInsertAnotherDiskLine1, DriveLetter );
  264. print( StrInsertAnotherDiskLine2, StrDiskLabel5 );
  265. PressAnyKeyToContinue();
  266. while( ! WriteImageToFloppy( NT_IMAGE_5_NAME, DrivePath ) )
  267. {
  268. bTryAgain = DoesUserWantToTryCopyAgain();
  269. if( ! bTryAgain )
  270. {
  271. exit( 1 );
  272. }
  273. }
  274. print( L"" );
  275. print( StrInsertAnotherDiskLine1, DriveLetter );
  276. print( StrInsertAnotherDiskLine2, StrDiskLabel6 );
  277. PressAnyKeyToContinue();
  278. while( ! WriteImageToFloppy( NT_IMAGE_6_NAME, DrivePath ) )
  279. {
  280. bTryAgain = DoesUserWantToTryCopyAgain();
  281. if( ! bTryAgain )
  282. {
  283. exit( 1 );
  284. }
  285. }
  286. print( L"" );
  287. print( StrCompletedSuccessfully );
  288. print( StrStars );
  289. FreeStrings();
  290. return( 0 );
  291. }
  292. //----------------------------------------------------------------------------
  293. //
  294. // Function: WriteImageToFloppy
  295. //
  296. // Purpose: Writes an image file to a floppy disk. Handles all error
  297. // reporting to the user.
  298. //
  299. // Arguments: char *szFileName - filename to write to the floppy
  300. // char *DrivePath - drive path of the floppy to write to, it is of
  301. // the form \\.\x where x is the drive letter
  302. //
  303. // Returns: BOOL - TRUE if image written to floppy properly
  304. // FALSE if there were errors
  305. //
  306. //----------------------------------------------------------------------------
  307. BOOL
  308. WriteImageToFloppy( WCHAR *szFileName, WCHAR *DrivePath )
  309. {
  310. INT iCurrentTrack;
  311. INT cBytesRead = 0;
  312. INT cBytesWritten = 0;
  313. INT iPercentComplete = 0;
  314. INT iWheelPosition = 0;
  315. HANDLE hFloppyImage = NULL;
  316. HANDLE hFloppyDrive = NULL;
  317. char TrackBuffer[TRACK_SIZE];
  318. hFloppyImage = CreateFile( szFileName,
  319. GENERIC_READ,
  320. FILE_SHARE_READ | FILE_SHARE_WRITE,
  321. NULL,
  322. OPEN_EXISTING,
  323. FILE_FLAG_SEQUENTIAL_SCAN,
  324. NULL );
  325. if( hFloppyImage == INVALID_HANDLE_VALUE )
  326. {
  327. PrintErrorMessage();
  328. return( FALSE );
  329. }
  330. hFloppyDrive = CreateFile( DrivePath,
  331. GENERIC_WRITE,
  332. 0,
  333. NULL,
  334. OPEN_EXISTING,
  335. FILE_FLAG_SEQUENTIAL_SCAN,
  336. NULL );
  337. if( hFloppyDrive == INVALID_HANDLE_VALUE )
  338. {
  339. PrintErrorMessage();
  340. CleanUp( &hFloppyDrive, &hFloppyImage );
  341. return( FALSE );
  342. }
  343. for( iCurrentTrack = 0; iCurrentTrack < TRACKS_ON_DISK; iCurrentTrack++ )
  344. {
  345. if( ! ReadFile( hFloppyImage, TrackBuffer, TRACK_SIZE, &cBytesRead, NULL ) )
  346. {
  347. PrintErrorMessage();
  348. CleanUp( &hFloppyDrive, &hFloppyImage );
  349. return( FALSE );
  350. }
  351. if( ! WriteFile( hFloppyDrive, TrackBuffer, TRACK_SIZE, &cBytesWritten, NULL ) )
  352. {
  353. PrintErrorMessage();
  354. CleanUp( &hFloppyDrive, &hFloppyImage );
  355. return( FALSE );
  356. }
  357. iPercentComplete = (int) ( ( (double) (iCurrentTrack) / (double) (TRACKS_ON_DISK) ) * 100.0 );
  358. ConsolePrint( L"%c %3d%% %s.\r",
  359. rgAsciiWheel[iWheelPosition],
  360. iPercentComplete,
  361. StrComplete );
  362. //
  363. // Advance the ASCII wheel
  364. //
  365. iWheelPosition++;
  366. if( iWheelPosition >= NUMBER_OF_ASCII_WHEEL_SYMBOLS )
  367. {
  368. iWheelPosition = 0;
  369. }
  370. }
  371. //
  372. // We are done copying the disk so force it to read 100% and get rid of
  373. // the ascii wheel symbol.
  374. //
  375. ConsolePrint( L" 100%% %s. \n", StrComplete );
  376. //
  377. // Free allocated resources
  378. //
  379. CleanUp( &hFloppyDrive, &hFloppyImage );
  380. return TRUE;
  381. }
  382. //----------------------------------------------------------------------------
  383. //
  384. // Function: PrintErrorMessage
  385. //
  386. // Purpose: To get the last system error, look up what it is and print it out
  387. // to the user.
  388. //
  389. // Arguments: VOID
  390. //
  391. // Returns: VOID
  392. //
  393. //----------------------------------------------------------------------------
  394. VOID
  395. PrintErrorMessage( VOID )
  396. {
  397. LPVOID lpMsgBuf = NULL;
  398. if(!FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  399. FORMAT_MESSAGE_FROM_SYSTEM |
  400. FORMAT_MESSAGE_IGNORE_INSERTS,
  401. NULL,
  402. GetLastError(),
  403. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  404. (LPWSTR) &lpMsgBuf,
  405. 0,
  406. NULL )) {
  407. // Great. Not enough memory to format an error message.
  408. ConsolePrint( L"\nNot enough memory to format error message.\n" );
  409. if( lpMsgBuf )
  410. LocalFree( lpMsgBuf );
  411. }
  412. else {
  413. ConsolePrint( L"\n%s\n", (LPCWSTR)lpMsgBuf );
  414. LocalFree( lpMsgBuf );
  415. }
  416. }
  417. //----------------------------------------------------------------------------
  418. //
  419. // Function: PrintErrorWrongDriveType
  420. //
  421. // Purpose: To translate a drive type error code into a message and print it
  422. //
  423. // Arguments: UINT iDriveType - drive type error code to look-up
  424. //
  425. // Returns: VOID
  426. //
  427. //----------------------------------------------------------------------------
  428. VOID
  429. PrintErrorWrongDriveType( UINT iDriveType )
  430. {
  431. if( iDriveType == DRIVE_NO_ROOT_DIR )
  432. {
  433. WCHAR *StrNoRootDir = MyLoadString( IDS_NO_ROOT_DIR );
  434. ConsolePrint( L"\n%s\n", StrNoRootDir );
  435. free( StrNoRootDir );
  436. }
  437. else
  438. {
  439. WCHAR *StrDriveNotFloppy = MyLoadString( IDS_DRIVE_NOT_FL0PPY );
  440. ConsolePrint( L"\n%s\n", StrDriveNotFloppy );
  441. free( StrDriveNotFloppy );
  442. }
  443. }
  444. //----------------------------------------------------------------------------
  445. //
  446. // Function: IsDriveLargeEnough
  447. //
  448. // Purpose: To determine if the floppy drive supports 1.44 MB or larger disks
  449. //
  450. // Arguments: char* DrivePath - drive path of the floppy to write to, it is of
  451. // the form \\.\x where x is the drive letter
  452. //
  453. // Returns: BOOL - TRUE if the drive supports 1.44 MB or greater, FALSE if not
  454. //
  455. //----------------------------------------------------------------------------
  456. BOOL
  457. IsDriveLargeEnough( WCHAR *DrivePath )
  458. {
  459. UINT i;
  460. HANDLE hFloppyDrive;
  461. DISK_GEOMETRY SupportedGeometry[20];
  462. DWORD SupportedGeometryCount;
  463. DWORD ReturnedByteCount;
  464. hFloppyDrive = CreateFile( DrivePath,
  465. 0,
  466. FILE_SHARE_READ,
  467. NULL,
  468. OPEN_ALWAYS,
  469. 0,
  470. NULL );
  471. if( hFloppyDrive == INVALID_HANDLE_VALUE )
  472. {
  473. PrintErrorMessage();
  474. exit( 1 );
  475. }
  476. if( DeviceIoControl( hFloppyDrive,
  477. IOCTL_DISK_GET_MEDIA_TYPES,
  478. NULL,
  479. 0,
  480. SupportedGeometry,
  481. sizeof( SupportedGeometry ),
  482. &ReturnedByteCount,
  483. NULL ) )
  484. {
  485. SupportedGeometryCount = ( ReturnedByteCount / sizeof( DISK_GEOMETRY ) );
  486. }
  487. else
  488. {
  489. SupportedGeometryCount = 0;
  490. }
  491. CloseHandle( hFloppyDrive );
  492. for( i = 0; i < SupportedGeometryCount; i++ )
  493. {
  494. if( SupportedGeometry[i].MediaType == F3_1Pt44_512 )
  495. {
  496. //
  497. // This drive supports 3.5, 1.44MB, 512 bytes/sector.
  498. //
  499. return( TRUE );
  500. }
  501. }
  502. return( FALSE );
  503. }
  504. //----------------------------------------------------------------------------
  505. //
  506. // Function: DoImageFilesExist
  507. //
  508. // Purpose: Determines if all the image files are in the current directory or
  509. // not. If an image file is missing, an error message is printed
  510. // to the user.
  511. //
  512. // Note: it detemines if a file exists by seeing if it can open it
  513. // for reading.
  514. //
  515. // Arguments: VOID
  516. //
  517. // Returns: INT -- non-zero on success, all images files exist in current dir
  518. // zero on failure, 1 or more image files do not exist
  519. //
  520. //----------------------------------------------------------------------------
  521. INT
  522. DoImageFilesExist( VOID )
  523. {
  524. BOOL bAllFilesExist = TRUE;
  525. if( ! DoesFileExist( NT_IMAGE_1_NAME ) )
  526. {
  527. print( StrCanNotFindFile, NT_IMAGE_1_NAME );
  528. bAllFilesExist = FALSE;
  529. }
  530. if( ! DoesFileExist( NT_IMAGE_2_NAME ) )
  531. {
  532. print( StrCanNotFindFile, NT_IMAGE_2_NAME );
  533. bAllFilesExist = FALSE;
  534. }
  535. if( ! DoesFileExist( NT_IMAGE_3_NAME ) )
  536. {
  537. print( StrCanNotFindFile, NT_IMAGE_3_NAME );
  538. bAllFilesExist = FALSE;
  539. }
  540. if( ! DoesFileExist( NT_IMAGE_4_NAME ) )
  541. {
  542. print( StrCanNotFindFile, NT_IMAGE_4_NAME );
  543. bAllFilesExist = FALSE;
  544. }
  545. if( ! DoesFileExist( NT_IMAGE_5_NAME ) )
  546. {
  547. print( StrCanNotFindFile, NT_IMAGE_5_NAME );
  548. bAllFilesExist = FALSE;
  549. }
  550. if( ! DoesFileExist( NT_IMAGE_6_NAME ) )
  551. {
  552. print( StrCanNotFindFile, NT_IMAGE_6_NAME );
  553. bAllFilesExist = FALSE;
  554. }
  555. if( bAllFilesExist )
  556. {
  557. return( 1 );
  558. }
  559. else
  560. {
  561. return( 0 );
  562. }
  563. }
  564. //----------------------------------------------------------------------------
  565. //
  566. // Function: CleanUp
  567. //
  568. // Purpose: Closes open handles. This function should be called just before
  569. // exiting the program.
  570. //
  571. // Arguments: HANDLE *hFloppyDrive - the floppy disk handle to be closed
  572. // HANDLE *hFloppyImage - the floppy image file handle to be closed
  573. //
  574. // Returns: VOID
  575. //
  576. //----------------------------------------------------------------------------
  577. VOID
  578. CleanUp( HANDLE *hFloppyDrive, HANDLE *hFloppyImage )
  579. {
  580. if( *hFloppyDrive )
  581. {
  582. CloseHandle( *hFloppyDrive );
  583. *hFloppyDrive = NULL;
  584. }
  585. if( *hFloppyImage )
  586. {
  587. CloseHandle( *hFloppyImage );
  588. *hFloppyImage = NULL;
  589. }
  590. }
  591. //----------------------------------------------------------------------------
  592. //
  593. // Function: FreeStrings
  594. //
  595. // Purpose: Deallocate the memory for all the strings.
  596. //
  597. // Arguments: VOID
  598. //
  599. // Returns: VOID
  600. //
  601. //----------------------------------------------------------------------------
  602. VOID
  603. FreeStrings( VOID )
  604. {
  605. free( StrNtVersionName );
  606. free( StrDiskLabel1 );
  607. free( StrDiskLabel2 );
  608. free( StrDiskLabel3 );
  609. free( StrDiskLabel4 );
  610. free( StrDiskLabel5 );
  611. free( StrDiskLabel6 );
  612. free( StrStars );
  613. free( StrExplanationLine1 );
  614. free( StrExplanationLine2 );
  615. free( StrExplanationLine3 );
  616. free( StrExplanationLine4 );
  617. free( StrInsertFirstDiskLine1 );
  618. free( StrInsertFirstDiskLine2 );
  619. free( StrInsertAnotherDiskLine1 );
  620. free( StrInsertAnotherDiskLine2 );
  621. free( StrPressAnyKeyWhenReady );
  622. free( StrCompletedSuccessfully );
  623. free( StrComplete );
  624. free( StrCanNotFindFile );
  625. free( StrOutOfMemory );
  626. }
  627. //----------------------------------------------------------------------------
  628. //
  629. // Function: LoadStrings
  630. //
  631. // Purpose: Load the string constants from the string table.
  632. //
  633. // Arguments: VOID
  634. //
  635. // Returns: VOID
  636. //
  637. //----------------------------------------------------------------------------
  638. VOID
  639. LoadStrings( VOID )
  640. {
  641. INT Length;
  642. //
  643. // Loading the Out of Memory string is a little tricky because of the
  644. // error that can occur while loading it.
  645. //
  646. // For the other strings, just call the MyLoadString function to do
  647. // the work
  648. //
  649. StrOutOfMemory = (WCHAR *) malloc( MAKEBOOT_MAX_STRING_LEN * sizeof(WCHAR) + 1 );
  650. if( StrOutOfMemory == NULL )
  651. {
  652. //
  653. // Can't localize this string
  654. //
  655. ConsolePrint( L"\nOut of memory. Please free more memory and run this program again.\n" );
  656. exit( 1 );
  657. }
  658. Length = LoadString( NULL,
  659. IDS_OUT_OF_MEMORY,
  660. StrOutOfMemory,
  661. MAKEBOOT_MAX_STRING_LEN );
  662. if( ! Length )
  663. {
  664. //
  665. // Can't localize this string
  666. //
  667. ConsolePrint( L"Unable to load resources.\n" );
  668. exit( 1 ) ;
  669. }
  670. StrStars = MyLoadString( IDS_STARS );
  671. StrExplanationLine1 = MyLoadString( IDS_PROGRAM_EXPLANATION_LINE_1 );
  672. StrExplanationLine2 = MyLoadString( IDS_PROGRAM_EXPLANATION_LINE_2 );
  673. StrExplanationLine3 = MyLoadString( IDS_PROGRAM_EXPLANATION_LINE_3 );
  674. StrExplanationLine4 = MyLoadString( IDS_PROGRAM_EXPLANATION_LINE_4 );
  675. StrInsertFirstDiskLine1 = MyLoadString( IDS_INSERT_FIRST_DISK_LINE_1 );
  676. StrInsertFirstDiskLine2 = MyLoadString( IDS_INSERT_FIRST_DISK_LINE_2 );
  677. StrInsertAnotherDiskLine1 = MyLoadString( IDS_INSERT_ANOTHER_DISK_LINE_1 );
  678. StrInsertAnotherDiskLine2 = MyLoadString( IDS_INSERT_ANOTHER_DISK_LINE_2 );
  679. StrPressAnyKeyWhenReady = MyLoadString( IDS_PRESS_ANY_KEY_WHEN_READY );
  680. StrCompletedSuccessfully = MyLoadString( IDS_COMPLETED_SUCCESSFULLY );
  681. StrComplete = MyLoadString( IDS_COMPLETE );
  682. StrCanNotFindFile = MyLoadString( IDS_CANNOT_FIND_FILE );
  683. StrNtVersionName = MyLoadString( IDS_NT_VERSION_NAME_DEFAULT );
  684. StrDiskLabel1 = MyLoadString( IDS_DISK_LABEL_1_DEFAULT );
  685. StrDiskLabel2 = MyLoadString( IDS_DISK_LABEL_2_DEFAULT );
  686. StrDiskLabel3 = MyLoadString( IDS_DISK_LABEL_3_DEFAULT );
  687. StrDiskLabel4 = MyLoadString( IDS_DISK_LABEL_4_DEFAULT );
  688. StrDiskLabel5 = MyLoadString( IDS_DISK_LABEL_5_DEFAULT );
  689. StrDiskLabel6 = MyLoadString( IDS_DISK_LABEL_6_DEFAULT );
  690. }
  691. //----------------------------------------------------------------------------
  692. //
  693. // Function: DoesUserWantToTryCopyAgain
  694. //
  695. // Purpose: Ask the user if they want to retry to copy the image to floppy.
  696. // Get the user input and return whether to copy again or not.
  697. //
  698. // Arguments: VOID
  699. //
  700. // Returns: BOOL - TRUE if user wants to attempt to copy again
  701. // - FALSE if user does not want to attempt to copy again
  702. //
  703. //----------------------------------------------------------------------------
  704. BOOL
  705. DoesUserWantToTryCopyAgain( VOID )
  706. {
  707. INT ch;
  708. WCHAR *StrAttemptToCreateFloppyAgain = MyLoadString( IDS_ATTEMPT_TO_CREATE_FLOPPY_AGAIN );
  709. WCHAR *StrPressEnterOrEsc = MyLoadString( IDS_PRESS_ENTER_OR_ESC );
  710. //
  711. // Clear the input stream by eating all the chars until there are none
  712. // left. Print the message and then wait for a key press.
  713. //
  714. while( _kbhit() )
  715. {
  716. _getch();
  717. }
  718. do
  719. {
  720. ConsolePrint( L"%s\n", StrAttemptToCreateFloppyAgain );
  721. ConsolePrint( L"%s\n", StrPressEnterOrEsc );
  722. ch = _getch();
  723. } while( ch != ENTER_KEY && ch != ESC_KEY );
  724. if( ch == ENTER_KEY )
  725. {
  726. return( TRUE );
  727. }
  728. else
  729. {
  730. return( FALSE );
  731. }
  732. free( StrAttemptToCreateFloppyAgain );
  733. free( StrPressEnterOrEsc );
  734. }
  735. //----------------------------------------------------------------------------
  736. //
  737. // Function: PressAnyKeyToContinue
  738. //
  739. // Purpose: Print the "Press any key when ready" message and wait until the
  740. // user presses a key.
  741. //
  742. // Arguments: VOID
  743. //
  744. // Returns: VOID
  745. //
  746. //----------------------------------------------------------------------------
  747. VOID
  748. PressAnyKeyToContinue( VOID )
  749. {
  750. //
  751. // Clear the input stream by eating all the chars until there are none
  752. // left. Print the message and then wait for a key press.
  753. //
  754. while( _kbhit() )
  755. {
  756. _getch();
  757. }
  758. print( StrPressAnyKeyWhenReady );
  759. //
  760. // Spin until the keyboard is pressed
  761. //
  762. while( ! _kbhit() )
  763. {
  764. ;
  765. }
  766. }
  767. //----------------------------------------------------------------------------
  768. //
  769. // Function: MyLoadString
  770. //
  771. // Purpose: Loads a string resource given it's IDS_* and returns
  772. // a malloc'ed buffer with its contents.
  773. //
  774. // The malloc()'ed buffer must be freed with free()
  775. //
  776. // This function will either return the string or exit. It will
  777. // never return NULL or a bad pointer.
  778. //
  779. // Arguments: UINT StringId - the string ID to load
  780. //
  781. // Returns:
  782. // Pointer to buffer. An empty string is returned if the StringId
  783. // does not exist. Null is returned if out of memory.
  784. //
  785. //----------------------------------------------------------------------------
  786. LPWSTR
  787. MyLoadString( UINT StringId )
  788. {
  789. WCHAR Buffer[ MAKEBOOT_MAX_STRING_LEN ];
  790. WCHAR *String = NULL;
  791. UINT Length;
  792. Length = LoadString( NULL,
  793. StringId,
  794. Buffer,
  795. MAKEBOOT_MAX_STRING_LEN );
  796. if( Length )
  797. {
  798. String = (WCHAR *) malloc( Length * sizeof(WCHAR) + 1 );
  799. if( String == NULL )
  800. {
  801. ConsolePrint( L"%s\n", StrOutOfMemory );
  802. exit( 1 );
  803. }
  804. else
  805. {
  806. wcscpy( String, Buffer );
  807. String[Length] = L'\0';
  808. return( String );
  809. }
  810. }
  811. else
  812. {
  813. //
  814. // Can't load the string so exit
  815. // NOTE: this string will not be localized
  816. //
  817. ConsolePrint( L"Unable to load resources.\n" );
  818. exit( 1 );
  819. }
  820. }
  821. //----------------------------------------------------------------------------
  822. //
  823. // Function: print
  824. //
  825. // Purpose: To print out strings to the user. Useful when there is
  826. // embedded formatting characters in a string that was loaded from
  827. // a string table.
  828. //
  829. // Arguments: szFirstString - the string that contains the embedded formatting
  830. // characters (such as %s, %c, etc.)
  831. // ... - variable number of arguments that correspond to each
  832. // formatting character
  833. //
  834. // Returns: VOID
  835. //
  836. //----------------------------------------------------------------------------
  837. VOID
  838. print( WCHAR *szFirstString, ... )
  839. {
  840. WCHAR OutputBuffer[MAKEBOOT_MAX_STRING_LEN];
  841. va_list arglist;
  842. va_start( arglist, szFirstString );
  843. wvsprintf( OutputBuffer, szFirstString, arglist );
  844. ConsolePrint( L"%s\n", OutputBuffer );
  845. va_end( arglist );
  846. }
  847. //----------------------------------------------------------------------------
  848. //
  849. // Function: DoesFileExist
  850. //
  851. // Purpose: To determine whether a file exists or not
  852. //
  853. // Arguments: LPWSTR lpFileName - filename to see if it exists or not
  854. //
  855. // Returns: BOOL - TRUE if the file exists
  856. // - FALSE if the file does not exist
  857. //
  858. //----------------------------------------------------------------------------
  859. BOOL
  860. DoesFileExist( LPWSTR lpFileName )
  861. {
  862. DWORD dwAttribs = GetFileAttributes( lpFileName );
  863. if( dwAttribs == (DWORD) -1 )
  864. {
  865. return( FALSE );
  866. }
  867. if( dwAttribs & FILE_ATTRIBUTE_DIRECTORY )
  868. {
  869. return( FALSE );
  870. }
  871. return( TRUE );
  872. }
  873. //----------------------------------------------------------------------------
  874. //
  875. // Function: IsDBCSConsole
  876. //
  877. // Purpose: To determine whether a DBC console or not
  878. //
  879. // Arguments: None
  880. //
  881. // Returns: BOOL - TRUE if FE console codepage
  882. // - FALSE if not FE console codepage
  883. //
  884. //----------------------------------------------------------------------------
  885. BOOL
  886. IsDBCSCodePage(UINT CodePage)
  887. {
  888. switch(CodePage) {
  889. case 932:
  890. case 936:
  891. case 949:
  892. case 950:
  893. return TRUE;
  894. }
  895. return FALSE;
  896. }
  897. //----------------------------------------------------------------------------
  898. //
  899. // Function: SetFarEastThread
  900. //
  901. // Purpose: FarEast version wants to display bi-lingual string according console OCP
  902. //
  903. // Arguments: None
  904. //
  905. // Returns: None
  906. //----------------------------------------------------------------------------
  907. void SetFarEastThread()
  908. {
  909. LANGID LangId = 0;
  910. switch(GetConsoleOutputCP()) {
  911. case 932:
  912. LangId = MAKELANGID( LANG_JAPANESE, SUBLANG_DEFAULT );
  913. break;
  914. case 949:
  915. LangId = MAKELANGID( LANG_KOREAN, SUBLANG_KOREAN );
  916. break;
  917. case 936:
  918. LangId = MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED );
  919. break;
  920. case 950:
  921. LangId = MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL );
  922. break;
  923. default:
  924. {
  925. LANGID TmpLangId = PRIMARYLANGID(LANGIDFROMLCID( GetUserDefaultLCID() ));
  926. if (TmpLangId == LANG_JAPANESE ||
  927. TmpLangId == LANG_KOREAN ||
  928. TmpLangId == LANG_CHINESE ) {
  929. LangId = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
  930. }
  931. }
  932. break;
  933. }
  934. if (LangId) {
  935. SetThreadLocale( MAKELCID(LangId, SORT_DEFAULT) );
  936. }
  937. }
  938. //----------------------------------------------------------------------------
  939. //
  940. // Function: ConsolePrint
  941. //
  942. // Purpose: There is a bug in CRT library that unicode FE characters can't
  943. // convert correctly, so we output characters directly.
  944. //
  945. // Arguments: None
  946. //
  947. // Returns: None
  948. //----------------------------------------------------------------------------
  949. void ConsolePrint( WCHAR *szFirstString, ... )
  950. {
  951. HANDLE StdOut;
  952. DWORD WrittenCount;
  953. WCHAR OutputBuffer[MAKEBOOT_MAX_STRING_LEN];
  954. va_list arglist;
  955. if((StdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
  956. return;
  957. }
  958. va_start( arglist, szFirstString );
  959. wvsprintf( OutputBuffer, szFirstString, arglist );
  960. WriteConsoleW(
  961. StdOut,
  962. OutputBuffer,
  963. lstrlenW(OutputBuffer),
  964. &WrittenCount,
  965. NULL
  966. );
  967. va_end( arglist );
  968. }