https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3e44a5d71c6ef6f0d6662…
commit 3e44a5d71c6ef6f0d66625369f2633318a73a493
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Fri Jan 14 22:00:55 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Tue Feb 8 15:58:02 2022 +0100
[KERNEL32][CONSRV] Retrieve the best-suited language ID corresponding to the active
console output code page. (#4301)
CORE-17601, CORE-17803
Replaces PR #4281.
Implement SrvGetConsoleLangId() (server-side) and set the new current
thread's locale after connecting to a console, or changing its output
code page.
Based on API tracing on Windows 2003, as well as on comments and code
gathered from:
https://github.com/microsoft/terminal
Tests results are listed in PR #4301.
---
dll/win32/kernel32/client/console/console.c | 57 +++++++++++++++++++++----
dll/win32/kernel32/client/console/init.c | 9 ++--
dll/win32/kernel32/include/console.h | 3 +-
sdk/include/reactos/subsys/win/conmsg.h | 7 ++++
win32ss/user/winsrv/concfg/font.h | 9 ++++
win32ss/user/winsrv/consrv/console.c | 64 +++++++++++++++++++++++++++--
6 files changed, 131 insertions(+), 18 deletions(-)
diff --git a/dll/win32/kernel32/client/console/console.c
b/dll/win32/kernel32/client/console/console.c
index 5c687dfde1d..7a5b3b61c34 100644
--- a/dll/win32/kernel32/client/console/console.c
+++ b/dll/win32/kernel32/client/console/console.c
@@ -1375,8 +1375,6 @@ AllocConsole(VOID)
ULONG AppNameLength = 128 * sizeof(WCHAR);
ULONG CurDirLength = (MAX_PATH + 1) * sizeof(WCHAR);
- LCID lcid;
-
RtlEnterCriticalSection(&ConsoleLock);
if (NtCurrentPeb()->ProcessParameters->ConsoleHandle)
@@ -1427,8 +1425,8 @@ AllocConsole(VOID)
/* Initialize Console Ctrl Handling */
InitializeCtrlHandling();
- /* Sets the current console locale for this thread */
- SetTEBLangID(lcid);
+ /* Sync the current thread's LangId with the console's one */
+ SetTEBLangID();
}
Quit:
@@ -2500,6 +2498,9 @@ SetConsoleOutputCP(UINT wCodePageID)
return FALSE;
}
+ /* Sync the current thread's LangId with the console's one */
+ SetTEBLangID();
+
return TRUE;
}
@@ -2676,9 +2677,7 @@ AttachConsole(DWORD dwProcessId)
{
BOOL Success;
CONSOLE_START_INFO ConsoleStartInfo;
-
DWORD dummy;
- LCID lcid;
RtlEnterCriticalSection(&ConsoleLock);
@@ -2711,8 +2710,8 @@ AttachConsole(DWORD dwProcessId)
/* Initialize Console Ctrl Handling */
InitializeCtrlHandling();
- /* Sets the current console locale for this thread */
- SetTEBLangID(lcid);
+ /* Sync the current thread's LangId with the console's one */
+ SetTEBLangID();
}
Quit:
@@ -3067,6 +3066,48 @@ UnregisterConsoleIME(VOID)
return FALSE;
}
+/**
+ * @brief
+ * Internal helper function used to synchronize the current
+ * thread's language ID with the one from the console.
+ **/
+VOID
+SetTEBLangID(VOID)
+{
+ CONSOLE_API_MESSAGE ApiMessage;
+ PCONSOLE_GETLANGID LangIdRequest = &ApiMessage.Data.LangIdRequest;
+
+ /* Retrieve the "best-suited" language ID corresponding
+ * to the active console output code page. */
+ LangIdRequest->ConsoleHandle =
NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+
+ CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+ NULL,
+ CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX,
ConsolepGetLangId),
+ sizeof(*LangIdRequest));
+ if (!NT_SUCCESS(ApiMessage.Status))
+ {
+ /*
+ * No best console language ID: keep the current thread's one.
+ * Since this internal function only modifies an optional setting,
+ * don't set any last error, as it could otherwise mess with the
+ * main last error set by the caller.
+ */
+ return;
+ }
+
+ /*
+ * We succeeded, set the current thread's language ID by
+ * modifying its locale -- Windows <= 2003 does not have
+ * the concept of a separate thread UI language.
+ * Ignore the returned value.
+ */
+ if (!SetThreadLocale(MAKELCID(LangIdRequest->LangId, SORT_DEFAULT)))
+ {
+ DPRINT1("SetTEBLangID: Could not set thread locale to console lang ID
%lu\n",
+ LangIdRequest->LangId);
+ }
+}
static
BOOL
diff --git a/dll/win32/kernel32/client/console/init.c
b/dll/win32/kernel32/client/console/init.c
index 3186bf4e71f..eb97ac73ded 100644
--- a/dll/win32/kernel32/client/console/init.c
+++ b/dll/win32/kernel32/client/console/init.c
@@ -342,14 +342,13 @@ ConDllInitialize(IN ULONG Reason,
PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
BOOLEAN InServerProcess = FALSE;
CONSRV_API_CONNECTINFO ConnectInfo;
- LCID lcid;
if (Reason != DLL_PROCESS_ATTACH)
{
if ((Reason == DLL_THREAD_ATTACH) && IsConsoleApp())
{
- /* Sets the current console locale for the new thread */
- SetTEBLangID(lcid);
+ /* Sync the new thread's LangId with the console's one */
+ SetTEBLangID();
}
else if (Reason == DLL_PROCESS_DETACH)
{
@@ -522,8 +521,8 @@ ConDllInitialize(IN ULONG Reason,
InputWaitHandle = ConnectInfo.ConsoleStartInfo.InputWaitHandle;
- /* Sets the current console locale for this thread */
- SetTEBLangID(lcid);
+ /* Sync the current thread's LangId with the console's one */
+ SetTEBLangID();
}
DPRINT("Console setup: 0x%p, 0x%p, 0x%p, 0x%p\n",
diff --git a/dll/win32/kernel32/include/console.h b/dll/win32/kernel32/include/console.h
index b6462af46b6..5fe84cb304c 100644
--- a/dll/win32/kernel32/include/console.h
+++ b/dll/win32/kernel32/include/console.h
@@ -60,7 +60,8 @@ GetConsoleInputWaitHandle(VOID);
HANDLE
TranslateStdHandle(HANDLE hHandle);
-#define SetTEBLangID(p) (p)
+VOID
+SetTEBLangID(VOID);
VOID
SetUpConsoleInfo(IN BOOLEAN CaptureTitle,
diff --git a/sdk/include/reactos/subsys/win/conmsg.h
b/sdk/include/reactos/subsys/win/conmsg.h
index b96441dd9aa..dd50cb11437 100644
--- a/sdk/include/reactos/subsys/win/conmsg.h
+++ b/sdk/include/reactos/subsys/win/conmsg.h
@@ -859,6 +859,12 @@ typedef struct _CONSOLE_SETINPUTOUTPUTCP
HANDLE EventHandle;
} CONSOLE_SETINPUTOUTPUTCP, *PCONSOLE_SETINPUTOUTPUTCP;
+typedef struct _CONSOLE_GETLANGID
+{
+ HANDLE ConsoleHandle;
+ LANGID LangId;
+} CONSOLE_GETLANGID, *PCONSOLE_GETLANGID;
+
typedef struct _CONSOLE_GETKBDLAYOUTNAME
{
HANDLE ConsoleHandle;
@@ -991,6 +997,7 @@ typedef struct _CONSOLE_API_MESSAGE
/* Input and Output Code Pages; keyboard */
CONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest;
CONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest;
+ CONSOLE_GETLANGID LangIdRequest;
CONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest;
/* Virtual DOS Machine */
diff --git a/win32ss/user/winsrv/concfg/font.h b/win32ss/user/winsrv/concfg/font.h
index 15224b3f9d6..870b3805a63 100644
--- a/win32ss/user/winsrv/concfg/font.h
+++ b/win32ss/user/winsrv/concfg/font.h
@@ -19,6 +19,15 @@
#define CP_GB2312 936 // Chinese Simplified (GB2312)
#define CP_BIG5 950 // Chinese Traditional (Big5)
+/*
+ * "Human-understandable" names for the previous standard code pages.
+ * Taken from
https://github.com/microsoft/terminal/blob/main/src/inc/unicode.hpp
+ */
+#define CP_JAPANESE CP_SHIFTJIS
+#define CP_KOREAN CP_HANGUL
+#define CP_CHINESE_SIMPLIFIED CP_GB2312
+#define CP_CHINESE_TRADITIONAL CP_BIG5
+
/* IsFarEastCP(CodePage) */
#define IsCJKCodePage(CodePage) \
((CodePage) == CP_SHIFTJIS || (CodePage) == CP_HANGUL || \
diff --git a/win32ss/user/winsrv/consrv/console.c b/win32ss/user/winsrv/consrv/console.c
index 1e35fdea127..cc269604ba7 100644
--- a/win32ss/user/winsrv/consrv/console.c
+++ b/win32ss/user/winsrv/consrv/console.c
@@ -16,7 +16,7 @@
#define COBJMACROS
#include <shlobj.h>
-
+#include "../concfg/font.h"
#include <alias.h>
#include <history.h>
#include "procinit.h"
@@ -2014,10 +2014,66 @@ CSR_API(SrvSetConsoleNlsMode)
}
/* API_NUMBER: ConsolepGetLangId */
-CSR_API(SrvGetConsoleLangId)
+CON_API(SrvGetConsoleLangId,
+ CONSOLE_GETLANGID, LangIdRequest)
{
- DPRINT1("%s not yet implemented\n", __FUNCTION__);
- return STATUS_NOT_IMPLEMENTED;
+ /*
+ * Quoting MS Terminal, see function GetConsoleLangId() at
+ *
https://github.com/microsoft/terminal/blob/main/src/host/srvinit.cpp#L655
+ * "Only attempt to return the Lang ID if the Windows ACP on console
+ * launch was an East Asian Code Page."
+ *
+ * The underlying logic is as follows:
+ *
+ * - When the current user's UI language is *not* CJK, the user expects
+ * to not see any CJK output to the console by default, even if its
+ * output has been set to a CJK code page (this is possible when CJK
+ * fonts are installed on the system). That is, of course, unless if
+ * the attached console program chooses to actually output CJK text.
+ * Whatever current language of the running program's thread should
+ * be kept: STATUS_NOT_SUPPORTED is returned.
+ *
+ * - When the current user's UI language *is* CJK, the user expects to
+ * see CJK output to the console by default when its code page is CJK.
+ * A valid LangId is returned in this case to ensure this.
+ * However, if the console code page is not CJK, then it is evident
+ * that CJK text will not be able to be correctly shown, and therefore
+ * we should fall back to a standard language that can be shown, namely
+ * en-US english, instead of keeping the current language.
+ */
+
+ BYTE UserCharSet = CodePageToCharSet(GetACP());
+ if (!IsCJKCharSet(UserCharSet))
+ return STATUS_NOT_SUPPORTED;
+
+ /* Return a "best-suited" language ID corresponding
+ * to the active console output code page. */
+ switch (Console->OutputCodePage)
+ {
+/** ReactOS-specific: do nothing if the code page is UTF-8. This will allow
+ ** programs to naturally output in whatever current language they are. **/
+ case CP_UTF8:
+ return STATUS_NOT_SUPPORTED;
+/** End ReactOS-specific **/
+ case CP_JAPANESE:
+ LangIdRequest->LangId = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT);
+ break;
+ case CP_KOREAN:
+ LangIdRequest->LangId = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
+ break;
+ case CP_CHINESE_SIMPLIFIED:
+ LangIdRequest->LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
+ break;
+ case CP_CHINESE_TRADITIONAL:
+ LangIdRequest->LangId = MAKELANGID(LANG_CHINESE,
SUBLANG_CHINESE_TRADITIONAL);
+ break;
+ default:
+ /* Default to en-US english otherwise */
+ LangIdRequest->LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
+ break;
+ }
+
+ return STATUS_SUCCESS;
}
/* EOF */