Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

852 lines
25 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. security.c
  5. Abstract:
  6. This file handles the management of the NLS per-thread and process cache.
  7. The cache is only established when hitting an API that needs it. The process
  8. NLS cache is used when accessing NLS info for a process NOT running in the
  9. context of the interactive logged on user. The per-thread NLS cache is used
  10. when accssing NLS info and the thread is doing a user impersonation.
  11. External Routines found in this file:
  12. NlsFlushProcessCache
  13. NlsGetCurrentUserNlsInfo
  14. NlsIsInteractiveUserProcess
  15. NlsCheckForInteractiveUser
  16. NlsGetUserLocale
  17. Revision History:
  18. 03-29-1999 SamerA Created.
  19. --*/
  20. //
  21. // Include Files.
  22. //
  23. #include "nls.h"
  24. //
  25. // Global Variables.
  26. //
  27. //
  28. // Process Nls Cache.
  29. //
  30. PNLS_LOCAL_CACHE gpNlsProcessCache;
  31. //
  32. // Whether the current running process is the same as the
  33. // interactive logged on user.
  34. //
  35. BOOL gInteractiveLogonUserProcess = (BOOL)-1;
  36. //
  37. // Forward Declarations.
  38. //
  39. NTSTATUS FASTCALL
  40. NlsGetCacheBuffer(
  41. PNLS_USER_INFO pNlsUserInfo,
  42. LCTYPE LCType,
  43. PWSTR *ppCache);
  44. void FASTCALL
  45. NlsInvalidateCache(
  46. PNLS_USER_INFO pNlsUserInfo);
  47. //-------------------------------------------------------------------------//
  48. // EXTERNAL ROUTINES //
  49. //-------------------------------------------------------------------------//
  50. ////////////////////////////////////////////////////////////////////////////
  51. //
  52. // NlsFlushProcessCache
  53. //
  54. // Invalidates an entry in the NLS process cache.
  55. //
  56. // 05-22-99 SamerA Created.
  57. ////////////////////////////////////////////////////////////////////////////
  58. NTSTATUS NlsFlushProcessCache(
  59. LCTYPE LCType)
  60. {
  61. PWSTR pOutputCache;
  62. NTSTATUS NtStatus = STATUS_SUCCESS;
  63. //
  64. // If there is no thread impersonation, then flush the
  65. // process entry cache.
  66. //
  67. if (NtCurrentTeb()->IsImpersonating != 0)
  68. {
  69. return (NtStatus);
  70. }
  71. if (gpNlsProcessCache)
  72. {
  73. NtStatus = NlsGetCacheBuffer( &gpNlsProcessCache->NlsInfo,
  74. LCType,
  75. &pOutputCache );
  76. if (NT_SUCCESS(NtStatus))
  77. {
  78. RtlEnterCriticalSection(&gcsNlsProcessCache);
  79. pOutputCache[0] = NLS_INVALID_INFO_CHAR;
  80. RtlLeaveCriticalSection(&gcsNlsProcessCache);
  81. }
  82. }
  83. return (NtStatus);
  84. }
  85. ////////////////////////////////////////////////////////////////////////////
  86. //
  87. // NlsGetCurrentUserNlsInfo
  88. //
  89. // Retreive the NLS info correponding to the current security context.
  90. //
  91. // 03-29-99 SamerA Created.
  92. ////////////////////////////////////////////////////////////////////////////
  93. NTSTATUS NlsGetCurrentUserNlsInfo(
  94. LCID Locale,
  95. LCTYPE LCType,
  96. PWSTR RegistryValue,
  97. PWSTR pOutputBuffer,
  98. BOOL IgnoreLocaleValue)
  99. {
  100. NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
  101. PNLS_LOCAL_CACHE pNlsThreadCache;
  102. PWSTR pOutputCache;
  103. //
  104. // Possible NtCurrentTeb()->IsImpersonating values :
  105. //
  106. // 0 : Thread isn't impersonating any user.
  107. //
  108. // 1 : Thread has just started to do impersonation.
  109. // Per thread cache needs to be allocated now.
  110. //
  111. // 2 : Thread is calling the NLS apis while its
  112. // a context other than the interactive logged on user.
  113. //
  114. switch (NtCurrentTeb()->IsImpersonating)
  115. {
  116. case ( 0 ) :
  117. {
  118. //
  119. // Thread is NOT impersonating any user. We check if the process
  120. // belongs to the interactive user, then we retreive the info from
  121. // the NLS cache in CSR. Otherwise if the process is running in
  122. // the context of a different user, then we retreive the NLS info
  123. // from the process cache.
  124. //
  125. if (gInteractiveLogonUserProcess == (BOOL)-1)
  126. {
  127. NlsIsInteractiveUserProcess();
  128. }
  129. if (gInteractiveLogonUserProcess == FALSE)
  130. {
  131. if ((IgnoreLocaleValue) ||
  132. (GetUserDefaultLCID() == Locale))
  133. {
  134. if (!gpNlsProcessCache)
  135. {
  136. //
  137. // Allocate and invalidate the NLS process cache.
  138. //
  139. RtlEnterCriticalSection(&gcsNlsProcessCache);
  140. if (!gpNlsProcessCache)
  141. {
  142. gpNlsProcessCache = RtlAllocateHeap(
  143. RtlProcessHeap(),
  144. 0,
  145. sizeof(NLS_LOCAL_CACHE) );
  146. if (gpNlsProcessCache)
  147. {
  148. NlsInvalidateCache(&gpNlsProcessCache->NlsInfo);
  149. gpNlsProcessCache->CurrentUserKeyHandle = NULL;
  150. }
  151. }
  152. RtlLeaveCriticalSection(&gcsNlsProcessCache);
  153. }
  154. if (gpNlsProcessCache)
  155. {
  156. NtStatus = NlsGetCacheBuffer( &gpNlsProcessCache->NlsInfo,
  157. LCType,
  158. &pOutputCache );
  159. if (NT_SUCCESS(NtStatus))
  160. {
  161. //
  162. // See if it is a valid cache.
  163. //
  164. if (pOutputCache[0] == NLS_INVALID_INFO_CHAR)
  165. {
  166. RtlEnterCriticalSection(&gcsNlsProcessCache);
  167. if (GetUserInfoFromRegistry( RegistryValue,
  168. pOutputCache, 0 ) == FALSE)
  169. {
  170. NtStatus = STATUS_UNSUCCESSFUL;
  171. pOutputCache[0] = NLS_INVALID_INFO_CHAR;
  172. }
  173. RtlLeaveCriticalSection(&gcsNlsProcessCache);
  174. }
  175. if (NT_SUCCESS(NtStatus))
  176. {
  177. NlsStrCpyW(pOutputBuffer, pOutputCache);
  178. }
  179. }
  180. }
  181. }
  182. }
  183. break;
  184. }
  185. case ( 1 ) :
  186. {
  187. //
  188. // Thread started to do impersonation.
  189. //
  190. pNlsThreadCache = NtCurrentTeb()->NlsCache;
  191. if (!pNlsThreadCache)
  192. {
  193. pNlsThreadCache = RtlAllocateHeap( RtlProcessHeap(),
  194. 0,
  195. sizeof(NLS_LOCAL_CACHE) );
  196. if (pNlsThreadCache)
  197. {
  198. pNlsThreadCache->CurrentUserKeyHandle = NULL;
  199. }
  200. NtCurrentTeb()->NlsCache = (PVOID) pNlsThreadCache;
  201. }
  202. if (pNlsThreadCache)
  203. {
  204. NlsInvalidateCache(&pNlsThreadCache->NlsInfo);
  205. }
  206. NtCurrentTeb()->IsImpersonating = 2;
  207. //
  208. // Fall Thru...
  209. //
  210. }
  211. case ( 2 ) :
  212. {
  213. //
  214. // Thread is impersonating a particular user.
  215. //
  216. pNlsThreadCache = NtCurrentTeb()->NlsCache;
  217. if (pNlsThreadCache)
  218. {
  219. if ((IgnoreLocaleValue) ||
  220. (GetUserDefaultLCID() == Locale))
  221. {
  222. NtStatus = NlsGetCacheBuffer( &pNlsThreadCache->NlsInfo,
  223. LCType,
  224. &pOutputCache );
  225. if (NT_SUCCESS(NtStatus))
  226. {
  227. if (pOutputCache[0] == NLS_INVALID_INFO_CHAR)
  228. {
  229. //
  230. // Don't cache key handles - this will break
  231. // profile unload.
  232. //
  233. OPEN_CPANEL_INTL_KEY( pNlsThreadCache->CurrentUserKeyHandle,
  234. STATUS_UNSUCCESSFUL,
  235. KEY_READ );
  236. NtStatus = NlsQueryCurrentUserInfo( pNlsThreadCache,
  237. RegistryValue,
  238. pOutputCache );
  239. CLOSE_REG_KEY(pNlsThreadCache->CurrentUserKeyHandle);
  240. if (!NT_SUCCESS(NtStatus))
  241. {
  242. pOutputCache[0] = NLS_INVALID_INFO_CHAR;
  243. }
  244. }
  245. if (NT_SUCCESS(NtStatus))
  246. {
  247. NlsStrCpyW(pOutputBuffer, pOutputCache);
  248. }
  249. }
  250. }
  251. }
  252. break;
  253. }
  254. }
  255. return (NtStatus);
  256. }
  257. ////////////////////////////////////////////////////////////////////////////
  258. //
  259. // NlsIsInteractiveUserProcess
  260. //
  261. // Read the process's authetication id out of its access token object and
  262. // cache it since it never changes.
  263. //
  264. // 12-27-98 SamerA Created.
  265. ////////////////////////////////////////////////////////////////////////////
  266. NTSTATUS NlsIsInteractiveUserProcess()
  267. {
  268. NTSTATUS NtStatus;
  269. TOKEN_STATISTICS TokenInformation;
  270. HANDLE TokenHandle;
  271. ULONG BytesRequired;
  272. BOOL IsInteractiveProcess = TRUE;
  273. //
  274. // Get the process access token.
  275. //
  276. NtStatus = NtOpenProcessToken( NtCurrentProcess(),
  277. TOKEN_QUERY,
  278. &TokenHandle );
  279. if (NT_SUCCESS(NtStatus))
  280. {
  281. //
  282. // Get the LUID.
  283. //
  284. NtStatus = NtQueryInformationToken( TokenHandle,
  285. TokenStatistics,
  286. &TokenInformation,
  287. sizeof(TokenInformation),
  288. &BytesRequired );
  289. if (NT_SUCCESS(NtStatus))
  290. {
  291. if (RtlEqualLuid( &pNlsUserInfo->InteractiveUserLuid,
  292. &TokenInformation.AuthenticationId ) == FALSE)
  293. {
  294. IsInteractiveProcess = FALSE;
  295. }
  296. }
  297. NtClose(TokenHandle);
  298. }
  299. gInteractiveLogonUserProcess = IsInteractiveProcess;
  300. return (NtStatus);
  301. }
  302. ////////////////////////////////////////////////////////////////////////////
  303. //
  304. // NlsCheckForInteractiveUser
  305. //
  306. // This function makes sure that the current thread isn't impersonating
  307. // anybody, but the interactive. It compares the authentication-id of the
  308. // interactive user -cached in CSRSS at logon time- with the
  309. // authentication-id of the current thread or process. It returns failure
  310. // ONLY if the current security context -session- isn't the same as the
  311. // interactive logged-on user.
  312. //
  313. // 12-16-98 SamerA Created.
  314. ////////////////////////////////////////////////////////////////////////////
  315. NTSTATUS NlsCheckForInteractiveUser()
  316. {
  317. NTSTATUS NtStatus, ReturnStatus = STATUS_SUCCESS;
  318. TOKEN_STATISTICS TokenInformation;
  319. HANDLE TokenHandle;
  320. ULONG BytesRequired;
  321. PLUID InteractiveUserLuid = &pNlsUserInfo->InteractiveUserLuid;
  322. //
  323. // Get the Token Handle.
  324. // Fast optimization to detect if a thread hasn't started to do any
  325. // impersonation, which is the case for most GUI user apps.
  326. //
  327. if (NtCurrentTeb()->IsImpersonating == 0)
  328. {
  329. NtStatus = STATUS_NO_TOKEN;
  330. }
  331. else
  332. {
  333. NtStatus = NtOpenThreadToken( NtCurrentThread(),
  334. TOKEN_QUERY,
  335. FALSE,
  336. &TokenHandle );
  337. }
  338. if (!NT_SUCCESS(NtStatus))
  339. {
  340. if (NtStatus != STATUS_NO_TOKEN)
  341. {
  342. KdPrint(("NLSAPI: Couldn't retreive thread token - %lx.\n", NtStatus));
  343. return (STATUS_SUCCESS);
  344. }
  345. //
  346. // Get the process access token.
  347. //
  348. if (gInteractiveLogonUserProcess == (BOOL)-1)
  349. {
  350. NtStatus = NlsIsInteractiveUserProcess();
  351. if (!NT_SUCCESS(NtStatus))
  352. {
  353. KdPrint(("NLSAPI: Couldn't retreive process token - %lx\n", NtStatus));
  354. return (STATUS_SUCCESS);
  355. }
  356. }
  357. if (gInteractiveLogonUserProcess == FALSE)
  358. {
  359. ReturnStatus = STATUS_UNSUCCESSFUL;
  360. }
  361. }
  362. else
  363. {
  364. //
  365. // Get the AuthenticationId of the current thread's security context.
  366. //
  367. NtStatus = NtQueryInformationToken( TokenHandle,
  368. TokenStatistics,
  369. &TokenInformation,
  370. sizeof(TokenInformation),
  371. &BytesRequired );
  372. //
  373. // Close the thread token here.
  374. //
  375. NtClose(TokenHandle);
  376. if (NT_SUCCESS(NtStatus))
  377. {
  378. if (RtlEqualLuid( InteractiveUserLuid,
  379. &TokenInformation.AuthenticationId ) == FALSE)
  380. {
  381. ReturnStatus = STATUS_UNSUCCESSFUL;
  382. }
  383. }
  384. }
  385. return (ReturnStatus);
  386. }
  387. ////////////////////////////////////////////////////////////////////////////
  388. //
  389. // NlsGetUserLocale
  390. //
  391. // Retreives the user locale from the registry of the current security
  392. // context. It is called ONLY when the running security context is
  393. // different from the interactive logged-on security context-(user).
  394. //
  395. // 12-16-98 SamerA Created.
  396. ////////////////////////////////////////////////////////////////////////////
  397. NTSTATUS NlsGetUserLocale(
  398. LCID *Lcid)
  399. {
  400. NTSTATUS NtStatus;
  401. WCHAR wszLocale[MAX_REG_VAL_SIZE];
  402. UNICODE_STRING ObLocaleString;
  403. PNLS_LOCAL_CACHE pNlsCache = NtCurrentTeb()->NlsCache;
  404. //
  405. // Get the current user locale.
  406. //
  407. NtStatus = NlsGetCurrentUserNlsInfo( LOCALE_USER_DEFAULT,
  408. (LCTYPE)LOCALE_SLOCALE,
  409. L"Locale",
  410. wszLocale,
  411. TRUE );
  412. if ((NT_SUCCESS(NtStatus)) ||
  413. (GetUserInfoFromRegistry(L"Locale", wszLocale, 0)))
  414. {
  415. RtlInitUnicodeString(&ObLocaleString, wszLocale);
  416. NtStatus = RtlUnicodeStringToInteger( &ObLocaleString,
  417. 16,
  418. (PULONG)Lcid);
  419. }
  420. return (NtStatus);
  421. }
  422. //-------------------------------------------------------------------------//
  423. // INTERNAL ROUTINES //
  424. //-------------------------------------------------------------------------//
  425. ////////////////////////////////////////////////////////////////////////////
  426. //
  427. // NlsGetCacheBuffer
  428. //
  429. // Get a buffer pointer inside the cache for this LCTYPE.
  430. //
  431. // 03-29-99 SamerA Created.
  432. ////////////////////////////////////////////////////////////////////////////
  433. NTSTATUS FASTCALL NlsGetCacheBuffer(
  434. PNLS_USER_INFO pNlsUserInfo,
  435. LCTYPE LCType,
  436. PWSTR *ppCache)
  437. {
  438. NTSTATUS NtStatus = STATUS_SUCCESS;
  439. switch (LCType)
  440. {
  441. case ( LOCALE_SLANGUAGE ) :
  442. {
  443. *ppCache = pNlsUserInfo->sAbbrevLangName;
  444. break;
  445. }
  446. case ( LOCALE_ICOUNTRY ) :
  447. {
  448. *ppCache = pNlsUserInfo->iCountry;
  449. break;
  450. }
  451. case ( LOCALE_SCOUNTRY ) :
  452. {
  453. *ppCache = pNlsUserInfo->sCountry;
  454. break;
  455. }
  456. case ( LOCALE_SLIST ) :
  457. {
  458. *ppCache = pNlsUserInfo->sList;
  459. break;
  460. }
  461. case ( LOCALE_IMEASURE ) :
  462. {
  463. *ppCache = pNlsUserInfo->iMeasure;
  464. break;
  465. }
  466. case ( LOCALE_IPAPERSIZE ) :
  467. {
  468. *ppCache = pNlsUserInfo->iPaperSize;
  469. break;
  470. }
  471. case ( LOCALE_SDECIMAL ) :
  472. {
  473. *ppCache = pNlsUserInfo->sDecimal;
  474. break;
  475. }
  476. case ( LOCALE_STHOUSAND ) :
  477. {
  478. *ppCache = pNlsUserInfo->sThousand;
  479. break;
  480. }
  481. case ( LOCALE_SGROUPING ) :
  482. {
  483. *ppCache = pNlsUserInfo->sGrouping;
  484. break;
  485. }
  486. case ( LOCALE_IDIGITS ) :
  487. {
  488. *ppCache = pNlsUserInfo->iDigits;
  489. break;
  490. }
  491. case ( LOCALE_ILZERO ) :
  492. {
  493. *ppCache = pNlsUserInfo->iLZero;
  494. break;
  495. }
  496. case ( LOCALE_INEGNUMBER ) :
  497. {
  498. *ppCache = pNlsUserInfo->iNegNumber;
  499. break;
  500. }
  501. case ( LOCALE_SNATIVEDIGITS ) :
  502. {
  503. *ppCache = pNlsUserInfo->sNativeDigits;
  504. break;
  505. }
  506. case ( LOCALE_IDIGITSUBSTITUTION ) :
  507. {
  508. *ppCache = pNlsUserInfo->iDigitSubstitution;
  509. break;
  510. }
  511. case ( LOCALE_SCURRENCY ) :
  512. {
  513. *ppCache = pNlsUserInfo->sCurrency;
  514. break;
  515. }
  516. case ( LOCALE_SMONDECIMALSEP ) :
  517. {
  518. *ppCache = pNlsUserInfo->sMonDecSep;
  519. break;
  520. }
  521. case ( LOCALE_SMONTHOUSANDSEP ) :
  522. {
  523. *ppCache = pNlsUserInfo->sMonThouSep;
  524. break;
  525. }
  526. case ( LOCALE_SMONGROUPING ) :
  527. {
  528. *ppCache = pNlsUserInfo->sMonGrouping;
  529. break;
  530. }
  531. case ( LOCALE_ICURRDIGITS ) :
  532. {
  533. *ppCache = pNlsUserInfo->iCurrDigits;
  534. break;
  535. }
  536. case ( LOCALE_ICURRENCY ) :
  537. {
  538. *ppCache = pNlsUserInfo->iCurrency;
  539. break;
  540. }
  541. case ( LOCALE_INEGCURR ) :
  542. {
  543. *ppCache = pNlsUserInfo->iNegCurr;
  544. break;
  545. }
  546. case ( LOCALE_SPOSITIVESIGN ) :
  547. {
  548. *ppCache = pNlsUserInfo->sPosSign;
  549. break;
  550. }
  551. case ( LOCALE_SNEGATIVESIGN ) :
  552. {
  553. *ppCache = pNlsUserInfo->sNegSign;
  554. break;
  555. }
  556. case ( LOCALE_STIMEFORMAT ) :
  557. {
  558. *ppCache = pNlsUserInfo->sTimeFormat;
  559. break;
  560. }
  561. case ( LOCALE_STIME ) :
  562. {
  563. *ppCache = pNlsUserInfo->sTime;
  564. break;
  565. }
  566. case ( LOCALE_ITIME ) :
  567. {
  568. *ppCache = pNlsUserInfo->iTime;
  569. break;
  570. }
  571. case ( LOCALE_ITLZERO ) :
  572. {
  573. *ppCache = pNlsUserInfo->iTLZero;
  574. break;
  575. }
  576. case ( LOCALE_ITIMEMARKPOSN ) :
  577. {
  578. *ppCache = pNlsUserInfo->iTimeMarkPosn;
  579. break;
  580. }
  581. case ( LOCALE_S1159 ) :
  582. {
  583. *ppCache = pNlsUserInfo->s1159;
  584. break;
  585. }
  586. case ( LOCALE_S2359 ) :
  587. {
  588. *ppCache = pNlsUserInfo->s2359;
  589. break;
  590. }
  591. case ( LOCALE_SSHORTDATE ) :
  592. {
  593. *ppCache = pNlsUserInfo->sShortDate;
  594. break;
  595. }
  596. case ( LOCALE_SDATE ) :
  597. {
  598. *ppCache = pNlsUserInfo->sDate;
  599. break;
  600. }
  601. case ( LOCALE_IDATE ) :
  602. {
  603. *ppCache = pNlsUserInfo->iDate;
  604. break;
  605. }
  606. case ( LOCALE_SYEARMONTH ) :
  607. {
  608. *ppCache = pNlsUserInfo->sYearMonth;
  609. break;
  610. }
  611. case ( LOCALE_SLONGDATE ) :
  612. {
  613. *ppCache = pNlsUserInfo->sLongDate;
  614. break;
  615. }
  616. case ( LOCALE_ICALENDARTYPE ) :
  617. {
  618. *ppCache = pNlsUserInfo->iCalType;
  619. break;
  620. }
  621. case ( LOCALE_IFIRSTDAYOFWEEK ) :
  622. {
  623. *ppCache = pNlsUserInfo->iFirstDay;
  624. break;
  625. }
  626. case ( LOCALE_IFIRSTWEEKOFYEAR ) :
  627. {
  628. *ppCache = pNlsUserInfo->iFirstWeek;
  629. break;
  630. }
  631. case ( LOCALE_SLOCALE ) :
  632. {
  633. *ppCache = pNlsUserInfo->sLocale;
  634. break;
  635. }
  636. default :
  637. {
  638. NtStatus = STATUS_UNSUCCESSFUL;
  639. break;
  640. }
  641. }
  642. return (NtStatus);
  643. }
  644. ////////////////////////////////////////////////////////////////////////////
  645. //
  646. // NlsQueryCurrentUserInfo
  647. //
  648. // Retreive the NLS info from the registry using a cached key.
  649. //
  650. // 04-07-99 SamerA Created.
  651. ////////////////////////////////////////////////////////////////////////////
  652. NTSTATUS NlsQueryCurrentUserInfo(
  653. PNLS_LOCAL_CACHE pNlsCache,
  654. LPWSTR pValue,
  655. LPWSTR pOutput)
  656. {
  657. PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
  658. BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
  659. ULONG rc;
  660. //
  661. // Initialize the output string.
  662. //
  663. *pOutput = 0;
  664. //
  665. // Query the registry value.
  666. //
  667. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  668. rc = QueryRegValue( pNlsCache->CurrentUserKeyHandle,
  669. pValue,
  670. &pKeyValueFull,
  671. MAX_KEY_VALUE_FULLINFO,
  672. NULL );
  673. //
  674. // If the query failed or if the output buffer is not large enough,
  675. // then return failure.
  676. //
  677. if ((rc != NO_ERROR) ||
  678. (pKeyValueFull->DataLength > (MAX_REG_VAL_SIZE * sizeof(WCHAR))))
  679. {
  680. return (STATUS_UNSUCCESSFUL);
  681. }
  682. //
  683. // Save the string in pOutput.
  684. //
  685. NlsStrCpyW(pOutput, GET_VALUE_DATA_PTR(pKeyValueFull));
  686. //
  687. // Return success.
  688. //
  689. return (STATUS_SUCCESS);
  690. }
  691. ////////////////////////////////////////////////////////////////////////////
  692. //
  693. // NlsInvalidateCache
  694. //
  695. // Invalidate an NLS Cache.
  696. //
  697. // 03-29-99 SamerA Created.
  698. ////////////////////////////////////////////////////////////////////////////
  699. void FASTCALL NlsInvalidateCache(
  700. PNLS_USER_INFO pNlsUserInfo)
  701. {
  702. pNlsUserInfo->sAbbrevLangName[0] = NLS_INVALID_INFO_CHAR;
  703. pNlsUserInfo->iCountry[0] = NLS_INVALID_INFO_CHAR;
  704. pNlsUserInfo->sCountry[0] = NLS_INVALID_INFO_CHAR;
  705. pNlsUserInfo->sList[0] = NLS_INVALID_INFO_CHAR;
  706. pNlsUserInfo->iMeasure[0] = NLS_INVALID_INFO_CHAR;
  707. pNlsUserInfo->iPaperSize[0] = NLS_INVALID_INFO_CHAR;
  708. pNlsUserInfo->sDecimal[0] = NLS_INVALID_INFO_CHAR;
  709. pNlsUserInfo->sThousand[0] = NLS_INVALID_INFO_CHAR;
  710. pNlsUserInfo->sGrouping[0] = NLS_INVALID_INFO_CHAR;
  711. pNlsUserInfo->iDigits[0] = NLS_INVALID_INFO_CHAR;
  712. pNlsUserInfo->iLZero[0] = NLS_INVALID_INFO_CHAR;
  713. pNlsUserInfo->iNegNumber[0] = NLS_INVALID_INFO_CHAR;
  714. pNlsUserInfo->sNativeDigits[0] = NLS_INVALID_INFO_CHAR;
  715. pNlsUserInfo->iDigitSubstitution[0] = NLS_INVALID_INFO_CHAR;
  716. pNlsUserInfo->sCurrency[0] = NLS_INVALID_INFO_CHAR;
  717. pNlsUserInfo->sMonDecSep[0] = NLS_INVALID_INFO_CHAR;
  718. pNlsUserInfo->sMonThouSep[0] = NLS_INVALID_INFO_CHAR;
  719. pNlsUserInfo->sMonGrouping[0] = NLS_INVALID_INFO_CHAR;
  720. pNlsUserInfo->iCurrDigits[0] = NLS_INVALID_INFO_CHAR;
  721. pNlsUserInfo->iCurrency[0] = NLS_INVALID_INFO_CHAR;
  722. pNlsUserInfo->iNegCurr[0] = NLS_INVALID_INFO_CHAR;
  723. pNlsUserInfo->sPosSign[0] = NLS_INVALID_INFO_CHAR;
  724. pNlsUserInfo->sNegSign[0] = NLS_INVALID_INFO_CHAR;
  725. pNlsUserInfo->sTimeFormat[0] = NLS_INVALID_INFO_CHAR;
  726. pNlsUserInfo->sTime[0] = NLS_INVALID_INFO_CHAR;
  727. pNlsUserInfo->iTime[0] = NLS_INVALID_INFO_CHAR;
  728. pNlsUserInfo->iTLZero[0] = NLS_INVALID_INFO_CHAR;
  729. pNlsUserInfo->iTimeMarkPosn[0] = NLS_INVALID_INFO_CHAR;
  730. pNlsUserInfo->s1159[0] = NLS_INVALID_INFO_CHAR;
  731. pNlsUserInfo->s2359[0] = NLS_INVALID_INFO_CHAR;
  732. pNlsUserInfo->sShortDate[0] = NLS_INVALID_INFO_CHAR;
  733. pNlsUserInfo->sDate[0] = NLS_INVALID_INFO_CHAR;
  734. pNlsUserInfo->iDate[0] = NLS_INVALID_INFO_CHAR;
  735. pNlsUserInfo->sYearMonth[0] = NLS_INVALID_INFO_CHAR;
  736. pNlsUserInfo->sLongDate[0] = NLS_INVALID_INFO_CHAR;
  737. pNlsUserInfo->iCalType[0] = NLS_INVALID_INFO_CHAR;
  738. pNlsUserInfo->iFirstDay[0] = NLS_INVALID_INFO_CHAR;
  739. pNlsUserInfo->iFirstWeek[0] = NLS_INVALID_INFO_CHAR;
  740. pNlsUserInfo->sLocale[0] = NLS_INVALID_INFO_CHAR;
  741. return;
  742. }