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-2018 ReactOS Team
7 * Copyright 2017-2018 Hermes Belusca-Maito
10 /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
17 #include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
18 #include <wincon.h> // Console APIs (only if kernel32 support included)
21 /* PSEH for SEH Support */
22 #include <pseh/pseh2.h>
24 // #include "conutils.h"
28 * General-purpose utility functions (wrappers around,
29 * or reimplementations of, Win32 APIs).
32 #if 0 // The following function may be useful in the future...
34 // Performs MultiByteToWideChar then WideCharToMultiByte .
35 // See https://github.com/pcman-bbs/pcman-windows/blob/master/Lite/StrUtils.h#l33
36 // and http://www.openfoundry.org/svn/pcman/branches/OpenPCMan_2009/Lite/StrUtils.cpp
40 // IN WORD wTranslations,
43 IN LPCSTR lpSrcString
,
46 OUT LPSTR wDestString OPTIONAL
,
53 * 'LoadStringW' API ripped from user32.dll to remove
54 * any dependency of this library from user32.dll
59 IN HINSTANCE hInstance OPTIONAL
,
72 /* Use LOWORD (incremented by 1) as ResourceID */
73 /* There are always blocks of 16 strings */
74 // FindResourceExW(hInstance, RT_STRING, name, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
75 // NOTE: Instead of using LANG_NEUTRAL, one might use LANG_USER_DEFAULT...
76 hrsrc
= FindResourceW(hInstance
,
77 MAKEINTRESOURCEW((LOWORD(uID
) >> 4) + 1),
81 hmem
= LoadResource(hInstance
, hrsrc
);
84 p
= LockResource(hmem
);
85 // FreeResource(hmem);
87 /* Find the string we're looking for */
88 uID
&= 0x000F; /* Position in the block, same as % 16 */
89 for (i
= 0; i
< uID
; i
++)
93 * If nBufferMax == 0, then return a read-only pointer
94 * to the resource itself in lpBuffer it is assumed that
95 * lpBuffer is actually a (LPWSTR *).
99 *((LPWSTR
*)lpBuffer
) = p
+ 1;
103 i
= min(nBufferMax
- 1, *p
);
106 memcpy(lpBuffer
, p
+ 1, i
* sizeof(WCHAR
));
122 * "Safe" version of FormatMessageW, that does not crash if a malformed
123 * source string is retrieved and then being used for formatting.
124 * It basically wraps calls to FormatMessageW within SEH.
130 IN LPCVOID lpSource OPTIONAL
,
131 IN DWORD dwMessageId
,
132 IN DWORD dwLanguageId
,
135 IN
va_list *Arguments OPTIONAL
)
142 * Retrieve the message string. Wrap in SEH
143 * to protect from invalid string parameters.
147 dwLength
= FormatMessageW(dwFlags
,
155 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
160 * An exception occurred while calling FormatMessage, this is usually
161 * the sign that a parameter was invalid, either 'lpBuffer' was NULL
162 * but we did not pass the flag FORMAT_MESSAGE_ALLOCATE_BUFFER, or the
163 * array pointer 'Arguments' was NULL or did not contain enough elements,
164 * and we did not pass the flag FORMAT_MESSAGE_IGNORE_INSERTS, and the
165 * message string expected too many inserts.
166 * In this last case only, we can call again FormatMessage but ignore
167 * explicitely the inserts. The string that we will return to the user
168 * will not be pre-formatted.
170 if (((dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) || lpBuffer
) &&
171 !(dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
))
173 /* Remove any possible harmful flags and always ignore inserts */
174 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
175 dwFlags
|= FORMAT_MESSAGE_IGNORE_INSERTS
;
177 /* If this call also throws an exception, we are really dead */
178 dwLength
= FormatMessageW(dwFlags
,
184 NULL
/* Arguments */);
198 IsTTYHandle(IN HANDLE hHandle
)
201 * More general test than IsConsoleHandle. Consoles, as well as
202 * serial ports, etc... verify this test, but only consoles verify
203 * the IsConsoleHandle test: indeed the latter checks whether
204 * the handle is really handled by the console subsystem.
206 return ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) == FILE_TYPE_CHAR
);
210 IsConsoleHandle(IN HANDLE hHandle
)
214 /* Check whether the handle may be that of a console... */
215 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
219 * It may be. Perform another test. The idea comes from the
220 * MSDN description of the WriteConsole API:
222 * "WriteConsole fails if it is used with a standard handle
223 * that is redirected to a file. If an application processes
224 * multilingual output that can be redirected, determine whether
225 * the output handle is a console handle (one method is to call
226 * the GetConsoleMode function and check whether it succeeds).
227 * If the handle is a console handle, call WriteConsole. If the
228 * handle is not a console handle, the output is redirected and
229 * you should call WriteFile to perform the I/O."
231 return GetConsoleMode(hHandle
, &dwMode
);