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) \
361 CON_STREAM_WRITE_CALL((Stream), (Str), (Len))
367 * @name ConStreamWrite
368 * Writes a counted string to a stream.
371 * Stream to which the write operation is issued.
374 * Pointer to the counted string to write.
377 * Length of the string pointed by @p szStr, specified
378 * in number of characters.
381 * Numbers of characters successfully written to @p Stream.
385 IN PCON_STREAM Stream
,
390 CON_STREAM_WRITE2(Stream
, szStr
, len
, Len
);
396 * Writes a NULL-terminated string to a stream.
399 * Stream to which the write operation is issued.
402 * Pointer to the NULL-terminated string to write.
405 * Numbers of characters successfully written to @p Stream.
408 * Contrary to the CRT puts() function, ConPuts() does not append
409 * a terminating new-line character. In this way it behaves more like
410 * the CRT fputs() function.
414 IN PCON_STREAM Stream
,
420 CON_STREAM_WRITE2(Stream
, szStr
, Len
, Len
);
422 /* Fixup returned length in case of errors */
431 * Formats and writes a NULL-terminated string to a stream.
434 * Stream to which the write operation is issued.
437 * Pointer to the NULL-terminated format string, that follows the same
438 * specifications as the @a szStr format string in ConPrintf().
441 * Parameter describing a variable number of arguments,
442 * initialized with va_start(), that can be expected by the function,
443 * depending on the @p szStr format string. Each argument is used to
444 * replace a <em>format specifier</em> in the format string.
447 * Numbers of characters successfully written to @p Stream.
449 * @see ConPrintf(), printf(), vprintf()
453 IN PCON_STREAM Stream
,
458 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
460 // Len = vfwprintf(Stream->fStream, szStr, args); // vfprintf for direct ANSI
463 * Reuse szStr as the pointer to end-of-string, to compute
464 * the string length instead of calling wcslen().
466 // StringCchVPrintfW(bufSrc, ARRAYSIZE(bufSrc), szStr, args);
467 // Len = wcslen(bufSrc);
468 StringCchVPrintfExW(bufSrc
, ARRAYSIZE(bufSrc
), &szStr
, NULL
, 0, szStr
, args
);
469 Len
= szStr
- bufSrc
;
471 CON_STREAM_WRITE2(Stream
, bufSrc
, Len
, Len
);
473 /* Fixup returned length in case of errors */
482 * Formats and writes a NULL-terminated string to a stream.
485 * Stream to which the write operation is issued.
488 * Pointer to the NULL-terminated format string, that follows the same
489 * specifications as the @a format string in printf(). This string can
490 * optionally contain embedded <em>format specifiers</em> that are
491 * replaced by the values specified in subsequent additional arguments
492 * and formatted as requested.
495 * Additional arguments that can be expected by the function, depending
496 * on the @p szStr format string. Each argument is used to replace a
497 * <em>format specifier</em> in the format string.
500 * Numbers of characters successfully written to @p Stream.
502 * @see ConPrintfV(), printf(), vprintf()
507 IN PCON_STREAM Stream
,
514 // Len = vfwprintf(Stream->fStream, szMsgBuf, args); // vfprintf for direct ANSI
517 va_start(args
, szStr
);
518 Len
= ConPrintfV(Stream
, szStr
, args
);
526 * Writes a string resource to a stream.
529 * Stream to which the write operation is issued.
531 * @param[in] hInstance
532 * Optional handle to an instance of the module whose executable file
533 * contains the string resource. Can be set to NULL to get the handle
534 * to the application itself.
537 * The identifier of the string to be written.
539 * @param[in] LanguageId
540 * The language identifier of the resource. If this parameter is
541 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
542 * associated with the calling thread is used. To specify a language other
543 * than the current language, use the @c MAKELANGID macro to create this
547 * Numbers of characters successfully written to @p Stream.
550 * Similarly to ConPuts(), no terminating new-line character is appended.
552 * @see ConPuts(), ConResPuts()
556 IN PCON_STREAM Stream
,
557 IN HINSTANCE hInstance OPTIONAL
,
559 IN LANGID LanguageId
)
564 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, (PWSTR
)&szStr
, 0);
566 // Len = ConPuts(Stream, szStr);
567 CON_STREAM_WRITE2(Stream
, szStr
, Len
, Len
);
569 /* Fixup returned length in case of errors */
578 * Writes a string resource contained in the current application
582 * Stream to which the write operation is issued.
585 * The identifier of the string to be written.
588 * Numbers of characters successfully written to @p Stream.
591 * Similarly to ConPuts(), no terminating new-line character is appended.
593 * @see ConPuts(), ConResPutsEx()
597 IN PCON_STREAM Stream
,
600 return ConResPutsEx(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
601 uID
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
));
605 * @name ConResPrintfExV
606 * Formats and writes a string resource to a stream.
609 * Stream to which the write operation is issued.
611 * @param[in] hInstance
612 * Optional handle to an instance of the module whose executable file
613 * contains the string resource. Can be set to NULL to get the handle
614 * to the application itself.
617 * The identifier of the format string. The format string follows the
618 * same specifications as the @a szStr format string in ConPrintf().
620 * @param[in] LanguageId
621 * The language identifier of the resource. If this parameter is
622 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
623 * associated with the calling thread is used. To specify a language other
624 * than the current language, use the @c MAKELANGID macro to create this
628 * Parameter describing a variable number of arguments,
629 * initialized with va_start(), that can be expected by the function,
630 * depending on the @p szStr format string. Each argument is used to
631 * replace a <em>format specifier</em> in the format string.
634 * Numbers of characters successfully written to @p Stream.
636 * @see ConPrintf(), ConResPrintfEx(), ConResPrintfV(), ConResPrintf()
640 IN PCON_STREAM Stream
,
641 IN HINSTANCE hInstance OPTIONAL
,
643 IN LANGID LanguageId
,
647 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
649 // NOTE: We may use the special behaviour where nBufMaxSize == 0
650 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, bufSrc
, ARRAYSIZE(bufSrc
));
652 Len
= ConPrintfV(Stream
, bufSrc
, args
);
658 * @name ConResPrintfV
659 * Formats and writes a string resource contained in the
660 * current application to a stream.
663 * Stream to which the write operation is issued.
666 * The identifier of the format string. The format string follows the
667 * same specifications as the @a szStr format string in ConPrintf().
670 * Parameter describing a variable number of arguments,
671 * initialized with va_start(), that can be expected by the function,
672 * depending on the @p szStr format string. Each argument is used to
673 * replace a <em>format specifier</em> in the format string.
676 * Numbers of characters successfully written to @p Stream.
678 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfEx(), ConResPrintf()
682 IN PCON_STREAM Stream
,
686 return ConResPrintfExV(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
687 uID
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
),
692 * @name ConResPrintfEx
693 * Formats and writes a string resource to a stream.
696 * Stream to which the write operation is issued.
698 * @param[in] hInstance
699 * Optional handle to an instance of the module whose executable file
700 * contains the string resource. Can be set to NULL to get the handle
701 * to the application itself.
704 * The identifier of the format string. The format string follows the
705 * same specifications as the @a szStr format string in ConPrintf().
707 * @param[in] LanguageId
708 * The language identifier of the resource. If this parameter is
709 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
710 * associated with the calling thread is used. To specify a language other
711 * than the current language, use the @c MAKELANGID macro to create this
715 * Additional arguments that can be expected by the function, depending
716 * on the @p szStr format string. Each argument is used to replace a
717 * <em>format specifier</em> in the format string.
720 * Numbers of characters successfully written to @p Stream.
722 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfV(), ConResPrintf()
727 IN PCON_STREAM Stream
,
728 IN HINSTANCE hInstance OPTIONAL
,
730 IN LANGID LanguageId
,
736 va_start(args
, LanguageId
);
737 Len
= ConResPrintfExV(Stream
, hInstance
, uID
, LanguageId
, args
);
745 * Formats and writes a string resource contained in the
746 * current application to a stream.
749 * Stream to which the write operation is issued.
752 * The identifier of the format string. The format string follows the
753 * same specifications as the @a szStr format string in ConPrintf().
756 * Additional arguments that can be expected by the function, depending
757 * on the @p szStr format string. Each argument is used to replace a
758 * <em>format specifier</em> in the format string.
761 * Numbers of characters successfully written to @p Stream.
763 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfEx(), ConResPrintfV()
768 IN PCON_STREAM Stream
,
776 Len
= ConResPrintfV(Stream
, uID
, args
);
784 * Writes a message string to a stream without formatting. The function
785 * requires a message definition as input. The message definition can come
786 * from a buffer passed to the function. It can come from a message table
787 * resource in an already-loaded module, or the caller can ask the function
788 * to search the system's message table resource(s) for the message definition.
789 * Please refer to the Win32 FormatMessage() function for more details.
792 * Stream to which the write operation is issued.
795 * The formatting options, and how to interpret the @p lpSource parameter.
796 * See FormatMessage() for more details. The @b FORMAT_MESSAGE_ALLOCATE_BUFFER
797 * and @b FORMAT_MESSAGE_ARGUMENT_ARRAY flags are always ignored.
798 * The function implicitly uses the @b FORMAT_MESSAGE_IGNORE_INSERTS flag
799 * to implement its behaviour.
801 * @param[in] lpSource
802 * The location of the message definition. The type of this parameter
803 * depends upon the settings in the @p dwFlags parameter.
805 * @param[in] dwMessageId
806 * The message identifier for the requested message. This parameter
807 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
809 * @param[in] dwLanguageId
810 * The language identifier for the requested message. This parameter
811 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
814 * Numbers of characters successfully written to @p Stream.
817 * Similarly to ConPuts(), no terminating new-line character is appended.
819 * @see ConPuts(), ConResPuts() and associated functions,
820 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx">FormatMessage() (on MSDN)</a>
824 IN PCON_STREAM Stream
,
826 IN LPCVOID lpSource OPTIONAL
,
827 IN DWORD dwMessageId
,
828 IN DWORD dwLanguageId
)
832 LPWSTR lpMsgBuf
= NULL
;
835 * Sanitize dwFlags. This version always ignore explicitely the inserts
836 * as we emulate the behaviour of the (f)puts function.
838 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
839 dwFlags
|= FORMAT_MESSAGE_IGNORE_INSERTS
; // Ignore inserts for FormatMessage.
840 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
843 * Retrieve the message string without appending extra newlines.
844 * Wrap in SEH to protect from invalid string parameters.
848 dwLength
= FormatMessageW(dwFlags
,
856 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
865 // ASSERT(dwLength == 0);
869 // ASSERT(dwLength != 0);
871 /* lpMsgBuf is NULL-terminated by FormatMessage */
872 // Len = ConPuts(Stream, lpMsgBuf);
873 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
875 /* Fixup returned length in case of errors */
879 /* Free the buffer allocated by FormatMessage */
887 * @name ConMsgPrintf2V
888 * Formats and writes a message string to a stream.
890 * @remark For internal use only.
892 * @see ConMsgPrintfV()
896 IN PCON_STREAM Stream
,
898 IN LPCVOID lpSource OPTIONAL
,
899 IN DWORD dwMessageId
,
900 IN DWORD dwLanguageId
,
905 LPWSTR lpMsgBuf
= NULL
;
908 * Sanitize dwFlags. This version always ignore explicitely the inserts.
909 * The string that we will return to the user will not be pre-formatted.
911 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
912 dwFlags
|= FORMAT_MESSAGE_IGNORE_INSERTS
; // Ignore inserts for FormatMessage.
913 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
916 * Retrieve the message string without appending extra newlines.
917 * Wrap in SEH to protect from invalid string parameters.
921 dwLength
= FormatMessageW(dwFlags
,
929 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
938 // ASSERT(dwLength == 0);
942 // ASSERT(dwLength != 0);
944 /* lpMsgBuf is NULL-terminated by FormatMessage */
945 Len
= ConPrintfV(Stream
, lpMsgBuf
, args
);
946 // CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
948 /* Fixup returned length in case of errors */
952 /* Free the buffer allocated by FormatMessage */
960 * @name ConMsgPrintfV
961 * Formats and writes a message string to a stream. The function requires
962 * a message definition as input. The message definition can come from a
963 * buffer passed to the function. It can come from a message table resource
964 * in an already-loaded module, or the caller can ask the function to search
965 * the system's message table resource(s) for the message definition.
966 * Please refer to the Win32 FormatMessage() function for more details.
969 * Stream to which the write operation is issued.
972 * The formatting options, and how to interpret the @p lpSource parameter.
973 * See FormatMessage() for more details.
974 * The @b FORMAT_MESSAGE_ALLOCATE_BUFFER flag is always ignored.
976 * @param[in] lpSource
977 * The location of the message definition. The type of this parameter
978 * depends upon the settings in the @p dwFlags parameter.
980 * @param[in] dwMessageId
981 * The message identifier for the requested message. This parameter
982 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
984 * @param[in] dwLanguageId
985 * The language identifier for the requested message. This parameter
986 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
988 * @param[in] Arguments
989 * Optional pointer to an array of values describing a variable number of
990 * arguments, depending on the message string. Each argument is used to
991 * replace an <em>insert sequence</em> in the message string.
992 * By default, the @p Arguments parameter is of type @c va_list*, initialized
993 * with va_start(). The state of the @c va_list argument is undefined upon
994 * return from the function. To use the @c va_list again, destroy the variable
995 * argument list pointer using va_end() and reinitialize it with va_start().
996 * If you do not have a pointer of type @c va_list*, then specify the
997 * @b FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
998 * of @c DWORD_PTR values; those values are input to the message formatted
999 * as the insert values. Each insert must have a corresponding element in
1003 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1004 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1005 * These sequences extend the standard <em>format specifiers</em> as they
1006 * allow to specify an <em>insert number</em> referring which precise value
1007 * given in arguments to use.
1010 * Numbers of characters successfully written to @p Stream.
1012 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1013 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx">FormatMessage() (on MSDN)</a>
1017 IN PCON_STREAM Stream
,
1019 IN LPCVOID lpSource OPTIONAL
,
1020 IN DWORD dwMessageId
,
1021 IN DWORD dwLanguageId
,
1022 IN
va_list *Arguments OPTIONAL
)
1026 LPWSTR lpMsgBuf
= NULL
;
1028 /* Sanitize dwFlags */
1029 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
1032 * Retrieve the message string without appending extra newlines.
1033 * Use the "safe" FormatMessage version (SEH-protected) to protect
1034 * from invalid string parameters.
1036 dwLength
= FormatMessageSafeW(dwFlags
,
1044 Len
= (INT
)dwLength
;
1048 // ASSERT(dwLength == 0);
1052 // ASSERT(dwLength != 0);
1054 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
1056 /* Fixup returned length in case of errors */
1060 /* Free the buffer allocated by FormatMessage */
1061 LocalFree(lpMsgBuf
);
1068 * @name ConMsgPrintf
1069 * Formats and writes a message string to a stream. The function requires
1070 * a message definition as input. The message definition can come from a
1071 * buffer passed to the function. It can come from a message table resource
1072 * in an already-loaded module, or the caller can ask the function to search
1073 * the system's message table resource(s) for the message definition.
1074 * Please refer to the Win32 FormatMessage() function for more details.
1077 * Stream to which the write operation is issued.
1079 * @param[in] dwFlags
1080 * The formatting options, and how to interpret the @p lpSource parameter.
1081 * See FormatMessage() for more details. The @b FORMAT_MESSAGE_ALLOCATE_BUFFER
1082 * and @b FORMAT_MESSAGE_ARGUMENT_ARRAY flags are always ignored.
1084 * @param[in] lpSource
1085 * The location of the message definition. The type of this parameter
1086 * depends upon the settings in the @p dwFlags parameter.
1088 * @param[in] dwMessageId
1089 * The message identifier for the requested message. This parameter
1090 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
1092 * @param[in] dwLanguageId
1093 * The language identifier for the requested message. This parameter
1094 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
1097 * Additional arguments that can be expected by the function, depending
1098 * on the message string. Each argument is used to replace an
1099 * <em>insert sequence</em> in the message string.
1102 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1103 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1104 * These sequences extend the standard <em>format specifiers</em> as they
1105 * allow to specify an <em>insert number</em> referring which precise value
1106 * given in arguments to use.
1109 * Numbers of characters successfully written to @p Stream.
1111 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintfV(),
1112 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx">FormatMessage() (on MSDN)</a>
1117 IN PCON_STREAM Stream
,
1119 IN LPCVOID lpSource OPTIONAL
,
1120 IN DWORD dwMessageId
,
1121 IN DWORD dwLanguageId
,
1127 /* Sanitize dwFlags */
1128 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1130 va_start(args
, dwLanguageId
);
1131 Len
= ConMsgPrintfV(Stream
,
1143 * @name ConResMsgPrintfExV
1144 * Formats and writes a message string to a stream. The function requires
1145 * a message definition as input. Contrary to the ConMsg* or the Win32
1146 * FormatMessage() functions, the message definition comes from a resource
1147 * string table, much like the strings for ConResPrintf(), but is formatted
1148 * according to the rules of ConMsgPrintf().
1151 * Stream to which the write operation is issued.
1153 * @param[in] hInstance
1154 * Optional handle to an instance of the module whose executable file
1155 * contains the string resource. Can be set to NULL to get the handle
1156 * to the application itself.
1158 * @param[in] dwFlags
1159 * The formatting options, see FormatMessage() for more details.
1160 * The only valid flags are @b FORMAT_MESSAGE_ARGUMENT_ARRAY,
1161 * @b FORMAT_MESSAGE_IGNORE_INSERTS and @b FORMAT_MESSAGE_MAX_WIDTH_MASK.
1162 * All the other flags are internally overridden by the function
1163 * to implement its behaviour.
1166 * The identifier of the message string. The format string follows the
1167 * same specifications as the @a lpSource format string in ConMsgPrintf().
1169 * @param[in] LanguageId
1170 * The language identifier of the resource. If this parameter is
1171 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
1172 * associated with the calling thread is used. To specify a language other
1173 * than the current language, use the @c MAKELANGID macro to create this
1176 * @param[in] Arguments
1177 * Optional pointer to an array of values describing a variable number of
1178 * arguments, depending on the message string. Each argument is used to
1179 * replace an <em>insert sequence</em> in the message string.
1180 * By default, the @p Arguments parameter is of type @c va_list*, initialized
1181 * with va_start(). The state of the @c va_list argument is undefined upon
1182 * return from the function. To use the @c va_list again, destroy the variable
1183 * argument list pointer using va_end() and reinitialize it with va_start().
1184 * If you do not have a pointer of type @c va_list*, then specify the
1185 * @b FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
1186 * of @c DWORD_PTR values; those values are input to the message formatted
1187 * as the insert values. Each insert must have a corresponding element in
1191 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1192 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1193 * These sequences extend the standard <em>format specifiers</em> as they
1194 * allow to specify an <em>insert number</em> referring which precise value
1195 * given in arguments to use.
1198 * Numbers of characters successfully written to @p Stream.
1200 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1201 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx">FormatMessage() (on MSDN)</a>
1205 IN PCON_STREAM Stream
,
1206 IN HINSTANCE hInstance OPTIONAL
,
1209 IN LANGID LanguageId
,
1210 IN
va_list *Arguments OPTIONAL
)
1214 LPWSTR lpMsgBuf
= NULL
;
1215 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
1217 /* Retrieve the string from the resource string table */
1218 // NOTE: We may use the special behaviour where nBufMaxSize == 0
1219 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, bufSrc
, ARRAYSIZE(bufSrc
));
1223 /* Sanitize dwFlags */
1224 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
1226 /* The string has already been manually loaded */
1227 dwFlags
&= ~(FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_FROM_SYSTEM
);
1228 dwFlags
|= FORMAT_MESSAGE_FROM_STRING
;
1231 * Retrieve the message string without appending extra newlines.
1232 * Use the "safe" FormatMessage version (SEH-protected) to protect
1233 * from invalid string parameters.
1235 dwLength
= FormatMessageSafeW(dwFlags
,
1242 Len
= (INT
)dwLength
;
1246 // ASSERT(dwLength == 0);
1250 // ASSERT(dwLength != 0);
1252 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
1254 /* Fixup returned length in case of errors */
1258 /* Free the buffer allocated by FormatMessage */
1259 LocalFree(lpMsgBuf
);
1266 * @name ConResMsgPrintfV
1267 * Formats and writes a message string to a stream. The function requires
1268 * a message definition as input. Contrary to the ConMsg* or the Win32
1269 * FormatMessage() functions, the message definition comes from a resource
1270 * string table, much like the strings for ConResPrintf(), but is formatted
1271 * according to the rules of ConMsgPrintf().
1274 * Stream to which the write operation is issued.
1276 * @param[in] dwFlags
1277 * The formatting options, see FormatMessage() for more details.
1278 * The only valid flags are @b FORMAT_MESSAGE_ARGUMENT_ARRAY,
1279 * @b FORMAT_MESSAGE_IGNORE_INSERTS and @b FORMAT_MESSAGE_MAX_WIDTH_MASK.
1280 * All the other flags are internally overridden by the function
1281 * to implement its behaviour.
1284 * The identifier of the message string. The format string follows the
1285 * same specifications as the @a lpSource format string in ConMsgPrintf().
1287 * @param[in] Arguments
1288 * Optional pointer to an array of values describing a variable number of
1289 * arguments, depending on the message string. Each argument is used to
1290 * replace an <em>insert sequence</em> in the message string.
1291 * By default, the @p Arguments parameter is of type @c va_list*, initialized
1292 * with va_start(). The state of the @c va_list argument is undefined upon
1293 * return from the function. To use the @c va_list again, destroy the variable
1294 * argument list pointer using va_end() and reinitialize it with va_start().
1295 * If you do not have a pointer of type @c va_list*, then specify the
1296 * @b FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
1297 * of @c DWORD_PTR values; those values are input to the message formatted
1298 * as the insert values. Each insert must have a corresponding element in
1302 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1303 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1304 * These sequences extend the standard <em>format specifiers</em> as they
1305 * allow to specify an <em>insert number</em> referring which precise value
1306 * given in arguments to use.
1309 * Numbers of characters successfully written to @p Stream.
1311 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1312 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx">FormatMessage() (on MSDN)</a>
1316 IN PCON_STREAM Stream
,
1319 IN
va_list *Arguments OPTIONAL
)
1321 return ConResMsgPrintfExV(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
1323 MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
),
1328 * @name ConResMsgPrintfEx
1329 * Formats and writes a message string to a stream. The function requires
1330 * a message definition as input. Contrary to the ConMsg* or the Win32
1331 * FormatMessage() functions, the message definition comes from a resource
1332 * string table, much like the strings for ConResPrintf(), but is formatted
1333 * according to the rules of ConMsgPrintf().
1336 * Stream to which the write operation is issued.
1338 * @param[in] hInstance
1339 * Optional handle to an instance of the module whose executable file
1340 * contains the string resource. Can be set to NULL to get the handle
1341 * to the application itself.
1343 * @param[in] dwFlags
1344 * The formatting options, see FormatMessage() for more details.
1345 * The only valid flags are @b FORMAT_MESSAGE_IGNORE_INSERTS and
1346 * @b FORMAT_MESSAGE_MAX_WIDTH_MASK. All the other flags are internally
1347 * overridden by the function to implement its behaviour.
1350 * The identifier of the message string. The format string follows the
1351 * same specifications as the @a lpSource format string in ConMsgPrintf().
1353 * @param[in] LanguageId
1354 * The language identifier of the resource. If this parameter is
1355 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
1356 * associated with the calling thread is used. To specify a language other
1357 * than the current language, use the @c MAKELANGID macro to create this
1361 * Additional arguments that can be expected by the function, depending
1362 * on the message string. Each argument is used to replace an
1363 * <em>insert sequence</em> in the message string.
1366 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1367 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1368 * These sequences extend the standard <em>format specifiers</em> as they
1369 * allow to specify an <em>insert number</em> referring which precise value
1370 * given in arguments to use.
1373 * Numbers of characters successfully written to @p Stream.
1375 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1376 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx">FormatMessage() (on MSDN)</a>
1381 IN PCON_STREAM Stream
,
1382 IN HINSTANCE hInstance OPTIONAL
,
1385 IN LANGID LanguageId
,
1391 /* Sanitize dwFlags */
1392 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1394 va_start(args
, LanguageId
);
1395 Len
= ConResMsgPrintfExV(Stream
,
1407 * @name ConResMsgPrintf
1408 * Formats and writes a message string to a stream. The function requires
1409 * a message definition as input. Contrary to the ConMsg* or the Win32
1410 * FormatMessage() functions, the message definition comes from a resource
1411 * string table, much like the strings for ConResPrintf(), but is formatted
1412 * according to the rules of ConMsgPrintf().
1415 * Stream to which the write operation is issued.
1417 * @param[in] dwFlags
1418 * The formatting options, see FormatMessage() for more details.
1419 * The only valid flags are @b FORMAT_MESSAGE_IGNORE_INSERTS and
1420 * @b FORMAT_MESSAGE_MAX_WIDTH_MASK. All the other flags are internally
1421 * overridden by the function to implement its behaviour.
1424 * The identifier of the message string. The format string follows the
1425 * same specifications as the @a lpSource format string in ConMsgPrintf().
1428 * Additional arguments that can be expected by the function, depending
1429 * on the message string. Each argument is used to replace an
1430 * <em>insert sequence</em> in the message string.
1433 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1434 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1435 * These sequences extend the standard <em>format specifiers</em> as they
1436 * allow to specify an <em>insert number</em> referring which precise value
1437 * given in arguments to use.
1440 * Numbers of characters successfully written to @p Stream.
1442 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1443 * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx">FormatMessage() (on MSDN)</a>
1448 IN PCON_STREAM Stream
,
1456 /* Sanitize dwFlags */
1457 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1459 va_start(args
, uID
);
1460 Len
= ConResMsgPrintfV(Stream
, dwFlags
, uID
, &args
);
1469 ConClearLine(IN PCON_STREAM Stream
)
1471 HANDLE hOutput
= ConStreamGetOSHandle(Stream
);
1474 * Erase the full line where the cursor is, and move
1475 * the cursor back to the beginning of the line.
1478 if (IsConsoleHandle(hOutput
))
1480 CONSOLE_SCREEN_BUFFER_INFO csbi
;
1483 GetConsoleScreenBufferInfo(hOutput
, &csbi
);
1485 csbi
.dwCursorPosition
.X
= 0;
1486 // csbi.dwCursorPosition.Y;
1488 FillConsoleOutputCharacterW(hOutput
, L
' ',
1490 csbi
.dwCursorPosition
,
1492 SetConsoleCursorPosition(hOutput
, csbi
.dwCursorPosition
);
1494 else if (IsTTYHandle(hOutput
))
1496 ConPuts(Stream
, L
"\x1B[2K\x1B[1G"); // FIXME: Just use WriteFile
1498 // else, do nothing for files