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 // Also known as: RC_STRING_MAX_SIZE, MAX_BUFFER_SIZE (some programs:
53 // wlanconf, shutdown, set it to 5024), OUTPUT_BUFFER_SIZE (name given
54 // in cmd/console.c), MAX_STRING_SIZE (name given in diskpart) or
55 // MAX_MESSAGE_SIZE (set to 512 in shutdown).
56 #define CON_RC_STRING_MAX_SIZE 4096
61 * Writes a counted string to a stream.
64 * Stream to which the write operation is issued.
67 * Pointer to the counted string to write.
70 * Length of the string pointed by @p szStr, specified
71 * in number of characters.
74 * Numbers of characters successfully written to @p Stream.
77 * This function is used as an internal function.
78 * Use the ConStreamWrite() function instead.
81 * Should be called with the stream locked.
86 IN PCON_STREAM Stream
,
91 DWORD TotalLen
= len
, dwNumBytes
= 0;
94 /* If we do not write anything, just return */
95 if (!szStr
|| len
== 0)
98 /* Check whether we are writing to a console */
99 // if (IsConsoleHandle(Stream->hHandle))
100 if (Stream
->IsConsole
)
102 // TODO: Check if (Stream->Mode == WideText or UTF16Text) ??
105 * This code is inspired from _cputws, in particular from the fact that,
106 * according to MSDN: https://msdn.microsoft.com/en-us/library/ms687401(v=vs.85).aspx
107 * the buffer size must be less than 64 KB.
109 * A similar code can be used for implementing _cputs too.
113 TotalLen
= len
, dwNumBytes
= 0;
117 cchWrite
= min(len
, 65535 / sizeof(WCHAR
));
119 // FIXME: Check return value!
120 WriteConsole(Stream
->hHandle
, szStr
, cchWrite
, &dwNumBytes
, NULL
);
126 return (INT
)TotalLen
; // FIXME: Really return the number of chars written!
130 * We are redirected and writing to a file or pipe instead of the console.
131 * Convert the string from TCHARs to the desired output format, if the two differ.
133 * Implementation NOTE:
134 * MultiByteToWideChar (resp. WideCharToMultiByte) are equivalent to
135 * OemToCharBuffW (resp. CharToOemBuffW), but these latter functions
136 * uselessly depend on user32.dll, while MultiByteToWideChar and
137 * WideCharToMultiByte only need kernel32.dll.
139 if ((Stream
->Mode
== WideText
) || (Stream
->Mode
== UTF16Text
))
141 #ifndef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
142 /* Convert from the current process/thread's code page to UTF-16 */
143 PWCHAR buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
146 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
149 len
= (DWORD
)MultiByteToWideChar(CP_THREAD_ACP
, // CP_ACP, CP_OEMCP
150 0, szStr
, (INT
)len
, buffer
, (INT
)len
);
151 szStr
= (PVOID
)buffer
;
154 * Do not perform any conversion since we are already in UTF-16,
155 * that is the same encoding as the stream.
160 * Find any newline character in the buffer,
161 * write the part BEFORE the newline, then emit
162 * a carriage-return + newline sequence and finally
163 * write the remaining part of the buffer.
165 * This fixes output in files and serial console.
169 /* Loop until we find a newline character */
171 while (len
> 0 && *(PCWCH
)p
!= L
'\n')
173 /* Advance one character */
174 p
= (LPCVOID
)((PCWCH
)p
+ 1);
178 /* Write everything up to \n */
179 dwNumBytes
= ((PCWCH
)p
- (PCWCH
)szStr
) * sizeof(WCHAR
);
180 WriteFile(Stream
->hHandle
, szStr
, dwNumBytes
, &dwNumBytes
, NULL
);
183 * If we hit a newline and the previous character is not a carriage-return,
184 * emit a carriage-return + newline sequence, otherwise just emit the newline.
186 if (len
> 0 && *(PCWCH
)p
== L
'\n')
188 if (p
== (LPCVOID
)szStr
|| (p
> (LPCVOID
)szStr
&& *((PCWCH
)p
- 1) != L
'\r'))
189 WriteFile(Stream
->hHandle
, L
"\r\n", 2 * sizeof(WCHAR
), &dwNumBytes
, NULL
);
191 WriteFile(Stream
->hHandle
, L
"\n", sizeof(WCHAR
), &dwNumBytes
, NULL
);
194 p
= (LPCVOID
)((PCWCH
)p
+ 1);
201 HeapFree(GetProcessHeap(), 0, buffer
);
204 else if ((Stream
->Mode
== UTF8Text
) || (Stream
->Mode
== AnsiText
))
210 * Resolve the current code page if it has not been assigned yet
211 * (we do this only if the stream is in ANSI mode; in UTF8 mode
212 * the code page is always set to CP_UTF8). Otherwise use the
213 * current stream's code page.
215 if (/*(Stream->Mode == AnsiText) &&*/ (Stream
->CodePage
== INVALID_CP
))
216 CodePage
= GetConsoleOutputCP(); // CP_ACP, CP_OEMCP
218 CodePage
= Stream
->CodePage
;
220 #ifdef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
221 /* Convert from UTF-16 to either UTF-8 or ANSI, using the stream code page */
222 // NOTE: MB_LEN_MAX defined either in limits.h or in stdlib.h .
223 buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* MB_LEN_MAX
);
226 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
229 len
= WideCharToMultiByte(CodePage
, 0,
230 szStr
, len
, buffer
, len
* MB_LEN_MAX
,
232 szStr
= (PVOID
)buffer
;
235 * Convert from the current process/thread's code page to either
236 * UTF-8 or ANSI, using the stream code page.
237 * We need to perform a double conversion, by going through UTF-16.
240 #error "Need to implement double conversion!"
244 * Find any newline character in the buffer,
245 * write the part BEFORE the newline, then emit
246 * a carriage-return + newline sequence and finally
247 * write the remaining part of the buffer.
249 * This fixes output in files and serial console.
253 /* Loop until we find a newline character */
255 while (len
> 0 && *(PCCH
)p
!= '\n')
257 /* Advance one character */
258 p
= (LPCVOID
)((PCCH
)p
+ 1);
262 /* Write everything up to \n */
263 dwNumBytes
= ((PCCH
)p
- (PCCH
)szStr
) * sizeof(CHAR
);
264 WriteFile(Stream
->hHandle
, szStr
, dwNumBytes
, &dwNumBytes
, NULL
);
267 * If we hit a newline and the previous character is not a carriage-return,
268 * emit a carriage-return + newline sequence, otherwise just emit the newline.
270 if (len
> 0 && *(PCCH
)p
== '\n')
272 if (p
== (LPCVOID
)szStr
|| (p
> (LPCVOID
)szStr
&& *((PCCH
)p
- 1) != '\r'))
273 WriteFile(Stream
->hHandle
, "\r\n", 2, &dwNumBytes
, NULL
);
275 WriteFile(Stream
->hHandle
, "\n", 1, &dwNumBytes
, NULL
);
278 p
= (LPCVOID
)((PCCH
)p
+ 1);
285 HeapFree(GetProcessHeap(), 0, buffer
);
290 else // if (Stream->Mode == Binary)
292 /* Directly output the string */
293 WriteFile(Stream
->hHandle
, szStr
, len
, &dwNumBytes
, NULL
);
297 return (INT
)TotalLen
;
299 #else /* defined(USE_CRT) */
304 /* If we do not write anything, just return */
305 if (!szStr
|| len
== 0)
310 * There is no "counted" printf-to-stream or puts-like function, therefore
311 * we use this trick to output the counted string to the stream.
315 written
= fwprintf(Stream
->fStream
, L
"%.*s", total
, szStr
);
319 * Some embedded NULL or special character
320 * was encountered, print it apart.
324 fputwc(*szStr
, Stream
->fStream
);
338 /* ANSI text or Binary output only */
339 _setmode(_fileno(Stream
->fStream
), _O_TEXT
); // _O_BINARY
340 return fwrite(szStr
, sizeof(*szStr
), len
, Stream
->fStream
);
343 #endif /* defined(USE_CRT) */
347 #define CON_STREAM_WRITE_CALL(Stream, Str, Len) \
348 (Stream)->WriteFunc((Stream), (Str), (Len))
350 /* Lock the stream only in non-USE_CRT mode (otherwise use the CRT stream lock) */
353 #define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
355 EnterCriticalSection(&(Stream)->Lock); \
356 (RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
357 LeaveCriticalSection(&(Stream)->Lock); \
360 #define CON_STREAM_WRITE(Stream, Str, Len) \
362 EnterCriticalSection(&(Stream)->Lock); \
363 CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
364 LeaveCriticalSection(&(Stream)->Lock); \
369 #define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
371 (RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
374 #define CON_STREAM_WRITE(Stream, Str, Len) \
375 CON_STREAM_WRITE_CALL((Stream), (Str), (Len))
381 * @name ConStreamWrite
382 * Writes a counted string to a stream.
385 * Stream to which the write operation is issued.
388 * Pointer to the counted string to write.
391 * Length of the string pointed by @p szStr, specified
392 * in number of characters.
395 * Numbers of characters successfully written to @p Stream.
399 IN PCON_STREAM Stream
,
404 CON_STREAM_WRITE2(Stream
, szStr
, len
, Len
);
410 * Writes a NULL-terminated string to a stream.
413 * Stream to which the write operation is issued.
416 * Pointer to the NULL-terminated string to write.
419 * Numbers of characters successfully written to @p Stream.
422 * Contrary to the CRT puts() function, ConPuts() does not append
423 * a terminating new-line character. In this way it behaves more like
424 * the CRT fputs() function.
428 IN PCON_STREAM Stream
,
434 CON_STREAM_WRITE2(Stream
, szStr
, Len
, Len
);
436 /* Fixup returned length in case of errors */
445 * Formats and writes a NULL-terminated string to a stream.
448 * Stream to which the write operation is issued.
451 * Pointer to the NULL-terminated format string, that follows the same
452 * specifications as the @a szStr format string in ConPrintf().
455 * Parameter describing a variable number of arguments,
456 * initialized with va_start(), that can be expected by the function,
457 * depending on the @p szStr format string. Each argument is used to
458 * replace a <em>format specifier</em> in the format string.
461 * Numbers of characters successfully written to @p Stream.
463 * @see ConPrintf(), printf(), vprintf()
467 IN PCON_STREAM Stream
,
472 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
474 // Len = vfwprintf(Stream->fStream, szStr, args); // vfprintf for direct ANSI
477 * Re-use szStr as the pointer to end-of-string, so as
478 * to compute the string length instead of calling wcslen().
480 // StringCchVPrintfW(bufSrc, ARRAYSIZE(bufSrc), szStr, args);
481 // Len = wcslen(bufSrc);
482 StringCchVPrintfExW(bufSrc
, ARRAYSIZE(bufSrc
), (PWSTR
*)&szStr
, NULL
, 0, szStr
, args
);
483 Len
= szStr
- bufSrc
;
485 CON_STREAM_WRITE2(Stream
, bufSrc
, Len
, Len
);
487 /* Fixup returned length in case of errors */
496 * Formats and writes a NULL-terminated string to a stream.
499 * Stream to which the write operation is issued.
502 * Pointer to the NULL-terminated format string, that follows the same
503 * specifications as the @a format string in printf(). This string can
504 * optionally contain embedded <em>format specifiers</em> that are
505 * replaced by the values specified in subsequent additional arguments
506 * and formatted as requested.
509 * Additional arguments that can be expected by the function, depending
510 * on the @p szStr format string. Each argument is used to replace a
511 * <em>format specifier</em> in the format string.
514 * Numbers of characters successfully written to @p Stream.
516 * @see ConPrintfV(), printf(), vprintf()
521 IN PCON_STREAM Stream
,
528 // Len = vfwprintf(Stream->fStream, szMsgBuf, args); // vfprintf for direct ANSI
531 va_start(args
, szStr
);
532 Len
= ConPrintfV(Stream
, szStr
, args
);
540 * Writes a string resource to a stream.
543 * Stream to which the write operation is issued.
545 * @param[in] hInstance
546 * Optional handle to an instance of the module whose executable file
547 * contains the string resource. Can be set to NULL to get the handle
548 * to the application itself.
551 * The identifier of the string to be written.
553 * @param[in] LanguageId
554 * The language identifier of the resource. If this parameter is
555 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
556 * associated with the calling thread is used. To specify a language other
557 * than the current language, use the @c MAKELANGID macro to create this
561 * Numbers of characters successfully written to @p Stream.
564 * Similarly to ConPuts(), no terminating new-line character is appended.
566 * @see ConPuts(), ConResPuts()
570 IN PCON_STREAM Stream
,
571 IN HINSTANCE hInstance OPTIONAL
,
573 IN LANGID LanguageId
)
578 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, (PWSTR
)&szStr
, 0);
580 // Len = ConPuts(Stream, szStr);
581 CON_STREAM_WRITE2(Stream
, szStr
, Len
, Len
);
583 /* Fixup returned length in case of errors */
592 * Writes a string resource contained in the current application
596 * Stream to which the write operation is issued.
599 * The identifier of the string to be written.
602 * Numbers of characters successfully written to @p Stream.
605 * Similarly to ConPuts(), no terminating new-line character is appended.
607 * @see ConPuts(), ConResPutsEx()
611 IN PCON_STREAM Stream
,
614 return ConResPutsEx(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
615 uID
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
));
619 * @name ConResPrintfExV
620 * Formats and writes a string resource to a stream.
623 * Stream to which the write operation is issued.
625 * @param[in] hInstance
626 * Optional handle to an instance of the module whose executable file
627 * contains the string resource. Can be set to NULL to get the handle
628 * to the application itself.
631 * The identifier of the format string. The format string follows the
632 * same specifications as the @a szStr format string in ConPrintf().
634 * @param[in] LanguageId
635 * The language identifier of the resource. If this parameter is
636 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
637 * associated with the calling thread is used. To specify a language other
638 * than the current language, use the @c MAKELANGID macro to create this
642 * Parameter describing a variable number of arguments,
643 * initialized with va_start(), that can be expected by the function,
644 * depending on the @p szStr format string. Each argument is used to
645 * replace a <em>format specifier</em> in the format string.
648 * Numbers of characters successfully written to @p Stream.
650 * @see ConPrintf(), ConResPrintfEx(), ConResPrintfV(), ConResPrintf()
654 IN PCON_STREAM Stream
,
655 IN HINSTANCE hInstance OPTIONAL
,
657 IN LANGID LanguageId
,
661 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
663 // NOTE: We may use the special behaviour where nBufMaxSize == 0
664 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, bufSrc
, ARRAYSIZE(bufSrc
));
666 Len
= ConPrintfV(Stream
, bufSrc
, args
);
672 * @name ConResPrintfV
673 * Formats and writes a string resource contained in the
674 * current application to a stream.
677 * Stream to which the write operation is issued.
680 * The identifier of the format string. The format string follows the
681 * same specifications as the @a szStr format string in ConPrintf().
684 * Parameter describing a variable number of arguments,
685 * initialized with va_start(), that can be expected by the function,
686 * depending on the @p szStr format string. Each argument is used to
687 * replace a <em>format specifier</em> in the format string.
690 * Numbers of characters successfully written to @p Stream.
692 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfEx(), ConResPrintf()
696 IN PCON_STREAM Stream
,
700 return ConResPrintfExV(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
701 uID
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
),
706 * @name ConResPrintfEx
707 * Formats and writes a string resource to a stream.
710 * Stream to which the write operation is issued.
712 * @param[in] hInstance
713 * Optional handle to an instance of the module whose executable file
714 * contains the string resource. Can be set to NULL to get the handle
715 * to the application itself.
718 * The identifier of the format string. The format string follows the
719 * same specifications as the @a szStr format string in ConPrintf().
721 * @param[in] LanguageId
722 * The language identifier of the resource. If this parameter is
723 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
724 * associated with the calling thread is used. To specify a language other
725 * than the current language, use the @c MAKELANGID macro to create this
729 * Additional arguments that can be expected by the function, depending
730 * on the @p szStr format string. Each argument is used to replace a
731 * <em>format specifier</em> in the format string.
734 * Numbers of characters successfully written to @p Stream.
736 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfV(), ConResPrintf()
741 IN PCON_STREAM Stream
,
742 IN HINSTANCE hInstance OPTIONAL
,
744 IN LANGID LanguageId
,
750 va_start(args
, LanguageId
);
751 Len
= ConResPrintfExV(Stream
, hInstance
, uID
, LanguageId
, args
);
759 * Formats and writes a string resource contained in the
760 * current application to a stream.
763 * Stream to which the write operation is issued.
766 * The identifier of the format string. The format string follows the
767 * same specifications as the @a szStr format string in ConPrintf().
770 * Additional arguments that can be expected by the function, depending
771 * on the @p szStr format string. Each argument is used to replace a
772 * <em>format specifier</em> in the format string.
775 * Numbers of characters successfully written to @p Stream.
777 * @see ConPrintf(), ConResPrintfExV(), ConResPrintfEx(), ConResPrintfV()
782 IN PCON_STREAM Stream
,
790 Len
= ConResPrintfV(Stream
, uID
, args
);
798 * Writes a message string to a stream without formatting. The function
799 * requires a message definition as input. The message definition can come
800 * from a buffer passed to the function. It can come from a message table
801 * resource in an already-loaded module, or the caller can ask the function
802 * to search the system's message table resource(s) for the message definition.
803 * Please refer to the Win32 FormatMessage() function for more details.
806 * Stream to which the write operation is issued.
809 * The formatting options, and how to interpret the @p lpSource parameter.
810 * See FormatMessage() for more details. The @b FORMAT_MESSAGE_ALLOCATE_BUFFER
811 * and @b FORMAT_MESSAGE_ARGUMENT_ARRAY flags are always ignored.
812 * The function implicitly uses the @b FORMAT_MESSAGE_IGNORE_INSERTS flag
813 * to implement its behaviour.
815 * @param[in] lpSource
816 * The location of the message definition. The type of this parameter
817 * depends upon the settings in the @p dwFlags parameter.
819 * @param[in] dwMessageId
820 * The message identifier for the requested message. This parameter
821 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
823 * @param[in] dwLanguageId
824 * The language identifier for the requested message. This parameter
825 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
828 * Numbers of characters successfully written to @p Stream.
831 * Similarly to ConPuts(), no terminating new-line character is appended.
833 * @see ConPuts(), ConResPuts() and associated functions,
834 * <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage">FormatMessage() (on MSDN)</a>
838 IN PCON_STREAM Stream
,
840 IN LPCVOID lpSource OPTIONAL
,
841 IN DWORD dwMessageId
,
842 IN DWORD dwLanguageId
)
846 LPWSTR lpMsgBuf
= NULL
;
849 * Sanitize dwFlags. This version always ignores explicitly the inserts
850 * as we emulate the behaviour of the (f)puts function.
852 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
853 dwFlags
|= FORMAT_MESSAGE_IGNORE_INSERTS
; // Ignore inserts for FormatMessage.
854 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
857 * Retrieve the message string without appending extra newlines.
858 * Wrap in SEH to protect from invalid string parameters.
862 dwLength
= FormatMessageW(dwFlags
,
870 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
879 // ASSERT(dwLength == 0);
883 // ASSERT(dwLength != 0);
885 /* lpMsgBuf is NULL-terminated by FormatMessage */
886 // Len = ConPuts(Stream, lpMsgBuf);
887 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
889 /* Fixup returned length in case of errors */
893 /* Free the buffer allocated by FormatMessage */
901 * @name ConMsgPrintf2V
902 * Formats and writes a message string to a stream.
904 * @remark For internal use only.
906 * @see ConMsgPrintfV()
910 IN PCON_STREAM Stream
,
912 IN LPCVOID lpSource OPTIONAL
,
913 IN DWORD dwMessageId
,
914 IN DWORD dwLanguageId
,
919 LPWSTR lpMsgBuf
= NULL
;
922 * Sanitize dwFlags. This version always ignores explicitly the inserts.
923 * The string that we will return to the user will not be pre-formatted.
925 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
926 dwFlags
|= FORMAT_MESSAGE_IGNORE_INSERTS
; // Ignore inserts for FormatMessage.
927 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
930 * Retrieve the message string without appending extra newlines.
931 * Wrap in SEH to protect from invalid string parameters.
935 dwLength
= FormatMessageW(dwFlags
,
943 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
952 // ASSERT(dwLength == 0);
956 // ASSERT(dwLength != 0);
958 /* lpMsgBuf is NULL-terminated by FormatMessage */
959 Len
= ConPrintfV(Stream
, lpMsgBuf
, args
);
960 // CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
962 /* Fixup returned length in case of errors */
966 /* Free the buffer allocated by FormatMessage */
974 * @name ConMsgPrintfV
975 * Formats and writes a message string to a stream. The function requires
976 * a message definition as input. The message definition can come from a
977 * buffer passed to the function. It can come from a message table resource
978 * in an already-loaded module, or the caller can ask the function to search
979 * the system's message table resource(s) for the message definition.
980 * Please refer to the Win32 FormatMessage() function for more details.
983 * Stream to which the write operation is issued.
986 * The formatting options, and how to interpret the @p lpSource parameter.
987 * See FormatMessage() for more details.
988 * The @b FORMAT_MESSAGE_ALLOCATE_BUFFER flag is always ignored.
990 * @param[in] lpSource
991 * The location of the message definition. The type of this parameter
992 * depends upon the settings in the @p dwFlags parameter.
994 * @param[in] dwMessageId
995 * The message identifier for the requested message. This parameter
996 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
998 * @param[in] dwLanguageId
999 * The language identifier for the requested message. This parameter
1000 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
1002 * @param[in] Arguments
1003 * Optional pointer to an array of values describing a variable number of
1004 * arguments, depending on the message string. Each argument is used to
1005 * replace an <em>insert sequence</em> in the message string.
1006 * By default, the @p Arguments parameter is of type @c va_list*, initialized
1007 * with va_start(). The state of the @c va_list argument is undefined upon
1008 * return from the function. To use the @c va_list again, destroy the variable
1009 * argument list pointer using va_end() and reinitialize it with va_start().
1010 * If you do not have a pointer of type @c va_list*, then specify the
1011 * @b FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
1012 * of @c DWORD_PTR values; those values are input to the message formatted
1013 * as the insert values. Each insert must have a corresponding element in
1017 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1018 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1019 * These sequences extend the standard <em>format specifiers</em> as they
1020 * allow to specify an <em>insert number</em> referring which precise value
1021 * given in arguments to use.
1024 * Numbers of characters successfully written to @p Stream.
1026 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1027 * <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage">FormatMessage() (on MSDN)</a>
1031 IN PCON_STREAM Stream
,
1033 IN LPCVOID lpSource OPTIONAL
,
1034 IN DWORD dwMessageId
,
1035 IN DWORD dwLanguageId
,
1036 IN
va_list *Arguments OPTIONAL
)
1040 LPWSTR lpMsgBuf
= NULL
;
1042 /* Sanitize dwFlags */
1043 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
1046 * Retrieve the message string without appending extra newlines.
1047 * Use the "safe" FormatMessage version (SEH-protected) to protect
1048 * from invalid string parameters.
1050 dwLength
= FormatMessageSafeW(dwFlags
,
1058 Len
= (INT
)dwLength
;
1062 // ASSERT(dwLength == 0);
1066 // ASSERT(dwLength != 0);
1068 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
1070 /* Fixup returned length in case of errors */
1074 /* Free the buffer allocated by FormatMessage */
1075 LocalFree(lpMsgBuf
);
1082 * @name ConMsgPrintf
1083 * Formats and writes a message string to a stream. The function requires
1084 * a message definition as input. The message definition can come from a
1085 * buffer passed to the function. It can come from a message table resource
1086 * in an already-loaded module, or the caller can ask the function to search
1087 * the system's message table resource(s) for the message definition.
1088 * Please refer to the Win32 FormatMessage() function for more details.
1091 * Stream to which the write operation is issued.
1093 * @param[in] dwFlags
1094 * The formatting options, and how to interpret the @p lpSource parameter.
1095 * See FormatMessage() for more details. The @b FORMAT_MESSAGE_ALLOCATE_BUFFER
1096 * and @b FORMAT_MESSAGE_ARGUMENT_ARRAY flags are always ignored.
1098 * @param[in] lpSource
1099 * The location of the message definition. The type of this parameter
1100 * depends upon the settings in the @p dwFlags parameter.
1102 * @param[in] dwMessageId
1103 * The message identifier for the requested message. This parameter
1104 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
1106 * @param[in] dwLanguageId
1107 * The language identifier for the requested message. This parameter
1108 * is ignored if @p dwFlags includes @b FORMAT_MESSAGE_FROM_STRING.
1111 * Additional arguments that can be expected by the function, depending
1112 * on the message string. Each argument is used to replace an
1113 * <em>insert sequence</em> in the message string.
1116 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1117 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1118 * These sequences extend the standard <em>format specifiers</em> as they
1119 * allow to specify an <em>insert number</em> referring which precise value
1120 * given in arguments to use.
1123 * Numbers of characters successfully written to @p Stream.
1125 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintfV(),
1126 * <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage">FormatMessage() (on MSDN)</a>
1131 IN PCON_STREAM Stream
,
1133 IN LPCVOID lpSource OPTIONAL
,
1134 IN DWORD dwMessageId
,
1135 IN DWORD dwLanguageId
,
1141 /* Sanitize dwFlags */
1142 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1144 va_start(args
, dwLanguageId
);
1145 Len
= ConMsgPrintfV(Stream
,
1157 * @name ConResMsgPrintfExV
1158 * Formats and writes a message string to a stream. The function requires
1159 * a message definition as input. Contrary to the ConMsg* or the Win32
1160 * FormatMessage() functions, the message definition comes from a resource
1161 * string table, much like the strings for ConResPrintf(), but is formatted
1162 * according to the rules of ConMsgPrintf().
1165 * Stream to which the write operation is issued.
1167 * @param[in] hInstance
1168 * Optional handle to an instance of the module whose executable file
1169 * contains the string resource. Can be set to NULL to get the handle
1170 * to the application itself.
1172 * @param[in] dwFlags
1173 * The formatting options, see FormatMessage() for more details.
1174 * The only valid flags are @b FORMAT_MESSAGE_ARGUMENT_ARRAY,
1175 * @b FORMAT_MESSAGE_IGNORE_INSERTS and @b FORMAT_MESSAGE_MAX_WIDTH_MASK.
1176 * All the other flags are internally overridden by the function
1177 * to implement its behaviour.
1180 * The identifier of the message string. The format string follows the
1181 * same specifications as the @a lpSource format string in ConMsgPrintf().
1183 * @param[in] LanguageId
1184 * The language identifier of the resource. If this parameter is
1185 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
1186 * associated with the calling thread is used. To specify a language other
1187 * than the current language, use the @c MAKELANGID macro to create this
1190 * @param[in] Arguments
1191 * Optional pointer to an array of values describing a variable number of
1192 * arguments, depending on the message string. Each argument is used to
1193 * replace an <em>insert sequence</em> in the message string.
1194 * By default, the @p Arguments parameter is of type @c va_list*, initialized
1195 * with va_start(). The state of the @c va_list argument is undefined upon
1196 * return from the function. To use the @c va_list again, destroy the variable
1197 * argument list pointer using va_end() and reinitialize it with va_start().
1198 * If you do not have a pointer of type @c va_list*, then specify the
1199 * @b FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
1200 * of @c DWORD_PTR values; those values are input to the message formatted
1201 * as the insert values. Each insert must have a corresponding element in
1205 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1206 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1207 * These sequences extend the standard <em>format specifiers</em> as they
1208 * allow to specify an <em>insert number</em> referring which precise value
1209 * given in arguments to use.
1212 * Numbers of characters successfully written to @p Stream.
1214 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1215 * <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage">FormatMessage() (on MSDN)</a>
1219 IN PCON_STREAM Stream
,
1220 IN HINSTANCE hInstance OPTIONAL
,
1223 IN LANGID LanguageId
,
1224 IN
va_list *Arguments OPTIONAL
)
1228 LPWSTR lpMsgBuf
= NULL
;
1229 WCHAR bufSrc
[CON_RC_STRING_MAX_SIZE
];
1231 /* Retrieve the string from the resource string table */
1232 // NOTE: We may use the special behaviour where nBufMaxSize == 0
1233 Len
= K32LoadStringExW(hInstance
, uID
, LanguageId
, bufSrc
, ARRAYSIZE(bufSrc
));
1237 /* Sanitize dwFlags */
1238 dwFlags
|= FORMAT_MESSAGE_ALLOCATE_BUFFER
; // Always allocate an internal buffer.
1240 /* The string has already been manually loaded */
1241 dwFlags
&= ~(FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_FROM_SYSTEM
);
1242 dwFlags
|= FORMAT_MESSAGE_FROM_STRING
;
1245 * Retrieve the message string without appending extra newlines.
1246 * Use the "safe" FormatMessage version (SEH-protected) to protect
1247 * from invalid string parameters.
1249 dwLength
= FormatMessageSafeW(dwFlags
,
1256 Len
= (INT
)dwLength
;
1260 // ASSERT(dwLength == 0);
1264 // ASSERT(dwLength != 0);
1266 CON_STREAM_WRITE2(Stream
, lpMsgBuf
, dwLength
, Len
);
1268 /* Fixup returned length in case of errors */
1272 /* Free the buffer allocated by FormatMessage */
1273 LocalFree(lpMsgBuf
);
1280 * @name ConResMsgPrintfV
1281 * Formats and writes a message string to a stream. The function requires
1282 * a message definition as input. Contrary to the ConMsg* or the Win32
1283 * FormatMessage() functions, the message definition comes from a resource
1284 * string table, much like the strings for ConResPrintf(), but is formatted
1285 * according to the rules of ConMsgPrintf().
1288 * Stream to which the write operation is issued.
1290 * @param[in] dwFlags
1291 * The formatting options, see FormatMessage() for more details.
1292 * The only valid flags are @b FORMAT_MESSAGE_ARGUMENT_ARRAY,
1293 * @b FORMAT_MESSAGE_IGNORE_INSERTS and @b FORMAT_MESSAGE_MAX_WIDTH_MASK.
1294 * All the other flags are internally overridden by the function
1295 * to implement its behaviour.
1298 * The identifier of the message string. The format string follows the
1299 * same specifications as the @a lpSource format string in ConMsgPrintf().
1301 * @param[in] Arguments
1302 * Optional pointer to an array of values describing a variable number of
1303 * arguments, depending on the message string. Each argument is used to
1304 * replace an <em>insert sequence</em> in the message string.
1305 * By default, the @p Arguments parameter is of type @c va_list*, initialized
1306 * with va_start(). The state of the @c va_list argument is undefined upon
1307 * return from the function. To use the @c va_list again, destroy the variable
1308 * argument list pointer using va_end() and reinitialize it with va_start().
1309 * If you do not have a pointer of type @c va_list*, then specify the
1310 * @b FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
1311 * of @c DWORD_PTR values; those values are input to the message formatted
1312 * as the insert values. Each insert must have a corresponding element in
1316 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1317 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1318 * These sequences extend the standard <em>format specifiers</em> as they
1319 * allow to specify an <em>insert number</em> referring which precise value
1320 * given in arguments to use.
1323 * Numbers of characters successfully written to @p Stream.
1325 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1326 * <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage">FormatMessage() (on MSDN)</a>
1330 IN PCON_STREAM Stream
,
1333 IN
va_list *Arguments OPTIONAL
)
1335 return ConResMsgPrintfExV(Stream
, NULL
/*GetModuleHandleW(NULL)*/,
1337 MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
),
1342 * @name ConResMsgPrintfEx
1343 * Formats and writes a message string to a stream. The function requires
1344 * a message definition as input. Contrary to the ConMsg* or the Win32
1345 * FormatMessage() functions, the message definition comes from a resource
1346 * string table, much like the strings for ConResPrintf(), but is formatted
1347 * according to the rules of ConMsgPrintf().
1350 * Stream to which the write operation is issued.
1352 * @param[in] hInstance
1353 * Optional handle to an instance of the module whose executable file
1354 * contains the string resource. Can be set to NULL to get the handle
1355 * to the application itself.
1357 * @param[in] dwFlags
1358 * The formatting options, see FormatMessage() for more details.
1359 * The only valid flags are @b FORMAT_MESSAGE_IGNORE_INSERTS and
1360 * @b FORMAT_MESSAGE_MAX_WIDTH_MASK. All the other flags are internally
1361 * overridden by the function to implement its behaviour.
1364 * The identifier of the message string. The format string follows the
1365 * same specifications as the @a lpSource format string in ConMsgPrintf().
1367 * @param[in] LanguageId
1368 * The language identifier of the resource. If this parameter is
1369 * <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
1370 * associated with the calling thread is used. To specify a language other
1371 * than the current language, use the @c MAKELANGID macro to create this
1375 * Additional arguments that can be expected by the function, depending
1376 * on the message string. Each argument is used to replace an
1377 * <em>insert sequence</em> in the message string.
1380 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1381 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1382 * These sequences extend the standard <em>format specifiers</em> as they
1383 * allow to specify an <em>insert number</em> referring which precise value
1384 * given in arguments to use.
1387 * Numbers of characters successfully written to @p Stream.
1389 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1390 * <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage">FormatMessage() (on MSDN)</a>
1395 IN PCON_STREAM Stream
,
1396 IN HINSTANCE hInstance OPTIONAL
,
1399 IN LANGID LanguageId
,
1405 /* Sanitize dwFlags */
1406 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1408 va_start(args
, LanguageId
);
1409 Len
= ConResMsgPrintfExV(Stream
,
1421 * @name ConResMsgPrintf
1422 * Formats and writes a message string to a stream. The function requires
1423 * a message definition as input. Contrary to the ConMsg* or the Win32
1424 * FormatMessage() functions, the message definition comes from a resource
1425 * string table, much like the strings for ConResPrintf(), but is formatted
1426 * according to the rules of ConMsgPrintf().
1429 * Stream to which the write operation is issued.
1431 * @param[in] dwFlags
1432 * The formatting options, see FormatMessage() for more details.
1433 * The only valid flags are @b FORMAT_MESSAGE_IGNORE_INSERTS and
1434 * @b FORMAT_MESSAGE_MAX_WIDTH_MASK. All the other flags are internally
1435 * overridden by the function to implement its behaviour.
1438 * The identifier of the message string. The format string follows the
1439 * same specifications as the @a lpSource format string in ConMsgPrintf().
1442 * Additional arguments that can be expected by the function, depending
1443 * on the message string. Each argument is used to replace an
1444 * <em>insert sequence</em> in the message string.
1447 * Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
1448 * the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
1449 * These sequences extend the standard <em>format specifiers</em> as they
1450 * allow to specify an <em>insert number</em> referring which precise value
1451 * given in arguments to use.
1454 * Numbers of characters successfully written to @p Stream.
1456 * @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
1457 * <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage">FormatMessage() (on MSDN)</a>
1462 IN PCON_STREAM Stream
,
1470 /* Sanitize dwFlags */
1471 dwFlags
&= ~FORMAT_MESSAGE_ARGUMENT_ARRAY
;
1473 va_start(args
, uID
);
1474 Len
= ConResMsgPrintfV(Stream
, dwFlags
, uID
, &args
);
1483 ConClearLine(IN PCON_STREAM Stream
)
1485 HANDLE hOutput
= ConStreamGetOSHandle(Stream
);
1488 * Erase the full line where the cursor is, and move
1489 * the cursor back to the beginning of the line.
1492 if (IsConsoleHandle(hOutput
))
1494 CONSOLE_SCREEN_BUFFER_INFO csbi
;
1497 GetConsoleScreenBufferInfo(hOutput
, &csbi
);
1499 csbi
.dwCursorPosition
.X
= 0;
1500 // csbi.dwCursorPosition.Y;
1502 FillConsoleOutputCharacterW(hOutput
, L
' ',
1504 csbi
.dwCursorPosition
,
1506 SetConsoleCursorPosition(hOutput
, csbi
.dwCursorPosition
);
1508 else if (IsTTYHandle(hOutput
))
1510 ConPuts(Stream
, L
"\x1B[2K\x1B[1G"); // FIXME: Just use WriteFile
1512 // else, do nothing for files