2 * PROJECT: ReactOS Console Utilities Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Provides basic abstraction wrappers around CRT streams or
5 * Win32 console API I/O functions, to deal with i18n + Unicode
7 * COPYRIGHT: Copyright 2017-2018 ReactOS Team
8 * Copyright 2017-2018 Hermes Belusca-Maito
15 * @brief Console I/O utility API -- Output
19 * Enable this define if you want to only use CRT functions to output
20 * UNICODE stream to the console, as in the way explained by
21 * http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
23 /** NOTE: Experimental! Don't use USE_CRT yet because output to console is a bit broken **/
26 /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
35 #include <stdlib.h> // limits.h // For MB_LEN_MAX
40 #include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
41 #include <wincon.h> // Console APIs (only if kernel32 support included)
44 /* PSEH for SEH Support */
45 #include <pseh/pseh2.h>
49 #include "stream_private.h"
52 // #define RC_STRING_MAX_SIZE 4096
53 #define CON_RC_STRING_MAX_SIZE 4096
54 // #define MAX_BUFFER_SIZE 4096 // Some programs (wlanconf, shutdown) set it to 5024
55 // #define OUTPUT_BUFFER_SIZE 4096 // Name given in cmd/console.c
56 // MAX_STRING_SIZE // Name given in diskpart
58 // #define MAX_MESSAGE_SIZE 512 // See shutdown...
63 * Writes a counted string to a stream.
66 * Stream to which the write operation is issued.
69 * Pointer to the counted string to write.
72 * Length of the string pointed by @p szStr, specified
73 * in number of characters.
76 * Numbers of characters successfully written to @p Stream.
79 * This function is used as an internal function.
80 * Use the ConStreamWrite() function instead.
83 * Should be called with the stream locked.
88 IN PCON_STREAM Stream
,
93 DWORD TotalLen
= len
, dwNumBytes
= 0;
96 // CHAR strOem[CON_RC_STRING_MAX_SIZE]; // Some static buffer...
98 /* If we do not write anything, just return */
99 if (!szStr
|| len
== 0)
102 /* Check whether we are writing to a console */
103 // if (IsConsoleHandle(Stream->hHandle))
104 if (Stream
->IsConsole
)
106 // TODO: Check if (ConStream->Mode == WideText or UTF16Text) ??
109 * This code is inspired from _cputws, in particular from the fact that,
110 * according to MSDN: https://msdn.microsoft.com/en-us/library/ms687401(v=vs.85).aspx
111 * the buffer size must be less than 64 KB.
113 * A similar code can be used for implementing _cputs too.
117 TotalLen
= len
, dwNumBytes
= 0;
121 cchWrite
= min(len
, 65535 / sizeof(WCHAR
));
123 // FIXME: Check return value!
124 WriteConsole(Stream
->hHandle
, szStr
, cchWrite
, &dwNumBytes
, NULL
);
130 return (INT
)TotalLen
; // FIXME: Really return the number of chars written!
134 * We are redirected and writing to a file or pipe instead of the console.
135 * Convert the string from TCHARs to the desired output format, if the two differ.
137 * Implementation NOTE:
138 * MultiByteToWideChar (resp. WideCharToMultiByte) are equivalent to
139 * OemToCharBuffW (resp. CharToOemBuffW), but the latters uselessly
140 * depend on user32.dll, while MultiByteToWideChar and WideCharToMultiByte
141 * only need kernel32.dll.
143 if ((Stream
->Mode
== WideText
) || (Stream
->Mode
== UTF16Text
))
145 #ifndef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
146 /* Convert from the current process/thread's codepage to UTF-16 */
147 WCHAR
*buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
150 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
153 len
= (DWORD
)MultiByteToWideChar(CP_THREAD_ACP
, // CP_ACP, CP_OEMCP
154 0, szStr
, (INT
)len
, buffer
, (INT
)len
);
155 szStr
= (PVOID
)buffer
;
158 * Do not perform any conversion since we are already in UTF-16,
159 * that is the same encoding as the stream.
164 * Find any newline character in the buffer,
165 * write the part BEFORE the newline, then write
166 * a carriage-return + newline, and then write
167 * the remaining part of the buffer.
169 * This fixes output in files and serial console.
173 /* Loop until we find a \r or \n character */
174 // FIXME: What about the pair \r\n ?
176 while (len
> 0 && *(PWCHAR
)p
!= L
'\r' && *(PWCHAR
)p
!= L
'\n')
178 /* Advance one character */
179 p
= (PVOID
)((PWCHAR
)p
+ 1);
183 /* Write everything up to \r or \n */
184 dwNumBytes
= ((PWCHAR
)p
- (PWCHAR
)szStr
) * sizeof(WCHAR
);
185 WriteFile(Stream
->hHandle
, szStr
, dwNumBytes
, &dwNumBytes
, NULL
);
187 /* If we hit \r or \n ... */
188 if (len
> 0 && (*(PWCHAR
)p
== L
'\r' || *(PWCHAR
)p
== L
'\n'))
190 /* ... send a carriage-return + newline sequence and skip \r or \n */
191 WriteFile(Stream
->hHandle
, L
"\r\n", 2 * sizeof(WCHAR
), &dwNumBytes
, NULL
);
192 szStr
= (PVOID
)((PWCHAR
)p
+ 1);
198 HeapFree(GetProcessHeap(), 0, buffer
);
201 else if ((Stream
->Mode
== UTF8Text
) || (Stream
->Mode
== AnsiText
))
206 * Resolve the codepage cache if it was not assigned yet
207 * (only if the stream is in ANSI mode; in UTF8 mode the
208 * codepage was already set to CP_UTF8).
210 if (/*(Stream->Mode == AnsiText) &&*/ (Stream
->CodePage
== INVALID_CP
))
211 Stream
->CodePage
= GetConsoleOutputCP(); // CP_ACP, CP_OEMCP
213 #ifdef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
214 /* Convert from UTF-16 to either UTF-8 or ANSI, using stream codepage */
215 // NOTE: MB_LEN_MAX defined either in limits.h or in stdlib.h .
216 buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* MB_LEN_MAX
);
219 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
222 len
= WideCharToMultiByte(Stream
->CodePage
, 0,
223 szStr
, len
, buffer
, len
* MB_LEN_MAX
,
225 szStr
= (PVOID
)buffer
;
228 * Convert from the current process/thread's codepage to either
229 * UTF-8 or ANSI, using stream codepage.
230 * We need to perform a double conversion, by going through UTF-16.
233 #error "Need to implement double conversion!"
237 * Find any newline character in the buffer,
238 * write the part BEFORE the newline, then write
239 * a carriage-return + newline, and then write
240 * the remaining part of the buffer.
242 * This fixes output in files and serial console.
246 /* Loop until we find a \r or \n character */
247 // FIXME: What about the pair \r\n ?
249 while (len
> 0 && *(PCHAR
)p
!= '\r' && *(PCHAR
)p
!= '\n')
251 /* Advance one character */
252 p
= (PVOID
)((PCHAR
)p
+ 1);
256 /* Write everything up to \r or \n */
257 dwNumBytes
= ((PCHAR
)p
- (PCHAR
)szStr
) * sizeof(CHAR
);
258 WriteFile(Stream
->hHandle
, szStr
, dwNumBytes
, &dwNumBytes
, NULL
);
260 /* If we hit \r or \n ... */
261 if (len
> 0 && (*(PCHAR
)p
== '\r' || *(PCHAR
)p
== '\n'))
263 /* ... send a carriage-return + newline sequence and skip \r or \n */
264 WriteFile(Stream
->hHandle
, "\r\n", 2, &dwNumBytes
, NULL
);
265 szStr
= (PVOID
)((PCHAR
)p
+ 1);
271 HeapFree(GetProcessHeap(), 0, buffer
);
276 else // if (Stream->Mode == Binary)
278 /* Directly output the string */
279 WriteFile(Stream
->hHandle
, szStr
, len
, &dwNumBytes
, NULL
);
283 return (INT
)TotalLen
;
285 #else /* defined(USE_CRT) */
290 /* If we do not write anything, just return */
291 if (!szStr
|| len
== 0)
296 * There is no "counted" printf-to-stream or puts-like function, therefore
297 * we use this trick to output the counted string to the stream.
301 written
= fwprintf(Stream
->fStream
, L
"%.*s", total
, szStr
);
305 * Some embedded NULL or special character
306 * was encountered, print it apart.
310 fputwc(*szStr
, Stream
->fStream
);
324 /* ANSI text or Binary output only */
325 _setmode(_fileno(Stream
->fStream
), _O_TEXT
); // _O_BINARY
326 return fwrite(szStr
, sizeof(*szStr
), len
, Stream
->fStream
);
329 #endif /* defined(USE_CRT) */
333 #define CON_STREAM_WRITE_CALL(Stream, Str, Len) \
334 (Stream)->WriteFunc((Stream), (Str), (Len));
336 /* Lock the stream only in non-USE_CRT mode (otherwise use the CRT stream lock) */
339 #define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
341 EnterCriticalSection(&(Stream)->Lock); \
342 (RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
343 LeaveCriticalSection(&(Stream)->Lock); \
346 #define CON_STREAM_WRITE(Stream, Str, Len) \
348 EnterCriticalSection(&(Stream)->Lock); \
349 CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
350 LeaveCriticalSection(&(Stream)->Lock); \
355 #define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
357 (RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
360 #define CON_STREAM_WRITE(Stream, Str, Len) \
362 CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
369 * @name ConStreamWrite
370 * Writes a counted string to a stream.
373 * Stream to which the write operation is issued.
376 * Pointer to the counted string to write.
379 * Length of the string pointed by @p szStr, specified
380 * in number of characters.
383 * Numbers of characters successfully written to @p Stream.
387 IN PCON_STREAM Stream
,
392 CON_STREAM_WRITE2(Stream
, szStr
, len
, Len
);
398 * Writes a NULL-terminated string to a stream.
401 * Stream to which the write operation is issued.
404 * Pointer to the NULL-terminated string to write.
407 * Numbers of characters successfully written to @p Stream.
410 * Contrary to the CRT puts() function, ConPuts() does not append
411 * a terminating new-line character. In this way it behaves more like
412 * the CRT fputs() function.
416 IN PCON_STREAM Stream
,
422 CON_STREAM_WRITE2(Stream
, szStr
, Len
, Len
);
424 /* Fixup returned length in case of errors */
433 * Formats and writes a NULL-terminated string to a stream.
436 * Stream to which the write operation is issued.
439 * Pointer to the NULL-terminated format string, that follows the same
440 * specifications as the @a szStr format string in ConPrintf().
443 * Parameter describing a variable number of arguments,
444 * initialized with va_start(), that can be expected by the function,
445 * depending on the @p szStr format string. Each argument is used to
446 * replace a <em>format specifier</em> in the format string.
449 * Numbers of characters successfully written to @p Stream.
451 * @see ConPrintf(), printf(), vprintf()
455 IN PCON_STREAM Stream
,
460 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
462 // Len = vfwprintf(Stream->fStream, szStr, args); // vfprintf for direct ANSI
465 * Reuse szStr as the pointer to end-of-string, to compute
466 * the string length instead of calling wcslen().
468 // StringCchVPrintfW(bufSrc, ARRAYSIZE(bufSrc), szStr, args);
469 // Len = wcslen(bufSrc);
470 StringCchVPrintfExW(bufSrc
, ARRAYSIZE(bufSrc
), &szStr
, NULL
, 0, szStr
, args
);
471 Len
= szStr
- bufSrc
;
473 CON_STREAM_WRITE2(Stream
, bufSrc
, Len
, Len
);
475 /* Fixup returned length in case of errors */
484 * Formats and writes a NULL-terminated string to a stream.
487 * Stream to which the write operation is issued.
490 * Pointer to the NULL-terminated format string, that follows the same
491 * specifications as the @a format string in printf(). This string can
492 * optionally contain embedded <em>format specifiers</em> that are
493 * replaced by the values specified in subsequent additional arguments
494 * and formatted as requested.
497 * Additional arguments that can be expected by the function, depending
498 * on the @p szStr format string. Each argument is used to replace a
499 * <em>format specifier</em> in the format string.
502 * Numbers of characters successfully written to @p Stream.
504 * @see ConPrintfV(), printf(), vprintf()
509 IN PCON_STREAM Stream
,
516 // Len = vfwprintf(Stream->fStream, szMsgBuf, args); // vfprintf for direct ANSI
519 va_start(args
, szStr
);
520 Len
= ConPrintfV(Stream
, szStr
, args
);
528 * Writes a string resource to a stream.
531 * Stream to which the write operation is issued.
533 * @param[in] hInstance
534 * Optional handle to an instance of the module whose executable file
535 * contains the string resource. Can be set to NULL to get the handle
536 * to the application itself.
539 * The identifier of the string to be written.
541 * @param[in] LanguageId
542 * The language identifier of the resource. If this parameter is
543 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
544 * associated with the calling thread is used. To specify a language other
545 * than the current language, use the @c MAKELANGID macro to create this
549 * Numbers of characters successfully written to @p Stream.
552 * Similarly to ConPuts(), no terminating new-line character is appended.
554 * @see ConPuts(), ConResPuts()
558 IN PCON_STREAM Stream
,
559 IN HINSTANCE hInstance OPTIONAL
,
561 IN LANGID LanguageId
)
566 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, (PWSTR
)&szStr
, 0);
568 // Len = ConPuts(Stream, szStr);
569 CON_STREAM_WRITE2(Stream
, szStr
, Len
, Len
);
571 /* Fixup returned length in case of errors */
580 * Writes a string resource contained in the current application
584 * Stream to which the write operation is issued.
587 * The identifier of the string to be written.
590 * Numbers of characters successfully written to @p Stream.
593 * Similarly to ConPuts(), no terminating new-line character is appended.
595 * @see ConPuts(), ConResPutsEx()
599 IN PCON_STREAM Stream
,
602 return ConResPutsEx(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
603 uID
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
));
607 * @name ConResPrintfExV
608 * Formats and writes a string resource to a stream.
611 * Stream to which the write operation is issued.
613 * @param[in] hInstance
614 * Optional handle to an instance of the module whose executable file
615 * contains the string resource. Can be set to NULL to get the handle
616 * to the application itself.
619 * The identifier of the format string. The format string follows the
620 * same specifications as the @a szStr format string in ConPrintf().
622 * @param[in] LanguageId
623 * The language identifier of the resource. If this parameter is
624 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
625 * associated with the calling thread is used. To specify a language other
626 * than the current language, use the @c MAKELANGID macro to create this
630 * Parameter describing a variable number of arguments,
631 * initialized with va_start(), that can be expected by the function,
632 * depending on the @p szStr format string. Each argument is used to
633 * replace a <em>format specifier</em> in the format string.
636 * Numbers of characters successfully written to @p Stream.
638 * @see ConPrintf(), ConResPrintfEx(), ConResPrintfV(), ConResPrintf()
642 IN PCON_STREAM Stream
,
643 IN HINSTANCE hInstance OPTIONAL
,
645 IN LANGID LanguageId
,
649 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
651 // NOTE: We may use the special behaviour where nBufMaxSize == 0
652 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, bufSrc
, ARRAYSIZE(bufSrc
));
654 Len
= ConPrintfV(Stream
, bufSrc
, args
);
660 * @name ConResPrintfV
661 * Formats and writes a string resource contained in the
662 * current application to a stream.
665 * Stream to which the write operation is issued.
668 * The identifier of the format string. The format string follows the
669 * same specifications as the @a szStr format string in ConPrintf().
672 * Parameter describing a variable number of arguments,
673 * initialized with va_start(), that can be expected by the function,
674 * depending on the @p szStr format string. Each argument is used to
675 * replace a <em>format specifier</em> in the format string.
678 * Numbers of characters successfully written to @p Stream.
680 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfEx(), ConResPrintf()
684 IN PCON_STREAM Stream
,
688 return ConResPrintfExV(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
689 uID
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
),
694 * @name ConResPrintfEx
695 * Formats and writes a string resource to a stream.
698 * Stream to which the write operation is issued.
700 * @param[in] hInstance
701 * Optional handle to an instance of the module whose executable file
702 * contains the string resource. Can be set to NULL to get the handle
703 * to the application itself.
706 * The identifier of the format string. The format string follows the
707 * same specifications as the @a szStr format string in ConPrintf().
709 * @param[in] LanguageId
710 * The language identifier of the resource. If this parameter is
711 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
712 * associated with the calling thread is used. To specify a language other
713 * than the current language, use the @c MAKELANGID macro to create this
717 * Additional arguments that can be expected by the function, depending
718 * on the @p szStr format string. Each argument is used to replace a
719 * <em>format specifier</em> in the format string.
722 * Numbers of characters successfully written to @p Stream.
724 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfV(), ConResPrintf()
729 IN PCON_STREAM Stream
,
730 IN HINSTANCE hInstance OPTIONAL
,
732 IN LANGID LanguageId
,
738 va_start(args
, LanguageId
);
739 Len
= ConResPrintfExV(Stream
, hInstance
, uID
, LanguageId
, args
);
747 * Formats and writes a string resource contained in the
748 * current application to a stream.
751 * Stream to which the write operation is issued.
754 * The identifier of the format string. The format string follows the
755 * same specifications as the @a szStr format string in ConPrintf().
758 * Additional arguments that can be expected by the function, depending
759 * on the @p szStr format string. Each argument is used to replace a
760 * <em>format specifier</em> in the format string.
763 * Numbers of characters successfully written to @p Stream.
765 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfEx(), ConResPrintfV()
770 IN PCON_STREAM Stream
,
778 Len
= ConResPrintfV(Stream
, uID
, args
);
786 * Writes a message string to a stream without formatting. The function
787 * requires a message definition as input. The message definition can come
788 * from a buffer passed to the function. It can come from a message table
789 * resource in an already-loaded module, or the caller can ask the function
790 * to search the system's message table resource(s) for the message definition.
791 * Please refer to the Win32 FormatMessage() function for more details.
794 * Stream to which the write operation is issued.
797 * The formatting options, and how to interpret the @p lpSource parameter.
798 * See FormatMessage() for more details. The @b@c FORMAT_MESSAGE_ALLOCATE_BUFFER
799 * and @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY flags are always ignored.
800 * The function implicitly uses the @b@c FORMAT_MESSAGE_IGNORE_INSERTS and
801 * @b@c FORMAT_MESSAGE_MAX_WIDTH_MASK flags to implement its behaviour.
803 * @param[in] lpSource
804 * The location of the message definition. The type of this parameter
805 * depends upon the settings in the @p dwFlags parameter.
807 * @param[in] dwMessageId
808 * The message identifier for the requested message. This parameter
809 * is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
811 * @param[in] dwLanguageId
812 * The language identifier for the requested message. This parameter
813 * is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
816 * Numbers of characters successfully written to @p Stream.
819 * Similarly to ConPuts(), no terminating new-line character is appended.
821 * @see ConPuts(), ConResPuts() and associated functions,
822 * <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
826 IN PCON_STREAM Stream
,
828 IN LPCVOID lpSource OPTIONAL
,
829 IN DWORD dwMessageId
,
830 IN DWORD dwLanguageId
)
834 LPWSTR lpMsgBuf
= NULL
;
837 * Sanitize dwFlags. This version always ignore explicitely the inserts
838 * as we emulate the behaviour of the (f)puts function.
840 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
841 dwFlags
|= FORMAT_MESSAGE_IGNORE_INSERTS
; // Ignore inserts for FormatMessage.
842 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
844 dwFlags
|= FORMAT_MESSAGE_MAX_WIDTH_MASK
;
847 * Retrieve the message string without appending extra newlines.
848 * Wrap in SEH to protect from invalid string parameters.
852 dwLength
= FormatMessageW(dwFlags
,
860 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
869 // ASSERT(dwLength == 0);
873 // ASSERT(dwLength != 0);
875 /* lpMsgBuf is NULL-terminated by FormatMessage */
876 // Len = ConPuts(Stream, lpMsgBuf);
877 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
879 /* Fixup returned length in case of errors */
883 /* Free the buffer allocated by FormatMessage */
891 * @name ConMsgPrintf2V
892 * Formats and writes a message string to a stream.
894 * @remark For internal use only.
896 * @see ConMsgPrintfV()
900 IN PCON_STREAM Stream
,
902 IN LPCVOID lpSource OPTIONAL
,
903 IN DWORD dwMessageId
,
904 IN DWORD dwLanguageId
,
909 LPWSTR lpMsgBuf
= NULL
;
912 * Sanitize dwFlags. This version always ignore explicitely the inserts.
913 * The string that we will return to the user will not be pre-formatted.
915 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
916 dwFlags
|= FORMAT_MESSAGE_IGNORE_INSERTS
; // Ignore inserts for FormatMessage.
917 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
919 dwFlags
|= FORMAT_MESSAGE_MAX_WIDTH_MASK
;
922 * Retrieve the message string without appending extra newlines.
923 * Wrap in SEH to protect from invalid string parameters.
927 dwLength
= FormatMessageW(dwFlags
,
935 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
944 // ASSERT(dwLength == 0);
948 // ASSERT(dwLength != 0);
950 /* lpMsgBuf is NULL-terminated by FormatMessage */
951 Len
= ConPrintfV(Stream
, lpMsgBuf
, args
);
952 // CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
954 /* Fixup returned length in case of errors */
958 /* Free the buffer allocated by FormatMessage */
966 * @name ConMsgPrintfV
967 * Formats and writes a message string to a stream. The function requires
968 * a message definition as input. The message definition can come from a
969 * buffer passed to the function. It can come from a message table resource
970 * in an already-loaded module, or the caller can ask the function to search
971 * the system's message table resource(s) for the message definition.
972 * Please refer to the Win32 FormatMessage() function for more details.
975 * Stream to which the write operation is issued.
978 * The formatting options, and how to interpret the @p lpSource parameter.
979 * See FormatMessage() for more details. The @b@c FORMAT_MESSAGE_ALLOCATE_BUFFER
980 * flags is always ignored. The function implicitly uses the
981 * @b@c FORMAT_MESSAGE_MAX_WIDTH_MASK flag to implement its behaviour.
983 * @param[in] lpSource
984 * The location of the message definition. The type of this parameter
985 * depends upon the settings in the @p dwFlags parameter.
987 * @param[in] dwMessageId
988 * The message identifier for the requested message. This parameter
989 * is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
991 * @param[in] dwLanguageId
992 * The language identifier for the requested message. This parameter
993 * is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
995 * @param[in] Arguments
996 * Optional pointer to an array of values describing a variable number of
997 * arguments, depending on the message string. Each argument is used to
998 * replace an <em>insert sequence</em> in the message string.
999 * By default, the @p Arguments parameter is of type @c va_list*, initialized
1000 * with va_start(). The state of the @c va_list argument is undefined upon
1001 * return from the function. To use the @c va_list again, destroy the variable
1002 * argument list pointer using va_end() and reinitialize it with va_start().
1003 * If you do not have a pointer of type @c va_list*, then specify the
1004 * @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
1005 * of @c DWORD_PTR values; those values are input to the message formatted
1006 * as the insert values. Each insert must have a corresponding element in
1010 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1011 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1012 * These sequences extend the standard <em>format specifiers</em> as they
1013 * allow to specify an <em>insert number</em> referring which precise value
1014 * given in arguments to use.
1017 * Numbers of characters successfully written to @p Stream.
1019 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1020 * <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
1024 IN PCON_STREAM Stream
,
1026 IN LPCVOID lpSource OPTIONAL
,
1027 IN DWORD dwMessageId
,
1028 IN DWORD dwLanguageId
,
1029 IN
va_list *Arguments OPTIONAL
)
1033 LPWSTR lpMsgBuf
= NULL
;
1035 /* Sanitize dwFlags */
1036 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
1038 // NOTE: Technique taken from eventvwr.c!GetMessageStringFromDll()
1040 dwFlags
|= FORMAT_MESSAGE_MAX_WIDTH_MASK
;
1043 * Retrieve the message string without appending extra newlines.
1044 * Use the "safe" FormatMessage version (SEH-protected) to protect
1045 * from invalid string parameters.
1047 dwLength
= FormatMessageSafeW(dwFlags
,
1055 Len
= (INT
)dwLength
;
1059 // ASSERT(dwLength == 0);
1063 // ASSERT(dwLength != 0);
1065 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
1067 /* Fixup returned length in case of errors */
1071 /* Free the buffer allocated by FormatMessage */
1072 LocalFree(lpMsgBuf
);
1079 * @name ConMsgPrintf
1080 * Formats and writes a message string to a stream. The function requires
1081 * a message definition as input. The message definition can come from a
1082 * buffer passed to the function. It can come from a message table resource
1083 * in an already-loaded module, or the caller can ask the function to search
1084 * the system's message table resource(s) for the message definition.
1085 * Please refer to the Win32 FormatMessage() function for more details.
1088 * Stream to which the write operation is issued.
1090 * @param[in] dwFlags
1091 * The formatting options, and how to interpret the @p lpSource parameter.
1092 * See FormatMessage() for more details. The @b@c FORMAT_MESSAGE_ALLOCATE_BUFFER
1093 * and @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY flags are always ignored.
1094 * The function implicitly uses the @b@c FORMAT_MESSAGE_MAX_WIDTH_MASK flag
1095 * to implement its behaviour.
1097 * @param[in] lpSource
1098 * The location of the message definition. The type of this parameter
1099 * depends upon the settings in the @p dwFlags parameter.
1101 * @param[in] dwMessageId
1102 * The message identifier for the requested message. This parameter
1103 * is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
1105 * @param[in] dwLanguageId
1106 * The language identifier for the requested message. This parameter
1107 * is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
1110 * Additional arguments that can be expected by the function, depending
1111 * on the message string. Each argument is used to replace an
1112 * <em>insert sequence</em> in the message string.
1115 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1116 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1117 * These sequences extend the standard <em>format specifiers</em> as they
1118 * allow to specify an <em>insert number</em> referring which precise value
1119 * given in arguments to use.
1122 * Numbers of characters successfully written to @p Stream.
1124 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintfV(),
1125 * <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
1130 IN PCON_STREAM Stream
,
1132 IN LPCVOID lpSource OPTIONAL
,
1133 IN DWORD dwMessageId
,
1134 IN DWORD dwLanguageId
,
1140 /* Sanitize dwFlags */
1141 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1143 va_start(args
, dwLanguageId
);
1144 Len
= ConMsgPrintfV(Stream
,
1156 * @name ConResMsgPrintfExV
1157 * Formats and writes a message string to a stream. The function requires
1158 * a message definition as input. Contrary to the ConMsg* or the Win32
1159 * FormatMessage() functions, the message definition comes from a resource
1160 * string table, much like the strings for ConResPrintf(), but is formatted
1161 * according to the rules of ConMsgPrintf().
1164 * Stream to which the write operation is issued.
1166 * @param[in] hInstance
1167 * Optional handle to an instance of the module whose executable file
1168 * contains the string resource. Can be set to NULL to get the handle
1169 * to the application itself.
1171 * @param[in] dwFlags
1172 * The formatting options, see FormatMessage() for more details.
1173 * The only valid flags are @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY and
1174 * @b@c FORMAT_MESSAGE_IGNORE_INSERTS. All the other flags are internally
1175 * overridden by the function to implement its behaviour.
1178 * The identifier of the message string. The format string follows the
1179 * same specifications as the @a lpSource format string in ConMsgPrintf().
1181 * @param[in] LanguageId
1182 * The language identifier of the resource. If this parameter is
1183 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
1184 * associated with the calling thread is used. To specify a language other
1185 * than the current language, use the @c MAKELANGID macro to create this
1189 * Parameter describing a variable number of arguments, initialized
1190 * with va_start(), that can be expected by the function, depending
1191 * on the message string. Each argument is used to replace an
1192 * <em>insert sequence</em> in the message string.
1195 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1196 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1197 * These sequences extend the standard <em>format specifiers</em> as they
1198 * allow to specify an <em>insert number</em> referring which precise value
1199 * given in arguments to use.
1202 * Numbers of characters successfully written to @p Stream.
1204 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1205 * <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
1209 IN PCON_STREAM Stream
,
1210 IN HINSTANCE hInstance OPTIONAL
,
1213 IN LANGID LanguageId
,
1214 IN
va_list *Arguments OPTIONAL
)
1218 LPWSTR lpMsgBuf
= NULL
;
1219 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
1221 /* Retrieve the string from the resource string table */
1222 // NOTE: We may use the special behaviour where nBufMaxSize == 0
1223 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, bufSrc
, ARRAYSIZE(bufSrc
));
1227 /* Sanitize dwFlags */
1228 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
1230 // NOTE: Technique taken from eventvwr.c!GetMessageStringFromDll()
1232 dwFlags
|= FORMAT_MESSAGE_MAX_WIDTH_MASK
;
1234 /* The string has already been manually loaded */
1235 dwFlags
&= ~(FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_FROM_SYSTEM
);
1236 dwFlags
|= FORMAT_MESSAGE_FROM_STRING
;
1239 * Retrieve the message string without appending extra newlines.
1240 * Use the "safe" FormatMessage version (SEH-protected) to protect
1241 * from invalid string parameters.
1243 dwLength
= FormatMessageSafeW(dwFlags
,
1250 Len
= (INT
)dwLength
;
1254 // ASSERT(dwLength == 0);
1258 // ASSERT(dwLength != 0);
1260 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
1262 /* Fixup returned length in case of errors */
1266 /* Free the buffer allocated by FormatMessage */
1267 LocalFree(lpMsgBuf
);
1274 * @name ConResMsgPrintfV
1275 * Formats and writes a message string to a stream. The function requires
1276 * a message definition as input. Contrary to the ConMsg* or the Win32
1277 * FormatMessage() functions, the message definition comes from a resource
1278 * string table, much like the strings for ConResPrintf(), but is formatted
1279 * according to the rules of ConMsgPrintf().
1282 * Stream to which the write operation is issued.
1284 * @param[in] dwFlags
1285 * The formatting options, see FormatMessage() for more details.
1286 * The only valid flags are @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY and
1287 * @b@c FORMAT_MESSAGE_IGNORE_INSERTS. All the other flags are internally
1288 * overridden by the function to implement its behaviour.
1291 * The identifier of the message string. The format string follows the
1292 * same specifications as the @a lpSource format string in ConMsgPrintf().
1294 * @param[in] Arguments
1295 * Optional pointer to an array of values describing a variable number of
1296 * arguments, depending on the message string. Each argument is used to
1297 * replace an <em>insert sequence</em> in the message string.
1298 * By default, the @p Arguments parameter is of type @c va_list*, initialized
1299 * with va_start(). The state of the @c va_list argument is undefined upon
1300 * return from the function. To use the @c va_list again, destroy the variable
1301 * argument list pointer using va_end() and reinitialize it with va_start().
1302 * If you do not have a pointer of type @c va_list*, then specify the
1303 * @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
1304 * of @c DWORD_PTR values; those values are input to the message formatted
1305 * as the insert values. Each insert must have a corresponding element in
1309 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1310 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1311 * These sequences extend the standard <em>format specifiers</em> as they
1312 * allow to specify an <em>insert number</em> referring which precise value
1313 * given in arguments to use.
1316 * Numbers of characters successfully written to @p Stream.
1318 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1319 * <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
1323 IN PCON_STREAM Stream
,
1326 IN
va_list *Arguments OPTIONAL
)
1328 return ConResMsgPrintfExV(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
1330 MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
),
1335 * @name ConResMsgPrintfEx
1336 * Formats and writes a message string to a stream. The function requires
1337 * a message definition as input. Contrary to the ConMsg* or the Win32
1338 * FormatMessage() functions, the message definition comes from a resource
1339 * string table, much like the strings for ConResPrintf(), but is formatted
1340 * according to the rules of ConMsgPrintf().
1343 * Stream to which the write operation is issued.
1345 * @param[in] hInstance
1346 * Optional handle to an instance of the module whose executable file
1347 * contains the string resource. Can be set to NULL to get the handle
1348 * to the application itself.
1350 * @param[in] dwFlags
1351 * The formatting options, see FormatMessage() for more details.
1352 * The only valid flag is @b@c FORMAT_MESSAGE_IGNORE_INSERTS.
1353 * All the other flags are internally overridden by the function
1354 * to implement its behaviour.
1357 * The identifier of the message string. The format string follows the
1358 * same specifications as the @a lpSource format string in ConMsgPrintf().
1360 * @param[in] LanguageId
1361 * The language identifier of the resource. If this parameter is
1362 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
1363 * associated with the calling thread is used. To specify a language other
1364 * than the current language, use the @c MAKELANGID macro to create this
1368 * Additional arguments that can be expected by the function, depending
1369 * on the message string. Each argument is used to replace an
1370 * <em>insert sequence</em> in the message string.
1373 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1374 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1375 * These sequences extend the standard <em>format specifiers</em> as they
1376 * allow to specify an <em>insert number</em> referring which precise value
1377 * given in arguments to use.
1380 * Numbers of characters successfully written to @p Stream.
1382 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1383 * <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
1388 IN PCON_STREAM Stream
,
1389 IN HINSTANCE hInstance OPTIONAL
,
1392 IN LANGID LanguageId
,
1398 /* Sanitize dwFlags */
1399 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1401 va_start(args
, LanguageId
);
1402 Len
= ConResMsgPrintfExV(Stream
,
1414 * @name ConResMsgPrintf
1415 * Formats and writes a message string to a stream. The function requires
1416 * a message definition as input. Contrary to the ConMsg* or the Win32
1417 * FormatMessage() functions, the message definition comes from a resource
1418 * string table, much like the strings for ConResPrintf(), but is formatted
1419 * according to the rules of ConMsgPrintf().
1422 * Stream to which the write operation is issued.
1424 * @param[in] dwFlags
1425 * The formatting options, see FormatMessage() for more details.
1426 * The only valid flag is @b@c FORMAT_MESSAGE_IGNORE_INSERTS.
1427 * All the other flags are internally overridden by the function
1428 * to implement its behaviour.
1431 * The identifier of the message string. The format string follows the
1432 * same specifications as the @a lpSource format string in ConMsgPrintf().
1435 * Additional arguments that can be expected by the function, depending
1436 * on the message string. Each argument is used to replace an
1437 * <em>insert sequence</em> in the message string.
1440 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1441 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1442 * These sequences extend the standard <em>format specifiers</em> as they
1443 * allow to specify an <em>insert number</em> referring which precise value
1444 * given in arguments to use.
1447 * Numbers of characters successfully written to @p Stream.
1449 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1450 * <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
1455 IN PCON_STREAM Stream
,
1463 /* Sanitize dwFlags */
1464 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1466 va_start(args
, uID
);
1467 Len
= ConResMsgPrintfV(Stream
, dwFlags
, uID
, &args
);
1476 ConClearLine(IN PCON_STREAM Stream
)
1478 HANDLE hOutput
= ConStreamGetOSHandle(Stream
);
1481 * Erase the full line where the cursor is, and move
1482 * the cursor back to the beginning of the line.
1485 if (IsConsoleHandle(hOutput
))
1487 CONSOLE_SCREEN_BUFFER_INFO csbi
;
1490 GetConsoleScreenBufferInfo(hOutput
, &csbi
);
1492 csbi
.dwCursorPosition
.X
= 0;
1493 // csbi.dwCursorPosition.Y;
1495 FillConsoleOutputCharacterW(hOutput
, L
' ',
1497 csbi
.dwCursorPosition
,
1499 SetConsoleCursorPosition(hOutput
, csbi
.dwCursorPosition
);
1501 else if (IsTTYHandle(hOutput
))
1503 ConPuts(Stream
, L
"\x1B[2K\x1B[1G"); // FIXME: Just use WriteFile
1505 // else, do nothing for files