ReactOS 0.4.15-dev-7907-g95bf896
utils.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Console Utilities Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Base set of functions for loading string resources
5 * and message strings, and handle type identification.
6 * COPYRIGHT: Copyright 2017-2021 ReactOS Team
7 * Copyright 2017-2021 Hermes Belusca-Maito
8 */
9
18/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
19#define UNICODE
20#define _UNICODE
21
22#include <windef.h>
23#include <winbase.h>
24#include <winnls.h>
25#include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
26#include <wincon.h> // Console APIs (only if kernel32 support included)
27#include <strsafe.h>
28
29/* PSEH for SEH Support */
30#include <pseh/pseh2.h>
31
32// #include "conutils.h"
33#include "utils.h"
34
35#if 0 // The following function may be useful in the future...
36
37// Performs MultiByteToWideChar then WideCharToMultiByte .
38// See https://github.com/pcman-bbs/pcman-windows/blob/master/Lite/StrUtils.h#l33
39// and http://www.openfoundry.org/svn/pcman/branches/OpenPCMan_2009/Lite/StrUtils.cpp
40// for the idea.
41int
42MultiByteToMultiByte(
43 // IN WORD wTranslations,
45 IN UINT SrcCodePage,
46 IN LPCSTR lpSrcString,
47 IN int cbSrcChar,
48 IN UINT DestCodePage,
49 OUT LPSTR wDestString OPTIONAL,
50 IN int cbDestChar
51);
52
53#endif
54
97INT
101 IN UINT uID,
102 IN LANGID LanguageId,
104 IN INT nBufferMax)
105{
106 HRSRC hrsrc;
107 HGLOBAL hmem;
108 WCHAR *p;
109 UINT i;
110
111 if (!lpBuffer)
112 return 0;
113
114 /* Use LOWORD (incremented by 1) as ResourceID */
115 /* There are always blocks of 16 strings */
118 MAKEINTRESOURCEW((LOWORD(uID) >> 4) + 1),
119 LanguageId);
120 if (!hrsrc) return 0;
121
122 hmem = LoadResource(hInstance, hrsrc);
123 if (!hmem) return 0;
124
125 p = LockResource(hmem);
126 // FreeResource(hmem);
127
128 /* Find the string we're looking for */
129 uID &= 0x000F; /* Position in the block, same as % 16 */
130 for (i = 0; i < uID; i++)
131 p += *p + 1;
132
133 /*
134 * If nBufferMax == 0, then return a read-only pointer
135 * to the resource itself in lpBuffer it is assumed that
136 * lpBuffer is actually a (LPWSTR*).
137 */
138 if (nBufferMax == 0)
139 {
140 *((LPWSTR*)lpBuffer) = p + 1;
141 return *p;
142 }
143
144 i = min(nBufferMax - 1, *p);
145 if (i > 0)
146 {
147 memcpy(lpBuffer, p + 1, i * sizeof(WCHAR));
148 lpBuffer[i] = L'\0';
149 }
150 else
151 {
152 if (nBufferMax > 1)
153 {
154 lpBuffer[0] = L'\0';
155 return 0;
156 }
157 }
158
159 return i;
160}
161
171INT
172WINAPI
175 IN UINT uID,
177 IN INT nBufferMax)
178{
179 // NOTE: Instead of using LANG_NEUTRAL, one might use LANG_USER_DEFAULT...
180 return K32LoadStringExW(hInstance, uID,
182 lpBuffer, nBufferMax);
183}
184
252DWORD
253WINAPI
256 IN LPCVOID lpSource OPTIONAL,
257 IN DWORD dwMessageId,
258 IN DWORD dwLanguageId,
260 IN DWORD nSize,
261 IN va_list *Arguments OPTIONAL)
262{
263 DWORD dwLength = 0;
264
266 {
267 /*
268 * Retrieve the message string. Wrap in SEH
269 * to protect from invalid string parameters.
270 */
272 {
274 lpSource,
275 dwMessageId,
276 dwLanguageId,
277 lpBuffer,
278 nSize,
279 Arguments);
280 }
282 {
283 dwLength = 0;
284
285 /*
286 * An exception occurred while calling FormatMessage, this is usually
287 * the sign that a parameter was invalid, either 'lpBuffer' was NULL
288 * but we did not pass the flag FORMAT_MESSAGE_ALLOCATE_BUFFER, or the
289 * array pointer 'Arguments' was NULL or did not contain enough elements,
290 * and we did not pass the flag FORMAT_MESSAGE_IGNORE_INSERTS, and the
291 * message string expected too many inserts.
292 * In this last case only, we can call again FormatMessage but ignore
293 * explicitly the inserts. The string that we will return to the user
294 * will not be pre-formatted.
295 */
298 {
299 /* Remove any possible harmful flags and always ignore inserts */
300 dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
302
303 /* If this call also throws an exception, we are really dead */
305 lpSource,
306 dwMessageId,
307 dwLanguageId,
308 lpBuffer,
309 nSize,
310 NULL /* Arguments */);
311 }
312 }
313 _SEH2_END;
314 }
316 {
317 }
318 _SEH2_END;
319
320 return dwLength;
321}
322
351LANGID
353 IN LANGID LangId OPTIONAL)
354{
355 /* The function pointer is shared amongst all threads */
356 static volatile LANGID (WINAPI *pfnSetThreadUILanguage)(LANGID) = NULL;
357
358 if (!pfnSetThreadUILanguage)
359 {
360 /* Load the API from kernel32 */
361 PVOID pFunc = (PVOID)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetThreadUILanguage");
362 if (!pFunc)
363 {
364 /* Fail since the API is not available */
365 return 0;
366 }
367 /* Set the function pointer in case it hasn't been already set by another thread */
368 InterlockedCompareExchangePointer((PVOID*)&pfnSetThreadUILanguage, pFunc, NULL);
369 // ASSERT(pfnSetThreadUILanguage);
370 }
371 return pfnSetThreadUILanguage(LangId);
372}
373
392BOOL
394{
395 /*
396 * More general test than IsConsoleHandle(). Consoles, as well as serial
397 * (communications) ports, etc... verify this test, but only consoles
398 * verify the IsConsoleHandle() test: indeed the latter checks whether
399 * the handle is really handled by the console subsystem.
400 */
401 return ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) == FILE_TYPE_CHAR);
402}
403
418BOOL
420{
421 DWORD dwMode;
422
423 /* Check whether the handle may be that of a console... */
424 if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
425 return FALSE;
426
427 /*
428 * It may be. Perform another test. The idea comes from the
429 * MSDN description of the WriteConsole API:
430 *
431 * "WriteConsole fails if it is used with a standard handle
432 * that is redirected to a file. If an application processes
433 * multilingual output that can be redirected, determine whether
434 * the output handle is a console handle (one method is to call
435 * the GetConsoleMode function and check whether it succeeds).
436 * If the handle is a console handle, call WriteConsole. If the
437 * handle is not a console handle, the output is redirected and
438 * you should call WriteFile to perform the I/O."
439 */
440 return GetConsoleMode(hHandle, &dwMode);
441}
442
443/* EOF */
char * va_list
Definition: acmsvcex.h:78
HINSTANCE hInstance
Definition: charmap.c:19
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:175
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define GetProcAddress(x, y)
Definition: compat.h:753
static DWORD DWORD * dwLength
Definition: fusion.c:86
BOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode)
Definition: console.c:1569
DWORD WINAPI GetFileType(HANDLE hFile)
Definition: fileinfo.c:269
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:838
LPVOID WINAPI LockResource(HGLOBAL handle)
Definition: res.c:550
HRSRC WINAPI FindResourceExW(HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang)
Definition: res.c:164
HGLOBAL WINAPI LoadResource(HINSTANCE hModule, HRSRC hRsrc)
Definition: res.c:532
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:583
#define _SEH2_FINALLY
Definition: filesup.c:21
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLfloat GLfloat p
Definition: glext.h:8902
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
USHORT LANGID
Definition: mui.h:9
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
#define L(x)
Definition: ntvdm.h:50
#define LOWORD(l)
Definition: pedump.c:82
#define RT_STRING
Definition: pedump.c:368
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define LANG_NEUTRAL
Definition: nls.h:22
#define MAKELANGID(p, s)
Definition: nls.h:15
#define SUBLANG_NEUTRAL
Definition: nls.h:167
#define IsConsoleHandle(h)
Definition: console.h:14
LANGID ConSetThreadUILanguage(IN LANGID LangId OPTIONAL)
Definition: utils.c:352
INT WINAPI K32LoadStringW(IN HINSTANCE hInstance OPTIONAL, IN UINT uID, OUT LPWSTR lpBuffer, IN INT nBufferMax)
Definition: utils.c:173
INT WINAPI K32LoadStringExW(IN HINSTANCE hInstance OPTIONAL, IN UINT uID, IN LANGID LanguageId, OUT LPWSTR lpBuffer, IN INT nBufferMax)
Definition: utils.c:99
BOOL IsTTYHandle(IN HANDLE hHandle)
Definition: utils.c:393
DWORD 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)
Definition: utils.c:254
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
void * PVOID
Definition: typedefs.h:50
int32_t INT
Definition: typedefs.h:58
#define IN
Definition: typedefs.h:39
#define OUT
Definition: typedefs.h:40
#define FORMAT_MESSAGE_IGNORE_INSERTS
Definition: winbase.h:420
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:419
#define FILE_TYPE_CHAR
Definition: winbase.h:260
#define FILE_TYPE_REMOTE
Definition: winbase.h:262
*nSize LPSTR _Inout_ LPDWORD nSize
Definition: winbase.h:2084
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176
CONST void * LPCVOID
Definition: windef.h:191
#define WINAPI
Definition: msvc.h:6
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
const char * LPCSTR
Definition: xmlstorage.h:183
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185