Niektóre aplikacje konsolowe wymagają by podczas ich działania, możliwe było zarówno wprowadzanie jak i wyświetlanie danych. Wówczas w aplikacji należy pobrać dwa uchwyty konsoli : jeden dla wejścia a drugi dla wyjścia konsoli.
Tworzymy program, który po uruchomieniu czeka na podanie napisu. Następnie kolor podanego napisu zmieniany jest na niebieski i wyświetlany w konsoli. Podobnie jak w przykładzie poprzedniego ćwiczenia, na początku definiujemy wszystkie dyrektywy, stałe i funkcje potrzebne do działania naszego programu:
.586 ;typ instrukcji procesora
.MODEL
FLAT,STDCALL
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
STD_OUTPUT_HANDLE EQU -11
STD_INPUT_HANDLE EQU -10
FOREGROUND_BLUE EQU 1h
FOREGROUND_INTENSITY EQU 8h
COL1 EQU 1h + 8h
EXTERN AllocConsole@0:NEAR
EXTERN FreeConsole@0:NEAR
EXTERN GetStdHandle@4:NEAR
EXTERN ExitProcess@4:NEAR
EXTERN WriteConsoleA@20:NEAR
EXTERN CharToOemA@8:NEAR
EXTERN SetConsoleTextAttribute@8:NEAR
EXTERN ReadConsoleA@20:NEAR
EXTERN lstrlenA@4:NEAR
Jednak zamiast pliku masm32rt.inc umieszczamy tu biblioteki
user32.lib i kernel32.lib, gdyż nie wymagamy wszystkich tych samych funkcji i stałych co w pliku zdefiniowanym w poprzednim przykładzie. Obok standardowego wyjścia konsoli - STD_OUTPUT_HANDLE
, definiujemy również standardowe wejście na konsolę - STD_INPUT_HANDLE
. Określamy również kolor wyświetlanego tekstu jako : COL1
, będący złożeniem stałych FOREGROUND_BLUE
- koloru niebieskiego i FOREGROUND_INTENSITY
, określającego pogrubioną czcionkę. Obok wykorzystywanych w poprzednim przykładzie funkcji, w programie użyjemy jeszcze: SetConsoleTextAttribute@8
i ReadConsoleA@20
. SetConsoleTextAttribute@8
określa po podaniu wartości określonego koloru i uchwytu konsoli kolor wyświetlanego tekstu, natomiast ReadConsoleA@20
pobiera tekst od użytkownika. Definicja funkcji w WinAPI wygląda następująco:
BOOL WINAPI ReadConsole(
HANDLE hConsoleInput, //uchwyt konsoli
LPVOID lpBuffer, //wskaźnik na zmienną do której zostanie zapisany tekst
DWORD nNumberOfCharsToRead, //ilość znaków do przeczytania
LPDWORD lpNumberOfCharsRead, //ilość znaków przeczytanych
LPVOID pInputControl //parametr zarezerwowany- wynosi 0
);
Następnie określamy sekcje danych wykorzystywanych w programie:
.DATA?
HANDL DWORD ? ;uchwyt konsoli dla wyjścia
HANDL1 DWORD ? ;uchwyt konsoli dla wyjścia
LENS DWORD ? ;parametr dla funkcji WriteConsole i ReadConsole
.DATA
BUF DB 200 DUP (0)
tekst DB 'Wprowadź tekst:',10,13,0 ;komunikat
Na początku w porównaniu do poprzedniego przykładu należy pobrać za pomocą funkcji GetStdHandle@4
,
dwa razy uchwyt konsoli, zarówno dla wejścia jak i wyjścia:
.CODE
START:
CALL AllocConsole@0
PUSH STD_OUTPUT_HANDLE
CALL GetStdHandle@4
MOV HANDL,EAX
PUSH STD_INPUT_HANDLE
CALL GetStdHandle@4
MOV HANDL1,EAX
Następnie konwertujemy napis i wyświetlamy komunikat funkcją WriteConsoleA@20
:
PUSH OFFSET tekst
PUSH OFFSET tekst
CALL CharToOemA@8
PUSH OFFSET tekst
CALL lstrlenA@4
PUSH 0
PUSH OFFSET LENS
PUSH EAX
PUSH OFFSET tekst
PUSH HANDL
CALL WriteConsoleA@20
Pobieramy ciąg znaków od użytkownika:
PUSH 0
PUSH OFFSET LENS
PUSH 200
PUSH OFFSET BUF
PUSH HANDL1
CALL ReadConsoleA@20
Ustawiamy nowy kolor naszego tekstu:
PUSH COL1
PUSH HANDL
CALL SetConsoleTextAttribute@8
I wyświetlamy ponownie nasz tekst:
PUSH OFFSET BUF
CALL lstrlenA@4
PUSH 0
PUSH OFFSET LENS
PUSH EAX
PUSH OFFSET BUF
PUSH HANDL
CALL WriteConsoleA@20
Na końcu programu umieszczamy pętlę opóźniającą, by nasz tekst jakiś czas wyświetlał się na ekranie:
MOV EAX,05FFFFFFFH
opoznienie:
LOOP opoznienie
CALL FreeConsole@0
PUSH 0
CALL ExitProcess@4
RET
END START
Przykładowe wywołanie gotowego programu wygląda następująco:
Całość programu przedstawiona jest na poniższym listingu:
.586 ;typ instrukcji procesora
.MODEL
FLAT,STDCALL
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
STD_OUTPUT_HANDLE EQU -11
STD_INPUT_HANDLE EQU -10
FOREGROUND_BLUE EQU 1h
FOREGROUND_INTENSITY EQU 8h
COL1 EQU 1h + 8h
EXTERN AllocConsole@0:NEAR
EXTERN FreeConsole@0:NEAR
EXTERN GetStdHandle@4:NEAR
EXTERN ExitProcess@4:NEAR
EXTERN WriteConsoleA@20:NEAR
EXTERN CharToOemA@8:NEAR
EXTERN SetConsoleTextAttribute@8:NEAR
EXTERN ReadConsoleA@20:NEAR
EXTERN lstrlenA@4:NEAR
.DATA?
HANDL DWORD ? ;uchwyt konsoli dla wyjścia
HANDL1 DWORD ? ;uchwyt konsoli dla wyjścia
LENS DWORD ? ;parametr dla funkcji WriteConsole i ReadConsole
.DATA
BUF DB 200 DUP (0)
tekst DB 'Wprowadź tekst:',10,13,0 ;komunikat
.CODE
START:
CALL AllocConsole@0
PUSH STD_OUTPUT_HANDLE
CALL GetStdHandle@4
MOV HANDL,EAX
PUSH STD_INPUT_HANDLE
CALL GetStdHandle@4
MOV HANDL1,EAX
PUSH OFFSET tekst
PUSH OFFSET tekst
CALL CharToOemA@8
PUSH OFFSET tekst
CALL lstrlenA@4
PUSH 0
PUSH OFFSET LENS
PUSH EAX
PUSH OFFSET tekst
PUSH HANDL
CALL WriteConsoleA@20
PUSH 0
PUSH OFFSET LENS
PUSH 200
PUSH OFFSET BUF
PUSH HANDL1
CALL ReadConsoleA@20
PUSH COL1
PUSH HANDL
CALL SetConsoleTextAttribute@8
PUSH OFFSET BUF
CALL lstrlenA@4
PUSH 0
PUSH OFFSET LENS
PUSH EAX
PUSH OFFSET BUF
PUSH HANDL
CALL WriteConsoleA@20
MOV EAX,05FFFFFFFH
opoznienie:
LOOP opoznienie
CALL FreeConsole@0
PUSH 0
CALL ExitProcess@4
RET
END START
Napisać program który pobiera ciąg znaków od użytkownika, określającego jeden z trzech kolorów: niebieski, czerwony lub zielony. W przypadku wpisania nazwy określonego koloru, w oknie konsoli wyświetla się komunikat o podanym przez użytkownika kolorze oraz zapytanie o zakończenie programu, wywoływane przez naciśnięcie przycisku ESC. Przykładowe wywołania programu przedstawione są poniżej - Rys.2a i Rys.2b.