Example: Printing and Prompting
The ConsolePrompt function, which appears in Appendix A and provided on the Web site), contains the UNICODE and _UNICODE definitions (the definitions are commented out; remove the comment characters to build a Unicode application) and related preprocessor variables to specify the environment. The header files on the Web site also define additional modifiers to import or export the function names and to assure that the functions use the proper calling conventions.
Program 2-1. PrintMsg: Console Prompt and Print Utility Functions
Notice that ConsolePrompt returns a Boolean success indicator, exploiting ANSI C's guaranteed left-to-right "short circuit" evaluation of logical "and" operators (&&) where evaluation stops on encountering the first FALSE. This coding style may appear compact, but it has the advantage of presenting the system calls in a clear, sequential order without the clutter of numerous conditional statements. Furthermore, GetLastError will return the error from the function that failed. Windows' Boolean return values (for many functions) encourage the technique.The function does not report an error; the calling program can do this if necessary.The code exploits the documented fact that WriteConsole fails if the handle is redirected to something other than a console handle. Therefore, it is not necessary to interrogate the handle properties. The function will take advantage of the console mode when the handle is attached to a console.Also, ReadConsole returns a carriage return and line feed, so the last step is to insert a null character in the proper location over the carriage return.
/* PrintMsg.c: ConsolePrompt, PrintStrings, PrintMsg */
#include "Envirmnt.h" /* #define or #undef UNICODE here. */
#include <windows.h>
#include <stdarg.h>
BOOL PrintStrings (HANDLE hOut, ...)
/* Write the messages to the output handle. */
{
DWORD MsgLen, Count;
LPCTSTR pMsg;
va_list pMsgList; /* Current message string. */
va_start (pMsgList, hOut); /* Start processing messages. */
while ((pMsg = va_arg (pMsgList, LPCTSTR)) != NULL) {
MsgLen = _tcslen (pMsg);
/* WriteConsole succeeds only for console handles. */
if (!WriteConsole (hOut, pMsg, MsgLen, &Count, NULL)
/* Call WriteFile only if WriteConsole fails. */
&& !WriteFile (hOut, pMsg, MsgLen * sizeof (TCHAR),
&Count, NULL))
return FALSE;
}
va_end (pMsgList);
return TRUE;
}
BOOL PrintMsg (HANDLE hOut, LPCTSTR pMsg)
/* Single message version of PrintStrings. */
{
return PrintStrings (hOut, pMsg, NULL);
}
BOOL ConsolePrompt (LPCTSTR pPromptMsg, LPTSTR pResponse,
DWORD MaxTchar, BOOL Echo)
/* Prompt the user at the console and get a response. */
{
HANDLE hStdIn, hStdOut;
DWORD TcharIn, EchoFlag;
BOOL Success;
hStdIn = CreateFile (_T ("CONIN$"),
GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
hStdOut = CreateFile (_T ("CONOUT$"), GENERIC_WRITE, 0,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
EchoFlag = Echo ? ENABLE_ECHO_INPUT : 0;
Success =
SetConsoleMode (hStdIn, ENABLE_LINE_INPUT |
EchoFlag | ENABLE_PROCESSED_INPUT)
&& SetConsoleMode (hStdOut,
ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_PROCESSED_OUTPUT)
&& PrintStrings (hStdOut, pPromptMsg, NULL)
&& ReadConsole (hStdIn, pResponse,
MaxTchar, &TcharIn, NULL);
if (Success) pResponse [TcharIn - 2] = '\0';
CloseHandle (hStdIn);
CloseHandle (hStdOut);
return Success;
}
