[CONUTILS] Diverse improvements: start doxygenating and add some resource messsage helper functions.

- Start to doxygenate the library, focusing in great details on the
  functions of the "outstream" module.
- Add a K32LoadStringEx function that expands (K32)LoadString by
  allowing a LanguageId parameter to be able to load strings from other
  languages than the current one.
- Add "ConResMsg*" helper functions to be able to (format and) print
  message strings with inserts that come *NOT* from a message table (as
  usual) *BUT* from resource string tables.
  Will be helpful for CORE-14265 in particular.

[CMD] Fix the call to ConMsgPrintfV().
This commit is contained in:
Hermès Bélusca-Maïto 2018-02-02 00:35:08 +01:00
parent 3f8788d6e5
commit f982d77b8a
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
14 changed files with 981 additions and 79 deletions

View file

@ -141,7 +141,7 @@ VOID __cdecl ConFormatMessage(PCON_STREAM Stream, DWORD MessageId, ...)
NULL, NULL,
MessageId, MessageId,
LANG_USER_DEFAULT, LANG_USER_DEFAULT,
arg_ptr); &arg_ptr);
va_end(arg_ptr); va_end(arg_ptr);
if (Len <= 0) if (Len <= 0)

View file

@ -8,6 +8,21 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file conutils.h
* @ingroup ConUtils
*
* @defgroup ConUtils ReactOS Console Utilities Library
*
* @brief This library contains common functions used in many places inside
* the ReactOS console utilities and the ReactOS Command-Line Interpreter.
* Most of these functions are related with internationalisation and
* the problem of correctly displaying Unicode text on the console.
* Besides those, helpful functions for retrieving strings and messages
* from application resources are provided, together with printf-like
* functionality.
**/
#ifndef __CONUTILS_H__ #ifndef __CONUTILS_H__
#define __CONUTILS_H__ #define __CONUTILS_H__

View file

@ -8,6 +8,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file instream.c
* @ingroup ConUtils
*
* @brief Console I/O utility API -- Input
**/
/* /*
* Enable this define if you want to only use CRT functions to output * Enable this define if you want to only use CRT functions to output
* UNICODE stream to the console, as in the way explained by * UNICODE stream to the console, as in the way explained by
@ -42,8 +49,4 @@
#include "stream_private.h" #include "stream_private.h"
/*
* Console I/O utility API -- Input
*/
/* EOF */ /* EOF */

View file

