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.

1503 lines
43 KiB

  1. //-----------------------------------------------------------------------//
  2. //
  3. // File: query.cpp
  4. // Created: Jan 1997
  5. // By: Martin Holladay (a-martih)
  6. // Purpose: Registry Query Support for REG.CPP
  7. // Modification History:
  8. // Created - Jan 1997 (a-martih)
  9. // Aug 1997 (John Whited) Implemented a Binary output function for
  10. // REG_BINARY
  11. // Oct 1997 (martinho) fixed output for REG_MULTI_SZ \0 delimited strings
  12. // April 1998 - MartinHo - Incremented to 1.05 for REG_MULTI_SZ bug fixes.
  13. // Correct support for displaying query REG_MULTI_SZ of. Fix AV.
  14. // April 1999 Zeyong Xu: re-design, revision -> version 2.0
  15. //
  16. //------------------------------------------------------------------------//
  17. #include "stdafx.h"
  18. #include "reg.h"
  19. //
  20. // query specific structure
  21. //
  22. typedef struct __tagRegQueryInfo
  23. {
  24. // instance level variables
  25. BOOL bShowKey;
  26. BOOL bKeyMatched;
  27. BOOL bValueNameMatched;
  28. BOOL bUpdateMatchCount;
  29. // ...
  30. DWORD dwMatchCount;
  31. } TREG_QUERY_INFO, *PTREG_QUERY_INFO;
  32. //
  33. // function prototypes
  34. //
  35. BOOL ParseQueryCmdLine( DWORD argc, LPCWSTR argv[],
  36. PTREG_PARAMS pParams, BOOL* pbUsage );
  37. LONG QueryValue( HKEY hKey,
  38. LPCWSTR pwszFullKey, LPCWSTR pwszValueName,
  39. PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo );
  40. LONG QueryEnumValues( HKEY hKey,
  41. LPCWSTR pwszFullKey,
  42. PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo );
  43. LONG QueryEnumKeys( HKEY hKey,
  44. LPCWSTR pwszFullKey,
  45. PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo );
  46. BOOL SearchData( LPBYTE pByteData, DWORD dwType,
  47. DWORD dwSize, PTREG_PARAMS pParams );
  48. BOOL ParseTypeInfo( LPCWSTR pwszTypes, PTREG_PARAMS pParams );
  49. //
  50. // implementation
  51. //
  52. //-----------------------------------------------------------------------//
  53. //
  54. // QueryRegistry()
  55. //
  56. //-----------------------------------------------------------------------//
  57. LONG
  58. QueryRegistry( DWORD argc, LPCWSTR argv[] )
  59. /*++
  60. Routine Description:
  61. Main function for QUERY option which calls appropriate functions
  62. Arguments:
  63. None
  64. Return Value:
  65. ERROR_SUCCESS on success
  66. EXIT_FAILURE on failure
  67. --*/
  68. {
  69. // local variables
  70. LONG lResult = 0;
  71. HKEY hKey = NULL;
  72. BOOL bResult = FALSE;
  73. BOOL bUsage = FALSE;
  74. TREG_PARAMS params;
  75. DWORD dwExitCode = 0;
  76. TREG_QUERY_INFO info;
  77. BOOL bSearchMessage = FALSE;
  78. if ( argc == 0 || argv == NULL )
  79. {
  80. SetLastError( ERROR_INVALID_PARAMETER );
  81. ShowLastError( stderr );
  82. return 1;
  83. }
  84. // initialize the global data structure
  85. InitGlobalData( REG_QUERY, &params );
  86. //
  87. // Parse the cmd-line
  88. //
  89. bResult = ParseQueryCmdLine( argc, argv, &params, &bUsage );
  90. if ( bResult == FALSE )
  91. {
  92. ShowLastErrorEx( stderr, SLE_INTERNAL );
  93. FreeGlobalData( &params );
  94. return 1;
  95. }
  96. // check whether we need to display the usage
  97. if ( bUsage == TRUE )
  98. {
  99. Usage( REG_QUERY );
  100. FreeGlobalData( &params );
  101. return 0;
  102. }
  103. //
  104. // Connect to the Remote Machine(s) - if applicable
  105. //
  106. bResult = RegConnectMachine( &params );
  107. if( bResult == FALSE )
  108. {
  109. SaveErrorMessage( -1 );
  110. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  111. FreeGlobalData( &params );
  112. return 1;
  113. }
  114. //
  115. // Open the registry key
  116. //
  117. lResult = RegOpenKeyEx( params.hRootKey,
  118. params.pwszSubKey, 0, KEY_READ, &hKey );
  119. if( lResult != ERROR_SUCCESS)
  120. {
  121. SaveErrorMessage( lResult );
  122. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  123. FreeGlobalData( &params );
  124. return 1;
  125. }
  126. // show a blank line below starting the output
  127. ShowMessage( stdout, L"\n" );
  128. //
  129. // do the query
  130. //
  131. ZeroMemory( &info, sizeof( TREG_QUERY_INFO ) );
  132. if( params.pwszSearchData == NULL &&
  133. params.pwszValueName != NULL &&
  134. params.arrTypes == NULL &&
  135. params.bRecurseSubKeys == FALSE )
  136. {
  137. info.bShowKey = TRUE;
  138. if ( params.pwszValueName != NULL &&
  139. ( StringLength( params.pwszValueName, 0 ) == 0 ||
  140. FindOneOf2( params.pwszValueName, L"*?", TRUE, 0 ) == -1 ) )
  141. {
  142. lResult = QueryValue( hKey,
  143. params.pwszFullKey, params.pwszValueName, &params, &info );
  144. bSearchMessage = FALSE;
  145. ShowMessage( stdout, L"\n" );
  146. }
  147. else
  148. {
  149. bSearchMessage = TRUE;
  150. lResult = QueryEnumValues( hKey, params.pwszFullKey, &params, &info );
  151. }
  152. }
  153. else
  154. {
  155. info.bShowKey = TRUE;
  156. lResult = QueryEnumKeys( hKey, params.pwszFullKey, &params, &info );
  157. // determine the kind of success message that needs to be displayed
  158. bSearchMessage = ! ( params.pwszSearchData == NULL &&
  159. params.pwszValueName == NULL && params.arrTypes == NULL );
  160. }
  161. dwExitCode = 0;
  162. if ( lResult == ERROR_SUCCESS )
  163. {
  164. if ( bSearchMessage == FALSE )
  165. {
  166. //
  167. // BUG: 698877 Reg.exe: Need to turn off newly-added success messages to avoid breaking scripts
  168. // that parse output
  169. //
  170. // SaveErrorMessage( ERROR_SUCCESS );
  171. // ShowLastErrorEx( stdout, SLE_INTERNAL );
  172. //
  173. }
  174. else
  175. {
  176. if ( info.dwMatchCount == 0 )
  177. {
  178. dwExitCode = 1;
  179. }
  180. // ...
  181. ShowMessageEx( stdout, 1, TRUE, STATISTICS_QUERY, info.dwMatchCount );
  182. }
  183. }
  184. else
  185. {
  186. dwExitCode = 1;
  187. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  188. }
  189. // release the handle
  190. SafeCloseKey( &hKey );
  191. // return the error code
  192. return dwExitCode;
  193. }
  194. //------------------------------------------------------------------------//
  195. //
  196. // ParseQueryCmdLine()
  197. //
  198. //------------------------------------------------------------------------//
  199. BOOL
  200. ParseQueryCmdLine( DWORD argc,
  201. LPCWSTR argv[],
  202. PTREG_PARAMS pParams, BOOL* pbUsage )
  203. /*++
  204. Routine Description:
  205. Parse the command line arguments
  206. Arguments:
  207. None
  208. Return Value:
  209. REG_STATUS
  210. --*/
  211. {
  212. //
  213. // local variables
  214. DWORD dw = 0;
  215. DWORD dwLength = 0;
  216. LPCWSTR pwszTemp = NULL;
  217. LPCWSTR pwszSearchData = NULL;
  218. // query parser result trackers
  219. LONG lResult = 0;
  220. BOOL bResult = FALSE;
  221. // query operation validators
  222. BOOL bHasSeparator = FALSE;
  223. //
  224. // implementation starts from here
  225. //
  226. // check the input
  227. if ( argc == 0 || argv == NULL || pParams == NULL || pbUsage == NULL )
  228. {
  229. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  230. return FALSE;
  231. }
  232. // check whether this function is being called for
  233. // valid operation or not
  234. if ( pParams->lOperation < 0 || pParams->lOperation >= REG_OPTIONS_COUNT )
  235. {
  236. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  237. return FALSE;
  238. }
  239. //
  240. // Do we have a *valid* number of cmd-line params
  241. //
  242. if( argc < 3 || argc > 12 )
  243. {
  244. SetLastError( (DWORD) MK_E_SYNTAX );
  245. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_QUERY ] );
  246. return FALSE;
  247. }
  248. else if ( StringCompareEx( argv[ 1 ], L"QUERY", TRUE, 0 ) != 0 )
  249. {
  250. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  251. return FALSE;
  252. }
  253. else if( InString( argv[ 2 ], L"/?|-?|/h|-h", TRUE ) == TRUE )
  254. {
  255. if ( argc == 3 )
  256. {
  257. *pbUsage = TRUE;
  258. return TRUE;
  259. }
  260. else
  261. {
  262. SetLastError( (DWORD) MK_E_SYNTAX );
  263. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_QUERY ] );
  264. return FALSE;
  265. }
  266. }
  267. // Machine Name and Registry key
  268. //
  269. bResult = BreakDownKeyString( argv[ 2 ], pParams );
  270. if( bResult == FALSE )
  271. {
  272. return FALSE;
  273. }
  274. // parsing the command line arguments
  275. bResult = TRUE;
  276. lResult = ERROR_SUCCESS;
  277. pParams->dwSearchFlags = 0;
  278. pParams->bExactMatch = FALSE;
  279. pParams->bCaseSensitive = FALSE;
  280. pParams->bRecurseSubKeys = FALSE;
  281. pParams->bShowTypeNumber = FALSE;
  282. for( dw = 3; dw < argc; dw++ )
  283. {
  284. // /f -- search the registry
  285. if( StringCompareEx( argv[ dw ], L"/f", TRUE, 0 ) == 0 )
  286. {
  287. if ( pwszSearchData != NULL )
  288. {
  289. bResult = FALSE;
  290. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  291. break;
  292. }
  293. // ...
  294. dw++;
  295. if( dw < argc )
  296. {
  297. pwszSearchData = argv[ dw ];
  298. }
  299. else
  300. {
  301. bResult = FALSE;
  302. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  303. break;
  304. }
  305. }
  306. // /k -- searches the REGISTRY KEYS
  307. else if ( StringCompareEx( argv[ dw ], L"/k", TRUE, 0 ) == 0 )
  308. {
  309. if ( pParams->dwSearchFlags & REG_FIND_KEYS )
  310. {
  311. // /k is already specified
  312. bResult = FALSE;
  313. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  314. break;
  315. }
  316. // ...
  317. pParams->dwSearchFlags |= REG_FIND_KEYS;
  318. }
  319. // /v -- searches/displays contents of the specific value names
  320. else if( StringCompareEx( argv[ dw ], L"/v", TRUE, 0 ) == 0 )
  321. {
  322. if( pParams->pwszValueName != NULL ||
  323. (pParams->dwSearchFlags & REG_FIND_VALUENAMES) )
  324. {
  325. bResult = FALSE;
  326. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  327. break;
  328. }
  329. if( dw + 1 < argc )
  330. {
  331. // determine the length of the current argument
  332. dwLength = StringLength( argv[ dw + 1 ], 0 );
  333. // since the value for the /v switch is optional,
  334. // we need to see if the user specified the next switch
  335. // or data to this switch
  336. if ( dwLength < 2 ||
  337. argv[ dw + 1 ][ 0 ] != L'/' ||
  338. InString( argv[ dw + 1 ] + 1, L"z|ve|f|k|d|c|e|s|t|se", TRUE ) == FALSE )
  339. {
  340. // get the value for /v
  341. dw++;
  342. dwLength++;
  343. pParams->pwszValueName = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) );
  344. if ( pParams->pwszValueName == NULL )
  345. {
  346. lResult = ERROR_OUTOFMEMORY;
  347. break;
  348. }
  349. // ...
  350. StringCopy( pParams->pwszValueName, argv[ dw ], dwLength );
  351. }
  352. }
  353. else
  354. {
  355. // since the value for the /v is optional
  356. // this is a valid condition
  357. }
  358. // if the /v is specified and no memory is allocated for the buffer
  359. if ( pParams->pwszValueName == NULL )
  360. {
  361. // set the flag
  362. pParams->dwSearchFlags |= REG_FIND_VALUENAMES;
  363. }
  364. }
  365. // /ve -- displays the data for empty value name "(Default)"
  366. else if( StringCompareEx( argv[ dw ], L"/ve", TRUE, 0 ) == 0 )
  367. {
  368. if( pParams->pwszValueName != NULL ||
  369. (pParams->dwSearchFlags & REG_FIND_VALUENAMES) )
  370. {
  371. bResult = FALSE;
  372. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  373. break;
  374. }
  375. pParams->pwszValueName = (LPWSTR) AllocateMemory( 2 * sizeof( WCHAR ) );
  376. if ( pParams->pwszValueName == NULL)
  377. {
  378. lResult = ERROR_OUTOFMEMORY;
  379. break;
  380. }
  381. }
  382. // /d -- searches the DATA field of the REGISTRY
  383. else if ( StringCompareEx( argv[ dw ], L"/d", TRUE, 0 ) == 0 )
  384. {
  385. if ( pParams->dwSearchFlags & REG_FIND_DATA )
  386. {
  387. // /d is already specified
  388. bResult = FALSE;
  389. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  390. break;
  391. }
  392. // ...
  393. pParams->dwSearchFlags |= REG_FIND_DATA;
  394. }
  395. // /c -- case sensitive search
  396. else if( StringCompareEx( argv[ dw ], L"/c", TRUE, 0 ) == 0 )
  397. {
  398. if ( pParams->bCaseSensitive == TRUE )
  399. {
  400. bResult = FALSE;
  401. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  402. break;
  403. }
  404. // ...
  405. pParams->bCaseSensitive = TRUE;
  406. }
  407. // /e -- exact text match
  408. else if( StringCompareEx( argv[ dw ], L"/e", TRUE, 0 ) == 0 )
  409. {
  410. if ( pParams->bExactMatch == TRUE )
  411. {
  412. bResult = FALSE;
  413. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  414. break;
  415. }
  416. // ...
  417. pParams->bExactMatch = TRUE;
  418. }
  419. // /z -- show the type number along with the text
  420. else if ( StringCompareEx( argv[ dw ], L"/z", TRUE, 0 ) == 0 )
  421. {
  422. if ( pParams->bShowTypeNumber == TRUE )
  423. {
  424. bResult = FALSE;
  425. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  426. break;
  427. }
  428. // ...
  429. pParams->bShowTypeNumber = TRUE;
  430. }
  431. // /s -- recursive search/display
  432. else if( StringCompareEx( argv[ dw ], L"/s", TRUE, 0 ) == 0 )
  433. {
  434. if( pParams->bRecurseSubKeys == TRUE )
  435. {
  436. bResult = FALSE;
  437. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  438. break;
  439. }
  440. pParams->bRecurseSubKeys = TRUE;
  441. }
  442. // /se -- seperator to display for REG_MULTI_SZ valuename type
  443. else if( StringCompareEx( argv[ dw ], L"/se", TRUE, 0 ) == 0 )
  444. {
  445. if( bHasSeparator == TRUE )
  446. {
  447. bResult = FALSE;
  448. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  449. break;
  450. }
  451. dw++;
  452. if( dw < argc )
  453. {
  454. if( StringLength( argv[ dw ], 0 ) == 1 )
  455. {
  456. bHasSeparator = TRUE;
  457. StringCopy( pParams->wszSeparator,
  458. argv[ dw ], SIZE_OF_ARRAY( pParams->wszSeparator ) );
  459. }
  460. else
  461. {
  462. bResult = FALSE;
  463. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  464. break;
  465. }
  466. }
  467. else
  468. {
  469. bResult = FALSE;
  470. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  471. break;
  472. }
  473. }
  474. // /t -- REGISTRY value type that only needs to be shown
  475. else if( StringCompareEx( argv[ dw ], L"/t", TRUE, 0 ) == 0 )
  476. {
  477. if ( pParams->arrTypes != NULL )
  478. {
  479. bResult = FALSE;
  480. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  481. break;
  482. }
  483. dw++;
  484. if( dw < argc )
  485. {
  486. if ( ParseTypeInfo( argv[ dw ], pParams ) == FALSE )
  487. {
  488. if ( GetLastError() == (DWORD) MK_E_SYNTAX )
  489. {
  490. bResult = FALSE;
  491. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  492. break;
  493. }
  494. else
  495. {
  496. bResult = TRUE;
  497. lResult = GetLastError();
  498. break;
  499. }
  500. }
  501. }
  502. else
  503. {
  504. bResult = FALSE;
  505. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  506. break;
  507. }
  508. }
  509. // default -- invalid
  510. else
  511. {
  512. bResult = FALSE;
  513. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  514. break;
  515. }
  516. }
  517. //
  518. // validate the search information specified
  519. if ( lResult == ERROR_SUCCESS )
  520. {
  521. if ( pwszSearchData == NULL )
  522. {
  523. if ( pParams->dwSearchFlags != 0 ||
  524. pParams->bExactMatch == TRUE ||
  525. pParams->bCaseSensitive == TRUE )
  526. {
  527. bResult = FALSE;
  528. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  529. }
  530. }
  531. else if ( pParams->dwSearchFlags == 0 )
  532. {
  533. if ( pParams->pwszValueName == NULL )
  534. {
  535. pParams->dwSearchFlags = REG_FIND_ALL;
  536. }
  537. else
  538. {
  539. pParams->dwSearchFlags = REG_FIND_KEYS | REG_FIND_DATA;
  540. }
  541. }
  542. }
  543. // prepare the final search pattern
  544. if ( pwszSearchData != NULL && lResult == ERROR_SUCCESS )
  545. {
  546. // determine the length of the search pattern
  547. dwLength = StringLength( pwszSearchData, 0 );
  548. if ( pParams->bExactMatch == FALSE )
  549. {
  550. dwLength += 2;
  551. }
  552. // accomodate space for null characters
  553. dwLength++;
  554. // allocate memory
  555. pParams->pwszSearchData = AllocateMemory( (dwLength + 2) * sizeof( WCHAR ) );
  556. if ( pParams->pwszSearchData == NULL )
  557. {
  558. lResult = ERROR_OUTOFMEMORY;
  559. }
  560. else
  561. {
  562. // if the /e is not specified -- we will search for "*<text>*"
  563. // otherwise if /e is specified we will search exactly for "<text>"
  564. // where "<text>" is what is specified by user at the command prompt
  565. StringCopy( pParams->pwszSearchData, L"", dwLength );
  566. if ( pParams->bExactMatch == FALSE )
  567. {
  568. StringCopy( pParams->pwszSearchData, L"*", dwLength );
  569. }
  570. // ...
  571. StringConcat( pParams->pwszSearchData, pwszSearchData, dwLength );
  572. // ...
  573. if ( pParams->bExactMatch == FALSE )
  574. {
  575. StringConcat( pParams->pwszSearchData, L"*", dwLength );
  576. }
  577. }
  578. }
  579. //
  580. // if /t is specified, then /s needs to be specified
  581. // if /s is not specified, then atleast /v or /ve should not be specified
  582. //
  583. // if ( lResult == ERROR_SUCCESS && pParams->arrTypes != NULL &&
  584. // pParams->bRecurseSubKeys == FALSE && pParams->pwszValueName != NULL )
  585. // {
  586. // bResult = FALSE;
  587. // lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  588. // }
  589. //
  590. // parse the pattern information if specified by user and store only
  591. // the optimized version of it
  592. //
  593. if ( lResult == ERROR_SUCCESS )
  594. {
  595. //
  596. // value name
  597. //
  598. if ( pParams->pwszValueName != NULL &&
  599. StringLength( pParams->pwszValueName, 0 ) != 0 )
  600. {
  601. pwszTemp = ParsePattern( pParams->pwszValueName );
  602. if ( pwszTemp == NULL )
  603. {
  604. lResult = GetLastError();
  605. }
  606. // copy the optimized pattern into the original buffer
  607. dw = GetBufferSize( pParams->pwszValueName );
  608. StringCopy( pParams->pwszValueName, pwszTemp, dw );
  609. }
  610. //
  611. // search data
  612. //
  613. if ( pParams->pwszSearchData != NULL )
  614. {
  615. pwszTemp = ParsePattern( pParams->pwszSearchData );
  616. if ( pwszTemp == NULL )
  617. {
  618. lResult = GetLastError();
  619. }
  620. // copy the optimized pattern into the original buffer
  621. dw = GetBufferSize( pParams->pwszSearchData );
  622. StringCopy( pParams->pwszSearchData, pwszTemp, dw );
  623. }
  624. }
  625. //
  626. // check the end result
  627. //
  628. if( lResult != ERROR_SUCCESS )
  629. {
  630. if( bResult == FALSE )
  631. {
  632. SetLastError( (DWORD) MK_E_SYNTAX );
  633. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_QUERY ] );
  634. }
  635. else
  636. {
  637. SaveErrorMessage( lResult );
  638. }
  639. }
  640. else
  641. {
  642. }
  643. // return the result
  644. return (lResult == ERROR_SUCCESS);
  645. }
  646. //-----------------------------------------------------------------------//
  647. //
  648. // QueryValue()
  649. //
  650. //-----------------------------------------------------------------------//
  651. LONG
  652. QueryValue( HKEY hKey,
  653. LPCWSTR pwszFullKey,
  654. LPCWSTR pwszValueName,
  655. PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo )
  656. {
  657. // local variables
  658. LONG lResult = 0;
  659. DWORD dwType = 0;
  660. DWORD dwLength = 0;
  661. PBYTE pByteData = NULL;
  662. TREG_SHOW_INFO showinfo;
  663. BOOL bDataMatched = FALSE;
  664. // check the input
  665. if ( hKey == NULL || pwszFullKey == NULL ||
  666. pwszValueName == NULL || pParams == NULL || pInfo == NULL )
  667. {
  668. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  669. lResult = ERROR_INVALID_PARAMETER;
  670. goto cleanup;
  671. }
  672. // get the size of the buffer to hold the value associated with the value name
  673. lResult = RegQueryValueEx( hKey, pwszValueName, NULL, NULL, NULL, &dwLength );
  674. if ( lResult != ERROR_SUCCESS )
  675. {
  676. // special case -- "(Default)" value
  677. if ( lResult == ERROR_FILE_NOT_FOUND &&
  678. StringLength( pwszValueName, 0 ) == 0 )
  679. {
  680. dwLength = StringLength( GetResString2( IDS_VALUENOTSET, 0 ), 0 ) + 1;
  681. dwLength *= sizeof( WCHAR );
  682. }
  683. else
  684. {
  685. SaveErrorMessage( lResult );
  686. goto cleanup;
  687. }
  688. }
  689. //
  690. // to handle the corrupted registry data properly, adjust the memory
  691. // allocation size which is divisible by 2
  692. //
  693. dwLength += (dwLength % 2);
  694. // allocate the buffer
  695. pByteData = (LPBYTE) AllocateMemory( (dwLength + 2) * sizeof( BYTE ) );
  696. if ( pByteData == NULL )
  697. {
  698. SaveErrorMessage( ERROR_OUTOFMEMORY );
  699. lResult = ERROR_OUTOFMEMORY;
  700. goto cleanup;
  701. }
  702. // now get the data
  703. lResult = RegQueryValueEx( hKey, pwszValueName, NULL, &dwType, pByteData, &dwLength );
  704. if ( lResult != ERROR_SUCCESS )
  705. {
  706. // special case -- "(Default)" value
  707. if ( lResult == ERROR_FILE_NOT_FOUND &&
  708. StringLength( pwszValueName, 0 ) == 0 )
  709. {
  710. dwType = REG_SZ;
  711. StringCopy( (LPWSTR) pByteData,
  712. GetResString2( IDS_VALUENOTSET, 0 ), dwLength / sizeof( WCHAR ));
  713. }
  714. else
  715. {
  716. SaveErrorMessage( lResult );
  717. goto cleanup;
  718. }
  719. }
  720. // check whether the data matches with the search pattern specified
  721. bDataMatched = TRUE; // default
  722. if ( pInfo->bValueNameMatched == FALSE )
  723. {
  724. if ( pParams->dwSearchFlags & REG_FIND_DATA )
  725. {
  726. bDataMatched = SearchData( pByteData, dwType, dwLength, pParams );
  727. if ( bDataMatched == TRUE )
  728. {
  729. pInfo->dwMatchCount++;
  730. }
  731. }
  732. }
  733. // check the result of the search
  734. if ( bDataMatched == FALSE )
  735. {
  736. SetLastError( ERROR_NOT_FOUND );
  737. lResult = ERROR_SUCCESS;
  738. goto cleanup;
  739. }
  740. // if the bUpdateMatchCount flag is set -- increment the matched
  741. // count by 1 and reset the flag
  742. if ( pInfo->bUpdateMatchCount == TRUE )
  743. {
  744. if ( pParams->pwszValueName == NULL && pParams->arrTypes == NULL )
  745. {
  746. pInfo->dwMatchCount++;
  747. }
  748. // ...
  749. pInfo->bUpdateMatchCount = FALSE;
  750. }
  751. // show the full key -- if needed
  752. if ( pInfo->bShowKey == TRUE )
  753. {
  754. // display the key path for which query proceeds
  755. ShowMessageEx( stdout, 1, TRUE, L"%s\n", pwszFullKey );
  756. // flag off -- this will block from display the full key for each value
  757. pInfo->bShowKey = FALSE;
  758. }
  759. // update the match count -- if needed
  760. if ( pParams->pwszValueName != NULL || pParams->arrTypes != NULL )
  761. {
  762. pInfo->dwMatchCount++;
  763. }
  764. // init to ZERO
  765. ZeroMemory( &showinfo, sizeof( TREG_SHOW_INFO ) );
  766. // set the data
  767. showinfo.pwszValueName = pwszValueName;
  768. showinfo.dwType = dwType;
  769. showinfo.pByteData = pByteData;
  770. showinfo.pwszSeparator = L" ";
  771. showinfo.dwMaxValueNameLength = 0;
  772. showinfo.dwPadLength = 4;
  773. showinfo.dwSize = dwLength;
  774. showinfo.pwszMultiSzSeparator = pParams->wszSeparator;
  775. if ( pParams->bShowTypeNumber == TRUE )
  776. {
  777. showinfo.dwFlags |= RSI_SHOWTYPENUMBER;
  778. }
  779. // show
  780. ShowRegistryValue( &showinfo );
  781. // end result
  782. lResult = ERROR_SUCCESS;
  783. cleanup:
  784. // release the memory
  785. FreeMemory( &pByteData );
  786. // return
  787. return lResult;
  788. }
  789. LONG
  790. QueryEnumValues( HKEY hKey,
  791. LPCWSTR pwszFullKey,
  792. PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo )
  793. /*++
  794. Routine Description:
  795. Queries Values and Data
  796. Arguments:
  797. None
  798. Return Value:
  799. ERROR_SUCCESS on success
  800. EXIT_FAILURE on failure
  801. --*/
  802. {
  803. // local variables
  804. DWORD dw = 0;
  805. LONG lResult = 0;
  806. DWORD dwType = 0;
  807. DWORD dwLength = 0;
  808. DWORD dwMaxLength = 0;
  809. DWORD dwValueNames = 0;
  810. LPWSTR pwszValueName = NULL;
  811. // check the input
  812. if ( hKey == NULL || pwszFullKey == NULL || pParams == NULL || pInfo == NULL )
  813. {
  814. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  815. return ERROR_INVALID_PARAMETER;
  816. }
  817. //
  818. // First find out how much memory to allocate.
  819. //
  820. lResult = RegQueryInfoKey( hKey,
  821. NULL, NULL, NULL, NULL, NULL, NULL,
  822. &dwValueNames, &dwMaxLength, NULL, NULL, NULL );
  823. if ( lResult != ERROR_SUCCESS )
  824. {
  825. SaveErrorMessage( lResult );
  826. return lResult;
  827. }
  828. //
  829. // do the memory allocations
  830. //
  831. // value name
  832. dwMaxLength++;
  833. pwszValueName = (LPWSTR) AllocateMemory( dwMaxLength * sizeof( WCHAR ) );
  834. if ( pwszValueName == NULL )
  835. {
  836. SaveErrorMessage( ERROR_OUTOFMEMORY );
  837. return lResult;
  838. }
  839. //
  840. // enumerate the value names and display
  841. //
  842. lResult = ERROR_SUCCESS;
  843. for( dw = 0; dw < dwValueNames; dw++ )
  844. {
  845. dwLength = dwMaxLength;
  846. ZeroMemory( pwszValueName, dwLength * sizeof( WCHAR ) );
  847. lResult = RegEnumValue( hKey, dw,
  848. pwszValueName, &dwLength, NULL, &dwType, NULL, NULL );
  849. if ( lResult != ERROR_SUCCESS )
  850. {
  851. SaveErrorMessage( lResult );
  852. break;
  853. }
  854. // check if user is looking for any explicit value name
  855. // this will improve the performance of the tool
  856. if ( pParams->pwszValueName != NULL &&
  857. MatchPatternEx( pwszValueName,
  858. pParams->pwszValueName,
  859. PATTERN_COMPARE_IGNORECASE | PATTERN_NOPARSING ) == FALSE )
  860. {
  861. // skip processing this value name
  862. continue;
  863. }
  864. // filter on type information
  865. if ( pParams->arrTypes != NULL &&
  866. DynArrayFindLongEx( pParams->arrTypes, 1, dwType ) == -1 )
  867. {
  868. // skip processing this value names
  869. continue;
  870. }
  871. // search for the pattern -- if needed
  872. pInfo->bValueNameMatched = TRUE; // default
  873. if ( pParams->dwSearchFlags & REG_FIND_VALUENAMES )
  874. {
  875. pInfo->bValueNameMatched = SearchData(
  876. (BYTE*) pwszValueName, REG_SZ, dwLength * sizeof( WCHAR ), pParams );
  877. if ( pInfo->bValueNameMatched == FALSE )
  878. {
  879. if ( pParams->dwSearchFlags == REG_FIND_VALUENAMES )
  880. {
  881. // user just want to search in the value names
  882. // since the current didn't match skip this valuename
  883. continue;
  884. }
  885. }
  886. else
  887. {
  888. if ( pParams->pwszValueName == NULL && pParams->arrTypes == NULL )
  889. {
  890. pInfo->dwMatchCount++;
  891. }
  892. }
  893. }
  894. else if ( pParams->dwSearchFlags != 0 &&
  895. pParams->pwszValueName == NULL && pParams->arrTypes == NULL )
  896. {
  897. pInfo->bValueNameMatched = FALSE;
  898. }
  899. // process the value of this regisry valuename
  900. if ( pInfo->bValueNameMatched == TRUE ||
  901. pParams->dwSearchFlags == 0 || pParams->dwSearchFlags & REG_FIND_DATA )
  902. {
  903. lResult = QueryValue( hKey, pwszFullKey, pwszValueName, pParams, pInfo );
  904. }
  905. }
  906. // show the new line at the end -- only if needed
  907. if ( pInfo->bShowKey == FALSE )
  908. {
  909. ShowMessage( stdout, L"\n" );
  910. }
  911. // release the memory
  912. FreeMemory( &pwszValueName );
  913. // return
  914. return lResult;
  915. }
  916. LONG
  917. QueryEnumKeys( HKEY hKey,
  918. LPCWSTR pwszFullKey,
  919. PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo )
  920. /*++
  921. Routine Description:
  922. Queries Values and Data
  923. Arguments:
  924. None
  925. Return Value:
  926. ERROR_SUCCESS on success
  927. EXIT_FAILURE on failure
  928. --*/
  929. {
  930. // local variables
  931. DWORD dw = 0;
  932. LONG lResult = 0;
  933. DWORD dwLength = 0;
  934. DWORD dwSubKeys = 0;
  935. DWORD dwMaxLength = 0;
  936. HKEY hSubKey = NULL;
  937. DWORD dwNewFullKeyLength = 0;
  938. LPWSTR pwszSubKey = NULL;
  939. LPWSTR pwszNewFullKey = NULL;
  940. // check the input
  941. if ( hKey == NULL ||
  942. pwszFullKey == NULL ||
  943. pParams == NULL || pInfo == NULL )
  944. {
  945. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  946. lResult = ERROR_INVALID_PARAMETER;
  947. goto cleanup;
  948. }
  949. // show the values under the current hive first
  950. // NOTE: enumerate the values only when /F is not specified
  951. // or subkey is matched or search flags specify to search in
  952. // value names and/or data also
  953. if ( pInfo->bKeyMatched == TRUE &&
  954. pParams->dwSearchFlags == REG_FIND_KEYS &&
  955. pParams->pwszValueName == NULL && pParams->arrTypes == NULL )
  956. {
  957. // do nothing
  958. }
  959. else if ( pParams->dwSearchFlags == 0 ||
  960. pParams->dwSearchFlags != REG_FIND_KEYS ||
  961. (pInfo->bKeyMatched == TRUE && (pParams->pwszValueName != NULL || pParams->arrTypes != NULL)) )
  962. {
  963. lResult = QueryEnumValues( hKey, pwszFullKey, pParams, pInfo );
  964. if ( lResult != ERROR_SUCCESS )
  965. {
  966. goto cleanup;
  967. }
  968. }
  969. //
  970. // First find out how much memory to allocate.
  971. //
  972. lResult = RegQueryInfoKey( hKey, NULL, NULL, NULL,
  973. &dwSubKeys, &dwMaxLength, NULL, NULL, NULL, NULL, NULL, NULL );
  974. if ( lResult != ERROR_SUCCESS )
  975. {
  976. SaveErrorMessage( lResult );
  977. goto cleanup;
  978. }
  979. //
  980. // SPECIAL CASE:
  981. // -------------
  982. // For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
  983. // though there are subkeys underneath this -- to handle this, we are doing a workaround
  984. // by assuming the max registry key length
  985. //
  986. if ( dwSubKeys != 0 && dwMaxLength == 0 )
  987. {
  988. dwMaxLength = 256;
  989. }
  990. else if ( dwMaxLength < 256 )
  991. {
  992. // always assume 100% more length that what is returned by the API
  993. dwMaxLength *= 2;
  994. }
  995. //
  996. // do the memory allocations
  997. //
  998. // sub key
  999. dwMaxLength++;
  1000. pwszSubKey = (LPWSTR) AllocateMemory( dwMaxLength * sizeof( WCHAR ) );
  1001. if ( pwszSubKey == NULL )
  1002. {
  1003. SaveErrorMessage( ERROR_OUTOFMEMORY );
  1004. lResult = ERROR_OUTOFMEMORY;
  1005. goto cleanup;
  1006. }
  1007. // buffer for new full key name
  1008. dwNewFullKeyLength = StringLength( pwszFullKey, 0 ) + dwMaxLength + 1;
  1009. pwszNewFullKey = (LPWSTR) AllocateMemory( dwNewFullKeyLength * sizeof( WCHAR ) );
  1010. if ( pwszNewFullKey == NULL )
  1011. {
  1012. SaveErrorMessage( ERROR_OUTOFMEMORY );
  1013. lResult = ERROR_OUTOFMEMORY;
  1014. goto cleanup;
  1015. }
  1016. //
  1017. // enumerate the value names and display
  1018. //
  1019. lResult = ERROR_SUCCESS;
  1020. for( dw = 0; dw < dwSubKeys; dw++ )
  1021. {
  1022. dwLength = dwMaxLength;
  1023. ZeroMemory( pwszSubKey, dwLength * sizeof( WCHAR ) );
  1024. lResult = RegEnumKeyEx( hKey, dw,
  1025. pwszSubKey, &dwLength, NULL, NULL, NULL, NULL );
  1026. if ( lResult != ERROR_SUCCESS )
  1027. {
  1028. // **********************************************************
  1029. // simply ignore the error here -- for a detailed description
  1030. // check the raid bug #572077
  1031. // **********************************************************
  1032. lResult = ERROR_SUCCESS;
  1033. continue;
  1034. }
  1035. // search for the pattern -- if needed
  1036. pInfo->bKeyMatched = TRUE; // default
  1037. pInfo->bUpdateMatchCount = FALSE;
  1038. if ( pParams->dwSearchFlags & REG_FIND_KEYS )
  1039. {
  1040. pInfo->bKeyMatched = SearchData(
  1041. (BYTE*) pwszSubKey, REG_SZ, dwLength * sizeof( WCHAR ), pParams );
  1042. if ( pInfo->bKeyMatched == FALSE )
  1043. {
  1044. if ( pParams->bRecurseSubKeys == FALSE &&
  1045. pParams->dwSearchFlags == REG_FIND_KEYS )
  1046. {
  1047. // user just want to search in the key names
  1048. // and there is no recursion
  1049. // since the current didn't match skip this key
  1050. continue;
  1051. }
  1052. }
  1053. else
  1054. {
  1055. pInfo->bUpdateMatchCount = TRUE;
  1056. }
  1057. }
  1058. else if ( pParams->dwSearchFlags != 0 || pParams->pwszValueName != NULL )
  1059. {
  1060. pInfo->bKeyMatched = FALSE;
  1061. }
  1062. // format the new full key name
  1063. StringCopy( pwszNewFullKey, pwszFullKey, dwNewFullKeyLength );
  1064. StringConcat( pwszNewFullKey, L"\\", dwNewFullKeyLength );
  1065. StringConcat( pwszNewFullKey, pwszSubKey, dwNewFullKeyLength );
  1066. // show the key name
  1067. pInfo->bShowKey = TRUE;
  1068. if ( pInfo->bKeyMatched == TRUE && pParams->pwszValueName == NULL && pParams->arrTypes == NULL )
  1069. {
  1070. // update the match count
  1071. pInfo->dwMatchCount++;
  1072. pInfo->bUpdateMatchCount = FALSE;
  1073. // ...
  1074. pInfo->bShowKey = FALSE;
  1075. ShowMessageEx( stdout, 1, TRUE, L"%s\n", pwszNewFullKey );
  1076. }
  1077. // check whether we need to recurse or not
  1078. if ( pParams->bRecurseSubKeys == TRUE )
  1079. {
  1080. lResult = RegOpenKeyEx( hKey, pwszSubKey, 0, KEY_READ, &hSubKey );
  1081. if ( lResult == ERROR_SUCCESS )
  1082. {
  1083. // enumerate the sub-keys
  1084. lResult = QueryEnumKeys( hSubKey, pwszNewFullKey, pParams, pInfo );
  1085. // close the sub key
  1086. SafeCloseKey( &hSubKey );
  1087. }
  1088. else
  1089. {
  1090. // **********************************************************
  1091. // simply ignore the error here -- for a detailed description
  1092. // check the raid bug #572077
  1093. // **********************************************************
  1094. lResult = ERROR_SUCCESS;
  1095. }
  1096. }
  1097. }
  1098. cleanup:
  1099. // release the memory
  1100. FreeMemory( &pwszSubKey );
  1101. FreeMemory( &pwszNewFullKey );
  1102. // return
  1103. return lResult;
  1104. }
  1105. BOOL
  1106. SearchData( LPBYTE pByteData, DWORD dwType,
  1107. DWORD dwSize, PTREG_PARAMS pParams )
  1108. {
  1109. // local variables
  1110. DWORD dw = 0;
  1111. DWORD dwLength = 0;
  1112. BOOL bResult = FALSE;
  1113. LPCWSTR pwszEnd = NULL;
  1114. LPCWSTR pwszData = NULL;
  1115. LPWSTR pwszString = NULL;
  1116. LPCWSTR pwszSeparator = NULL;
  1117. BOOL bShowSeparator = FALSE;
  1118. DWORD dwFlags = 0;
  1119. // check input
  1120. if ( pByteData == NULL || pParams == NULL )
  1121. {
  1122. SetLastError( ERROR_INVALID_PARAMETER );
  1123. return FALSE;
  1124. }
  1125. switch( dwType )
  1126. {
  1127. case REG_SZ:
  1128. case REG_EXPAND_SZ:
  1129. {
  1130. pwszData = (LPCWSTR) pByteData;
  1131. break;
  1132. }
  1133. default:
  1134. {
  1135. // allocate memory which is double the (dwSize + 1) & +10 -> buffer
  1136. // but do this only for types that need memory allocation
  1137. dwLength = (dwSize + 1) * 2 + 10;
  1138. pwszString = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) );
  1139. if ( pwszString == NULL )
  1140. {
  1141. return FALSE;
  1142. }
  1143. // ...
  1144. pwszData = pwszString;
  1145. }
  1146. }
  1147. switch( dwType )
  1148. {
  1149. case REG_MULTI_SZ:
  1150. {
  1151. //
  1152. // Replace '\0' with "\0" for MULTI_SZ
  1153. //
  1154. pwszEnd = (LPCWSTR) pByteData;
  1155. pwszSeparator = pParams->wszSeparator;
  1156. StringCopy( pwszString, cwszNullString, dwLength );
  1157. while( ((BYTE*) pwszEnd) < (pByteData + dwSize) )
  1158. {
  1159. if( *pwszEnd == 0 )
  1160. {
  1161. // enable the display of value separator and skip this
  1162. pwszEnd++;
  1163. bShowSeparator = TRUE;
  1164. }
  1165. else
  1166. {
  1167. // check whether we need to display the separator or not
  1168. if ( bShowSeparator == TRUE )
  1169. {
  1170. StringConcat( pwszString, pwszSeparator, dwLength );
  1171. }
  1172. // ...
  1173. StringConcat( pwszString, pwszEnd, dwLength );
  1174. pwszEnd += StringLength( pwszEnd, 0 );
  1175. }
  1176. }
  1177. // ...
  1178. break;
  1179. }
  1180. case REG_SZ:
  1181. case REG_EXPAND_SZ:
  1182. // do nothing
  1183. break;
  1184. default:
  1185. {
  1186. StringCopy( pwszString, cwszNullString, dwLength );
  1187. for( dw = 0; dw < dwSize; dw++ )
  1188. {
  1189. if ( SetReason2( 1, L"%02X", pByteData[ dw ] ) == FALSE )
  1190. {
  1191. FreeMemory( &pwszString );
  1192. SetLastError( ERROR_OUTOFMEMORY );
  1193. return FALSE;
  1194. }
  1195. // ...
  1196. StringConcat( pwszString, GetReason(), dwLength );
  1197. }
  1198. // ...
  1199. break;
  1200. }
  1201. case REG_DWORD:
  1202. case REG_DWORD_BIG_ENDIAN:
  1203. {
  1204. if ( StringCompare( pParams->pwszSearchData, L"0x", TRUE, 2 ) == 0 )
  1205. {
  1206. if ( SetReason2( 1, L"0x%x", *((DWORD*) pByteData) ) == FALSE )
  1207. {
  1208. FreeMemory( &pwszString );
  1209. SetLastError( ERROR_OUTOFMEMORY );
  1210. return FALSE;
  1211. }
  1212. }
  1213. else
  1214. {
  1215. if ( SetReason2( 1, L"%d", *((DWORD*) pByteData) ) == FALSE )
  1216. {
  1217. FreeMemory( &pwszString );
  1218. SetLastError( ERROR_OUTOFMEMORY );
  1219. return FALSE;
  1220. }
  1221. }
  1222. // ...
  1223. StringCopy( pwszString, GetReason(), dwLength );
  1224. break;
  1225. }
  1226. }
  1227. // do the search now
  1228. bResult = TRUE;
  1229. if ( pParams->bExactMatch == FALSE )
  1230. {
  1231. // prepare the comparision flags
  1232. dwFlags = PATTERN_NOPARSING;
  1233. dwFlags |= ((pParams->bCaseSensitive == FALSE) ? PATTERN_COMPARE_IGNORECASE : 0);
  1234. // ...
  1235. if ( MatchPatternEx( pwszData, pParams->pwszSearchData, dwFlags ) == FALSE )
  1236. {
  1237. bResult = FALSE;
  1238. SetLastError( ERROR_NOT_FOUND );
  1239. }
  1240. }
  1241. else
  1242. {
  1243. if ( StringCompare( pwszData,
  1244. pParams->pwszSearchData,
  1245. (pParams->bCaseSensitive == FALSE), 0 ) != 0 )
  1246. {
  1247. bResult = FALSE;
  1248. SetLastError( ERROR_NOT_FOUND );
  1249. }
  1250. }
  1251. // release the memory allocated
  1252. FreeMemory( &pwszString );
  1253. // return
  1254. return bResult;
  1255. }
  1256. BOOL
  1257. ParseTypeInfo( LPCWSTR pwszTypes,
  1258. PTREG_PARAMS pParams )
  1259. {
  1260. // local variables
  1261. LONG lArrayIndex = 0;
  1262. LONG lLength = 0;
  1263. LONG lIndex = 0;
  1264. LONG lStart = 0;
  1265. LONG lType = 0;
  1266. LPCWSTR pwsz = NULL;
  1267. // check input
  1268. if ( pwszTypes == NULL || pParams == NULL )
  1269. {
  1270. SetLastError( ERROR_INVALID_PARAMETER );
  1271. return FALSE;
  1272. }
  1273. // validate the types array
  1274. if ( pParams->arrTypes == NULL )
  1275. {
  1276. pParams->arrTypes = CreateDynamicArray();
  1277. if ( pParams->arrTypes == NULL )
  1278. {
  1279. SetLastError( ERROR_OUTOFMEMORY );
  1280. return FALSE;
  1281. }
  1282. }
  1283. // parse the types information
  1284. lStart = lIndex = 0;
  1285. while ( lIndex != -1 )
  1286. {
  1287. lIndex = FindString2( pwszTypes, L",", TRUE, lStart );
  1288. if ( lIndex == -1 )
  1289. {
  1290. lLength = 0;
  1291. }
  1292. else
  1293. {
  1294. lLength = lIndex - lStart;
  1295. }
  1296. // append a row
  1297. lArrayIndex = DynArrayAppendRow( pParams->arrTypes, 2 );
  1298. if ( lArrayIndex == -1 )
  1299. {
  1300. SetLastError( ERROR_OUTOFMEMORY );
  1301. return FALSE;
  1302. }
  1303. // add the type info
  1304. if ( DynArraySetString2( pParams->arrTypes,
  1305. lArrayIndex, 0, pwszTypes + lStart, lLength ) == -1 )
  1306. {
  1307. SetLastError( ERROR_OUTOFMEMORY );
  1308. return FALSE;
  1309. }
  1310. // get the type back from array
  1311. pwsz = DynArrayItemAsString2( pParams->arrTypes, lArrayIndex, 0 );
  1312. if ( pwsz == NULL )
  1313. {
  1314. SetLastError( (DWORD) STG_E_UNKNOWN );
  1315. return FALSE;
  1316. }
  1317. // determine the numeric equivalent of it
  1318. lType = IsRegDataType( pwsz );
  1319. if( lType == -1 )
  1320. {
  1321. if (IsNumeric( pwsz, 10, TRUE ) == TRUE )
  1322. {
  1323. lType = AsLong( pwsz, 10 );
  1324. }
  1325. else
  1326. {
  1327. SetLastError( (DWORD) MK_E_SYNTAX );
  1328. return FALSE;
  1329. }
  1330. }
  1331. if ( DynArraySetLong2( pParams->arrTypes, lArrayIndex, 1, lType ) == -1 )
  1332. {
  1333. SetLastError( ERROR_OUTOFMEMORY );
  1334. return FALSE;
  1335. }
  1336. // update the start position
  1337. lStart = lIndex + 1;
  1338. }
  1339. // ...
  1340. SetLastError( ERROR_SUCCESS );
  1341. return TRUE;
  1342. }