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.

4843 lines
128 KiB

  1. // ****************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // Module Name:
  6. //
  7. // cmdline.c
  8. //
  9. // Abstract:
  10. //
  11. // This modules implements common functionality for all the
  12. // command line tools.
  13. //
  14. //
  15. // Author:
  16. //
  17. // Sunil G.V.N. Murali ([email protected]) 01-Sep-2000
  18. //
  19. // Revision History:
  20. //
  21. // Sunil G.V.N. Murali ([email protected]) 01-Sep-2000 : Created It.
  22. //
  23. // ****************************************************************************
  24. #include "pch.h"
  25. // indexes to the internal array
  26. #define INDEX_ERROR_TEXT 0
  27. #define INDEX_RESOURCE_STRING 1
  28. #define INDEX_QUOTE_STRING 2
  29. #define INDEX_TEMP_BUFFER 3
  30. // permanent indexes to the temporary buffers
  31. #define INDEX_TEMP_SHOWMESSAGE 3
  32. #define INDEX_TEMP_RESOURCE 4
  33. #define INDEX_TEMP_REASON 5
  34. #define INDEX_TEMP_PATTERN 6
  35. //
  36. // global variable(s)
  37. //
  38. BOOL g_bInitialized = FALSE;
  39. BOOL g_bWinsockLoaded = FALSE;
  40. static TARRAY g_arrData = NULL;
  41. static DWORD g_dwMajorVersion = 5;
  42. static DWORD g_dwMinorVersion = 1;
  43. static WORD g_wServicePackMajor = 0;
  44. //
  45. // global constants
  46. //
  47. const WCHAR cwchNullChar = L'\0';
  48. const WCHAR cwszNullString[ 2 ] = L"\0";
  49. //
  50. // internal structures
  51. //
  52. typedef struct __tagBuffer
  53. {
  54. CHAR szSignature[ 7 ]; // "BUFFER\0"
  55. DWORD dwLength;
  56. LPWSTR pwszData;
  57. } TBUFFER;
  58. //
  59. // private functions
  60. //
  61. BOOL InternalRecursiveMatchPatternEx( IN LPCWSTR pwszText, IN LPCWSTR pwszPattern,
  62. IN DWORD dwLocale, IN DWORD dwCompareFlags, IN DWORD dwDepth );
  63. // prototypes
  64. BOOL SetThreadUILanguage0( DWORD dwReserved );
  65. __inline LPWSTR
  66. GetTempBuffer(
  67. IN DWORD dwIndexNumber,
  68. IN LPCWSTR pwszText,
  69. IN DWORD dwLength,
  70. IN BOOL bNullify
  71. )
  72. /*++
  73. Routine Description:
  74. NOTE: since every file will need the temporary buffers -- in order to see
  75. that their buffers wont be override with other functions, we are
  76. creating a for each file
  77. so, the temporary buffers in this file will range from index 0 to 5
  78. thisgives total of 6 temporary buffers for this file
  79. Arguments:
  80. [IN] dwIndexNumber : Index number
  81. [IN] pwszText : Text string
  82. [IN] dwLength : length of the text string
  83. [IN] bNullify : flag to specify either TRUE/FALSE
  84. Return Value:
  85. NULL : On failure
  86. LPWSTR : On success
  87. --*/
  88. {
  89. if ( dwIndexNumber >= TEMP_CMDLINE_C_COUNT )
  90. {
  91. return NULL;
  92. }
  93. // check if caller is requesting existing buffer contents
  94. if ( pwszText == NULL && dwLength == 0 && bNullify == FALSE )
  95. {
  96. // yes -- we need to pass the existing buffer contents
  97. return GetInternalTemporaryBufferRef(
  98. dwIndexNumber + INDEX_TEMP_CMDLINE_C );
  99. }
  100. // ...
  101. return GetInternalTemporaryBuffer(
  102. dwIndexNumber + INDEX_TEMP_CMDLINE_C, pwszText, dwLength, bNullify );
  103. }
  104. BOOL
  105. InitGlobals()
  106. /*++
  107. Routine Description:
  108. Initializes the global variables
  109. Arguments: None
  110. Return Value:
  111. FALSE : On failure
  112. TRUE : On success
  113. --*/
  114. {
  115. //
  116. // for historical reasons we wont neither clear nor set the error code here
  117. //
  118. // check whether the initialization is already done or not
  119. if ( g_bInitialized == TRUE )
  120. {
  121. if ( IsValidArray( g_arrData ) == FALSE )
  122. {
  123. // some one corrupted the data
  124. UNEXPECTED_ERROR();
  125. return FALSE;
  126. }
  127. else
  128. {
  129. // just inform the caller that the function call is successful
  130. return TRUE;
  131. }
  132. }
  133. else if ( g_arrData != NULL )
  134. {
  135. UNEXPECTED_ERROR();
  136. return FALSE;
  137. }
  138. // create the dynamic array
  139. g_arrData = CreateDynamicArray();
  140. if ( IsValidArray( g_arrData ) == FALSE )
  141. {
  142. OUT_OF_MEMORY();
  143. return FALSE;
  144. }
  145. //
  146. // prepare for the data storage
  147. // error text
  148. if ( DynArrayAppendString(g_arrData, cwszNullString, 0) != INDEX_ERROR_TEXT ||
  149. DynArrayAppendRow( g_arrData, 3 ) != INDEX_RESOURCE_STRING ||
  150. DynArrayAppendRow( g_arrData, 3 ) != INDEX_QUOTE_STRING ||
  151. DynArrayAppendRow( g_arrData, 3 ) != INDEX_TEMP_BUFFER )
  152. {
  153. OUT_OF_MEMORY();
  154. return FALSE;
  155. }
  156. // every thing went well -- return
  157. // though the rest of the code still needs to execute
  158. // we treat as initialized once we create the global data structure
  159. g_bInitialized = TRUE;
  160. //
  161. // initialize the thread specific resource information to use
  162. //
  163. // NOTE: since there is nothing much to do here,
  164. // we are intentionally not checking the error code
  165. //
  166. if ( SetThreadUILanguage0( 0 ) == FALSE )
  167. {
  168. // SetThreadUILanguage0 is supposed to set the errro value
  169. return FALSE;
  170. }
  171. return TRUE;
  172. }
  173. LPWSTR
  174. GetInternalTemporaryBufferRef( IN DWORD dwIndexNumber )
  175. /*++
  176. Routine Description:
  177. Arguments:
  178. [IN] dwIndexNumber : Index number
  179. Return Value:
  180. NULL : On failure
  181. LPWSTR : On success
  182. --*/
  183. {
  184. // local variables
  185. DWORD dw = 0;
  186. TBUFFER* pBuffer = NULL;
  187. const CHAR cszSignature[ 7 ] = "BUFFER";
  188. //
  189. // for historical reasons we wont neither clear nor set the error code here
  190. //
  191. // initialize the global data structure
  192. if ( g_bInitialized == FALSE )
  193. {
  194. return NULL;
  195. }
  196. // get the temp buffer array
  197. dw = DynArrayGetCount2( g_arrData, INDEX_TEMP_BUFFER );
  198. if ( dw <= dwIndexNumber )
  199. {
  200. return NULL;
  201. }
  202. // check whether we need to allocate a new TBUFFER or we can use the
  203. // already allocated
  204. if ( DynArrayGetItemType2( g_arrData,
  205. INDEX_TEMP_BUFFER,
  206. dwIndexNumber ) != DA_TYPE_NONE )
  207. {
  208. // we can use the already created buffer
  209. pBuffer = DynArrayItem2( g_arrData, INDEX_TEMP_BUFFER, dwIndexNumber );
  210. if ( pBuffer == NULL )
  211. {
  212. // unexpected behavior
  213. return NULL;
  214. }
  215. }
  216. else
  217. {
  218. return NULL;
  219. }
  220. // verify the signature of the buffer
  221. // this is just to ensure that we have everything in right place
  222. if ( StringCompareA( pBuffer->szSignature, cszSignature, TRUE, 0 ) != 0 )
  223. {
  224. return NULL;
  225. }
  226. // return
  227. return pBuffer->pwszData;
  228. }
  229. LPWSTR
  230. GetInternalTemporaryBuffer( IN DWORD dwIndexNumber,
  231. IN OUT LPCWSTR pwszText,
  232. IN DWORD dwLength,
  233. IN BOOL bNullify )
  234. /*++
  235. Routine Description:
  236. Get the temporary buffer by allocating the buffer dynamically
  237. Arguments:
  238. [IN] dwIndexNumber : Index number
  239. [IN] pwszText : Text string
  240. [IN] dwLength : length of the text string
  241. [IN] bNullify : flag to specify either TRUE/FALSE
  242. Return Value:
  243. FALSE : On failure
  244. TRUE : On success
  245. --*/
  246. {
  247. // local variables
  248. DWORD dw = 0;
  249. DWORD dwNewLength = 0;
  250. TARRAY arrTemp = NULL;
  251. TBUFFER* pBuffer = NULL;
  252. const CHAR cszSignature[ 7 ] = "BUFFER";
  253. //
  254. // for historical reasons we wont neither clear nor set the error code here
  255. //
  256. // check the input
  257. if ( pwszText == NULL && dwLength == 0 )
  258. {
  259. // caller should pass either of them -- if not fail
  260. return NULL;
  261. }
  262. // initialize the global data structure
  263. if ( InitGlobals() == FALSE )
  264. {
  265. return NULL;
  266. }
  267. // get the temp buffer array
  268. dw = DynArrayGetCount2( g_arrData, INDEX_TEMP_BUFFER );
  269. if ( dw <= dwIndexNumber )
  270. {
  271. // add the some more buffers so that requirement can be satisfied
  272. arrTemp = DynArrayItem( g_arrData, INDEX_TEMP_BUFFER );
  273. if ( arrTemp == NULL ||
  274. DynArrayAddColumns( arrTemp, dwIndexNumber - dw + 1 ) == -1 )
  275. {
  276. return NULL;
  277. }
  278. }
  279. // check whether we need to allocate a new TBUFFER or we can use the
  280. // already allocated
  281. if ( DynArrayGetItemType2( g_arrData,
  282. INDEX_TEMP_BUFFER,
  283. dwIndexNumber ) != DA_TYPE_NONE )
  284. {
  285. // we can use the already created buffer
  286. pBuffer = DynArrayItem2( g_arrData, INDEX_TEMP_BUFFER, dwIndexNumber );
  287. if ( pBuffer == NULL )
  288. {
  289. // unexpected behavior
  290. return NULL;
  291. }
  292. }
  293. else
  294. {
  295. // we need to allocate temporary buffer
  296. pBuffer = (TBUFFER*) AllocateMemory( sizeof( TBUFFER ) );
  297. if ( pBuffer == NULL )
  298. {
  299. return NULL;
  300. }
  301. // initialize the block
  302. pBuffer->dwLength = 0;
  303. pBuffer->pwszData = NULL;
  304. StringCopyA( pBuffer->szSignature, cszSignature, SIZE_OF_ARRAY( pBuffer->szSignature ) );
  305. // save the buffer in array
  306. if ( DynArraySet2( g_arrData,
  307. INDEX_TEMP_BUFFER,
  308. dwIndexNumber, pBuffer ) == FALSE )
  309. {
  310. // failed to set the buffer -- release the newly allocated
  311. // and return
  312. FreeMemory( &pBuffer );
  313. return NULL;
  314. }
  315. //
  316. // once we save the newly allocated buffer in array -- we are set
  317. // we need to worry about the furthur return statements -- the memory
  318. // that is allocated in this section will be automatically released
  319. // by ReleaseGlobals
  320. //
  321. }
  322. // verify the signature of the buffer
  323. // this is just to ensure that we have everything in right place
  324. if ( StringCompareA( pBuffer->szSignature, cszSignature, TRUE, 0 ) != 0 )
  325. {
  326. return NULL;
  327. }
  328. // indentify the amount of memory required
  329. // we need extra space for NULL
  330. dwNewLength = ((pwszText == NULL) ? dwLength : (StringLength(pwszText, 0) + 1));
  331. // allocate memory for temporary buffer -- if needed
  332. // NOTE: we will re-allocate memory even if the two-time of current
  333. // requested buffer length is less than the buffer length that is
  334. // currently allocated on heap -- this we are doing to use the
  335. // heap effectively
  336. if ( dwNewLength > pBuffer->dwLength ||
  337. ( dwNewLength > 256 && (dwNewLength * 2) < pBuffer->dwLength ) )
  338. {
  339. // we need to toggle between allocate / reallocate based on the
  340. // current length of the string in the TBUFFER
  341. if ( pBuffer->dwLength == 0 )
  342. {
  343. pBuffer->pwszData = AllocateMemory( dwNewLength * sizeof( WCHAR ) );
  344. if ( pBuffer->pwszData == NULL )
  345. {
  346. return NULL;
  347. }
  348. }
  349. else
  350. {
  351. if ( ReallocateMemory( &pBuffer->pwszData,
  352. dwNewLength * sizeof( WCHAR ) ) == FALSE )
  353. {
  354. return NULL;
  355. }
  356. }
  357. // save the current length of the data
  358. pBuffer->dwLength = dwNewLength;
  359. }
  360. // safety check
  361. if ( pBuffer->pwszData == NULL )
  362. {
  363. return NULL;
  364. }
  365. // copy the data
  366. if ( pwszText != NULL )
  367. {
  368. StringCopy( pBuffer->pwszData, pwszText, dwNewLength );
  369. }
  370. else if ( bNullify == TRUE )
  371. {
  372. ZeroMemory( pBuffer->pwszData, dwNewLength * sizeof( WCHAR ) );
  373. }
  374. // return
  375. return pBuffer->pwszData;
  376. }
  377. BOOL
  378. SetThreadUILanguage0( IN DWORD dwReserved )
  379. /*++
  380. Routine Description:
  381. Complex scripts cannot be rendered in the console, so we
  382. force the English (US) resource.
  383. Arguments:
  384. [ in ] dwReserved => must be zero
  385. Return Value:
  386. TRUE : on Success
  387. FALSE : On Failure
  388. --*/
  389. {
  390. // local variables
  391. UINT ui = 0;
  392. UINT uiSize = 0;
  393. OSVERSIONINFOEX osvi;
  394. LPWSTR pwszPath = NULL;
  395. LPCWSTR pwszLibPath = NULL;
  396. HMODULE hKernel32Lib = NULL;
  397. DWORDLONG dwlConditionMask = 0;
  398. const CHAR cszFunctionName[] = "SetThreadUILanguage";
  399. typedef BOOLEAN (WINAPI * FUNC_SetThreadUILanguage)( DWORD dwReserved );
  400. FUNC_SetThreadUILanguage pfnSetThreadUILanguage = NULL;
  401. //
  402. // for historical reasons we wont neither clear nor set the error code here
  403. //
  404. // Initialize the OSVERSIONINFOEX structure
  405. ZeroMemory( &osvi, sizeof( OSVERSIONINFOEX ) );
  406. osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
  407. osvi.dwMajorVersion = 5; // WINDOWS 2000
  408. osvi.dwMinorVersion = 0; // ...
  409. osvi.wServicePackMajor = 0; // ...
  410. // Initialize the condition mask.
  411. VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_EQUAL );
  412. VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_EQUAL );
  413. VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
  414. // now check if the current os version is 5.0
  415. if ( VerifyVersionInfo( &osvi,
  416. VER_MAJORVERSION | VER_MINORVERSION,
  417. dwlConditionMask ) == TRUE )
  418. {
  419. // currently os is W2K -- no need to proceed furthur
  420. // still the function didn't encounter any error
  421. // but return success as well as set the error code
  422. SetLastError( ERROR_OLD_WIN_VERSION );
  423. return TRUE;
  424. }
  425. //
  426. // get the system files path
  427. uiSize = MAX_PATH + 1;
  428. do
  429. {
  430. pwszPath = GetTempBuffer( 0, NULL, uiSize + 10, TRUE );
  431. if ( pwszPath == NULL )
  432. {
  433. OUT_OF_MEMORY();
  434. return FALSE;
  435. }
  436. // ...
  437. ui = GetSystemDirectory( pwszPath, uiSize );
  438. if ( ui == 0 )
  439. {
  440. return FALSE;
  441. }
  442. else if ( ui > uiSize )
  443. {
  444. // buffer is not sufficient -- need more buffer
  445. // but check whether this is the first time that
  446. // API is reported that the buffer is not sufficient
  447. // if not, then it is an error -- something is going wrong
  448. if ( uiSize != MAX_PATH + 1 )
  449. {
  450. uiSize = ui + 1;
  451. ui = 0;
  452. }
  453. else
  454. {
  455. UNEXPECTED_ERROR();
  456. return FALSE;
  457. }
  458. }
  459. } while ( ui == 0 );
  460. // we will make use of failure buffer to format the
  461. // string for file path
  462. if ( SetReason2( 2, L"%s\\%s", pwszPath, L"kernel32.dll" ) == FALSE )
  463. {
  464. OUT_OF_MEMORY();
  465. return FALSE;
  466. }
  467. // try loading the kernel32 dynamic link library
  468. pwszLibPath = GetReason();
  469. hKernel32Lib = LoadLibrary( pwszLibPath );
  470. if ( hKernel32Lib != NULL )
  471. {
  472. // library loaded successfully ... now load the addresses of functions
  473. pfnSetThreadUILanguage =
  474. (FUNC_SetThreadUILanguage) GetProcAddress( hKernel32Lib, cszFunctionName );
  475. // we will keep the library loaded in memory only if all the
  476. // functions were loaded successfully
  477. if ( pfnSetThreadUILanguage == NULL )
  478. {
  479. // some (or) all of the functions were not loaded ... unload the library
  480. FreeLibrary( hKernel32Lib );
  481. hKernel32Lib = NULL;
  482. return FALSE;
  483. }
  484. else
  485. {
  486. // call the function
  487. ((FUNC_SetThreadUILanguage) pfnSetThreadUILanguage)( dwReserved );
  488. }
  489. // unload the library and return success
  490. FreeLibrary( hKernel32Lib );
  491. hKernel32Lib = NULL;
  492. pfnSetThreadUILanguage = NULL;
  493. }
  494. else
  495. {
  496. return FALSE;
  497. }
  498. // success
  499. return TRUE;
  500. }
  501. //
  502. // public functions
  503. //
  504. LPCWSTR
  505. GetReason()
  506. /*++
  507. Routine Description:
  508. Get the reason depends on the GetLastError() (WIN32 API error code)
  509. set by the SaveLastError()
  510. Arguments:
  511. None
  512. Return Value:
  513. LPCWSTR : on Success
  514. NULL_STRING : On Failure
  515. --*/
  516. {
  517. //
  518. // we should not clear the error code here
  519. //
  520. // check whether buffer is allocated or not ... if not, empty string
  521. if ( g_arrData == NULL || IsValidArray( g_arrData ) == FALSE )
  522. {
  523. return cwszNullString;
  524. }
  525. // returh the reason for the last failure
  526. return DynArrayItemAsString( g_arrData, INDEX_ERROR_TEXT );
  527. }
  528. BOOL
  529. SetReason( LPCWSTR pwszReason )
  530. /*++
  531. Routine Description:
  532. Set the reason depends on the GetLastError() (WIN32 API error code)
  533. set by the SaveLastError()
  534. Arguments:
  535. None
  536. Return Value:
  537. TRUE : on Success
  538. FALSE : On Failure
  539. --*/
  540. {
  541. // local variables
  542. DWORD dwLastError = 0;
  543. //
  544. // we should not clear the error code here
  545. //
  546. // preserve the last error
  547. dwLastError = GetLastError();
  548. // check the input value
  549. if ( pwszReason == NULL )
  550. {
  551. INVALID_PARAMETER();
  552. return FALSE;
  553. }
  554. // initialize the global data structure
  555. if ( InitGlobals() == FALSE )
  556. {
  557. return FALSE;
  558. }
  559. // set the reason ..
  560. if ( DynArraySetString( g_arrData, INDEX_ERROR_TEXT, pwszReason, 0 ) == FALSE )
  561. {
  562. OUT_OF_MEMORY();
  563. return FALSE;
  564. }
  565. SetLastError( dwLastError );
  566. return TRUE;
  567. }
  568. BOOL
  569. SetReason2( IN DWORD dwCount,
  570. IN LPCWSTR pwszFormat, ... )
  571. /*++
  572. Routine Description:
  573. Saves text in memory
  574. Generally used for saving the reason for the failure but can be used
  575. in any context.
  576. This variant of SetReason accepts variable no. of arguments just as
  577. sprintf statements and does the formatting
  578. Arguments:
  579. [ in ] dwCount : Specifies no. of variable no. of arguments being
  580. passed to this function
  581. [ in ] pwszFormat : Specifies the format string -- to format the text
  582. [ in ] ... : Variable no. of arguments specification
  583. Return Value:
  584. TRUE : on Success
  585. FALSE : On Failure
  586. --*/
  587. {
  588. // local variables
  589. va_list vargs;
  590. DWORD dwBufferLength = 0;
  591. LPWSTR pwszBuffer = NULL;
  592. HRESULT hr = S_OK;
  593. //
  594. // we should not clear the error code here
  595. //
  596. // check the input
  597. if ( pwszFormat == NULL )
  598. {
  599. INVALID_PARAMETER();
  600. return FALSE;
  601. }
  602. else if ( dwCount == 0 )
  603. {
  604. SetReason( pwszFormat );
  605. return TRUE;
  606. }
  607. do
  608. {
  609. // get the variable args start position
  610. va_start( vargs, pwszFormat );
  611. if ( vargs == NULL )
  612. {
  613. UNEXPECTED_ERROR();
  614. return FALSE;
  615. }
  616. // we will start with buffer length of 256 bytes and then increment
  617. // the buffer by 256 bytes each time we run thru this loop
  618. dwBufferLength += 256;
  619. if ( (pwszBuffer = GetTempBuffer( INDEX_TEMP_REASON,
  620. NULL, dwBufferLength, TRUE )) == NULL )
  621. {
  622. OUT_OF_MEMORY();
  623. return FALSE;
  624. }
  625. // try the printf
  626. hr = StringCchVPrintfW( pwszBuffer, dwBufferLength, pwszFormat, vargs );
  627. // reset the va_list parameter
  628. va_end( vargs );
  629. } while ( hr == STRSAFE_E_INSUFFICIENT_BUFFER );
  630. // check the hr (vprintf might have failed for some other reason)
  631. if ( FAILED( hr ) )
  632. {
  633. SetLastError( HRESULT_CODE( hr ) );
  634. return FALSE;
  635. }
  636. // now save the reason
  637. return SetReason( pwszBuffer );
  638. }
  639. BOOL
  640. SaveLastError()
  641. /*++
  642. Routine Description:
  643. Format the message depends on GetLastError() error code and set the
  644. message to SetReason().
  645. Arguments: None
  646. Return Value:
  647. FALSE : On failure
  648. TRUE : On success
  649. --*/
  650. {
  651. // local variables
  652. DWORD dw = 0;
  653. BOOL bResult = FALSE;
  654. LPVOID lpMsgBuf = NULL; // pointer to handle error message
  655. //
  656. // we should not clear the error text here
  657. //
  658. // load the system error message from the windows itself
  659. dw = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  660. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  661. NULL, GetLastError(), 0, (LPWSTR) &lpMsgBuf, 0, NULL );
  662. // check the function call succeeded or not
  663. if ( dw == 0 || lpMsgBuf == NULL )
  664. {
  665. // return
  666. if ( lpMsgBuf != NULL )
  667. {
  668. LocalFree( lpMsgBuf );
  669. // since there is a chance of last error to get clear
  670. // by LocalFree, set the last error once again
  671. OUT_OF_MEMORY();
  672. }
  673. // ...
  674. OUT_OF_MEMORY();
  675. return FALSE;
  676. }
  677. // save the error message
  678. bResult = SetReason( ( LPCWSTR ) lpMsgBuf );
  679. // Free the buffer ... using LocalFree is slow, but still, we are using ...
  680. // later on need to replaced with HeapXXX functions
  681. LocalFree( lpMsgBuf );
  682. lpMsgBuf = NULL;
  683. // return
  684. return bResult;
  685. }
  686. DWORD
  687. WNetSaveLastError()
  688. /*++
  689. Routine Description:
  690. Format the message depends on most recent extended error code and set the
  691. message to SetReason().
  692. Arguments: None
  693. Return Value:
  694. FALSE : On failure
  695. TRUE : On success
  696. --*/
  697. {
  698. // local variables
  699. DWORD dwResult = 0;
  700. DWORD dwErrorCode = 0;
  701. LPWSTR pwszMessage = NULL; // handle error message
  702. LPWSTR pwszProvider = NULL; // store the provider for error
  703. //
  704. // we should not clear error here
  705. //
  706. //
  707. // get the memory for message and provider buffers
  708. // message
  709. if ( (pwszMessage = GetTempBuffer( 0, NULL, 256, TRUE )) == NULL )
  710. {
  711. return ERROR_NOT_ENOUGH_MEMORY;
  712. }
  713. // provider
  714. if ( (pwszProvider = GetTempBuffer( 1, NULL, 256, TRUE )) == NULL )
  715. {
  716. return ERROR_NOT_ENOUGH_MEMORY;
  717. }
  718. // load the system error message from the windows itself
  719. dwResult = WNetGetLastError( &dwErrorCode,
  720. pwszMessage, (GetBufferSize( pwszMessage ) / sizeof( WCHAR )) - 1,
  721. pwszProvider, (GetBufferSize( pwszProvider ) / sizeof( WCHAR )) - 1 );
  722. // check whether the function succeeded or not
  723. if ( dwResult != NO_ERROR )
  724. {
  725. return dwResult;
  726. }
  727. // save the error
  728. if ( SetReason( pwszMessage ) == FALSE )
  729. {
  730. return ERROR_NOT_ENOUGH_MEMORY;
  731. }
  732. // return the error code obtained
  733. return dwErrorCode;
  734. }
  735. BOOL
  736. ShowLastError( IN FILE* fp )
  737. /*++
  738. Routine Description:
  739. Displays the message for most recent error code (GetLastError())
  740. based on the file pointer
  741. Arguments: None
  742. Return Value:
  743. FALSE : On failure
  744. TRUE : On success
  745. --*/
  746. {
  747. //
  748. // we should not clear error here
  749. //
  750. // save the last error first
  751. if ( SaveLastError() == FALSE )
  752. {
  753. // error occured while trying to save the error message
  754. return FALSE;
  755. }
  756. // display error message on console screen ...
  757. if ( ShowMessage( fp, GetReason() ) == FALSE )
  758. {
  759. return FALSE;
  760. }
  761. // return
  762. return TRUE;
  763. }
  764. BOOL
  765. ShowLastErrorEx( IN FILE* fp,
  766. IN DWORD dwFlags )
  767. /*++
  768. Routine Description:
  769. Arguments:
  770. Return Value:
  771. --*/
  772. {
  773. // check the input
  774. if ( NULL == fp || 0 == (dwFlags & SLE_MASK) )
  775. {
  776. INVALID_PARAMETER();
  777. return FALSE;
  778. }
  779. // check whether to display the internal error message
  780. // or the system error
  781. if ( dwFlags & SLE_SYSTEM )
  782. {
  783. SaveLastError();
  784. }
  785. // check the flags and show the appropriate tag
  786. // NOTE: some times, caller even might not need the flag to show
  787. if ( dwFlags & SLE_TYPE_ERROR )
  788. {
  789. ShowMessageEx( fp, 1, TRUE, L"%s ", TAG_ERROR );
  790. }
  791. else if ( dwFlags & SLE_TYPE_WARNING )
  792. {
  793. ShowMessageEx( fp, 1, TRUE, L"%s ", TAG_WARNING );
  794. }
  795. else if ( dwFlags & SLE_TYPE_INFO )
  796. {
  797. ShowMessageEx( fp, 1, TRUE, L"%s ", TAG_INFORMATION );
  798. }
  799. else if ( dwFlags & SLE_TYPE_SUCCESS )
  800. {
  801. ShowMessageEx( fp, 1, TRUE, L"%s ", TAG_SUCCESS );
  802. }
  803. // show the actual error message
  804. ShowMessage( fp, GetReason() );
  805. return TRUE;
  806. }
  807. BOOL
  808. ReleaseGlobals()
  809. /*++
  810. Routine Description:
  811. De-allocate the memory for all the global variables
  812. Arguments: None
  813. Return Value:
  814. FALSE : On failure
  815. TRUE : On success
  816. --*/
  817. {
  818. // local variables
  819. DWORD dw = 0;
  820. DWORD dwCount = 0;
  821. TBUFFER* pBuffer = NULL;
  822. //
  823. // for historical reasons we wont neither clear nor set the error code here
  824. //
  825. //
  826. // memory is allocated then free memory
  827. // do this only if the memory is allocated
  828. if ( IsValidArray( g_arrData ) == TRUE )
  829. {
  830. // release memory allocated for temporary buffers
  831. dwCount = DynArrayGetCount2( g_arrData, INDEX_TEMP_BUFFER );
  832. for( dw = dwCount; dw != 0; dw-- )
  833. {
  834. if ( DynArrayGetItemType2( g_arrData,
  835. INDEX_TEMP_BUFFER, dw - 1 ) == DA_TYPE_GENERAL )
  836. {
  837. pBuffer = DynArrayItem2( g_arrData, INDEX_TEMP_BUFFER, dw - 1 );
  838. if ( pBuffer == NULL )
  839. {
  840. // this is error condition -- still ignore
  841. continue;
  842. }
  843. // release data first
  844. FreeMemory( &pBuffer->pwszData );
  845. // now release the memory
  846. FreeMemory( &pBuffer );
  847. // remove the item from dynamic array
  848. DynArrayRemoveColumn( g_arrData, INDEX_TEMP_BUFFER, dw - 1 );
  849. }
  850. }
  851. // free the memory allocated for global data storage
  852. DestroyDynamicArray( &g_arrData );
  853. }
  854. // if winsock module is loaded, release it
  855. if ( g_bWinsockLoaded == TRUE )
  856. {
  857. WSACleanup();
  858. }
  859. return TRUE;
  860. }
  861. BOOL
  862. IsWin2KOrLater()
  863. /*++
  864. Routine Description:
  865. Checks whether the OS version of target system is WINDOWS 2000 or later
  866. Arguments: None
  867. Return Value:
  868. FALSE : On failure
  869. TRUE : On success
  870. --*/
  871. {
  872. // local variables
  873. OSVERSIONINFOEX osvi;
  874. DWORDLONG dwlConditionMask = 0;
  875. //
  876. // for historical reasons we wont neither clear nor set the error code here
  877. //
  878. // Initialize the OSVERSIONINFOEX structure.
  879. ZeroMemory( &osvi, sizeof( OSVERSIONINFOEX ) );
  880. osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
  881. osvi.dwMajorVersion = g_dwMajorVersion;
  882. osvi.dwMinorVersion = g_dwMinorVersion;
  883. osvi.wServicePackMajor = g_wServicePackMajor;
  884. // Initialize the condition mask.
  885. VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
  886. VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );
  887. VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
  888. // Perform the test.
  889. return VerifyVersionInfo( &osvi, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask );
  890. }
  891. BOOL
  892. IsCompatibleOperatingSystem( IN DWORD dwVersion )
  893. /*++
  894. Routine Description:
  895. Checks whether the OS version of target system is compatible or not
  896. Arguments: None
  897. Return Value:
  898. FALSE : On failure
  899. TRUE : On success
  900. --*/
  901. {
  902. //
  903. // for historical reasons we wont neither clear nor set the error code here
  904. //
  905. // OS version above windows 2000 is compatible
  906. return (dwVersion >= 5000);
  907. }
  908. BOOL
  909. SetOsVersion( IN DWORD dwMajor,
  910. IN DWORD dwMinor,
  911. IN WORD wServicePackMajor )
  912. /*++
  913. Routine Description:
  914. Sets the OS version of target system with the specified mask
  915. Arguments:
  916. [IN] dwMajor : Major version
  917. [IN] dwMinor : Minor version
  918. [IN] wServicePackMajor : Service pack major version
  919. Return Value:
  920. FALSE : On failure
  921. TRUE : On success
  922. --*/
  923. {
  924. // local variables
  925. static BOOL bSet = FALSE;
  926. //
  927. // for historical reasons we wont neither clear nor set the error code here
  928. //
  929. // we won't support below Windows 2000
  930. if ( dwMajor < 5 || bSet == TRUE )
  931. {
  932. INVALID_PARAMETER();
  933. return FALSE;
  934. }
  935. // rest of information we need not bother
  936. bSet = TRUE;
  937. g_dwMajorVersion = dwMajor;
  938. g_dwMinorVersion = dwMinor;
  939. g_wServicePackMajor = wServicePackMajor;
  940. // return
  941. return TRUE;
  942. }
  943. LPCWSTR
  944. GetResString( IN UINT uID )
  945. /*++
  946. Routine Description:
  947. Sets the OS version of target system with the specified mask
  948. Arguments:
  949. [IN] uID : Resource ID
  950. Return Value:
  951. FALSE : On failure
  952. TRUE : On success
  953. --*/
  954. {
  955. static DWORD dwCount = 0;
  956. dwCount++;
  957. return GetResString2( uID, 4 + (dwCount % 10) );
  958. }
  959. LPCWSTR
  960. GetResString2( IN UINT uID,
  961. IN DWORD dwIndexNumber )
  962. /*++
  963. Routine Description:
  964. Sets the OS version of target system with the specified mask
  965. Arguments:
  966. [IN] uID : Resource ID
  967. [IN] dwIndexNumber : Index number
  968. Return Value:
  969. FALSE : On failure
  970. TRUE : On success
  971. --*/
  972. {
  973. // local variables
  974. DWORD dwCount = 0;
  975. DWORD dwLength = 0;
  976. LPVOID pvBuffer = NULL;
  977. TARRAY arrTemp = NULL;
  978. LPWSTR pwszTemp = NULL; // pointer to handle error message
  979. //
  980. // for historical reasons we wont neither clear nor set the error code here
  981. //
  982. // check the input value
  983. if ( uID == 0 )
  984. {
  985. INVALID_PARAMETER();
  986. return cwszNullString;
  987. }
  988. // initialize the gloabal data structure
  989. if ( InitGlobals() == FALSE )
  990. {
  991. return cwszNullString;
  992. }
  993. // check whether we have sufficient indexes or not
  994. dwCount = DynArrayGetCount2( g_arrData, INDEX_RESOURCE_STRING );
  995. if ( dwCount <= dwIndexNumber )
  996. {
  997. // requested index is more than existing
  998. // add new columns to the array so that request can be satisfied
  999. arrTemp = DynArrayItem( g_arrData, INDEX_RESOURCE_STRING );
  1000. if ( arrTemp == NULL ||
  1001. DynArrayAddColumns( arrTemp, dwIndexNumber - dwCount + 1 ) == -1 )
  1002. {
  1003. OUT_OF_MEMORY();
  1004. return cwszNullString;
  1005. }
  1006. }
  1007. //
  1008. // we need to load the entire string that is defined string table
  1009. // we will try to load the string incrementing our buffer by 128 bytes
  1010. // at a time
  1011. dwCount = 0;
  1012. dwLength = 128;
  1013. // ...
  1014. do
  1015. {
  1016. // increment the buffer length by 256
  1017. // we will always double the length we curretly have
  1018. dwLength *= 2;
  1019. //
  1020. // LoadString will null terminate the string with null character
  1021. // and will return the no. of characters read from string table
  1022. // not including the null terminator -- so at all times, in order
  1023. // make sure that we load the entire string from the string table
  1024. // check the no. of characters returned with one less than the buffer
  1025. // we have -- if that condition matches, we will loop once again
  1026. // to load the rest of the string and we will continue this way
  1027. // until we got the entire string into memory
  1028. //
  1029. // loading the string from resource file string table
  1030. if ( (pwszTemp = GetTempBuffer( INDEX_TEMP_RESOURCE,
  1031. NULL, dwLength, TRUE )) == NULL )
  1032. {
  1033. OUT_OF_MEMORY();
  1034. return cwszNullString;
  1035. }
  1036. // try to load the string
  1037. dwCount = LoadString( NULL, uID, pwszTemp, dwLength );
  1038. if ( dwCount == 0 )
  1039. {
  1040. // check the last error
  1041. if ( GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND )
  1042. {
  1043. // try if message exists in the message table
  1044. dwCount = FormatMessageW( FORMAT_MESSAGE_FROM_HMODULE |
  1045. FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1046. NULL, uID, 0, (LPWSTR) &pvBuffer, 0, NULL );
  1047. // check the result
  1048. if ( dwCount != 0 )
  1049. {
  1050. pwszTemp = (LPWSTR) pvBuffer;
  1051. }
  1052. }
  1053. if ( dwCount == 0 )
  1054. {
  1055. // error occurred -- return
  1056. return cwszNullString;
  1057. }
  1058. }
  1059. } while ( dwCount >= (dwLength - 1) );
  1060. // save the resource message
  1061. // and check whether we are successful in saving the resource text or not
  1062. if ( DynArraySetString2( g_arrData,
  1063. INDEX_RESOURCE_STRING,
  1064. dwIndexNumber, pwszTemp, 0 ) == FALSE )
  1065. {
  1066. OUT_OF_MEMORY();
  1067. return cwszNullString;
  1068. }
  1069. // free the memory allocated with FormatMessage function
  1070. if ( pvBuffer != NULL )
  1071. {
  1072. LocalFree( pvBuffer );
  1073. pvBuffer = NULL;
  1074. }
  1075. // return
  1076. return DynArrayItemAsString2( g_arrData, INDEX_RESOURCE_STRING, dwIndexNumber );
  1077. }
  1078. double
  1079. AsFloat( IN LPCWSTR pwszValue )
  1080. /*++
  1081. Routine Description:
  1082. Gets the float value for a given string
  1083. Arguments:
  1084. [IN] pwszValue : Input string
  1085. Return Value:
  1086. 0.0f : On failure
  1087. double value : On success
  1088. --*/
  1089. {
  1090. // local variables
  1091. double dblValue = 0.0f;
  1092. LPWSTR pwszStopString = NULL;
  1093. LPCWSTR pwszValueString = NULL;
  1094. //
  1095. // for historical reasons we wont neither clear nor set the error code here
  1096. //
  1097. // check the input value
  1098. if ( pwszValue == NULL || StringLength( pwszValue, 0 ) == 0 )
  1099. {
  1100. INVALID_PARAMETER();
  1101. return 0.0f;
  1102. }
  1103. // initialize the global data structure
  1104. if ( InitGlobals() == FALSE )
  1105. {
  1106. return 0.0f;
  1107. }
  1108. // get the temporary memory location
  1109. pwszValueString = GetTempBuffer( 0, pwszValue, 0, FALSE );
  1110. if ( pwszValueString == NULL )
  1111. {
  1112. OUT_OF_MEMORY();
  1113. return 0.0f;
  1114. }
  1115. // convert the string value into double value and return the same
  1116. dblValue = wcstod( pwszValueString, &pwszStopString );
  1117. // determine whether the conversion took place properly or not
  1118. // value is invalid if
  1119. // 1. overflow / underflow occured
  1120. // 2. pwszStopString's length is not equal to 0
  1121. if ( errno == ERANGE ||
  1122. ( pwszStopString != NULL && StringLength( pwszStopString, 0 ) != 0 ) )
  1123. {
  1124. INVALID_PARAMETER();
  1125. return 0.0f;
  1126. }
  1127. // return the value
  1128. return dblValue;
  1129. }
  1130. BOOL
  1131. IsFloatingPoint( IN LPCWSTR pwszValue )
  1132. /*++
  1133. Routine Description:
  1134. Checks whether the given string is float value or not
  1135. Arguments:
  1136. [IN] pwszValue : Input string
  1137. Return Value:
  1138. FALSE : On failure
  1139. TRUE : On success
  1140. --*/
  1141. {
  1142. // attempt to convert the value
  1143. AsFloat( pwszValue );
  1144. // check the error code
  1145. return (GetLastError() == NO_ERROR);
  1146. }
  1147. LONG
  1148. AsLong( IN LPCWSTR pwszValue,
  1149. IN DWORD dwBase )
  1150. /*++
  1151. Routine Description:
  1152. Gets the long value for a given string
  1153. Arguments:
  1154. [IN] pwszValue : Input string
  1155. [IN] dwBase : Base value
  1156. Return Value:
  1157. 0L : On failure
  1158. Long value : On success
  1159. --*/
  1160. {
  1161. // local variables
  1162. LONG lValue = 0L;
  1163. LPWSTR pwszStopString = NULL;
  1164. LPWSTR pwszValueString = NULL;
  1165. //
  1166. // for historical reasons we wont neither clear nor set the error code here
  1167. //
  1168. // validate the base
  1169. // value should be in the range of 2 - 36 only
  1170. if ( dwBase < 2 || dwBase > 36 || pwszValue == NULL )
  1171. {
  1172. INVALID_PARAMETER();
  1173. return 0L;
  1174. }
  1175. // initialize the global data structure
  1176. // and save the current value in global data structure
  1177. if ( InitGlobals() == FALSE )
  1178. {
  1179. return 0L;
  1180. }
  1181. // get the temporary buffer
  1182. pwszValueString = GetTempBuffer( 0, pwszValue, 0, FALSE );
  1183. if ( pwszValueString == NULL )
  1184. {
  1185. OUT_OF_MEMORY();
  1186. return 0L;
  1187. }
  1188. // trim the string
  1189. TrimString2( pwszValueString, NULL, TRIM_ALL );
  1190. if ( StringLength( pwszValueString, 0 ) == 0 )
  1191. {
  1192. INVALID_PARAMETER();
  1193. return 0L;
  1194. }
  1195. // convert the string value into long value and return the same
  1196. // based on the "sign" of the number choose the path
  1197. if ( pwszValueString[ 0 ] == L'-' )
  1198. {
  1199. lValue = wcstol( pwszValueString, &pwszStopString, dwBase );
  1200. }
  1201. else
  1202. {
  1203. // NOTE: though we are not capturing the return value into
  1204. // unsigned long we do need to call the unsigned long conversion function
  1205. lValue = wcstoul( pwszValueString, &pwszStopString, dwBase );
  1206. }
  1207. // determine whether the conversion took place properly or not
  1208. // value is invalid if
  1209. // 1. overflow / underflow occured
  1210. // 2. pwszStopString's length is not equal to 0
  1211. if ( errno == ERANGE ||
  1212. ( pwszStopString != NULL && StringLength( pwszStopString, 0 ) != 0 ) )
  1213. {
  1214. INVALID_PARAMETER();
  1215. return 0L;
  1216. }
  1217. // return
  1218. return lValue;
  1219. }
  1220. BOOL
  1221. IsNumeric( IN LPCWSTR pwszValue,
  1222. IN DWORD dwBase,
  1223. IN BOOL bSigned )
  1224. /*++
  1225. Routine Description:
  1226. Checks whether the given string is numeric or not
  1227. Arguments:
  1228. [IN] pwszValue : Input string
  1229. [IN] dwBase : Base value
  1230. [IN] bSigned : Sign Value (+/-)
  1231. Return Value:
  1232. FALSE : On failure
  1233. TRUE : On success
  1234. --*/
  1235. {
  1236. // local variables
  1237. LPWSTR pwszNumber = NULL;
  1238. LPWSTR pwszStopString = NULL;
  1239. // check the input:
  1240. // validate the base
  1241. // value should be in the range of 2 - 36 only
  1242. if ( dwBase < 2 || dwBase > 36 || pwszValue == NULL )
  1243. {
  1244. INVALID_PARAMETER();
  1245. return 0L;
  1246. }
  1247. // to better validate the numeric values we need the TRIMmed string
  1248. pwszNumber = GetTempBuffer( 0, pwszValue, 0, FALSE );
  1249. if ( pwszNumber == NULL )
  1250. {
  1251. OUT_OF_MEMORY();
  1252. return FALSE;
  1253. }
  1254. // trim the string contents
  1255. TrimString2( pwszNumber, NULL, TRIM_ALL );
  1256. // check the length
  1257. if( StringLength( pwszNumber, 0 ) == 0 )
  1258. {
  1259. return FALSE;
  1260. }
  1261. // validate the "sign"
  1262. if ( bSigned == FALSE && pwszNumber[ 0 ] == L'-' )
  1263. {
  1264. return FALSE;
  1265. }
  1266. // convert the string value into long value and return the same
  1267. if ( bSigned == TRUE )
  1268. {
  1269. wcstol( pwszNumber, &pwszStopString, dwBase );
  1270. }
  1271. else
  1272. {
  1273. wcstoul( pwszNumber, &pwszStopString, dwBase );
  1274. }
  1275. // determine whether the conversion took place properly or not
  1276. // value is invalid if
  1277. // 1. overflow / underflow occured
  1278. // 2. pwszStopString's length is not equal to 0
  1279. if ( errno == ERANGE ||
  1280. ( pwszStopString != NULL && StringLength( pwszStopString, 0 ) != 0 ) )
  1281. {
  1282. return FALSE;
  1283. }
  1284. // value is valid numeric
  1285. return TRUE;
  1286. }
  1287. LPCWSTR
  1288. FindChar( IN LPCWSTR pwszString,
  1289. IN WCHAR wch,
  1290. IN DWORD dwFrom )
  1291. /*++
  1292. Routine Description:
  1293. Searches a string for the first occurrence of a character that
  1294. matches the specified character. The comparison is not case sensitive.
  1295. Arguments:
  1296. [IN] pwszValue : Address of the string to be searched.
  1297. [IN] wch : Character to be used for comparison.
  1298. [IN] dwFrom : to start from the location
  1299. Return Value:
  1300. NULL : On failure
  1301. LPWSTR : On success
  1302. --*/
  1303. {
  1304. // local variables
  1305. LONG lIndex = 0;
  1306. lIndex = FindChar2( pwszString, wch, TRUE, dwFrom );
  1307. if ( lIndex == -1 )
  1308. {
  1309. return NULL;
  1310. }
  1311. return pwszString + lIndex;
  1312. }
  1313. LONG
  1314. FindChar2( IN LPCWSTR pwszString,
  1315. IN WCHAR wch,
  1316. IN BOOL bIgnoreCase,
  1317. IN DWORD dwFrom )
  1318. /*++
  1319. Routine Description:
  1320. Searches a string for the first occurrence of a character that
  1321. matches the specified character. The comparison either (case sensitive/in-sensitive)
  1322. depends on the bIgoneCase value.
  1323. Arguments:
  1324. [IN] pwszValue : Address of the string to be searched.
  1325. [IN] wch : Character to be used for comparison.
  1326. [IN] bIgnoreCase : Flag to check for case sensitive/in-sensitive
  1327. If FALSE, case sensitive else in-sensitive
  1328. [IN] dwFrom : to start from the location
  1329. Return Value:
  1330. 0 : On failure
  1331. Long value : On success
  1332. --*/
  1333. {
  1334. // local variables
  1335. DWORD dwLength = 0;
  1336. LPWSTR pwsz = NULL;
  1337. //
  1338. // for historical reasons we wont neither clear nor set the error code here
  1339. //
  1340. // check the inputs
  1341. if ( pwszString == NULL )
  1342. {
  1343. INVALID_PARAMETER();
  1344. return -1;
  1345. }
  1346. // check the length of the text that has to be find. if it is
  1347. // more than the original it is obvious that it cannot be found
  1348. dwLength = StringLength( pwszString, 0 );
  1349. if ( dwLength == 0 || dwFrom >= dwLength )
  1350. {
  1351. SetLastError( ERROR_NOT_FOUND );
  1352. return -1;
  1353. }
  1354. // search for the character
  1355. if ( bIgnoreCase == TRUE )
  1356. {
  1357. pwsz = StrChrI( pwszString + dwFrom, wch );
  1358. }
  1359. else
  1360. {
  1361. pwsz = StrChr( pwszString + dwFrom, wch );
  1362. }
  1363. // check the result
  1364. if ( pwsz == NULL )
  1365. {
  1366. SetLastError( ERROR_NOT_FOUND );
  1367. return -1;
  1368. }
  1369. // determine the position and return
  1370. return (LONG) (DWORD_PTR)(pwsz - pwszString);
  1371. }
  1372. BOOL
  1373. InString( IN LPCWSTR pwszString,
  1374. IN LPCWSTR pwszList,
  1375. IN BOOL bIgnoreCase )
  1376. /*++
  1377. Routine Description:
  1378. Checks for the first occurrence of one string within the list.
  1379. Arguments:
  1380. [IN] pwszValue : Address of the string
  1381. [IN] pwsz : List of string to be searched for
  1382. [IN] bIgnoreCase : Flag to check for case sensitive/in-sensitive
  1383. If FALSE, case sensitive else in-sensitive
  1384. Return Value:
  1385. FALSE : On failure
  1386. TRUE : On success
  1387. --*/
  1388. {
  1389. // local variables
  1390. DWORD dwListLength = 0;
  1391. DWORD dwStringLength = 0;
  1392. LPWSTR pwszFmtList = NULL;
  1393. LPWSTR pwszFmtString = NULL;
  1394. HRESULT hr = S_OK;
  1395. //
  1396. // for historical reasons we wont neither clear nor set the error code here
  1397. //
  1398. // check the input value
  1399. if ( pwszString == NULL || pwszList == NULL )
  1400. {
  1401. INVALID_PARAMETER();
  1402. return FALSE;
  1403. }
  1404. //
  1405. // get memory for the temporary buffers
  1406. // | + length of the original string ( list / string ) + | + NULL + NULL
  1407. // format list
  1408. dwListLength = StringLength( pwszList, 0 ) + 4;
  1409. if ( (pwszFmtList = GetTempBuffer( 0,
  1410. NULL,
  1411. dwListLength, TRUE )) == NULL )
  1412. {
  1413. OUT_OF_MEMORY();
  1414. return FALSE;
  1415. }
  1416. // format string
  1417. dwStringLength = StringLength( pwszString, 0 ) + 4;
  1418. if ( (pwszFmtString = GetTempBuffer( 1,
  1419. NULL,
  1420. dwStringLength, TRUE )) == NULL )
  1421. {
  1422. OUT_OF_MEMORY();
  1423. return FALSE;
  1424. }
  1425. // prepare the strings for searching
  1426. hr = StringCchPrintfW( pwszFmtList, dwListLength, L"|%s|", pwszList );
  1427. if ( FAILED( hr ) )
  1428. {
  1429. SetLastError( HRESULT_CODE( hr ) );
  1430. return FALSE;
  1431. }
  1432. hr = StringCchPrintfW( pwszFmtString, dwStringLength, L"|%s|", pwszString );
  1433. if ( FAILED( hr ) )
  1434. {
  1435. SetLastError( HRESULT_CODE( hr ) );
  1436. return FALSE;
  1437. }
  1438. // search for the string in the list and return result
  1439. return (FindString2( pwszFmtList, pwszFmtString, bIgnoreCase, 0 ) != -1);
  1440. }
  1441. LPCWSTR
  1442. FindOneOf( IN LPCWSTR pwszText,
  1443. IN LPCWSTR pwszTextToFind,
  1444. IN DWORD dwFrom )
  1445. /*++
  1446. Routine Description:
  1447. Finds the first occurrence one of characters from a substring within a string.
  1448. The comparison is not case sensitive.
  1449. Arguments:
  1450. [IN] pwszText : Address of the string being searched.
  1451. [IN] pwszTextToFind : Substring to search for.
  1452. [IN] dwFrom : to start from the location
  1453. Return Value:
  1454. FALSE : On failure
  1455. TRUE : On success
  1456. --*/
  1457. {
  1458. // local variables
  1459. LONG lIndex = 0;
  1460. lIndex = FindOneOf2( pwszText, pwszTextToFind, TRUE, dwFrom );
  1461. if ( lIndex == -1 )
  1462. {
  1463. return NULL;
  1464. }
  1465. return pwszText + lIndex;
  1466. }
  1467. LONG
  1468. FindOneOf2( IN LPCWSTR pwszText,
  1469. IN LPCWSTR pwszTextToFind,
  1470. IN BOOL bIgnoreCase,
  1471. IN DWORD dwFrom )
  1472. /*++
  1473. Routine Description:
  1474. Finds the first occurrence one of characters from a substring within a string.
  1475. The comparison is either case sensitive/in-sensitive depends on
  1476. bIgnoreCase value.
  1477. Arguments:
  1478. [IN] pwszText : Address of the string being searched.
  1479. [IN] pwszTextToFind : Substring to search for.
  1480. [IN] bIgnoreCase : Flag to check for case sensitive/in-sensitive
  1481. If FALSE, case sensitive else in-sensitive
  1482. [IN] dwFrom : to start from the location
  1483. Return Value:
  1484. 0L : On failure
  1485. Long value : On success
  1486. --*/
  1487. {
  1488. // local variables
  1489. DWORD dw = 0;
  1490. LONG lResult = 0;
  1491. DWORD dwFindLength = 0;
  1492. //
  1493. // for historical reasons we wont neither clear nor set the error code here
  1494. //
  1495. // check the inputs
  1496. if ( pwszText == NULL || pwszTextToFind == NULL )
  1497. {
  1498. INVALID_PARAMETER();
  1499. return -1;
  1500. }
  1501. // get the length of the find string
  1502. dwFindLength = StringLength( pwszTextToFind, 0 );
  1503. // check the length of the text that has to be find. if it is
  1504. // more than the original it is obvious that it cannot be found
  1505. if ( dwFindLength == 0 ||
  1506. StringLength( pwszText, 0 ) == 0 ||
  1507. dwFrom >= (DWORD) StringLength( pwszText, 0 ) )
  1508. {
  1509. SetLastError( ERROR_NOT_FOUND );
  1510. return -1;
  1511. }
  1512. // traverse thru the original text
  1513. for( dw = 0; dw < dwFindLength; dw++ )
  1514. {
  1515. // search for the character
  1516. lResult = FindChar2( pwszText, pwszTextToFind[ dw ], bIgnoreCase, dwFrom );
  1517. if ( lResult != -1 )
  1518. {
  1519. return lResult;
  1520. }
  1521. }
  1522. // string not found
  1523. SetLastError( ERROR_NOT_FOUND );
  1524. return -1;
  1525. }
  1526. LPCWSTR
  1527. FindString( IN LPCWSTR pwszText,
  1528. IN LPCWSTR pwszTextToFind,
  1529. IN DWORD dwFrom )
  1530. /*++
  1531. Routine Description:
  1532. Finds the first occurrence of a substring within a string.
  1533. The comparison is not case sensitive.
  1534. Arguments:
  1535. [IN] pwszText : Address of the string being searched.
  1536. [IN] pwszTextToFind : Substring to search for.
  1537. [IN] dwFrom : to start from the location
  1538. Return Value:
  1539. 0L : On failure
  1540. Long value : On success
  1541. --*/
  1542. {
  1543. // local variables
  1544. LONG lIndex = 0;
  1545. lIndex = FindString2( pwszText, pwszTextToFind, TRUE, dwFrom );
  1546. if ( lIndex == -1 )
  1547. {
  1548. return NULL;
  1549. }
  1550. return pwszText + lIndex;
  1551. }
  1552. LONG
  1553. FindString2( IN LPCWSTR pwszText,
  1554. IN LPCWSTR pwszTextToFind,
  1555. IN BOOL bIgnoreCase,
  1556. IN DWORD dwFrom )
  1557. /*++
  1558. Routine Description:
  1559. Finds the first occurrence of a substring within a string.
  1560. The comparison is either case sensitive/in-sensitive depends on
  1561. bIgnoreCase value.
  1562. Arguments:
  1563. [IN] pwszText : Address of the string being searched.
  1564. [IN] pwszTextToFind : Substring to search for.
  1565. [IN] bIgnoreCase : Flag to check for case sensitive/in-sensitive
  1566. If FALSE, case sensitive else in-sensitive
  1567. [IN] dwFrom : to start from the location
  1568. Return Value:
  1569. 0L : On failure
  1570. Long value : On success
  1571. --*/
  1572. {
  1573. // local variables
  1574. DWORD dwLength = 0;
  1575. DWORD dwFindLength = 0;
  1576. LPWSTR pwsz = NULL;
  1577. //
  1578. // for historical reasons we wont neither clear nor set the error code here
  1579. //
  1580. // check the inputs
  1581. if ( pwszText == NULL || pwszTextToFind == NULL )
  1582. {
  1583. INVALID_PARAMETER();
  1584. return -1;
  1585. }
  1586. // get the lengths
  1587. dwLength = StringLength( pwszText, 0 );
  1588. dwFindLength = StringLength( pwszTextToFind, 0 );
  1589. // check the length of the text that has to be find. if it is
  1590. // more than the original it is obvious that it cannot be found
  1591. if ( dwFindLength == 0 || dwLength == 0 ||
  1592. dwFrom >= dwLength || (dwLength - dwFrom < dwFindLength) )
  1593. {
  1594. SetLastError( ERROR_NOT_FOUND );
  1595. return -1;
  1596. }
  1597. // do the search
  1598. if ( bIgnoreCase == TRUE )
  1599. {
  1600. pwsz = StrStrI( pwszText + dwFrom, pwszTextToFind );
  1601. }
  1602. else
  1603. {
  1604. pwsz = StrStr( pwszText + dwFrom, pwszTextToFind );
  1605. }
  1606. if ( pwsz == NULL )
  1607. {
  1608. // string not found
  1609. SetLastError( ERROR_NOT_FOUND );
  1610. return -1;
  1611. }
  1612. // determine the position an return
  1613. return (LONG) (DWORD_PTR)(pwsz - pwszText);
  1614. }
  1615. LONG
  1616. StringLengthInBytes( IN LPCWSTR pwszText )
  1617. /*++
  1618. Routine Description:
  1619. Finds length of a given string
  1620. Arguments:
  1621. [IN] pwszText : Address of the string being searched.
  1622. Return Value:
  1623. 0L : On failure
  1624. Long value : On success
  1625. --*/
  1626. {
  1627. // local variables
  1628. LONG lLength = 0;
  1629. if ( NULL == pwszText || StringLength( pwszText, 0 ) == 0)
  1630. {
  1631. return 0;
  1632. }
  1633. //
  1634. // for historical reasons we wont neither clear nor set the error code here
  1635. //
  1636. // get the length of the string in bytes
  1637. // since this function includes the count for null character also, ignore that information
  1638. lLength = WideCharToMultiByte( _DEFAULT_CODEPAGE, 0, pwszText, -1, NULL, 0, NULL, NULL ) - 1;
  1639. // return the length information
  1640. return lLength;
  1641. }
  1642. LPCWSTR
  1643. TrimString( IN OUT LPWSTR pwszString,
  1644. IN DWORD dwFlags )
  1645. /*++
  1646. Routine Description:
  1647. Removes (trims) spaces/tabs from a string.
  1648. Arguments:
  1649. [IN] pwszString : Address of the string to be trimmed.
  1650. [IN] dwFlags : Flags to trim LEFT or RIGHT or both sides
  1651. Return Value:
  1652. 0L : On failure
  1653. Long value : On success
  1654. --*/
  1655. {
  1656. return TrimString2( pwszString, NULL, dwFlags );
  1657. }
  1658. LPCWSTR
  1659. TrimString2( IN OUT LPWSTR pwszString,
  1660. IN LPCWSTR pwszTrimChars,
  1661. IN DWORD dwFlags )
  1662. /*++
  1663. Routine Description:
  1664. Removes (trims) specified leading and trailing characters from a string.
  1665. Arguments:
  1666. [IN] pwszString : Address of the string to be trimmed.
  1667. [IN] pwszString : characters will be trimmed from pwszString.
  1668. [IN] dwFlags : Flags to trim LEFT or RIGHT or both sides
  1669. Return Value:
  1670. 0L : On failure
  1671. Long value : On success
  1672. --*/
  1673. {
  1674. //sub-local variables
  1675. LPWSTR psz = NULL;
  1676. LPWSTR pszStartMeAt = NULL;
  1677. LPWSTR pszMark = NULL;
  1678. const WCHAR wszDefaultTrimChars[3] = L" \t";
  1679. //
  1680. // for historical reasons we wont neither clear nor set the error code here
  1681. //
  1682. // check for empty string
  1683. if ( NULL == pwszString || StringLength( pwszString , 0 ) == 0 )
  1684. {
  1685. // there is no need to set any error here..
  1686. // if string is empty.. then return the same.
  1687. return cwszNullString;
  1688. }
  1689. // check for empty string.. if pwszTrimChars is empty,
  1690. // by default it trims spaces and tabs
  1691. if ( NULL == pwszTrimChars || StringLength( pwszTrimChars, 0 ) == 0 )
  1692. {
  1693. pwszTrimChars = wszDefaultTrimChars;
  1694. }
  1695. //
  1696. // Trim leading characters.
  1697. //
  1698. psz = pwszString;
  1699. //check whether to trim left or both side(s)
  1700. if ( (dwFlags == TRIM_ALL) || (dwFlags == TRIM_LEFT) )
  1701. {
  1702. //search for character(s) to trim
  1703. while (*psz && StrChrW(pwszTrimChars, *psz))
  1704. {
  1705. //increment the address
  1706. psz++;
  1707. }
  1708. pszStartMeAt = psz;
  1709. }
  1710. //
  1711. // Trim trailing characters.
  1712. //
  1713. //check whether to trim right or both side(s)
  1714. if ( (dwFlags == TRIM_ALL) || (dwFlags == TRIM_RIGHT) )
  1715. {
  1716. if (dwFlags == TRIM_RIGHT)
  1717. {
  1718. psz = pwszString;
  1719. }
  1720. while (*psz)
  1721. {
  1722. //search for character(s) to trim
  1723. if (StrChrW(pwszTrimChars, *psz))
  1724. {
  1725. if (!pszMark)
  1726. {
  1727. pszMark = psz;
  1728. }
  1729. }
  1730. else
  1731. {
  1732. pszMark = NULL;
  1733. }
  1734. //increment the address
  1735. psz++;
  1736. }
  1737. // Any trailing characters to clip?
  1738. if ( pszMark != NULL )
  1739. {
  1740. // Yes.. set NULL character..
  1741. *pszMark = '\0';
  1742. }
  1743. }
  1744. /* Relocate stripped string. */
  1745. if (pszStartMeAt > pwszString)
  1746. {
  1747. /* (+ 1) for null terminator. */
  1748. StringCopy ( pwszString, pszStartMeAt, StringLength(pszStartMeAt, 0) + 1 );
  1749. }
  1750. // return the trimmed string
  1751. return pwszString;
  1752. }
  1753. LPCWSTR
  1754. QuoteMeta( IN LPCWSTR pwszText,
  1755. IN DWORD dwQuoteIndex )
  1756. /*++
  1757. Routine Description:
  1758. Formats the string properly if the string contains any '%' characters
  1759. Arguments:
  1760. [IN] pwszString : Address of the string.
  1761. [IN] dwQuoteIndex : Index number
  1762. Return Value:
  1763. NULL : On failure
  1764. LPWSTR : On success
  1765. --*/
  1766. {
  1767. // local variables
  1768. DWORD dw = 0;
  1769. DWORD dwIndex = 0;
  1770. DWORD dwBufLen = 0;
  1771. DWORD dwLength = 0;
  1772. TARRAY arrQuotes = NULL;
  1773. LPCWSTR pwszTemp = NULL;
  1774. LPWSTR pwszQuoteText = NULL;
  1775. const WCHAR pwszQuoteChars[] = L"%";
  1776. //
  1777. // for historical reasons we wont neither clear nor set the error code here
  1778. //
  1779. // check the inputs
  1780. if ( pwszText == NULL || dwQuoteIndex == 0 )
  1781. {
  1782. INVALID_PARAMETER();
  1783. return cwszNullString;
  1784. }
  1785. // determine the length of the text that needs to be quoted
  1786. dwLength = StringLength( pwszText, 0 );
  1787. if ( dwLength == 0 )
  1788. {
  1789. return pwszText;
  1790. }
  1791. // check whether the special chacters do exist in the text or not
  1792. // if not, simply return
  1793. else if ( FindOneOf( pwszText, pwszQuoteChars, 0 ) == NULL )
  1794. {
  1795. return pwszText;
  1796. }
  1797. // initialize the global data structure
  1798. if ( InitGlobals() == FALSE )
  1799. {
  1800. return cwszNullString;
  1801. }
  1802. // get the quotes array pointer
  1803. arrQuotes = DynArrayItem( g_arrData, INDEX_QUOTE_STRING );
  1804. if ( arrQuotes == NULL )
  1805. {
  1806. UNEXPECTED_ERROR();
  1807. return cwszNullString;
  1808. }
  1809. // though the quote index needs to be > 0 when passing to this function,
  1810. // internally we need this to be 1 less than the value passed -- so
  1811. dwQuoteIndex--;
  1812. // check whether needed indexes exist or not
  1813. dwIndex = DynArrayGetCount( arrQuotes );
  1814. if ( dwIndex <= dwQuoteIndex )
  1815. {
  1816. // add the needed no. of columns
  1817. dw = DynArrayAddColumns( arrQuotes, dwQuoteIndex - dwIndex + 1 );
  1818. // check whether columns were added or not
  1819. if ( dw != dwQuoteIndex - dwIndex + 1 )
  1820. {
  1821. OUT_OF_MEMORY();
  1822. return cwszNullString;
  1823. }
  1824. }
  1825. // allocate the buffer ... it should twice the original
  1826. dwBufLen = (dwLength + 1) * 2;
  1827. pwszQuoteText = GetTempBuffer( 0, NULL, dwBufLen, TRUE );
  1828. if ( pwszQuoteText == NULL )
  1829. {
  1830. OUT_OF_MEMORY();
  1831. return cwszNullString;
  1832. }
  1833. // do the quoting ...
  1834. dwIndex = 0;
  1835. for( dw = 0; dw < dwLength; dw++ )
  1836. {
  1837. // check whether the current character is quote char or not
  1838. // NOTE: for time being this function only suppresses the '%' character escape sequences
  1839. if ( FindChar( pwszQuoteChars, pwszText[ dw ], 0 ) != NULL )
  1840. {
  1841. pwszQuoteText[ dwIndex++ ] = L'%';
  1842. }
  1843. // copy the character
  1844. pwszQuoteText[ dwIndex++ ] = pwszText[ dw ];
  1845. // it is obvious that we wont come into this condition
  1846. // but, makes no difference if we are more cautious on this
  1847. if ( dwIndex == dwBufLen - 1 )
  1848. {
  1849. // error, error -- we should never come here
  1850. // this is because even if the original string is full of
  1851. // '%' characters, we are allocating memory for two null characters
  1852. // which means, the loop should be terminated before falling into
  1853. // this condition
  1854. break;
  1855. }
  1856. }
  1857. // put the null character
  1858. pwszQuoteText[ dwIndex ] = cwchNullChar;
  1859. // save the quoted text in dynamic array
  1860. if ( DynArraySetString( arrQuotes, dwQuoteIndex, pwszQuoteText, 0 ) == FALSE )
  1861. {
  1862. OUT_OF_MEMORY();
  1863. return cwszNullString;
  1864. }
  1865. // get the text from the array
  1866. pwszTemp = DynArrayItemAsString( arrQuotes, dwQuoteIndex );
  1867. if ( pwszTemp == NULL )
  1868. {
  1869. UNEXPECTED_ERROR();
  1870. return cwszNullString;
  1871. }
  1872. // return
  1873. return pwszTemp;
  1874. }
  1875. LPCWSTR
  1876. AdjustStringLength( IN LPWSTR pwszValue,
  1877. IN DWORD dwLength,
  1878. IN BOOL bPadLeft )
  1879. /*++
  1880. Routine Description:
  1881. Adjusts the string length by padding spaces for displaying output in
  1882. LIST, TABLE or CSV formats
  1883. Arguments:
  1884. [IN] pwszValue : Address of the string.
  1885. [IN] dwLength : Index number
  1886. [IN] bPadLeft : Flag to pad left/right spaces
  1887. Return Value:
  1888. NULL : On failure
  1889. LPWSTR : On success
  1890. --*/
  1891. {
  1892. // local variables
  1893. DWORD dw = 0;
  1894. DWORD dwTemp = 0;
  1895. DWORD dwBufLen = 0;
  1896. DWORD dwCurrLength = 0;
  1897. LPWSTR pwszBuffer = NULL;
  1898. LPWSTR pwszSpaces = NULL;
  1899. WCHAR wszCharacter[ 3 ] = L"\0"; // two WCHAR's is enough -- but took 3
  1900. //
  1901. // for historical reasons we wont neither clear nor set the error code here
  1902. //
  1903. // check the input value
  1904. if ( pwszValue == NULL )
  1905. {
  1906. INVALID_PARAMETER();
  1907. return cwszNullString;
  1908. }
  1909. // determine the buffer length required
  1910. // ( accomadate some extra space than the original buffer/required length -
  1911. // this will save us from crashes )
  1912. dw = StringLengthInBytes( pwszValue );
  1913. dwBufLen = (( dw > dwLength ) ? dw : dwLength ) + 10;
  1914. // ...
  1915. if ( (pwszBuffer = GetTempBuffer( 0, NULL, dwBufLen, TRUE )) == NULL )
  1916. {
  1917. OUT_OF_MEMORY();
  1918. return cwszNullString;
  1919. }
  1920. // ...
  1921. dwCurrLength = dw;
  1922. // adjust the string value
  1923. if ( dwCurrLength < dwLength )
  1924. {
  1925. //
  1926. // length of the current value is less than the needed
  1927. // get the pointers to the temporary buffers
  1928. if ( (pwszSpaces = GetTempBuffer( 1, NULL, dwBufLen, TRUE )) == NULL )
  1929. {
  1930. OUT_OF_MEMORY();
  1931. return cwszNullString;
  1932. }
  1933. // get the spaces for the rest of the length
  1934. Replicate( pwszSpaces, L" ", dwLength - dwCurrLength, dwBufLen );
  1935. // append the spaces either to the end of the value or begining of the value
  1936. // based on the padding property
  1937. if ( bPadLeft == TRUE )
  1938. {
  1939. // spaces first and then value
  1940. StringCopy( pwszBuffer, pwszSpaces, dwBufLen );
  1941. StringConcat( pwszBuffer, pwszValue, dwBufLen );
  1942. }
  1943. else
  1944. {
  1945. // value first and then spaces
  1946. StringCopy( pwszBuffer, pwszValue, dwBufLen );
  1947. StringConcat( pwszBuffer, pwszSpaces, dwBufLen );
  1948. }
  1949. }
  1950. else
  1951. {
  1952. // copy only the characters of required length
  1953. // copy character by character
  1954. dwCurrLength = 0;
  1955. for( dw = 0; dwCurrLength < dwLength; dw++ )
  1956. {
  1957. // get the character -- 1 + 1 ( character + NULL character )
  1958. StringCopy( wszCharacter, pwszValue + dw, 2 );
  1959. // determine whether character can be appended or not
  1960. dwTemp = dwCurrLength + StringLengthInBytes( wszCharacter );
  1961. if ( dwTemp <= dwLength )
  1962. {
  1963. StringConcat( pwszBuffer, wszCharacter, dwBufLen );
  1964. }
  1965. else if ( dwTemp > dwLength )
  1966. {
  1967. break;
  1968. }
  1969. // get the current string length
  1970. dwCurrLength = dwTemp;
  1971. }
  1972. // target buffer might not got filled completely
  1973. // so, add needed no. of spaces
  1974. for( ; dwCurrLength < dwLength; dwCurrLength++ )
  1975. {
  1976. StringConcat( pwszBuffer, L" ", dwBufLen );
  1977. }
  1978. }
  1979. // copy the contents back to the original buffer
  1980. // NOTE: Buffer length assumed to be passed +1 to the length asked to adjust
  1981. StringCopy( pwszValue, pwszBuffer, dwLength + 1 );
  1982. // return the same buffer back to the caller
  1983. return pwszValue;
  1984. }
  1985. LPCWSTR
  1986. Replicate( IN LPWSTR pwszBuffer,
  1987. IN LPCWSTR pwszText,
  1988. IN DWORD dwCount,
  1989. IN DWORD dwLength )
  1990. /*++
  1991. Routine Description:
  1992. Adjusts the string length by padding spaces for displaying output in
  1993. LIST, TABLE or CSV formats
  1994. Arguments:
  1995. [IN] pwszBuffer : Address of the string to be replicated.
  1996. [IN] pwszText : String used for replicate
  1997. [IN] dwCount : Number of characters
  1998. [IN] dwLength : Length of a string
  1999. Return Value:
  2000. NULL : On failure
  2001. LPWSTR : On success
  2002. --*/
  2003. {
  2004. // local variables
  2005. DWORD dw = 0;
  2006. //
  2007. // for historical reasons we wont neither clear nor set the error code here
  2008. //
  2009. // validate the input buffers
  2010. if ( pwszBuffer == NULL || pwszText == NULL )
  2011. {
  2012. INVALID_PARAMETER();
  2013. return cwszNullString;
  2014. }
  2015. // form the string of required length
  2016. StringCopy( pwszBuffer, cwszNullString, dwLength );
  2017. for( dw = 0; dw < dwCount; dw++ )
  2018. {
  2019. // append the replication character
  2020. if ( StringConcat( pwszBuffer, pwszText, dwLength ) == FALSE )
  2021. {
  2022. // not an error condition -- but might destination buffer
  2023. // might have got filled
  2024. break;
  2025. }
  2026. }
  2027. // return the replicated buffer
  2028. return pwszBuffer;
  2029. }
  2030. BOOL
  2031. IsConsoleFile( IN FILE* fp )
  2032. /*++
  2033. Routine Description:
  2034. checks whether the file handle passed is console file or not
  2035. Arguments:
  2036. [IN] fp : File pointer
  2037. Return Value:
  2038. NULL : On failure
  2039. LPWSTR : On success
  2040. --*/
  2041. {
  2042. // local variables
  2043. INT filenum = 0;
  2044. LONG_PTR lHandle = 0;
  2045. HANDLE hFile = NULL;
  2046. DWORD dwType = 0;
  2047. DWORD dwMode = 0;
  2048. //
  2049. // for historical reasons we wont neither clear nor set the error code here
  2050. //
  2051. // check the input file pointer
  2052. if ( fp == NULL )
  2053. {
  2054. INVALID_PARAMETER();
  2055. return FALSE;
  2056. }
  2057. // get internal file index
  2058. filenum = (_fileno)( fp ); // forcing for the function version
  2059. // now get the file handle from file index and then get the type of the file
  2060. lHandle = _get_osfhandle( filenum );
  2061. if ( lHandle == -1 || errno == EBADF )
  2062. {
  2063. // set the last error
  2064. SetLastError( ERROR_INVALID_HANDLE );
  2065. // return
  2066. return FALSE;
  2067. }
  2068. // now get the type of the file handle
  2069. dwType = GetFileType( ( HANDLE ) lHandle );
  2070. // check the type of the file -- if it is not ANSI, we wont treat it as a console file
  2071. if ( dwType != FILE_TYPE_CHAR )
  2072. {
  2073. // return -- this is not an error condition --
  2074. // so we are not setting error
  2075. return FALSE;
  2076. }
  2077. // now based on the file index, get the appropriate handle
  2078. switch( filenum )
  2079. {
  2080. case 0:
  2081. {
  2082. // stdin
  2083. hFile = GetStdHandle( STD_INPUT_HANDLE );
  2084. break;
  2085. }
  2086. case 1:
  2087. {
  2088. // stdout
  2089. hFile = GetStdHandle( STD_OUTPUT_HANDLE );
  2090. break;
  2091. }
  2092. case 2:
  2093. {
  2094. // stderr
  2095. hFile = GetStdHandle( STD_ERROR_HANDLE );
  2096. break;
  2097. }
  2098. default:
  2099. {
  2100. hFile = NULL;
  2101. break;
  2102. }
  2103. }
  2104. // check the file handle
  2105. if ( hFile == NULL )
  2106. {
  2107. // file internal index couldn't be found
  2108. // this is also not an error check -- so no error
  2109. return FALSE;
  2110. }
  2111. else if ( hFile == INVALID_HANDLE_VALUE )
  2112. {
  2113. // this is a failure case
  2114. // GetStdHandle would have set the appropriate error
  2115. return FALSE;
  2116. }
  2117. // get the console file mode
  2118. if ( GetConsoleMode( hFile, &dwMode ) == FALSE )
  2119. {
  2120. // error occured in getting the console mode --
  2121. // this means, it is not a valid console file
  2122. // GetConsoleMode would have set the error code
  2123. return FALSE;
  2124. }
  2125. // yes -- the file handle passed to this function is console file
  2126. return TRUE;
  2127. }
  2128. LCID
  2129. GetSupportedUserLocale( IN OUT BOOL* pbLocaleChanged )
  2130. /*++
  2131. Routine Description:
  2132. check whether the current locale is supported by our tool or not
  2133. Arguments:
  2134. [IN] pbLocaleChanged : Flag
  2135. Return Value:
  2136. 0 : On failure
  2137. LCID : On success
  2138. --*/
  2139. {
  2140. // local variables
  2141. LCID lcid;
  2142. //
  2143. // for historical reasons we wont neither clear nor set the error code here
  2144. //
  2145. // get the current locale
  2146. lcid = GetUserDefaultLCID();
  2147. // check whether the current locale is supported by our tool or not
  2148. // if not change the locale to the english which is our default locale
  2149. if ( pbLocaleChanged != NULL )
  2150. {
  2151. *pbLocaleChanged = FALSE;
  2152. }
  2153. // ...
  2154. if ( PRIMARYLANGID( lcid ) == LANG_ARABIC || PRIMARYLANGID( lcid ) == LANG_HEBREW ||
  2155. PRIMARYLANGID( lcid ) == LANG_THAI || PRIMARYLANGID( lcid ) == LANG_HINDI ||
  2156. PRIMARYLANGID( lcid ) == LANG_TAMIL || PRIMARYLANGID( lcid ) == LANG_FARSI )
  2157. {
  2158. if ( pbLocaleChanged != NULL )
  2159. {
  2160. *pbLocaleChanged = TRUE;
  2161. }
  2162. // ...
  2163. lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ), SORT_DEFAULT ); // 0x409;
  2164. }
  2165. // return the locale
  2166. return lcid;
  2167. }
  2168. BOOL
  2169. StringCopyA( IN OUT LPSTR pszDest,
  2170. IN LPCSTR pszSource,
  2171. IN LONG lSize )
  2172. /*++
  2173. Routine Description:
  2174. Copies static ANSI string to a buffer
  2175. Arguments:
  2176. [ in/out ] pszDest => Destination buffer
  2177. [ in ] pszSource => Source buffer
  2178. [ in ] lSize => length of destination buffer
  2179. Return Value:
  2180. FALSE : On failure
  2181. TRUE : On success
  2182. --*/
  2183. {
  2184. // local variables
  2185. HRESULT hr = S_OK;
  2186. //
  2187. // for historical reasons we neither clear the error
  2188. // not set the error in this function
  2189. //
  2190. // validate the arguments
  2191. if ( pszDest == NULL || pszSource == NULL || lSize <= 0 )
  2192. {
  2193. return FALSE;
  2194. }
  2195. // do the copy
  2196. hr = StringCchCopyA( pszDest, lSize, pszSource );
  2197. // check for hr value
  2198. if ( FAILED( hr ) )
  2199. {
  2200. //set the error code
  2201. SetLastError( HRESULT_CODE( hr ) );
  2202. return FALSE;
  2203. }
  2204. // return success
  2205. return TRUE;
  2206. }
  2207. BOOL
  2208. StringCopyW( IN OUT LPWSTR pwszDest,
  2209. IN LPCWSTR pwszSource,
  2210. IN LONG lSize )
  2211. /*++
  2212. Routine Description:
  2213. Copies static UNICODE string to a buffer
  2214. Arguments:
  2215. [ in/out ] pwszDest => Destination buffer
  2216. [ in ] pszSource => Source buffer
  2217. [ in ] lSize => length of destination buffer
  2218. Return Value:
  2219. FALSE : On failure
  2220. TRUE : On success
  2221. --*/
  2222. {
  2223. // local variables
  2224. HRESULT hr = S_OK;
  2225. //
  2226. // for historical reasons we neither clear the error
  2227. // not set the error in this function
  2228. //
  2229. // validate the arguments
  2230. if ( pwszDest == NULL || pwszSource == NULL || lSize <= 0 )
  2231. {
  2232. return FALSE;
  2233. }
  2234. // do the copy
  2235. hr = StringCchCopyW( pwszDest, lSize, pwszSource );
  2236. // check for hr value
  2237. if ( FAILED( hr ) )
  2238. {
  2239. //set the error code
  2240. SetLastError( HRESULT_CODE( hr ) );
  2241. return FALSE;
  2242. }
  2243. // return
  2244. return TRUE;
  2245. }
  2246. BOOL
  2247. StringConcatA( IN OUT LPSTR pszDest,
  2248. IN LPCSTR pszSource,
  2249. IN LONG lSize )
  2250. /*++
  2251. Routine Description:
  2252. Appends one static ANSI string to another
  2253. Arguments:
  2254. [ in/out ] pwszDest => Destination buffer
  2255. [ in ] pszSource => Source buffer
  2256. [ in ] lSize => length of destination buffer
  2257. Return Value:
  2258. FALSE : On failure
  2259. TRUE : On success
  2260. --*/
  2261. {
  2262. // local variable
  2263. HRESULT hr = S_OK;
  2264. //
  2265. // for historical reasons we neither clear the error
  2266. // not set the error in this function
  2267. //
  2268. // validate the arguments
  2269. if ( pszDest == NULL || pszSource == NULL || lSize <= 0 )
  2270. {
  2271. return FALSE;
  2272. }
  2273. // get the current length of the current contents in the destination
  2274. hr = StringCchCatA( pszDest, lSize, pszSource );
  2275. // check for hr value
  2276. if ( FAILED( hr ) )
  2277. {
  2278. //set the error code
  2279. SetLastError( HRESULT_CODE( hr ) );
  2280. return FALSE;
  2281. }
  2282. // return
  2283. return TRUE;
  2284. }
  2285. BOOL
  2286. StringConcatW( IN OUT LPWSTR pwszDest,
  2287. IN LPCWSTR pwszSource,
  2288. IN LONG lSize )
  2289. /*++
  2290. Routine Description:
  2291. Appends one UNICODE string to another
  2292. Arguments:
  2293. [ in/out ] pwszDest => Destination buffer
  2294. [ in ] pszSource => Source buffer
  2295. [ in ] lSize => length of destination buffer
  2296. Return Value:
  2297. FALSE : On failure
  2298. TRUE : On success
  2299. --*/
  2300. {
  2301. // local variable
  2302. HRESULT hr = S_OK;
  2303. //
  2304. // for historical reasons we neither clear the error
  2305. // not set the error in this function
  2306. //
  2307. // validate the arguments
  2308. if ( pwszDest == NULL || pwszSource == NULL || lSize <= 0 )
  2309. {
  2310. return FALSE;
  2311. }
  2312. // do the concatenation
  2313. hr = StringCchCatW( pwszDest, lSize, pwszSource );
  2314. // check for hr value
  2315. if ( FAILED( hr ) )
  2316. {
  2317. //set the error code
  2318. SetLastError( HRESULT_CODE( hr ) );
  2319. return FALSE;
  2320. }
  2321. // return
  2322. return TRUE;
  2323. }
  2324. BOOL
  2325. StringCopyExA( IN OUT LPSTR pszDest,
  2326. IN LPCSTR pszSource )
  2327. /*++
  2328. Routine Description:
  2329. Copies dynamic ANSI string to a buffer
  2330. Arguments:
  2331. [ in/out ] pszDest => Destination buffer
  2332. [ in ] pszSource => Source buffer
  2333. Return Value:
  2334. FALSE : On failure
  2335. TRUE : On success
  2336. --*/
  2337. {
  2338. // local variables
  2339. LONG lSize = 0;
  2340. //
  2341. // for historical reasons we neither clear the error
  2342. // not set the error in this function
  2343. //
  2344. // validate the inputs
  2345. if ( pszDest == NULL || pszSource == NULL )
  2346. {
  2347. // invalid arguments passed to the function
  2348. return FALSE;
  2349. }
  2350. // get the size of the destination buffer
  2351. lSize = GetBufferSize( pszDest );
  2352. if ( lSize < 0 )
  2353. {
  2354. // the source buffer is not allocated on heap
  2355. return FALSE;
  2356. }
  2357. else
  2358. {
  2359. // convert the size into TCHARs
  2360. lSize /= sizeof( CHAR );
  2361. }
  2362. // do the copy and return
  2363. return StringCopyA( pszDest, pszSource, lSize );
  2364. }
  2365. BOOL StringCopyExW( IN OUT LPWSTR pwszDest,
  2366. IN LPCWSTR pwszSource )
  2367. /*++
  2368. Routine Description:
  2369. Copies dynamic ANSI string to another
  2370. Arguments:
  2371. [ in/out ] pwszDest => Destination buffer
  2372. [ in ] pwszSource => Source buffer
  2373. Return Value:
  2374. FALSE : On failure
  2375. TRUE : On success
  2376. --*/
  2377. {
  2378. // local variables
  2379. LONG lSize = 0;
  2380. //
  2381. // for historical reasons we neither clear the error
  2382. // not set the error in this function
  2383. //
  2384. // validate the inputs
  2385. if ( pwszDest == NULL || pwszSource == NULL )
  2386. {
  2387. // invalid arguments passed to the function
  2388. return FALSE;
  2389. }
  2390. // get the size of the destination buffer
  2391. lSize = GetBufferSize( pwszDest );
  2392. if ( lSize < 0 )
  2393. {
  2394. // the source buffer is not allocated on heap
  2395. return FALSE;
  2396. }
  2397. else
  2398. {
  2399. // convert the size into TCHARs
  2400. lSize /= sizeof( WCHAR );
  2401. }
  2402. // do the copy and return
  2403. return StringCopyW( pwszDest, pwszSource, lSize );
  2404. }
  2405. BOOL
  2406. StringConcatExA( IN OUT LPSTR pszDest,
  2407. IN LPCSTR pszSource )
  2408. /*++
  2409. Routine Description:
  2410. Appends dynamic ANSI string to a buffer
  2411. Arguments:
  2412. [ in/out ] pszDest => Destination buffer
  2413. [ in ] pszSource => Source buffer
  2414. Return Value:
  2415. FALSE : On failure
  2416. TRUE : On success
  2417. --*/
  2418. {
  2419. // local variables
  2420. LONG lSize = 0;
  2421. //
  2422. // for historical reasons we neither clear the error
  2423. // not set the error in this function
  2424. //
  2425. // validate the inputs
  2426. if ( pszDest == NULL || pszSource == NULL )
  2427. {
  2428. // invalid arguments passed to the function
  2429. return FALSE;
  2430. }
  2431. // get the size of the destination buffer
  2432. lSize = GetBufferSize( pszDest );
  2433. if ( lSize < 0 )
  2434. {
  2435. // the source buffer is not allocated on heap
  2436. return FALSE;
  2437. }
  2438. else
  2439. {
  2440. // convert the size into CHARs
  2441. lSize /= sizeof( CHAR );
  2442. }
  2443. // do the concatenation and return
  2444. return StringConcatA( pszDest, pszSource, lSize );
  2445. }
  2446. BOOL
  2447. StringConcatExW( IN OUT LPWSTR pwszDest,
  2448. IN LPCWSTR pwszSource )
  2449. /*++
  2450. Routine Description:
  2451. Appends one dynamic ANSI string to another
  2452. Arguments:
  2453. [ in/out ] pwszDest => Destination buffer
  2454. [ in ] pwszSource => Source buffer
  2455. Return Value:
  2456. FALSE : On failure
  2457. TRUE : On success
  2458. --*/
  2459. {
  2460. // local variables
  2461. LONG lSize = 0;
  2462. //
  2463. // for historical reasons we neither clear the error
  2464. // not set the error in this function
  2465. //
  2466. // validate the inputs
  2467. if ( pwszDest == NULL || pwszSource == NULL )
  2468. {
  2469. // invalid arguments passed to the function
  2470. return FALSE;
  2471. }
  2472. // get the size of the destination buffer
  2473. lSize = GetBufferSize( pwszDest );
  2474. if ( lSize < 0 )
  2475. {
  2476. // the source buffer is not allocated on heap
  2477. return FALSE;
  2478. }
  2479. else
  2480. {
  2481. // convert the size into WCHARs
  2482. lSize /= sizeof( WCHAR );
  2483. }
  2484. // do the concatenation and return
  2485. return StringConcatW( pwszDest, pwszSource, lSize );
  2486. }
  2487. DWORD
  2488. StringLengthA( IN LPCSTR pszSource,
  2489. IN DWORD dwReserved )
  2490. /*++
  2491. Routine Description:
  2492. Finds the number of bytes in a ANSI string
  2493. Arguments:
  2494. [ in ] pszSource => String
  2495. Return Value:
  2496. int
  2497. --*/
  2498. {
  2499. UNREFERENCED_PARAMETER( dwReserved );
  2500. //
  2501. // for historical reasons we wont neither clear nor set the error code here
  2502. //
  2503. // validate the input
  2504. if ( NULL == pszSource )
  2505. {
  2506. // empty string..return 0..
  2507. return 0;
  2508. }
  2509. // return the length of string
  2510. return ( lstrlenA( pszSource ) );
  2511. }
  2512. DWORD
  2513. StringLengthW( IN LPCWSTR pwszSource,
  2514. IN DWORD dwReserved )
  2515. /*++
  2516. Routine Description:
  2517. Finds the number of characters in a UNICODE string
  2518. Arguments:
  2519. [ in ] pszSource => String
  2520. Return Value:
  2521. int
  2522. --*/
  2523. {
  2524. UNREFERENCED_PARAMETER( dwReserved );
  2525. //
  2526. // for historical reasons we wont neither clear nor set the error code here
  2527. //
  2528. // validate the input
  2529. if ( NULL == pwszSource )
  2530. {
  2531. // empty string..return 0..
  2532. return 0;
  2533. }
  2534. // return the length of string
  2535. return ( lstrlenW( pwszSource ) );
  2536. }
  2537. LONG
  2538. StringCompareW( IN LPCWSTR pwszString1,
  2539. IN LPCWSTR pwszString2,
  2540. IN BOOL bIgnoreCase,
  2541. IN DWORD dwCount )
  2542. /*++
  2543. Routine Description:
  2544. Compares two character strings, using the specified locale.
  2545. Arguments:
  2546. [in] pwszString1 => first string
  2547. [in] pwszString2 => second string
  2548. [in] bIgnoreCase => Flag to indicate case sensitive/in-sensitive
  2549. [in] dwCount => number of characters to be compared
  2550. Return Value:
  2551. FALSE : On failure
  2552. TRUE : On success
  2553. --*/
  2554. {
  2555. // local variables
  2556. LONG lResult = 0;
  2557. LONG lLength = 0;
  2558. DWORD dwFlags = 0;
  2559. // check the input value
  2560. if ( pwszString1 == NULL || pwszString2 == NULL )
  2561. {
  2562. INVALID_PARAMETER();
  2563. return 0;
  2564. }
  2565. // determine the flags
  2566. dwFlags = (bIgnoreCase == TRUE) ? NORM_IGNORECASE : 0;
  2567. // determine the length
  2568. lLength = (dwCount == 0) ? -1 : dwCount;
  2569. lResult = CompareStringW( GetThreadLocale(),
  2570. dwFlags, pwszString1, lLength, pwszString2, lLength );
  2571. // now return comparision result
  2572. // to this function in consistent with C-runtime, we need to subtract 2
  2573. // lResult return from CompareString
  2574. return lResult - 2;
  2575. }
  2576. LONG
  2577. StringCompareA( IN LPCSTR pszString1,
  2578. IN LPCSTR pszString2,
  2579. IN BOOL bIgnoreCase,
  2580. IN DWORD dwCount )
  2581. /*++
  2582. Routine Description:
  2583. Compares two character strings, using the specified locale.
  2584. Arguments:
  2585. [in] pwszString1 => first string
  2586. [in] pwszString2 => second string
  2587. [in] bIgnoreCase => Flag to indicate case sensitive/in-sensitive
  2588. [in] dwCount => number of characters to be compared
  2589. Return Value:
  2590. FALSE : On failure
  2591. TRUE : On success
  2592. --*/
  2593. {
  2594. // local variables
  2595. LONG lResult = 0;
  2596. LONG lLength = 0;
  2597. DWORD dwFlags = 0;
  2598. // check the input value
  2599. if ( pszString1 == NULL || pszString2 == NULL )
  2600. {
  2601. INVALID_PARAMETER();
  2602. return 0;
  2603. }
  2604. // determine the flags
  2605. dwFlags = (bIgnoreCase == TRUE) ? NORM_IGNORECASE : 0;
  2606. // determine the length
  2607. lLength = (dwCount == 0) ? -1 : dwCount;
  2608. lResult = CompareStringA( GetThreadLocale(),
  2609. dwFlags, pszString1, lLength, pszString2, lLength );
  2610. // now return comparision result
  2611. // to this function in consistent with C-runtime, we need to subtract 2
  2612. // lResult return from CompareString
  2613. return lResult - 2;
  2614. }
  2615. LONG
  2616. StringCompareExW( IN LPCWSTR pwszString1,
  2617. IN LPCWSTR pwszString2,
  2618. IN BOOL bIgnoreCase,
  2619. IN DWORD dwCount )
  2620. /*++
  2621. Routine Description:
  2622. Compares two character strings, using the specified locale.
  2623. Arguments:
  2624. [in] pwszString1 => first string
  2625. [in] pwszString2 => second string
  2626. [in] bIgnoreCase => Flag to indicate case sensitive/in-sensitive
  2627. [in] dwCount => number of characters to be compared
  2628. Return Value:
  2629. FALSE : On failure
  2630. TRUE : On success
  2631. --*/
  2632. {
  2633. // local variables
  2634. LONG lResult = 0;
  2635. LONG lLength = 0;
  2636. DWORD dwFlags = 0;
  2637. DWORD lcid = 0;
  2638. // check the input value
  2639. if ( pwszString1 == NULL || pwszString2 == NULL )
  2640. {
  2641. INVALID_PARAMETER();
  2642. return 0;
  2643. }
  2644. // determine the flags
  2645. dwFlags = (bIgnoreCase == TRUE) ? NORM_IGNORECASE : 0;
  2646. // determine the length
  2647. lLength = (dwCount == 0) ? -1 : dwCount;
  2648. // prepare the LCID
  2649. // if this tool is designed to work on XP and earlier, then
  2650. // we can use LOCALE_INVARIANT -- otherwise, we need to prepare the lcid
  2651. lcid = LOCALE_INVARIANT;
  2652. if ( g_dwMajorVersion == 5 && g_dwMinorVersion == 0 )
  2653. {
  2654. // tool desgined to work on pre-windows xp
  2655. lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT );
  2656. }
  2657. lResult = CompareStringW( lcid,
  2658. dwFlags, pwszString1, lLength, pwszString2, lLength );
  2659. // now return comparision result
  2660. // to this function in consistent with C-runtime, we need to subtract 2
  2661. // lResult return from CompareString
  2662. return lResult - 2;
  2663. }
  2664. LONG
  2665. StringCompareExA( IN LPCSTR pszString1,
  2666. IN LPCSTR pszString2,
  2667. IN BOOL bIgnoreCase,
  2668. IN DWORD dwCount )
  2669. /*++
  2670. Routine Description:
  2671. Compares two character strings, using the specified locale.
  2672. Arguments:
  2673. [in] pszString1 => first string
  2674. [in] pszString2 => second string
  2675. [in] bIgnoreCase => Flag to indicate case sensitive/in-sensitive
  2676. [in] dwCount => number of characters to be compared
  2677. Return Value:
  2678. FALSE : On failure
  2679. TRUE : On success
  2680. --*/
  2681. {
  2682. // local variables
  2683. LONG lResult = 0;
  2684. LONG lLength = 0;
  2685. DWORD dwFlags = 0;
  2686. DWORD lcid = 0;
  2687. // check the input value
  2688. if ( pszString1 == NULL || pszString2 == NULL )
  2689. {
  2690. INVALID_PARAMETER();
  2691. return 0;
  2692. }
  2693. // determine the flags
  2694. dwFlags = (bIgnoreCase == TRUE) ? NORM_IGNORECASE : 0;
  2695. // determine the length
  2696. lLength = (dwCount == 0) ? -1 : dwCount;
  2697. // prepare the LCID
  2698. // if this tool is designed to work on XP and earlier, then
  2699. // we can use LOCALE_INVARIANT -- otherwise, we need to prepare the lcid
  2700. lcid = LOCALE_INVARIANT;
  2701. if ( g_dwMajorVersion == 5 && g_dwMinorVersion == 0 )
  2702. {
  2703. // tool desgined to work on pre-windows xp
  2704. lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT );
  2705. }
  2706. lResult = CompareStringA( lcid,
  2707. dwFlags, pszString1, lLength, pszString2, lLength );
  2708. // now return comparision result
  2709. // to this function in consistent with C-runtime, we need to subtract 2
  2710. // lResult return from CompareString
  2711. return lResult - 2;
  2712. }
  2713. BOOL
  2714. ShowResMessage( IN FILE* fp,
  2715. IN UINT uID )
  2716. /*++
  2717. Routine Description:
  2718. Displays the message based on resource ID
  2719. Arguments:
  2720. [in] fp => file pointer
  2721. [in] uID => resource ID
  2722. Return Value:
  2723. FALSE : On failure
  2724. TRUE : On success
  2725. --*/
  2726. {
  2727. // show the string from the resource table and return
  2728. return ShowMessage( fp, GetResString( uID ) );
  2729. }
  2730. BOOL
  2731. ShowMessage( FILE* fp,
  2732. LPCWSTR pwszMessage )
  2733. /*++
  2734. Routine Description:
  2735. Displays the message with the given file pointer
  2736. Arguments:
  2737. [in] fp => file pointer
  2738. [in] pwszMessage => Message
  2739. Return Value:
  2740. FALSE : On failure
  2741. TRUE : On success
  2742. --*/
  2743. {
  2744. // local variables
  2745. DWORD dw = 0;
  2746. DWORD dwTemp = 0;
  2747. DWORD dwLength = 0;
  2748. DWORD dwBufferSize = 0;
  2749. DWORD dwSourceBuffer = 0;
  2750. BOOL bResult = FALSE;
  2751. HANDLE hOutput = NULL;
  2752. LPCWSTR pwszTemp = NULL;
  2753. static char szBuffer[ 256 ] = "\0";
  2754. //
  2755. // for historical reasons we wont neither clear nor set the error code here
  2756. //
  2757. // check the input value
  2758. if ( fp == NULL || pwszMessage == NULL )
  2759. {
  2760. INVALID_PARAMETER();
  2761. return FALSE;
  2762. }
  2763. // determine whether the handle passed is a console file or not
  2764. if ( IsConsoleFile( fp ) == TRUE )
  2765. {
  2766. // determine the file handle
  2767. if ( fp == stdout )
  2768. {
  2769. // handle to stdout
  2770. hOutput = GetStdHandle( STD_OUTPUT_HANDLE );
  2771. }
  2772. else if ( fp == stderr )
  2773. {
  2774. // handle to stderr
  2775. hOutput = GetStdHandle( STD_ERROR_HANDLE );
  2776. }
  2777. else
  2778. {
  2779. // there is no way that fp will not match with
  2780. // stderr and stdout -- but still
  2781. UNEXPECTED_ERROR();
  2782. return FALSE;
  2783. }
  2784. // get the length info.
  2785. dwTemp = 0;
  2786. dwLength = StringLength( pwszMessage, 0 );
  2787. // display the output
  2788. bResult = WriteConsole( hOutput, pwszMessage, dwLength, &dwTemp, NULL );
  2789. if ( bResult == FALSE || dwLength != dwTemp )
  2790. {
  2791. // buffer might not be sufficient -- check it
  2792. if ( GetLastError() == ERROR_NOT_ENOUGH_MEMORY )
  2793. {
  2794. // this is the only error that could occur
  2795. // NOTE: we will display the buffer in chunks of 1024 characters
  2796. dwLength = StringLength( pwszMessage, 0 );
  2797. for( dw = 0; dw < dwLength; dw += 1024 )
  2798. {
  2799. // write 256 characters at time
  2800. dwBufferSize = ((dwLength - dw) > 1024 ? 1024 : (dwLength - dw));
  2801. bResult = WriteConsole( hOutput,
  2802. pwszMessage + dw, dwBufferSize, &dwTemp, NULL );
  2803. if ( bResult == FALSE || dwBufferSize != dwTemp )
  2804. {
  2805. // can't help -- still the same error -- unexpected behaviour
  2806. ShowLastError( stderr );
  2807. ReleaseGlobals();
  2808. ExitProcess( 1 );
  2809. }
  2810. }
  2811. }
  2812. else
  2813. {
  2814. // unexpected error occured -- no idea
  2815. ShowLastError( stderr );
  2816. ReleaseGlobals();
  2817. ExitProcess( 1 );
  2818. }
  2819. }
  2820. }
  2821. else
  2822. {
  2823. // determine the length(s)
  2824. // NOTE: we need to the surround all '%' characters with extra '%'
  2825. // character to show it as it is
  2826. pwszTemp = QuoteMeta( pwszMessage, 1 );
  2827. dwLength = StringLength( pwszTemp, 0 );
  2828. dwBufferSize = SIZE_OF_ARRAY( szBuffer );
  2829. // zero the szBuffer
  2830. ZeroMemory( szBuffer, dwBufferSize * sizeof( CHAR ) );
  2831. // show the text in shunks of buffer size
  2832. dw = 0;
  2833. dwBufferSize--; // from this point lets assume that the ANSI
  2834. // buffer is 1 less than its actual size
  2835. while ( dwLength > dw )
  2836. {
  2837. dwTemp = 0;
  2838. dwSourceBuffer = ((dwBufferSize < (dwLength - dw)) ? dwBufferSize : (dwLength - dw));
  2839. while ( dwTemp == 0 )
  2840. {
  2841. // determine the ANSI buffer space required sufficient to
  2842. // transform the current UNICODE string length
  2843. dwTemp = WideCharToMultiByte( GetConsoleOutputCP(),
  2844. 0, pwszTemp + dw, dwSourceBuffer, NULL, 0, NULL, NULL );
  2845. // if the ANSI buffer space is not sufficient
  2846. if ( dwTemp == 0 )
  2847. {
  2848. ShowLastError( stdout );
  2849. ReleaseGlobals();
  2850. ExitProcess( 1 );
  2851. }
  2852. else if ( dwTemp > dwBufferSize )
  2853. {
  2854. if ( (dwTemp - dwBufferSize) > 3 )
  2855. {
  2856. dwSourceBuffer -= (dwTemp - dwBufferSize) / 2;
  2857. }
  2858. else
  2859. {
  2860. dwSourceBuffer--;
  2861. }
  2862. // reset the temp variable inorder to continue the loop
  2863. dwTemp = 0;
  2864. // check the source buffer contents
  2865. if ( dwSourceBuffer == 0 )
  2866. {
  2867. UNEXPECTED_ERROR();
  2868. ShowLastError( stdout );
  2869. ReleaseGlobals();
  2870. ExitProcess( 1 );
  2871. }
  2872. }
  2873. else if ( dwTemp < dwSourceBuffer )
  2874. {
  2875. dwSourceBuffer = dwTemp;
  2876. }
  2877. }
  2878. // get the string in 'multibyte' format
  2879. ZeroMemory( szBuffer, SIZE_OF_ARRAY( szBuffer ) * sizeof( CHAR ) );
  2880. dwTemp = WideCharToMultiByte( GetConsoleOutputCP(), 0,
  2881. pwszTemp + dw, dwSourceBuffer, szBuffer, dwBufferSize, NULL, NULL );
  2882. // check the result
  2883. if ( dwTemp == 0 )
  2884. {
  2885. ShowLastError( stdout );
  2886. ReleaseGlobals();
  2887. ExitProcess( 1 );
  2888. }
  2889. // determine the remaining buffer length
  2890. dw += dwSourceBuffer;
  2891. // display string onto the specified file
  2892. fprintf( fp, szBuffer );
  2893. fflush( fp );
  2894. // bResult = WriteFile( fp, szBuffer, StringLengthA( szBuffer, 0 ), &dwTemp, NULL );
  2895. // if ( bResult == FALSE ||
  2896. // StringLengthA( szBuffer, 0 ) != (LONG) dwTemp ||
  2897. // FlushFileBuffers( fp ) == FALSE )
  2898. // {
  2899. // UNEXPECTED_ERROR();
  2900. // ReleaseGlobals();
  2901. // ExitProcess( 1 );
  2902. // }
  2903. }
  2904. }
  2905. return TRUE;
  2906. }
  2907. BOOL
  2908. ShowMessageEx(
  2909. FILE* fp,
  2910. DWORD dwCount,
  2911. BOOL bStyle,
  2912. LPCWSTR pwszFormat,
  2913. ...)
  2914. /*++
  2915. Routine Description:
  2916. Replaces a string containing " %1, %2 ... " or "%s, %d, %f ..." with
  2917. appropriate values depending upon the way arguments are given as input.
  2918. Arguments:
  2919. [ IN ] FILE* fp - Contains file on to which message is to be copied.
  2920. [ IN ] DWORD dwCount - Contains number of arguments for 'va_list'
  2921. following 'lpszFormat'.
  2922. [ IN ] BOOL bStyle - If TRUE then formatting is done using "_vstprint",
  2923. if FALSE then formatting is done using "FormatMessage".
  2924. [ IN ] LPCTSTR lpszFormat - String which needs to formatted.
  2925. Return value:
  2926. TRUE - If successful in displaying message.
  2927. FALSE - If failed to display message or memory is insufficient.
  2928. ---*/
  2929. {
  2930. // local variables
  2931. va_list vargs; // Contains start variable of variable arguments.
  2932. BOOL bResult = FALSE; // Contains return value.
  2933. LPWSTR pwszBuffer = NULL; // Contains mem location of variable arguments.
  2934. DWORD dwBufferLength = 0;
  2935. LONG lCount = -1;
  2936. HRESULT hr = S_OK;
  2937. // Check for any NULL argument passed as input.
  2938. if( NULL == pwszFormat || NULL == fp )
  2939. {
  2940. INVALID_PARAMETER();
  2941. return FALSE;
  2942. }
  2943. // check how many variable arguments did caller passed
  2944. // if it is zero, just call the ShowMessage -- no need to proceed furthur
  2945. if ( dwCount == 0 )
  2946. {
  2947. return ShowMessage( fp, pwszFormat );
  2948. }
  2949. // Formatting is done using 'Format message' or '_vstprintf'?
  2950. if ( FALSE == bStyle )
  2951. {
  2952. // init
  2953. lCount = -1;
  2954. dwBufferLength = 0;
  2955. // try the FormatMessage
  2956. do
  2957. {
  2958. // get the variable args start position
  2959. va_start( vargs, pwszFormat );
  2960. if ( vargs == NULL )
  2961. {
  2962. UNEXPECTED_ERROR();
  2963. return FALSE;
  2964. }
  2965. // we will start with buffer length of 4K buffer and then increment
  2966. // the buffer by 2K each time we run thru this loop
  2967. dwBufferLength += (lCount == -1) ? 4096 : 2048;
  2968. if ( (pwszBuffer = GetTempBuffer( INDEX_TEMP_SHOWMESSAGE,
  2969. NULL, dwBufferLength, TRUE )) == NULL )
  2970. {
  2971. OUT_OF_MEMORY();
  2972. return FALSE;
  2973. }
  2974. // try the FormatMessage
  2975. lCount = FormatMessageW( FORMAT_MESSAGE_FROM_STRING,
  2976. pwszFormat, 0, 0, pwszBuffer, dwBufferLength - 1, &vargs );
  2977. // check the result
  2978. if ( lCount == 0 )
  2979. {
  2980. if ( GetLastError() == NO_ERROR )
  2981. {
  2982. // there is nothing to show
  2983. return TRUE;
  2984. }
  2985. else if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  2986. {
  2987. return FALSE;
  2988. }
  2989. }
  2990. // reset the va_list parameter
  2991. va_end( vargs );
  2992. } while ( lCount == 0 );
  2993. }
  2994. // Formatting is done using '_vsnwprintf'.
  2995. else
  2996. {
  2997. // init
  2998. dwBufferLength = 0;
  2999. // try the printf
  3000. do
  3001. {
  3002. // get the variable args start position
  3003. va_start( vargs, pwszFormat );
  3004. if ( vargs == NULL )
  3005. {
  3006. UNEXPECTED_ERROR();
  3007. return FALSE;
  3008. }
  3009. // we will start with buffer length of 4K buffer and then increment
  3010. // the buffer by 2K each time we run thru this loop
  3011. dwBufferLength += (lCount == 0) ? 4096 : 2048;
  3012. if ( (pwszBuffer = GetTempBuffer( INDEX_TEMP_SHOWMESSAGE,
  3013. NULL, dwBufferLength, TRUE )) == NULL )
  3014. {
  3015. OUT_OF_MEMORY();
  3016. return FALSE;
  3017. }
  3018. // try the printf
  3019. hr = StringCchVPrintfW( pwszBuffer, dwBufferLength, pwszFormat, vargs );
  3020. // reset the va_list parameter
  3021. va_end( vargs );
  3022. } while ( hr == STRSAFE_E_INSUFFICIENT_BUFFER );
  3023. // check whether we came out of the loop 'coz of the some other error
  3024. if ( FAILED( hr ) )
  3025. {
  3026. SetLastError( HRESULT_CODE( hr ) );
  3027. return FALSE;
  3028. }
  3029. }
  3030. // a safety check
  3031. if ( pwszBuffer == NULL )
  3032. {
  3033. UNEXPECTED_ERROR();
  3034. return FALSE;
  3035. }
  3036. // show the output
  3037. bResult = ShowMessage( fp, pwszBuffer );
  3038. // return
  3039. return bResult;
  3040. }
  3041. // ***************************************************************************
  3042. // Routine Description:
  3043. //
  3044. // ///////////////////////////////////////////////////////////////////////////
  3045. // NOTE:
  3046. // ----
  3047. // functions which i dont want to support any more -- they are just lying for
  3048. // compatiblity sake -- if at all you are facing any problem with these
  3049. // functions you better upgrade to version 2.0 -- but absoultely there is no
  3050. // support for this function
  3051. //
  3052. // ///////////////////////////////////////////////////////////////////////////
  3053. //
  3054. // Arguments:
  3055. //
  3056. // Return Value:
  3057. //
  3058. // ***************************************************************************
  3059. LPSTR
  3060. GetAsMultiByteString( IN LPCWSTR pwszSource,
  3061. IN OUT LPSTR pszDestination,
  3062. IN DWORD dwLength )
  3063. /*++
  3064. Routine Description:
  3065. convert string from UNICODE version to ANSI version
  3066. Arguments:
  3067. [IN] pszSource : UNICODE version of string
  3068. [IN/OUT] pwszDestination : ANSI version of string
  3069. [IN/OUT] dwLength : Length of a string
  3070. Return Value:
  3071. NULL_STRING : On failure
  3072. LPWSTR : On success
  3073. --*/
  3074. {
  3075. if ( GetAsMultiByteString2( pwszSource,
  3076. pszDestination,
  3077. &dwLength ) == FALSE )
  3078. {
  3079. return "";
  3080. }
  3081. // return the destination buffer
  3082. return pszDestination;
  3083. }
  3084. // ***************************************************************************
  3085. //
  3086. // ///////////////////////////////////////////////////////////////////////////
  3087. // NOTE:
  3088. // ----
  3089. // functions which i dont want to support any more -- they are just lying for
  3090. // compatiblity sake -- if at all you are facing any problem with these
  3091. // functions you better upgrade to version 2.0 -- but absoultely there is no
  3092. // support for this function
  3093. //
  3094. // ///////////////////////////////////////////////////////////////////////////
  3095. //
  3096. // ***************************************************************************
  3097. LPWSTR
  3098. GetAsUnicodeStringEx( IN LPCSTR pszSource,
  3099. IN OUT LPWSTR pwszDestination,
  3100. IN DWORD dwLength )
  3101. /*++
  3102. Routine Description:
  3103. convert string from ANSI version to UNICODE version
  3104. Arguments:
  3105. [IN] pszSource : Source string
  3106. [IN/OUT] pwszDestination : Unicode version of String
  3107. [IN/OUT] dwLength : Length of a string
  3108. Return Value:
  3109. NULL_STRING : On failure
  3110. LPWSTR : On success
  3111. --*/
  3112. {
  3113. if ( GetAsUnicodeString2( pszSource,
  3114. pwszDestination,
  3115. &dwLength ) == FALSE )
  3116. {
  3117. return L"";
  3118. }
  3119. // return the destination buffer
  3120. return pwszDestination;
  3121. }
  3122. BOOL
  3123. GetAsUnicodeString2( IN LPCSTR pszSource,
  3124. IN OUT LPWSTR pwszDestination,
  3125. IN OUT DWORD* pdwLength )
  3126. /*++
  3127. Routine Description:
  3128. convert string from ANSI version to UNICODE version
  3129. Arguments:
  3130. [IN] pszSource : Source string
  3131. [IN/OUT] pwszDestination : Unicode version of String
  3132. [IN/OUT] dwLength : Length of a string
  3133. Return Value:
  3134. FALSE : On failure
  3135. TRUE : On success
  3136. --*/
  3137. {
  3138. // local variables
  3139. DWORD dw = 0;
  3140. DWORD dwLength = 0;
  3141. LONG lSourceLength = 0;
  3142. //
  3143. // for historical reasons we wont neither clear nor set the error code here
  3144. //
  3145. // check the input values
  3146. if ( pszSource == NULL || pdwLength == NULL ||
  3147. ( pwszDestination == NULL && *pdwLength != 0 ) )
  3148. {
  3149. INVALID_PARAMETER();
  3150. return FALSE;
  3151. }
  3152. // ...
  3153. if ( *pdwLength != 0 )
  3154. {
  3155. if ( *pdwLength > 1 )
  3156. {
  3157. dwLength = (*pdwLength) - 1;
  3158. }
  3159. else
  3160. {
  3161. ZeroMemory( pwszDestination, *pdwLength * sizeof( wchar_t ) );
  3162. return TRUE;
  3163. }
  3164. }
  3165. // initialize the values with zeros
  3166. // NOTE:- MultiByteToWideChar wont null terminate its result so
  3167. // if its not initialized to nulls, you'll get junk after
  3168. // the converted string and will result in crashes
  3169. if ( pwszDestination != NULL && dwLength != 0 )
  3170. {
  3171. ZeroMemory( pwszDestination, (dwLength + 1) * sizeof( wchar_t ) );
  3172. }
  3173. // determine the source length to pass to the function call
  3174. lSourceLength = -1;
  3175. if ( dwLength != 0 )
  3176. {
  3177. lSourceLength = StringLengthA( pszSource, 0 );
  3178. if ( lSourceLength > (LONG) dwLength )
  3179. {
  3180. lSourceLength = dwLength;
  3181. }
  3182. }
  3183. // convert string from ANSI version to UNICODE version
  3184. dw = MultiByteToWideChar( _DEFAULT_CODEPAGE, 0,
  3185. pszSource, lSourceLength, pwszDestination, dwLength );
  3186. if ( dw == 0 )
  3187. {
  3188. UNEXPECTED_ERROR();
  3189. // to keep the destination buffer clean and safe
  3190. if ( pwszDestination != NULL && dwLength != 0 )
  3191. {
  3192. ZeroMemory( pwszDestination, (dwLength + 1) * sizeof( wchar_t ) );
  3193. }
  3194. // failure
  3195. return FALSE;
  3196. }
  3197. else
  3198. {
  3199. *pdwLength = dw;
  3200. }
  3201. // success
  3202. return TRUE;
  3203. }
  3204. BOOL
  3205. GetAsMultiByteString2( IN LPCWSTR pwszSource,
  3206. IN OUT LPSTR pszDestination,
  3207. IN OUT DWORD* pdwLength )
  3208. /*++
  3209. Routine Description:
  3210. Complex scripts cannot be rendered in the console, so we
  3211. force the English (US) resource.
  3212. Arguments:
  3213. [IN] pwszSource : Source string
  3214. [IN|OUT] pszDestination : Multibyte string
  3215. [IN] pdwLength : length of the text string
  3216. Return Value:
  3217. TRUE : on Success
  3218. FALSE : On Failure
  3219. --*/
  3220. {
  3221. // local variables
  3222. DWORD dw = 0;
  3223. DWORD dwLength = 0;
  3224. LONG lSourceLength = 0;
  3225. //
  3226. // for historical reasons we wont neither clear nor set the error code here
  3227. //
  3228. // check the input values
  3229. if ( pwszSource == NULL || pdwLength == NULL ||
  3230. ( pszDestination == NULL && *pdwLength != 0 ) )
  3231. {
  3232. INVALID_PARAMETER();
  3233. return FALSE;
  3234. }
  3235. // ...
  3236. if ( *pdwLength != 0 )
  3237. {
  3238. if ( *pdwLength > 1 )
  3239. {
  3240. dwLength = (*pdwLength) - 1;
  3241. }
  3242. else
  3243. {
  3244. ZeroMemory( pszDestination, *pdwLength * sizeof( char ) );
  3245. return TRUE;
  3246. }
  3247. }
  3248. // initialize the values with zeros
  3249. // NOTE:- WideCharToMultiByte wont null terminate its result so
  3250. // if its not initialized to nulls, you'll get junk after
  3251. // the converted string and will result in crashes
  3252. if ( pszDestination != NULL && dwLength != 0 )
  3253. {
  3254. ZeroMemory( pszDestination, (dwLength + 1) * sizeof( char ) );
  3255. }
  3256. // determine the source length to pass to the function call
  3257. lSourceLength = -1;
  3258. if ( dwLength != 0 )
  3259. {
  3260. lSourceLength = StringLengthW( pwszSource, 0 );
  3261. if ( lSourceLength > (LONG) dwLength )
  3262. {
  3263. lSourceLength = dwLength;
  3264. }
  3265. }
  3266. // convert string from UNICODE version to ANSI version
  3267. dw = WideCharToMultiByte( _DEFAULT_CODEPAGE, 0,
  3268. pwszSource, lSourceLength, pszDestination, dwLength, NULL, NULL );
  3269. if ( dw == 0 )
  3270. {
  3271. UNEXPECTED_ERROR();
  3272. // to keep the destination buffer clean and safe
  3273. if ( pszDestination != NULL && dwLength != 0 )
  3274. {
  3275. ZeroMemory( pszDestination, (dwLength + 1) * sizeof( char ) );
  3276. }
  3277. // failure
  3278. return FALSE;
  3279. }
  3280. // success
  3281. return TRUE;
  3282. }
  3283. BOOL
  3284. GetPassword( LPWSTR pwszPassword,
  3285. DWORD dwMaxPasswordSize )
  3286. /*++
  3287. Routine Description:
  3288. Takes the password from the keyboard. While entering the password it shows
  3289. the charecters as '*'
  3290. Arguments:
  3291. [in] pszPassword --password string to store password
  3292. [in] dwMaxPasswordSize --Maximun size of the password. MAX_PASSWORD_LENGTH.
  3293. Return Value:
  3294. FALSE : On failure
  3295. TRUE : On success
  3296. --*/
  3297. {
  3298. // local variables
  3299. CHAR ch;
  3300. WCHAR wch;
  3301. DWORD dwIndex = 0;
  3302. DWORD dwCharsRead = 0;
  3303. DWORD dwCharsWritten = 0;
  3304. DWORD dwPrevConsoleMode = 0;
  3305. HANDLE hInputConsole = NULL;
  3306. CHAR szBuffer[ 10 ] = "\0"; // actually contains only character at all the times
  3307. WCHAR wszBuffer[ 10 ] = L"\0"; // actually contains only character at all the times
  3308. BOOL bIndirectionInput = FALSE;
  3309. // check the input value
  3310. if ( pwszPassword == NULL )
  3311. {
  3312. INVALID_PARAMETER();
  3313. return FALSE;
  3314. }
  3315. // get the handle for the standard input
  3316. hInputConsole = GetStdHandle( STD_INPUT_HANDLE );
  3317. if ( hInputConsole == NULL )
  3318. {
  3319. // could not get the handle so return failure
  3320. return FALSE;
  3321. }
  3322. // check for the input redirection on console and telnet session
  3323. if( ( hInputConsole != (HANDLE)0x0000000F ) &&
  3324. ( hInputConsole != (HANDLE)0x00000003 ) &&
  3325. ( hInputConsole != INVALID_HANDLE_VALUE ) )
  3326. {
  3327. bIndirectionInput = TRUE;
  3328. }
  3329. // redirect the data from StdIn.txt file into the console
  3330. if ( bIndirectionInput == FALSE )
  3331. {
  3332. // Get the current input mode of the input buffer
  3333. GetConsoleMode( hInputConsole, &dwPrevConsoleMode );
  3334. // Set the mode such that the control keys are processed by the system
  3335. if ( SetConsoleMode( hInputConsole, ENABLE_PROCESSED_INPUT ) == 0 )
  3336. {
  3337. // could not set the mode, return failure
  3338. return FALSE;
  3339. }
  3340. }
  3341. // init the unicode and ansi buffers to NULL
  3342. ZeroMemory( szBuffer, SIZE_OF_ARRAY( szBuffer ) * sizeof( CHAR ) );
  3343. ZeroMemory( wszBuffer, SIZE_OF_ARRAY( wszBuffer ) * sizeof( WCHAR ) );
  3344. // Read the characters until a carriage return is hit
  3345. for( ;; )
  3346. {
  3347. if ( bIndirectionInput == TRUE )
  3348. {
  3349. //read the contents of file
  3350. if ( ReadFile( hInputConsole, &ch, 1, &dwCharsRead, NULL ) == FALSE )
  3351. {
  3352. return FALSE;
  3353. }
  3354. // check for end of file
  3355. if ( dwCharsRead == 0 )
  3356. {
  3357. break;
  3358. }
  3359. else
  3360. {
  3361. // convert the ANSI character into UNICODE character
  3362. szBuffer[ 0 ] = ch;
  3363. dwCharsRead = SIZE_OF_ARRAY( wszBuffer );
  3364. GetAsUnicodeString2( szBuffer, wszBuffer, &dwCharsRead );
  3365. wch = wszBuffer[ 0 ];
  3366. }
  3367. }
  3368. else
  3369. {
  3370. if ( ReadConsole( hInputConsole, &wch, 1, &dwCharsRead, NULL ) == 0 )
  3371. {
  3372. // Set the original console settings
  3373. SetConsoleMode( hInputConsole, dwPrevConsoleMode );
  3374. // return failure
  3375. return FALSE;
  3376. }
  3377. }
  3378. // Check for carraige return
  3379. if ( wch == CARRIAGE_RETURN )
  3380. {
  3381. // break from the loop
  3382. break;
  3383. }
  3384. // Check id back space is hit
  3385. if ( wch == BACK_SPACE )
  3386. {
  3387. if ( dwIndex != 0 )
  3388. {
  3389. //
  3390. // Remove a asterix from the console
  3391. // move the cursor one character back
  3392. StringCchPrintfW(
  3393. wszBuffer,
  3394. SIZE_OF_ARRAY( wszBuffer ), L"%c", BACK_SPACE );
  3395. WriteConsole(
  3396. GetStdHandle( STD_OUTPUT_HANDLE ),
  3397. wszBuffer, 1, &dwCharsWritten, NULL );
  3398. // replace the existing character with space
  3399. StringCchPrintfW(
  3400. wszBuffer,
  3401. SIZE_OF_ARRAY( wszBuffer ), L"%c", BLANK_CHAR );
  3402. WriteConsole(
  3403. GetStdHandle( STD_OUTPUT_HANDLE ),
  3404. wszBuffer, 1, &dwCharsWritten, NULL );
  3405. // now set the cursor at back position
  3406. StringCchPrintfW(
  3407. wszBuffer,
  3408. SIZE_OF_ARRAY( wszBuffer ), L"%c", BACK_SPACE );
  3409. WriteConsole(
  3410. GetStdHandle( STD_OUTPUT_HANDLE ),
  3411. wszBuffer, 1, &dwCharsWritten, NULL );
  3412. // decrement the index
  3413. dwIndex--;
  3414. }
  3415. // process the next character
  3416. continue;
  3417. }
  3418. // if the max password length has been reached then sound a beep
  3419. if ( dwIndex == ( dwMaxPasswordSize - 1 ) )
  3420. {
  3421. WriteConsole(
  3422. GetStdHandle( STD_OUTPUT_HANDLE ),
  3423. BEEP_SOUND, 1, &dwCharsWritten, NULL );
  3424. }
  3425. else
  3426. {
  3427. // check for new line character
  3428. if ( wch != L'\n' )
  3429. {
  3430. // store the input character
  3431. *( pwszPassword + dwIndex ) = wch;
  3432. dwIndex++;
  3433. // display asterix onto the console
  3434. WriteConsole(
  3435. GetStdHandle( STD_OUTPUT_HANDLE ),
  3436. ASTERIX, 1, &dwCharsWritten, NULL );
  3437. }
  3438. }
  3439. }
  3440. // Add the NULL terminator
  3441. *( pwszPassword + dwIndex ) = cwchNullChar;
  3442. //Set the original console settings
  3443. SetConsoleMode( hInputConsole, dwPrevConsoleMode );
  3444. // display the character ( new line character )
  3445. StringCopy( wszBuffer, L"\n\n", SIZE_OF_ARRAY( wszBuffer ) );
  3446. WriteConsole(
  3447. GetStdHandle( STD_OUTPUT_HANDLE ),
  3448. wszBuffer, 2, &dwCharsWritten, NULL );
  3449. // Return success
  3450. return TRUE;
  3451. }
  3452. BOOL
  3453. FreeMemory( IN OUT LPVOID* ppv )
  3454. /*++
  3455. Routine Description:
  3456. Frees a memory block allocated from a heap
  3457. Arguments:
  3458. [in] ppv => buffer
  3459. Return Value:
  3460. FALSE : On failure
  3461. TRUE : On success
  3462. --*/
  3463. {
  3464. // local variables
  3465. LONG lSize = 0;
  3466. HANDLE hHeap = NULL;
  3467. BOOL bResult = FALSE;
  3468. //
  3469. // for historical reasons we wont neither clear nor set the error code here
  3470. //
  3471. // check the input
  3472. if ( ppv == NULL )
  3473. {
  3474. INVALID_PARAMETER();
  3475. return FALSE;
  3476. }
  3477. else if ( *ppv == NULL )
  3478. {
  3479. // just a NULL pointer -- not an error -- just return
  3480. return TRUE;
  3481. }
  3482. // get the handle to process heap
  3483. hHeap = GetProcessHeap();
  3484. if ( hHeap == NULL )
  3485. {
  3486. // GetProcessHeap will set the error code
  3487. return FALSE;
  3488. }
  3489. // it is a safe technique to clear the contents of the memory being released
  3490. lSize = GetBufferSize( *ppv );
  3491. if ( lSize == -1 )
  3492. {
  3493. // looks like this is not a valid buffer pointer
  3494. SetLastError( (DWORD) E_POINTER );
  3495. return FALSE;
  3496. }
  3497. // ...
  3498. ZeroMemory( *ppv, lSize );
  3499. // release the memory
  3500. bResult = HeapFree( hHeap, 0, *ppv );
  3501. // we need not check the result here
  3502. // ir-respective of whether the function call is successful or not
  3503. // clear the contents of the pointer -- this will help us in eliminating
  3504. // furthur failures
  3505. *ppv = NULL;
  3506. // return
  3507. return bResult;
  3508. }
  3509. BOOL
  3510. CheckMemory( IN OUT LPVOID pv )
  3511. /*++
  3512. Routine Description:
  3513. Attempts to validate a specified heap.
  3514. Arguments:
  3515. [in/out] ppv => buffer
  3516. Return Value:
  3517. FALSE : On failure
  3518. TRUE : On success
  3519. --*/
  3520. {
  3521. // local variables
  3522. HANDLE hHeap = NULL;
  3523. BOOL bResult = FALSE;
  3524. //
  3525. // for historical reasons we wont neither clear nor set the error code here
  3526. //
  3527. // check the input
  3528. if ( pv == NULL )
  3529. {
  3530. INVALID_PARAMETER();
  3531. return FALSE;
  3532. }
  3533. // get the handle to process heap
  3534. hHeap = GetProcessHeap();
  3535. if ( hHeap == NULL )
  3536. {
  3537. // GetProcessHeap will set the error code
  3538. return FALSE;
  3539. }
  3540. // validate the memory address
  3541. bResult = HeapValidate( hHeap, 0, pv );
  3542. if ( bResult == FALSE )
  3543. {
  3544. SetLastError( ERROR_INVALID_HANDLE );
  3545. return FALSE;
  3546. }
  3547. // return
  3548. return bResult;
  3549. }
  3550. LPVOID
  3551. AllocateMemory( IN DWORD dwBytes )
  3552. /*++
  3553. Routine Description:
  3554. Allocates a block of memory from a heap.
  3555. Arguments:
  3556. [in] dwBytesNew => number of bytes to reallocate
  3557. Return Value:
  3558. NULL : On failure
  3559. pv : On success
  3560. --*/
  3561. {
  3562. // local variables
  3563. LPVOID pv = NULL;
  3564. HANDLE hHeap = NULL;
  3565. //
  3566. // for historical reasons we wont neither clear nor set the error code here
  3567. //
  3568. // check the input
  3569. if ( dwBytes <= 0 )
  3570. {
  3571. INVALID_PARAMETER();
  3572. return NULL;
  3573. }
  3574. // get the handle to process heap
  3575. hHeap = GetProcessHeap();
  3576. if ( hHeap == NULL )
  3577. {
  3578. // GetProcessHeap will set the error code
  3579. return NULL;
  3580. }
  3581. //
  3582. // for safe play with heap allocation -- we use structured exception handling
  3583. //
  3584. __try
  3585. {
  3586. // allocate memory
  3587. pv = HeapAlloc( hHeap,
  3588. HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, dwBytes );
  3589. }
  3590. __except( EXCEPTION_EXECUTE_HANDLER )
  3591. {
  3592. if ( GetExceptionCode() == STATUS_NO_MEMORY )
  3593. {
  3594. OUT_OF_MEMORY();
  3595. return NULL;
  3596. }
  3597. else if ( GetExceptionCode() == STATUS_ACCESS_VIOLATION )
  3598. {
  3599. SetLastError( ERROR_FILE_CORRUPT );
  3600. SaveLastError();
  3601. return NULL;
  3602. }
  3603. else
  3604. {
  3605. OUT_OF_MEMORY();
  3606. return NULL;
  3607. }
  3608. }
  3609. // return the allocated the memory pointer
  3610. return pv;
  3611. }
  3612. BOOL
  3613. ReallocateMemory( IN OUT LPVOID* ppv,
  3614. IN DWORD dwBytesNew )
  3615. /*++
  3616. Routine Description:
  3617. Reallocates a block of memory from a heap.
  3618. Arguments:
  3619. [in] ppv => buffer
  3620. [in] dwBytesNew => number of bytes to reallocate
  3621. Return Value:
  3622. FALSE : On failure
  3623. TRUE : On success
  3624. --*/
  3625. {
  3626. // local variables
  3627. LPVOID pvNew = NULL;
  3628. HANDLE hHeap = NULL;
  3629. //
  3630. // for historical reasons we wont neither clear nor set the error code here
  3631. //
  3632. // check the input
  3633. if ( ppv == NULL || *ppv == NULL )
  3634. {
  3635. INVALID_PARAMETER();
  3636. return FALSE;
  3637. }
  3638. else if ( dwBytesNew == 0 )
  3639. {
  3640. // caller wants to free the memory
  3641. return FreeMemory( ppv );
  3642. }
  3643. else if ( CheckMemory( *ppv ) == FALSE )
  3644. {
  3645. // memory handle is invalid
  3646. // set it to NULL -- this is to avoid furthur errors
  3647. *ppv = NULL;
  3648. return FALSE;
  3649. }
  3650. // get the handle to process heap
  3651. hHeap = GetProcessHeap();
  3652. if ( hHeap == NULL )
  3653. {
  3654. // GetProcessHeap will set the error code
  3655. return FALSE;
  3656. }
  3657. //
  3658. // for safe play with heap allocation -- we use structured exception handling
  3659. //
  3660. __try
  3661. {
  3662. // allocate memory
  3663. pvNew = HeapReAlloc( hHeap,
  3664. HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, *ppv, dwBytesNew );
  3665. // check for failure case
  3666. if ( pvNew == NULL )
  3667. {
  3668. OUT_OF_MEMORY();
  3669. return FALSE;
  3670. }
  3671. //assign the value ...
  3672. *ppv = pvNew;
  3673. }
  3674. __except( EXCEPTION_EXECUTE_HANDLER )
  3675. {
  3676. //
  3677. // we will not alter the passed memory pointer to this function
  3678. // in case of error -- the pointer will be returned as it is
  3679. //
  3680. if ( GetExceptionCode() == STATUS_NO_MEMORY )
  3681. {
  3682. OUT_OF_MEMORY();
  3683. return FALSE;
  3684. }
  3685. else if ( GetExceptionCode() == STATUS_ACCESS_VIOLATION )
  3686. {
  3687. SetLastError( ERROR_FILE_CORRUPT );
  3688. SaveLastError();
  3689. return FALSE;
  3690. }
  3691. else
  3692. {
  3693. OUT_OF_MEMORY();
  3694. return FALSE;
  3695. }
  3696. }
  3697. // return the allocated the memory pointer
  3698. return TRUE;
  3699. }
  3700. LONG
  3701. GetBufferSize( IN OUT LPVOID pv )
  3702. /*++
  3703. Routine Description:
  3704. Gets the size, in bytes, of a memory block allocated from a heap
  3705. Arguments:
  3706. [in] pv => buffer
  3707. Return Value:
  3708. FALSE : On failure
  3709. TRUE : On success
  3710. --*/
  3711. {
  3712. // local variables
  3713. HANDLE hHeap = NULL;
  3714. //
  3715. // for historical reasons we wont neither clear nor set the error code here
  3716. //
  3717. // check the input
  3718. if ( pv == NULL )
  3719. {
  3720. INVALID_PARAMETER();
  3721. return -1;
  3722. }
  3723. else if ( CheckMemory( pv ) == FALSE )
  3724. {
  3725. return -1;
  3726. }
  3727. // get the handle to process heap
  3728. hHeap = GetProcessHeap();
  3729. if ( hHeap == NULL )
  3730. {
  3731. // GetProcessHeap will set the error code
  3732. return -1;
  3733. }
  3734. // return
  3735. return (DWORD)((DWORD_PTR)(HeapSize( hHeap, 0, pv )));
  3736. }
  3737. BOOL
  3738. MatchPattern(
  3739. IN LPWSTR szPat,
  3740. IN LPWSTR szFile
  3741. )
  3742. /*++
  3743. Routine Description : This routine is used to check whether file is mathced against
  3744. pattern or not.
  3745. [ IN ] szPat : A string variable pattern against which the file name to be matched.
  3746. [ IN ] szFile : A pattern string which specifies the file name to be matched.
  3747. Return Value : BOOL
  3748. Returns successfully if function is success other wise return failure.
  3749. --*/
  3750. {
  3751. switch (*szPat) {
  3752. case '\0':
  3753. return *szFile == L'\0';
  3754. case '?':
  3755. return *szFile != L'\0' && MatchPattern(szPat + 1, szFile + 1);
  3756. case '*':
  3757. do {
  3758. if (MatchPattern(szPat + 1, szFile))
  3759. return TRUE;
  3760. } while (*szFile++);
  3761. return FALSE;
  3762. default:
  3763. return toupper (*szFile) == toupper (*szPat) && MatchPattern(szPat + 1, szFile + 1);
  3764. }
  3765. }
  3766. LPCWSTR
  3767. ParsePattern( LPCWSTR pwszPattern )
  3768. {
  3769. // local variables
  3770. DWORD dw = 0;
  3771. DWORD dwLength = 0;
  3772. DWORD dwNewIndex = 0;
  3773. LPWSTR pwszNewPattern = NULL;
  3774. // check the pattern
  3775. if( pwszPattern == NULL ||
  3776. (dwLength = StringLength( pwszPattern, 0 )) == 0 )
  3777. {
  3778. INVALID_PARAMETER();
  3779. return NULL;
  3780. }
  3781. // allocate the buffer for the pattern
  3782. pwszNewPattern = GetTempBuffer( INDEX_TEMP_PATTERN, NULL, dwLength + 10, TRUE );
  3783. if ( pwszNewPattern == NULL )
  3784. {
  3785. OUT_OF_MEMORY();
  3786. return NULL;
  3787. }
  3788. //
  3789. // detect the un-necessary wild-card repetitions
  3790. // *, **, *****, *?*, *?*? etc -- all this combinations
  3791. // will result in just '*'
  3792. dwNewIndex = 0;
  3793. pwszNewPattern[ 0 ] = pwszPattern[ 0 ];
  3794. for( dw = 1; dw < dwLength; dw++ )
  3795. {
  3796. switch( pwszPattern[ dw ] )
  3797. {
  3798. case L'*':
  3799. case L'?':
  3800. {
  3801. if ( pwszNewPattern[ dwNewIndex ] == L'*' )
  3802. {
  3803. // since the pattern already contains the
  3804. // '*' and having another '*' after the existing
  3805. // '*' or having '?' after the '*' is of no use
  3806. // we will skip this character
  3807. break;
  3808. }
  3809. }
  3810. default:
  3811. dwNewIndex++;
  3812. pwszNewPattern[ dwNewIndex ] = pwszPattern[ dw ];
  3813. break;
  3814. }
  3815. }
  3816. dwNewIndex++;
  3817. pwszNewPattern[ dwNewIndex ] = L'\0';
  3818. return pwszNewPattern;
  3819. }
  3820. BOOL
  3821. InternalRecursiveMatchPatternEx(
  3822. IN LPCWSTR pwszText,
  3823. IN LPCWSTR pwszPattern,
  3824. IN DWORD dwLocale,
  3825. IN DWORD dwCompareFlags,
  3826. IN DWORD dwDepth )
  3827. {
  3828. // local variables
  3829. BOOL bResult = FALSE;
  3830. DWORD dwTextIndex = 0;
  3831. DWORD dwPatternIndex = 0;
  3832. DWORD dwTextLength = 0;
  3833. DWORD dwPatternLength = 0;
  3834. // check the input
  3835. if ( pwszText == NULL || pwszPattern == NULL )
  3836. {
  3837. INVALID_PARAMETER();
  3838. return FALSE;
  3839. }
  3840. //
  3841. // search the string for the specified pattern
  3842. bResult = TRUE;
  3843. dwTextLength = StringLength( pwszText, 0 );
  3844. dwPatternLength = StringLength( pwszPattern, 0 );
  3845. for( dwPatternIndex = 0, dwTextIndex = 0; dwPatternIndex < dwPatternLength; )
  3846. {
  3847. // check the current text position --
  3848. // if it reached the end of the string, exit from the loop
  3849. if ( dwTextIndex >= dwTextLength )
  3850. {
  3851. break;
  3852. }
  3853. switch( pwszPattern[ dwPatternIndex ] )
  3854. {
  3855. case L'?':
  3856. {
  3857. // pattern allows any character at this position
  3858. // increment the text and pattern index
  3859. dwTextIndex++;
  3860. dwPatternIndex++;
  3861. break;
  3862. }
  3863. case L'*':
  3864. {
  3865. // pattern allows sequence of any characters
  3866. // to be specified from the current text index
  3867. // until the next character the index is found
  3868. // if the current '*' itself is the end of the
  3869. // pattern, then this text matches the pattern
  3870. if ( dwPatternIndex + 1 < dwPatternLength )
  3871. {
  3872. for( ; dwTextIndex < dwTextLength; dwTextIndex++ )
  3873. {
  3874. if ( CompareString( dwLocale,
  3875. dwCompareFlags,
  3876. pwszText + dwTextIndex, 1,
  3877. pwszPattern + dwPatternIndex + 1, 1 ) == CSTR_EQUAL )
  3878. {
  3879. // the current character in the text matched with the
  3880. // next character in the pattern --
  3881. // now check whether the text from the current index
  3882. // matches with the rest of the pattern
  3883. bResult = InternalRecursiveMatchPatternEx(
  3884. pwszText + dwTextIndex,
  3885. pwszPattern + dwPatternIndex + 1,
  3886. dwLocale, dwCompareFlags, dwDepth + 1 );
  3887. if ( bResult == TRUE )
  3888. {
  3889. // text matched with the pattern
  3890. // set the text index to its length
  3891. // this makes the end result to give TRUE
  3892. dwTextIndex = dwTextLength;
  3893. dwPatternIndex = dwPatternLength;
  3894. // break from the loop
  3895. break;
  3896. }
  3897. else
  3898. {
  3899. // looks like pattern is not matching
  3900. // from the current position -- skip some more characters
  3901. }
  3902. }
  3903. }
  3904. }
  3905. else
  3906. {
  3907. // since we make the entire text matched with the pattern
  3908. // set the text index also to the length of the text
  3909. dwTextIndex = dwTextLength;
  3910. dwPatternIndex = dwPatternLength;
  3911. }
  3912. // ...
  3913. break;
  3914. }
  3915. default:
  3916. {
  3917. if ( CompareString( dwLocale,
  3918. dwCompareFlags,
  3919. pwszText + dwTextIndex, 1,
  3920. pwszPattern + dwPatternIndex, 1 ) == CSTR_EQUAL )
  3921. {
  3922. // update the text position by one character
  3923. dwTextIndex++;
  3924. dwPatternIndex++;
  3925. }
  3926. else
  3927. {
  3928. // character didn't match -- we should exit from the loop
  3929. bResult = FALSE;
  3930. }
  3931. // ...
  3932. break;
  3933. }
  3934. }
  3935. // check if any error is triggered in between or not
  3936. if ( bResult == FALSE )
  3937. {
  3938. // at some place mismatch is found
  3939. break;
  3940. }
  3941. }
  3942. // now the final check -- we need to know how we did we come out of the loop
  3943. // this we can determine by checking the pattern index position
  3944. // if the pattern index is equal to the length of the pattern length -- and
  3945. // the text index is equal to the the length of the text then the pattern is
  3946. // matched
  3947. if ( bResult != FALSE )
  3948. {
  3949. bResult = FALSE;
  3950. if ( dwTextIndex == dwTextLength && dwPatternIndex == dwPatternLength )
  3951. {
  3952. // pattern is matched
  3953. bResult = TRUE;
  3954. }
  3955. else
  3956. {
  3957. // still our conclusion might not be correct
  3958. // for ex: the text "abc" perfectly matches with "???*"
  3959. // but our logic says this is not a valid text -- to aovid
  3960. // this sort of conflicts, we will do one more additional
  3961. // final check to confirm whether the text we have is valid or not
  3962. if ( dwTextIndex == dwTextLength &&
  3963. dwPatternIndex + 1 == dwPatternLength &&
  3964. StringCompareEx( pwszPattern + dwPatternIndex, L"*", TRUE, 1 ) == 0 )
  3965. {
  3966. // the text matches the pattern
  3967. bResult = TRUE;
  3968. }
  3969. }
  3970. }
  3971. // return the result of the pattern matching
  3972. return bResult;
  3973. }
  3974. BOOL
  3975. MatchPatternEx(
  3976. IN LPCWSTR pwszText,
  3977. IN LPCWSTR pwszPattern,
  3978. IN DWORD dwFlags )
  3979. {
  3980. // local variables
  3981. BOOL bResult = FALSE;
  3982. // text comparision flags
  3983. LCID lcid = 0;
  3984. DWORD dwCompareFlags = 0;
  3985. // check the input
  3986. if ( pwszText == NULL )
  3987. {
  3988. return FALSE;
  3989. }
  3990. // check the pattern
  3991. if ( pwszPattern == NULL )
  3992. {
  3993. // get the parsed pattern information
  3994. pwszPattern = GetTempBuffer( INDEX_TEMP_PATTERN, NULL, 0, FALSE );
  3995. if ( pwszPattern == NULL || StringLength( pwszPattern, 0 ) == 0 )
  3996. {
  3997. INVALID_PARAMETER();
  3998. return FALSE;
  3999. }
  4000. }
  4001. else
  4002. {
  4003. if ( (dwFlags & PATTERN_NOPARSING) == 0 )
  4004. {
  4005. // user passed a new pattern information parse and validate it
  4006. pwszPattern = ParsePattern( pwszPattern );
  4007. if ( pwszPattern == FALSE )
  4008. {
  4009. return FALSE;
  4010. }
  4011. }
  4012. }
  4013. // check whether we have the pattern information or not -- safety check
  4014. if ( pwszPattern == NULL )
  4015. {
  4016. UNEXPECTED_ERROR();
  4017. return FALSE;
  4018. }
  4019. // if the pattern is '*' we dont need to do any thing
  4020. // just pass TRUE to the caller
  4021. // the pattern will match to the any string
  4022. if ( StringCompareEx( pwszPattern, L"*", TRUE, 0 ) == 0 )
  4023. {
  4024. return TRUE;
  4025. }
  4026. //
  4027. // determine the locale
  4028. if ( dwFlags & PATTERN_LOCALE_USENGLISH )
  4029. {
  4030. // prepare the LCID
  4031. // if this tool is designed to work on XP and earlier, then
  4032. // we can use LOCALE_INVARIANT -- otherwise, we need to prepare the lcid
  4033. lcid = LOCALE_INVARIANT;
  4034. if ( g_dwMajorVersion == 5 && g_dwMinorVersion == 0 )
  4035. {
  4036. // tool desgined to work on pre-windows xp
  4037. lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT );
  4038. }
  4039. }
  4040. else
  4041. {
  4042. lcid = GetThreadLocale();
  4043. }
  4044. //
  4045. // determine the comparision flags
  4046. // NORM_IGNORECASE
  4047. if ( dwFlags & PATTERN_COMPARE_IGNORECASE )
  4048. {
  4049. dwCompareFlags |= NORM_IGNORECASE;
  4050. }
  4051. // NORM_IGNOREKANATYPE
  4052. if ( dwFlags & PATTERN_COMPARE_IGNOREKANATYPE )
  4053. {
  4054. dwCompareFlags |= NORM_IGNOREKANATYPE;
  4055. }
  4056. // NORM_IGNORENONSPACE
  4057. if ( dwFlags & PATTERN_COMPARE_IGNORENONSPACE )
  4058. {
  4059. dwCompareFlags |= NORM_IGNORENONSPACE;
  4060. }
  4061. // NORM_IGNORESYMBOLS
  4062. if ( dwFlags & PATTERN_COMPARE_IGNORESYMBOLS )
  4063. {
  4064. dwCompareFlags |= NORM_IGNORESYMBOLS;
  4065. }
  4066. // NORM_IGNOREWIDTH
  4067. if ( dwFlags & PATTERN_COMPARE_IGNOREWIDTH )
  4068. {
  4069. dwCompareFlags |= NORM_IGNOREWIDTH;
  4070. }
  4071. // SORT_STRINGSORT
  4072. if ( dwFlags & PATTERN_COMPARE_STRINGSORT )
  4073. {
  4074. dwCompareFlags |= SORT_STRINGSORT;
  4075. }
  4076. //
  4077. // check the pattern match
  4078. bResult = InternalRecursiveMatchPatternEx(
  4079. pwszText, pwszPattern, lcid, dwCompareFlags, 0 );
  4080. // return
  4081. return bResult;
  4082. }