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.

858 lines
22 KiB

  1. //
  2. // Driver Verifier UI
  3. // Copyright (c) Microsoft Corporation, 1999
  4. //
  5. //
  6. //
  7. // module: CmdLine.cpp
  8. // author: DMihai
  9. // created: 11/1/00
  10. //
  11. // Description:
  12. //
  13. #include "stdafx.h"
  14. #include "verifier.h"
  15. #include "CmdLine.h"
  16. #include "VrfUtil.h"
  17. #include "VGlobal.h"
  18. /////////////////////////////////////////////////////////////////////////////
  19. //
  20. // Execute command line
  21. //
  22. DWORD CmdLineExecute( INT argc, TCHAR *argv[] )
  23. {
  24. BOOL bFoundCmdLineSwitch;
  25. BOOL bHaveNewFlags;
  26. BOOL bHaveNewDrivers;
  27. BOOL bHaveVolatile;
  28. BOOL bVolatileAddDriver;
  29. DWORD dwExitCode;
  30. DWORD dwNewFlags;
  31. INT_PTR nDrivers;
  32. INT_PTR nCrtDriver;
  33. CStringArray astrNewDrivers;
  34. CString strAllDrivers;
  35. dwExitCode = EXIT_CODE_SUCCESS;
  36. //
  37. // See if the user asked for help
  38. //
  39. bFoundCmdLineSwitch = CmdLineExecuteIfHelp( argc,
  40. argv );
  41. if( TRUE == bFoundCmdLineSwitch )
  42. {
  43. //
  44. // We are done printing out the help strings
  45. //
  46. goto Done;
  47. }
  48. //
  49. // See if the user asked to reset all the existing verifier settings
  50. //
  51. bFoundCmdLineSwitch = CmdLineFindResetSwitch( argc,
  52. argv );
  53. if( TRUE == bFoundCmdLineSwitch )
  54. {
  55. if( VrfDeleteAllVerifierSettings() )
  56. {
  57. if( g_bSettingsSaved )
  58. {
  59. //
  60. // Had some non-void verifier settings before
  61. //
  62. dwExitCode = EXIT_CODE_REBOOT_NEEDED;
  63. }
  64. else
  65. {
  66. //
  67. // Nothing has changed
  68. //
  69. dwExitCode = EXIT_CODE_SUCCESS;
  70. }
  71. }
  72. else
  73. {
  74. dwExitCode = EXIT_CODE_ERROR;
  75. }
  76. //
  77. // We are deleting the settings
  78. //
  79. goto Done;
  80. }
  81. //
  82. // See if we need to start logging statistics
  83. //
  84. bFoundCmdLineSwitch = CmdLineExecuteIfLog( argc,
  85. argv );
  86. if( TRUE == bFoundCmdLineSwitch )
  87. {
  88. //
  89. // We are done logging
  90. //
  91. goto Done;
  92. }
  93. //
  94. // See if the user asked to dump the current statistics
  95. // to the console
  96. //
  97. bFoundCmdLineSwitch = CmdLineExecuteIfQuery( argc,
  98. argv );
  99. if( TRUE == bFoundCmdLineSwitch )
  100. {
  101. //
  102. // We are done with the query
  103. //
  104. goto Done;
  105. }
  106. //
  107. // See if the user asked to dump the current registry settings
  108. //
  109. bFoundCmdLineSwitch = CmdLineExecuteIfQuerySettings( argc,
  110. argv );
  111. if( TRUE == bFoundCmdLineSwitch )
  112. {
  113. //
  114. // We are done with the settings query
  115. //
  116. goto Done;
  117. }
  118. //
  119. // Get the new flags, drivers and volatile
  120. // if they have been specified
  121. //
  122. bHaveNewFlags = FALSE;
  123. bHaveNewDrivers = FALSE;
  124. bHaveVolatile = FALSE;
  125. CmdLineGetFlagsDriversVolatile(
  126. argc,
  127. argv,
  128. dwNewFlags,
  129. bHaveNewFlags,
  130. astrNewDrivers,
  131. bHaveNewDrivers,
  132. bHaveVolatile,
  133. bVolatileAddDriver );
  134. if( bHaveNewFlags || bHaveNewDrivers )
  135. {
  136. //
  137. // Some new drivers and/or flags have been specified
  138. //
  139. if( FALSE != bHaveVolatile )
  140. {
  141. //
  142. // Have new volative settings
  143. //
  144. if( bHaveNewFlags )
  145. {
  146. VrfSetNewFlagsVolatile( dwNewFlags );
  147. }
  148. else
  149. {
  150. if( astrNewDrivers.GetSize() > 0 )
  151. {
  152. //
  153. // Have some new drivers to add or remove
  154. // from the verify list
  155. //
  156. if( bVolatileAddDriver )
  157. {
  158. //
  159. // Add some drivers
  160. //
  161. VrfAddDriversVolatile( astrNewDrivers );
  162. }
  163. else
  164. {
  165. //
  166. // Remove some drivers
  167. //
  168. VrfRemoveDriversVolatile( astrNewDrivers );
  169. }
  170. }
  171. }
  172. }
  173. else
  174. {
  175. //
  176. // Have new persistent settings (registry)
  177. //
  178. //
  179. // Try to get the old settings
  180. //
  181. VrtLoadCurrentRegistrySettings( g_bAllDriversVerified,
  182. g_astrVerifyDriverNamesRegistry,
  183. g_dwVerifierFlagsRegistry );
  184. if( bHaveNewDrivers )
  185. {
  186. //
  187. // Concat all the new driver names in only one string,
  188. // separated with spaces
  189. //
  190. nDrivers = astrNewDrivers.GetSize();
  191. for( nCrtDriver = 0; nCrtDriver < nDrivers; nCrtDriver += 1 )
  192. {
  193. if( strAllDrivers.GetLength() > 0 )
  194. {
  195. strAllDrivers += _T( ' ' );
  196. }
  197. strAllDrivers += astrNewDrivers.ElementAt( nCrtDriver );
  198. }
  199. }
  200. //
  201. // If:
  202. //
  203. // - we are switching to "all drivers verified" OR
  204. // - we are switching to a new set of drivers to be verified OR
  205. // - we are switching to other verifier flags
  206. //
  207. if( ( bHaveNewDrivers &&
  208. strAllDrivers.CompareNoCase( _T( "*" ) ) == 0 &&
  209. TRUE != g_bAllDriversVerified ) ||
  210. ( bHaveNewDrivers &&
  211. strAllDrivers.CompareNoCase( _T( "*" ) ) != 0 &&
  212. VrfIsDriversSetDifferent( strAllDrivers, g_astrVerifyDriverNamesRegistry ) ) ||
  213. ( bHaveNewFlags && dwNewFlags != g_dwVerifierFlagsRegistry ) )
  214. {
  215. //
  216. // These are different settings from what we had before
  217. //
  218. VrfWriteVerifierSettings( bHaveNewDrivers,
  219. strAllDrivers,
  220. bHaveNewFlags,
  221. dwNewFlags );
  222. }
  223. else
  224. {
  225. //
  226. // The new settings are the same as previous
  227. //
  228. VrfMesssageFromResource( IDS_NO_SETTINGS_WERE_CHANGED );
  229. }
  230. if( g_bSettingsSaved )
  231. {
  232. VrfMesssageFromResource( IDS_NEW_SETTINGS );
  233. VrfDumpRegistrySettingsToConsole();
  234. }
  235. }
  236. }
  237. Done:
  238. return dwExitCode;
  239. }
  240. /////////////////////////////////////////////////////////////////////////////
  241. //
  242. // See if the user asked for help and print out the help strings
  243. //
  244. BOOL CmdLineExecuteIfHelp( INT argc,
  245. TCHAR *argv[] )
  246. {
  247. BOOL bPrintedHelp;
  248. TCHAR szCmdLineSwitch[ 64 ];
  249. bPrintedHelp = FALSE;
  250. VERIFY( VrfLoadString( IDS_HELP_CMDLINE_SWITCH,
  251. szCmdLineSwitch,
  252. ARRAY_LENGTH( szCmdLineSwitch ) ) );
  253. //
  254. // Search for help switch in the command line
  255. //
  256. if( argc == 2 && _tcsicmp( argv[ 1 ], szCmdLineSwitch) == 0)
  257. {
  258. CmdLinePrintHelpInformation();
  259. bPrintedHelp = TRUE;
  260. }
  261. return bPrintedHelp;
  262. }
  263. /////////////////////////////////////////////////////////////////////////////
  264. VOID CmdLinePrintHelpInformation()
  265. {
  266. VrfTPrintfResourceFormat( IDS_HELP_LINE1, VER_PRODUCTVERSION_STR );
  267. puts( VER_LEGALCOPYRIGHT_STR );
  268. VrfPrintStringFromResources( IDS_HELP_LINE3 );
  269. VrfPrintStringFromResources( IDS_HELP_LINE4 );
  270. VrfPrintStringFromResources( IDS_HELP_LINE5 );
  271. VrfPrintStringFromResources( IDS_HELP_LINE6 );
  272. VrfPrintStringFromResources( IDS_HELP_LINE7 );
  273. VrfPrintStringFromResources( IDS_HELP_LINE8 );
  274. VrfPrintStringFromResources( IDS_HELP_LINE9 );
  275. VrfPrintStringFromResources( IDS_HELP_LINE10 );
  276. VrfPrintStringFromResources( IDS_HELP_LINE11 );
  277. VrfPrintStringFromResources( IDS_HELP_LINE12 );
  278. VrfPrintStringFromResources( IDS_HELP_LINE13 );
  279. VrfPrintStringFromResources( IDS_HELP_LINE14 );
  280. VrfPrintStringFromResources( IDS_HELP_LINE15 );
  281. VrfPrintStringFromResources( IDS_HELP_LINE16 );
  282. VrfPrintStringFromResources( IDS_HELP_LINE17 );
  283. VrfPrintStringFromResources( IDS_HELP_LINE18 );
  284. VrfPrintStringFromResources( IDS_HELP_LINE19 );
  285. VrfPrintStringFromResources( IDS_HELP_LINE20 );
  286. VrfPrintStringFromResources( IDS_HELP_LINE21 );
  287. VrfPrintStringFromResources( IDS_HELP_LINE22 );
  288. VrfPrintStringFromResources( IDS_HELP_LINE23 );
  289. VrfPrintStringFromResources( IDS_HELP_LINE24 );
  290. VrfPrintStringFromResources( IDS_HELP_LINE25 );
  291. VrfPrintStringFromResources( IDS_HELP_LINE26 );
  292. VrfPrintStringFromResources( IDS_HELP_LINE27 );
  293. VrfPrintStringFromResources( IDS_HELP_LINE28 );
  294. VrfPrintStringFromResources( IDS_HELP_LINE29 );
  295. VrfPrintStringFromResources( IDS_HELP_LINE30 );
  296. VrfPrintStringFromResources( IDS_HELP_LINE31 );
  297. }
  298. /////////////////////////////////////////////////////////////////////////////
  299. //
  300. // See if the user asked to reset all the existing verifier settings
  301. //
  302. BOOL CmdLineFindResetSwitch( INT argc,
  303. TCHAR *argv[] )
  304. {
  305. BOOL bFound;
  306. TCHAR szCmdLineOption[ 64 ];
  307. bFound = FALSE;
  308. if( 2 == argc )
  309. {
  310. VERIFY( VrfLoadString( IDS_RESET_CMDLINE_SWITCH,
  311. szCmdLineOption,
  312. ARRAY_LENGTH( szCmdLineOption ) ) );
  313. bFound = ( _tcsicmp( argv[ 1 ], szCmdLineOption) == 0 );
  314. }
  315. return bFound;
  316. }
  317. /////////////////////////////////////////////////////////////////////////////
  318. //
  319. // See if we need to start logging statistics
  320. //
  321. BOOL CmdLineExecuteIfLog( INT argc,
  322. TCHAR *argv[] )
  323. {
  324. INT nCrtArg;
  325. BOOL bStartLogging;
  326. LPCTSTR szLogFileName;
  327. DWORD dwLogMillisec;
  328. FILE *file;
  329. TCHAR szLogCmdLineOption[ 64 ];
  330. TCHAR szIntervalCmdLineOption[ 64 ];
  331. bStartLogging = FALSE;
  332. szLogFileName = NULL;
  333. if( argc < 2 )
  334. {
  335. //
  336. // Need at least /log LOG_FILE_NAME IN THE CMD LINE
  337. //
  338. goto Done;
  339. }
  340. //
  341. // Default log period - 30 sec
  342. //
  343. dwLogMillisec = 30000;
  344. VERIFY( VrfLoadString( IDS_LOG_CMDLINE_SWITCH,
  345. szLogCmdLineOption,
  346. ARRAY_LENGTH( szLogCmdLineOption ) ) );
  347. VERIFY( VrfLoadString( IDS_INTERVAL_CMDLINE_SWITCH,
  348. szIntervalCmdLineOption,
  349. ARRAY_LENGTH( szIntervalCmdLineOption ) ) );
  350. for( nCrtArg = 1; nCrtArg < argc - 1; nCrtArg += 1 )
  351. {
  352. if( _tcsicmp( argv[ nCrtArg ], szLogCmdLineOption) == 0 )
  353. {
  354. //
  355. // Start logging
  356. //
  357. bStartLogging = TRUE;
  358. szLogFileName = argv[ nCrtArg + 1 ];
  359. }
  360. else
  361. {
  362. if( _tcsicmp( argv[ nCrtArg ], szIntervalCmdLineOption) == 0 )
  363. {
  364. //
  365. // Logging period
  366. //
  367. dwLogMillisec = _ttoi( argv[ nCrtArg + 1 ] ) * 1000;
  368. }
  369. }
  370. }
  371. if( TRUE == bStartLogging )
  372. {
  373. ASSERT( szLogFileName != NULL );
  374. while( TRUE )
  375. {
  376. //
  377. // Open the file
  378. //
  379. file = _tfopen( szLogFileName, TEXT("a+") );
  380. if( file == NULL )
  381. {
  382. //
  383. // print a error message
  384. //
  385. VrfTPrintfResourceFormat(
  386. IDS_CANT_APPEND_FILE,
  387. szLogFileName );
  388. break;
  389. }
  390. //
  391. // Dump current information
  392. //
  393. if( ! VrfDumpStateToFile ( file ) )
  394. {
  395. //
  396. // Insufficient disk space ?
  397. //
  398. VrfTPrintfResourceFormat(
  399. IDS_CANT_WRITE_FILE,
  400. szLogFileName );
  401. }
  402. fflush( file );
  403. VrfFTPrintf(
  404. file,
  405. TEXT("\n\n") );
  406. //
  407. // Close the file
  408. //
  409. fclose( file );
  410. //
  411. // Sleep
  412. //
  413. Sleep( dwLogMillisec );
  414. }
  415. }
  416. Done:
  417. return bStartLogging;
  418. }
  419. /////////////////////////////////////////////////////////////////////////////
  420. //
  421. // See if we need to dump the statistics to the console
  422. //
  423. BOOL CmdLineExecuteIfQuery( INT argc,
  424. TCHAR *argv[] )
  425. {
  426. BOOL bFoundCmdLineSwitch;
  427. TCHAR szCmdLineSwitch[ 64 ];
  428. bFoundCmdLineSwitch = FALSE;
  429. VERIFY( VrfLoadString( IDS_QUERY_CMDLINE_SWITCH,
  430. szCmdLineSwitch,
  431. ARRAY_LENGTH( szCmdLineSwitch ) ) );
  432. //
  433. // Search for our switch in the command line
  434. //
  435. if( argc == 2 && _tcsicmp( argv[1], szCmdLineSwitch) == 0)
  436. {
  437. bFoundCmdLineSwitch = TRUE;
  438. VrfDumpStateToFile( stdout );
  439. }
  440. return bFoundCmdLineSwitch;
  441. }
  442. /////////////////////////////////////////////////////////////////////////////
  443. //
  444. // See if we need to dump the statistics to the console
  445. //
  446. BOOL CmdLineExecuteIfQuerySettings( INT argc,
  447. TCHAR *argv[] )
  448. {
  449. BOOL bFoundCmdLineSwitch;
  450. TCHAR szCmdLineSwitch[ 64 ];
  451. bFoundCmdLineSwitch = FALSE;
  452. VERIFY( VrfLoadString( IDS_QUERYSETT_CMDLINE_SWITCH,
  453. szCmdLineSwitch,
  454. ARRAY_LENGTH( szCmdLineSwitch ) ) );
  455. //
  456. // Search for our switch in the command line
  457. //
  458. if( argc == 2 && _tcsicmp( argv[1], szCmdLineSwitch) == 0)
  459. {
  460. bFoundCmdLineSwitch = TRUE;
  461. VrfDumpRegistrySettingsToConsole();
  462. }
  463. return bFoundCmdLineSwitch;
  464. }
  465. /////////////////////////////////////////////////////////////////////////////
  466. //
  467. // Get the new flags, drivers and volatile
  468. // if they have been specified
  469. //
  470. VOID CmdLineGetFlagsDriversVolatile( INT argc,
  471. TCHAR *argv[],
  472. DWORD &dwNewFlags,
  473. BOOL &bHaveNewFlags,
  474. CStringArray &astrNewDrivers,
  475. BOOL &bHaveNewDrivers,
  476. BOOL &bHaveVolatile,
  477. BOOL &bVolatileAddDriver )
  478. {
  479. INT nCrtArg;
  480. NTSTATUS Status;
  481. UNICODE_STRING ustrFlags;
  482. TCHAR szFlagsCmdLineOption[ 64 ];
  483. TCHAR szAllCmdLineOption[ 64 ];
  484. TCHAR szVolatileCmdLineOption[ 64 ];
  485. TCHAR szDriversCmdLineOption[ 64 ];
  486. TCHAR szAddDriversCmdLineOption[ 64 ];
  487. TCHAR szRemoveDriversCmdLineOption[ 64 ];
  488. TCHAR szStandardCmdLineOption[ 64 ];
  489. #ifndef UNICODE
  490. //
  491. // ANSI
  492. //
  493. INT nNameLength;
  494. LPWSTR szUnicodeName;
  495. #endif //#ifndef UNICODE
  496. astrNewDrivers.RemoveAll();
  497. bHaveNewFlags = FALSE;
  498. bHaveNewDrivers = FALSE;
  499. bHaveVolatile = FALSE;
  500. //
  501. // Load the switches from the resources
  502. //
  503. VERIFY( VrfLoadString( IDS_FLAGS_CMDLINE_SWITCH,
  504. szFlagsCmdLineOption,
  505. ARRAY_LENGTH( szFlagsCmdLineOption ) ) );
  506. VERIFY( VrfLoadString( IDS_ALL_CMDLINE_SWITCH,
  507. szAllCmdLineOption,
  508. ARRAY_LENGTH( szAllCmdLineOption ) ) );
  509. VERIFY( VrfLoadString( IDS_DONTREBOOT_CMDLINE_SWITCH,
  510. szVolatileCmdLineOption,
  511. ARRAY_LENGTH( szVolatileCmdLineOption ) ) );
  512. VERIFY( VrfLoadString( IDS_DRIVER_CMDLINE_SWITCH,
  513. szDriversCmdLineOption,
  514. ARRAY_LENGTH( szDriversCmdLineOption ) ) );
  515. VERIFY( VrfLoadString( IDS_ADDDRIVER_CMDLINE_SWITCH,
  516. szAddDriversCmdLineOption,
  517. ARRAY_LENGTH( szAddDriversCmdLineOption ) ) );
  518. VERIFY( VrfLoadString( IDS_REMOVEDRIVER_CMDLINE_SWITCH,
  519. szRemoveDriversCmdLineOption,
  520. ARRAY_LENGTH( szRemoveDriversCmdLineOption ) ) );
  521. VERIFY( VrfLoadString( IDS_STANDARD_CMDLINE_SWITCH,
  522. szStandardCmdLineOption,
  523. ARRAY_LENGTH( szStandardCmdLineOption ) ) );
  524. //
  525. // Parse all the cmd line arguments, looking for ours
  526. //
  527. for( nCrtArg = 1; nCrtArg < argc; nCrtArg += 1 )
  528. {
  529. if( _tcsicmp( argv[ nCrtArg ], szFlagsCmdLineOption) == 0 )
  530. {
  531. if( nCrtArg < argc - 1 )
  532. {
  533. //
  534. // Not the last cmd line arg - look for the flags next
  535. //
  536. #ifdef UNICODE
  537. //
  538. // UNICODE
  539. //
  540. RtlInitUnicodeString( &ustrFlags,
  541. argv[ nCrtArg + 1 ] );
  542. #else
  543. //
  544. // ANSI
  545. //
  546. nNameLength = strlen( argv[ nCrtArg + 1 ] );
  547. szUnicodeName = new WCHAR[ nNameLength + 1 ];
  548. if( NULL == szUnicodeName )
  549. {
  550. VrfErrorResourceFormat( IDS_NOT_ENOUGH_MEMORY );
  551. goto DoneWithFlags;
  552. }
  553. MultiByteToWideChar( CP_ACP,
  554. 0,
  555. argv[ nCrtArg + 1 ],
  556. -1,
  557. szUnicodeName,
  558. nNameLength + 1 );
  559. RtlInitUnicodeString( &ustrFlags,
  560. szUnicodeName );
  561. #endif
  562. Status = RtlUnicodeStringToInteger( &ustrFlags,
  563. 0,
  564. &dwNewFlags );
  565. if( NT_SUCCESS( Status ) )
  566. {
  567. bHaveNewFlags = TRUE;
  568. }
  569. #ifndef UNICODE
  570. //
  571. // ANSI
  572. //
  573. ASSERT( NULL != szUnicodeName );
  574. delete [] szUnicodeName;
  575. szUnicodeName = NULL;
  576. DoneWithFlags:
  577. NOTHING;
  578. #endif
  579. }
  580. }
  581. else if( _tcsicmp( argv[ nCrtArg ], szAllCmdLineOption) == 0 )
  582. {
  583. //
  584. // Verify all drivers
  585. //
  586. bHaveVolatile = FALSE;
  587. astrNewDrivers.Add( _T( '*' ) );
  588. bHaveNewDrivers = TRUE;
  589. }
  590. else if( _tcsicmp( argv[ nCrtArg ], szStandardCmdLineOption) == 0 )
  591. {
  592. //
  593. // Standard verifier flags
  594. //
  595. dwNewFlags = VrfGetStandardFlags();
  596. bHaveNewFlags = TRUE;
  597. }
  598. else if( _tcsicmp( argv[ nCrtArg ], szVolatileCmdLineOption) == 0 )
  599. {
  600. //
  601. // Volatile
  602. //
  603. bHaveVolatile = TRUE;
  604. }
  605. else if( _tcsicmp( argv[ nCrtArg ], szDriversCmdLineOption) == 0 )
  606. {
  607. //
  608. // /Driver
  609. //
  610. bHaveVolatile = FALSE;
  611. CmdLineGetDriversFromArgv( argc,
  612. argv,
  613. nCrtArg + 1,
  614. astrNewDrivers,
  615. bHaveNewDrivers );
  616. //
  617. // All done - all the rest of argumentshave been driver names
  618. //
  619. break;
  620. }
  621. else if( bHaveVolatile && _tcsicmp( argv[ nCrtArg ], szAddDriversCmdLineOption) == 0 )
  622. {
  623. //
  624. // /adddriver
  625. //
  626. bVolatileAddDriver = TRUE;
  627. CmdLineGetDriversFromArgv( argc,
  628. argv,
  629. nCrtArg + 1,
  630. astrNewDrivers,
  631. bHaveNewDrivers );
  632. //
  633. // All done - all the rest of argumentshave been driver names
  634. //
  635. break;
  636. }
  637. else if( bHaveVolatile && _tcsicmp( argv[ nCrtArg ], szRemoveDriversCmdLineOption) == 0 )
  638. {
  639. //
  640. // /removedriver
  641. //
  642. bVolatileAddDriver = FALSE;
  643. CmdLineGetDriversFromArgv( argc,
  644. argv,
  645. nCrtArg + 1,
  646. astrNewDrivers,
  647. bHaveNewDrivers );
  648. //
  649. // All done - all the rest of arguments have been driver names
  650. //
  651. break;
  652. }
  653. }
  654. //
  655. // If we have new drivers look if they are miniports
  656. //
  657. if( bHaveNewDrivers )
  658. {
  659. VrfAddMiniports( astrNewDrivers );
  660. }
  661. }
  662. /////////////////////////////////////////////////////////////////////////////
  663. //
  664. // Everything that follows after /driver, /adddriver, /removedriver
  665. // should be driver names. Extract these from the command line
  666. //
  667. VOID CmdLineGetDriversFromArgv( INT argc,
  668. TCHAR *argv[],
  669. INT nFirstDriverArgIndex,
  670. CStringArray &astrNewDrivers,
  671. BOOL &bHaveNewDrivers )
  672. {
  673. INT nDriverArg;
  674. bHaveNewDrivers = FALSE;
  675. astrNewDrivers.RemoveAll();
  676. //
  677. // Everything in the command line from here on should be driver names
  678. //
  679. for( nDriverArg = nFirstDriverArgIndex; nDriverArg < argc; nDriverArg += 1 )
  680. {
  681. astrNewDrivers.Add( argv[ nDriverArg ] );
  682. }
  683. bHaveNewDrivers = ( astrNewDrivers.GetSize() > 0 );
  684. }