2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Base API Server DLL
4 * FILE: subsystems/win/basesrv/nls.c
5 * PURPOSE: National Language Support (NLS)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *******************************************************************/
13 #include <ndk/mmfuncs.h>
18 /* GLOBALS ********************************************************************/
20 RTL_CRITICAL_SECTION NlsCacheCriticalSection
;
21 PNLS_USER_INFO pNlsRegUserInfo
;
23 BOOLEAN BaseSrvKernel32DelayLoadComplete
;
24 HANDLE BaseSrvKernel32DllHandle
;
25 UNICODE_STRING BaseSrvKernel32DllPath
;
27 POPEN_DATA_FILE pOpenDataFile
;
28 PVOID
/*PGET_DEFAULT_SORTKEY_SIZE */ pGetDefaultSortkeySize
;
29 PVOID
/*PGET_LINGUIST_LANG_SIZE*/ pGetLinguistLangSize
;
30 PVOID
/*PNLS_CONVERT_INTEGER_TO_STRING*/ pNlsConvertIntegerToString
;
31 PVOID
/*PVALIDATE_LCTYPE*/ pValidateLCType
;
32 PVALIDATE_LOCALE pValidateLocale
;
33 PGET_NLS_SECTION_NAME pGetNlsSectionName
;
34 PVOID
/*PGET_USER_DEFAULT_LANGID*/ pGetUserDefaultLangID
;
35 PGET_CP_FILE_NAME_FROM_REGISTRY pGetCPFileNameFromRegistry
;
36 PCREATE_NLS_SECURTY_DESCRIPTOR pCreateNlsSecurityDescriptor
;
38 BASESRV_KERNEL_IMPORTS BaseSrvKernel32Imports
[10] =
40 { "OpenDataFile", (PVOID
*) &pOpenDataFile
},
41 { "GetDefaultSortkeySize", (PVOID
*) &pGetDefaultSortkeySize
},
42 { "GetLinguistLangSize", (PVOID
*) &pGetLinguistLangSize
},
43 { "NlsConvertIntegerToString", (PVOID
*) &pNlsConvertIntegerToString
},
44 { "ValidateLCType", (PVOID
*) &pValidateLCType
},
45 { "ValidateLocale", (PVOID
*) &pValidateLocale
},
46 { "GetNlsSectionName", (PVOID
*) &pGetNlsSectionName
},
47 { "GetUserDefaultLangID", (PVOID
*) &pGetUserDefaultLangID
},
48 { "GetCPFileNameFromRegistry", (PVOID
*) &pGetCPFileNameFromRegistry
},
49 { "CreateNlsSecurityDescriptor", (PVOID
*) &pCreateNlsSecurityDescriptor
},
52 /* FUNCTIONS *****************************************************************/
56 BaseSrvDelayLoadKernel32(VOID
)
60 ANSI_STRING ProcedureName
;
62 /* Only do this once */
63 if (BaseSrvKernel32DelayLoadComplete
) return STATUS_SUCCESS
;
65 /* Loop all imports */
66 for (i
= 0; i
< RTL_NUMBER_OF(BaseSrvKernel32Imports
); i
++)
68 /* Only look them up once */
69 if (!*BaseSrvKernel32Imports
[i
].FunctionPointer
)
71 /* If we haven't loaded the DLL yet, do it now */
72 if (!BaseSrvKernel32DllHandle
)
74 Status
= LdrLoadDll(0,
76 &BaseSrvKernel32DllPath
,
77 &BaseSrvKernel32DllHandle
);
78 if (!NT_SUCCESS(Status
))
80 DPRINT1("Failed to load %wZ\n", &BaseSrvKernel32DllPath
);
85 /* Get the address of the routine being looked up*/
86 RtlInitAnsiString(&ProcedureName
, BaseSrvKernel32Imports
[i
].FunctionName
);
87 Status
= LdrGetProcedureAddress(BaseSrvKernel32DllHandle
,
90 BaseSrvKernel32Imports
[i
].FunctionPointer
);
91 DPRINT1("NLS: Found %Z at 0x%p\n",
93 BaseSrvKernel32Imports
[i
].FunctionPointer
);
94 if (!NT_SUCCESS(Status
)) break;
98 /* Did we find them all? */
99 if (i
== RTL_NUMBER_OF(BaseSrvKernel32Imports
))
102 BaseSrvKernel32DelayLoadComplete
= TRUE
;
103 return STATUS_SUCCESS
;
112 BaseSrvNLSInit(IN PBASE_STATIC_SERVER_DATA StaticData
)
114 /* Initialize the lock */
115 RtlInitializeCriticalSection(&NlsCacheCriticalSection
);
117 /* Initialize the data with all F's */
118 pNlsRegUserInfo
= &StaticData
->NlsUserInfo
;
119 RtlFillMemory(&StaticData
->NlsUserInfo
, sizeof(StaticData
->NlsUserInfo
), 0xFF);
122 pNlsRegUserInfo
->UserLocaleId
= 0;
124 /* Reset the cache update counter */
125 RtlEnterCriticalSection(&NlsCacheCriticalSection
);
126 pNlsRegUserInfo
->ulCacheUpdateCount
= 0;
127 RtlLeaveCriticalSection(&NlsCacheCriticalSection
);
130 NtQueryDefaultLocale(0, &pNlsRegUserInfo
->UserLocaleId
);
135 BaseSrvNlsConnect(IN PCSR_PROCESS CsrProcess
,
136 IN OUT PVOID ConnectionInfo
,
137 IN OUT PULONG ConnectionInfoLength
)
140 return STATUS_SUCCESS
;
143 /* PUBLIC SERVER APIS *********************************************************/
145 CSR_API(BaseSrvNlsSetUserInfo
)
147 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
148 return STATUS_NOT_IMPLEMENTED
;
151 CSR_API(BaseSrvNlsSetMultipleUserInfo
)
153 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
154 return STATUS_NOT_IMPLEMENTED
;
157 CSR_API(BaseSrvNlsCreateSection
)
160 HANDLE SectionHandle
, ProcessHandle
, FileHandle
;
162 UNICODE_STRING NlsSectionName
;
164 PSECURITY_DESCRIPTOR NlsSd
;
165 OBJECT_ATTRIBUTES ObjectAttributes
;
166 WCHAR FileNameBuffer
[32];
167 WCHAR NlsSectionNameBuffer
[32];
168 PBASE_NLS_CREATE_SECTION NlsMsg
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.NlsCreateSection
;
170 /* Load kernel32 first and import the NLS routines */
171 Status
= BaseSrvDelayLoadKernel32();
172 if (!NT_SUCCESS(Status
)) return Status
;
175 NlsMsg
->SectionHandle
= NULL
;
177 /* Check and validate the locale ID, if one is present */
178 LocaleId
= NlsMsg
->LocaleId
;
179 DPRINT1("NLS: Create Section with LCID: %lx for Type: %d\n", LocaleId
, NlsMsg
->Type
);
182 if (!pValidateLocale(LocaleId
)) return STATUS_INVALID_PARAMETER
;
185 /* Check which NLS section is being created */
186 switch (NlsMsg
->Type
)
188 /* For each one, set the correct filename and object name */
190 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionUnicode");
191 NlsFileName
= L
"unicode.nls";
194 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionLocale");
195 NlsFileName
= L
"locale.nls";
198 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionCType");
199 NlsFileName
= L
"ctype.nls";
202 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionSortkey");
203 NlsFileName
= L
"sortkey.nls";
206 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionSortTbls");
207 NlsFileName
= L
"sorttbls.nls";
210 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionCP437");
211 NlsFileName
= L
"c_437.nls";
214 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionCP1252");
215 NlsFileName
= L
"c_1252.nls";
218 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionLANG_EXCEPT");
219 NlsFileName
= L
"l_except.nls";
222 DPRINT1("This type not yet supported\n");
223 return STATUS_NOT_IMPLEMENTED
;
225 DPRINT1("This type not yet supported\n");
226 return STATUS_NOT_IMPLEMENTED
;
228 /* Get the filename for this locale */
229 if (!pGetCPFileNameFromRegistry(NlsMsg
->LocaleId
,
231 RTL_NUMBER_OF(FileNameBuffer
)))
233 DPRINT1("File name query failed\n");
234 return STATUS_INVALID_PARAMETER
;
237 /* Get the name of the section for this locale */
238 DPRINT1("File name: %S\n", FileNameBuffer
);
239 Status
= pGetNlsSectionName(NlsMsg
->LocaleId
,
242 L
"\\NLS\\NlsSectionCP",
243 NlsSectionNameBuffer
,
244 RTL_NUMBER_OF(NlsSectionNameBuffer
));
245 if (!NT_SUCCESS(Status
))
247 DPRINT1("Section name query failed: %lx\n", Status
);
251 /* Setup the name and go open it */
252 NlsFileName
= FileNameBuffer
;
253 DPRINT1("Section name: %S\n", NlsSectionNameBuffer
);
254 RtlInitUnicodeString(&NlsSectionName
, NlsSectionNameBuffer
);
257 RtlInitUnicodeString(&NlsSectionName
, L
"\\NLS\\NlsSectionGeo");
258 NlsFileName
= L
"geo.nls";
261 DPRINT1("NLS: Invalid NLS type!\n");
262 return STATUS_INVALID_PARAMETER
;
265 /* Open the specified NLS file */
266 Status
= pOpenDataFile(&FileHandle
, NlsFileName
);
267 if (Status
!= STATUS_SUCCESS
)
269 DPRINT1("NLS: Failed to open file: %lx\n", Status
);
273 /* Create an SD for the section object */
274 Status
= pCreateNlsSecurityDescriptor(&NlsSd
,
275 sizeof(SECURITY_DESCRIPTOR
),
277 if (!NT_SUCCESS(Status
))
279 DPRINT1("NLS: CreateNlsSecurityDescriptor FAILED!: %lx\n", Status
);
284 /* Create the section object proper */
285 InitializeObjectAttributes(&ObjectAttributes
,
287 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
| OBJ_OPENIF
,
290 Status
= NtCreateSection(&SectionHandle
,
298 RtlFreeHeap(RtlGetProcessHeap(), 0, NlsSd
);
299 if (!NT_SUCCESS(Status
))
301 DPRINT1("NLS: Failed to create section! %lx\n", Status
);
305 /* Open a handle to the calling process */
306 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
307 Status
= NtOpenProcess(&ProcessHandle
,
310 &ApiMessage
->Header
.ClientId
);
311 if (!NT_SUCCESS(Status
))
313 DPRINT1("NLS: Failed to open process! %lx\n", Status
);
314 NtClose(SectionHandle
);
318 /* Duplicate the handle to the section object into it */
319 Status
= NtDuplicateObject(NtCurrentProcess(),
322 &NlsMsg
->SectionHandle
,
326 NtClose(ProcessHandle
);
330 CSR_API(BaseSrvNlsUpdateCacheCount
)
332 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
333 return STATUS_NOT_IMPLEMENTED
;
336 CSR_API(BaseSrvNlsGetUserInfo
)
339 PBASE_NLS_GET_USER_INFO NlsMsg
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.NlsGetUserInfo
;
341 /* Make sure the buffer is valid and of the right size */
342 if ((CsrValidateMessageBuffer(ApiMessage
, &NlsMsg
->NlsUserInfo
, NlsMsg
->Size
, sizeof(BYTE
))) &&
343 (NlsMsg
->Size
== sizeof(NLS_USER_INFO
)))
345 /* Acquire the lock to prevent updates while we copy */
346 Status
= RtlEnterCriticalSection(&NlsCacheCriticalSection
);
347 if (NT_SUCCESS(Status
))
349 /* Do the copy now, then drop the lock */
350 RtlCopyMemory(NlsMsg
->NlsUserInfo
, pNlsRegUserInfo
, NlsMsg
->Size
);
351 DPRINT1("NLS Data copy complete\n");
352 RtlLeaveCriticalSection(&NlsCacheCriticalSection
);
357 /* The data was invalid, bail out */
358 DPRINT1("NLS: Size of info is invalid: %lx vs %lx\n", NlsMsg
->Size
, sizeof(NLS_USER_INFO
));
359 Status
= STATUS_INVALID_PARAMETER
;
366 /* PUBLIC APIS ****************************************************************/
370 BaseSrvNlsLogon(DWORD Unknown
)
372 DPRINT1("%s(%lu) not yet implemented\n", __FUNCTION__
, Unknown
);
373 return STATUS_NOT_IMPLEMENTED
;
378 BaseSrvNlsUpdateRegistryCache(DWORD Unknown1
,
381 DPRINT1("%s(%lu, %lu) not yet implemented\n", __FUNCTION__
, Unknown1
, Unknown2
);
382 return STATUS_NOT_IMPLEMENTED
;