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.

621 lines
19 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. Whoami.cpp
  5. Abstract:
  6. This file can be used to get the information of user name, groups
  7. with the respective security identifiers (SID), privileges, logon
  8. identifier (logon ID) in the current access token on a local system
  9. or a remote system.
  10. Authors:
  11. Christophe Robert
  12. Revision History:
  13. 02-July-2001 : Updated by Wipro Technologies.
  14. --*/
  15. //common header files needed for this file
  16. #include "pch.h"
  17. #include "CommonHeaderFiles.h"
  18. DWORD __cdecl
  19. wmain(
  20. IN DWORD argc,
  21. IN LPCWSTR argv[]
  22. )
  23. /*++
  24. Routine Description:
  25. This is the main entry for this utility. This function reads the input from
  26. console and calls the appropriate functions to achieve the functionality.
  27. Arguments:
  28. [IN] argc : Command line argument count
  29. [IN] argv : Command line argument
  30. Return Value:
  31. EXIT_FAILURE : On failure
  32. EXIT_SUCCESS : On success
  33. --*/
  34. {
  35. // class instance
  36. WsUser User ;
  37. // Local variables
  38. BOOL bUser = FALSE;
  39. BOOL bGroups = FALSE;
  40. BOOL bPriv = FALSE;
  41. BOOL bLogonId = FALSE;
  42. BOOL bSid = FALSE;
  43. BOOL bAll = FALSE;
  44. BOOL bUsage = FALSE;
  45. BOOL bUpn = FALSE;
  46. BOOL bFqdn = FALSE;
  47. BOOL bFlag = FALSE;
  48. DWORD dwCount = 0 ;
  49. DWORD dwRetVal = 0 ;
  50. DWORD dwFormatType = 0 ;
  51. DWORD dwNameFormat = 0 ;
  52. BOOL bResult = 0;
  53. DWORD dwFormatActuals = 0;
  54. BOOL bNoHeader = FALSE;
  55. WCHAR wszFormat[ MAX_STRING_LENGTH ];
  56. SecureZeroMemory ( wszFormat, SIZE_OF_ARRAY(wszFormat) );
  57. //check for empty arguments
  58. if ( NULL == argv )
  59. {
  60. SetLastError ((DWORD)ERROR_INVALID_PARAMETER );
  61. SaveLastError();
  62. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  63. return EXIT_FAILURE;
  64. }
  65. //parse command line options
  66. bResult = ProcessOptions(argc, argv, &bUser, &bGroups, &bPriv, &bLogonId, &bAll,
  67. &bUpn, &bFqdn, wszFormat, &dwFormatActuals, &bUsage, &bNoHeader );
  68. if( FALSE == bResult )
  69. {
  70. // display an error message with respect to the GetReason()
  71. //ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  72. ReleaseGlobals();
  73. return( EXIT_FAILURE );
  74. }
  75. // Check for invalid syntax
  76. if ( //( ( TRUE == bOthers ) && ( argc > 1 ) ) ||
  77. ( ( TRUE == bUsage ) && ( argc > 2 ) ) ||
  78. ( ( ( (bUser && dwCount++) || (bGroups && dwCount++) || (bLogonId && dwCount++) || (bPriv && dwCount++) ||
  79. (bAll && dwCount++) || (bUsage && dwCount++) || ( bUpn && dwCount++ ) || ( bFqdn && dwCount++ ) || ( bNoHeader && dwCount++ ) ||
  80. (dwFormatActuals && dwCount++)) && (dwCount == 0) ) &&
  81. ( argc > 1 ) ) ||
  82. ( ( (bUser && dwCount++) || (bGroups && dwCount++) || (bLogonId && dwCount++) || (bPriv && dwCount++)|| ( bUpn && dwCount++ ) || ( bFqdn && dwCount++ ) ) && (dwCount > 0 ) && ( TRUE == bAll ) ) ||
  83. ( bUpn && bFqdn) || ( bUpn && ( argc > 2 ) ) || ( bFqdn && ( argc > 2 )) || ( bLogonId && ( argc > 2 )) ||
  84. ( ( 1 == dwFormatActuals ) && ( 3 == argc )) || ( ( TRUE == bNoHeader ) && ( 1 == dwFormatActuals ) && ( 4 == argc )) )
  85. {
  86. // display an error message as .. invalid syntax specified..
  87. ShowMessage( stderr, GetResString(IDS_INVALID_SYNERROR ));
  88. ReleaseGlobals();
  89. return EXIT_FAILURE;
  90. }
  91. // if /FO option is specified
  92. if ( 1 == dwFormatActuals )
  93. {
  94. // if /FO LIST specified
  95. if( StringCompare( wszFormat , FORMAT_LIST, TRUE, 0 ) == 0 )
  96. {
  97. dwFormatType = SR_FORMAT_LIST;
  98. }
  99. // if /FO TABLE is specified
  100. else if( StringCompare ( wszFormat , FORMAT_TABLE, TRUE, 0 ) == 0 )
  101. {
  102. dwFormatType = SR_FORMAT_TABLE;
  103. }
  104. // if /FO CSV is specified
  105. else if( StringCompare ( wszFormat , FORMAT_CSV, TRUE, 0 ) == 0 )
  106. {
  107. dwFormatType = SR_FORMAT_CSV;
  108. }
  109. else // check for invalid format .. other than /LIST, /TABLE or /CSV
  110. {
  111. // display an error message as ..invalid format specified..
  112. ShowMessage ( stderr, GetResString ( IDS_INVALID_FORMAT ));
  113. ReleaseGlobals();
  114. return EXIT_FAILURE;
  115. }
  116. }
  117. else
  118. {
  119. // If /FO is not specified. Default format is TABLE
  120. dwFormatType = SR_FORMAT_TABLE;
  121. }
  122. if ((SR_FORMAT_LIST == dwFormatType) && ( TRUE == bNoHeader ) )
  123. {
  124. ShowMessage ( stderr, GetResString (IDS_NOT_NH_LIST) );
  125. ReleaseGlobals();
  126. return EXIT_FAILURE;
  127. }
  128. if ( TRUE == bNoHeader )
  129. {
  130. dwFormatType |= SR_HIDECOLUMN;
  131. }
  132. // Initialize access token , user, groups and privileges
  133. if( EXIT_SUCCESS != User.Init () ){
  134. //display an error message
  135. ShowLastErrorEx(stderr, SLE_TYPE_ERROR | SLE_SYSTEM);
  136. // release memory
  137. ReleaseGlobals();
  138. return EXIT_FAILURE ;
  139. }
  140. // if /UPN (User Pricipal Name)is specified
  141. if ( ( TRUE == bUpn ) && ( 2 == argc ) )
  142. {
  143. dwNameFormat = UPN_FORMAT;
  144. }
  145. // if /FQDN (Fully Qualified Distinguished Name) is specified
  146. else if ( ( TRUE == bFqdn ) && ( 2 == argc ))
  147. {
  148. dwNameFormat = FQDN_FORMAT;
  149. }
  150. //reset to 0
  151. dwCount = 0;
  152. // if /USER /GROUPS /PRIV or /ALL specified, set the flag to TRUE
  153. if ( ( (bUser && dwCount++) || (bGroups && dwCount++) || (bPriv && dwCount++) && ( dwCount > 1 )) || ( TRUE == bAll ) )
  154. {
  155. bFlag = TRUE;
  156. }
  157. // Display information
  158. // if /all option is specified, then set all the flags to TRUE.
  159. if( TRUE == bAll ) {
  160. // set all the flags i.e./USER, /GROUPS, /PRIV to TRUE
  161. bUser = TRUE;
  162. bGroups = TRUE ;
  163. bPriv = TRUE ;
  164. bSid = TRUE ;
  165. }
  166. // if /user option is specified
  167. if ( ( TRUE == bUser ) || (FQDN_FORMAT == dwNameFormat) || (UPN_FORMAT == dwNameFormat) )
  168. {
  169. // display the current logged-on user name
  170. dwRetVal = User.DisplayUser ( dwFormatType , dwNameFormat ) ;
  171. if ( EXIT_SUCCESS != dwRetVal )
  172. {
  173. //release memory
  174. ReleaseGlobals();
  175. return EXIT_FAILURE;
  176. }
  177. }
  178. // if /groups option is specified
  179. if( TRUE == bGroups ) {
  180. if ( TRUE == bFlag )
  181. {
  182. // display a new line
  183. ShowMessage ( stdout, L"\n");
  184. }
  185. // display the group names
  186. dwRetVal = User.DisplayGroups ( dwFormatType ) ;
  187. if ( EXIT_SUCCESS != dwRetVal )
  188. {
  189. if ( GetLastError() != E_OUTOFMEMORY )
  190. {
  191. // display an error message as .. there are no groups available..
  192. ShowMessage ( stderr, GetResString (IDS_NO_GROUPS) );
  193. }
  194. ReleaseGlobals();
  195. return EXIT_FAILURE;
  196. }
  197. }
  198. // if /logonid option is specified
  199. if( TRUE == bLogonId ) {
  200. // display LOGON ID
  201. dwRetVal = User.DisplayLogonId () ;
  202. if ( EXIT_SUCCESS != dwRetVal )
  203. {
  204. // display an error messagw with respect to GetLastError() error code
  205. ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_SYSTEM );
  206. // release memory
  207. ReleaseGlobals();
  208. return EXIT_FAILURE;
  209. }
  210. }
  211. // if /priv option is specified
  212. if( TRUE == bPriv ) {
  213. if ( TRUE == bFlag )
  214. {
  215. ShowMessage ( stdout, L"\n");
  216. }
  217. // display all privilege names
  218. dwRetVal = User.DisplayPrivileges ( dwFormatType ) ;
  219. if ( EXIT_SUCCESS != dwRetVal )
  220. {
  221. // display an error message with respect to GetLastError() error code
  222. ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_SYSTEM );
  223. //release memory
  224. ReleaseGlobals();
  225. return EXIT_FAILURE;
  226. }
  227. }
  228. // if /? option is specified
  229. if ( bUsage == TRUE )
  230. {
  231. // display the help/usage for this tool
  232. DisplayHelp() ;
  233. // release memory
  234. ReleaseGlobals();
  235. return EXIT_SUCCESS;
  236. }
  237. // if the command is "whoami.exe" .. then display the username by default
  238. // in other words.. if argument count is 1.. then display current logged-on user name
  239. if ( ( !( (bUser && dwCount++) || (bGroups && dwCount++) || (bLogonId && dwCount++) ||
  240. (bPriv && dwCount++) || (bAll && dwCount++) || (bUsage && dwCount++) ||
  241. ( bUpn && dwCount++ ) || ( bFqdn && dwCount++ ) ) && ( dwCount == 0 ) && (1 == argc)) )
  242. {
  243. dwNameFormat = USER_ONLY;
  244. // display current logged-on user name
  245. dwRetVal = User.DisplayUser ( dwFormatType, dwNameFormat ) ;
  246. if ( EXIT_SUCCESS != dwRetVal )
  247. {
  248. ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_SYSTEM );
  249. // release memory
  250. ReleaseGlobals();
  251. return EXIT_FAILURE;
  252. }
  253. }
  254. // release memory
  255. ReleaseGlobals();
  256. //retrun success
  257. return EXIT_SUCCESS;
  258. }
  259. VOID
  260. DisplayHelp (
  261. VOID
  262. )
  263. /*++
  264. Routine Description:
  265. This function displays the help/usage for this utility.
  266. Arguments:
  267. None
  268. Return Value:
  269. None
  270. --*/
  271. {
  272. // sub-local variable
  273. WORD wCount = 0;
  274. // display the help/usage
  275. for ( wCount = IDS_WHOAMI_HELP_START; wCount <= IDS_WHOAMI_HELP_END ; wCount++ )
  276. {
  277. //display the help/usage
  278. ShowMessage ( stdout, GetResString ( wCount ) );
  279. }
  280. // return success
  281. return;
  282. }
  283. BOOL
  284. ProcessOptions(
  285. IN DWORD argc,
  286. IN LPCWSTR argv[],
  287. OUT BOOL *pbUser,
  288. OUT BOOL *pbGroups,
  289. OUT BOOL *pbPriv,
  290. OUT BOOL *pbLogonId,
  291. OUT BOOL *pbAll,
  292. OUT BOOL *pbUpn,
  293. OUT BOOL *pbFqdn,
  294. OUT LPWSTR wszFormat,
  295. OUT DWORD *dwFormatActuals,
  296. OUT BOOL *pbUsage,
  297. OUT BOOL *pbNoHeader
  298. )
  299. /*++
  300. Routine Description
  301. This function processes the command line for the main options
  302. Arguments:
  303. [in] argc : Number of Command line arguments.
  304. [in] argv : Pointer to Command line arguments.
  305. [out] pbUser : Flag that indicates whether /USER option is specified or not
  306. [out] pbGroups : Flag that indicates whether /GROUPS option is specified or not
  307. [out] pbPriv : Flag that indicates whether /PRIV option is specified or not
  308. [out] pbLogonId : Flag that indicates whether /LOGONID option is specified or not
  309. [out] pbAll : Flag that indicates whether /ALL option is specified or not
  310. [out] pbUpn : Flag that indicates whether /UPN option is specified or not
  311. [out] pbFqdn : Flag that indicates whether /FQDN option is specified or not
  312. [out] wszFormat : Value for /FO option
  313. [out] dwFormatActuals : Flag that indicates whether /FO option is specified or not
  314. [out] pbUsage : Flag that indicates whether /? option is specified or not
  315. Return Value
  316. TRUE on success
  317. FALSE on failure
  318. --*/
  319. {
  320. // sub-local variables
  321. TCMDPARSER2* pcmdParser = NULL;
  322. TCMDPARSER2 cmdParserOptions[MAX_COMMANDLINE_OPTIONS];
  323. BOOL bReturn = FALSE;
  324. // command line options
  325. const WCHAR szUserOption[] = L"user";
  326. const WCHAR szGroupOption[] = L"groups";
  327. const WCHAR szLogonOpt[] = L"logonid";
  328. const WCHAR szPrivOption[] = L"priv";
  329. const WCHAR szAllOption[] = L"all";
  330. const WCHAR szUpnOption[] = L"upn";
  331. const WCHAR szFqdnOption[] = L"fqdn";
  332. const WCHAR szFormatOption[] = L"fo";
  333. const WCHAR szHelpOpt[] = L"?";
  334. const WCHAR szNoHeaderOption[] = L"nh";
  335. const WCHAR szFormatValues[] = L"table|list|csv";
  336. //
  337. // fill the commandline parser
  338. //
  339. // -? help/usage
  340. pcmdParser = cmdParserOptions + OI_USAGE;
  341. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  342. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  343. pcmdParser->pwszOptions = szHelpOpt;
  344. pcmdParser->pwszFriendlyName = NULL;
  345. pcmdParser->pwszValues = NULL;
  346. pcmdParser->dwFlags = CP2_USAGE;
  347. pcmdParser->dwCount = 1;
  348. pcmdParser->dwActuals = 0;
  349. pcmdParser->pValue = pbUsage;
  350. pcmdParser->dwLength = 0;
  351. pcmdParser->pFunction = NULL;
  352. pcmdParser->pFunctionData = NULL;
  353. pcmdParser->dwReserved = 0;
  354. pcmdParser->pReserved1 = NULL;
  355. pcmdParser->pReserved2 = NULL;
  356. pcmdParser->pReserved3 = NULL;
  357. // -user option
  358. pcmdParser = cmdParserOptions + OI_USER;
  359. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  360. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  361. pcmdParser->pwszOptions = szUserOption;
  362. pcmdParser->pwszFriendlyName = NULL;
  363. pcmdParser->pwszValues = NULL;
  364. pcmdParser->dwFlags = 0;
  365. pcmdParser->dwCount = 1;
  366. pcmdParser->dwActuals = 0;
  367. pcmdParser->pValue = pbUser;
  368. pcmdParser->dwLength = 0;
  369. pcmdParser->pFunction = NULL;
  370. pcmdParser->pFunctionData = NULL;
  371. pcmdParser->dwReserved = 0;
  372. pcmdParser->pReserved1 = NULL;
  373. pcmdParser->pReserved2 = NULL;
  374. pcmdParser->pReserved3 = NULL;
  375. // -groups option
  376. pcmdParser = cmdParserOptions + OI_GROUPS;
  377. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  378. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  379. pcmdParser->pwszOptions = szGroupOption;
  380. pcmdParser->pwszFriendlyName = NULL;
  381. pcmdParser->pwszValues = NULL;
  382. pcmdParser->dwFlags = 0;
  383. pcmdParser->dwCount = 1;
  384. pcmdParser->dwActuals = 0;
  385. pcmdParser->pValue = pbGroups;
  386. pcmdParser->dwLength = 0;
  387. pcmdParser->pFunction = NULL;
  388. pcmdParser->pFunctionData = NULL;
  389. pcmdParser->dwReserved = 0;
  390. pcmdParser->pReserved1 = NULL;
  391. pcmdParser->pReserved2 = NULL;
  392. pcmdParser->pReserved3 = NULL;
  393. // -logonid option
  394. pcmdParser = cmdParserOptions + OI_LOGONID;
  395. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  396. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  397. pcmdParser->pwszOptions = szLogonOpt;
  398. pcmdParser->pwszFriendlyName = NULL;
  399. pcmdParser->pwszValues = NULL;
  400. pcmdParser->dwFlags = 0;
  401. pcmdParser->dwCount = 1;
  402. pcmdParser->dwActuals = 0;
  403. pcmdParser->pValue = pbLogonId;
  404. pcmdParser->dwLength = 0;
  405. pcmdParser->pFunction = NULL;
  406. pcmdParser->pFunctionData = NULL;
  407. pcmdParser->dwReserved = 0;
  408. pcmdParser->pReserved1 = NULL;
  409. pcmdParser->pReserved2 = NULL;
  410. pcmdParser->pReserved3 = NULL;
  411. // -priv option
  412. pcmdParser = cmdParserOptions + OI_PRIV;
  413. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  414. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  415. pcmdParser->pwszOptions = szPrivOption;
  416. pcmdParser->pwszFriendlyName = NULL;
  417. pcmdParser->pwszValues = NULL;
  418. pcmdParser->dwFlags = 0;
  419. pcmdParser->dwCount = 1;
  420. pcmdParser->dwActuals = 0;
  421. pcmdParser->pValue = pbPriv;
  422. pcmdParser->dwLength = 0;
  423. pcmdParser->pFunction = NULL;
  424. pcmdParser->pFunctionData = NULL;
  425. pcmdParser->dwReserved = 0;
  426. pcmdParser->pReserved1 = NULL;
  427. pcmdParser->pReserved2 = NULL;
  428. pcmdParser->pReserved3 = NULL;
  429. // -all option
  430. pcmdParser = cmdParserOptions + OI_ALL;
  431. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  432. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  433. pcmdParser->pwszOptions = szAllOption;
  434. pcmdParser->pwszFriendlyName = NULL;
  435. pcmdParser->pwszValues = NULL;
  436. pcmdParser->dwFlags = 0;
  437. pcmdParser->dwCount = 1;
  438. pcmdParser->dwActuals = 0;
  439. pcmdParser->pValue = pbAll;
  440. pcmdParser->dwLength = 0;
  441. pcmdParser->pFunction = NULL;
  442. pcmdParser->pFunctionData = NULL;
  443. pcmdParser->dwReserved = 0;
  444. pcmdParser->pReserved1 = NULL;
  445. pcmdParser->pReserved2 = NULL;
  446. pcmdParser->pReserved3 = NULL;
  447. // -upn option
  448. pcmdParser = cmdParserOptions + OI_UPN;
  449. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  450. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  451. pcmdParser->pwszOptions = szUpnOption;
  452. pcmdParser->pwszFriendlyName = NULL;
  453. pcmdParser->pwszValues = NULL;
  454. pcmdParser->dwFlags = 0;
  455. pcmdParser->dwCount = 1;
  456. pcmdParser->dwActuals = 0;
  457. pcmdParser->pValue = pbUpn;
  458. pcmdParser->dwLength = 0;
  459. pcmdParser->pFunction = NULL;
  460. pcmdParser->pFunctionData = NULL;
  461. pcmdParser->dwReserved = 0;
  462. pcmdParser->pReserved1 = NULL;
  463. pcmdParser->pReserved2 = NULL;
  464. pcmdParser->pReserved3 = NULL;
  465. // -fqdn option
  466. pcmdParser = cmdParserOptions + OI_FQDN;
  467. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  468. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  469. pcmdParser->pwszOptions = szFqdnOption;
  470. pcmdParser->pwszFriendlyName = NULL;
  471. pcmdParser->pwszValues = NULL;
  472. pcmdParser->dwFlags = 0;
  473. pcmdParser->dwCount = 1;
  474. pcmdParser->dwActuals = 0;
  475. pcmdParser->pValue = pbFqdn;
  476. pcmdParser->dwLength = 0;
  477. pcmdParser->pFunction = NULL;
  478. pcmdParser->pFunctionData = NULL;
  479. pcmdParser->dwReserved = 0;
  480. pcmdParser->pReserved1 = NULL;
  481. pcmdParser->pReserved2 = NULL;
  482. pcmdParser->pReserved3 = NULL;
  483. // -fo <format>
  484. pcmdParser = cmdParserOptions + OI_FORMAT;
  485. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  486. pcmdParser->dwType = CP_TYPE_TEXT;
  487. pcmdParser->pwszOptions = szFormatOption;
  488. pcmdParser->pwszFriendlyName = NULL;
  489. pcmdParser->pwszValues = szFormatValues;
  490. pcmdParser->dwFlags = CP2_MODE_VALUES|CP2_VALUE_TRIMINPUT|CP2_VALUE_NONULL;
  491. pcmdParser->dwCount = 1;
  492. pcmdParser->dwActuals = 0;
  493. pcmdParser->pValue = wszFormat;
  494. pcmdParser->dwLength = MAX_STRING_LENGTH;
  495. pcmdParser->pFunction = NULL;
  496. pcmdParser->pFunctionData = NULL;
  497. pcmdParser->dwReserved = 0;
  498. pcmdParser->pReserved1 = NULL;
  499. pcmdParser->pReserved2 = NULL;
  500. pcmdParser->pReserved3 = NULL;
  501. // -nh
  502. pcmdParser = cmdParserOptions + OI_NOHEADER;
  503. StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
  504. pcmdParser->dwType = CP_TYPE_BOOLEAN;
  505. pcmdParser->pwszOptions = szNoHeaderOption;
  506. pcmdParser->pwszFriendlyName = NULL;
  507. pcmdParser->pwszValues = NULL;
  508. pcmdParser->dwFlags = 0;
  509. pcmdParser->dwCount = 1;
  510. pcmdParser->dwActuals = 0;
  511. pcmdParser->pValue = pbNoHeader;
  512. pcmdParser->dwLength = 0;
  513. pcmdParser->pFunction = NULL;
  514. pcmdParser->pFunctionData = NULL;
  515. pcmdParser->dwReserved = 0;
  516. pcmdParser->pReserved1 = NULL;
  517. pcmdParser->pReserved2 = NULL;
  518. pcmdParser->pReserved3 = NULL;
  519. //parse command line arguments
  520. bReturn = DoParseParam2( argc, argv, -1, SIZE_OF_ARRAY(cmdParserOptions), cmdParserOptions, 0);
  521. if( FALSE == bReturn) // Invalid commandline
  522. {
  523. //display an error message
  524. ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  525. ReleaseGlobals();
  526. return FALSE;
  527. }
  528. // check whether /FO is specified in the command line or not.
  529. pcmdParser = cmdParserOptions + OI_FORMAT;
  530. *dwFormatActuals = pcmdParser->dwActuals;
  531. //return 0
  532. return TRUE;
  533. }