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
14 * @brief General-purpose utility functions (wrappers around
15 * or reimplementations of Win32 APIs).
18 /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
25 #include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
26 #include <wincon.h> // Console APIs (only if kernel32 support included)
29 /* PSEH for SEH Support */
30 #include <pseh/pseh2.h>
32 // #include "conutils.h"
35 #if 0 // The following function may be useful in the future...
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
43 // IN WORD wTranslations,
46 IN LPCSTR lpSrcString
,
49 OUT LPSTR wDestString OPTIONAL
,
56 * 'LoadStringW' API ripped from user32.dll to remove
57 * any dependency of this library from user32.dll
62 IN HINSTANCE hInstance OPTIONAL
,
76 /* Use LOWORD (incremented by 1) as ResourceID */
77 /* There are always blocks of 16 strings */
78 hrsrc
= FindResourceExW(hInstance
,
80 MAKEINTRESOURCEW((LOWORD(uID
) >> 4) + 1),
84 hmem
= LoadResource(hInstance
, hrsrc
);
87 p
= LockResource(hmem
);
88 // FreeResource(hmem);
90 /* Find the string we're looking for */
91 uID
&= 0x000F; /* Position in the block, same as % 16 */
92 for (i
= 0; i
< uID
; i
++)
96 * If nBufferMax == 0, then return a read-only pointer
97 * to the resource itself in lpBuffer it is assumed that
98 * lpBuffer is actually a (LPWSTR *).
102 *((LPWSTR
*)lpBuffer
) = p
+ 1;
106 i
= min(nBufferMax
- 1, *p
);
109 memcpy(lpBuffer
, p
+ 1, i
* sizeof(WCHAR
));
127 IN HINSTANCE hInstance OPTIONAL
,
132 // NOTE: Instead of using LANG_NEUTRAL, one might use LANG_USER_DEFAULT...
133 return K32LoadStringExW(hInstance
, uID
,
134 MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
),
135 lpBuffer
, nBufferMax
);
139 * "Safe" version of FormatMessageW, that does not crash if a malformed
140 * source string is retrieved and then being used for formatting.
141 * It basically wraps calls to FormatMessageW within SEH.
147 IN LPCVOID lpSource OPTIONAL
,
148 IN DWORD dwMessageId
,
149 IN DWORD dwLanguageId
,
152 IN
va_list *Arguments OPTIONAL
)
159 * Retrieve the message string. Wrap in SEH
160 * to protect from invalid string parameters.
164 dwLength
= FormatMessageW(dwFlags
,
172 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
177 * An exception occurred while calling FormatMessage, this is usually
178 * the sign that a parameter was invalid, either 'lpBuffer' was NULL
179 * but we did not pass the flag FORMAT_MESSAGE_ALLOCATE_BUFFER, or the
180 * array pointer 'Arguments' was NULL or did not contain enough elements,
181 * and we did not pass the flag FORMAT_MESSAGE_IGNORE_INSERTS, and the
182 * message string expected too many inserts.
183 * In this last case only, we can call again FormatMessage but ignore
184 * explicitely the inserts. The string that we will return to the user
185 * will not be pre-formatted.
187 if (((dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) || lpBuffer
) &&
188 !(dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
))
190 /* Remove any possible harmful flags and always ignore inserts */
191 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
192 dwFlags
|= FORMAT_MESSAGE_IGNORE_INSERTS
;
194 /* If this call also throws an exception, we are really dead */
195 dwLength
= FormatMessageW(dwFlags
,
201 NULL
/* Arguments */);
216 * Checks whether a handle refers to a valid TTY object.
217 * A TTY object may be a console or a "communications" (e.g. serial) port.
220 * Handle to the TTY object to check for.
223 * @b@c TRUE when the handle refers to a valid TTY object,
224 * @b@c FALSE if it does not.
227 * This test is more general than IsConsoleHandle() as it is not limited
228 * to Win32 console objects only.
230 * @see IsConsoleHandle()
233 IsTTYHandle(IN HANDLE hHandle
)
236 * More general test than IsConsoleHandle(). Consoles, as well as serial
237 * (communications) ports, etc... verify this test, but only consoles
238 * verify the IsConsoleHandle() test: indeed the latter checks whether
239 * the handle is really handled by the console subsystem.
241 return ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) == FILE_TYPE_CHAR
);
245 * @name IsConsoleHandle
246 * Checks whether a handle refers to a valid Win32 console object.
249 * Handle to the Win32 console object to check for:
250 * console input buffer, console output buffer.
253 * @b@c TRUE when the handle refers to a valid Win32 console object,
254 * @b@c FALSE if it does not.
259 IsConsoleHandle(IN HANDLE hHandle
)
263 /* Check whether the handle may be that of a console... */
264 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
268 * It may be. Perform another test. The idea comes from the
269 * MSDN description of the WriteConsole API:
271 * "WriteConsole fails if it is used with a standard handle
272 * that is redirected to a file. If an application processes
273 * multilingual output that can be redirected, determine whether
274 * the output handle is a console handle (one method is to call
275 * the GetConsoleMode function and check whether it succeeds).
276 * If the handle is a console handle, call WriteConsole. If the
277 * handle is not a console handle, the output is redirected and
278 * you should call WriteFile to perform the I/O."
280 return GetConsoleMode(hHandle
, &dwMode
);