|
|
/*++
Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
Module Name:
init.c
Abstract:
This file contains the initialization code for the NLS APIs.
External Routines found in this file: NlsDllInitialize
Revision History:
05-31-91 JulieB Created.
--*/
//
// Include Files.
//
#include "nls.h"
#include "nlssafe.h"
#include "stdio.h"
//
// Global Variables.
//
HANDLE hModule; // handle to module
RTL_CRITICAL_SECTION gcsTblPtrs; // critical section for tbl ptrs
UINT gAnsiCodePage; // Ansi code page value
UINT gOemCodePage; // OEM code page value
UINT gMacCodePage; // MAC code page value
LCID gSystemLocale; // system locale value
LANGID gSystemInstallLang; // system's original install language
PLOC_HASH gpSysLocHashN; // ptr to system loc hash node
PLOC_HASH gpInvLocHashN; // ptr to invariant loc hash node
PCP_HASH gpACPHashN; // ptr to ACP hash node
PCP_HASH gpOEMCPHashN; // ptr to OEMCP hash node
PCP_HASH gpMACCPHashN; // ptr to MACCP hash node
HANDLE hCodePageKey; // handle to System\Nls\CodePage key
HANDLE hLocaleKey; // handle to System\Nls\Locale key
HANDLE hAltSortsKey; // handle to Locale\Alternate Sorts key
HANDLE hLangGroupsKey; // handle to System\Nls\Language Groups key
PNLS_USER_INFO pNlsUserInfo; // ptr to the user info cache
PNLS_USER_INFO pServerNlsUserInfo; // ptr to the user info cache in the csrss.exe.
NLS_USER_INFO gProcUserInfo; // The user info cache for the process.
// The values in this cached are updated from the content of the
// server side cache (pNlsRegUserInfo in csrss.exe).
// Every time when we read the cache, we will check a version count (ulCacheUpdateCount
// field in NLS_USER_INFO) against the server-side cache (pNlsRegUserInfo) to
// see if the process cache is still valid. The ulCacheUpdateCount will be incremented
// and sync'ed in the server-side when SetLocaleInfo() happens or intl registry key changes.
RTL_CRITICAL_SECTION gcsNlsProcessCache; // critical section for nls process cache
//
// Forward Declarations.
//
ULONG NlsServerInitialize(void);
ULONG NlsProcessInitialize(void);
void InitKoreanWeights(void);
//-------------------------------------------------------------------------//
// EXTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// NlsDllInitialize
//
// DLL Entry initialization procedure for NLSAPI. This is called by
// the base dll initialization.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOLEAN NlsDllInitialize( IN PVOID hMod, ULONG Reason, IN PBASE_STATIC_SERVER_DATA pBaseStaticServerData) { if (Reason == DLL_PROCESS_ATTACH) { ULONG rc;
//
// Save module handle for use later.
//
hModule = (HANDLE)hMod;
//
// Initialize the cached user info pointer.
//
pServerNlsUserInfo = &(pBaseStaticServerData->NlsUserInfo);
pNlsUserInfo = &gProcUserInfo;
//
// Process attaching, so initialize tables.
//
rc = NlsServerInitialize(); if (rc) { KdPrint(("NLSAPI: Could NOT initialize Server - %lx.\n", rc)); return (FALSE); }
rc = NlsProcessInitialize(); if (rc) { KdPrint(("NLSAPI: Could NOT initialize Process - %lx.\n", rc)); return (FALSE); } }
//
// Return success.
//
return (TRUE); }
////////////////////////////////////////////////////////////////////////////
//
// NlsThreadCleanup
//
// Cleanup for thread resources when it terminates.
//
// 03-30-99 SamerA Created.
////////////////////////////////////////////////////////////////////////////
VOID NlsThreadCleanup( VOID) { if (NtCurrentTeb()->NlsCache) { CLOSE_REG_KEY( ((PNLS_LOCAL_CACHE)NtCurrentTeb()->NlsCache)->CurrentUserKeyHandle ); RtlFreeHeap( RtlProcessHeap(), 0, NtCurrentTeb()->NlsCache ); } }
//-------------------------------------------------------------------------//
// INTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// NlsServerInitialize
//
// Server initialization procedure for NLSAPI. This is the ONE-TIME
// initialization code for the NLSAPI DLL. It simply does the calls
// to NtCreateSection for the code pages that are currently found in the
// system.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG NlsServerInitialize(void) { HANDLE hSec = (HANDLE)0; // section handle
ULONG rc; PPEB Peb; #ifndef DOSWIN32
PIMAGE_NT_HEADERS NtHeaders; #endif
Peb = NtCurrentPeb();
//
// MultiUser NT (Hydra). SesssionId = 0 is the console CSRSS.
// If this is NOT the first server process, then just return success,
// since we only want to create the object directories once.
//
if (Peb->SessionId != 0) { return (NO_ERROR); }
#ifndef DOSWIN32
//
// This is to avoid being initialized again when NTSD dynlinks to
// a server to get at its debugger extensions.
//
NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress); if (NtHeaders && (NtHeaders->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE)) { return (NO_ERROR); } #endif
//
// Create the NLS object directory.
//
// Must create a separate directory off the root in order to have
// CreateSection access on the fly.
//
if (rc = CreateNlsObjectDirectory()) { return (rc); }
//
// The ACP, OEMCP, and Default Language files are already created
// at boot time. The pointers to the files are stored in the PEB.
//
// Create the section for the following data files:
// UNICODE
// LOCALE
// CTYPE
// SORTKEY
// SORT TABLES
//
// All other data files will have the sections created only as they
// are needed.
//
if ((!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_UNICODE, 0, &hSec))) || (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_LOCALE, 0, &hSec))) || (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_CTYPE, 0, &hSec))) || (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_SORTKEY, 0, &hSec))) || (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_SORTTBLS, 0, &hSec)))) { return (rc); }
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// NlsProcessInitialize
//
// Process initialization procedure for NLS API. This routine sets up all
// of the tables so that they are accessable from the current process. If
// it is unable to allocate the appropriate memory or memory map the
// appropriate files, an error is returned.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG NlsProcessInitialize(void) { ULONG rc; LPWORD pBaseAddr; // ptr to base address of section
LCID UserLocale; // user locale id
PLOC_HASH pUserLocHashN; // ptr to user locale hash node
PPEB Peb;
Peb = NtCurrentPeb();
//
// Initialize the critical section that protects the NLS cache for
// this process.
//
if ((rc = RtlInitializeCriticalSection(&gcsNlsProcessCache)) != ERROR_SUCCESS) { return (rc); }
//
// Initialize the table pointers critical section.
// Enter the critical section to set up the tables.
//
if ((rc = RtlInitializeCriticalSectionAndSpinCount(&gcsTblPtrs, 4000)) != ERROR_SUCCESS) { return (rc); } RtlEnterCriticalSection(&gcsTblPtrs);
//
// Allocate initial tables.
//
if (rc = AllocTables()) { KdPrint(("AllocTables failed, rc %lx\n", rc)); RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// Initialize the handles to the various registry keys to NULL.
//
hCodePageKey = NULL; hLocaleKey = NULL; hAltSortsKey = NULL; hLangGroupsKey = NULL;
//
// Get the ANSI code page value.
// Create the hash node for the ACP.
// Insert the hash node into the global CP hash table.
//
// At this point, the ACP table has already been mapped into
// the process, so get the pointer from the PEB.
//
pBaseAddr = Peb->AnsiCodePageData; gAnsiCodePage = ((PCP_TABLE)(pBaseAddr + CP_HEADER))->CodePage; if (rc = MakeCPHashNode( gAnsiCodePage, pBaseAddr, &gpACPHashN, FALSE, NULL )) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// Get the OEM code page value.
// Create the hash node for the OEMCP.
// Insert the hash node into the global CP hash table.
//
// At this point, the OEMCP table has already been mapped into
// the process, so get the pointer from the PEB.
//
pBaseAddr = Peb->OemCodePageData; gOemCodePage = ((PCP_TABLE)(pBaseAddr + CP_HEADER))->CodePage; if (gOemCodePage != gAnsiCodePage) { //
// Oem code page is different than the Ansi code page, so
// need to create and store the new hash node.
//
if (rc = MakeCPHashNode( gOemCodePage, pBaseAddr, &gpOEMCPHashN, FALSE, NULL )) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); } } else { //
// Oem code page is the same as the Ansi code page, so set
// the oem cp hash node to be the same as the ansi cp hash node.
//
gpOEMCPHashN = gpACPHashN; }
//
// Initialize the MAC code page values to 0.
// These values will be set the first time they are requested for use.
//
gMacCodePage = 0; gpMACCPHashN = NULL;
//
// Open and Map a View of the Section for UNICODE.NLS.
// Save the pointers to the table information in the table ptrs
// structure.
//
if (rc = GetUnicodeFileInfo()) { KdPrint(("GetUnicodeFileInfo failed, rc %lx\n", rc)); RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// Cache the system locale value.
//
rc = NtQueryDefaultLocale(FALSE, &gSystemLocale); if (!NT_SUCCESS(rc)) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// Store the user locale value.
//
UserLocale = pNlsUserInfo->UserLocaleId; if (UserLocale == 0) { UserLocale = gSystemLocale; }
//
// Initialize the system install language to zero. This will only
// be retrieved on an as need basis.
//
gSystemInstallLang = 0;
//
// Open and Map a View of the Section for LOCALE.NLS.
// Create and insert the hash node into the global Locale hash table
// for the system default locale.
//
if (rc = GetLocaleFileInfo( gSystemLocale, &gpSysLocHashN, TRUE )) { //
// Change the system locale to be the default (English).
//
if (GetLocaleFileInfo( MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT), &gpSysLocHashN, TRUE )) { KdPrint(("Couldn't do English\n")); RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); } else { //
// Registry is corrupt, but allow the English default to
// work. Need to reset the system default.
//
gSystemLocale = MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT); KdPrint(("NLSAPI: Registry is corrupt - Using Default Locale.\n")); } }
//
// If the user default locale is different from the system default
// locale, then create and insert the hash node into the global
// Locale hash table for the user default locale.
//
// NOTE: The System Default Locale Hash Node should be
// created before this call.
//
if (UserLocale != gSystemLocale) { if (rc = GetLocaleFileInfo( UserLocale, &pUserLocHashN, TRUE )) { //
// Change the user locale to be equal to the system default.
//
UserLocale = gSystemLocale; KdPrint(("NLSAPI: Registry is corrupt - User Locale Now Equals System Locale.\n")); } }
//
// Create and insert the hash node into the global Locale hash
// table for the invariant locale.
//
if (rc = GetLocaleFileInfo( LOCALE_INVARIANT, &gpInvLocHashN, TRUE )) { KdPrint(("NLSAPI: Registry is corrupt - Invariant Locale Cannot Be Initialized.\n")); }
//
// Open and Map a View of the Section for SORTKEY.NLS.
// Save the pointers to the semaphore dword and the default sortkey
// table in the table ptrs structure.
//
if (rc = GetDefaultSortkeyFileInfo()) { KdPrint(("NLSAPI: Initialization, GetDefaultSortkeyFileInfo failed with rc %lx.\n", rc)); // RtlLeaveCriticalSection(&gcsTblPtrs);
// return (rc);
}
//
// Open and Map a View of the Section for SORTTBLS.NLS.
// Save the pointers to the sort table information in the
// table ptrs structure.
//
if (rc = GetDefaultSortTablesFileInfo()) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// Get the language information portion of the system locale.
//
// NOTE: GetDefaultSortkeyFileInfo and GetDefaultSortTablesFileInfo
// should be called before this so that the default sorting
// tables are already initialized at the time of the call.
//
if (rc = GetLanguageFileInfo( gSystemLocale, &gpSysLocHashN, FALSE, 0 )) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// Get the language information portion of the invariant locale. We
// use the default locale (US English).
//
if (rc = GetLanguageFileInfo( MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT), &gpInvLocHashN, FALSE, 0 )) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// If the user default is different from the system default,
// get the language information portion of the user default locale.
//
// NOTE: GetDefaultSortkeyFileInfo and GetDefaultSortTablesFileInfo
// should be called before this so that the default sorting
// tables are already initialized at the time of the call.
//
if (gSystemLocale != UserLocale) { if (rc = MakeLangHashNode( UserLocale, NULL, &pUserLocHashN, FALSE )) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); } }
//
// Initialize the Korean SMWeight values.
//
InitKoreanWeights();
//
// Leave the critical section.
//
RtlLeaveCriticalSection(&gcsTblPtrs);
RtlEnterCriticalSection(&gcsNlsProcessCache); //
// Fill up the cache from the cache in csrss.exe so that we have a fresh copy of cache
// values. We will retrieve a copy of ulCacheUpdateCount so that we can check
// if the cache values are no longer valid after they are retrieved here.
//
// Enter a critical section gcsNlsProcessCache to provide synchronization between
// threads since we are updating the process-wide cache.
//
if (!NT_SUCCESS(CsrBasepNlsGetUserInfo(pNlsUserInfo, sizeof(NLS_USER_INFO)))) { RtlLeaveCriticalSection(&gcsNlsProcessCache); return (ERROR_INVALID_FUNCTION); } RtlLeaveCriticalSection(&gcsNlsProcessCache);
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// InitKoreanWeights
//
// Creates the SMWeight array with the IDEOGRAPH script member sorting
// before all other script members.
//
// NOTE: This function assumes we're in a critical section.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
void InitKoreanWeights() { DWORD ctr; // loop counter
BYTE NewScript; // new script to store
LPBYTE pSMWeight = pTblPtrs->SMWeight; // ptr to script member weights
PMULTI_WT pMulti; // ptr to multi weight
//
// Set the 0 to FIRST_SCRIPT of script structure to its default
// value.
//
RtlZeroMemory(pSMWeight, NUM_SM); for (ctr = 1; ctr < FIRST_SCRIPT; ctr++) { pSMWeight[ctr] = (BYTE)ctr; }
//
// Save the order in the SMWeight array.
//
NewScript = FIRST_SCRIPT; pSMWeight[IDEOGRAPH] = NewScript; NewScript++;
//
// See if the script is part of a multiple weights script.
//
pMulti = pTblPtrs->pMultiWeight; for (ctr = pTblPtrs->NumMultiWeight; ctr > 0; ctr--, pMulti++) { if (pMulti->FirstSM == IDEOGRAPH) { //
// Part of multiple weight, so must move entire range
// by setting each value in range to NewScript and
// then incrementing NewScript.
//
// NOTE: May use 'ctr' here since it ALWAYS breaks
// out of outer for loop.
//
for (ctr = 1; ctr < pMulti->NumSM; ctr++) { pSMWeight[IDEOGRAPH + ctr] = NewScript; NewScript++; } break; } }
//
// Must set each script member that has not yet been reset to its
// new order.
//
// The default ordering is to assign:
// Order = Script Member Value
//
// Therefore, can simply set each zero entry in order to the end
// of the array to the next 'NewScript' value.
//
for (ctr = FIRST_SCRIPT; ctr < NUM_SM; ctr++) { //
// If it's a zero value, set it to the next sorting order value.
//
if (pSMWeight[ctr] == 0) { pSMWeight[ctr] = NewScript; NewScript++; } } }
|