--- mstools/samples/console/console.c 2018/08/09 18:21:18 1.1.1.2 +++ mstools/samples/console/console.c 2018/08/09 18:23:14 1.1.1.3 @@ -1,11 +1,21 @@ + +/******************************************************************************\ +* This is a part of the Microsoft Source Code Samples. +* Copyright (C) 1993 Microsoft Corporation. +* All rights reserved. +* This source code is only intended as a supplement to +* Microsoft Development Tools and/or WinHelp documentation. +* See these sources for detailed information regarding the +* Microsoft samples programs. +\******************************************************************************/ + #include #include #include #include #include "console.h" +#include "size.h" /* for resizeConBufAndWindow() */ -/* Microsoft Developer Support - Copyright (c) 1992 Microsoft Corporation */ /* used to set our initial console screen buffer size */ #define CONX 80 @@ -30,6 +40,7 @@ extern void demoScrollCon(HANDLE hConOut extern void demoSizeInfo(HANDLE hConOut); extern void demoSetCtrlHandler(HANDLE hConOut); extern void demoWriteIn(HANDLE hConOut); +// extern void demoCodePage(HANDLE hConOut); /* information to display on the screen for user to click on */ PCHAR conAPIs[] = { @@ -39,6 +50,7 @@ PCHAR conAPIs[] = { "FillConsoleOutputCharacter Writes characters to the screen buffer", "FlushConsoleInputBuffer Clears the console input buffer", "FreeConsole Frees the current console", + "GenerateConsoleCtrlEvent Generates a console control event", "GetConsoleCursorInfo Returns console size and visibility", "GetConsoleMode Returns console input or output mode", "GetConsoleScreenBufferInfo Returns screen-buffer information", @@ -69,9 +81,10 @@ PCHAR conAPIs[] = { /* this variable holds the number next to the API on the screen that */ /* the user clicks on */ -enum cAPIs { ALLOC = 1, CREATE, FILLATT, FILLCHAR, FLUSH, FREE, GETCUR, - GETMODE, GETCONINFO, GETTITLE, GETLARGEST, GETNUMEV, GETNUMBUT, PEEK, - READCONIN, READCONOUT, READCONATT, READCONCHAR, SCROLL, SETACTIVE, +enum cAPIs { ALLOC = 1, CREATE, FILLATT, FILLCHAR, FLUSH, FREE, + GENCTRL, GETCUR, GETMODE, GETCONINFO, GETTITLE, + GETLARGEST, GETNUMEV, GETNUMBUT, PEEK, READCONIN, READCONOUT, + READCONATT, READCONCHAR, SCROLL, SETACTIVE, SETCURINF, SETCURPOS, SETMODE, SETSIZE, SETATT, SETTITLE, SETINFO, SETHAND, WRITEIN, WRITEOUT, WRITEATT, WRITECHAR }; @@ -115,31 +128,6 @@ CHAR myGetchar(void) return(chBuf); } - -/******************************************************************** -* FUNCTION: perrError(void) * -* * -* PURPOSE: beep twice and abort program * -* * -* INPUT: none * -* * -* RETURNS: none * -* * -* COMMENTS: only called from perr() when a fatal error has occurred * -********************************************************************/ - -void perrError(void) -{ - DWORD dwLastError; /* for debugger purposes */ - - dwLastError = GetLastError(); - /* we can't output an error message - beep instead */ - Beep(600, 500); - Beep(700, 500); - exit(1); -} - - /********************************************************************* * FUNCTION: perr(PCHAR szFileName, int line, PCHAR szApiName, * * DWORD dwError) * @@ -154,84 +142,39 @@ void perrError(void) * RETURNS: none * *********************************************************************/ -/* this is the size of the buffer for the error message text */ -#define MSG_BUF_SIZE 512 +/* maximum size of the buffer to be returned from FormatMessage */ +#define MAX_MSG_BUF_SIZE 512 void perr(PCHAR szFileName, int line, PCHAR szApiName, DWORD dwError) { - BOOL bSuccess; - HANDLE hConTemp; /* temp console buffer to put error message on */ - HANDLE hCurrentCon; /* to save the current console so we can restore it */ - CHAR szTemp[256]; - DWORD cCharsWritten; - DWORD dwLastError; /* for debugging purposes */ - CHAR msgBuf[MSG_BUF_SIZE]; /* buffer for message text from system */ + CHAR szTemp[1024]; + DWORD cMsgLen; + CHAR *msgBuf; /* buffer for message text from system */ + int iButtonPressed; /* receives button pressed in the error box */ - /* create a handle to the current console buffer */ - hCurrentCon = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_READ | - FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hCurrentCon == INVALID_HANDLE_VALUE) - { - dwLastError = GetLastError(); - /* just in case this works */ - printf("Fatal error in perr() on line %d: %d\n", __LINE__, dwLastError); - Beep(600, 500); - exit(1); - } - /* create a temporary console buffer that we can write on */ - hConTemp = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, - NULL); - if (hConTemp == INVALID_HANDLE_VALUE) - { - dwLastError = GetLastError(); - printf("Fatal error in perr() on line %d: %d\n", __LINE__, dwLastError); - Beep(600, 500); - exit(1); - } - /* make the temp buffer to the current buffer */ - bSuccess = SetConsoleActiveScreenBuffer(hConTemp); - if (!bSuccess) - { - dwLastError = GetLastError(); - printf("Fatal error in perr() on line %d: %d\n", __LINE__, dwLastError); - Beep(600, 500); - exit(1); - } - /* set red on white text for future text output */ - SetConsoleTextAttribute(hConTemp, FOREGROUND_RED | BACKGROUND_WHITE); /* format our error message */ - sprintf(szTemp, "%s: Error %d from %s on line %d\n", szFileName, + sprintf(szTemp, "%s: Error %d from %s on line %d:\n", szFileName, dwError, szApiName, line); - /* write the message to the console */ - bSuccess = WriteFile(hConTemp, szTemp, strlen(szTemp), &cCharsWritten, - NULL); - if (!bSuccess) - perrError(); - memset(msgBuf, 0, sizeof(msgBuf)); /* get the text description for that error number from the system */ - cCharsWritten = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | - getConX(hConTemp), NULL, dwError, MAKELANGID(0, SUBLANG_ENGLISH_US), - msgBuf, sizeof(msgBuf), NULL); - if (!cCharsWritten) - perrError(); + cMsgLen = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | 40, NULL, dwError, + MAKELANGID(0, SUBLANG_ENGLISH_US), (LPTSTR) &msgBuf, MAX_MSG_BUF_SIZE, + NULL); + if (!cMsgLen) + sprintf(szTemp + strlen(szTemp), "Unable to obtain error message text! \n" + "%s: Error %d from %s on line %d", __FILE__, + GetLastError(), "FormatMessage", __LINE__); else - { - /* write the text description to the console */ - bSuccess = WriteFile(hConTemp, msgBuf, strlen(msgBuf), &cCharsWritten, - NULL); - if (!bSuccess) - perrError(); - } - myGetchar(); - /* reset the current buffer to the original one */ - bSuccess = SetConsoleActiveScreenBuffer(hCurrentCon); - if (!bSuccess) - perrError(); - CloseHandle(hConTemp); - bSuccess = CloseHandle(hCurrentCon); - if (!bSuccess) - perrError(); + strcat(szTemp, msgBuf); + strcat(szTemp, "\n\nContinue execution?"); + MessageBeep(MB_ICONEXCLAMATION); + iButtonPressed = MessageBox(NULL, szTemp, "Console API Error", + MB_ICONEXCLAMATION | MB_YESNO | MB_SETFOREGROUND); + /* free the message buffer returned to us by the system */ + if (cMsgLen) + LocalFree((HLOCAL) msgBuf); + if (iButtonPressed == IDNO) + exit(1); return; } @@ -320,46 +263,18 @@ SHORT getConY(HANDLE hCon) void showConAPIs(HANDLE hConsole) { - COORD coordScreen = {CONX, CONY}; /* used to set the console buffer size */ - /* used to set the console window size */ - SMALL_RECT srWindowRect = {0, 0, CONX - 1, CONY - 1}; + COORD coordScreen; int i; BOOL bSuccess; DWORD cCharsWritten; CHAR szTemps[128]; - WORD wConBufSize; /* used to hold current console buffer size */ - /* get the current console buffer size, in chars */ - wConBufSize = getConX(hConsole) * getConY(hConsole); - /* force an CONX x CONY screen */ - /* if the current buffer is larger than what we want, resize the */ - /* console window first, then the buffer */ - if (wConBufSize > CONX * CONY) - { - bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); - PERR(bSuccess, "SetConsoleWindowInfo"); - bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); - PERR(bSuccess, "SetConsoleScreenBufferSize"); - } - /* if the current buffer is smaller than what we want, resize the */ - /* buffer first, then the console window */ - if (wConBufSize < CONX * CONY) - { - bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); - PERR(bSuccess, "SetConsoleScreenBufferSize"); - bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); - PERR(bSuccess, "SetConsoleWindowInfo"); - } - coordScreen.X = 0; - coordScreen.Y = 0; - /* set the screen */ - bSuccess = FillConsoleOutputAttribute(hConsole, BACKGROUND_BLUE, - CONX * CONY, coordScreen, &cCharsWritten); - PERR(bSuccess, "FillConsoleOutputAttribute"); + resizeConBufAndWindow(hConsole, CONX, CONY); /* defined in size.c */ /* set attributes for new writes to the console */ bSuccess = SetConsoleTextAttribute(hConsole, BACKGROUND_BLUE | FOREGROUND_WHITE); PERR(bSuccess, "SetConsoleTextAttribute"); + cls(hConsole); /* will clear screen to newly set color attribute */ /* fill screen with API list */ for (i = 0; i < sizeof(conAPIs) / sizeof(conAPIs[0]); i++) { @@ -384,7 +299,7 @@ void showConAPIs(HANDLE hConsole) PERR(bSuccess, "FillConsoleOutputAttribute"); } myPuts(hConsole, "\nClick on an API to see a demonstration of that API.\n" - "Hit ESC to exit the program.\n"); + "Hit ESC to exit the program."); return; } @@ -438,8 +353,6 @@ void putStatusLine(HANDLE hOut, PCHAR bu static void demoAPI(HANDLE *phConsole, enum cAPIs apiNumber) { - const COORD coordScreen = {0, 0}; - DWORD cCharsWritten; BOOL bSuccess; HANDLE hConTemp; CHAR szConsoleTitle[128]; /* to store the console title */ @@ -455,12 +368,9 @@ static void demoAPI(HANDLE *phConsole, e bSuccess = SetConsoleActiveScreenBuffer(hConTemp); PERR(bSuccess, "SetConsoleActiveScreenBuffer"); /* clear screen & save the console title */ - cls(hConTemp); - bSuccess = FillConsoleOutputAttribute(hConTemp, BACKGROUND_CYAN, - getConX(hConTemp) * getConY(hConTemp), coordScreen, &cCharsWritten); - PERR(bSuccess, "FillConsoleOutputAttribute"); bSuccess = SetConsoleTextAttribute(hConTemp, BACKGROUND_CYAN); PERR(bSuccess, "SetConsoleTextAttribute"); + cls(hConTemp); /* will clear with new color attribute */ dwCharsRead = GetConsoleTitle(szConsoleTitle, sizeof(szConsoleTitle)); PERR(dwCharsRead, "GetConsoleTitle"); @@ -533,6 +443,7 @@ static void demoAPI(HANDLE *phConsole, e demoSizeInfo(hConTemp); break; case SETHAND: + case GENCTRL: demoSetCtrlHandler(hConTemp); break; case WRITEIN: @@ -572,11 +483,24 @@ void cls(HANDLE hConsole) COORD coordScreen = { 0, 0 }; /* here's where we'll home the cursor */ BOOL bSuccess; DWORD cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ + DWORD dwConSize; /* number of character cells in the current buffer */ + /* get the number of character cells in the current buffer */ + bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi); + PERR(bSuccess, "GetConsoleScreenBufferInfo"); + dwConSize = csbi.dwSize.X * csbi.dwSize.Y; /* fill the entire screen with blanks */ bSuccess = FillConsoleOutputCharacter(hConsole, (TCHAR) ' ', - getConX(hConsole) * getConY(hConsole), coordScreen, &cCharsWritten); + dwConSize, coordScreen, &cCharsWritten); PERR(bSuccess, "FillConsoleOutputCharacter"); + /* get the current text attribute */ + bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi); + PERR(bSuccess, "ConsoleScreenBufferInfo"); + /* now set the buffer's attributes accordingly */ + bSuccess = FillConsoleOutputAttribute(hConsole, csbi.wAttributes, + dwConSize, coordScreen, &cCharsWritten); + PERR(bSuccess, "FillConsoleOutputAttribute"); /* put the cursor at (0, 0) */ bSuccess = SetConsoleCursorPosition(hConsole, coordScreen); PERR(bSuccess, "SetConsoleCursorPosition"); @@ -604,7 +528,6 @@ void setConTitle(PCHAR szTitle) return; } - /********************************************************************* * FUNCTION: main * * * @@ -623,10 +546,10 @@ void setConTitle(PCHAR szTitle) * for a normal exit * *********************************************************************/ -int main() +int main(void) { BOOL bSuccess; - HANDLE hStdIn, hStdOut; /* standard input and standard output */ + HANDLE hStdIn, hStdOut; /* standard input, output handles */ DWORD dwMode; /* array of console input event records */ INPUT_RECORD inputBuffer; @@ -638,25 +561,27 @@ int main() DWORD cCharsRead; enum cAPIs apiNumber; /* the index number of the API read from the screen */ /* used when turning off the cursor */ - CONSOLE_CURSOR_INFO cci = {100, FALSE}; + CONSOLE_CURSOR_INFO cciHidden = {100, FALSE}; + /* Check to make sure we are running on Windows NT */ + if( GetVersion() & 0x80000000 ) + { + MessageBox(NULL, "Sorry, this application requires Windows NT.\n" + "This application will now terminate.", + "Error: Windows NT Required to Run", MB_OK ); + return(1); + } /* free the console and immediately allocate a new one. This is done so */ /* that when debugging under ntsd, the application output will not be */ - /* intermingled with the debugger output. This section can be removed */ - /* without any change in the behavior of this program */ + /* intermingled with the debugger output. This also makes cleanup */ + /* much easier; we won't need to restore the cursor, buffer/console */ + /* sizes, screen colors, etc. since we'll have our own console window */ + /* that will go away when we terminate. */ bSuccess = FreeConsole(); /* C run-time output will not work from now on! */ - if (!bSuccess) - { - Beep(600, 500); /* can't output an error message! */ - return(1); - } + PERR(bSuccess, "FreeConsole"); bSuccess = AllocConsole(); - if (!bSuccess) - { - Beep(600, 500); /* can't output an error message! */ - return(2); - } + PERR(bSuccess, "AllocConsole"); /* let's put up a meaningful console title */ bSuccess = SetConsoleTitle("Win32 Console API Demo"); PERR(bSuccess, "SetConsoleTitle"); @@ -673,8 +598,8 @@ int main() bSuccess = SetConsoleMode(hStdIn, (dwMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)) | ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); PERR(bSuccess, "SetConsoleMode"); - /* hide the cursor */ - bSuccess = SetConsoleCursorInfo(hStdOut, &cci); + /* save then hide the cursor */ + bSuccess = SetConsoleCursorInfo(hStdOut, &cciHidden); PERR(bSuccess, "SetConsoleCursorInfo"); /* resize console to CONX * CONY and put list of console APIs up */ showConAPIs(hStdOut); @@ -683,7 +608,7 @@ int main() szLineBuf = (char *) malloc(getConX(hStdOut)); PERR(szLineBuf, "malloc"); - for(;;) + do { /* read an input events from the input event queue */ bSuccess = ReadConsoleInput(hStdIn, &inputBuffer, 1, &dwInputEvents); @@ -697,11 +622,6 @@ int main() sprintf(bOutBuf, "key: virtual=%d ascii=%c", inputBuffer.Event.KeyEvent.wVirtualKeyCode, inputBuffer.Event.KeyEvent.uChar.AsciiChar); - if (inputBuffer.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) - { - free(szLineBuf); /* free allocated line buffer */ - return(0); - } putStatusLine(hStdOut, bOutBuf); } break; @@ -736,7 +656,10 @@ int main() Sleep(1000); break; } /* switch */ - } /* while */ + /* when we receive an esc down key, drop out of do loop */ + } while (!(inputBuffer.EventType == KEY_EVENT && + inputBuffer.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE && + inputBuffer.Event.KeyEvent.bKeyDown)); free(szLineBuf); /* free allocated line buffer */ return(0); }