mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 07:46:29 +00:00
[CONUTILS]: Create a C library for console output/input functions, last-error messages display, etc. to be used for all of our internal command-line utilities. Useless user32.dll dependencies are removed thanks to this lib. Currently only output functions are supported.
CORE-10504 [EVENTCREATE]: Adapt EventCreate to use ConUtils library, as an example of how to use this library. svn path=/trunk/; revision=72913
This commit is contained in:
parent
b881e7c859
commit
89db25b0b1
6 changed files with 1063 additions and 68 deletions
|
@ -1,11 +1,14 @@
|
||||||
|
|
||||||
PROJECT(eventcreate)
|
PROJECT(eventcreate)
|
||||||
|
|
||||||
|
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
||||||
|
|
||||||
## The message string templates are in ANSI to reduce binary size
|
## The message string templates are in ANSI to reduce binary size
|
||||||
add_message_headers(ANSI evtmsgstr.mc)
|
add_message_headers(ANSI evtmsgstr.mc)
|
||||||
|
|
||||||
add_executable(eventcreate eventcreate.c eventcreate.rc)
|
add_executable(eventcreate eventcreate.c eventcreate.rc)
|
||||||
set_module_type(eventcreate win32cui UNICODE)
|
set_module_type(eventcreate win32cui UNICODE)
|
||||||
add_dependencies(eventcreate evtmsgstr)
|
add_dependencies(eventcreate evtmsgstr)
|
||||||
add_importlibs(eventcreate advapi32 user32 msvcrt kernel32)
|
target_link_libraries(eventcreate conutils ${PSEH_LIB})
|
||||||
|
add_importlibs(eventcreate advapi32 msvcrt kernel32)
|
||||||
add_cd_file(TARGET eventcreate DESTINATION reactos/system32 FOR all)
|
add_cd_file(TARGET eventcreate DESTINATION reactos/system32 FOR all)
|
||||||
|
|
|
@ -80,9 +80,10 @@
|
||||||
|
|
||||||
#include <windef.h>
|
#include <windef.h>
|
||||||
#include <winbase.h>
|
#include <winbase.h>
|
||||||
#include <winuser.h>
|
|
||||||
#include <winreg.h>
|
#include <winreg.h>
|
||||||
|
|
||||||
|
#include <conutils.h>
|
||||||
|
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
|
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
@ -107,56 +108,15 @@
|
||||||
#define APPLICATION_NAME L"EventCreate"
|
#define APPLICATION_NAME L"EventCreate"
|
||||||
|
|
||||||
|
|
||||||
VOID PrintStringV(LPWSTR szStr, va_list args)
|
|
||||||
{
|
|
||||||
WCHAR bufFormatted[RC_STRING_MAX_SIZE];
|
|
||||||
CHAR bufFormattedOem[RC_STRING_MAX_SIZE];
|
|
||||||
|
|
||||||
_vsnwprintf(bufFormatted, ARRAYSIZE(bufFormatted), szStr, args);
|
|
||||||
|
|
||||||
CharToOemW(bufFormatted, bufFormattedOem);
|
|
||||||
// puts(bufFormattedOem);
|
|
||||||
fputs(bufFormattedOem, stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PrintString(LPWSTR szStr, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, szStr);
|
|
||||||
PrintStringV(szStr, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PrintResourceStringV(UINT uID, va_list args)
|
|
||||||
{
|
|
||||||
WCHAR bufSrc[RC_STRING_MAX_SIZE];
|
|
||||||
|
|
||||||
LoadStringW(GetModuleHandleW(NULL), uID, bufSrc, ARRAYSIZE(bufSrc));
|
|
||||||
PrintStringV(bufSrc, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PrintResourceString(UINT uID, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, uID);
|
|
||||||
PrintResourceStringV(uID, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PrintError(DWORD dwError)
|
VOID PrintError(DWORD dwError)
|
||||||
{
|
{
|
||||||
LPWSTR lpMsgBuf = NULL;
|
|
||||||
|
|
||||||
if (dwError == ERROR_SUCCESS)
|
if (dwError == ERROR_SUCCESS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
ConMsgPrintf(StdErr,
|
||||||
NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
(LPWSTR)&lpMsgBuf, 0, NULL);
|
NULL, dwError, LANG_USER_DEFAULT);
|
||||||
PrintString(L"%s\n", lpMsgBuf);
|
ConPrintf(StdErr, L"\n");
|
||||||
LocalFree(lpMsgBuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -594,7 +554,7 @@ Finalize:
|
||||||
if (LogNameValid && !FoundLog)
|
if (LogNameValid && !FoundLog)
|
||||||
{
|
{
|
||||||
/* We have specified a log but it does not exist! */
|
/* We have specified a log but it does not exist! */
|
||||||
PrintResourceString(IDS_LOG_NOT_FOUND, EventLogName);
|
ConResPrintf(StdErr, IDS_LOG_NOT_FOUND, EventLogName);
|
||||||
goto Quit;
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,7 +574,7 @@ Finalize:
|
||||||
if (/* LogSourceValid && */ FoundSource && SourceAlreadyExists)
|
if (/* LogSourceValid && */ FoundSource && SourceAlreadyExists)
|
||||||
{
|
{
|
||||||
/* The source is in another log than the specified one */
|
/* The source is in another log than the specified one */
|
||||||
PrintResourceString(IDS_SOURCE_EXISTS, LogNameErr);
|
ConResPrintf(StdErr, IDS_SOURCE_EXISTS, LogNameErr);
|
||||||
goto Quit;
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,7 +594,7 @@ Finalize:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* This is NOT a custom source, we must return an error! */
|
/* This is NOT a custom source, we must return an error! */
|
||||||
PrintResourceString(IDS_SOURCE_NOT_CUSTOM);
|
ConResPrintf(StdErr, IDS_SOURCE_NOT_CUSTOM);
|
||||||
goto Quit;
|
goto Quit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,7 +605,7 @@ Finalize:
|
||||||
if (!LogNameValid /* && !FoundLog */)
|
if (!LogNameValid /* && !FoundLog */)
|
||||||
{
|
{
|
||||||
/* The log name is not specified, we cannot create the source */
|
/* The log name is not specified, we cannot create the source */
|
||||||
PrintResourceString(IDS_SOURCE_NOCREATE);
|
ConResPrintf(StdErr, IDS_SOURCE_NOCREATE);
|
||||||
goto Quit;
|
goto Quit;
|
||||||
}
|
}
|
||||||
else // LogNameValid && FoundLog
|
else // LogNameValid && FoundLog
|
||||||
|
@ -667,7 +627,7 @@ Finalize:
|
||||||
if (lRet != ERROR_SUCCESS)
|
if (lRet != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
PrintError(lRet);
|
PrintError(lRet);
|
||||||
PrintString(L"Impossible to create the source `%s' for log `%s'!\n",
|
ConPrintf(StdErr, L"Impossible to create the source `%s' for log `%s'!\n",
|
||||||
EventLogSource, EventLogName);
|
EventLogSource, EventLogName);
|
||||||
goto Quit;
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
@ -1044,15 +1004,15 @@ PrintParserError(PARSER_ERROR Error, ...)
|
||||||
if (Error < ARRAYSIZE(ErrorIDs))
|
if (Error < ARRAYSIZE(ErrorIDs))
|
||||||
{
|
{
|
||||||
va_start(args, Error);
|
va_start(args, Error);
|
||||||
PrintResourceStringV(ErrorIDs[Error], args);
|
ConResPrintfV(StdErr, ErrorIDs[Error], args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
if (Error != Success)
|
if (Error != Success)
|
||||||
PrintResourceString(IDS_USAGE);
|
ConResPrintf(StdErr, IDS_USAGE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PrintString(L"PARSER: Unknown error %d\n", Error);
|
ConPrintf(StdErr, L"PARSER: Unknown error %d\n", Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,6 +1103,9 @@ int wmain(int argc, WCHAR* argv[])
|
||||||
#define OPT_PASSWD (Options[3])
|
#define OPT_PASSWD (Options[3])
|
||||||
#define OPT_EVTID (Options[8])
|
#define OPT_EVTID (Options[8])
|
||||||
|
|
||||||
|
/* Initialize the Console Standard Streams */
|
||||||
|
ConInitStdStreams();
|
||||||
|
|
||||||
/* Parse command line for options */
|
/* Parse command line for options */
|
||||||
if (!DoParse(argc, argv, Options, ARRAYSIZE(Options), PrintParserError))
|
if (!DoParse(argc, argv, Options, ARRAYSIZE(Options), PrintParserError))
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -1158,7 +1121,7 @@ int wmain(int argc, WCHAR* argv[])
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintResourceString(IDS_HELP);
|
ConResPrintf(StdOut, IDS_HELP);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1166,19 +1129,19 @@ int wmain(int argc, WCHAR* argv[])
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
// TODO: Implement!
|
||||||
if (szSystem)
|
if (szSystem)
|
||||||
PrintResourceString(IDS_SWITCH_UNIMPLEMENTED, OPT_SYSTEM.OptionStr);
|
ConResPrintf(StdOut, IDS_SWITCH_UNIMPLEMENTED, OPT_SYSTEM.OptionStr);
|
||||||
if (szDomainUser)
|
if (szDomainUser)
|
||||||
PrintResourceString(IDS_SWITCH_UNIMPLEMENTED, OPT_USER.OptionStr);
|
ConResPrintf(StdOut, IDS_SWITCH_UNIMPLEMENTED, OPT_USER.OptionStr);
|
||||||
if (szPassword)
|
if (szPassword)
|
||||||
PrintResourceString(IDS_SWITCH_UNIMPLEMENTED, OPT_PASSWD.OptionStr);
|
ConResPrintf(StdOut, IDS_SWITCH_UNIMPLEMENTED, OPT_PASSWD.OptionStr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ulEventIdentifier < EVENT_ID_MIN || ulEventIdentifier > EVENT_ID_MAX)
|
if (ulEventIdentifier < EVENT_ID_MIN || ulEventIdentifier > EVENT_ID_MAX)
|
||||||
{
|
{
|
||||||
/* Invalid event identifier */
|
/* Invalid event identifier */
|
||||||
PrintResourceString(IDS_BADSYNTAX_7, OPT_EVTID.OptionStr, EVENT_ID_MIN, EVENT_ID_MAX);
|
ConResPrintf(StdErr, IDS_BADSYNTAX_7, OPT_EVTID.OptionStr, EVENT_ID_MIN, EVENT_ID_MAX);
|
||||||
PrintResourceString(IDS_USAGE);
|
ConResPrintf(StdErr, IDS_USAGE);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1275,18 +1238,18 @@ int wmain(int argc, WCHAR* argv[])
|
||||||
if (!Success)
|
if (!Success)
|
||||||
{
|
{
|
||||||
PrintError(GetLastError());
|
PrintError(GetLastError());
|
||||||
PrintString(L"Failed to report event!\n");
|
ConPrintf(StdErr, L"Failed to report event!\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Show success */
|
/* Show success */
|
||||||
PrintString(L"\n");
|
ConPrintf(StdOut, L"\n");
|
||||||
if (!szEventSource)
|
if (!szEventSource)
|
||||||
PrintResourceString(IDS_SUCCESS_1, szEventType, szLogName);
|
ConResPrintf(StdOut, IDS_SUCCESS_1, szEventType, szLogName);
|
||||||
else if (!szLogName)
|
else if (!szLogName)
|
||||||
PrintResourceString(IDS_SUCCESS_2, szEventType, szEventSource);
|
ConResPrintf(StdOut, IDS_SUCCESS_2, szEventType, szEventSource);
|
||||||
else
|
else
|
||||||
PrintResourceString(IDS_SUCCESS_3, szEventType, szLogName, szEventSource);
|
ConResPrintf(StdOut, IDS_SUCCESS_3, szEventType, szLogName, szEventSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, pUserToken);
|
HeapFree(GetProcessHeap(), 0, pUserToken);
|
||||||
|
@ -1294,7 +1257,7 @@ int wmain(int argc, WCHAR* argv[])
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PrintError(GetLastError());
|
PrintError(GetLastError());
|
||||||
PrintString(L"GetUserToken() failed!\n");
|
ConPrintf(StdErr, L"GetUserToken() failed!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close the event log */
|
/* Close the event log */
|
||||||
|
|
|
@ -7,6 +7,7 @@ if(CMAKE_CROSSCOMPILING)
|
||||||
add_subdirectory(3rdparty)
|
add_subdirectory(3rdparty)
|
||||||
add_subdirectory(atl)
|
add_subdirectory(atl)
|
||||||
add_subdirectory(comsupp)
|
add_subdirectory(comsupp)
|
||||||
|
add_subdirectory(conutils)
|
||||||
add_subdirectory(cportlib)
|
add_subdirectory(cportlib)
|
||||||
add_subdirectory(crt)
|
add_subdirectory(crt)
|
||||||
add_subdirectory(cryptlib)
|
add_subdirectory(cryptlib)
|
||||||
|
|
8
reactos/sdk/lib/conutils/CMakeLists.txt
Normal file
8
reactos/sdk/lib/conutils/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
## Temporary HACK before we cleanly support UNICODE functions
|
||||||
|
add_definitions(-DUNICODE -D_UNICODE)
|
||||||
|
|
||||||
|
add_library(conutils conutils.c)
|
||||||
|
add_dependencies(conutils psdk)
|
||||||
|
target_link_libraries(conutils ${PSEH_LIB})
|
||||||
|
# add_importlibs(conutils msvcrt kernel32) ## ntdll
|
767
reactos/sdk/lib/conutils/conutils.c
Normal file
767
reactos/sdk/lib/conutils/conutils.c
Normal file
|
@ -0,0 +1,767 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Console Utilities Library
|
||||||
|
* FILE: sdk/lib/conutils/conutils.c
|
||||||
|
* PURPOSE: Provides simple ready-to-use abstraction wrappers around
|
||||||
|
* CRT streams or Win32 console API I/O functions, to deal with
|
||||||
|
* i18n + Unicode related problems.
|
||||||
|
* PROGRAMMERS: - Hermes Belusca-Maito (for making this library);
|
||||||
|
* - All programmers who wrote the different console applications
|
||||||
|
* from which I took those functions and improved them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable this define if you want to only use CRT functions to output
|
||||||
|
* UNICODE stream to the console, as in the way explained by
|
||||||
|
* http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
|
||||||
|
*/
|
||||||
|
/** NOTE: Experimental! Don't use USE_CRT yet because output to console is a bit broken **/
|
||||||
|
// #define USE_CRT
|
||||||
|
|
||||||
|
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||||
|
|
||||||
|
#ifdef USE_CRT
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <io.h>
|
||||||
|
#endif /* defined(USE_CRT) */
|
||||||
|
|
||||||
|
#include <windef.h>
|
||||||
|
#include <winbase.h>
|
||||||
|
|
||||||
|
#include <winnls.h>
|
||||||
|
#include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
|
||||||
|
|
||||||
|
#include <wincon.h> // Console APIs (only if kernel32 support included)
|
||||||
|
|
||||||
|
#include "conutils.h"
|
||||||
|
#include <strsafe.h>
|
||||||
|
|
||||||
|
/* PSEH for SEH Support */
|
||||||
|
#include <pseh/pseh2.h>
|
||||||
|
|
||||||
|
|
||||||
|
// #define RC_STRING_MAX_SIZE 4096
|
||||||
|
// #define MAX_BUFFER_SIZE 4096
|
||||||
|
// #define OUTPUT_BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* General-purpose utility functions (wrappers around,
|
||||||
|
* or reimplementations of, Win32 APIs).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'LoadStringW' API ripped from user32.dll to remove
|
||||||
|
* any dependency of this library from user32.dll
|
||||||
|
*/
|
||||||
|
INT
|
||||||
|
WINAPI
|
||||||
|
K32LoadStringW(
|
||||||
|
IN HINSTANCE hInstance OPTIONAL,
|
||||||
|
IN UINT uID,
|
||||||
|
OUT LPWSTR lpBuffer,
|
||||||
|
IN INT nBufferMax)
|
||||||
|
{
|
||||||
|
HRSRC hrsrc;
|
||||||
|
HGLOBAL hmem;
|
||||||
|
WCHAR *p;
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
if (!lpBuffer)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Use LOWORD (incremented by 1) as ResourceID */
|
||||||
|
/* There are always blocks of 16 strings */
|
||||||
|
// FindResourceExW(hInstance, RT_STRING, name, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
|
||||||
|
// NOTE: Instead of using LANG_NEUTRAL, one might use LANG_USER_DEFAULT...
|
||||||
|
hrsrc = FindResourceW(hInstance,
|
||||||
|
MAKEINTRESOURCEW((LOWORD(uID) >> 4) + 1),
|
||||||
|
(LPWSTR)RT_STRING);
|
||||||
|
if (!hrsrc) return 0;
|
||||||
|
|
||||||
|
hmem = LoadResource(hInstance, hrsrc);
|
||||||
|
if (!hmem) return 0;
|
||||||
|
|
||||||
|
p = LockResource(hmem);
|
||||||
|
// FreeResource(hmem);
|
||||||
|
|
||||||
|
/* Find the string we're looking for */
|
||||||
|
uID &= 0x000F; /* Position in the block, same as % 16 */
|
||||||
|
for (i = 0; i < uID; i++)
|
||||||
|
p += *p + 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If nBufferMax == 0, then return a read-only pointer
|
||||||
|
* to the resource itself in lpBuffer it is assumed that
|
||||||
|
* lpBuffer is actually a (LPWSTR *).
|
||||||
|
*/
|
||||||
|
if (nBufferMax == 0)
|
||||||
|
{
|
||||||
|
*((LPWSTR*)lpBuffer) = p + 1;
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = min(nBufferMax - 1, *p);
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
memcpy(lpBuffer, p + 1, i * sizeof(WCHAR));
|
||||||
|
lpBuffer[i] = L'\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nBufferMax > 1)
|
||||||
|
{
|
||||||
|
lpBuffer[0] = L'\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Safe" version of FormatMessageW, that does not crash if a malformed
|
||||||
|
* source string is retrieved and then being used for formatting.
|
||||||
|
* It basically wraps calls to FormatMessageW within SEH.
|
||||||
|
*/
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
FormatMessageSafeW(
|
||||||
|
IN DWORD dwFlags,
|
||||||
|
IN LPCVOID lpSource OPTIONAL,
|
||||||
|
IN DWORD dwMessageId,
|
||||||
|
IN DWORD dwLanguageId,
|
||||||
|
OUT LPWSTR lpBuffer,
|
||||||
|
IN DWORD nSize,
|
||||||
|
IN va_list *Arguments OPTIONAL)
|
||||||
|
{
|
||||||
|
DWORD dwLength = 0;
|
||||||
|
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Retrieve the message string. Wrap in SEH
|
||||||
|
* to protect from invalid string parameters.
|
||||||
|
*/
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
dwLength = FormatMessageW(dwFlags,
|
||||||
|
lpSource,
|
||||||
|
dwMessageId,
|
||||||
|
dwLanguageId,
|
||||||
|
lpBuffer,
|
||||||
|
nSize,
|
||||||
|
Arguments);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
dwLength = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An exception occurred while calling FormatMessage, this is usually
|
||||||
|
* the sign that a parameter was invalid, either 'lpBuffer' was NULL
|
||||||
|
* but we did not pass the flag FORMAT_MESSAGE_ALLOCATE_BUFFER, or the
|
||||||
|
* array pointer 'Arguments' was NULL or did not contain enough elements,
|
||||||
|
* and we did not pass the flag FORMAT_MESSAGE_IGNORE_INSERTS, and the
|
||||||
|
* message string expected too many inserts.
|
||||||
|
* In this last case only, we can call again FormatMessage but ignore
|
||||||
|
* explicitely the inserts. The string that we will return to the user
|
||||||
|
* will not be pre-formatted.
|
||||||
|
*/
|
||||||
|
if (((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) || lpBuffer) &&
|
||||||
|
!(dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS))
|
||||||
|
{
|
||||||
|
/* Remove any possible harmful flags and always ignore inserts */
|
||||||
|
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
|
||||||
|
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||||
|
|
||||||
|
/* If this call also throws an exception, we are really dead */
|
||||||
|
dwLength = FormatMessageW(dwFlags,
|
||||||
|
lpSource,
|
||||||
|
dwMessageId,
|
||||||
|
dwLanguageId,
|
||||||
|
lpBuffer,
|
||||||
|
nSize,
|
||||||
|
NULL /* Arguments */);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
}
|
||||||
|
_SEH2_FINALLY
|
||||||
|
{
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
return dwLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Console I/O streams
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _CON_STREAM
|
||||||
|
{
|
||||||
|
CON_WRITE_FUNC WriteFunc;
|
||||||
|
|
||||||
|
#ifdef USE_CRT
|
||||||
|
FILE* fStream;
|
||||||
|
#else
|
||||||
|
HANDLE hHandle;
|
||||||
|
BOOL bIsConsole; // TRUE if 'hHandle' refers to a console,
|
||||||
|
// in which case I/O UNICODE is directly used.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'Mode' flag is used to know the translation mode
|
||||||
|
* when 'hHandle' refers to a file or a pipe.
|
||||||
|
*/
|
||||||
|
CON_STREAM_MODE Mode;
|
||||||
|
UINT CodePage; // Used to convert UTF-16 text to some ANSI codepage.
|
||||||
|
#endif /* defined(USE_CRT) */
|
||||||
|
} CON_STREAM, *PCON_STREAM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Standard console streams, initialized by
|
||||||
|
* calls to ConStreamInit/ConInitStdStreams.
|
||||||
|
*/
|
||||||
|
#if 0 // FIXME!
|
||||||
|
CON_STREAM StdStreams[3] =
|
||||||
|
{
|
||||||
|
{0}, // StdIn // TODO!
|
||||||
|
{0}, // StdOut
|
||||||
|
{0}, // StdErr
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
CON_STREAM csStdIn;
|
||||||
|
CON_STREAM csStdOut;
|
||||||
|
CON_STREAM csStdErr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
BOOL
|
||||||
|
IsConsoleHandle(IN HANDLE hHandle)
|
||||||
|
{
|
||||||
|
DWORD dwMode;
|
||||||
|
|
||||||
|
/* Check whether the handle may be that of a console... */
|
||||||
|
if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It may be. Perform another test. The idea comes from the
|
||||||
|
* MSDN description of the WriteConsole API:
|
||||||
|
*
|
||||||
|
* "WriteConsole fails if it is used with a standard handle
|
||||||
|
* that is redirected to a file. If an application processes
|
||||||
|
* multilingual output that can be redirected, determine whether
|
||||||
|
* the output handle is a console handle (one method is to call
|
||||||
|
* the GetConsoleMode function and check whether it succeeds).
|
||||||
|
* If the handle is a console handle, call WriteConsole. If the
|
||||||
|
* handle is not a console handle, the output is redirected and
|
||||||
|
* you should call WriteFile to perform the I/O."
|
||||||
|
*/
|
||||||
|
return GetConsoleMode(hHandle, &dwMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
ConStreamInitEx(
|
||||||
|
OUT PCON_STREAM Stream,
|
||||||
|
IN PVOID Handle,
|
||||||
|
IN CON_STREAM_MODE Mode,
|
||||||
|
IN CON_WRITE_FUNC WriteFunc OPTIONAL)
|
||||||
|
{
|
||||||
|
/* Parameters validation */
|
||||||
|
if (!Stream || !Handle)
|
||||||
|
return FALSE;
|
||||||
|
if (Mode > UTF8Text)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Use the default 'ConWrite' helper if nothing is specified */
|
||||||
|
Stream->WriteFunc = (WriteFunc ? WriteFunc : ConWrite);
|
||||||
|
|
||||||
|
#ifdef USE_CRT
|
||||||
|
{
|
||||||
|
/* Lookup table to convert CON_STREAM_MODE to CRT mode */
|
||||||
|
static int ConToCRTMode[] =
|
||||||
|
{
|
||||||
|
_O_BINARY, // Binary (untranslated)
|
||||||
|
_O_TEXT, // AnsiText (translated)
|
||||||
|
_O_WTEXT, // WideText (UTF16 with BOM; translated)
|
||||||
|
_O_U16TEXT, // UTF16Text (UTF16 without BOM; translated)
|
||||||
|
_O_U8TEXT, // UTF8Text (UTF8 without BOM; translated)
|
||||||
|
};
|
||||||
|
|
||||||
|
Stream->fStream = (FILE*)Handle;
|
||||||
|
|
||||||
|
/* Set the correct file translation mode */
|
||||||
|
// NOTE: May the translated mode be cached somehow?
|
||||||
|
// NOTE2: We may also call IsConsoleHandle to directly set the mode to
|
||||||
|
// _O_U16TEXT if it's ok??
|
||||||
|
if (Mode < ARRAYSIZE(ConToCRTMode))
|
||||||
|
_setmode(_fileno(Stream->fStream), ConToCRTMode[Mode]);
|
||||||
|
else
|
||||||
|
_setmode(_fileno(Stream->fStream), _O_TEXT); // Default to ANSI text.
|
||||||
|
// _setmode returns the previous mode, or -1 if failure.
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
Stream->hHandle = (HANDLE)Handle;
|
||||||
|
Stream->bIsConsole = IsConsoleHandle(Stream->hHandle);
|
||||||
|
Stream->Mode = Mode;
|
||||||
|
|
||||||
|
// NOTE: Or recompute them @ each ConWrite call?
|
||||||
|
if (Mode == AnsiText)
|
||||||
|
Stream->CodePage = GetConsoleOutputCP(); // CP_ACP, CP_OEMCP
|
||||||
|
else if (Mode == UTF8Text)
|
||||||
|
Stream->CodePage = CP_UTF8;
|
||||||
|
else // Mode == Binary, WideText, UTF16Text
|
||||||
|
Stream->CodePage = 0;
|
||||||
|
|
||||||
|
#endif /* defined(USE_CRT) */
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
ConStreamInit(
|
||||||
|
OUT PCON_STREAM Stream,
|
||||||
|
IN PVOID Handle,
|
||||||
|
IN CON_STREAM_MODE Mode)
|
||||||
|
{
|
||||||
|
return ConStreamInitEx(Stream, Handle, Mode, ConWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Console I/O utility API
|
||||||
|
* (for the moment, only Output)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ConWriteStr
|
||||||
|
INT
|
||||||
|
__stdcall
|
||||||
|
ConWrite(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN PTCHAR szStr,
|
||||||
|
IN DWORD len)
|
||||||
|
{
|
||||||
|
#ifndef USE_CRT
|
||||||
|
DWORD TotalLen = len, dwNumBytes = 0;
|
||||||
|
PVOID p;
|
||||||
|
|
||||||
|
// CHAR strOem[CON_RC_STRING_MAX_SIZE]; // Some static buffer...
|
||||||
|
|
||||||
|
/* If we do not write anything, just return */
|
||||||
|
if (!szStr || len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check whether we are writing to a console */
|
||||||
|
// if (IsConsoleHandle(Stream->hHandle))
|
||||||
|
if (Stream->bIsConsole)
|
||||||
|
{
|
||||||
|
// TODO: Check if (ConStream->Mode == WideText or UTF16Text) ??
|
||||||
|
WriteConsole(Stream->hHandle, szStr, len, &dwNumBytes, NULL);
|
||||||
|
return (INT)dwNumBytes; // Really return the number of chars written.
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are redirected and writing to a file or pipe instead of the console.
|
||||||
|
* Convert the string from TCHARs to the desired output format, if the two differ.
|
||||||
|
*
|
||||||
|
* Implementation NOTE:
|
||||||
|
* MultiByteToWideChar (resp. WideCharToMultiByte) are equivalent to
|
||||||
|
* OemToCharBuffW (resp. CharToOemBuffW), but the latters uselessly
|
||||||
|
* depend on user32.dll, while MultiByteToWideChar and WideCharToMultiByte
|
||||||
|
* only need kernel32.dll.
|
||||||
|
*/
|
||||||
|
if ((Stream->Mode == WideText) || (Stream->Mode == UTF16Text))
|
||||||
|
{
|
||||||
|
#ifndef _UNICODE
|
||||||
|
WCHAR *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
len = (DWORD)MultiByteToWideChar(/* Stream->CodePage */ CP_THREAD_ACP /* CP_ACP -- CP_OEMCP */,
|
||||||
|
0, szStr, (INT)len, buffer, (INT)len);
|
||||||
|
szStr = (PVOID)buffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find any newline character in the buffer,
|
||||||
|
* write the part BEFORE the newline, then write
|
||||||
|
* a carriage-return + newline, and then write
|
||||||
|
* the remaining part of the buffer.
|
||||||
|
*
|
||||||
|
* This fixes output in files and serial console.
|
||||||
|
*/
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
/* Loop until we find a \r or \n character */
|
||||||
|
// FIXME: What about the pair \r\n ?
|
||||||
|
p = szStr;
|
||||||
|
while (len > 0 && *(PWCHAR)p != L'\r' && *(PWCHAR)p != L'\n')
|
||||||
|
{
|
||||||
|
/* Advance one character */
|
||||||
|
p = (PVOID)((PWCHAR)p + 1);
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write everything up to \r or \n */
|
||||||
|
dwNumBytes = ((PWCHAR)p - (PWCHAR)szStr) * sizeof(WCHAR);
|
||||||
|
WriteFile(Stream->hHandle, szStr, dwNumBytes, &dwNumBytes, NULL);
|
||||||
|
|
||||||
|
/* If we hit \r or \n ... */
|
||||||
|
if (len > 0 && (*(PWCHAR)p == L'\r' || *(PWCHAR)p == L'\n'))
|
||||||
|
{
|
||||||
|
/* ... send a carriage-return + newline sequence and skip \r or \n */
|
||||||
|
WriteFile(Stream->hHandle, L"\r\n", 2 * sizeof(WCHAR), &dwNumBytes, NULL);
|
||||||
|
szStr = (PVOID)((PWCHAR)p + 1);
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _UNICODE
|
||||||
|
HeapFree(GetProcessHeap(), 0, buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if ((Stream->Mode == UTF8Text) || (Stream->Mode == AnsiText))
|
||||||
|
{
|
||||||
|
#ifdef _UNICODE
|
||||||
|
// NOTE: MB_LEN_MAX defined either in limits.h or in stdlib.h .
|
||||||
|
CHAR *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * MB_LEN_MAX);
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
len = WideCharToMultiByte(Stream->CodePage, 0, szStr, len, buffer, len * MB_LEN_MAX, NULL, NULL);
|
||||||
|
szStr = (PVOID)buffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find any newline character in the buffer,
|
||||||
|
* write the part BEFORE the newline, then write
|
||||||
|
* a carriage-return + newline, and then write
|
||||||
|
* the remaining part of the buffer.
|
||||||
|
*
|
||||||
|
* This fixes output in files and serial console.
|
||||||
|
*/
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
/* Loop until we find a \r or \n character */
|
||||||
|
// FIXME: What about the pair \r\n ?
|
||||||
|
p = szStr;
|
||||||
|
while (len > 0 && *(PCHAR)p != '\r' && *(PCHAR)p != '\n')
|
||||||
|
{
|
||||||
|
/* Advance one character */
|
||||||
|
p = (PVOID)((PCHAR)p + 1);
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write everything up to \r or \n */
|
||||||
|
dwNumBytes = ((PCHAR)p - (PCHAR)szStr) * sizeof(CHAR);
|
||||||
|
WriteFile(Stream->hHandle, szStr, dwNumBytes, &dwNumBytes, NULL);
|
||||||
|
|
||||||
|
/* If we hit \r or \n ... */
|
||||||
|
if (len > 0 && (*(PCHAR)p == '\r' || *(PCHAR)p == '\n'))
|
||||||
|
{
|
||||||
|
/* ... send a carriage-return + newline sequence and skip \r or \n */
|
||||||
|
WriteFile(Stream->hHandle, "\r\n", 2, &dwNumBytes, NULL);
|
||||||
|
szStr = (PVOID)((PCHAR)p + 1);
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _UNICODE
|
||||||
|
HeapFree(GetProcessHeap(), 0, buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else // if (Stream->Mode == Binary)
|
||||||
|
{
|
||||||
|
WriteFile(Stream->hHandle, szStr, len, &dwNumBytes, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME!
|
||||||
|
return (INT)TotalLen;
|
||||||
|
|
||||||
|
#else /* defined(USE_CRT) */
|
||||||
|
|
||||||
|
DWORD total = len;
|
||||||
|
DWORD written = 0;
|
||||||
|
|
||||||
|
/* If we do not write anything, just return */
|
||||||
|
if (!szStr || len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
|
||||||
|
* and http://archives.miloush.net/michkap/archive/2009/08/14/9869928.html
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
// _setmode(_fileno(Stream->fStream), _O_U16TEXT); // Normally, already set before.
|
||||||
|
#if 1
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
written = wprintf(L"%.*s", total, szStr);
|
||||||
|
if (written < total)
|
||||||
|
{
|
||||||
|
if (written == 0)
|
||||||
|
{
|
||||||
|
fputwc(*szStr, Stream->fStream);
|
||||||
|
written++;
|
||||||
|
}
|
||||||
|
|
||||||
|
szStr += written;
|
||||||
|
total -= written;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (INT)len;
|
||||||
|
#else
|
||||||
|
return fwrite(szStr, sizeof(*szStr), len, Stream->fStream);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* defined(USE_CRT) */
|
||||||
|
}
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConPrintfV(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN LPWSTR szStr,
|
||||||
|
IN va_list args) // arg_ptr
|
||||||
|
{
|
||||||
|
INT Len;
|
||||||
|
WCHAR bufFormatted[CON_RC_STRING_MAX_SIZE];
|
||||||
|
|
||||||
|
#if 1 /////////////////////////////////////////////////////////////////////// 0
|
||||||
|
PWSTR pEnd;
|
||||||
|
StringCchVPrintfExW(bufFormatted, ARRAYSIZE(bufFormatted), &pEnd, NULL, 0, szStr, args);
|
||||||
|
Len = pEnd - bufFormatted;
|
||||||
|
#else
|
||||||
|
StringCchVPrintfW(bufFormatted, ARRAYSIZE(bufFormatted), szStr, args);
|
||||||
|
Len = wcslen(bufFormatted);
|
||||||
|
#endif
|
||||||
|
Len = Stream->WriteFunc(Stream, bufFormatted, Len);
|
||||||
|
|
||||||
|
/* Fixup returned length in case of errors */
|
||||||
|
if (Len < 0)
|
||||||
|
Len = 0;
|
||||||
|
|
||||||
|
return Len;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConPrintf(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN LPWSTR szStr,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
INT Len;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
Len = vfwprintf(stdout, szMsgBuf, arg_ptr); // vfprintf for direct ANSI
|
||||||
|
// or: Len = vwprintf(szMsgBuf, arg_ptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// StringCchPrintfW
|
||||||
|
va_start(args, szStr);
|
||||||
|
Len = ConPrintfV(Stream, szStr, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return Len;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConResPrintfV(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN UINT uID,
|
||||||
|
IN va_list args) // arg_ptr
|
||||||
|
{
|
||||||
|
INT Len;
|
||||||
|
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
|
||||||
|
|
||||||
|
// NOTE: We may use the special behaviour where nBufMaxSize == 0
|
||||||
|
Len = K32LoadStringW(GetModuleHandleW(NULL), uID, bufSrc, ARRAYSIZE(bufSrc));
|
||||||
|
if (Len)
|
||||||
|
Len = ConPrintfV(Stream, bufSrc, args);
|
||||||
|
|
||||||
|
return Len;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConResPrintf(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN UINT uID,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
INT Len;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, uID);
|
||||||
|
Len = ConResPrintfV(Stream, uID, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return Len;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConMsgPrintf2V(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN DWORD dwFlags,
|
||||||
|
IN LPCVOID lpSource OPTIONAL,
|
||||||
|
IN DWORD dwMessageId,
|
||||||
|
IN DWORD dwLanguageId,
|
||||||
|
IN va_list args) // arg_ptr
|
||||||
|
{
|
||||||
|
INT Len;
|
||||||
|
DWORD dwLength = 0;
|
||||||
|
LPWSTR lpMsgBuf = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanitize dwFlags. This version always ignore explicitely the inserts.
|
||||||
|
* The string that we will return to the user will not be pre-formatted.
|
||||||
|
*/
|
||||||
|
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
|
||||||
|
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage.
|
||||||
|
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
|
||||||
|
|
||||||
|
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve the message string without appending extra newlines.
|
||||||
|
* Wrap in SEH to protect from invalid string parameters.
|
||||||
|
*/
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
dwLength = FormatMessageW(dwFlags,
|
||||||
|
lpSource,
|
||||||
|
dwMessageId,
|
||||||
|
dwLanguageId,
|
||||||
|
(LPWSTR)&lpMsgBuf,
|
||||||
|
0, NULL);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
Len = (INT)dwLength;
|
||||||
|
|
||||||
|
if (!lpMsgBuf)
|
||||||
|
{
|
||||||
|
// ASSERT(dwLength == 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ASSERT(dwLength != 0);
|
||||||
|
|
||||||
|
/* lpMsgBuf is NULL-terminated by FormatMessage */
|
||||||
|
Len = ConPrintfV(Stream, lpMsgBuf, args);
|
||||||
|
// Len = Stream->WriteFunc(Stream, lpMsgBuf, dwLength);
|
||||||
|
|
||||||
|
/* Fixup returned length in case of errors */
|
||||||
|
if (Len < 0)
|
||||||
|
Len = 0;
|
||||||
|
|
||||||
|
/* Free the buffer allocated by FormatMessage */
|
||||||
|
LocalFree(lpMsgBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Len;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConMsgPrintfV(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN DWORD dwFlags,
|
||||||
|
IN LPCVOID lpSource OPTIONAL,
|
||||||
|
IN DWORD dwMessageId,
|
||||||
|
IN DWORD dwLanguageId,
|
||||||
|
IN va_list args) // arg_ptr
|
||||||
|
{
|
||||||
|
INT Len;
|
||||||
|
DWORD dwLength = 0;
|
||||||
|
LPWSTR lpMsgBuf = NULL;
|
||||||
|
|
||||||
|
/* Sanitize dwFlags */
|
||||||
|
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()
|
||||||
|
//
|
||||||
|
|
||||||
|
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve the message string without appending extra newlines.
|
||||||
|
* Use the "safe" FormatMessage version (SEH-protected) to protect
|
||||||
|
* from invalid string parameters.
|
||||||
|
*/
|
||||||
|
dwLength = FormatMessageSafeW(dwFlags,
|
||||||
|
lpSource,
|
||||||
|
dwMessageId,
|
||||||
|
dwLanguageId,
|
||||||
|
(LPWSTR)&lpMsgBuf,
|
||||||
|
0, &args);
|
||||||
|
|
||||||
|
Len = (INT)dwLength;
|
||||||
|
|
||||||
|
if (!lpMsgBuf)
|
||||||
|
{
|
||||||
|
// ASSERT(dwLength == 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ASSERT(dwLength != 0);
|
||||||
|
|
||||||
|
// Len = ConPrintfV(Stream, lpMsgBuf, args);
|
||||||
|
Len = Stream->WriteFunc(Stream, lpMsgBuf, dwLength);
|
||||||
|
|
||||||
|
/* Fixup returned length in case of errors */
|
||||||
|
if (Len < 0)
|
||||||
|
Len = 0;
|
||||||
|
|
||||||
|
/* Free the buffer allocated by FormatMessage */
|
||||||
|
LocalFree(lpMsgBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Len;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConMsgPrintf(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN DWORD dwFlags,
|
||||||
|
IN LPCVOID lpSource OPTIONAL,
|
||||||
|
IN DWORD dwMessageId,
|
||||||
|
IN DWORD dwLanguageId,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
INT Len;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, dwLanguageId);
|
||||||
|
// ConMsgPrintf2V
|
||||||
|
Len = ConMsgPrintfV(Stream,
|
||||||
|
dwFlags,
|
||||||
|
lpSource,
|
||||||
|
dwMessageId,
|
||||||
|
dwLanguageId,
|
||||||
|
args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return Len;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// TODO: Add Console paged-output printf & ResPrintf functions!
|
||||||
|
//
|
253
reactos/sdk/lib/conutils/conutils.h
Normal file
253
reactos/sdk/lib/conutils/conutils.h
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Console Utilities Library
|
||||||
|
* FILE: sdk/lib/conutils/conutils.h
|
||||||
|
* PURPOSE: Provides simple ready-to-use abstraction wrappers around
|
||||||
|
* CRT streams or Win32 console API I/O functions, to deal with
|
||||||
|
* i18n + Unicode related problems.
|
||||||
|
* PROGRAMMERS: - Hermes Belusca-Maito (for making this library);
|
||||||
|
* - All programmers who wrote the different console applications
|
||||||
|
* from which I took those functions and improved them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CONUTILS_H__
|
||||||
|
#define __CONUTILS_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable this define if you want to only use CRT functions to output
|
||||||
|
* UNICODE stream to the console, as in the way explained by
|
||||||
|
* http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
|
||||||
|
*/
|
||||||
|
/** NOTE: Experimental! Don't use USE_CRT yet because output to console is a bit broken **/
|
||||||
|
// #define USE_CRT
|
||||||
|
|
||||||
|
#ifndef _UNICODE
|
||||||
|
#error The ConUtils library only supports compilation with _UNICODE defined, at the moment!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* General-purpose utility functions (wrappers around,
|
||||||
|
* or reimplementations of, Win32 APIs).
|
||||||
|
*/
|
||||||
|
|
||||||
|
INT
|
||||||
|
WINAPI
|
||||||
|
K32LoadStringW(
|
||||||
|
IN HINSTANCE hInstance OPTIONAL,
|
||||||
|
IN UINT uID,
|
||||||
|
OUT LPWSTR lpBuffer,
|
||||||
|
IN INT nBufferMax);
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
FormatMessageSafeW(
|
||||||
|
IN DWORD dwFlags,
|
||||||
|
IN LPCVOID lpSource OPTIONAL,
|
||||||
|
IN DWORD dwMessageId,
|
||||||
|
IN DWORD dwLanguageId,
|
||||||
|
OUT LPWSTR lpBuffer,
|
||||||
|
IN DWORD nSize,
|
||||||
|
IN va_list *Arguments OPTIONAL);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Console I/O streams
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See http://archives.miloush.net/michkap/archive/2009/08/14/9869928.html
|
||||||
|
* for more information.
|
||||||
|
*/
|
||||||
|
typedef enum _CON_STREAM_MODE
|
||||||
|
{
|
||||||
|
Binary = 0, // #define _O_BINARY 0x8000 // file mode is binary (untranslated)
|
||||||
|
// #define _O_RAW _O_BINARY
|
||||||
|
AnsiText, // #define _O_TEXT 0x4000 // file mode is text (translated) -- "ANSI"
|
||||||
|
WideText, // #define _O_WTEXT 0x10000 // file mode is UTF16 with BOM (translated) -- "Unicode" of Windows
|
||||||
|
UTF16Text, // #define _O_U16TEXT 0x20000 // file mode is UTF16 no BOM (translated) -- "" ""
|
||||||
|
UTF8Text, // #define _O_U8TEXT 0x40000 // file mode is UTF8 no BOM (translated)
|
||||||
|
} CON_STREAM_MODE, *PCON_STREAM_MODE;
|
||||||
|
|
||||||
|
// Shadow type, implementation-specific
|
||||||
|
typedef struct _CON_STREAM CON_STREAM, *PCON_STREAM;
|
||||||
|
|
||||||
|
// Stream, szStr, len
|
||||||
|
typedef INT (__stdcall *CON_WRITE_FUNC)(IN PCON_STREAM, IN PTCHAR, IN DWORD);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Standard console streams, initialized by
|
||||||
|
* calls to ConStreamInit/ConInitStdStreams.
|
||||||
|
*/
|
||||||
|
#if 0 // FIXME!
|
||||||
|
extern CON_STREAM StdStreams[3];
|
||||||
|
#define StdIn (&StdStreams[0]) // TODO!
|
||||||
|
#define StdOut (&StdStreams[1])
|
||||||
|
#define StdErr (&StdStreams[2])
|
||||||
|
#else
|
||||||
|
extern CON_STREAM csStdIn;
|
||||||
|
extern CON_STREAM csStdOut;
|
||||||
|
extern CON_STREAM csStdErr;
|
||||||
|
#define StdIn (&csStdIn) // TODO!
|
||||||
|
#define StdOut (&csStdOut)
|
||||||
|
#define StdErr (&csStdErr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// static
|
||||||
|
BOOL
|
||||||
|
IsConsoleHandle(IN HANDLE hHandle);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
ConStreamInitEx(
|
||||||
|
OUT PCON_STREAM Stream,
|
||||||
|
IN PVOID Handle,
|
||||||
|
IN CON_STREAM_MODE Mode,
|
||||||
|
IN CON_WRITE_FUNC WriteFunc OPTIONAL);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
ConStreamInit(
|
||||||
|
OUT PCON_STREAM Stream,
|
||||||
|
IN PVOID Handle,
|
||||||
|
IN CON_STREAM_MODE Mode);
|
||||||
|
|
||||||
|
|
||||||
|
/* Console Standard Streams initialization helpers */
|
||||||
|
#ifdef _UNICODE
|
||||||
|
|
||||||
|
#ifdef USE_CRT
|
||||||
|
#define ConInitStdStreams() \
|
||||||
|
do { \
|
||||||
|
ConStreamInit(StdOut, stdout, UTF16Text); \
|
||||||
|
ConStreamInit(StdErr, stderr, UTF16Text); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define ConInitStdStreams() \
|
||||||
|
do { \
|
||||||
|
ConStreamInit(StdOut, GetStdHandle(STD_OUTPUT_HANDLE), UTF16Text); \
|
||||||
|
ConStreamInit(StdErr, GetStdHandle(STD_ERROR_HANDLE) , UTF16Text); \
|
||||||
|
} while(0)
|
||||||
|
#endif /* defined(USE_CRT) */
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef USE_CRT
|
||||||
|
#define ConInitStdStreams() \
|
||||||
|
do { \
|
||||||
|
ConStreamInit(StdOut, stdout, AnsiText); \
|
||||||
|
ConStreamInit(StdErr, stderr, AnsiText); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define ConInitStdStreams() \
|
||||||
|
do { \
|
||||||
|
ConStreamInit(StdOut, GetStdHandle(STD_OUTPUT_HANDLE), AnsiText); \
|
||||||
|
ConStreamInit(StdErr, GetStdHandle(STD_ERROR_HANDLE) , AnsiText); \
|
||||||
|
} while(0)
|
||||||
|
#endif /* defined(USE_CRT) */
|
||||||
|
|
||||||
|
#endif /* defined(_UNICODE) */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Console I/O utility API
|
||||||
|
* (for the moment, only Output)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** Redundant defines to keep compat with existing code for now... ***/
|
||||||
|
/*** Must be removed later! ***/
|
||||||
|
|
||||||
|
#define CON_RC_STRING_MAX_SIZE 4096
|
||||||
|
#define MAX_BUFFER_SIZE 4096 // some exotic programs set it to 5024
|
||||||
|
#define OUTPUT_BUFFER_SIZE 4096
|
||||||
|
// MAX_STRING_SIZE
|
||||||
|
|
||||||
|
// #define MAX_MESSAGE_SIZE 512
|
||||||
|
|
||||||
|
|
||||||
|
INT
|
||||||
|
__stdcall
|
||||||
|
ConWrite(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN PTCHAR szStr,
|
||||||
|
IN DWORD len);
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConPrintfV(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN LPWSTR szStr,
|
||||||
|
IN va_list args); // arg_ptr
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConPrintf(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN LPWSTR szStr,
|
||||||
|
...);
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConResPrintfV(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN UINT uID,
|
||||||
|
IN va_list args); // arg_ptr
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConResPrintf(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN UINT uID,
|
||||||
|
...);
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConMsgPrintf2V(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN DWORD dwFlags,
|
||||||
|
IN LPCVOID lpSource OPTIONAL,
|
||||||
|
IN DWORD dwMessageId,
|
||||||
|
IN DWORD dwLanguageId,
|
||||||
|
IN va_list args); // arg_ptr
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConMsgPrintfV(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN DWORD dwFlags,
|
||||||
|
IN LPCVOID lpSource OPTIONAL,
|
||||||
|
IN DWORD dwMessageId,
|
||||||
|
IN DWORD dwLanguageId,
|
||||||
|
IN va_list args); // arg_ptr
|
||||||
|
|
||||||
|
INT
|
||||||
|
ConMsgPrintf(
|
||||||
|
IN PCON_STREAM Stream,
|
||||||
|
IN DWORD dwFlags,
|
||||||
|
IN LPCVOID lpSource OPTIONAL,
|
||||||
|
IN DWORD dwMessageId,
|
||||||
|
IN DWORD dwLanguageId,
|
||||||
|
...);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Those are compatibility #defines for old code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** tree.c ***/
|
||||||
|
|
||||||
|
#define PrintStringV(szStr, args) \
|
||||||
|
ConPrintfV(StdOut, (szStr), (args))
|
||||||
|
#define PrintString(szStr, ...) \
|
||||||
|
ConPrintf(StdOut, (szStr), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/*** network/net/main.c ***/
|
||||||
|
#define PrintToConsole(szStr, ...) \
|
||||||
|
ConPrintf(StdOut, (szStr), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/*** clip.c, comp.c, help.c, tree.c ***/
|
||||||
|
/*** subst.c ***/
|
||||||
|
/*** format.c, network/net/main.c, shutdown.c, wlanconf.c, diskpart.c ***/
|
||||||
|
|
||||||
|
#define PrintResourceStringV(uID, args) \
|
||||||
|
ConResPrintfV(StdOut, (uID), (args))
|
||||||
|
#define PrintResourceString(uID, ...) \
|
||||||
|
ConResPrintf(StdOut, (uID), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
//
|
||||||
|
// TODO: Add Console paged-output printf & ResPrintf functions!
|
||||||
|
//
|
||||||
|
|
||||||
|
#endif /* __CONUTILS_H__ */
|
Loading…
Add table
Add a link
Reference in a new issue