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.

644 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. init.c
  5. Abstract:
  6. This file contains the initialization code for the NLS APIs.
  7. External Routines found in this file:
  8. NlsDllInitialize
  9. Revision History:
  10. 05-31-91 JulieB Created.
  11. --*/
  12. //
  13. // Include Files.
  14. //
  15. #include "nls.h"
  16. #include "stdio.h"
  17. //
  18. // Global Variables.
  19. //
  20. HANDLE hModule; // handle to module
  21. RTL_CRITICAL_SECTION gcsTblPtrs; // critical section for tbl ptrs
  22. UINT gAnsiCodePage; // Ansi code page value
  23. UINT gOemCodePage; // OEM code page value
  24. UINT gMacCodePage; // MAC code page value
  25. LCID gSystemLocale; // system locale value
  26. LANGID gSystemInstallLang; // system's original install language
  27. PLOC_HASH gpSysLocHashN; // ptr to system loc hash node
  28. PLOC_HASH gpInvLocHashN; // ptr to invariant loc hash node
  29. PCP_HASH gpACPHashN; // ptr to ACP hash node
  30. PCP_HASH gpOEMCPHashN; // ptr to OEMCP hash node
  31. PCP_HASH gpMACCPHashN; // ptr to MACCP hash node
  32. HANDLE hCodePageKey; // handle to System\Nls\CodePage key
  33. HANDLE hLocaleKey; // handle to System\Nls\Locale key
  34. HANDLE hAltSortsKey; // handle to Locale\Alternate Sorts key
  35. HANDLE hLangGroupsKey; // handle to System\Nls\Language Groups key
  36. PNLS_USER_INFO pNlsUserInfo; // ptr to the user info cache
  37. RTL_CRITICAL_SECTION gcsNlsProcessCache; // critical section for nls process cache
  38. //
  39. // Forward Declarations.
  40. //
  41. ULONG
  42. NlsServerInitialize(void);
  43. ULONG
  44. NlsProcessInitialize(void);
  45. void
  46. InitKoreanWeights(void);
  47. //-------------------------------------------------------------------------//
  48. // EXTERNAL ROUTINES //
  49. //-------------------------------------------------------------------------//
  50. ////////////////////////////////////////////////////////////////////////////
  51. //
  52. // NlsDllInitialize
  53. //
  54. // DLL Entry initialization procedure for NLSAPI. This is called by
  55. // the base dll initialization.
  56. //
  57. // 05-31-91 JulieB Created.
  58. ////////////////////////////////////////////////////////////////////////////
  59. BOOLEAN NlsDllInitialize(
  60. IN PVOID hMod,
  61. ULONG Reason,
  62. IN PBASE_STATIC_SERVER_DATA pBaseStaticServerData)
  63. {
  64. if (Reason == DLL_PROCESS_ATTACH)
  65. {
  66. ULONG rc;
  67. //
  68. // Save module handle for use later.
  69. //
  70. hModule = (HANDLE)hMod;
  71. //
  72. // Initialize the cached user info pointer.
  73. //
  74. pNlsUserInfo = &(pBaseStaticServerData->NlsUserInfo);
  75. //
  76. // Process attaching, so initialize tables.
  77. //
  78. rc = NlsServerInitialize();
  79. if (rc)
  80. {
  81. KdPrint(("NLSAPI: Could NOT initialize Server - %lx.\n", rc));
  82. return (FALSE);
  83. }
  84. rc = NlsProcessInitialize();
  85. if (rc)
  86. {
  87. KdPrint(("NLSAPI: Could NOT initialize Process - %lx.\n", rc));
  88. return (FALSE);
  89. }
  90. }
  91. //
  92. // Return success.
  93. //
  94. return (TRUE);
  95. }
  96. ////////////////////////////////////////////////////////////////////////////
  97. //
  98. // NlsThreadCleanup
  99. //
  100. // Cleanup for thread resources when it terminates.
  101. //
  102. // 03-30-99 SamerA Created.
  103. ////////////////////////////////////////////////////////////////////////////
  104. BOOLEAN NlsThreadCleanup(void)
  105. {
  106. if (NtCurrentTeb()->NlsCache)
  107. {
  108. CLOSE_REG_KEY( ((PNLS_LOCAL_CACHE)NtCurrentTeb()->NlsCache)->CurrentUserKeyHandle );
  109. RtlFreeHeap( RtlProcessHeap(),
  110. 0,
  111. NtCurrentTeb()->NlsCache
  112. );
  113. }
  114. return (TRUE);
  115. }
  116. //-------------------------------------------------------------------------//
  117. // INTERNAL ROUTINES //
  118. //-------------------------------------------------------------------------//
  119. ////////////////////////////////////////////////////////////////////////////
  120. //
  121. // NlsServerInitialize
  122. //
  123. // Server initialization procedure for NLSAPI. This is the ONE-TIME
  124. // initialization code for the NLSAPI DLL. It simply does the calls
  125. // to NtCreateSection for the code pages that are currently found in the
  126. // system.
  127. //
  128. // 05-31-91 JulieB Created.
  129. ////////////////////////////////////////////////////////////////////////////
  130. ULONG NlsServerInitialize(void)
  131. {
  132. HANDLE hSec = (HANDLE)0; // section handle
  133. ULONG rc = 0L; // return code
  134. #ifndef DOSWIN32
  135. PIMAGE_NT_HEADERS NtHeaders;
  136. //
  137. // This is to avoid being initialized again when NTSD dynlinks to
  138. // a server to get at its debugger extensions.
  139. //
  140. NtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
  141. if (NtHeaders &&
  142. (NtHeaders->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE))
  143. {
  144. return (NO_ERROR);
  145. }
  146. #endif
  147. //
  148. // MultiUser NT (Hydra). SesssionId = 0 is the console CSRSS.
  149. // If this is NOT the first server process, then just return success,
  150. // since we only want to create the object directories once.
  151. //
  152. if (NtCurrentPeb()->SessionId != 0)
  153. {
  154. return (NO_ERROR);
  155. }
  156. //
  157. // Create the NLS object directory.
  158. //
  159. // Must create a separate directory off the root in order to have
  160. // CreateSection access on the fly.
  161. //
  162. if (rc = CreateNlsObjectDirectory())
  163. {
  164. return (rc);
  165. }
  166. //
  167. // The ACP, OEMCP, and Default Language files are already created
  168. // at boot time. The pointers to the files are stored in the PEB.
  169. //
  170. // Create the section for the following data files:
  171. // UNICODE
  172. // LOCALE
  173. // CTYPE
  174. // SORTKEY
  175. // SORT TABLES
  176. //
  177. // All other data files will have the sections created only as they
  178. // are needed.
  179. //
  180. if ((!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_UNICODE, 0, &hSec))) ||
  181. (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_LOCALE, 0, &hSec))) ||
  182. (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_CTYPE, 0, &hSec))) ||
  183. (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_SORTKEY, 0, &hSec))) ||
  184. (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_SORTTBLS, 0, &hSec))))
  185. {
  186. return (rc);
  187. }
  188. //
  189. // Return success.
  190. //
  191. return (NO_ERROR);
  192. }
  193. ////////////////////////////////////////////////////////////////////////////
  194. //
  195. // NlsProcessInitialize
  196. //
  197. // Process initialization procedure for NLS API. This routine sets up all
  198. // of the tables so that they are accessable from the current process. If
  199. // it is unable to allocate the appropriate memory or memory map the
  200. // appropriate files, an error is returned.
  201. //
  202. // 05-31-91 JulieB Created.
  203. ////////////////////////////////////////////////////////////////////////////
  204. ULONG NlsProcessInitialize(void)
  205. {
  206. ULONG rc = 0L; // return code
  207. LPWORD pBaseAddr; // ptr to base address of section
  208. LCID UserLocale; // user locale id
  209. PLOC_HASH pUserLocHashN; // ptr to user locale hash node
  210. //
  211. // Initialize the critical section that protects the NLS cache for
  212. // this process.
  213. //
  214. if ((rc = RtlInitializeCriticalSection(&gcsNlsProcessCache)) != ERROR_SUCCESS)
  215. {
  216. return (rc);
  217. }
  218. //
  219. // Initialize the table pointers critical section.
  220. // Enter the critical section to set up the tables.
  221. //
  222. if ((rc = RtlInitializeCriticalSectionAndSpinCount(&gcsTblPtrs, 4000)) != ERROR_SUCCESS)
  223. {
  224. return (rc);
  225. }
  226. RtlEnterCriticalSection(&gcsTblPtrs);
  227. //
  228. // Allocate initial tables.
  229. //
  230. if (rc = AllocTables())
  231. {
  232. KdPrint(("AllocTables failed, rc %lx\n", rc));
  233. RtlLeaveCriticalSection(&gcsTblPtrs);
  234. return (rc);
  235. }
  236. //
  237. // Initialize the handles to the various registry keys to NULL.
  238. //
  239. hCodePageKey = NULL;
  240. hLocaleKey = NULL;
  241. hAltSortsKey = NULL;
  242. hLangGroupsKey = NULL;
  243. //
  244. // Get the ANSI code page value.
  245. // Create the hash node for the ACP.
  246. // Insert the hash node into the global CP hash table.
  247. //
  248. // At this point, the ACP table has already been mapped into
  249. // the process, so get the pointer from the PEB.
  250. //
  251. pBaseAddr = NtCurrentPeb()->AnsiCodePageData;
  252. gAnsiCodePage = ((PCP_TABLE)(pBaseAddr + CP_HEADER))->CodePage;
  253. if (rc = MakeCPHashNode( gAnsiCodePage,
  254. pBaseAddr,
  255. &gpACPHashN,
  256. FALSE,
  257. NULL ))
  258. {
  259. RtlLeaveCriticalSection(&gcsTblPtrs);
  260. return (rc);
  261. }
  262. //
  263. // Get the OEM code page value.
  264. // Create the hash node for the OEMCP.
  265. // Insert the hash node into the global CP hash table.
  266. //
  267. // At this point, the OEMCP table has already been mapped into
  268. // the process, so get the pointer from the PEB.
  269. //
  270. pBaseAddr = NtCurrentPeb()->OemCodePageData;
  271. gOemCodePage = ((PCP_TABLE)(pBaseAddr + CP_HEADER))->CodePage;
  272. if (gOemCodePage != gAnsiCodePage)
  273. {
  274. //
  275. // Oem code page is different than the Ansi code page, so
  276. // need to create and store the new hash node.
  277. //
  278. if (rc = MakeCPHashNode( gOemCodePage,
  279. pBaseAddr,
  280. &gpOEMCPHashN,
  281. FALSE,
  282. NULL ))
  283. {
  284. RtlLeaveCriticalSection(&gcsTblPtrs);
  285. return (rc);
  286. }
  287. }
  288. else
  289. {
  290. //
  291. // Oem code page is the same as the Ansi code page, so set
  292. // the oem cp hash node to be the same as the ansi cp hash node.
  293. //
  294. gpOEMCPHashN = gpACPHashN;
  295. }
  296. //
  297. // Initialize the MAC code page values to 0.
  298. // These values will be set the first time they are requested for use.
  299. //
  300. gMacCodePage = 0;
  301. gpMACCPHashN = NULL;
  302. //
  303. // Open and Map a View of the Section for UNICODE.NLS.
  304. // Save the pointers to the table information in the table ptrs
  305. // structure.
  306. //
  307. if (rc = GetUnicodeFileInfo())
  308. {
  309. KdPrint(("GetUnicodeFileInfo failed, rc %lx\n", rc));
  310. RtlLeaveCriticalSection(&gcsTblPtrs);
  311. return (rc);
  312. }
  313. //
  314. // Cache the system locale value.
  315. //
  316. rc = NtQueryDefaultLocale(FALSE, &gSystemLocale);
  317. if (!NT_SUCCESS(rc))
  318. {
  319. RtlLeaveCriticalSection(&gcsTblPtrs);
  320. return (rc);
  321. }
  322. //
  323. // Store the user locale value.
  324. //
  325. UserLocale = pNlsUserInfo->UserLocaleId;
  326. if (UserLocale == 0)
  327. {
  328. UserLocale = gSystemLocale;
  329. }
  330. //
  331. // Initialize the system install language to zero. This will only
  332. // be retrieved on an as need basis.
  333. //
  334. gSystemInstallLang = 0;
  335. //
  336. // Open and Map a View of the Section for LOCALE.NLS.
  337. // Create and insert the hash node into the global Locale hash table
  338. // for the system default locale.
  339. //
  340. if (rc = GetLocaleFileInfo( gSystemLocale,
  341. &gpSysLocHashN,
  342. TRUE ))
  343. {
  344. //
  345. // Change the system locale to be the default (English).
  346. //
  347. if (GetLocaleFileInfo( MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT),
  348. &gpSysLocHashN,
  349. TRUE ))
  350. {
  351. KdPrint(("Couldn't do English\n"));
  352. RtlLeaveCriticalSection(&gcsTblPtrs);
  353. return (rc);
  354. }
  355. else
  356. {
  357. //
  358. // Registry is corrupt, but allow the English default to
  359. // work. Need to reset the system default.
  360. //
  361. gSystemLocale = MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT);
  362. KdPrint(("NLSAPI: Registry is corrupt - Using Default Locale.\n"));
  363. }
  364. }
  365. //
  366. // If the user default locale is different from the system default
  367. // locale, then create and insert the hash node into the global
  368. // Locale hash table for the user default locale.
  369. //
  370. // NOTE: The System Default Locale Hash Node should be
  371. // created before this call.
  372. //
  373. if (UserLocale != gSystemLocale)
  374. {
  375. if (rc = GetLocaleFileInfo( UserLocale,
  376. &pUserLocHashN,
  377. TRUE ))
  378. {
  379. //
  380. // Change the user locale to be equal to the system default.
  381. //
  382. UserLocale = gSystemLocale;
  383. KdPrint(("NLSAPI: Registry is corrupt - User Locale Now Equals System Locale.\n"));
  384. }
  385. }
  386. //
  387. // Create and insert the hash node into the global Locale hash
  388. // table for the invariant locale.
  389. //
  390. if (rc = GetLocaleFileInfo( LOCALE_INVARIANT,
  391. &gpInvLocHashN,
  392. TRUE ))
  393. {
  394. KdPrint(("NLSAPI: Registry is corrupt - Invariant Locale Cannot Be Initialized.\n"));
  395. }
  396. //
  397. // Open and Map a View of the Section for SORTKEY.NLS.
  398. // Save the pointers to the semaphore dword and the default sortkey
  399. // table in the table ptrs structure.
  400. //
  401. if (rc = GetDefaultSortkeyFileInfo())
  402. {
  403. KdPrint(("NLSAPI: Initialization, GetDefaultSortkeyFileInfo failed with rc %lx.\n", rc));
  404. // RtlLeaveCriticalSection(&gcsTblPtrs);
  405. // return (rc);
  406. }
  407. //
  408. // Open and Map a View of the Section for SORTTBLS.NLS.
  409. // Save the pointers to the sort table information in the
  410. // table ptrs structure.
  411. //
  412. if (rc = GetDefaultSortTablesFileInfo())
  413. {
  414. RtlLeaveCriticalSection(&gcsTblPtrs);
  415. return (rc);
  416. }
  417. //
  418. // Get the language information portion of the system locale.
  419. //
  420. // NOTE: GetDefaultSortkeyFileInfo and GetDefaultSortTablesFileInfo
  421. // should be called before this so that the default sorting
  422. // tables are already initialized at the time of the call.
  423. //
  424. if (rc = GetLanguageFileInfo( gSystemLocale,
  425. &gpSysLocHashN,
  426. FALSE,
  427. 0 ))
  428. {
  429. RtlLeaveCriticalSection(&gcsTblPtrs);
  430. return (rc);
  431. }
  432. //
  433. // Get the language information portion of the invariant locale. We
  434. // use the default locale (US English).
  435. //
  436. if (rc = GetLanguageFileInfo( MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT),
  437. &gpInvLocHashN,
  438. FALSE,
  439. 0 ))
  440. {
  441. RtlLeaveCriticalSection(&gcsTblPtrs);
  442. return (rc);
  443. }
  444. //
  445. // If the user default is different from the system default,
  446. // get the language information portion of the user default locale.
  447. //
  448. // NOTE: GetDefaultSortkeyFileInfo and GetDefaultSortTablesFileInfo
  449. // should be called before this so that the default sorting
  450. // tables are already initialized at the time of the call.
  451. //
  452. if (gSystemLocale != UserLocale)
  453. {
  454. if (rc = MakeLangHashNode( UserLocale,
  455. NULL,
  456. &pUserLocHashN,
  457. FALSE ))
  458. {
  459. RtlLeaveCriticalSection(&gcsTblPtrs);
  460. return (rc);
  461. }
  462. }
  463. //
  464. // Initialize the Korean SMWeight values.
  465. //
  466. InitKoreanWeights();
  467. //
  468. // Leave the critical section.
  469. //
  470. RtlLeaveCriticalSection(&gcsTblPtrs);
  471. //
  472. // Return success.
  473. //
  474. return (NO_ERROR);
  475. }
  476. ////////////////////////////////////////////////////////////////////////////
  477. //
  478. // InitKoreanWeights
  479. //
  480. // Creates the SMWeight array with the IDEOGRAPH script member sorting
  481. // before all other script members.
  482. //
  483. // NOTE: This function assumes we're in a critical section.
  484. //
  485. // 05-31-91 JulieB Created.
  486. ////////////////////////////////////////////////////////////////////////////
  487. void InitKoreanWeights()
  488. {
  489. DWORD ctr; // loop counter
  490. BYTE NewScript; // new script to store
  491. LPBYTE pSMWeight = pTblPtrs->SMWeight; // ptr to script member weights
  492. PMULTI_WT pMulti; // ptr to multi weight
  493. //
  494. // Set the 0 to FIRST_SCRIPT of script structure to its default
  495. // value.
  496. //
  497. RtlZeroMemory(pSMWeight, NUM_SM);
  498. for (ctr = 1; ctr < FIRST_SCRIPT; ctr++)
  499. {
  500. pSMWeight[ctr] = (BYTE)ctr;
  501. }
  502. //
  503. // Save the order in the SMWeight array.
  504. //
  505. NewScript = FIRST_SCRIPT;
  506. pSMWeight[IDEOGRAPH] = NewScript;
  507. NewScript++;
  508. //
  509. // See if the script is part of a multiple weights script.
  510. //
  511. pMulti = pTblPtrs->pMultiWeight;
  512. for (ctr = pTblPtrs->NumMultiWeight; ctr > 0; ctr--, pMulti++)
  513. {
  514. if (pMulti->FirstSM == IDEOGRAPH)
  515. {
  516. //
  517. // Part of multiple weight, so must move entire range
  518. // by setting each value in range to NewScript and
  519. // then incrementing NewScript.
  520. //
  521. // NOTE: May use 'ctr' here since it ALWAYS breaks
  522. // out of outer for loop.
  523. //
  524. for (ctr = 1; ctr < pMulti->NumSM; ctr++)
  525. {
  526. pSMWeight[IDEOGRAPH + ctr] = NewScript;
  527. NewScript++;
  528. }
  529. break;
  530. }
  531. }
  532. //
  533. // Must set each script member that has not yet been reset to its
  534. // new order.
  535. //
  536. // The default ordering is to assign:
  537. // Order = Script Member Value
  538. //
  539. // Therefore, can simply set each zero entry in order to the end
  540. // of the array to the next 'NewScript' value.
  541. //
  542. for (ctr = FIRST_SCRIPT; ctr < NUM_SM; ctr++)
  543. {
  544. //
  545. // If it's a zero value, set it to the next sorting order value.
  546. //
  547. if (pSMWeight[ctr] == 0)
  548. {
  549. pSMWeight[ctr] = NewScript;
  550. NewScript++;
  551. }
  552. }
  553. }