| ||
Consider several simple console functions and their use.
Working with inherited console isn't always convenient . To create a new console, the AllocConsole function is used. When the program terminates, all automatically allocated consoles are released. However, this can be forced using the FreeConsole function. To obtain the console descriptor, the GetStdHandle function is used, which you have already encountered . This function accepts one of the following three constants as an argument:
STD_INPUT_HANDLE equ -10 ; For input STD_OUTPUT_HANDLE equ -11 ; For output STD_ERROR_HANDLE equ -12 ; For an error message
It is necessary to mention that a process can have only one console; therefore, execution of the FreeConsole function is required when the program starts. If the program is started from another console, it inherits that console. Thus, it is impossible to create a new console until the process detaches itself from its current (inherited) console by executing the FreeConsole function.
For reading data from the console buffer, the ReadConsole function is used. The values of parameters accepted by this function (from left to right) are as follows : [i]
FirstDescriptor of the input buffer
SecondAddress of the buffer, in which the information for input is loaded
ThirdLength of that buffer
FourthNumber of symbols actually read
FifthReserved
To set the cursor position within the console, use the SetConsoleCursorPosition function, which accepts the following parameters:
FirstDescriptor of the console's input buffer
SecondThe coord structure, written as follows:
COORD STRUC X WORD ? Y WORD ? COORD ENDS
I'd like to mention again that the second parameter isn't the pointer to the structure (which usually is the case); on the contrary, it is the structure itself. Actually, for an assembler, this is simply a double word ( DWORD ), for which the least significant word stands for the X-coordinate and most significant word stands for the Y-coordinate.
The color of characters to be displayed can be set by the SetConsoleTextAttribute function. The first parameter of this function is the descriptor of the console's output buffer, and the second parameter specifies the foreground and background colors.
Actual color is obtained by combining (via the sum or the logical OR operation) two or more of the constants listed after this paragraph. Note that in addition to the possibility of creating combinations of color and intensity, it is possible to combine different colors (see Listing 8.3).
FOREGROUND_BLUE equ 1h ; Blue foreground letters FOREGROUND_GREEN equ 2h ; Green foreground letters FOREGROUND_RED equ 4h ; Red foreground letters FOREGROUND_INTENSITY equ 8h ; Foreground intensity BACKGROUND_BLUE equ 10h ; Blue background BACKGROUND_GREEN equ 20h ; Green background BACKGROUND_RED equ 40h ; Red background BACKGROUND_INTENSITY equ 80h ; Increased background intensity
To define the console window header, the SetConsoleTitle function is used. This function accepts the only parameter that represents the address of a zero- terminated string. At this point, it is necessary to point out that in contrast to output into the console window, where DOS-encoding was needed, here you need Windows encoding. To solve this problem and never return to it again, consider how this goal can be achieved using Windows functionality.
In Windows, there is a special function called CharToOem , which you considered in Chapter 6. The first parameter of this function is the pointer to the string that needs to be converted, and the second parameter is the pointer to the string that would store the result. Note that the result can be placed into the string being converted. Thus, the encoding problem will be solved . Later, in console applications, I will use this function without special mention.
You have considered only a small number of console functions, the total number of which is about 50. However, there is no need to describe them all. Some of them will be mentioned later; however, I hope that if you are interested, you can find information on other console functions on your own and use them according to the examples and explanations provided in the book. I'd only like to mention that most console functions typically return nonzero values if they terminate normally. In the case of an error, a zero value will be placed into the EAX register.
Well, it is time to proceed with examples.
.586P ; Flat memory model .MODEL FLAT, stdcall ; Constants STD_OUTPUT_HANDLE equ -11 STD_INPUT_HANDLE equ -10 ; Color attributes FOREGROUND_BLUE equ 1h ; Blue foreground FOREGROUND_GREEN equ 2h ; Green foreground FOREGROUND_RED equ 4h ; Red foreground FOREGROUND_INTENSITY equ 8h ; Increased foreground intensity BACKGROUND_BLUE equ l0h ; Blue background BACKGROUND_GREEN equ 2Oh ; Green background BACKGROUND_RED equ 4Oh ; Red background BACKGROUND_INTENSITY equ 80h ; Increased background intensity COL1 = 2h+8h ; Color of the text being displayed COL2 = 1h+2h+8h ; Second color of the text being displayed ; Prototypes of external procedures EXTERN GetStdHandle@4:NEAR EXTERN WriteConsoleA@20:NEAR EXTERN SetConsoleCursorPosition@8:NEAR EXTERN SetConsoleTitleA@4:NEAR EXTERN FreeConsole@0:NEAR EXTERN AllocConsole@0:NEAR EXTERN CharToOemA@8:NEAR EXTERN SetConsoleCursorPosition@8:NEAR EXTERN SetConsoleTextAttribute@8:NEAR EXTERN ReadConsoleA@20:NEAR EXTERN SetConsoleScreenBufferSize@8:NEAR EXTERN ExitProcess@4:NEAR ; Directives for the linker to include libraries includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ;----------------------------------------------- COOR STRUC X WORD ? Y WORD ? COOR ENDS ; Data segment _DATA SEGMENT HANDL DWORD ? HANDL1 DWORD ? STR1 DB "Enter a string:", 13, 10, 0 STR2 DB "A simple example of a console application", 0 BUF DB 200 dup(?) LENS DWORD ? ; Number of displayed symbols CRD COOR <?> _DAT'A ENDS ; Code segment _TEXT SEGMENT START: ; Convert the string PUSH OFFSET STR1 PUSH OFFSET STR1 CALL CharToOemA@8 ; Create a console ; First, release the existing console CALL FreeConsole@0 CALL AllocConsole@0 ; Get the HANDL1 input handle PUSH STD_INPUT_HANDLE CALL GetStdHandle@4 MOV HANDL1, EAX ; Get the HANDL output handle PUSH STD_OUTPUT_HANDLE CALL GetStdHandle@4 MOV HANDL, EAX ; Set the new size of the console window MOV CRD.X, 100 MOV CRD.Y, 25 PUSH CRD PUSH EAX CALL SetConsoleScreenBufferSize@8 ; Specify the console window header PUSH OFFSET STR2 CALL SetConsoleTitleA@4 ; Set the cursor position MOV CRD.X, 0 MOV CRD.Y, 10 PUSH CRD PUSH HANDL CALL SetConsoleCursorPosition@8 ; Set the color attributes of the text being displayed PUSH COL1 PUSH HANDL CALL SetConsoleTextAttribute@8 ; Output the string PUSH OFFSET STR1 CALL LENSTR ; EBX contains the string length PUSH 0 PUSH OFFSET LENS PUSH EBX PUSH OFFSET STR1 PUSH HANDL CALL WriteConsoleA@20 ; Wait for string input PUSH 0 PUSH OFFSET LENS PUSH 200, PUSH OFFSET BUF PUSH HANDL1 CALL ReadConsoleA@20 ; Display the entered string ; First, specify the color attributes of the displayed text PUSH COL2 PUSH HANDL CALL SetConsoleTextAttribute@8 ;------------------ PUSH 0 PUSH OFFSET LENS PUSH [LENS] ; Length of the entered string PUSH OFFSET BUF PUSH HANDL CALL WriteConsoleA@20 ; A small delay MOV ECX, 01FFFFFFFH L1: LOOP L1 ; Close the console CALL FreeConsole@0 CALL ExitProcess@4 ; String [EBP+08H] ; Length is in EBX LENSTR PROC ENTER 0, 0 PUSH EAX ;---------------------- CLD MOV EDI, DWORD PTR [EBP+08H] MOV EBX, EDI MOV ECX, 100 ; Limit the string length XOR AL, AL REPNE SCASB ; Find the 0 character SUB EDI, EBX ; String length including 0 MOV EBX, EDI DEC EBX ;---------------------- POP EAX LEAVE RET 4 LENSTR ENDP _TEXT ENDS END START
Listing 8.3 contains two functions in addition to the ones that I have described. These are the SetConsoleCursorPosition and SetConsoleScreenBufferSize functions. The SetConsoleCursorPosition function is used to set the cursor position. With this function, everything is clear and obvious. The SetConsoleScreenBufferSize function is less self-evident. It sets the size of the console window buffer. This cannot decrease the size of an already existing buffer (the existing window); it can only increase it.
Note that in the LENSTR function you are now using the ENTER-LEAVE pair of commands (see Chapter 2) instead of traditional combinations, such as PUSH BP/ MOV BP, SP/ SUB SP, N - MOV SP, BP/ POP BP . Honestly, the ENTER-LEAVE pair doesn't provide any particular advantage. It's simply time to extend your available fund of commands.
[i] As you/probably understand, for an assembler, practically all parameters have the DWORD type. By their meaning, however, they are either addresses or values. Therefore, it is much easier to list them by specifying their meaning rather than writing a function in C notation.
| ||