@ -8,6 +8,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file instream.h
* @ingroup ConUtils
*
* @brief Console I/O utility API -- Input
**/
#ifndef __INSTREAM_H__ #ifndef __INSTREAM_H__
#define __INSTREAM_H__ #define __INSTREAM_H__
@ -32,10 +39,6 @@ extern "C" {
// Shadow type, implementation-specific // Shadow type, implementation-specific
typedef struct _CON_STREAM CON_STREAM, *PCON_STREAM; typedef struct _CON_STREAM CON_STREAM, *PCON_STREAM;
/*
* Console I/O utility API -- Input
*/
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -8,6 +8,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file outstream.c
* @ingroup ConUtils
*
* @brief Console I/O utility API -- Output
**/
/* /*
* Enable this define if you want to only use CRT functions to output * Enable this define if you want to only use CRT functions to output
* UNICODE stream to the console, as in the way explained by * UNICODE stream to the console, as in the way explained by
@ -51,11 +58,30 @@
// #define MAX_MESSAGE_SIZE 512 // See shutdown... // #define MAX_MESSAGE_SIZE 512 // See shutdown...
/* /**
* Console I/O utility API -- Output * @name ConWrite
*/ * Writes a counted string to a stream.
*
// NOTE: Should be called with the stream locked. * @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] szStr
* Pointer to the counted string to write.
*
* @param[in] len
* Length of the string pointed by @p szStr, specified
* in number of characters.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @note
* This function is used as an internal function.
* Use the ConStreamWrite() function instead.
*
* @remark
* Should be called with the stream locked.
**/
INT INT
__stdcall __stdcall
ConWrite( ConWrite(
@ -339,6 +365,23 @@ do { \
#endif #endif
/**
* @name ConStreamWrite
* Writes a counted string to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] szStr
* Pointer to the counted string to write.
*
* @param[in] len
* Length of the string pointed by @p szStr, specified
* in number of characters.
*
* @return
* Numbers of characters successfully written to @p Stream.
**/
INT INT
ConStreamWrite( ConStreamWrite(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
@ -350,6 +393,24 @@ ConStreamWrite(
return Len; return Len;
} }
/**
* @name ConPuts
* Writes a NULL-terminated string to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] szStr
* Pointer to the NULL-terminated string to write.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @remark
* Contrary to the CRT puts() function, ConPuts() does not append
* a terminating new-line character. In this way it behaves more like
* the CRT fputs() function.
**/
INT INT
ConPuts( ConPuts(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
@ -367,11 +428,33 @@ ConPuts(
return Len; return Len;
} }
/**
* @name ConPrintfV
* Formats and writes a NULL-terminated string to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] szStr
* Pointer to the NULL-terminated format string, that follows the same
* specifications as the @a szStr format string in ConPrintf().
*
* @param[in] args
* Parameter describing a variable number of arguments,
* initialized with va_start(), that can be expected by the function,
* depending on the @p szStr format string. Each argument is used to
* replace a <em>format specifier</em> in the format string.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), printf(), vprintf()
**/
INT INT
ConPrintfV( ConPrintfV(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN LPWSTR szStr, IN LPWSTR szStr,
IN va_list args) // arg_ptr IN va_list args)
{ {
INT Len; INT Len;
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE]; WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
@ -396,6 +479,30 @@ ConPrintfV(
return Len; return Len;
} }
/**
* @name ConPrintf
* Formats and writes a NULL-terminated string to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] szStr
* Pointer to the NULL-terminated format string, that follows the same
* specifications as the @a format string in printf(). This string can
* optionally contain embedded <em>format specifiers</em> that are
* replaced by the values specified in subsequent additional arguments
* and formatted as requested.
*
* @param[in] ...
* Additional arguments that can be expected by the function, depending
* on the @p szStr format string. Each argument is used to replace a
* <em>format specifier</em> in the format string.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintfV(), printf(), vprintf()
**/
INT INT
__cdecl __cdecl
ConPrintf( ConPrintf(
@ -416,16 +523,47 @@ ConPrintf(
return Len; return Len;
} }
/**
* @name ConResPutsEx
* Writes a string resource to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] hInstance
* Optional handle to an instance of the module whose executable file
* contains the string resource. Can be set to NULL to get the handle
* to the application itself.
*
* @param[in] uID
* The identifier of the string to be written.
*
* @param[in] LanguageId
* The language identifier of the resource. If this parameter is
* <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
* associated with the calling thread is used. To specify a language other
* than the current language, use the @c MAKELANGID macro to create this
* parameter.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @remark
* Similarly to ConPuts(), no terminating new-line character is appended.
*
* @see ConPuts(), ConResPuts()
**/
INT INT
ConResPutsEx( ConResPutsEx(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL, IN HINSTANCE hInstance OPTIONAL,
IN UINT uID) IN UINT uID,
IN LANGID LanguageId)
{ {
INT Len; INT Len;
PWCHAR szStr = NULL; PWCHAR szStr = NULL;
Len = K32LoadStringW(hInstance, uID, (PWSTR)&szStr, 0); Len = K32LoadStringExW(hInstance, uID, LanguageId, (PWSTR)&szStr, 0);
if (szStr && Len) if (szStr && Len)
// Len = ConPuts(Stream, szStr); // Len = ConPuts(Stream, szStr);
CON_STREAM_WRITE2(Stream, szStr, Len, Len); CON_STREAM_WRITE2(Stream, szStr, Len, Len);
@ -437,59 +575,195 @@ ConResPutsEx(
return Len; return Len;
} }
/**
* @name ConResPuts
* Writes a string resource contained in the current application
* to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] uID
* The identifier of the string to be written.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @remark
* Similarly to ConPuts(), no terminating new-line character is appended.
*
* @see ConPuts(), ConResPutsEx()
**/
INT INT
ConResPuts( ConResPuts(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN UINT uID) IN UINT uID)
{ {
return ConResPutsEx(Stream, NULL /*GetModuleHandleW(NULL)*/, uID); return ConResPutsEx(Stream, NULL /*GetModuleHandleW(NULL)*/,
uID, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
} }
/**
* @name ConResPrintfExV
* Formats and writes a string resource to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] hInstance
* Optional handle to an instance of the module whose executable file
* contains the string resource. Can be set to NULL to get the handle
* to the application itself.
*
* @param[in] uID
* The identifier of the format string. The format string follows the
* same specifications as the @a szStr format string in ConPrintf().
*
* @param[in] LanguageId
* The language identifier of the resource. If this parameter is
* <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
* associated with the calling thread is used. To specify a language other
* than the current language, use the @c MAKELANGID macro to create this
* parameter.
*
* @param[in] args
* Parameter describing a variable number of arguments,
* initialized with va_start(), that can be expected by the function,
* depending on the @p szStr format string. Each argument is used to
* replace a <em>format specifier</em> in the format string.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintfEx(), ConResPrintfV(), ConResPrintf()
**/
INT INT
ConResPrintfExV( ConResPrintfExV(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL, IN HINSTANCE hInstance OPTIONAL,
IN UINT uID, IN UINT uID,
IN va_list args) // arg_ptr IN LANGID LanguageId,
IN va_list args)
{ {
INT Len; INT Len;
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE]; WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
// NOTE: We may use the special behaviour where nBufMaxSize == 0 // NOTE: We may use the special behaviour where nBufMaxSize == 0
Len = K32LoadStringW(hInstance, uID, bufSrc, ARRAYSIZE(bufSrc)); Len = K32LoadStringExW(hInstance, uID, LanguageId, bufSrc, ARRAYSIZE(bufSrc));
if (Len) if (Len)
Len = ConPrintfV(Stream, bufSrc, args); Len = ConPrintfV(Stream, bufSrc, args);
return Len; return Len;
} }
/**
* @name ConResPrintfV
* Formats and writes a string resource contained in the
* current application to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] uID
* The identifier of the format string. The format string follows the
* same specifications as the @a szStr format string in ConPrintf().
*
* @param[in] args
* Parameter describing a variable number of arguments,
* initialized with va_start(), that can be expected by the function,
* depending on the @p szStr format string. Each argument is used to
* replace a <em>format specifier</em> in the format string.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintfExV(), ConResPrintfEx(), ConResPrintf()
**/
INT INT
ConResPrintfV( ConResPrintfV(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN UINT uID, IN UINT uID,
IN va_list args) // arg_ptr IN va_list args)
{ {
return ConResPrintfExV(Stream, NULL /*GetModuleHandleW(NULL)*/, uID, args); return ConResPrintfExV(Stream, NULL /*GetModuleHandleW(NULL)*/,
uID, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
args);
} }
/**
* @name ConResPrintfEx
* Formats and writes a string resource to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] hInstance
* Optional handle to an instance of the module whose executable file
* contains the string resource. Can be set to NULL to get the handle
* to the application itself.
*
* @param[in] uID
* The identifier of the format string. The format string follows the
* same specifications as the @a szStr format string in ConPrintf().
*
* @param[in] LanguageId
* The language identifier of the resource. If this parameter is
* <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
* associated with the calling thread is used. To specify a language other
* than the current language, use the @c MAKELANGID macro to create this
* parameter.
*
* @param[in] ...
* Additional arguments that can be expected by the function, depending
* on the @p szStr format string. Each argument is used to replace a
* <em>format specifier</em> in the format string.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintfExV(), ConResPrintfV(), ConResPrintf()
**/
INT INT
__cdecl __cdecl
ConResPrintfEx( ConResPrintfEx(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL, IN HINSTANCE hInstance OPTIONAL,
IN UINT uID, IN UINT uID,
IN LANGID LanguageId,
...) ...)
{ {
INT Len; INT Len;
va_list args; va_list args;
va_start(args, uID); va_start(args, LanguageId);
Len = ConResPrintfExV(Stream, hInstance, uID, args); Len = ConResPrintfExV(Stream, hInstance, uID, LanguageId, args);
va_end(args); va_end(args);
return Len; return Len;
} }
/**
* @name ConResPrintf
* Formats and writes a string resource contained in the
* current application to a stream.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] uID
* The identifier of the format string. The format string follows the
* same specifications as the @a szStr format string in ConPrintf().
*
* @param[in] ...
* Additional arguments that can be expected by the function, depending
* on the @p szStr format string. Each argument is used to replace a
* <em>format specifier</em> in the format string.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintfExV(), ConResPrintfEx(), ConResPrintfV()
**/
INT INT
__cdecl __cdecl
ConResPrintf( ConResPrintf(
@ -507,6 +781,46 @@ ConResPrintf(
return Len; return Len;
} }
/**
* @name ConMsgPuts
* Writes a message string to a stream without formatting. The function
* requires a message definition as input. The message definition can come
* from a buffer passed to the function. It can come from a message table
* resource in an already-loaded module, or the caller can ask the function
* to search the system's message table resource(s) for the message definition.
* Please refer to the Win32 FormatMessage() function for more details.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] dwFlags
* The formatting options, and how to interpret the @p lpSource parameter.
* See FormatMessage() for more details. The @b@c FORMAT_MESSAGE_ALLOCATE_BUFFER
* and @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY flags are always ignored.
* The function implicitly uses the @b@c FORMAT_MESSAGE_IGNORE_INSERTS and
* @b@c FORMAT_MESSAGE_MAX_WIDTH_MASK flags to implement its behaviour.
*
* @param[in] lpSource
* The location of the message definition. The type of this parameter
* depends upon the settings in the @p dwFlags parameter.
*
* @param[in] dwMessageId
* The message identifier for the requested message. This parameter
* is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
*
* @param[in] dwLanguageId
* The language identifier for the requested message. This parameter
* is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @remark
* Similarly to ConPuts(), no terminating new-line character is appended.
*
* @see ConPuts(), ConResPuts() and associated functions,
* <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
**/
INT INT
ConMsgPuts( ConMsgPuts(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
@ -521,7 +835,7 @@ ConMsgPuts(
/* /*
* Sanitize dwFlags. This version always ignore explicitely the inserts * Sanitize dwFlags. This version always ignore explicitely the inserts
* as we emulate the behaviour of the *puts function. * as we emulate the behaviour of the (f)puts function.
*/ */
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer. dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage. dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage.
@ -540,7 +854,8 @@ ConMsgPuts(
dwMessageId, dwMessageId,
dwLanguageId, dwLanguageId,
(LPWSTR)&lpMsgBuf, (LPWSTR)&lpMsgBuf,
0, NULL); 0,
NULL);
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
@ -572,6 +887,14 @@ ConMsgPuts(
return Len; return Len;
} }
/**
* @name ConMsgPrintf2V
* Formats and writes a message string to a stream.
*
* @remark For internal use only.
*
* @see ConMsgPrintfV()
**/
INT INT
ConMsgPrintf2V( ConMsgPrintf2V(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
@ -579,7 +902,7 @@ ConMsgPrintf2V(
IN LPCVOID lpSource OPTIONAL, IN LPCVOID lpSource OPTIONAL,
IN DWORD dwMessageId, IN DWORD dwMessageId,
IN DWORD dwLanguageId, IN DWORD dwLanguageId,
IN va_list args) // arg_ptr IN va_list args)
{ {
INT Len; INT Len;
DWORD dwLength = 0; DWORD dwLength = 0;
@ -606,7 +929,8 @@ ConMsgPrintf2V(
dwMessageId, dwMessageId,
dwLanguageId, dwLanguageId,
(LPWSTR)&lpMsgBuf, (LPWSTR)&lpMsgBuf,
0, NULL); 0,
NULL);
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
@ -638,6 +962,63 @@ ConMsgPrintf2V(
return Len; return Len;
} }
/**
* @name ConMsgPrintfV
* Formats and writes a message string to a stream. The function requires
* a message definition as input. The message definition can come from a
* buffer passed to the function. It can come from a message table resource
* in an already-loaded module, or the caller can ask the function to search
* the system's message table resource(s) for the message definition.
* Please refer to the Win32 FormatMessage() function for more details.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] dwFlags
* The formatting options, and how to interpret the @p lpSource parameter.
* See FormatMessage() for more details. The @b@c FORMAT_MESSAGE_ALLOCATE_BUFFER
* flags is always ignored. The function implicitly uses the
* @b@c FORMAT_MESSAGE_MAX_WIDTH_MASK flag to implement its behaviour.
*
* @param[in] lpSource
* The location of the message definition. The type of this parameter
* depends upon the settings in the @p dwFlags parameter.
*
* @param[in] dwMessageId
* The message identifier for the requested message. This parameter
* is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
*
* @param[in] dwLanguageId
* The language identifier for the requested message. This parameter
* is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
*
* @param[in] Arguments
* Optional pointer to an array of values describing a variable number of
* arguments, depending on the message string. Each argument is used to
* replace an <em>insert sequence</em> in the message string.
* By default, the @p Arguments parameter is of type @c va_list*, initialized
* with va_start(). The state of the @c va_list argument is undefined upon
* return from the function. To use the @c va_list again, destroy the variable
* argument list pointer using va_end() and reinitialize it with va_start().
* If you do not have a pointer of type @c va_list*, then specify the
* @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
* of @c DWORD_PTR values; those values are input to the message formatted
* as the insert values. Each insert must have a corresponding element in
* the array.
*
* @remark
* Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
* the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
* These sequences extend the standard <em>format specifiers</em> as they
* allow to specify an <em>insert number</em> referring which precise value
* given in arguments to use.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
* <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
**/
INT INT
ConMsgPrintfV( ConMsgPrintfV(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
@ -645,7 +1026,7 @@ ConMsgPrintfV(
IN LPCVOID lpSource OPTIONAL, IN LPCVOID lpSource OPTIONAL,
IN DWORD dwMessageId, IN DWORD dwMessageId,
IN DWORD dwLanguageId, IN DWORD dwLanguageId,
IN va_list args) // arg_ptr IN va_list *Arguments OPTIONAL)
{ {
INT Len; INT Len;
DWORD dwLength = 0; DWORD dwLength = 0;
@ -653,13 +1034,9 @@ ConMsgPrintfV(
/* Sanitize dwFlags */ /* Sanitize dwFlags */
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer. dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
// dwFlags &= ~FORMAT_MESSAGE_IGNORE_INSERTS; // We always use arguments.
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY; // We always use arguments of type 'va_list'.
// //
// NOTE: Technique taken from eventvwr.c!GetMessageStringFromDll() // NOTE: Technique taken from eventvwr.c!GetMessageStringFromDll()
// //
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK; dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
/* /*
@ -672,7 +1049,8 @@ ConMsgPrintfV(
dwMessageId, dwMessageId,
dwLanguageId, dwLanguageId,
(LPWSTR)&lpMsgBuf, (LPWSTR)&lpMsgBuf,
0, &args); 0,
Arguments);
Len = (INT)dwLength; Len = (INT)dwLength;
@ -684,7 +1062,6 @@ ConMsgPrintfV(
{ {
// ASSERT(dwLength != 0); // ASSERT(dwLength != 0);
// Len = ConPrintfV(Stream, lpMsgBuf, args);
CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len); CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
/* Fixup returned length in case of errors */ /* Fixup returned length in case of errors */
@ -698,6 +1075,55 @@ ConMsgPrintfV(
return Len; return Len;
} }
/**
* @name ConMsgPrintf
* Formats and writes a message string to a stream. The function requires
* a message definition as input. The message definition can come from a
* buffer passed to the function. It can come from a message table resource
* in an already-loaded module, or the caller can ask the function to search
* the system's message table resource(s) for the message definition.
* Please refer to the Win32 FormatMessage() function for more details.
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] dwFlags
* The formatting options, and how to interpret the @p lpSource parameter.
* See FormatMessage() for more details. The @b@c FORMAT_MESSAGE_ALLOCATE_BUFFER
* and @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY flags are always ignored.
* The function implicitly uses the @b@c FORMAT_MESSAGE_MAX_WIDTH_MASK flag
* to implement its behaviour.
*
* @param[in] lpSource
* The location of the message definition. The type of this parameter
* depends upon the settings in the @p dwFlags parameter.
*
* @param[in] dwMessageId
* The message identifier for the requested message. This parameter
* is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
*
* @param[in] dwLanguageId
* The language identifier for the requested message. This parameter
* is ignored if @p dwFlags includes @b@c FORMAT_MESSAGE_FROM_STRING.
*
* @param[in] ...
* Additional arguments that can be expected by the function, depending
* on the message string. Each argument is used to replace an
* <em>insert sequence</em> in the message string.
*
* @remark
* Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
* the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
* These sequences extend the standard <em>format specifiers</em> as they
* allow to specify an <em>insert number</em> referring which precise value
* given in arguments to use.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintfV(),
* <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
**/
INT INT
__cdecl __cdecl
ConMsgPrintf( ConMsgPrintf(
@ -711,14 +1137,334 @@ ConMsgPrintf(
INT Len; INT Len;
va_list args; va_list args;
/* Sanitize dwFlags */
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
va_start(args, dwLanguageId); va_start(args, dwLanguageId);
// ConMsgPrintf2V
Len = ConMsgPrintfV(Stream, Len = ConMsgPrintfV(Stream,
dwFlags, dwFlags,
lpSource, lpSource,
dwMessageId, dwMessageId,
dwLanguageId, dwLanguageId,
args); &args);
va_end(args);
return Len;
}
/**
* @name ConResMsgPrintfExV
* Formats and writes a message string to a stream. The function requires
* a message definition as input. Contrary to the ConMsg* or the Win32
* FormatMessage() functions, the message definition comes from a resource
* string table, much like the strings for ConResPrintf(), but is formatted
* according to the rules of ConMsgPrintf().
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] hInstance
* Optional handle to an instance of the module whose executable file
* contains the string resource. Can be set to NULL to get the handle
* to the application itself.
*
* @param[in] dwFlags
* The formatting options, see FormatMessage() for more details.
* The only valid flags are @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY and
* @b@c FORMAT_MESSAGE_IGNORE_INSERTS. All the other flags are internally
* overridden by the function to implement its behaviour.
*
* @param[in] uID
* The identifier of the message string. The format string follows the
* same specifications as the @a lpSource format string in ConMsgPrintf().
*
* @param[in] LanguageId
* The language identifier of the resource. If this parameter is
* <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
* associated with the calling thread is used. To specify a language other
* than the current language, use the @c MAKELANGID macro to create this
* parameter.
*
* @param[in] args
* Parameter describing a variable number of arguments, initialized
* with va_start(), that can be expected by the function, depending
* on the message string. Each argument is used to replace an
* <em>insert sequence</em> in the message string.
*
* @remark
* Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
* the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
* These sequences extend the standard <em>format specifiers</em> as they
* allow to specify an <em>insert number</em> referring which precise value
* given in arguments to use.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
* <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
**/
INT
ConResMsgPrintfExV(
IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL,
IN DWORD dwFlags,
IN UINT uID,
IN LANGID LanguageId,
IN va_list *Arguments OPTIONAL)
{
INT Len;
DWORD dwLength = 0;
LPWSTR lpMsgBuf = NULL;
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
/* Retrieve the string from the resource string table */
// NOTE: We may use the special behaviour where nBufMaxSize == 0
Len = K32LoadStringExW(hInstance, uID, LanguageId, bufSrc, ARRAYSIZE(bufSrc));
if (Len == 0)
return Len;
/* Sanitize dwFlags */
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
//
// NOTE: Technique taken from eventvwr.c!GetMessageStringFromDll()
//
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
/* The string has already been manually loaded */
dwFlags &= ~(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM);
dwFlags |= FORMAT_MESSAGE_FROM_STRING;
/*
* Retrieve the message string without appending extra newlines.
* Use the "safe" FormatMessage version (SEH-protected) to protect
* from invalid string parameters.
*/
dwLength = FormatMessageSafeW(dwFlags,
bufSrc,
0, 0,
(LPWSTR)&lpMsgBuf,
0,
Arguments);
Len = (INT)dwLength;
if (!lpMsgBuf)
{
// ASSERT(dwLength == 0);
}
else
{
// ASSERT(dwLength != 0);
CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
/* Fixup returned length in case of errors */
if (Len < 0)
Len = 0;
/* Free the buffer allocated by FormatMessage */
LocalFree(lpMsgBuf);
}
return Len;
}
/**
* @name ConResMsgPrintfV
* Formats and writes a message string to a stream. The function requires
* a message definition as input. Contrary to the ConMsg* or the Win32
* FormatMessage() functions, the message definition comes from a resource
* string table, much like the strings for ConResPrintf(), but is formatted
* according to the rules of ConMsgPrintf().
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] dwFlags
* The formatting options, see FormatMessage() for more details.
* The only valid flags are @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY and
* @b@c FORMAT_MESSAGE_IGNORE_INSERTS. All the other flags are internally
* overridden by the function to implement its behaviour.
*
* @param[in] uID
* The identifier of the message string. The format string follows the
* same specifications as the @a lpSource format string in ConMsgPrintf().
*
* @param[in] Arguments
* Optional pointer to an array of values describing a variable number of
* arguments, depending on the message string. Each argument is used to
* replace an <em>insert sequence</em> in the message string.
* By default, the @p Arguments parameter is of type @c va_list*, initialized
* with va_start(). The state of the @c va_list argument is undefined upon
* return from the function. To use the @c va_list again, destroy the variable
* argument list pointer using va_end() and reinitialize it with va_start().
* If you do not have a pointer of type @c va_list*, then specify the
* @b@c FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array
* of @c DWORD_PTR values; those values are input to the message formatted
* as the insert values. Each insert must have a corresponding element in
* the array.
*
* @remark
* Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
* the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
* These sequences extend the standard <em>format specifiers</em> as they
* allow to specify an <em>insert number</em> referring which precise value
* given in arguments to use.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
* <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
**/
INT
ConResMsgPrintfV(
IN PCON_STREAM Stream,
IN DWORD dwFlags,
IN UINT uID,
IN va_list *Arguments OPTIONAL)
{
return ConResMsgPrintfExV(Stream, NULL /*GetModuleHandleW(NULL)*/,
dwFlags, uID,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
Arguments);
}
/**
* @name ConResMsgPrintfEx
* Formats and writes a message string to a stream. The function requires
* a message definition as input. Contrary to the ConMsg* or the Win32
* FormatMessage() functions, the message definition comes from a resource
* string table, much like the strings for ConResPrintf(), but is formatted
* according to the rules of ConMsgPrintf().
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] hInstance
* Optional handle to an instance of the module whose executable file
* contains the string resource. Can be set to NULL to get the handle
* to the application itself.
*
* @param[in] dwFlags
* The formatting options, see FormatMessage() for more details.
* The only valid flag is @b@c FORMAT_MESSAGE_IGNORE_INSERTS.
* All the other flags are internally overridden by the function
* to implement its behaviour.
*
* @param[in] uID
* The identifier of the message string. The format string follows the
* same specifications as the @a lpSource format string in ConMsgPrintf().
*
* @param[in] LanguageId
* The language identifier of the resource. If this parameter is
* <tt>MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)</tt>, the current language
* associated with the calling thread is used. To specify a language other
* than the current language, use the @c MAKELANGID macro to create this
* parameter.
*
* @param[in] ...
* Additional arguments that can be expected by the function, depending
* on the message string. Each argument is used to replace an
* <em>insert sequence</em> in the message string.
*
* @remark
* Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
* the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
* These sequences extend the standard <em>format specifiers</em> as they
* allow to specify an <em>insert number</em> referring which precise value
* given in arguments to use.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
* <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
**/
INT
__cdecl
ConResMsgPrintfEx(
IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL,
IN DWORD dwFlags,
IN UINT uID,
IN LANGID LanguageId,
...)
{
INT Len;
va_list args;
/* Sanitize dwFlags */
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
va_start(args, LanguageId);
Len = ConResMsgPrintfExV(Stream,
hInstance,
dwFlags,
uID,
LanguageId,
&args);
va_end(args);
return Len;
}
/**
* @name ConResMsgPrintf
* Formats and writes a message string to a stream. The function requires
* a message definition as input. Contrary to the ConMsg* or the Win32
* FormatMessage() functions, the message definition comes from a resource
* string table, much like the strings for ConResPrintf(), but is formatted
* according to the rules of ConMsgPrintf().
*
* @param[in] Stream
* Stream to which the write operation is issued.
*
* @param[in] dwFlags
* The formatting options, see FormatMessage() for more details.
* The only valid flag is @b@c FORMAT_MESSAGE_IGNORE_INSERTS.
* All the other flags are internally overridden by the function
* to implement its behaviour.
*
* @param[in] uID
* The identifier of the message string. The format string follows the
* same specifications as the @a lpSource format string in ConMsgPrintf().
*
* @param[in] ...
* Additional arguments that can be expected by the function, depending
* on the message string. Each argument is used to replace an
* <em>insert sequence</em> in the message string.
*
* @remark
* Contrary to printf(), ConPrintf(), ConResPrintf() and associated functions,
* the ConMsg* functions work on format strings that contain <em>insert sequences</em>.
* These sequences extend the standard <em>format specifiers</em> as they
* allow to specify an <em>insert number</em> referring which precise value
* given in arguments to use.
*
* @return
* Numbers of characters successfully written to @p Stream.
*
* @see ConPrintf(), ConResPrintf() and associated functions, ConMsgPrintf(),
* <a href="FormatMessage() (on MSDN)">https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx</a>
**/
INT
__cdecl
ConResMsgPrintf(
IN PCON_STREAM Stream,
IN DWORD dwFlags,
IN UINT uID,
...)
{
INT Len;
va_list args;
/* Sanitize dwFlags */
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
va_start(args, uID);
Len = ConResMsgPrintfV(Stream, dwFlags, uID, &args);
va_end(args); va_end(args);
return Len; return Len;

View file

@ -8,6 +8,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file outstream.h
* @ingroup ConUtils
*
* @brief Console I/O utility API -- Output
**/
#ifndef __OUTSTREAM_H__ #ifndef __OUTSTREAM_H__
#define __OUTSTREAM_H__ #define __OUTSTREAM_H__
@ -37,10 +44,6 @@ typedef struct _CON_STREAM CON_STREAM, *PCON_STREAM;
typedef INT (__stdcall *CON_WRITE_FUNC)(IN PCON_STREAM, IN PTCHAR, IN DWORD); typedef INT (__stdcall *CON_WRITE_FUNC)(IN PCON_STREAM, IN PTCHAR, IN DWORD);
/*
* Console I/O utility API -- Output
*/
INT INT
__stdcall __stdcall
ConWrite( ConWrite(
@ -63,7 +66,7 @@ INT
ConPrintfV( ConPrintfV(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN LPWSTR szStr, IN LPWSTR szStr,
IN va_list args); // arg_ptr IN va_list args);
INT INT
__cdecl __cdecl
@ -76,7 +79,8 @@ INT
ConResPutsEx( ConResPutsEx(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL, IN HINSTANCE hInstance OPTIONAL,
IN UINT uID); IN UINT uID,
IN LANGID LanguageId);
INT INT
ConResPuts( ConResPuts(
@ -88,13 +92,14 @@ ConResPrintfExV(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL, IN HINSTANCE hInstance OPTIONAL,
IN UINT uID, IN UINT uID,
IN va_list args); // arg_ptr IN LANGID LanguageId,
IN va_list args);
INT INT
ConResPrintfV( ConResPrintfV(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN UINT uID, IN UINT uID,
IN va_list args); // arg_ptr IN va_list args);
INT INT
__cdecl __cdecl
@ -102,6 +107,7 @@ ConResPrintfEx(
IN PCON_STREAM Stream, IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL, IN HINSTANCE hInstance OPTIONAL,
IN UINT uID, IN UINT uID,
IN LANGID LanguageId,
...); ...);
INT INT
@ -126,7 +132,7 @@ ConMsgPrintf2V(
IN LPCVOID lpSource OPTIONAL, IN LPCVOID lpSource OPTIONAL,
IN DWORD dwMessageId, IN DWORD dwMessageId,
IN DWORD dwLanguageId, IN DWORD dwLanguageId,
IN va_list args); // arg_ptr IN va_list args);
INT INT
ConMsgPrintfV( ConMsgPrintfV(
@ -135,7 +141,7 @@ ConMsgPrintfV(
IN LPCVOID lpSource OPTIONAL, IN LPCVOID lpSource OPTIONAL,
IN DWORD dwMessageId, IN DWORD dwMessageId,
IN DWORD dwLanguageId, IN DWORD dwLanguageId,
IN va_list args); // arg_ptr IN va_list *Arguments OPTIONAL);
INT INT
__cdecl __cdecl
@ -147,6 +153,40 @@ ConMsgPrintf(
IN DWORD dwLanguageId, IN DWORD dwLanguageId,
...); ...);
INT
ConResMsgPrintfExV(
IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL,
IN DWORD dwFlags,
IN UINT uID,
IN LANGID LanguageId,
IN va_list *Arguments OPTIONAL);
INT
ConResMsgPrintfV(
IN PCON_STREAM Stream,
IN DWORD dwFlags,
IN UINT uID,
IN va_list *Arguments OPTIONAL);
INT
__cdecl
ConResMsgPrintfEx(
IN PCON_STREAM Stream,
IN HINSTANCE hInstance OPTIONAL,
IN DWORD dwFlags,
IN UINT uID,
IN LANGID LanguageId,
...);
INT
__cdecl
ConResMsgPrintf(
IN PCON_STREAM Stream,
IN DWORD dwFlags,
IN UINT uID,
...);
VOID VOID

View file

@ -6,6 +6,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file pager.c
* @ingroup ConUtils
*
* @brief Console/terminal paging functionality.
**/
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */ /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
#define UNICODE #define UNICODE
#define _UNICODE #define _UNICODE

View file

@ -6,6 +6,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file pager.h
* @ingroup ConUtils
*
* @brief Console/terminal paging functionality.
**/
#ifndef __PAGER_H__ #ifndef __PAGER_H__
#define __PAGER_H__ #define __PAGER_H__

View file

@ -6,6 +6,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file screen.c
* @ingroup ConUtils
*
* @brief Console/terminal screen management.
**/
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */ /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
#define UNICODE #define UNICODE
#define _UNICODE #define _UNICODE

View file

@ -6,6 +6,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file screen.h
* @ingroup ConUtils
*
* @brief Console/terminal screen management.
**/
#ifndef __SCREEN_H__ #ifndef __SCREEN_H__
#define __SCREEN_H__ #define __SCREEN_H__

View file

@ -8,6 +8,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file stream.c
* @ingroup ConUtils
*
* @brief Console I/O streams
**/
/* /*
* Enable this define if you want to only use CRT functions to output * Enable this define if you want to only use CRT functions to output
* UNICODE stream to the console, as in the way explained by * UNICODE stream to the console, as in the way explained by
@ -37,10 +44,6 @@
#include "stream_private.h" #include "stream_private.h"
/*
* Console I/O streams
*/
/* /*
* Standard console streams, initialized by * Standard console streams, initialized by
* calls to ConStreamInit/ConInitStdStreams. * calls to ConStreamInit/ConInitStdStreams.

View file

@ -8,6 +8,13 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file stream.h
* @ingroup ConUtils
*
* @brief Console I/O streams
**/
#ifndef __STREAM_H__ #ifndef __STREAM_H__
#define __STREAM_H__ #define __STREAM_H__
@ -29,10 +36,6 @@
extern "C" { extern "C" {
#endif #endif
/*
* Console I/O streams
*/
/* /*
* See http://archives.miloush.net/michkap/archive/2009/08/14/9869928.html * See http://archives.miloush.net/michkap/archive/2009/08/14/9869928.html
* for more information. * for more information.

View file

@ -7,6 +7,14 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file utils.c
* @ingroup ConUtils
*
* @brief General-purpose utility functions (wrappers around
* or reimplementations of Win32 APIs).
**/
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */ /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
#define UNICODE #define UNICODE
#define _UNICODE #define _UNICODE
@ -24,11 +32,6 @@
// #include "conutils.h" // #include "conutils.h"
#include "utils.h" #include "utils.h"
/*
* General-purpose utility functions (wrappers around,
* or reimplementations of, Win32 APIs).
*/
#if 0 // The following function may be useful in the future... #if 0 // The following function may be useful in the future...
// Performs MultiByteToWideChar then WideCharToMultiByte . // Performs MultiByteToWideChar then WideCharToMultiByte .
@ -55,9 +58,10 @@ MultiByteToMultiByte(
*/ */
INT INT
WINAPI WINAPI
K32LoadStringW( K32LoadStringExW(
IN HINSTANCE hInstance OPTIONAL, IN HINSTANCE hInstance OPTIONAL,
IN UINT uID, IN UINT uID,
IN LANGID LanguageId,
OUT LPWSTR lpBuffer, OUT LPWSTR lpBuffer,
IN INT nBufferMax) IN INT nBufferMax)
{ {
@ -71,11 +75,10 @@ K32LoadStringW(
/* Use LOWORD (incremented by 1) as ResourceID */ /* Use LOWORD (incremented by 1) as ResourceID */
/* There are always blocks of 16 strings */ /* There are always blocks of 16 strings */
// FindResourceExW(hInstance, RT_STRING, name, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); hrsrc = FindResourceExW(hInstance,
// NOTE: Instead of using LANG_NEUTRAL, one might use LANG_USER_DEFAULT... (LPCWSTR)RT_STRING,
hrsrc = FindResourceW(hInstance,
MAKEINTRESOURCEW((LOWORD(uID) >> 4) + 1), MAKEINTRESOURCEW((LOWORD(uID) >> 4) + 1),
(LPWSTR)RT_STRING); LanguageId);
if (!hrsrc) return 0; if (!hrsrc) return 0;
hmem = LoadResource(hInstance, hrsrc); hmem = LoadResource(hInstance, hrsrc);
@ -118,6 +121,20 @@ K32LoadStringW(
return i; return i;
} }
INT
WINAPI
K32LoadStringW(
IN HINSTANCE hInstance OPTIONAL,
IN UINT uID,
OUT LPWSTR lpBuffer,
IN INT nBufferMax)
{
// NOTE: Instead of using LANG_NEUTRAL, one might use LANG_USER_DEFAULT...
return K32LoadStringExW(hInstance, uID,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
lpBuffer, nBufferMax);
}
/* /*
* "Safe" version of FormatMessageW, that does not crash if a malformed * "Safe" version of FormatMessageW, that does not crash if a malformed
* source string is retrieved and then being used for formatting. * source string is retrieved and then being used for formatting.
@ -194,18 +211,50 @@ FormatMessageSafeW(
return dwLength; return dwLength;
} }
/**
* @name IsTTYHandle
* Checks whether a handle refers to a valid TTY object.
* A TTY object may be a console or a "communications" (e.g. serial) port.
*
* @param[in] hHandle
* Handle to the TTY object to check for.
*
* @return
* @b@c TRUE when the handle refers to a valid TTY object,
* @b@c FALSE if it does not.
*
* @remark
* This test is more general than IsConsoleHandle() as it is not limited
* to Win32 console objects only.
*
* @see IsConsoleHandle()
**/
BOOL BOOL
IsTTYHandle(IN HANDLE hHandle) IsTTYHandle(IN HANDLE hHandle)
{ {
/* /*
* More general test than IsConsoleHandle. Consoles, as well as * More general test than IsConsoleHandle(). Consoles, as well as serial
* serial ports, etc... verify this test, but only consoles verify * (communications) ports, etc... verify this test, but only consoles
* the IsConsoleHandle test: indeed the latter checks whether * verify the IsConsoleHandle() test: indeed the latter checks whether
* the handle is really handled by the console subsystem. * the handle is really handled by the console subsystem.
*/ */
return ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) == FILE_TYPE_CHAR); return ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) == FILE_TYPE_CHAR);
} }
/**
* @name IsConsoleHandle
* Checks whether a handle refers to a valid Win32 console object.
*
* @param[in] hHandle
* Handle to the Win32 console object to check for:
* console input buffer, console output buffer.
*
* @return
* @b@c TRUE when the handle refers to a valid Win32 console object,
* @b@c FALSE if it does not.
*
* @see IsTTYHandle()
**/
BOOL BOOL
IsConsoleHandle(IN HANDLE hHandle) IsConsoleHandle(IN HANDLE hHandle)
{ {

View file

@ -7,6 +7,14 @@
* Copyright 2017-2018 Hermes Belusca-Maito * Copyright 2017-2018 Hermes Belusca-Maito
*/ */
/**
* @file utils.h
* @ingroup ConUtils
*
* @brief General-purpose utility functions (wrappers around
* or reimplementations of Win32 APIs).
**/
#ifndef __UTILS_H__ #ifndef __UTILS_H__
#define __UTILS_H__ #define __UTILS_H__
@ -20,10 +28,14 @@
extern "C" { extern "C" {
#endif #endif
/* INT
* General-purpose utility functions (wrappers around, WINAPI
* or reimplementations of, Win32 APIs). K32LoadStringExW(
*/ IN HINSTANCE hInstance OPTIONAL,
IN UINT uID,
IN LANGID LanguageId,
OUT LPWSTR lpBuffer,
IN INT nBufferMax);
INT INT
WINAPI WINAPI