xref: /reactos/sdk/lib/conutils/utils.c (revision 7c3aabc0)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:     ReactOS Console Utilities Library
34e697feeSHermès Bélusca-Maïto  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4c2c66affSColin Finck  * PURPOSE:     Base set of functions for loading string resources
5c2c66affSColin Finck  *              and message strings, and handle type identification.
6*7c3aabc0SHermès Bélusca-Maïto  * COPYRIGHT:   Copyright 2017-2021 ReactOS Team
7*7c3aabc0SHermès Bélusca-Maïto  *              Copyright 2017-2021 Hermes Belusca-Maito
8c2c66affSColin Finck  */
9c2c66affSColin Finck 
10f982d77bSHermès Bélusca-Maïto /**
11f982d77bSHermès Bélusca-Maïto  * @file    utils.c
12f982d77bSHermès Bélusca-Maïto  * @ingroup ConUtils
13f982d77bSHermès Bélusca-Maïto  *
14f982d77bSHermès Bélusca-Maïto  * @brief   General-purpose utility functions (wrappers around
15f982d77bSHermès Bélusca-Maïto  *          or reimplementations of Win32 APIs).
16f982d77bSHermès Bélusca-Maïto  **/
17f982d77bSHermès Bélusca-Maïto 
18c2c66affSColin Finck /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
19c2c66affSColin Finck #define UNICODE
20c2c66affSColin Finck #define _UNICODE
21c2c66affSColin Finck 
22c2c66affSColin Finck #include <windef.h>
23c2c66affSColin Finck #include <winbase.h>
24c2c66affSColin Finck #include <winnls.h>
25c2c66affSColin Finck #include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
26c2c66affSColin Finck #include <wincon.h>  // Console APIs (only if kernel32 support included)
27c2c66affSColin Finck #include <strsafe.h>
28c2c66affSColin Finck 
29c2c66affSColin Finck /* PSEH for SEH Support */
30c2c66affSColin Finck #include <pseh/pseh2.h>
31c2c66affSColin Finck 
32c2c66affSColin Finck // #include "conutils.h"
33c2c66affSColin Finck #include "utils.h"
34c2c66affSColin Finck 
35c2c66affSColin Finck #if 0 // The following function may be useful in the future...
36c2c66affSColin Finck 
37c2c66affSColin Finck // Performs MultiByteToWideChar then WideCharToMultiByte .
38c2c66affSColin Finck // See https://github.com/pcman-bbs/pcman-windows/blob/master/Lite/StrUtils.h#l33
39c2c66affSColin Finck // and http://www.openfoundry.org/svn/pcman/branches/OpenPCMan_2009/Lite/StrUtils.cpp
40c2c66affSColin Finck // for the idea.
41c2c66affSColin Finck int
42c2c66affSColin Finck MultiByteToMultiByte(
43c2c66affSColin Finck     // IN WORD wTranslations,
44c2c66affSColin Finck     IN DWORD dwFlags,
45c2c66affSColin Finck     IN UINT SrcCodePage,
46c2c66affSColin Finck     IN LPCSTR lpSrcString,
47c2c66affSColin Finck     IN int cbSrcChar,
48c2c66affSColin Finck     IN UINT DestCodePage,
49c2c66affSColin Finck     OUT LPSTR wDestString OPTIONAL,
50c2c66affSColin Finck     IN int cbDestChar
51c2c66affSColin Finck );
52c2c66affSColin Finck 
53c2c66affSColin Finck #endif
54c2c66affSColin Finck 
55ce044cf8SHermès Bélusca-Maïto /**
56ce044cf8SHermès Bélusca-Maïto  * @name K32LoadStringExW
57ce044cf8SHermès Bélusca-Maïto  *     Loads a string resource from the executable file associated with a
58ce044cf8SHermès Bélusca-Maïto  *     specified module, copies the string into a buffer, and appends a
59ce044cf8SHermès Bélusca-Maïto  *     terminating null character.
60ce044cf8SHermès Bélusca-Maïto  *     This is basically the LoadString() API ripped from user32.dll to
61ce044cf8SHermès Bélusca-Maïto  *     remove any dependency of ConUtils from user32.dll, and to add support
62ce044cf8SHermès Bélusca-Maïto  *     for loading strings from other languages than the current one.
63ce044cf8SHermès Bélusca-Maïto  *
64ce044cf8SHermès Bélusca-Maïto  * @param[in]   hInstance
65ce044cf8SHermès Bélusca-Maïto  *     Optional handle to an instance of the module whose executable file
66ce044cf8SHermès Bélusca-Maïto  *     contains the string resource. Can be set to NULL to get the handle
67ce044cf8SHermès Bélusca-Maïto  *     to the application itself.
68ce044cf8SHermès Bélusca-Maïto  *
69ce044cf8SHermès Bélusca-Maïto  * @param[in]   uID
70ce044cf8SHermès Bélusca-Maïto  *     The identifier of the string to be loaded.
71ce044cf8SHermès Bélusca-Maïto  *
72ce044cf8SHermès Bélusca-Maïto  * @param[in]   LanguageId
73ce044cf8SHermès Bélusca-Maïto  *     The language identifier of the resource. If this parameter is
74ce044cf8SHermès Bélusca-Maïto  *     <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
75ce044cf8SHermès Bélusca-Maïto  *     associated with the calling thread is used. To specify a language other
76ce044cf8SHermès Bélusca-Maïto  *     than the current language, use the @c MAKELANGID macro to create this
77ce044cf8SHermès Bélusca-Maïto  *     parameter.
78ce044cf8SHermès Bélusca-Maïto  *
79ce044cf8SHermès Bélusca-Maïto  * @param[out]  lpBuffer
80ce044cf8SHermès Bélusca-Maïto  *     The buffer that receives the string. Must be of sufficient length
81ce044cf8SHermès Bélusca-Maïto  *     to hold a pointer (8 bytes).
82ce044cf8SHermès Bélusca-Maïto  *
83ce044cf8SHermès Bélusca-Maïto  * @param[in]   nBufferMax
84ce044cf8SHermès Bélusca-Maïto  *     The size of the buffer, in characters. The string is truncated and
85ce044cf8SHermès Bélusca-Maïto  *     NULL-terminated if it is longer than the number of characters specified.
86ce044cf8SHermès Bélusca-Maïto  *     If this parameter is 0, then @p lpBuffer receives a read-only pointer
87ce044cf8SHermès Bélusca-Maïto  *     to the resource itself.
88ce044cf8SHermès Bélusca-Maïto  *
89ce044cf8SHermès Bélusca-Maïto  * @return
90ce044cf8SHermès Bélusca-Maïto  *     If the function succeeds, the return value is the number of characters
91ce044cf8SHermès Bélusca-Maïto  *     copied into the buffer, not including the terminating null character,
92ce044cf8SHermès Bélusca-Maïto  *     or zero if the string resource does not exist. To get extended error
93ce044cf8SHermès Bélusca-Maïto  *     information, call GetLastError().
94ce044cf8SHermès Bélusca-Maïto  *
95ce044cf8SHermès Bélusca-Maïto  * @see LoadString(), K32LoadStringW()
96ce044cf8SHermès Bélusca-Maïto  **/
97c2c66affSColin Finck INT
98c2c66affSColin Finck WINAPI
K32LoadStringExW(IN HINSTANCE hInstance OPTIONAL,IN UINT uID,IN LANGID LanguageId,OUT LPWSTR lpBuffer,IN INT nBufferMax)99f982d77bSHermès Bélusca-Maïto K32LoadStringExW(
100c2c66affSColin Finck     IN  HINSTANCE hInstance OPTIONAL,
101c2c66affSColin Finck     IN  UINT   uID,
102f982d77bSHermès Bélusca-Maïto     IN  LANGID LanguageId,
103c2c66affSColin Finck     OUT LPWSTR lpBuffer,
104c2c66affSColin Finck     IN  INT    nBufferMax)
105c2c66affSColin Finck {
106c2c66affSColin Finck     HRSRC hrsrc;
107c2c66affSColin Finck     HGLOBAL hmem;
108c2c66affSColin Finck     WCHAR *p;
109c2c66affSColin Finck     UINT i;
110c2c66affSColin Finck 
111c2c66affSColin Finck     if (!lpBuffer)
112c2c66affSColin Finck         return 0;
113c2c66affSColin Finck 
114c2c66affSColin Finck     /* Use LOWORD (incremented by 1) as ResourceID */
115c2c66affSColin Finck     /* There are always blocks of 16 strings */
116f982d77bSHermès Bélusca-Maïto     hrsrc = FindResourceExW(hInstance,
117f982d77bSHermès Bélusca-Maïto                             (LPCWSTR)RT_STRING,
118c2c66affSColin Finck                             MAKEINTRESOURCEW((LOWORD(uID) >> 4) + 1),
119f982d77bSHermès Bélusca-Maïto                             LanguageId);
120c2c66affSColin Finck     if (!hrsrc) return 0;
121c2c66affSColin Finck 
122c2c66affSColin Finck     hmem = LoadResource(hInstance, hrsrc);
123c2c66affSColin Finck     if (!hmem) return 0;
124c2c66affSColin Finck 
125c2c66affSColin Finck     p = LockResource(hmem);
126c2c66affSColin Finck     // FreeResource(hmem);
127c2c66affSColin Finck 
128c2c66affSColin Finck     /* Find the string we're looking for */
129c2c66affSColin Finck     uID &= 0x000F; /* Position in the block, same as % 16 */
130c2c66affSColin Finck     for (i = 0; i < uID; i++)
131c2c66affSColin Finck         p += *p + 1;
132c2c66affSColin Finck 
133c2c66affSColin Finck     /*
134c2c66affSColin Finck      * If nBufferMax == 0, then return a read-only pointer
135c2c66affSColin Finck      * to the resource itself in lpBuffer it is assumed that
136c2c66affSColin Finck      * lpBuffer is actually a (LPWSTR*).
137c2c66affSColin Finck      */
138c2c66affSColin Finck     if (nBufferMax == 0)
139c2c66affSColin Finck     {
140c2c66affSColin Finck         *((LPWSTR*)lpBuffer) = p + 1;
141c2c66affSColin Finck         return *p;
142c2c66affSColin Finck     }
143c2c66affSColin Finck 
144c2c66affSColin Finck     i = min(nBufferMax - 1, *p);
145c2c66affSColin Finck     if (i > 0)
146c2c66affSColin Finck     {
147c2c66affSColin Finck         memcpy(lpBuffer, p + 1, i * sizeof(WCHAR));
148c2c66affSColin Finck         lpBuffer[i] = L'\0';
149c2c66affSColin Finck     }
150c2c66affSColin Finck     else
151c2c66affSColin Finck     {
152c2c66affSColin Finck         if (nBufferMax > 1)
153c2c66affSColin Finck         {
154c2c66affSColin Finck             lpBuffer[0] = L'\0';
155c2c66affSColin Finck             return 0;
156c2c66affSColin Finck         }
157c2c66affSColin Finck     }
158c2c66affSColin Finck 
159c2c66affSColin Finck     return i;
160c2c66affSColin Finck }
161c2c66affSColin Finck 
162ce044cf8SHermès Bélusca-Maïto /**
163ce044cf8SHermès Bélusca-Maïto  * @name K32LoadStringW
164ce044cf8SHermès Bélusca-Maïto  *     Loads a string resource from the executable file associated with a
165ce044cf8SHermès Bélusca-Maïto  *     specified module, copies the string into a buffer, and appends a
166ce044cf8SHermès Bélusca-Maïto  *     terminating null character.
167ce044cf8SHermès Bélusca-Maïto  *     This is a restricted version of K32LoadStringExW().
168ce044cf8SHermès Bélusca-Maïto  *
169ce044cf8SHermès Bélusca-Maïto  * @see LoadString(), K32LoadStringExW()
170ce044cf8SHermès Bélusca-Maïto  **/
171f982d77bSHermès Bélusca-Maïto INT
172f982d77bSHermès Bélusca-Maïto WINAPI
K32LoadStringW(IN HINSTANCE hInstance OPTIONAL,IN UINT uID,OUT LPWSTR lpBuffer,IN INT nBufferMax)173f982d77bSHermès Bélusca-Maïto K32LoadStringW(
174f982d77bSHermès Bélusca-Maïto     IN  HINSTANCE hInstance OPTIONAL,
175f982d77bSHermès Bélusca-Maïto     IN  UINT   uID,
176f982d77bSHermès Bélusca-Maïto     OUT LPWSTR lpBuffer,
177f982d77bSHermès Bélusca-Maïto     IN  INT    nBufferMax)
178f982d77bSHermès Bélusca-Maïto {
179f982d77bSHermès Bélusca-Maïto     // NOTE: Instead of using LANG_NEUTRAL, one might use LANG_USER_DEFAULT...
180f982d77bSHermès Bélusca-Maïto     return K32LoadStringExW(hInstance, uID,
181f982d77bSHermès Bélusca-Maïto                             MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
182f982d77bSHermès Bélusca-Maïto                             lpBuffer, nBufferMax);
183f982d77bSHermès Bélusca-Maïto }
184f982d77bSHermès Bélusca-Maïto 
185ce044cf8SHermès Bélusca-Maïto /**
186ce044cf8SHermès Bélusca-Maïto  * @name FormatMessageSafeW
187ce044cf8SHermès Bélusca-Maïto  *     Loads and formats a message string. The function requires a message
188ce044cf8SHermès Bélusca-Maïto  *     definition as input. The message definition can come from a buffer
189ce044cf8SHermès Bélusca-Maïto  *     passed to the function. It can come from a message table resource in
190ce044cf8SHermès Bélusca-Maïto  *     an already-loaded module, or the caller can ask the function to search
191ce044cf8SHermès Bélusca-Maïto  *     the system's message table resource(s) for the message definition.
192ce044cf8SHermès Bélusca-Maïto  *     Please refer to the Win32 FormatMessage() function for more details.
193ce044cf8SHermès Bélusca-Maïto  *
194ce044cf8SHermès Bélusca-Maïto  * @param[in]   dwFlags
195ce044cf8SHermès Bélusca-Maïto  *     The formatting options, and how to interpret the @p lpSource parameter.
196ce044cf8SHermès Bélusca-Maïto  *     See FormatMessage() for more details.
197ce044cf8SHermès Bélusca-Maïto  *
198ce044cf8SHermès Bélusca-Maïto  * @param[in]   lpSource
199ce044cf8SHermès Bélusca-Maïto  *     The location of the message definition. The type of this parameter
200ce044cf8SHermès Bélusca-Maïto  *     depends upon the settings in the @p dwFlags parameter.
201ce044cf8SHermès Bélusca-Maïto  *
202ce044cf8SHermès Bélusca-Maïto  * @param[in]   dwMessageId
203ce044cf8SHermès Bélusca-Maïto  *     The message identifier for the requested message. This parameter
204ce044cf8SHermès Bélusca-Maïto  *     is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
205ce044cf8SHermès Bélusca-Maïto  *
206ce044cf8SHermès Bélusca-Maïto  * @param[in]   dwLanguageId
207ce044cf8SHermès Bélusca-Maïto  *     The language identifier for the requested message. This parameter
208ce044cf8SHermès Bélusca-Maïto  *     is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
209ce044cf8SHermès Bélusca-Maïto  *
210ce044cf8SHermès Bélusca-Maïto  * @param[out]  lpBuffer
211ce044cf8SHermès Bélusca-Maïto  *     A pointer to a buffer that receives the null-terminated string that
212ce044cf8SHermès Bélusca-Maïto  *     specifies the formatted message. If @p dwFlags includes
213ce044cf8SHermès Bélusca-Maïto  *     @b FORMAT_MESSAGE_ALLOCATE_BUFFER, the function allocates a buffer
214ce044cf8SHermès Bélusca-Maïto  *     using the LocalAlloc() function, and places the pointer to the buffer
215ce044cf8SHermès Bélusca-Maïto  *     at the address specified in @p lpBuffer.
216ce044cf8SHermès Bélusca-Maïto  *     This buffer cannot be larger than 64kB.
217ce044cf8SHermès Bélusca-Maïto  *
218ce044cf8SHermès Bélusca-Maïto  * @param[in]   nSize
219ce044cf8SHermès Bélusca-Maïto  *     If the @b FORMAT_MESSAGE_ALLOCATE_BUFFER flag is not set, this parameter
220ce044cf8SHermès Bélusca-Maïto  *     specifies the size of the output buffer, in @b TCHARs.
221ce044cf8SHermès Bélusca-Maïto  *     If @b FORMAT_MESSAGE_ALLOCATE_BUFFER is set, this parameter specifies
222ce044cf8SHermès Bélusca-Maïto  *     the minimum number of @b TCHARs to allocate for an output buffer.
223ce044cf8SHermès Bélusca-Maïto  *     The output buffer cannot be larger than 64kB.
224ce044cf8SHermès Bélusca-Maïto  *
225ce044cf8SHermès Bélusca-Maïto  * @param[in]   Arguments
226ce044cf8SHermès Bélusca-Maïto  *     Optional pointer to an array of values describing a variable number of
227ce044cf8SHermès Bélusca-Maïto  *     arguments, depending on the message string. Each argument is used to
228ce044cf8SHermès Bélusca-Maïto  *     replace an <em>insert sequence</em> in the message string.
229ce044cf8SHermès Bélusca-Maïto  *     By default, the @p Arguments parameter is of type @c va_list*, initialized
230ce044cf8SHermès Bélusca-Maïto  *     with va_start(). The state of the @c va_list argument is undefined upon
231ce044cf8SHermès Bélusca-Maïto  *     return from the function. To use the @c va_list again, destroy the variable
232ce044cf8SHermès Bélusca-Maïto  *     argument list pointer using va_end() and reinitialize it with va_start().
233ce044cf8SHermès Bélusca-Maïto  *     If you do not have a pointer of type @c va_list*, then specify the
234ce044cf8SHermès Bélusca-Maïto  *     @b FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
235ce044cf8SHermès Bélusca-Maïto  *     of @c DWORD_PTR values; those values are input to the message formatted
236ce044cf8SHermès Bélusca-Maïto  *     as the insert values. Each insert must have a corresponding element in
237ce044cf8SHermès Bélusca-Maïto  *     the array.
238ce044cf8SHermès Bélusca-Maïto  *
239ce044cf8SHermès Bélusca-Maïto  * @return
240ce044cf8SHermès Bélusca-Maïto  *     If the function succeeds, the return value is the number of characters
241ce044cf8SHermès Bélusca-Maïto  *     copied into the buffer, not including the terminating null character,
242ce044cf8SHermès Bélusca-Maïto  *     or zero if the string resource does not exist. To get extended error
243ce044cf8SHermès Bélusca-Maïto  *     information, call GetLastError().
244ce044cf8SHermès Bélusca-Maïto  *
245ce044cf8SHermès Bélusca-Maïto  * @remark
246ce044cf8SHermès Bélusca-Maïto  *     This function is a "safe" version of FormatMessage(), that does not
247ce044cf8SHermès Bélusca-Maïto  *     crash if a malformed source string is retrieved and then being used
248ce044cf8SHermès Bélusca-Maïto  *     for formatting. It basically wraps calls to FormatMessage() within SEH.
249ce044cf8SHermès Bélusca-Maïto  *
250f268430cSHermès Bélusca-Maïto  * @see <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage">FormatMessage() (on MSDN)</a>
251ce044cf8SHermès Bélusca-Maïto  **/
252c2c66affSColin Finck DWORD
253c2c66affSColin Finck WINAPI
FormatMessageSafeW(IN DWORD dwFlags,IN LPCVOID lpSource OPTIONAL,IN DWORD dwMessageId,IN DWORD dwLanguageId,OUT LPWSTR lpBuffer,IN DWORD nSize,IN va_list * Arguments OPTIONAL)254c2c66affSColin Finck FormatMessageSafeW(
255c2c66affSColin Finck     IN  DWORD   dwFlags,
256c2c66affSColin Finck     IN  LPCVOID lpSource OPTIONAL,
257c2c66affSColin Finck     IN  DWORD   dwMessageId,
258c2c66affSColin Finck     IN  DWORD   dwLanguageId,
259c2c66affSColin Finck     OUT LPWSTR  lpBuffer,
260c2c66affSColin Finck     IN  DWORD   nSize,
261c2c66affSColin Finck     IN  va_list *Arguments OPTIONAL)
262c2c66affSColin Finck {
263c2c66affSColin Finck     DWORD dwLength = 0;
264c2c66affSColin Finck 
265c2c66affSColin Finck     _SEH2_TRY
266c2c66affSColin Finck     {
267c2c66affSColin Finck         /*
268c2c66affSColin Finck          * Retrieve the message string. Wrap in SEH
269c2c66affSColin Finck          * to protect from invalid string parameters.
270c2c66affSColin Finck          */
271c2c66affSColin Finck         _SEH2_TRY
272c2c66affSColin Finck         {
273c2c66affSColin Finck             dwLength = FormatMessageW(dwFlags,
274c2c66affSColin Finck                                       lpSource,
275c2c66affSColin Finck                                       dwMessageId,
276c2c66affSColin Finck                                       dwLanguageId,
277c2c66affSColin Finck                                       lpBuffer,
278c2c66affSColin Finck                                       nSize,
279c2c66affSColin Finck                                       Arguments);
280c2c66affSColin Finck         }
281c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
282c2c66affSColin Finck         {
283c2c66affSColin Finck             dwLength = 0;
284c2c66affSColin Finck 
285c2c66affSColin Finck             /*
286c2c66affSColin Finck              * An exception occurred while calling FormatMessage, this is usually
287c2c66affSColin Finck              * the sign that a parameter was invalid, either 'lpBuffer' was NULL
288c2c66affSColin Finck              * but we did not pass the flag FORMAT_MESSAGE_ALLOCATE_BUFFER, or the
289c2c66affSColin Finck              * array pointer 'Arguments' was NULL or did not contain enough elements,
290c2c66affSColin Finck              * and we did not pass the flag FORMAT_MESSAGE_IGNORE_INSERTS, and the
291c2c66affSColin Finck              * message string expected too many inserts.
292c2c66affSColin Finck              * In this last case only, we can call again FormatMessage but ignore
293f268430cSHermès Bélusca-Maïto              * explicitly the inserts. The string that we will return to the user
294c2c66affSColin Finck              * will not be pre-formatted.
295c2c66affSColin Finck              */
296c2c66affSColin Finck             if (((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) || lpBuffer) &&
297c2c66affSColin Finck                 !(dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS))
298c2c66affSColin Finck             {
299c2c66affSColin Finck                 /* Remove any possible harmful flags and always ignore inserts */
300c2c66affSColin Finck                 dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
301c2c66affSColin Finck                 dwFlags |=  FORMAT_MESSAGE_IGNORE_INSERTS;
302c2c66affSColin Finck 
303c2c66affSColin Finck                 /* If this call also throws an exception, we are really dead */
304c2c66affSColin Finck                 dwLength = FormatMessageW(dwFlags,
305c2c66affSColin Finck                                           lpSource,
306c2c66affSColin Finck                                           dwMessageId,
307c2c66affSColin Finck                                           dwLanguageId,
308c2c66affSColin Finck                                           lpBuffer,
309c2c66affSColin Finck                                           nSize,
310c2c66affSColin Finck                                           NULL /* Arguments */);
311c2c66affSColin Finck             }
312c2c66affSColin Finck         }
313c2c66affSColin Finck         _SEH2_END;
314c2c66affSColin Finck     }
315c2c66affSColin Finck     _SEH2_FINALLY
316c2c66affSColin Finck     {
317c2c66affSColin Finck     }
318c2c66affSColin Finck     _SEH2_END;
319c2c66affSColin Finck 
320c2c66affSColin Finck     return dwLength;
321c2c66affSColin Finck }
322c2c66affSColin Finck 
323f982d77bSHermès Bélusca-Maïto /**
324*7c3aabc0SHermès Bélusca-Maïto  * @name ConSetThreadUILanguage
325*7c3aabc0SHermès Bélusca-Maïto  *     Sets the current thread's user interface language.
326*7c3aabc0SHermès Bélusca-Maïto  *     Mostly used by console applications for selecting a
327*7c3aabc0SHermès Bélusca-Maïto  *     language identifier that best supports the NT Console.
328*7c3aabc0SHermès Bélusca-Maïto  *     This function dynamically loads and calls kernel32!SetThreadUILanguage()
329*7c3aabc0SHermès Bélusca-Maïto  *     so as to be able to work on older environments where this
330*7c3aabc0SHermès Bélusca-Maïto  *     API is not supported.
331*7c3aabc0SHermès Bélusca-Maïto  *     The FormatMessage() API also bases itself on the thread's
332*7c3aabc0SHermès Bélusca-Maïto  *     current language for its default behaviour (unless an explicit
333*7c3aabc0SHermès Bélusca-Maïto  *     language identifier has been provided).
334*7c3aabc0SHermès Bélusca-Maïto  *
335*7c3aabc0SHermès Bélusca-Maïto  * @param[in,opt]   LangId
336*7c3aabc0SHermès Bélusca-Maïto  *     (Vista+) A non-zero language identifier that specifies the
337*7c3aabc0SHermès Bélusca-Maïto  *     current thread's user interface language to set.
338*7c3aabc0SHermès Bélusca-Maïto  *     (XP/2003) Set the language identifier to 0 for selecting a
339*7c3aabc0SHermès Bélusca-Maïto  *     language identifier that best supports the NT Console.
340*7c3aabc0SHermès Bélusca-Maïto  *
341*7c3aabc0SHermès Bélusca-Maïto  * @return
342*7c3aabc0SHermès Bélusca-Maïto  *     Returns LangId in case of success, or 0 in case of failure.
343*7c3aabc0SHermès Bélusca-Maïto  *     If LangId was set to 0, the function always succeeds and returns
344*7c3aabc0SHermès Bélusca-Maïto  *     the language identifier that best supports the NT Console.
345*7c3aabc0SHermès Bélusca-Maïto  *
346*7c3aabc0SHermès Bélusca-Maïto  * @remark
347*7c3aabc0SHermès Bélusca-Maïto  *     This function is thread-safe.
348*7c3aabc0SHermès Bélusca-Maïto  *
349*7c3aabc0SHermès Bélusca-Maïto  * @see <a href="https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-setthreaduilanguage">SetThreadUILanguage() (on MSDN)</a>
350*7c3aabc0SHermès Bélusca-Maïto  **/
351*7c3aabc0SHermès Bélusca-Maïto LANGID
ConSetThreadUILanguage(IN LANGID LangId OPTIONAL)352*7c3aabc0SHermès Bélusca-Maïto ConSetThreadUILanguage(
353*7c3aabc0SHermès Bélusca-Maïto     IN LANGID LangId OPTIONAL)
354*7c3aabc0SHermès Bélusca-Maïto {
355*7c3aabc0SHermès Bélusca-Maïto     /* The function pointer is shared amongst all threads */
356*7c3aabc0SHermès Bélusca-Maïto     static volatile LANGID (WINAPI *pfnSetThreadUILanguage)(LANGID) = NULL;
357*7c3aabc0SHermès Bélusca-Maïto 
358*7c3aabc0SHermès Bélusca-Maïto     if (!pfnSetThreadUILanguage)
359*7c3aabc0SHermès Bélusca-Maïto     {
360*7c3aabc0SHermès Bélusca-Maïto         /* Load the API from kernel32 */
361*7c3aabc0SHermès Bélusca-Maïto         PVOID pFunc = (PVOID)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetThreadUILanguage");
362*7c3aabc0SHermès Bélusca-Maïto         if (!pFunc)
363*7c3aabc0SHermès Bélusca-Maïto         {
364*7c3aabc0SHermès Bélusca-Maïto             /* Fail since the API is not available */
365*7c3aabc0SHermès Bélusca-Maïto             return 0;
366*7c3aabc0SHermès Bélusca-Maïto         }
367*7c3aabc0SHermès Bélusca-Maïto         /* Set the function pointer in case it hasn't been already set by another thread */
368*7c3aabc0SHermès Bélusca-Maïto         InterlockedCompareExchangePointer((PVOID*)&pfnSetThreadUILanguage, pFunc, NULL);
369*7c3aabc0SHermès Bélusca-Maïto         // ASSERT(pfnSetThreadUILanguage);
370*7c3aabc0SHermès Bélusca-Maïto     }
371*7c3aabc0SHermès Bélusca-Maïto     return pfnSetThreadUILanguage(LangId);
372*7c3aabc0SHermès Bélusca-Maïto }
373*7c3aabc0SHermès Bélusca-Maïto 
374*7c3aabc0SHermès Bélusca-Maïto /**
375f982d77bSHermès Bélusca-Maïto  * @name IsTTYHandle
376f982d77bSHermès Bélusca-Maïto  *     Checks whether a handle refers to a valid TTY object.
377f982d77bSHermès Bélusca-Maïto  *     A TTY object may be a console or a "communications" (e.g. serial) port.
378f982d77bSHermès Bélusca-Maïto  *
379f982d77bSHermès Bélusca-Maïto  * @param[in]   hHandle
380f982d77bSHermès Bélusca-Maïto  *     Handle to the TTY object to check for.
381f982d77bSHermès Bélusca-Maïto  *
382f982d77bSHermès Bélusca-Maïto  * @return
383ce044cf8SHermès Bélusca-Maïto  *     @b TRUE when the handle refers to a valid TTY object,
384ce044cf8SHermès Bélusca-Maïto  *     @b FALSE if it does not.
385f982d77bSHermès Bélusca-Maïto  *
386f982d77bSHermès Bélusca-Maïto  * @remark
387f982d77bSHermès Bélusca-Maïto  *     This test is more general than IsConsoleHandle() as it is not limited
388f982d77bSHermès Bélusca-Maïto  *     to Win32 console objects only.
389f982d77bSHermès Bélusca-Maïto  *
390f982d77bSHermès Bélusca-Maïto  * @see IsConsoleHandle()
391f982d77bSHermès Bélusca-Maïto  **/
392c2c66affSColin Finck BOOL
IsTTYHandle(IN HANDLE hHandle)393c2c66affSColin Finck IsTTYHandle(IN HANDLE hHandle)
394c2c66affSColin Finck {
395c2c66affSColin Finck     /*
396f982d77bSHermès Bélusca-Maïto      * More general test than IsConsoleHandle(). Consoles, as well as serial
397f982d77bSHermès Bélusca-Maïto      * (communications) ports, etc... verify this test, but only consoles
398f982d77bSHermès Bélusca-Maïto      * verify the IsConsoleHandle() test: indeed the latter checks whether
399c2c66affSColin Finck      * the handle is really handled by the console subsystem.
400c2c66affSColin Finck      */
401c2c66affSColin Finck     return ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) == FILE_TYPE_CHAR);
402c2c66affSColin Finck }
403c2c66affSColin Finck 
404f982d77bSHermès Bélusca-Maïto /**
405f982d77bSHermès Bélusca-Maïto  * @name IsConsoleHandle
406f982d77bSHermès Bélusca-Maïto  *     Checks whether a handle refers to a valid Win32 console object.
407f982d77bSHermès Bélusca-Maïto  *
408f982d77bSHermès Bélusca-Maïto  * @param[in]   hHandle
409f982d77bSHermès Bélusca-Maïto  *     Handle to the Win32 console object to check for:
410f982d77bSHermès Bélusca-Maïto  *     console input buffer, console output buffer.
411f982d77bSHermès Bélusca-Maïto  *
412f982d77bSHermès Bélusca-Maïto  * @return
413ce044cf8SHermès Bélusca-Maïto  *     @b TRUE when the handle refers to a valid Win32 console object,
414ce044cf8SHermès Bélusca-Maïto  *     @b FALSE if it does not.
415f982d77bSHermès Bélusca-Maïto  *
416f982d77bSHermès Bélusca-Maïto  * @see IsTTYHandle()
417f982d77bSHermès Bélusca-Maïto  **/
418c2c66affSColin Finck BOOL
IsConsoleHandle(IN HANDLE hHandle)419c2c66affSColin Finck IsConsoleHandle(IN HANDLE hHandle)
420c2c66affSColin Finck {
421c2c66affSColin Finck     DWORD dwMode;
422c2c66affSColin Finck 
423c2c66affSColin Finck     /* Check whether the handle may be that of a console... */
424c2c66affSColin Finck     if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
425c2c66affSColin Finck         return FALSE;
426c2c66affSColin Finck 
427c2c66affSColin Finck     /*
428c2c66affSColin Finck      * It may be. Perform another test. The idea comes from the
429c2c66affSColin Finck      * MSDN description of the WriteConsole API:
430c2c66affSColin Finck      *
431c2c66affSColin Finck      * "WriteConsole fails if it is used with a standard handle
432c2c66affSColin Finck      *  that is redirected to a file. If an application processes
433c2c66affSColin Finck      *  multilingual output that can be redirected, determine whether
434c2c66affSColin Finck      *  the output handle is a console handle (one method is to call
435c2c66affSColin Finck      *  the GetConsoleMode function and check whether it succeeds).
436c2c66affSColin Finck      *  If the handle is a console handle, call WriteConsole. If the
437c2c66affSColin Finck      *  handle is not a console handle, the output is redirected and
438c2c66affSColin Finck      *  you should call WriteFile to perform the I/O."
439c2c66affSColin Finck      */
440c2c66affSColin Finck     return GetConsoleMode(hHandle, &dwMode);
441c2c66affSColin Finck }
4424e697feeSHermès Bélusca-Maïto 
4434e697feeSHermès Bélusca-Maïto /* EOF */
444