mirror of
https://github.com/reactos/reactos.git
synced 2025-04-05 05:01:03 +00:00
[CONUTILS]
- Introduce new functionalities related to console streams, a console screen management api (almost stubbed), a console pager api (adapted from code from CMD). This new functionality will be used in the future. See CORE-10504 for more details. - As this library is therefore growing up, split it in small parts (sublibraries) that can be used, with the following dependency scheme: base utils (standalone); streams depending on base; screen depending on streams; pager depending on screen. [APPS]: As a result, modify the CMakeLists of the different apps that use conutils to make them depend on the correct sublibrary. svn path=/trunk/; revision=73024
This commit is contained in:
parent
26cf82fa5b
commit
eb198b854d
24 changed files with 1462 additions and 519 deletions
|
@ -3,6 +3,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(cacls cacls.c cacls.rc)
|
||||
set_module_type(cacls win32cui UNICODE)
|
||||
target_link_libraries(cacls conutils ${PSEH_LIB})
|
||||
target_link_libraries(cacls conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(cacls advapi32 user32 shell32 msvcrt kernel32)
|
||||
add_cd_file(TARGET cacls DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -3,6 +3,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(clip clip.c clip.rc)
|
||||
set_module_type(clip win32cui UNICODE)
|
||||
target_link_libraries(clip conutils ${PSEH_LIB})
|
||||
target_link_libraries(clip conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(clip advapi32 user32 msvcrt kernel32)
|
||||
add_cd_file(TARGET clip DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -3,6 +3,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(comp comp.c comp.rc)
|
||||
set_module_type(comp win32cui UNICODE)
|
||||
target_link_libraries(comp conutils ${PSEH_LIB})
|
||||
target_link_libraries(comp conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(comp msvcrt kernel32)
|
||||
add_cd_file(TARGET comp DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
PROJECT(eventcreate)
|
||||
|
||||
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
||||
|
||||
## The message string templates are in ANSI to reduce binary size
|
||||
|
@ -9,6 +7,6 @@ add_message_headers(ANSI evtmsgstr.mc)
|
|||
add_executable(eventcreate eventcreate.c eventcreate.rc)
|
||||
set_module_type(eventcreate win32cui UNICODE)
|
||||
add_dependencies(eventcreate evtmsgstr)
|
||||
target_link_libraries(eventcreate conutils ${PSEH_LIB})
|
||||
target_link_libraries(eventcreate conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(eventcreate advapi32 msvcrt kernel32)
|
||||
add_cd_file(TARGET eventcreate DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -3,7 +3,7 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(cmd_help help.c help.rc)
|
||||
set_module_type(cmd_help win32cui UNICODE)
|
||||
target_link_libraries(cmd_help conutils ${PSEH_LIB})
|
||||
target_link_libraries(cmd_help conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(cmd_help msvcrt kernel32)
|
||||
set_target_properties(cmd_help PROPERTIES OUTPUT_NAME "help")
|
||||
add_cd_file(TARGET cmd_help DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -3,7 +3,7 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(mode mode.c mode.rc)
|
||||
set_module_type(mode win32cui UNICODE)
|
||||
target_link_libraries(mode conutils ${PSEH_LIB})
|
||||
target_link_libraries(mode conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(mode user32 msvcrt kernel32)
|
||||
set_target_properties(mode PROPERTIES SUFFIX ".com")
|
||||
add_cd_file(TARGET mode DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -3,6 +3,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(logoff logoff.c logoff.rc)
|
||||
set_module_type(logoff win32cui UNICODE)
|
||||
target_link_libraries(logoff conutils ${PSEH_LIB})
|
||||
target_link_libraries(logoff conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(logoff advapi32 user32 msvcrt kernel32)
|
||||
add_cd_file(TARGET logoff DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -19,7 +19,7 @@ list(APPEND SOURCE
|
|||
|
||||
add_executable(net ${SOURCE} net.rc)
|
||||
set_module_type(net win32cui UNICODE)
|
||||
target_link_libraries(net conutils ${PSEH_LIB})
|
||||
target_link_libraries(net conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(net advapi32 netapi32 mpr msvcrt kernel32 ntdll)
|
||||
add_pch(net net.h SOURCE)
|
||||
add_cd_file(TARGET net DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -9,7 +9,7 @@ list(APPEND SOURCE
|
|||
|
||||
add_executable(shutdown ${SOURCE} shutdown.rc)
|
||||
set_module_type(shutdown win32cui UNICODE)
|
||||
target_link_libraries(shutdown conutils ${PSEH_LIB})
|
||||
target_link_libraries(shutdown conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(shutdown advapi32 user32 powrprof msvcrt kernel32)
|
||||
add_pch(shutdown precomp.h SOURCE)
|
||||
add_cd_file(TARGET shutdown DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -4,6 +4,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(chkdsk chkdsk.c chkdsk.rc)
|
||||
set_module_type(chkdsk win32cui UNICODE)
|
||||
target_link_libraries(chkdsk conutils ${PSEH_LIB})
|
||||
target_link_libraries(chkdsk conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(chkdsk fmifs msvcrt kernel32 ntdll)
|
||||
add_cd_file(TARGET chkdsk DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -45,7 +45,7 @@ list(APPEND SOURCE
|
|||
|
||||
add_executable(diskpart ${SOURCE} diskpart.rc)
|
||||
set_module_type(diskpart win32cui UNICODE)
|
||||
target_link_libraries(diskpart conutils ${PSEH_LIB})
|
||||
target_link_libraries(diskpart conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(diskpart advapi32 msvcrt kernel32 ntdll)
|
||||
|
||||
if(MSVC)
|
||||
|
|
|
@ -4,7 +4,7 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(format format.c format.rc)
|
||||
set_module_type(format win32cui UNICODE)
|
||||
target_link_libraries(format conutils ${PSEH_LIB})
|
||||
target_link_libraries(format conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(format fmifs msvcrt kernel32 ntdll)
|
||||
set_target_properties(format PROPERTIES SUFFIX ".com")
|
||||
add_cd_file(TARGET format DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -3,6 +3,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(subst subst.c subst.rc)
|
||||
set_module_type(subst win32cui UNICODE)
|
||||
target_link_libraries(subst conutils ${PSEH_LIB})
|
||||
target_link_libraries(subst conutils_stream ${PSEH_LIB})
|
||||
add_importlibs(subst msvcrt kernel32 ntdll)
|
||||
add_cd_file(TARGET subst DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -1,3 +1,36 @@
|
|||
|
||||
add_library(conutils conutils.c)
|
||||
add_dependencies(conutils xdk)
|
||||
##
|
||||
## 'conutils_base': the base utility library.
|
||||
##
|
||||
add_library(conutils_base utils.c)
|
||||
add_dependencies(conutils_base xdk)
|
||||
target_link_libraries(conutils_base ${PSEH_LIB})
|
||||
add_importlibs(conutils_base msvcrt kernel32)
|
||||
|
||||
##
|
||||
## 'conutils_stream': Console Stream API library.
|
||||
##
|
||||
add_library(conutils_stream stream.c)
|
||||
target_link_libraries(conutils_stream PUBLIC conutils_base)
|
||||
# add_dependencies(conutils_stream conutils_base xdk)
|
||||
|
||||
##
|
||||
## 'conutils_screen': Console Screen API library.
|
||||
##
|
||||
add_library(conutils_screen screen.c)
|
||||
target_link_libraries(conutils_screen PUBLIC conutils_stream conutils_base)
|
||||
# add_dependencies(conutils_screen conutils_stream conutils_base xdk)
|
||||
|
||||
##
|
||||
## 'conutils_pager': Console Pager API library.
|
||||
##
|
||||
add_library(conutils_pager pager.c)
|
||||
target_link_libraries(conutils_pager PUBLIC conutils_screen conutils_stream conutils_base)
|
||||
# add_dependencies(conutils_pager conutils_screen conutils_stream conutils_base xdk)
|
||||
|
||||
##
|
||||
## 'conutils': Library target that groups everything together.
|
||||
##
|
||||
add_library(conutils INTERFACE)
|
||||
target_link_libraries(conutils INTERFACE conutils_pager conutils_screen conutils_stream conutils_base)
|
||||
# add_dependencies(conutils conutils_pager conutils_screen conutils_stream conutils_base xdk)
|
||||
|
|
43
reactos/sdk/lib/conutils/README.txt
Normal file
43
reactos/sdk/lib/conutils/README.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
The ReactOS Console Utilities Library v0.1
|
||||
==========================================
|
||||
|
||||
COPYRIGHT: Under GPLv2, see COPYING in the top level directory.
|
||||
CREDITS: Thanks to the many people who originally wrote the code that finally
|
||||
ended up inside this library, with more or less refactoring, or
|
||||
whose code served as a basis for some functions of the library.
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
~-~-~-~-~-~-
|
||||
|
||||
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.
|
||||
|
||||
|
||||
CONTENTS
|
||||
~-~-~-~-
|
||||
|
||||
0. 'conutils_base' library (utils.c and utils.h): Base set of functions for
|
||||
loading string resources and message strings, and handle type identification.
|
||||
|
||||
1. 'conutils_stream' library (stream.c and stream.h): Console Stream API (CON_STREAM):
|
||||
Stream initialization, basic ConStreamRead/Write. Stream utility functions:
|
||||
ConPuts/Printf, ConResPuts/Printf, ConMsgPuts/Printf.
|
||||
Depends on the 'conutils_base' library.
|
||||
|
||||
2. 'conutils_screen' library (screen.c and screen.h): Console Screen API (CON_SCREEN):
|
||||
Introduces the notion of console/terminal screen around the streams. Manages
|
||||
console/terminal screen metrics for Win32 consoles and TTYs (serial...).
|
||||
Additional Screen utility functions.
|
||||
Depends on the 'conutils_stream' library, and indirectly on 'conutils_base'.
|
||||
|
||||
3. 'conutils_pager' library (pager.c and pager.h): Console Pager API (CON_PAGER):
|
||||
Implements core console/terminal paging functionality around console screens.
|
||||
Depends on the 'conutils_screen' library, and indirectly on 'conutils_stream'
|
||||
and 'conutils_base'.
|
||||
|
||||
4. More to come!
|
|
@ -2,10 +2,10 @@
|
|||
* 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);
|
||||
* PURPOSE: Provides simple abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
@ -13,238 +13,13 @@
|
|||
#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
|
||||
ConPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr);
|
||||
|
||||
INT
|
||||
ConPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
...);
|
||||
|
||||
INT
|
||||
ConResPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID);
|
||||
|
||||
INT
|
||||
ConResPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
...);
|
||||
|
||||
INT
|
||||
ConMsgPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId);
|
||||
|
||||
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
|
||||
__cdecl
|
||||
ConMsgPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
...);
|
||||
|
||||
|
||||
//
|
||||
// TODO: Add Console paged-output printf & ResPrintf functions!
|
||||
//
|
||||
#include "utils.h"
|
||||
#include "stream.h"
|
||||
#include "screen.h"
|
||||
#include "pager.h"
|
||||
|
||||
#endif /* __CONUTILS_H__ */
|
||||
|
|
148
reactos/sdk/lib/conutils/pager.c
Normal file
148
reactos/sdk/lib/conutils/pager.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/pager.c
|
||||
* PURPOSE: Console/terminal paging functionality.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
||||
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
|
||||
#define UNICODE
|
||||
#define _UNICODE
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
// #include <winnls.h>
|
||||
#include <wincon.h> // Console APIs (only if kernel32 support included)
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "conutils.h"
|
||||
#include "stream.h"
|
||||
#include "screen.h"
|
||||
#include "pager.h"
|
||||
|
||||
// Temporary HACK
|
||||
#define CON_STREAM_WRITE ConStreamWrite
|
||||
|
||||
|
||||
|
||||
/* Returns TRUE when all the text is displayed, and FALSE if display is stopped */
|
||||
BOOL
|
||||
ConWritePaging(
|
||||
IN PCON_PAGER Pager,
|
||||
IN PAGE_PROMPT PagePrompt,
|
||||
IN BOOL StartPaging,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
|
||||
/* Used to see how big the screen is */
|
||||
DWORD ScreenLines = 0;
|
||||
|
||||
/* Chars since start of line */
|
||||
DWORD CharSL;
|
||||
|
||||
DWORD from = 0, i = 0;
|
||||
|
||||
/* Parameters validation */
|
||||
if (!Pager)
|
||||
return FALSE;
|
||||
|
||||
/* Reset LineCount and return if no string has been given */
|
||||
if (StartPaging == TRUE)
|
||||
Pager->LineCount = 0;
|
||||
if (szStr == NULL)
|
||||
return TRUE;
|
||||
|
||||
/* Get the size of the visual screen that can be printed to */
|
||||
if (!ConGetScreenInfo(Pager->Screen, &csbi))
|
||||
{
|
||||
/* We assume it's a file handle */
|
||||
CON_STREAM_WRITE(Pager->Screen->Stream, szStr, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of lines currently displayed on screen, minus 1
|
||||
* to account for the "press any key..." prompt from PagePrompt().
|
||||
*/
|
||||
ScreenLines = (csbi.srWindow.Bottom - csbi.srWindow.Top);
|
||||
CharSL = csbi.dwCursorPosition.X;
|
||||
|
||||
/* Make sure the user doesn't have the screen too small */
|
||||
if (ScreenLines < 4)
|
||||
{
|
||||
CON_STREAM_WRITE(Pager->Screen->Stream, szStr, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
while (i < len)
|
||||
{
|
||||
/* Search until the end of a line is reached */
|
||||
if (szStr[i++] != TEXT('\n') && ++CharSL < csbi.dwSize.X)
|
||||
continue;
|
||||
|
||||
Pager->LineCount++;
|
||||
CharSL = 0;
|
||||
|
||||
if (Pager->LineCount >= ScreenLines)
|
||||
{
|
||||
CON_STREAM_WRITE(Pager->Screen->Stream, &szStr[from], i-from);
|
||||
from = i;
|
||||
|
||||
/* Prompt the user; give him some values for statistics */
|
||||
// FIXME TODO: The prompt proc can also take ScreenLines ??
|
||||
if (!PagePrompt(Pager, from, len))
|
||||
return FALSE;
|
||||
|
||||
// TODO: Recalculate 'ScreenLines' in case the user redimensions
|
||||
// the window during the prompt.
|
||||
|
||||
/* Reset the number of lines being printed */
|
||||
Pager->LineCount = 0;
|
||||
}
|
||||
}
|
||||
if (i > from)
|
||||
CON_STREAM_WRITE(Pager->Screen->Stream, &szStr[from], i-from);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
ConPutsPaging(
|
||||
IN PCON_PAGER Pager,
|
||||
IN PAGE_PROMPT PagePrompt,
|
||||
IN BOOL StartPaging,
|
||||
IN LPTSTR szStr)
|
||||
{
|
||||
DWORD len;
|
||||
|
||||
/* Return if no string has been given */
|
||||
if (szStr == NULL)
|
||||
return TRUE;
|
||||
|
||||
len = wcslen(szStr);
|
||||
return ConWritePaging(Pager, PagePrompt, StartPaging, szStr, len);
|
||||
}
|
||||
|
||||
BOOL
|
||||
ConResPaging(
|
||||
IN PCON_PAGER Pager,
|
||||
IN PAGE_PROMPT PagePrompt,
|
||||
IN BOOL StartPaging,
|
||||
IN UINT uID)
|
||||
{
|
||||
INT Len;
|
||||
PWCHAR szStr = NULL;
|
||||
|
||||
Len = K32LoadStringW(GetModuleHandleW(NULL), uID, (PWSTR)&szStr, 0);
|
||||
if (szStr && Len)
|
||||
return ConWritePaging(Pager, PagePrompt, StartPaging, szStr, Len);
|
||||
else
|
||||
return TRUE;
|
||||
}
|
58
reactos/sdk/lib/conutils/pager.h
Normal file
58
reactos/sdk/lib/conutils/pager.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/pager.h
|
||||
* PURPOSE: Console/terminal paging functionality.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
||||
#ifndef __PAGER_H__
|
||||
#define __PAGER_H__
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library at the moment only supports compilation with _UNICODE defined!
|
||||
#endif
|
||||
|
||||
|
||||
// #include <wincon.h>
|
||||
|
||||
|
||||
typedef struct _CON_PAGER
|
||||
{
|
||||
PCON_SCREEN Screen;
|
||||
|
||||
// TODO: Add more properties. Maybe those extra parameters
|
||||
// of PAGE_PROMPT could go there?
|
||||
|
||||
/* Used to count number of lines since last pause */
|
||||
DWORD LineCount;
|
||||
} CON_PAGER, *PCON_PAGER;
|
||||
|
||||
// Pager, Done, Total
|
||||
typedef BOOL (__stdcall *PAGE_PROMPT)(IN PCON_PAGER, IN DWORD, IN DWORD);
|
||||
|
||||
BOOL
|
||||
ConWritePaging(
|
||||
IN PCON_PAGER Pager,
|
||||
IN PAGE_PROMPT PagePrompt,
|
||||
IN BOOL StartPaging,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len);
|
||||
|
||||
BOOL
|
||||
ConPutsPaging(
|
||||
IN PCON_PAGER Pager,
|
||||
IN PAGE_PROMPT PagePrompt,
|
||||
IN BOOL StartPaging,
|
||||
IN LPTSTR szStr);
|
||||
|
||||
BOOL
|
||||
ConResPaging(
|
||||
IN PCON_PAGER Pager,
|
||||
IN PAGE_PROMPT PagePrompt,
|
||||
IN BOOL StartPaging,
|
||||
IN UINT uID);
|
||||
|
||||
#endif /* __PAGER_H__ */
|
175
reactos/sdk/lib/conutils/screen.c
Normal file
175
reactos/sdk/lib/conutils/screen.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/screen.c
|
||||
* PURPOSE: Console/terminal screen management.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
||||
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
|
||||
#define UNICODE
|
||||
#define _UNICODE
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
// #include <winnls.h>
|
||||
#include <wincon.h> // Console APIs (only if kernel32 support included)
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "conutils.h"
|
||||
#include "stream.h"
|
||||
#include "screen.h"
|
||||
|
||||
// Temporary HACK
|
||||
#define CON_STREAM_WRITE ConStreamWrite
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
VOID
|
||||
ConClearLine(IN PCON_STREAM Stream)
|
||||
{
|
||||
HANDLE hOutput = ConStreamGetOSHandle(Stream);
|
||||
|
||||
/*
|
||||
* Erase the full line where the cursor is, and move
|
||||
* the cursor back to the beginning of the line.
|
||||
*/
|
||||
|
||||
if (IsConsoleHandle(hOutput))
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
DWORD dwWritten;
|
||||
|
||||
GetConsoleScreenBufferInfo(hOutput, &csbi);
|
||||
|
||||
csbi.dwCursorPosition.X = 0;
|
||||
// csbi.dwCursorPosition.Y;
|
||||
|
||||
FillConsoleOutputCharacterW(hOutput, L' ',
|
||||
csbi.dwSize.X,
|
||||
csbi.dwCursorPosition,
|
||||
&dwWritten);
|
||||
SetConsoleCursorPosition(hOutput, csbi.dwCursorPosition);
|
||||
}
|
||||
else if (IsTTYHandle(hOutput))
|
||||
{
|
||||
ConPuts(Stream, L"\x1B[2K\x1B[1G"); // FIXME: Just use WriteFile
|
||||
}
|
||||
// else, do nothing for files
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
BOOL
|
||||
ConGetScreenInfo(
|
||||
IN PCON_SCREEN Screen,
|
||||
OUT PCONSOLE_SCREEN_BUFFER_INFO pcsbi)
|
||||
{
|
||||
BOOL Success;
|
||||
HANDLE hOutput;
|
||||
|
||||
/* Parameters validation */
|
||||
if (!Screen || !pcsbi)
|
||||
return FALSE;
|
||||
|
||||
hOutput = ConStreamGetOSHandle(Screen->Stream);
|
||||
|
||||
/* Screen handle must be of TTY type (console or TTY) */
|
||||
if (!IsTTYHandle(hOutput))
|
||||
return FALSE;
|
||||
|
||||
/* Update cached screen information */
|
||||
if (IsConsoleHandle(hOutput))
|
||||
{
|
||||
Success = GetConsoleScreenBufferInfo(hOutput, &Screen->csbi);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
/* TODO: Do something adequate for TTYs */
|
||||
// FIXME: At the moment we return hardcoded info.
|
||||
Screen->csbi.dwSize.X = 80;
|
||||
Screen->csbi.dwSize.Y = 25;
|
||||
|
||||
// Screen->csbi.dwCursorPosition;
|
||||
// Screen->csbi.wAttributes;
|
||||
// Screen->csbi.srWindow;
|
||||
Screen->csbi.dwMaximumWindowSize = Screen->csbi.dwSize;
|
||||
#else
|
||||
hOutput = CreateFileW(L"CONOUT$", GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, 0, NULL);
|
||||
|
||||
Success = IsConsoleHandle(hOutput) &&
|
||||
GetConsoleScreenBufferInfo(hOutput, &Screen->csbi);
|
||||
|
||||
CloseHandle(hOutput);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Success)
|
||||
{
|
||||
/* Return it to the caller */
|
||||
*pcsbi = Screen->csbi;
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
// For real consoles, erase everything, otherwise (TTY) erase just the "screen".
|
||||
// FIXME: Or we can add a BOOL flag?
|
||||
VOID
|
||||
ConClearScreen(IN PCON_SCREEN Screen)
|
||||
{
|
||||
HANDLE hOutput;
|
||||
|
||||
/* Parameters validation */
|
||||
if (!Screen) return;
|
||||
|
||||
#if 0
|
||||
/* Get the size of the visual screen */
|
||||
if (!ConGetScreenInfo(Screen, &csbi))
|
||||
{
|
||||
/* We assume it's a file handle */
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
hOutput = ConStreamGetOSHandle(Screen->Stream);
|
||||
|
||||
if (IsConsoleHandle(hOutput))
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
COORD coPos;
|
||||
DWORD dwWritten;
|
||||
|
||||
GetConsoleScreenBufferInfo(hOutput, &csbi);
|
||||
|
||||
coPos.X = 0;
|
||||
coPos.Y = 0;
|
||||
FillConsoleOutputAttribute(hOutput, csbi.wAttributes,
|
||||
csbi.dwSize.X * csbi.dwSize.Y,
|
||||
coPos, &dwWritten);
|
||||
FillConsoleOutputCharacterW(hOutput, L' ',
|
||||
csbi.dwSize.X * csbi.dwSize.Y,
|
||||
coPos, &dwWritten);
|
||||
SetConsoleCursorPosition(hOutput, coPos);
|
||||
}
|
||||
else if (IsTTYHandle(hOutput))
|
||||
{
|
||||
/* Clear the full screen and move the cursor to (0,0) */
|
||||
ConPuts(Screen->Stream, L"\x1B[2J\x1B[1;1H");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Issue a Form-Feed control */
|
||||
WCHAR ch = L'\f';
|
||||
CON_STREAM_WRITE(Screen->Stream, &ch, 1);
|
||||
}
|
||||
}
|
47
reactos/sdk/lib/conutils/screen.h
Normal file
47
reactos/sdk/lib/conutils/screen.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/screen.h
|
||||
* PURPOSE: Console/terminal screen management.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
||||
#ifndef __SCREEN_H__
|
||||
#define __SCREEN_H__
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library at the moment only supports compilation with _UNICODE defined!
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
VOID
|
||||
ConClearLine(IN PCON_STREAM Stream);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include <wincon.h>
|
||||
|
||||
typedef struct _CON_SCREEN
|
||||
{
|
||||
PCON_STREAM Stream; // Out
|
||||
// PCON_STREAM In;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
CONSOLE_CURSOR_INFO cci;
|
||||
} CON_SCREEN, *PCON_SCREEN;
|
||||
|
||||
BOOL
|
||||
ConGetScreenInfo(
|
||||
IN PCON_SCREEN Screen,
|
||||
OUT PCONSOLE_SCREEN_BUFFER_INFO pcsbi);
|
||||
|
||||
VOID
|
||||
ConClearScreen(IN PCON_SCREEN Screen);
|
||||
|
||||
|
||||
#endif /* __SCREEN_H__ */
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* 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);
|
||||
* FILE: sdk/lib/conutils/stream.c
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
@ -22,13 +22,13 @@
|
|||
#define UNICODE
|
||||
#define _UNICODE
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#ifdef USE_CRT
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#endif /* USE_CRT */
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
|
@ -40,161 +40,16 @@
|
|||
#include <pseh/pseh2.h>
|
||||
|
||||
#include "conutils.h"
|
||||
#include "stream.h"
|
||||
|
||||
|
||||
// #define RC_STRING_MAX_SIZE 4096
|
||||
// #define MAX_BUFFER_SIZE 4096
|
||||
// #define OUTPUT_BUFFER_SIZE 4096
|
||||
#define CON_RC_STRING_MAX_SIZE 4096
|
||||
// #define MAX_BUFFER_SIZE 4096 // Some programs (wlanconf, shutdown) set it to 5024
|
||||
// #define OUTPUT_BUFFER_SIZE 4096 // Name given in cmd/console.c
|
||||
// MAX_STRING_SIZE // Name given in diskpart
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
// #define MAX_MESSAGE_SIZE 512 // See shutdown...
|
||||
|
||||
|
||||
/*
|
||||
|
@ -208,12 +63,20 @@ typedef struct _CON_STREAM
|
|||
#ifdef USE_CRT
|
||||
FILE* fStream;
|
||||
#else
|
||||
BOOL IsInitialized;
|
||||
CRITICAL_SECTION Lock;
|
||||
|
||||
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
|
||||
* TRUE if 'hHandle' refers to a console, in which case I/O UTF-16
|
||||
* is directly used. If 'hHandle' refers to a file or a pipe, the
|
||||
* 'Mode' flag is used.
|
||||
*/
|
||||
BOOL IsConsole;
|
||||
|
||||
/*
|
||||
* The 'Mode' flag is used to know the translation mode
|
||||
* when 'hHandle' refers to a file or a pipe.
|
||||
*/
|
||||
CON_STREAM_MODE Mode;
|
||||
|
@ -228,7 +91,7 @@ typedef struct _CON_STREAM
|
|||
#if 0 // FIXME!
|
||||
CON_STREAM StdStreams[3] =
|
||||
{
|
||||
{0}, // StdIn // TODO!
|
||||
{0}, // StdIn
|
||||
{0}, // StdOut
|
||||
{0}, // StdErr
|
||||
};
|
||||
|
@ -239,88 +102,124 @@ CON_STREAM csStdErr;
|
|||
#endif
|
||||
|
||||
|
||||
// static
|
||||
BOOL
|
||||
IsConsoleHandle(IN HANDLE hHandle)
|
||||
/* Stream translation modes */
|
||||
#ifdef USE_CRT
|
||||
/* Lookup table to convert CON_STREAM_MODE to CRT mode */
|
||||
static int ConToCRTMode[] =
|
||||
{
|
||||
DWORD dwMode;
|
||||
_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)
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Check whether the handle may be that of a console... */
|
||||
if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
|
||||
return FALSE;
|
||||
#ifdef USE_CRT
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// 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??
|
||||
// NOTE3: _setmode returns the previous mode, or -1 if failure.
|
||||
#define CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage) \
|
||||
do { \
|
||||
fflush((Stream)->fStream); \
|
||||
if ((Mode) < ARRAYSIZE(ConToCRTMode)) \
|
||||
_setmode(_fileno((Stream)->fStream), ConToCRTMode[(Mode)]); \
|
||||
else \
|
||||
_setmode(_fileno((Stream)->fStream), _O_TEXT); /* Default to ANSI text */ \
|
||||
} while(0)
|
||||
|
||||
#else /* defined(USE_CRT) */
|
||||
|
||||
/*
|
||||
* We set Stream->CodePage to INVALID_CP (= -1) to signal that the codepage
|
||||
* is either not assigned (if the mode is Binary, WideText, or UTF16Text), or
|
||||
* is not cached yet (if the mode is AnsiText). In this latter case the cache
|
||||
* is resolved inside ConWrite. Finally, if the mode is UTF8Text, the codepage
|
||||
* cache is set to CP_UTF8.
|
||||
* The codepage cache can be reset by an explicit call to CON_STREAM_SET_MODE
|
||||
* (i.e. by calling ConStreamSetMode, or by reinitializing the stream with
|
||||
* ConStreamInit(Ex)).
|
||||
*
|
||||
* NOTE: the magic value could not be '0' since it is reserved for CP_ACP.
|
||||
*/
|
||||
#define CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage) \
|
||||
do { \
|
||||
(Stream)->Mode = (Mode); \
|
||||
\
|
||||
if ((Mode) == AnsiText) \
|
||||
(Stream)->CodePage = CacheCodePage; /* Possibly assigned */ \
|
||||
else if ((Mode) == UTF8Text) \
|
||||
(Stream)->CodePage = CP_UTF8; /* Fixed */ \
|
||||
else /* Mode == Binary, WideText, UTF16Text */ \
|
||||
(Stream)->CodePage = INVALID_CP; /* Not assigned (meaningless) */ \
|
||||
} while(0)
|
||||
|
||||
#endif /* defined(USE_CRT) */
|
||||
|
||||
/*
|
||||
* 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 UINT CacheCodePage OPTIONAL,
|
||||
// IN CON_READ_FUNC ReadFunc OPTIONAL,
|
||||
IN CON_WRITE_FUNC WriteFunc OPTIONAL)
|
||||
{
|
||||
/* Parameters validation */
|
||||
if (!Stream || !Handle)
|
||||
if (!Stream || !Handle || (Mode > UTF8Text))
|
||||
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;
|
||||
if ((HANDLE)Handle == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
// 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;
|
||||
/*
|
||||
* As the user calls us by giving us an existing handle to attach on,
|
||||
* it is not our duty to close it if we are called again. The user
|
||||
* is responsible for having opened those handles, and is responsible
|
||||
* for closing them!
|
||||
*/
|
||||
#if 0
|
||||
/* Attempt to close the handle of the old stream */
|
||||
if (/* Stream->IsInitialized && */ Stream->hHandle &&
|
||||
Stream->hHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(Stream->hHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the stream critical section if not already done */
|
||||
if (!Stream->IsInitialized)
|
||||
{
|
||||
InitializeCriticalSection/*AndSpinCount*/(&Stream->Lock /* , 4000 */);
|
||||
Stream->IsInitialized = TRUE;
|
||||
}
|
||||
|
||||
Stream->hHandle = (HANDLE)Handle;
|
||||
Stream->IsConsole = IsConsoleHandle(Stream->hHandle);
|
||||
|
||||
#endif /* defined(USE_CRT) */
|
||||
|
||||
/* Set the correct file translation mode */
|
||||
CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
|
||||
|
||||
/* Use the default 'ConWrite' helper if nothing is specified */
|
||||
Stream->WriteFunc = (WriteFunc ? WriteFunc : ConWrite);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -328,9 +227,116 @@ BOOL
|
|||
ConStreamInit(
|
||||
OUT PCON_STREAM Stream,
|
||||
IN PVOID Handle,
|
||||
IN CON_STREAM_MODE Mode)
|
||||
IN CON_STREAM_MODE Mode,
|
||||
IN UINT CacheCodePage OPTIONAL)
|
||||
{
|
||||
return ConStreamInitEx(Stream, Handle, Mode, ConWrite);
|
||||
return ConStreamInitEx(Stream, Handle, Mode, CacheCodePage, ConWrite);
|
||||
}
|
||||
|
||||
BOOL
|
||||
ConStreamSetMode(
|
||||
IN PCON_STREAM Stream,
|
||||
IN CON_STREAM_MODE Mode,
|
||||
IN UINT CacheCodePage OPTIONAL)
|
||||
{
|
||||
/* Parameters validation */
|
||||
if (!Stream || (Mode > UTF8Text))
|
||||
return FALSE;
|
||||
|
||||
#ifdef USE_CRT
|
||||
if (!Stream->fStream)
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
/* Set the correct file translation mode */
|
||||
CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
ConStreamSetCacheCodePage(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT CacheCodePage)
|
||||
{
|
||||
#ifdef USE_CRT
|
||||
// FIXME!
|
||||
#warning The ConStreamSetCacheCodePage function does not make much sense with the CRT!
|
||||
#else
|
||||
CON_STREAM_MODE Mode;
|
||||
|
||||
/* Parameters validation */
|
||||
if (!Stream)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* Keep the original stream mode but set the correct file codepage
|
||||
* (will be reset only if Mode == AnsiText).
|
||||
*/
|
||||
Mode = Stream->Mode;
|
||||
CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
HANDLE
|
||||
ConStreamGetOSHandle(
|
||||
IN PCON_STREAM Stream)
|
||||
{
|
||||
/* Parameters validation */
|
||||
if (!Stream)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
||||
/*
|
||||
* See https://support.microsoft.com/kb/99173
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifdef USE_CRT
|
||||
if (!Stream->fStream)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
||||
return (HANDLE)_get_osfhandle(_fileno(Stream->fStream));
|
||||
#else
|
||||
return Stream->hHandle;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL
|
||||
ConStreamSetOSHandle(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HANDLE Handle)
|
||||
{
|
||||
/* Parameters validation */
|
||||
if (!Stream)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* See https://support.microsoft.com/kb/99173
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifdef USE_CRT
|
||||
if (!Stream->fStream)
|
||||
return FALSE;
|
||||
|
||||
int fdOut = _open_osfhandle(Handle, _O_TEXT /* FIXME! */);
|
||||
FILE* fpOut = _fdopen(fdOut, "w");
|
||||
*Stream->fStream = *fpOut;
|
||||
/// setvbuf(Stream->fStream, NULL, _IONBF, 0);
|
||||
|
||||
return TRUE;
|
||||
#else
|
||||
/* Flush the stream and reset its handle */
|
||||
if (Stream->hHandle != INVALID_HANDLE_VALUE)
|
||||
FlushFileBuffers(Stream->hHandle);
|
||||
|
||||
Stream->hHandle = Handle;
|
||||
Stream->IsConsole = IsConsoleHandle(Stream->hHandle);
|
||||
|
||||
// NOTE: Mode reset??
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -339,7 +345,7 @@ ConStreamInit(
|
|||
* (for the moment, only Output)
|
||||
*/
|
||||
|
||||
// ConWriteStr
|
||||
// NOTE: Should be called with the stream locked.
|
||||
INT
|
||||
__stdcall
|
||||
ConWrite(
|
||||
|
@ -359,11 +365,33 @@ ConWrite(
|
|||
|
||||
/* Check whether we are writing to a console */
|
||||
// if (IsConsoleHandle(Stream->hHandle))
|
||||
if (Stream->bIsConsole)
|
||||
if (Stream->IsConsole)
|
||||
{
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This code is inspired from _cputws, in particular from the fact that,
|
||||
* according to MSDN: https://msdn.microsoft.com/en-us/library/ms687401(v=vs.85).aspx
|
||||
* the buffer size must be less than 64 KB.
|
||||
*
|
||||
* A similar code can be used for implementing _cputs too.
|
||||
*/
|
||||
|
||||
DWORD cchWrite;
|
||||
TotalLen = len, dwNumBytes = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
cchWrite = min(len, 65535 / sizeof(WCHAR));
|
||||
|
||||
// FIXME: Check return value!
|
||||
WriteConsole(Stream->hHandle, szStr, cchWrite, &dwNumBytes, NULL);
|
||||
|
||||
szStr += cchWrite;
|
||||
len -= cchWrite;
|
||||
}
|
||||
|
||||
return (INT)TotalLen; // FIXME: Really return the number of chars written!
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -378,16 +406,22 @@ ConWrite(
|
|||
*/
|
||||
if ((Stream->Mode == WideText) || (Stream->Mode == UTF16Text))
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
#ifndef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
|
||||
/* Convert from the current process/thread's codepage to UTF-16 */
|
||||
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 */,
|
||||
len = (DWORD)MultiByteToWideChar(CP_THREAD_ACP, // CP_ACP, CP_OEMCP
|
||||
0, szStr, (INT)len, buffer, (INT)len);
|
||||
szStr = (PVOID)buffer;
|
||||
#else
|
||||
/*
|
||||
* Do not perform any conversion since we are already in UTF-16,
|
||||
* that is the same encoding as the stream.
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -430,9 +464,20 @@ ConWrite(
|
|||
}
|
||||
else if ((Stream->Mode == UTF8Text) || (Stream->Mode == AnsiText))
|
||||
{
|
||||
#ifdef _UNICODE
|
||||
CHAR *buffer;
|
||||
|
||||
/*
|
||||
* Resolve the codepage cache if it was not assigned yet
|
||||
* (only if the stream is in ANSI mode; in UTF8 mode the
|
||||
* codepage was already set to CP_UTF8).
|
||||
*/
|
||||
if (/*(Stream->Mode == AnsiText) &&*/ (Stream->CodePage == INVALID_CP))
|
||||
Stream->CodePage = GetConsoleOutputCP(); // CP_ACP, CP_OEMCP
|
||||
|
||||
#ifdef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
|
||||
/* Convert from UTF-16 to either UTF-8 or ANSI, using stream codepage */
|
||||
// NOTE: MB_LEN_MAX defined either in limits.h or in stdlib.h .
|
||||
CHAR *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * MB_LEN_MAX);
|
||||
buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * MB_LEN_MAX);
|
||||
if (!buffer)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
@ -440,6 +485,14 @@ ConWrite(
|
|||
}
|
||||
len = WideCharToMultiByte(Stream->CodePage, 0, szStr, len, buffer, len * MB_LEN_MAX, NULL, NULL);
|
||||
szStr = (PVOID)buffer;
|
||||
#else
|
||||
/*
|
||||
* Convert from the current process/thread's codepage to either
|
||||
* UTF-8 or ANSI, using stream codepage.
|
||||
* We need to perform a double conversion, by going through UTF-16.
|
||||
*/
|
||||
// TODO!
|
||||
#error "Need to implement double conversion!"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -478,10 +531,13 @@ ConWrite(
|
|||
|
||||
#ifdef _UNICODE
|
||||
HeapFree(GetProcessHeap(), 0, buffer);
|
||||
#else
|
||||
// TODO!
|
||||
#endif
|
||||
}
|
||||
else // if (Stream->Mode == Binary)
|
||||
{
|
||||
/* Directly output the string */
|
||||
WriteFile(Stream->hHandle, szStr, len, &dwNumBytes, NULL);
|
||||
}
|
||||
|
||||
|
@ -497,18 +553,20 @@ ConWrite(
|
|||
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
|
||||
/*
|
||||
* There is no "counted" printf-to-stream or puts-like function, therefore
|
||||
* we use this trick to output the counted string to the stream.
|
||||
*/
|
||||
while (1)
|
||||
{
|
||||
written = wprintf(L"%.*s", total, szStr);
|
||||
written = fwprintf(Stream->fStream, L"%.*s", total, szStr);
|
||||
if (written < total)
|
||||
{
|
||||
/*
|
||||
* Some embedded NULL or special character
|
||||
* was encountered, print it apart.
|
||||
*/
|
||||
if (written == 0)
|
||||
{
|
||||
fputwc(*szStr, Stream->fStream);
|
||||
|
@ -525,12 +583,61 @@ ConWrite(
|
|||
}
|
||||
return (INT)len;
|
||||
#else
|
||||
/* ANSI text or Binary output only */
|
||||
_setmode(_fileno(Stream->fStream), _O_TEXT); // _O_BINARY
|
||||
return fwrite(szStr, sizeof(*szStr), len, Stream->fStream);
|
||||
#endif
|
||||
|
||||
#endif /* defined(USE_CRT) */
|
||||
}
|
||||
|
||||
|
||||
#define CON_STREAM_WRITE_CALL(Stream, Str, Len) \
|
||||
(Stream)->WriteFunc((Stream), (Str), (Len));
|
||||
|
||||
/* Lock the stream only in non-USE_CRT mode (otherwise use the CRT stream lock) */
|
||||
#ifndef USE_CRT
|
||||
|
||||
#define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
|
||||
do { \
|
||||
EnterCriticalSection(&(Stream)->Lock); \
|
||||
(RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
LeaveCriticalSection(&(Stream)->Lock); \
|
||||
} while(0)
|
||||
|
||||
#define CON_STREAM_WRITE(Stream, Str, Len) \
|
||||
do { \
|
||||
EnterCriticalSection(&(Stream)->Lock); \
|
||||
CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
LeaveCriticalSection(&(Stream)->Lock); \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
|
||||
do { \
|
||||
(RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
} while(0)
|
||||
|
||||
#define CON_STREAM_WRITE(Stream, Str, Len) \
|
||||
do { \
|
||||
CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
INT
|
||||
ConStreamWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len)
|
||||
{
|
||||
INT Len;
|
||||
CON_STREAM_WRITE2(Stream, szStr, len, Len);
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
|
@ -538,7 +645,8 @@ ConPuts(
|
|||
{
|
||||
INT Len;
|
||||
|
||||
Len = Stream->WriteFunc(Stream, szStr, wcslen(szStr));
|
||||
Len = wcslen(szStr);
|
||||
CON_STREAM_WRITE2(Stream, szStr, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
|
@ -556,15 +664,18 @@ ConPrintfV(
|
|||
INT Len;
|
||||
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
|
||||
|
||||
#if 1 /////////////////////////////////////////////////////////////////////// 0
|
||||
PWSTR pEnd;
|
||||
StringCchVPrintfExW(bufSrc, ARRAYSIZE(bufSrc), &pEnd, NULL, 0, szStr, args);
|
||||
Len = pEnd - bufSrc;
|
||||
#else
|
||||
StringCchVPrintfW(bufSrc, ARRAYSIZE(bufSrc), szStr, args);
|
||||
Len = wcslen(bufSrc);
|
||||
#endif
|
||||
Len = Stream->WriteFunc(Stream, bufSrc, Len);
|
||||
// Len = vfwprintf(Stream->fStream, szStr, args); // vfprintf for direct ANSI
|
||||
|
||||
/*
|
||||
* Reuse szStr as the pointer to end-of-string, to compute
|
||||
* the string length instead of calling wcslen().
|
||||
*/
|
||||
// StringCchVPrintfW(bufSrc, ARRAYSIZE(bufSrc), szStr, args);
|
||||
// Len = wcslen(bufSrc);
|
||||
StringCchVPrintfExW(bufSrc, ARRAYSIZE(bufSrc), &szStr, NULL, 0, szStr, args);
|
||||
Len = szStr - bufSrc;
|
||||
|
||||
CON_STREAM_WRITE2(Stream, bufSrc, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
|
@ -583,10 +694,7 @@ ConPrintf(
|
|||
INT Len;
|
||||
va_list args;
|
||||
|
||||
#if 0
|
||||
Len = vfwprintf(stdout, szMsgBuf, arg_ptr); // vfprintf for direct ANSI
|
||||
// or: Len = vwprintf(szMsgBuf, arg_ptr);
|
||||
#endif
|
||||
// Len = vfwprintf(Stream->fStream, szMsgBuf, args); // vfprintf for direct ANSI
|
||||
|
||||
// StringCchPrintfW
|
||||
va_start(args, szStr);
|
||||
|
@ -602,23 +710,16 @@ ConResPuts(
|
|||
IN UINT uID)
|
||||
{
|
||||
INT Len;
|
||||
#if 0
|
||||
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 = ConPuts(Stream, bufSrc);
|
||||
#else
|
||||
PWCHAR szStr = NULL;
|
||||
|
||||
Len = K32LoadStringW(GetModuleHandleW(NULL), uID, (PWSTR)&szStr, 0);
|
||||
if (Len)
|
||||
Len = Stream->WriteFunc(Stream, szStr, Len);
|
||||
if (szStr && Len)
|
||||
// Len = ConPuts(Stream, szStr);
|
||||
CON_STREAM_WRITE2(Stream, szStr, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
#endif
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
@ -709,7 +810,7 @@ ConMsgPuts(
|
|||
|
||||
/* lpMsgBuf is NULL-terminated by FormatMessage */
|
||||
// Len = ConPuts(Stream, lpMsgBuf);
|
||||
Len = Stream->WriteFunc(Stream, lpMsgBuf, dwLength);
|
||||
CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
|
@ -775,7 +876,7 @@ ConMsgPrintf2V(
|
|||
|
||||
/* lpMsgBuf is NULL-terminated by FormatMessage */
|
||||
Len = ConPrintfV(Stream, lpMsgBuf, args);
|
||||
// Len = Stream->WriteFunc(Stream, lpMsgBuf, dwLength);
|
||||
// CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
|
@ -835,7 +936,7 @@ ConMsgPrintfV(
|
|||
// ASSERT(dwLength != 0);
|
||||
|
||||
// Len = ConPrintfV(Stream, lpMsgBuf, args);
|
||||
Len = Stream->WriteFunc(Stream, lpMsgBuf, dwLength);
|
||||
CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
|
@ -874,6 +975,38 @@ ConMsgPrintf(
|
|||
return Len;
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Add Console paged-output printf & ResPrintf functions!
|
||||
//
|
||||
|
||||
|
||||
VOID
|
||||
ConClearLine(IN PCON_STREAM Stream)
|
||||
{
|
||||
HANDLE hOutput = ConStreamGetOSHandle(Stream);
|
||||
|
||||
/*
|
||||
* Erase the full line where the cursor is, and move
|
||||
* the cursor back to the beginning of the line.
|
||||
*/
|
||||
|
||||
if (IsConsoleHandle(hOutput))
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
DWORD dwWritten;
|
||||
|
||||
GetConsoleScreenBufferInfo(hOutput, &csbi);
|
||||
|
||||
csbi.dwCursorPosition.X = 0;
|
||||
// csbi.dwCursorPosition.Y;
|
||||
|
||||
FillConsoleOutputCharacterW(hOutput, L' ',
|
||||
csbi.dwSize.X,
|
||||
csbi.dwCursorPosition,
|
||||
&dwWritten);
|
||||
SetConsoleCursorPosition(hOutput, csbi.dwCursorPosition);
|
||||
}
|
||||
else if (IsTTYHandle(hOutput))
|
||||
{
|
||||
ConPuts(Stream, L"\x1B[2K\x1B[1G"); // FIXME: Just use WriteFile
|
||||
}
|
||||
// else, do nothing for files
|
||||
}
|
||||
|
246
reactos/sdk/lib/conutils/stream.h
Normal file
246
reactos/sdk/lib/conutils/stream.h
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/stream.h
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
||||
#ifndef __STREAM_H__
|
||||
#define __STREAM_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 at the moment only supports compilation with _UNICODE defined!
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#define INVALID_CP ((UINT)-1)
|
||||
|
||||
// Shadow type, implementation-specific
|
||||
typedef struct _CON_STREAM CON_STREAM, *PCON_STREAM;
|
||||
|
||||
// typedef INT (__stdcall *CON_READ_FUNC)(IN PCON_STREAM, IN PTCHAR, IN DWORD);
|
||||
// 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])
|
||||
#define StdOut (&StdStreams[1])
|
||||
#define StdErr (&StdStreams[2])
|
||||
#else
|
||||
extern CON_STREAM csStdIn;
|
||||
extern CON_STREAM csStdOut;
|
||||
extern CON_STREAM csStdErr;
|
||||
#define StdIn (&csStdIn )
|
||||
#define StdOut (&csStdOut)
|
||||
#define StdErr (&csStdErr)
|
||||
#endif
|
||||
|
||||
BOOL
|
||||
ConStreamInitEx(
|
||||
OUT PCON_STREAM Stream,
|
||||
IN PVOID Handle,
|
||||
IN CON_STREAM_MODE Mode,
|
||||
IN UINT CacheCodePage OPTIONAL,
|
||||
// IN ReadWriteMode ????
|
||||
// IN CON_READ_FUNC ReadFunc OPTIONAL,
|
||||
IN CON_WRITE_FUNC WriteFunc OPTIONAL);
|
||||
|
||||
BOOL
|
||||
ConStreamInit(
|
||||
OUT PCON_STREAM Stream,
|
||||
IN PVOID Handle,
|
||||
// IN ReadWriteMode ????
|
||||
IN CON_STREAM_MODE Mode,
|
||||
IN UINT CacheCodePage OPTIONAL);
|
||||
|
||||
|
||||
/* Console Standard Streams initialization helpers */
|
||||
#ifdef USE_CRT
|
||||
#define ConInitStdStreamsAndMode(Mode, CacheCodePage) \
|
||||
do { \
|
||||
ConStreamInit(StdIn , stdin , (Mode), (CacheCodePage)); \
|
||||
ConStreamInit(StdOut, stdout, (Mode), (CacheCodePage)); \
|
||||
ConStreamInit(StdErr, stderr, (Mode), (CacheCodePage)); \
|
||||
} while(0)
|
||||
#else
|
||||
#define ConInitStdStreamsAndMode(Mode, CacheCodePage) \
|
||||
do { \
|
||||
ConStreamInit(StdIn , GetStdHandle(STD_INPUT_HANDLE) , (Mode), (CacheCodePage)); \
|
||||
ConStreamInit(StdOut, GetStdHandle(STD_OUTPUT_HANDLE), (Mode), (CacheCodePage)); \
|
||||
ConStreamInit(StdErr, GetStdHandle(STD_ERROR_HANDLE) , (Mode), (CacheCodePage)); \
|
||||
} while(0)
|
||||
#endif /* defined(USE_CRT) */
|
||||
|
||||
#ifdef _UNICODE
|
||||
/*
|
||||
* Use UTF8 by default for file output, because this mode is back-compatible
|
||||
* with ANSI, and it displays nice on terminals that support UTF8 by default
|
||||
* (not many terminals support UTF16 on the contrary).
|
||||
*/
|
||||
#define ConInitStdStreams() \
|
||||
ConInitStdStreamsAndMode(UTF8Text, INVALID_CP); // Cache code page unused
|
||||
#else
|
||||
/* Use ANSI by default for file output */
|
||||
#define ConInitStdStreams() \
|
||||
ConInitStdStreamsAndMode(AnsiText, INVALID_CP);
|
||||
#endif /* defined(_UNICODE) */
|
||||
|
||||
/* Stream translation modes */
|
||||
BOOL
|
||||
ConStreamSetMode(
|
||||
IN PCON_STREAM Stream,
|
||||
IN CON_STREAM_MODE Mode,
|
||||
IN UINT CacheCodePage OPTIONAL);
|
||||
|
||||
#ifdef USE_CRT
|
||||
// FIXME!
|
||||
#warning The ConStreamSetCacheCodePage function does not make much sense with the CRT!
|
||||
#else
|
||||
BOOL
|
||||
ConStreamSetCacheCodePage(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT CacheCodePage);
|
||||
#endif
|
||||
|
||||
HANDLE
|
||||
ConStreamGetOSHandle(
|
||||
IN PCON_STREAM Stream);
|
||||
|
||||
BOOL
|
||||
ConStreamSetOSHandle(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HANDLE Handle);
|
||||
|
||||
|
||||
/*
|
||||
* Console I/O utility API
|
||||
* (for the moment, only Output)
|
||||
*/
|
||||
|
||||
INT
|
||||
__stdcall
|
||||
ConWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len);
|
||||
|
||||
INT
|
||||
ConStreamWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len);
|
||||
|
||||
INT
|
||||
ConPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr);
|
||||
|
||||
INT
|
||||
ConPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
...);
|
||||
|
||||
INT
|
||||
ConResPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID);
|
||||
|
||||
INT
|
||||
ConResPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
...);
|
||||
|
||||
INT
|
||||
ConMsgPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId);
|
||||
|
||||
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
|
||||
__cdecl
|
||||
ConMsgPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
...);
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
ConClearLine(IN PCON_STREAM Stream);
|
||||
|
||||
|
||||
#endif /* __STREAM_H__ */
|
234
reactos/sdk/lib/conutils/utils.c
Normal file
234
reactos/sdk/lib/conutils/utils.c
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/utils.c
|
||||
* PURPOSE: Base set of functions for loading string resources
|
||||
* and message strings, and handle type identification.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
||||
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
|
||||
#define UNICODE
|
||||
#define _UNICODE
|
||||
|
||||
#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 <strsafe.h>
|
||||
|
||||
/* PSEH for SEH Support */
|
||||
#include <pseh/pseh2.h>
|
||||
|
||||
// #include "conutils.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...
|
||||
|
||||
// Performs MultiByteToWideChar then WideCharToMultiByte .
|
||||
// See https://github.com/pcman-bbs/pcman-windows/blob/master/Lite/StrUtils.h#l33
|
||||
// and http://www.openfoundry.org/svn/pcman/branches/OpenPCMan_2009/Lite/StrUtils.cpp
|
||||
// for the idea.
|
||||
int
|
||||
MultiByteToMultiByte(
|
||||
// IN WORD wTranslations,
|
||||
IN DWORD dwFlags,
|
||||
IN UINT SrcCodePage,
|
||||
IN LPCSTR lpSrcString,
|
||||
IN int cbSrcChar,
|
||||
IN UINT DestCodePage,
|
||||
OUT LPSTR wDestString OPTIONAL,
|
||||
IN int cbDestChar
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* '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;
|
||||
}
|
||||
|
||||
BOOL
|
||||
IsTTYHandle(IN HANDLE hHandle)
|
||||
{
|
||||
/*
|
||||
* More general test than IsConsoleHandle. Consoles, as well as
|
||||
* serial ports, etc... verify this test, but only consoles verify
|
||||
* the IsConsoleHandle test: indeed the latter checks whether
|
||||
* the handle is really handled by the console subsystem.
|
||||
*/
|
||||
return ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) == FILE_TYPE_CHAR);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
53
reactos/sdk/lib/conutils/utils.h
Normal file
53
reactos/sdk/lib/conutils/utils.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/utils.h
|
||||
* PURPOSE: Base set of functions for loading string resources
|
||||
* and message strings, and handle type identification.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
*/
|
||||
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library at the moment only supports compilation with _UNICODE defined!
|
||||
#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);
|
||||
|
||||
BOOL
|
||||
IsTTYHandle(IN HANDLE hHandle);
|
||||
|
||||
BOOL
|
||||
IsConsoleHandle(IN HANDLE hHandle);
|
||||
|
||||
|
||||
// #include <wincon.h>
|
||||
|
||||
|
||||
#endif /* __UTILS_H__ */
|
Loading…
Reference in a new issue