Создаю папку masm64, в каталоге masm64 создаю подкаталоги bin, include, lib, examples. В каталоги include, lib копирую содержимое masm64.zip Содержимое для каталога bin (cvtres.exe, link.exe, ml64.exe, msobj80.dll, mspdb80.dll, msvcp80.dll, msvcp90.dll, msvcr80.dll, msvcr90.dll, rc.exe, rc.hlp, rcdll.dll) взято из комплекта C++ компиляторов от Microsoft Microsoft Windows SDK for Windows 7 and .NET Framework 4 (распространяется бесплатно) Создаю в папке Include файл win64a.inc следующего содержания Код (ASM): OPTION DOTNAME OPTION PROLOGUE:rbpFramePrologue OPTION EPILOGUE:none include win64.inc include temphls.inc include kernel32.inc includelib kernel32.lib include ntdll.inc includelib ntdll.lib include user32.inc includelib user32.lib ;--------------------------- pushaddr macro x db 68h dd x endm IMAGE_BASE equ 400000h ;--------------------------------- include gdi32.inc includelib gdi32.lib ;--------------------------------- include comctl32.inc includelib comctl32.lib include comdlg32.inc includelib comdlg32.lib include shell32.inc includelib shell32.lib ;-------------------------------- du macro string local bslash bslash = 0 irpc c,<string> if bslash eq 0 if '&c' eq "/" bslash = 1 elseif '&c'gt 127 db ('&c'- 0B0h),4 else dw '&c' endif else bslash = 0 if '&c' eq "n" DW 0Dh,0Ah elseif '&c' eq "/" dw '/' elseif '&c' eq "r" dw 0Dh elseif '&c' eq "l" dw 0Ah elseif '&c' eq "s" dw 20h elseif '&c' eq "c" dw 3Bh elseif '&c' eq "t" dw 9 endif endif endm dw 0 endm Пишу bat-файл следующего содержания Код (Text): cls set masm64_path=\masm64\ set filename= <--- здесь будет имя asm-файла del %filename%.exe %masm64_path%bin\ml64 /Cp /c /I"%masm64_path%Include" %filename%.asm || exit %masm64_path%bin\link /SUBSYSTEM:CONSOLE /LIBPATH:"%masm64_path%Lib" ^ /entry:WinMain %filename%.obj /LARGEADDRESSAWARE:NO ^ /ALIGN:16 /SECTION:.text,W /BASE:0x400000 || exit del %filename%.obj Запрос и освобождение консолиПрограмма, работающая в консольном режиме, либо наследует текущую консоль, либо открывает новую, если наследовать нечего. Примеры программ ниже создают для себя собственную консоль. Любые изменения в окне консоли будут касаться только этой консоли и не будут отражаться в наследованной консоли. Для создания консоли используется функция AllocConsole. Функция не имеет аргументов и предоставляет вызвавшей ее программе новую консольную сессию. При успешном завершении функция AllocConsole возвращает ненулевое значение, при возникновении ошибки ― ноль. Все выделенные консоли автоматически освобождаются при завершении запросившей их программы. При выделении консоли будет создано окно, которое имеет те же свойства (почти ), что и окно Windows в GUI-программе. Оно содержит заголовок, системное меню, кнопки минимизации, полноэкранной развертки, закрытия окна и вертикальную и горизонтальную линейки прокрутки. Программа, которая будет работать в консольном режиме и будет использовать собственную консоль, прежде чем запросить новую консоль должна освободить унаследованную консоль с помощью функции FreeConsole. Функция не имеет аргументов. При успешном завершении функция FreeConsole возвращает ненулевое значение, при возникновении ошибки ― ноль. Все программы ниже будут начинаться с Код (ASM): invoke FreeConsole;освободить существующую консоль invoke AllocConsole;создать консоль для себя Даже если родительская консоль отсутствует, вызов FreeConsole не повлечет за собой нежелательных последствий и новая консоль будет создана. Консоль, предоставленная программе автоматически освобождается при завершении программы, либо программа может принудительно освободить консоль функцией FreeConsole. Определение заголовка окна консолиДля формирования строки заголовка используется функция SetConsoleTitle. Если в строке заголовка есть кириллица, то заголовок должен быть сохранен в кодировке 866cp. Если функцию SetConsoleTitle не использовать, то в заголовке консольного окна будет отображается полный путь до консольного приложения. При успешном завершении функция SetConsoleTitle возвращает ненулевое значение, при возникновении ошибки ― ноль. Получение стандартных дескрипторов ввода и выводаБольшинству функций, которые поддерживают консольный интерфейс, для выполнения операций ввода/вывода требуются стандартные дескрипторы связанные со стандартными потоками ввода и вывода. Стандартный поток ввода связан с клавиатурой, мышью, файлами. Стандартный поток вывода ― с экраном, принтером, файлами. Для получения стандартного дескриптора используется функция GetStdHandle с единственным аргументом dwStdDev dwStdDevзначениеназначениеSTD_INPUT_HANDLE-10стандартный поток вводаSTD_OUTPUT_HANDLE-11стандартный поток выводаSTD_ERROR_HANDLE-12стандартный поток ошибокФункция GetStdHandle возвращает дескриптор запрашиваемого потока либо значение INVALID_HANDLE_VALUE в случае ошибки. Вывод текста в консолиОдин из способов вывести текст в консоль ― использовать функцию WriteConsole Код (C): BOOL WriteConsole ( HANDLE hConOut, // дескриптор потока вывода CONST VOID * lpString, // указатель на выводимую строку DWORD dwLen, // количество выводимых символов LPDWORD lpdwNumWritten, // действительное количество выводимых символов LPVOID lpNotUsed /* зарезервирован */ ); Строка выводится с текущими цветовыми атрибутами для текста и фона. Вывод начинается с текущей позиции курсора. Позиция курсора автоматически изменяется после вывода очередной строки. При успешном завершении функция WriteConsole возвращает ненулевое значение, при возникновении ошибки ― ноль. Ввод из консолиДля чтения из клавиатуры используется функция ReadConsole Код (C): BOOL ReadConsole ( HANDLE hConIn, // дескриптор входного потока LPVOID * lpBuf, // указатель на массив символов, в который будет записана строка DWORD dwLen, // возможное количество вводимых символов (величина буфера) LPDWORD lpdwNumRead, // количество фактически введенных символов LPVOID lpNotUsed /* зарезервирован */ ); При успешном завершении функция ReadConsole возвращает ненулевое значение, при возникновении ошибки ― ноль. Действие функции ReadConsole определяется с помощью функции SetConsoleMode Установка позиции курсораТекущая позиция курсора на экране устанавливается функцией SetConsoleCursorPosition Код (C): SetConsoleCursorPosition ( HANDLE hConOut, // дескриптор стандартного вывода COORD XY /* структура типа COORD, содержащая координаты нового курсора*/ ); Код (ASM): COORD struct dw X dw Y COORD ends При успешном завершении функция SetConsoleCursorPosition возвращает ненулевое значение, при возникновении ошибки ― ноль. содержимое asm-файла Код (ASM): ; CONSOLE # include win64a.inc BLACK equ 0 BLUE equ 1 GREEN equ 2 CYAN equ 3 RED equ 4 PURPLE equ 5 YELLOW equ 6 SYSTEM equ 7 GREY equ 8 BRIGHTBLUE equ 9 BRIGHTGREEN equ 10 BRIGHTCYAN equ 11 BRIGHTRED equ 12 BRIGHTPURPLE equ 13 BRIGHTYELLOW equ 14 WHITE equ 15 MAXSCREENX = 80 MAXSCREENY = 25 buffersize = 200 X = 0 Y = 10 .code WinMain proc local LENS:qword ;количество выведенных символов local BUFF[buffersize]:byte local ConsoleWindow:SMALL_RECT invoke FreeConsole;освободить существующую консоль invoke AllocConsole;создать консоль для себя invoke GetStdHandle,STD_OUTPUT_HANDLE;получить handle для вывода mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; rax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow and dword ptr [r8+SMALL_RECT.Left],0;mov [r8+SMALL_RECT.Left],0 ;mov [r8+SMALL_RECT.Top],0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX;establish the new size of a window of the console invoke SetConsoleTitle,&STR2 ;создать заголовок окна консоли invoke SetConsoleCursorPosition,hOut,Y*10000h+X;установить позицию курсора invoke SetConsoleTextAttribute,hOut,BRIGHTGREEN ;задать цветовые атрибуты выводимого текста invoke WriteConsole,hOut,&STR1,sizeof STR1,&BUFF,0 ;вывести строку invoke GetStdHandle,STD_INPUT_HANDLE ;получить HANDLE для ввода invoke ReadConsole,eax,&BUFF,buffersize,&LENS,0 ;ждать ввода строки invoke SetConsoleTextAttribute,hOut,BRIGHTCYAN ;задать цветовые атрибуты выводимого текста lea r9d,LENS mov r8d,[r9] ;длина вводимой строки invoke WriteConsole,hOut,&BUFF,,,0 invoke Sleep,3000 ;небольшая задержка invoke FreeConsole ;закрыть консоль invoke RtlExitUserProcess,NULL;завершить программу WinMain endp STR1 db 'Enter line of any symbols and press "Enter":',13,10 STR2 db 'Iczelion''s tutorial #38a',0 hOut dq ? end Здесь исходный текст программы и ехе-файл Очередные улучшенияДобавляю в папку bin файл stubby.exe следующего содержания: немного меняю содержимое bat-файла Код (Text): cls set masm64_path=\masm64\ set filename= <--- здесь будет имя asm-файла del %filename%.exe %masm64_path%bin\ml64 /Cp /c /I"%masm64_path%Include" %filename%.asm || exit %masm64_path%bin\link /SUBSYSTEM:CONSOLE /LIBPATH:"%masm64_path%Lib" ^ /entry:WinMain %filename%.obj /LARGEADDRESSAWARE:NO ^ /ALIGN:16 /SECTION:.text,W /BASE:0x400000 /STUB:%masm64_path%\bin\stubby.exe || exit del %filename%.obj Это на сотню байтов уменьшает исходный ехе-файл. Установка цвета символов и цвета фона в консольном приложенииВ отличие от GUI-приложений, где можно использовать всю цветовую палитру системы, в консольном приложении цвет задается всего одним байтом, младшие 4 разряда отвечают за цвет текста, а старшие 4 разряда ― за цвет фона. Соответственно, доступны комбинации из 24=16 цветов фона и столько же цветов для текста. константачислоцветдеся- тич- ноедвоичноеinten- sityredgreenblueBLACK00000BLUE10001GREEN20010CYAN30011RED40100PURPLE50101YELLOW60110SYSTEM70111GREY81000BRIGHTBLUE91001BRIGHTGREEN101010BRIGHTCYAN111011BRIGHTRED121100BRIGHTPURPLE131101BRIGHTYELLOW141110WHITE151111По умолчанию цвет фона в консоли черный, а цвет символов ― белый. Цвета можно изменить при помощи функции SetConsoleTextAttribute Код (C): SetConsoleTextAttribute ( HANDLE hConOut, // дескриптор потока вывода color /* формируется путем объединения цветов фона и символов */ ); константачислоЗначениеhexдвоичноеФонТекстiiFOREGROUND_BLUE100000001Цвет текста содержит синюю компонентуFOREGROUND_GREEN200000010Цвет текста содержит зеленую компонентуFOREGROUND_RED400000100Цвет текста содержит красную компонентуFOREGROUND_INTENSITY800001000Цвет текста имеет повышенную интенсивностьBACKGROUND_BLUE1000010000Цвет фона содержит синюю компонентуBACKGROUND_GREEN2000100000Цвет фона содержит зеленую компонентуBACKGROUND_RED4001000000Цвет фона содержит красную компонентуBACKGROUND_INTENSITY8010000000Цвет фона имеет повышенную интенсивностьСодержимое asm-файла Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 LEFT = 8 TOP = 4 buffersize = 100 .code WinMain proc local BUFF[buffersize]:byte local result:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD local color:qword local coord:COORD invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8+SMALL_RECT.Left],0;mov [r8+SMALL_RECT.Left],0 ;mov [r8+SMALL_RECT.Top],0 sub ax,MAXSCREENX sbb edx,edx and ax,dx add ax,MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax,16 sub eax,MAXSCREENY sbb edx,edx and eax,edx add eax,MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX;establish the new size of a window of the console invoke SetConsoleTitle,&Str1 ;прячем курсор---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke WriteConsole,hOut,&Str2,sizeof Str2,&result,0 mov coord.x,LEFT and color,0 @0: mov coord.y,TOP @@: invoke SetConsoleCursorPosition,hOut,coord ; To establish color and a background of the text of the console ; 4-7 бит - background color ; 0-3 бит - text color ; other bits aren't used invoke SetConsoleTextAttribute,hOut,color invoke wsprintf,&BUFF,&fmt,color invoke WriteConsole,hOut,&BUFF,eax,&result,0 inc coord.y inc color cmp coord.y,TOP+16 jb @b add coord.x,4 cmp coord.x,16*4+LEFT jb @0 @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp Str1 db 'Installation of color of symbols and background of the text of the console',0 Str2 db 'For exit press ESC or CTRL+C' fmt db '%.3d',0 hIn dq ? hOut dq ? end Для установки цвета текста в консоли, перед выводом текста используется функция SetConsoleTextAttribute. Здесь исходный текст программы и ехе-файл Консольное приложение. "Градиентная заливка"asm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 LEFT = 8 TOP = 4 buffersize = 100 .code WinMain proc local BUFF[buffersize]:byte local result:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD local color:dword local count:dword local coord:COORD invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8+SMALL_RECT],0 ; ConsoleWindow.Left = 0 ; ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX ;establish the new size of a window of the console invoke SetConsoleTitle,&Str1 ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke WriteConsole,hOut,&Str2,sizeof Str2,&result,0 mov count,0Fh mov coord,10000h ; X=0 Y=1 @0: mov color,0Fh @@: invoke SetConsoleCursorPosition,hOut,coord ; To establish color and a background of the text of the console ; 4-7 bits - background color ; 0-3 bits - text color ; other bits aren't used invoke SetConsoleTextAttribute,hOut,color invoke WriteConsole,hOut,&Str3,1,&result,0 inc color inc coord.x cmp coord.x,MAXSCREENX jb @b dec count mov eax,count mov color,eax inc coord.y mov coord.x,0 cmp coord.y,MAXSCREENY-1 jnz @b ;------------------------------------------------------------------ @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hIn dq ? hOut dq ? Str1 db 'Installation of color of symbols and background of the text of the console application',0 Str2 db 'For exit press ESC or CTRL+C or CTRL+Break' Str3 db 'o' end Здесь исходный текст программы и ехе-файл Простое консольное приложениеasm-файл Код (ASM): ; CONSOLE # include win64a.inc includelib msvcrt.lib MAXSCREENX = 80 MAXSCREENY = 25 buffersize = 200 .code WinMain proc local coord:COORD local BUFF[buffersize]:byte local ConsoleWindow:SMALL_RECT local result:qword local dwLength:dword local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD invoke FreeConsole ; release the existing console invoke AllocConsole ; create the console invoke GetStdHandle,STD_INPUT_HANDLE ; receive handle for a input mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE ; receive handle for a output mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8+SMALL_RECT],0 ; ConsoleWindow.Left = 0 ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE ; bAbsolute ;------------------------------------------------------------------ invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX ; establish the new size of console window invoke SetConsoleTitle,&NameConsole ; definition of a title bar ;------------------------------------------------------------------------ invoke WriteConsole,hOut,&Str1,sizeof Str1,&BUFF,0 ; display a line of symbols ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ ;demonstration of positioning of the cursor mov coord,10000h ;y=1 x=0 @@: movzx r9d,coord.y movzx r8d,coord.x invoke sprintf,&BUFF,&fmt1 mov dwLength,eax invoke SetConsoleCursorPosition,hOut,coord ; establish a cursor position invoke WriteConsole,hOut,&BUFF,dwLength,&result,0 ; display a line of symbols add coord,10005h ; x = x + 5 y = y + 1 cmp coord.y,10 jb @b ; change of color of symbols invoke SetConsoleCursorPosition,hOut,0C0000h ; establish a cursor position invoke SetConsoleTextAttribute,hOut,FOREGROUND_BLUE or BACKGROUND_GREEN ; set color attributes of the output text invoke WriteConsole,hOut,&Str3,sizeof Str3,&result,0 ; display a line of symbols invoke SetConsoleTextAttribute,hOut,FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED ; set color attributes of the output text invoke SetConsoleCursorPosition,hOut,0E0000h ; establish a cursor position invoke WriteConsole,hOut,&Str4,sizeof Str4,&result,0 ; display a line of symbols ; reading the entered line invoke ReadConsole,hIn,&BUFF,80,&result,0 ; wait for input of a line of symbols mov rax,result lea esi,BUFF mov byte ptr [rax+rsi-2],0 ; 2 symbols CR and LF ; remove ASCII code of the entered symbols xor eax,eax mov dwLength,eax @@: lodsb or eax,eax jz @f invoke printf,&fmt2,eax add dwLength,eax jmp @b @@: mov r8d,dwLength neg r8 ; length of the removed line invoke WriteConsole,hOut,&BUFF,,&result,0 ; it is possible to use the functions printf, gets, etc. invoke printf,&Str5 invoke gets,&BUFF invoke printf,&fmt3,&BUFF invoke printf,&Str2 @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b invoke FreeConsole;закрываем консоль invoke RtlExitUserProcess,NULL WinMain endp hOut dq ? hIn dq ? NameConsole db 'Simple example of console',0 Str1 db 'This is sample output string',13,10 Str2 db 'For exit from program press ESC or CTRL+C or CTRL+Break',0 Str3 db 'This is Blue text on Green background' Str4 db 'Enter a line of symbols and you can to see ASCII-code of symbols: ',13,10 Str5 db 0Dh,0Ah,'This is a test. Enter another string: ',13,10,0 fmt1 db "Text position X=%d, Y=%d",0 fmt2 db "%X ",0 fmt3 db "%s",13,10,0 end Программа демонстрирует изменение позиции курсора с помощью функции SetConsoleCursorPosition, изменение цветов фона и символов (SetConsoleTextAttribute), чтение введенной строки через ReadConsole, использование printf и gets, вывод ASCII-кода введенных символов строки, завершение программы по нажатию на клавишу "Esc". Здесь исходный текст программы и ехе-файл
Прогресс-бар в консольной программеasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 colors1 = 159 colors2 = 249 .code WinMain proc local result:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local CSBI:CONSOLE_SCREEN_BUFFER_INFO local MOUSE_KEY:INPUT_RECORD invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ; ConsoleWindow.Left = ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX ;establish the new size of a window of the console invoke SetConsoleTitle,&ConsoleName ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci ; lpConsoleCursorInfo lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke WriteConsole,hOut,&Str2,sizeof Str2,&result,0 ;Get Console Info ;with Get CursorPosition Start invoke GetConsoleScreenBufferInfo,hOut,&CSBI ;Loop of bar 0 - 100 ;Write procent char (only one time) mov procentbar[27], '%' ;Write ascii procent @0: mov dl,10 mov eax,procent div dl add ax,'00' mov word ptr procentbar[24], ax cmp al,3Ah jnz @f mov word ptr procentbar[23],'01' @@: ;Set CursorPosition Start mov eax,CSBI.dwCursorPosition invoke SetConsoleCursorPosition,hOut,eax ;Set Color1 invoke SetConsoleTextAttribute,hOut,colors1 ;Write proportial part mov r8d,procent shr r8d,1 invoke WriteFile,hOut,&procentbar,,&n,0 ;Set Color2 invoke SetConsoleTextAttribute,hOut,colors2 ;Write proportial part end mov edx,procent shr edx,1 mov r8d,50 sub r8d,edx add edx,offset procentbar invoke WriteFile,hOut,,,&n,0 ;Wait for slow speed mov ecx,procent shr ecx,2 add ecx,80 invoke Sleep ;Add procent inc procent cmp procent,101 jb @0 ;Set Text Color on default movzx edx,CSBI.wAttributes invoke SetConsoleTextAttribute,hOut @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hIn dq ? hOut dq ? ConsoleName db 'Progress bar in console',0 Str2 db 'For exit press ESC or CTRL+C or CTRL+Break',13,10,10,32 procentbar db 50 dup (32),0,0 procent dd 0 n dd 0 end Здесь исходный текст программы и ехе-файл Двоичные часы в консольной программеasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 50 MAXSCREENY = 15 MAX_STACK = 1000h BLACK = 0 BLUE = 1 GREEN = 2 CYAN = 3 RED = 4 PURPLE = 5 YELLOW = 6 SYSTEM = 7 GREY = 8 BRIGHTBLUE = 9 BRIGHTGREEN = 10 BRIGHTCYAN = 11 BRIGHTRED = 12 BRIGHTPURPLE = 13 BRIGHTYELLOW = 14 WHITE = 15 LEFT = 4 TOP = 4 W = 3 .code WinMain proc local szReadWrite:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD local stm:SYSTEMTIME invoke FreeConsole invoke AllocConsole invoke GetProcessHeap mov hHeap,rax invoke RtlAllocateHeap,rax,HEAP_ZERO_MEMORY,4*MAX_STACK mov lpStack,rax invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,rax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ; ConsoleWindow.Left = 0 ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX;устанавливаем новый размер окна консоли invoke SetConsoleTitle,&Str1 ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke WriteConsole,hOut,&Str2,sizeof Str2,&szReadWrite,0 ;вывести Str2 на консоль ;-------------------------------------------------------- ; Run until Esc is pressed main_loop: invoke Sleep,10 ; dwMilliseconds invoke GetLocalTime,&stm mov Y,TOP mov X,LEFT+W+1 k = 16 rept 5 test stm.wHour,k jz @f or color,10000000y ;установить в color 7-ой бит в 1 @@: invoke set k = k/2 endm ;----------------------------------------- mov X,LEFT add Y,W k = 32 rept 6 test stm.wMinute,k jz @f or color,10000000y ;установить в color 7-ой бит в 1 @@: invoke set k = k/2 endm ;----------------------------------- add Y,W mov X,LEFT k = 32 rept 6 test stm.wSecond,k jz @f or color,10000000y ;установить в color 7-ой бит в 1 @@: invoke set k = k/2 endm ;-------------------------------------- invoke GetAsyncKeyState,VK_ESCAPE ; vKey ; Determine whether a key is up or down test eax, 8000h jz main_loop EXIT: invoke CloseHandle,hOut ; hObject invoke CloseHandle,hIn ; hObject invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp set proc local Csbi:CONSOLE_SCREEN_BUFFER_INFO local lpRegion:SMALL_RECT invoke GetConsoleScreenBufferInfo,hOut,&Csbi mov edx, color mov ecx, edx shl edx, 4 or edx, ecx ; wAttributes invoke SetConsoleTextAttribute,hOut ;draw------------------------------------------------------- invoke GetConsoleScreenBufferInfo,hOut,&Csbi ;save------------------------------------------------------ mov edx,X mov lpRegion.Left,dx add edx,(W-1) mov lpRegion.Right,dx mov edx,Y mov lpRegion.Top,dx add edx,(W-2) mov lpRegion.Bottom,dx invoke RtlAllocateHeap,hHeap,HEAP_ZERO_MEMORY,4*W*(W-1)+260 mov edi,eax ; edi=lpBuffer lea edx,lpRegion mov [rsp+20h],rdx ; lpReadRegion invoke ReadConsoleOutput,hOut,rax,(W-1)*10000h+W,0 ;end save-------------------------------------------------- mov ecx,W*(W-1) @@: mov ax,Csbi.wAttributes shl eax,16 stosd loop @b sub edi,4*W*(W-1) ;load------------------------------------------------------ lea edx,lpRegion mov [rsp+20h],rdx ; lpWriteRegion invoke WriteConsoleOutput,hOut,edi,(W-1)*10000h+W,0 ;освободить память invoke HeapFree,hHeap,0,edi ;end load-------------------------------------------------- ;end draw--------------------------------------------------- and color,01111111y ;сбросить в color 7-ой бит в 0 add X,W+1 leave retn set endp ;------------------------------------------------------- Str1 db 'Binary clock',0 Str2 db 'For exit press ESC or CTRL+C or CTRL+Break',13,10,10,10,\ 5 dup(20h),'32 16 8 4 2 1',13,10,\ 30 dup(20h),'Hours',13,10,10,10,30 dup(20h),'Minutes',13,10,10,10,30 \ dup(20h),'Seconds' hOut dq ? hIn dq ? X dd ? Y dd ? color dd RED dwStackTop dd -1 lpStack dq ? hHeap dq ? end Здесь исходный текст программы и ехе-файл Перечисление и установка консольных шрифтовasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 MAX_STACK = 1000h TOP_MENU = 5 RIGHT_MENU = 34 COLS_MENU = 17 ;---------------------------------------------- CONSOLE_FONT_INFO struct index dd ? dwFontSize COORD <> CONSOLE_FONT_INFO ends ;---------------------------------------------- buffersize = 40 .code WinMain proc local n:dword local count:dword local new_op:dword local prev_op:dword local result:qword local buffer[buffersize]:byte local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local CSBI:CONSOLE_SCREEN_BUFFER_INFO local MOUSE_KEY:INPUT_RECORD local hMem:qword local coord:COORD mov prev_op,1 mov new_op,1 mov coord,TOP_MENU*10000h+RIGHT_MENU invoke GetProcessHeap mov hHeap,rax invoke RtlAllocateHeap,rax,HEAP_ZERO_MEMORY,4*MAX_STACK mov lpStack,rax invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0; ConsoleWindow.Left = 0 ; ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX ;establish the new size of a window of the console invoke SetConsoleTitle,&ConsoleName ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke WriteConsole,hOut,&Str2,sizeof Str2,&result,0 ;------------------------------------------------------ invoke GetNumberOfConsoleFonts mov count,eax shl eax,3 invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,eax ; eax = count * sizeof CONSOLE_FONT_INFO mov hMem,rax invoke GetConsoleFontInfo,hOut,TRUE,count,rax ;Draw menu----------------------------------------------------------- invoke SetConsoleTextAttribute,hOut,BACKGROUND_INTENSITY mov r9d,count add r9d,4 ;rows invoke draw,RIGHT_MENU-2,TOP_MENU-2,COLS_MENU+4 invoke SetConsoleTextAttribute,hOut,BACKGROUND_BLUE or BACKGROUND_GREEN or \ BACKGROUND_RED mov r9d,count add r9d,2 ;rows invoke draw,RIGHT_MENU-1,TOP_MENU-1,COLS_MENU+2 ;fill memu---------------------------------------------------------- mov edi,count mov rsi,hMem @@: mov ax,300 cwd div [rsi+CONSOLE_FONT_INFO.dwFontSize.y] mov r9d,eax ;font width mov ax,640 cwd div [rsi+CONSOLE_FONT_INFO.dwFontSize.x] invoke sprintf,&buffer,&fmt,eax mov n,eax invoke SetConsoleCursorPosition,hOut,coord;устанавливаем позицию курсора invoke WriteConsole,hOut,&buffer,n,&result,0 ;выводим строку символов inc coord.y add esi,sizeof CONSOLE_FONT_INFO dec edi jnz @b invoke GlobalFree,hMem ; Select first label invoke invert,TOP_MENU ; Keyboard read loop------------------------------------------------ @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.bKeyDown],0 jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_UP je vkUP cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_DOWN je vkDOWN cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_RETURN je vkRETURN cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b exit0: invoke HeapFree,hHeap,0,lpStack invoke CloseHandle,hOut invoke CloseHandle,hIn invoke FreeConsole invoke RtlExitUserProcess,NULL ;----------------------------------------------------- vkUP: dec new_op jnz proceed mov eax,count mov new_op,eax jmp proceed vkDOWN: mov eax,count inc new_op cmp new_op,eax jbe proceed mov new_op,1 proceed: ; Select new label mov ecx,new_op add ecx,TOP_MENU-1 invoke invert add prev_op,TOP_MENU-1 invoke invert,prev_op mov eax,new_op mov prev_op,eax jmp @b vkRETURN:mov edx,new_op dec edx invoke SetConsoleFont,hOut jmp @b WinMain endp ;-------------------------------------------------------- draw proc x:qword, y:qword, cols:qword, rows:qword local Csbi:CONSOLE_SCREEN_BUFFER_INFO local lpBuffer:qword local dwBufferSize:COORD local lpRegion:SMALL_RECT mov x,rcx mov y,rdx mov cols,r8 mov rows,r9 invoke GetConsoleScreenBufferInfo,hOut,&Csbi ;--------------------------------------------------------- mov eax,dword ptr cols mov dwBufferSize.x,ax mov ecx,dword ptr rows mov dwBufferSize.y,cx dec eax dec ecx mov edx,dword ptr x mov lpRegion.Left,dx add eax,dword ptr x ;eax=cols-1+x mov lpRegion.Right,ax mov edx,dword ptr y mov lpRegion.Top,dx add ecx,edx ;ecx=rows-1+y mov lpRegion.Bottom,cx mov eax,dword ptr cols mul dword ptr rows lea r8d,[rax*4+260] ;eax=4*cols*rows+260 dwBytes invoke RtlAllocateHeap,hHeap,HEAP_ZERO_MEMORY mov lpBuffer,rax mov edi,eax lea edx,lpRegion mov [rsp+20h],rdx ; lpReadRegion invoke ReadConsoleOutput,hOut,eax,dwBufferSize,0 ;--------------------------------------------------------- mov eax,dword ptr cols mul dword ptr rows mov ecx, eax mov ax,Csbi.wAttributes shl eax,16 rep stosd ;----------------------------------------------------------- lea edx, lpRegion mov [rsp+20h],rdx ; lpWriteRegion invoke WriteConsoleOutput,hOut,lpBuffer,dwBufferSize,0 invoke HeapFree,hHeap,0,lpBuffer leave retn draw endp ;------------------------------------------------------- invert proc y:qword local lpRegion:SMALL_RECT mov lpRegion.Left,RIGHT_MENU mov lpRegion.Right,COLS_MENU+RIGHT_MENU-1 mov lpRegion.Top,cx mov lpRegion.Bottom,cx invoke RtlAllocateHeap,hHeap,HEAP_ZERO_MEMORY,COLS_MENU*4+260 mov rdi,rax ; edi=lpBuffer lea edx,lpRegion mov [rsp+20h],rdx ; lpReadRegion invoke ReadConsoleOutput,hOut,rax,10000h+COLS_MENU,0 ;--------------------------------------------------------------- mov rsi,rdi mov ecx,COLS_MENU ; cols @@: lodsd ;eax=xxABxxxx ror eax,16 ;eax=xxxxxxAB ror al,4 ;eax=xxxxxxBA rol eax,16 ;eax=xxBAxxxx stosd loop @b sub edi,COLS_MENU*4 lea edx,lpRegion mov [rsp+20h],rdx ; lpWriteRegion invoke WriteConsoleOutput,hOut,edi,10000h+COLS_MENU,0 invoke HeapFree,hHeap,0,edi leave retn invert endp ;----------------------------------------------------------- ConsoleName db 'Enum and set console fonts',0 Str2 db 'For move into menu press Up or Down Arrow key',13,10,\ 'For set selected font press Enter',13,10,\ 'For exit press ESC or CTRL+C or CTRL+Break',13,10 hOut dq ? hIn dq ? hHeap dq ? lpStack dq ? fmt db 'font size %d x %d',0 end Здесь исходный текст программы и ехе-файл Обработка сообщений мыши в консольном приложенииДля получения сообщений от мыши используют ReadMouseInput Код (C): ReadMouseInput ( HANDLE hConIn, // дескриптор входного потока PINPUT_RECORD pBuf, /* указатель на структуру (массив структур), которая содержит информацию о запрашиваемом событии */ DWORD dwNum, // количество получаемых информационных записей о событиях LPDWORD lpdwNumRead /* указатель на двойное слово в которое записывается количество реально возвращаемых записей */ ); При успешном завершении ReadMouseInput возвращает ненулевое значение, иначе возвращается ноль. Каждый раз при нажатии клавиши или при перемещении мыши формируется запись, которая сохраняется в структуре Код (ASM): INPUT_RECORD STRUCT EventType WORD ? two_byte_alignment WORD ? UNION KeyEvent KEY_EVENT_RECORD <> MouseEvent MOUSE_EVENT_RECORD <> WindowBufferSizeEvent WINDOW_BUFFER_SIZE_RECORD <> MenuEvent MENU_EVENT_RECORD <> FocusEvent FOCUS_EVENT_RECORD <> ENDS INPUT_RECORD ENDS поле EventType определяет тип события и может принимать одно из значений hexbinтип событияKEY_EVENT10000.0001нажатие клавишиMOUSE_EVENT20000.0010событие мышиWINDOW_BUFFER_SIZE_EVENT40000.0100изменение размера окнаMENU_EVENT80000.1000события менюFOCUS_EVENT100001.0000событие фокусаПри приходе сообщения от мыши поле EventType содержит значение MOUSE_EVENT. Расшифровка сообщения заполнит структуру Код (ASM): MOUSE_EVENT_RECORD STRUCT dwMousePosition COORD <>; значение координат в момент прихода сообщения dwButtonState DWORD ?;состояние кнопок при генерации события dwControlKeyState DWORD ?;состояние управляющих клавиш dwEventFlags DWORD ?; при перемещении MOUSE_MOVED=1 либо при двойном щелчке DOUBLE_CLICK=2 MOUSE_EVENT_RECORD ENDS asm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 buffersize = 100 .code WinMain proc local BUFF[buffersize]:byte local result:qword local MOUSE_KEY:INPUT_RECORD local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; rax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ; ConsoleWindow.Left = 0 ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX ;establish the new size of console window invoke SetConsoleTitle,&NameConsole ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke WriteConsole,hOut,&Str1,sizeof Str1,&result,0 invoke SetConsoleCursorPosition,hOut,0B000Bh ;Y=11 X=0 invoke WriteConsole,hOut,&Str2,sizeof Str2,&result,0 @@: invoke SetConsoleCursorPosition,hOut,0A0009h ;Y=10 X=9 invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea edx,MOUSE_KEY cmp [rdx+INPUT_RECORD.EventType],MOUSE_EVENT jne LOO1 xor eax,eax mov ax,[rdx+INPUT_RECORD.MouseEvent.dwMousePosition.y] mov [rsp+20h],rax mov ax,[rdx+INPUT_RECORD.MouseEvent.dwMousePosition.x] mov r8d,[rdx+INPUT_RECORD.MouseEvent.dwButtonState] cmp r8d,4 sbb ecx,ecx and r8d,ecx invoke wsprintf,&BUFF,&fmt,,rax invoke WriteConsole,hOut,&BUFF,eax,&result,0 jmp @b LOO1: lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hIn dq ? hOut dq ? NameConsole db 'Processing of mouse messages',0 fmt db 'Button state: %u, X: %u, Y: %u',0 Str1 db 'For exit press ESC or CTRL+C' Str2 db 'No clicks = 0',0Dh,0Ah,\ ' Left click = 1',0Dh,0Ah,\ ' Right click = 2',0Dh,0Ah,\ 'Left and Right click = 3',0 end Здесь исходный текст программы и ехе-файл Просмотр главной загрузочной записиФункция CreateFile может открывать не только файлы, но и дисковые устройства. Для открытия первого диска компьютера используется имя "\\.\PhysicalDrive0", для открытия логического раздела C: имя "\\.\C:". После открытия устройства можно использовать функции ReadFile и WriteFile, то есть читать и писать непосредственно в кластеры и сектора диска. Функция DeviceIOControl позволяет получить статическую информацию о диске либо выполнить форматирование диска. Программа ниже позволяет прочитать главную загрузочную запись диска (Master Boot Record ― MBR). При открытии устройства "\\.\PhysicalDrive0" главная загрузочная запись диска находится в начале гипотетического файла. После создания exe-файла, добавьте в его свойства "Запуск от имени администратора" asm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 49 MAXSCREENY = 36 .code WinMain proc local hFile:qword local szReadWrite:qword local FileSize:qword local hMapping:qword local pMapping:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD local i:dword local buffer1[512+3]:byte local buffer2[3*512]:byte local buffer3:qword invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,rax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ; ConsoleWindow.Left = 0 ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX ;establish the new size of a window of the console invoke SetConsoleTitle,&Str0 ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],ebx;FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ ;open physical drive invoke CreateFile,&filename,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0 ;open file inc eax ;eax == INVALID_HANDLE_VALUE ? jz EXIT dec eax mov hFile,rax ;alignment on limit of the double word lea eax,buffer1 add eax,3 and eax,-4 mov buffer3,rax ;read from Partition Table invoke ReadFile,hFile,rax,512,&szReadWrite,0 ;------------------------------------------- lea edi,buffer2 mov esi,offset Str2 mov ecx,sizeof Str2 rep movsb mov rsi,buffer3 mov FileSize,sizeof Str2 mov i,ebx @@: lodsq bswap rax mov r9d,eax mov [rsp+20h],r9 shr rax,32 mov r9d,eax lodsq bswap rax mov edx,eax mov [rsp+30h],rdx shr rax,32 mov [rsp+28h],rax invoke wsprintf,rdi,&fmt,i add edi,eax add FileSize,rax inc i cmp i,512/16 jb @b mov esi,offset Str1 mov ecx,sizeof Str1 rep movsb add FileSize,sizeof Str1 ;to bring buffer contents to the console invoke WriteConsole,hOut,&buffer2,FileSize,&szReadWrite,0 ;close handle and file---------------------- invoke CloseHandle,hFile ; close file invoke CloseHandle,hOut ; close file ;-------------------------------------------------------- @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&szReadWrite lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b ;--------------------------------------------------------- EXIT: invoke CloseHandle,hIn invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp fmt db ' %.04X0 ',0BAh,' %.08X %.08X ',0B3h,' %.08X %.08X ',0BAh,0Dh,0Ah,0 Str0 db 'Master Boot Record',0 Str1 db 7 dup(20h),0C8h,19 dup (0CDh),0CFh,19 dup (0CDh),0BCh,13,10,\ 'For exit press ESC or CTRL+C or CTRL+Break' filename db "\\.\PhysicalDrive0",0 ;имя устройства (первый диск) hIn dq ? hOut dq ? Str2 db 10 dup(20h),'0 1 2 3 4 5 6 7 8 9 A B C D E F',0Dh,0Ah,\ 7 dup(20h),0C9h,19 dup (0CDh),0D1h,19 dup (0CDh),0BBh,0Dh,0Ah end Здесь исходный текст программы и ехе-файл Анимация в консольном приложенииСчитается, что консольное приложение работает ТОЛЬКО В ТЕКСТОВОМ РЕЖИМЕ. На самом деле в консольном приложении наряду с текстовым вводом-выводом можно использовать и графический ввод-вывод. В консольном приложении hWnd можно получить следующими способами: Код (ASM): invoke GetConsoleWindow mov hWnd,rax Код (ASM): .data ClassConsole db 'ConsoleWindowClass',0 . . . invoke FindWindow,&ClassConsole,0 mov hWnd,rax Зная hWnd получаем контекст устройства Код (ASM): invoke GetDC,hWnd mov hDC,rax
asm-файл Код (ASM): ; CONSOLE # include win64a.inc includelib winmm.lib include winmm.inc const1 = 68 MAXSCREENX = 80 MAXSCREENY = 25 .code WinMain proc local result:qword local hIn:qword local IDtimer:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD invoke FreeConsole ;release the existing console invoke AllocConsole ;create the console invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax ; receive handle for a input invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax ; receive handle for a output invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ;ConsoleWindow.Left = 0 ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX ; establish the new size of console window invoke FindWindow,&ClassConsole,0 mov hWnd,rax invoke GetDC,rax mov hDC,rax invoke CreateSolidBrush,0 mov BlackBrush,rax invoke SelectObject,hDC,rax ;keep a black brush in a context ;load the picture invoke LoadImage,400000h,&bmp,0,0,0,LR_LOADFROMFILE mov hBit,rax invoke SetConsoleTitle,&NameConsole ;definition of a title bar invoke timeSetEvent,100,0,&TIME,0,TIME_PERIODIC mov IDTimer,rax @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea edx,MOUSE_KEY cmp [rdx+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rdx+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rdx+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b invoke DeleteObject,BlackBrush ;delete a black brush invoke DeleteObject,hBit ;delete drawing invoke ReleaseDC,hWnd,hDC ;free hDC invoke timeKillEvent,IDTimer invoke FreeConsole ;close console invoke RtlExitUserProcess,NULL WinMain endp TIME proc local memDC:qword local result:qword invoke SetConsoleCursorPosition,hOut,0;Y=0 X=0 invoke WriteConsole,hOut,&STR1,sizeof STR1,&result,0 ;output of a line of symbols to the screen @@: invoke CreateCompatibleDC,hDC ;create compatible DC mov memDC,rax invoke SelectObject,rax,hBit mov eax,Y add eax,const1+1 mov [rsp+20h],rax mov r9d,X add r9d,const1+1 mov r8d,Y dec r8d mov edx,X dec edx invoke Ellipse,hDC ;remove a black circle to erase the previous image cmp X,640-const1 ;check that the planet is in console limits jna @f ;otherwise change the direction of the movement neg deltaX @@: cmp Y,300-const1 jna @f neg deltaY @@: mov eax,deltaX add X,eax ;change planet coordinates mov eax,deltaY add Y,eax mov qword ptr [rsp+40h],SRCCOPY ;dwRaster mov [rsp+38h],rbx ;SourceY=0 mov [rsp+30h],rbx ;SourceX=0 mov rax,memDC ;hSource mov [rsp+28h],rax mov r9d,const1 ;Width mov [rsp+20h],r9 ;const1=height mov edx,X mov r8d,Y invoke BitBlt,hDC ;display the image invoke DeleteDC,memDC ;release the DC memories leave retn TIME endp .data bmp db 'Earth.bmp',0 ClassConsole db 'ConsoleWindowClass',0 STR1 db 'For exit from program press ESC or CTRL+C or CTRL+Break' NameConsole db 'Console application animation',0 hOut dq ? hWnd dq ? hDC dq ? BlackBrush dq ? hBit dq ? deltaX dd 10 deltaY dd 2 X dd ? Y dd ? IDTimer dq ? end Здесь исходный текст программы и ехе-файл Вывод на консоль содержимого текстового файла. Первый вариантasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 .code WinMain proc local hFile:qword local result:qword local FileSize:qword local hMem:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ; ConsoleWindow.Left = 0 ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleTitle,&Str1 ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke CreateFile,&filename,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0 ;to open the file inc eax;cmp eax,-1 jz EXIT dec eax mov hFile,rax invoke GetFileSize,rax,0 mov FileSize,rax invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,rax mov hMem,rax invoke ReadFile,hFile,rax,FileSize,&result,0 ;to read in the buffer invoke WriteConsole,hOut,hMem,FileSize,&result,0 ;to bring buffer contents to the console invoke CloseHandle,hFile ;to close the file ;-------------------------------------------------------- invoke WriteConsole,hOut,&Str2,sizeof Str2,&result,0 ;to bring Str2 to the console ;-------------------------------------------------------- @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b EXIT: invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hIn dq ? hOut dq ? Str1 db 'Output to the console of text file contents. First variant.',0 Str2 db 13,10,'For exit press ESC or CTRL+C or CTRL+Break' filename db '11.asm' end Здесь исходный текст программы и ехе-файл Вывод на консоль содержимого текстового файла. Второй вариантasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 .code WinMain proc local hFile:qword local result:qword local FileSize:qword local hMem:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD invoke FreeConsole invoke AllocConsole invoke CreateFile,&filenameIn,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0 mov hIn,rax ; hConsoleInput invoke CreateFile,&filenameOut,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0 mov hOut,rax invoke GetLargestConsoleWindowSize,rax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ;lpConsoleWindow and dword ptr [r8],0 ; lpConsoleWindow.Left = 0 lpConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleTitle,&ConsoleTitle ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],ebx;FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke CreateFile,&filename,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0 ;to open the file inc eax;cmp eax,-1 jz EXIT dec eax mov hFile,rax invoke GetFileSize,rax,0 mov FileSize,rax invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,rax mov hMem,rax invoke ReadFile,hFile,rax,FileSize,&result,0 ;to read in the buffer invoke WriteConsole,hOut,hMem,FileSize,&result,0 ;to bring buffer contents to the console invoke CloseHandle,hFile ;to close the file ;-------------------------------------------------------- invoke WriteConsole,hOut,&Str2,sizeof Str2,&result,0 ;to bring Str2 to the console ;-------------------------------------------------------- @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&result lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b [B] [/B]cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b EXIT: invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hIn dq ? hOut dq ? ConsoleTitle db 'Output to the console of text file contents. Second variant.',0 Str2 db 13,10,'For exit press ESC or CTRL+C or CTRL+Break' filename db '12.asm',0 filenameOut db 'CONOUT$',0 filenameIn db 'CONIN$',0 end Здесь исходный текст программы и ехе-файл Управление памятью, файловый ввод/вывод через GlobalAlloc/Lock/Unlock и GlobalFreeasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 .code WinMain proc local hFile:qword local szReadWrite:qword local FileSize:qword local hMem:qword local pMem:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ; lpConsoleWindow.Left = 0 lpConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleTitle,&Str1 ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke CreateFile,&filename,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0 ;to open the file inc eax;cmp eax,-1 jz EXIT dec eax mov hFile,rax invoke GetFileSize,rax,0 mov FileSize,rax invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,rax mov hMem,rax invoke GlobalLock,rax mov pMem,rax invoke ReadFile,hFile,rax,FileSize,&szReadWrite,0 ;to read in the buffer invoke WriteConsole,hOut,pMem,FileSize,&szReadWrite,0 ;to bring buffer contents to the console invoke CloseHandle,hFile ;to close the file invoke GlobalUnlock,pMem invoke GlobalFree,hMem ;-------------------------------------------------------- invoke WriteConsole,hOut,&Str2,sizeof Str2,&szReadWrite,0 ;to bring Str2 to the console ;-------------------------------------------------------- @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&szReadWrite lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b EXIT: invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hIn dq ? hOut dq ? Str1 db 'Memory Management, File I/O, GlobalAlloc/Lock/Unlock and GlobalFree',0 Str2 db 13,10,'For exit press ESC or CTRL+C or CTRL+Break' filename db '14.asm',0 end Здесь исходный текст программы и ехе-файл Управление памятью, файловый ввод/вывод через GetProcessHeap, HeapAlloc and HeapFreeasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 MEM_SIZE = 65535 .code WinMain proc local hFile:qword local szReadWrite:qword local FileSize:qword local hHeap:qword local pMem:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ; lpConsoleWindow.Left = 0 lpConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleTitle,&Str1 ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],ebx;FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke CreateFile,&filename,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0 ;to open the file inc eax;cmp eax,-1 jz EXIT dec eax mov hFile,rax invoke GetFileSize,rax,0 mov FileSize,rax invoke GetProcessHeap mov hHeap,rax invoke RtlAllocateHeap,rax,HEAP_ZERO_MEMORY,MEM_SIZE mov pMem,rax invoke ReadFile,hFile,rax,FileSize,&szReadWrite,0 ;to read in the buffer invoke WriteConsole,hOut,pMem,FileSize,&szReadWrite,0 ;to bring buffer contents to the console invoke CloseHandle,hFile ;to close the file invoke HeapFree,hHeap,0,pMem ;-------------------------------------------------------- invoke WriteConsole,hOut,&Str2,sizeof Str2,&szReadWrite,0 ;to bring Str2 to the console ;-------------------------------------------------------- @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&szReadWrite lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b EXIT: invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hIn dq ? hOut dq ? Str1 db 'Memory Management, File I/O, GetProcessHeap, HeapAlloc and HeapFree',0 Str2 db 13,10,'For exit press ESC or CTRL+C or CTRL+Break' filename db '15.asm',0 end Здесь исходный текст программы и ехе-файл Memory Mapped Fileasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 MEM_SIZE = 65535 .code WinMain proc local hFile:qword local szReadWrite:qword local FileSize:qword local hMapping:qword local pMapping:qword local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local MOUSE_KEY:INPUT_RECORD invoke FreeConsole invoke AllocConsole invoke GetStdHandle,STD_INPUT_HANDLE mov hIn,rax invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow ; lpConsoleWindow and dword ptr [r8],0 ; lpConsoleWindow.Left = 0 lpConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleTitle,&Str1 ;hide cursor---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;------------------------------------------------------ invoke CreateFile,&filename,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0 ;to open the file inc eax;cmp eax,-1 jz EXIT dec eax mov hFile,rax invoke GetFileSize,rax,0 mov FileSize,rax ;creation in memory of object "a file projection" invoke CreateFileMapping,hFile,0,PAGE_READWRITE,0,0,0 mov hMapping,rax ;display of a projection of the file to address space of process invoke MapViewOfFile,rax,FILE_MAP_WRITE,0,0,0 mov pMapping,rax invoke WriteConsole,hOut,rax,FileSize,&szReadWrite,0 ;to bring buffer contents to the console invoke UnmapViewOfFile,pMapping invoke CloseHandle,pMapping ;to close the file invoke CloseHandle,hMapping ;-------------------------------------------------------- invoke WriteConsole,hOut,&Str2,sizeof Str2,&szReadWrite,0 ;to bring Str2 to the console ;-------------------------------------------------------- @@: invoke ReadConsoleInput,hIn,&MOUSE_KEY,1,&szReadWrite lea eax,MOUSE_KEY cmp [rax+INPUT_RECORD.EventType],MOUSE_EVENT je @b cmp [rax+INPUT_RECORD.EventType],KEY_EVENT jne @b cmp [rax+INPUT_RECORD.KeyEvent.wVirtualKeyCode],VK_ESCAPE jne @b EXIT: invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hIn dq ? hOut dq ? Str1 db 'Memory Mapped File',0 Str2 db 13,10,'For exit press ESC or CTRL+C or CTRL+Break' filename db '16.asm',0 end Здесь исходный текст программы и ехе-файл Вывод графики в консольное приложениеasm-файл Код (ASM): ; CONSOLE # include win64a.inc ;---------------------------------------------- .code WinMain proc local ConsoleWindow:SMALL_RECT local cci:CONSOLE_CURSOR_INFO local hWnd:qword local hDC:qword local hbitmap:qword local memDC:qword local bi:BITMAP local ScreenX:dword local ScreenY:dword invoke FreeConsole ; освободим существующую консоль invoke AllocConsole ; образуем свою консоль invoke SetConsoleTitle,&NameConsole; определение заголовка окна invoke GetStdHandle,STD_OUTPUT_HANDLE ; получаем handle для вывода mov hOut,rax ; загружаем рисунок в Heap invoke LoadImage,400000h,&bmp_path,0,0,0,LR_LOADFROMFILE mov hbitmap,rax invoke GetObject,rax,sizeof BITMAP,&bi movzx eax,bi.mBitsPixel shr eax,3 ; eax=bmBitsPixel/8 mul bi.bmWidth mul bi.bmHeight mov edi,eax ;eax=bmpBitsPixel*bmpWidth*bmBitsPixel/8 invoke GetProcessHeap invoke RtlAllocateHeap,rax,HEAP_NO_SERIALIZE,edi mov eax,bi.bmWidth shr eax,3 mov ScreenX,eax ; eax=bmWidth/8 mov edx,357913941 ; edx=(2^32)/12 mov eax,bi.bmHeight mul edx mov ScreenY,edx ; edx=bmHeight/12 invoke GetLargestConsoleWindowSize,hOut ;; eax return in 31-16 bits: dwCoord.y ;; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow mov dword ptr [r8],0 sub eax, ScreenX sbb edx, edx and ax, dx dec eax add eax, ScreenX mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax,ScreenY sbb edx, edx and eax, edx dec eax add eax, ScreenY mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE mov edx,ScreenY shl edx,16 ; Coord.y=ScreenY add edx,ScreenX ; Coord.x=ScreenX invoke SetConsoleScreenBufferSize,hOut;устанавливаем новый ;размер окна консоли, который зависит от размера рисунка ;прячем курсор---------------------------------------- invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],ebx ; FALSE invoke SetConsoleCursorInfo,hOut ;----------------------------------------------------- invoke CloseHandle,hOut ;------------------------------------------------------ invoke GetConsoleWindow mov hWnd,rax invoke GetDC,rax ;получить DC mov hDC,rax invoke CreateCompatibleDC,rax ;создать совместимый DC mov memDC,rax invoke SelectObject,rax,hbitmap ;-------------------------------------------------------- @@: invoke Sleep,150 mov eax,bi.bmHeight ;Rect.bottom mov [rsp+20h],rax mov r9d,bi.bmWidth ;Rect.right invoke BitBlt,hDC,0,0,,,memDC,0,0,SRCCOPY invoke GetAsyncKeyState,VK_ESCAPE ; vKey ; Determine whether a key is up or down test eax, 8000h jz @b ;--------------------------------------------------------- invoke DeleteObject,hbitmap invoke ReleaseDC,hDC,hWnd ;освободить DC invoke DeleteDC,memDC ;удаляем виртуальное окно invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp ;--------------------------------------------------------- bmp_path db '47.bmp',0 hOut dq ? NameConsole db "For exit press 'Esc'",0 end Здесь исходный текст программы и ехе-файл Имитация заряда аккумулятораasm-файл Код (ASM): ; CONSOLE # include win64a.inc MAXSCREENX = 80 MAXSCREENY = 25 .code WinMain proc local Result:dword local color:dword local cci:CONSOLE_CURSOR_INFO local ConsoleWindow:SMALL_RECT invoke FreeConsole invoke AllocConsole ; Allocate the console invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOut,rax ;------------------------------------------------------------------- invoke GetLargestConsoleWindowSize,eax ; eax return in 31-16 bits: dwCoord.y ; 15-00 bits: dwCoord.x lea r8d,ConsoleWindow and dword ptr [r8],0 ; ConsoleWindow.Left = 0 ConsoleWindow.Top = 0 sub ax, MAXSCREENX sbb edx, edx and ax, dx add ax, MAXSCREENX-1 mov [r8+SMALL_RECT.Right],ax shr eax, 16 sub eax, MAXSCREENY sbb edx, edx and eax, edx add eax, MAXSCREENY-1 mov [r8+SMALL_RECT.Bottom],ax invoke SetConsoleWindowInfo,hOut,TRUE invoke SetConsoleScreenBufferSize,hOut,MAXSCREENY*10000h+MAXSCREENX;establish the new size of a window of the console invoke SetConsoleTitle,&Str2 ;definition of a title bar ;hide the cursor------------------------------------------------------ invoke GetConsoleCursorInfo,hOut,&cci lea edx,cci ; lpConsoleCursorInfo mov [rdx+CONSOLE_CURSOR_INFO.bVisible],FALSE invoke SetConsoleCursorInfo,hOut ;-------------------------------------------------------------------- invoke WriteConsole,hOut,&Str3,sizeof Str3,&Result,0 ;remove a line of symbols main_loop:invoke SetConsoleCursorPosition,hOut,20001h;coord xor edi,edi @@: mov edx,edi shr edx,2 movzx edx,index_color[rdx] ;color invoke SetConsoleTextAttribute,hOut mov edx,edi and edx,3 add edx,offset Str4 invoke WriteConsole,hOut,,1,&Result,0 ;remove a line of symbols inc edi invoke GetAsyncKeyState,VK_ESCAPE ; vKey ; Determine whether a key is up or down test eax, 8000h jnz exit0 invoke Sleep,1000 cmp edi,16 jb @b invoke SetConsoleCursorPosition,hOut,20001h;coord invoke SetConsoleTextAttribute,hOut,0 invoke WriteConsole,hOut,&Str1,16,&Result,0 ;remove a line of symbols invoke Sleep,1000 jmp main_loop ;-------------------------------------------------------------- exit0: invoke CloseHandle,hOut invoke FreeConsole invoke RtlExitUserProcess,NULL WinMain endp hOut dq ? Str1 db 16 dup (0) Str2 db 'Charge accumulator',0 Str3 db 'For an exit from the program press CTRL+C or CTRL+Break key',10,\ 0C9h, 16 dup (0CDh),0BBh,10,\ 0BAh, 16 dup (0), 0BAh,0DDh,10,\ 0C8h, 16 dup (0CDh),0BCh Str4 db 176, 177, 178, 0DBh index_color db 4,0Ch,0CEh,0EFh end Здесь исходный текст программы и ехе-файл Теоретические основы программирования консольных приложений Консоли. Текстовый пользовательский интерфейс (Character User Interface)Консоли управляют вводом и выводом (I/O) консольных приложений (character-mode applications) (прикладных программ, которые не предусматривают свой собственный графический интерфейс пользователя (Graphics User Interface ― GUI)) — разновидность интерфейса пользователя, использующая при вводе-выводе и представлении информации исключительно набор буквенно-цифровых символов и символов псевдографики. Характеризуется малой требовательностью к ресурсам аппаратуры ввода-вывода (в частности, памяти) и высокой скоростью отображения информации. Недостатком подобного типа интерфейса является ограниченность изобразительных средств по причине ограниченности количества символов, включённых в состав шрифта, предоставляемого аппаратурой. Программы с текстовым интерфейсом могут имитировать оконный интерфейс. В простейшем случае текстовый интерфейс использует интерфейс командной строки, однако многие программы с помощью интерактивных элементов создают более дружественный интерфейс, приближающийся по удобству к графическому. В текстовом интерфейсе реализованы все базовые элементы интерфейса, используемые и в графическом интерфейсе — меню, кнопки, переключатели, флажки, выпадающие списки, полосы прокрутки и так далее. На программном уровне для ввода и вывода информации консольные программы используют стандартные устройства ввода-вывода (stdin, stdout, stderr), хотя могут открывать и другие файлы, сетевые соединения и совершать иные действия, доступные в выполняющей их среде. Вывод печатных символов в stdout и stderr приводит к появлению этих символов на устройстве вывода и к получению их пользователем.
Консольная программа не обязана заботиться о реализации самого взаимодействия с пользователем, ограничиваясь вводом-выводом на стандартные устройства. Собственно взаимодействие с пользователем обычно осуществляет операционная система. Любая программа, получающая данные путём чтения stdin и отправку данных путём записи в stdout, по определению является консольной программой. Однако, такие программы могут обходиться и без пользователя, поскольку stdin и stdout могут быть связаны не с интерактивными устройствами (клавиатурой и монитором), а с файлами или потоками ввода/вывода других программ. Консольные функции дают возможность разного уровня доступа к консоли. Высокоуровневые консольные функции ввода-вывода данных (I/O) дают возможность приложению читать из их стандартного ввода данных, чтобы извлечь введённую информации с клавиатуры, сохраненную во входном буфере консоли. Функции также дают возможность программе записать в стандартный вывод или показать на экране текст стандартной ошибки в экранном буфере консоли. Высокоуровневые функции поддерживают также переадресацию стандартных дескрипторов и управление режимами работы консоли для различных функциональных возможностей ввода-вывода. Низкоуровневые консольные функции I/O дают возможность прикладным программам получит подробный отчет о событиях ввод данных от клавиатуры и мыши, а также о событиях, включающих взаимодействие пользователя с консольным окном. Низкоуровневые функции также дают больше возможностей в управлении выводом данных на экран. Консольные приложения ― некогда единственная форма программного обеспечения для работы с пользователем. После широкого распространения программ с графическим интерфейсом, консольные приложения продолжают сохранять своё значение. Постепенно программное обеспечение с GUI практически полностью вытеснило приложения с текстовым интерфейсом из повседневного использования. Однако и сейчас есть консольные приложения, которые могут в большей или меньшей степени конкурировать с программами с графическим интерфейсом, быть полезными при решении разнообразных задач. Виды консольных программ: Файловые менеджеры (Far menager) Мультимедиа Веб браузеры Текстовые редакторы О консольных приложениях Консоли Создание консоли Присоединение к консоли Закрытие консоли Дескрипторы консоли Буфер вводимых данных консоли События клавиатуры События мыши События изменения размера буфера Экранный буфер консоли Внешний вид и позиция курсора Атрибуты символов Атрибуты шрифта Окно и размер экранного буфера Прокрутка экранного буфера Методы ввода и вывода данных Режимы консоли Высокоуровневый консольный ввод-вывод Высокоуровневые консольные режимы работы Высокоуровневые консольные функции ввода и вывода Низкоуровневый консольный ввод-вывод (I/O) Низкоуровневые консольные режимы работы Низкоуровневые консольные функции ввода данных Низкоуровневые консольные функции вывода данных Кодовые страницы консоли Консольное управление обработчиками Защита буфера и права доступа в консоли Использование консоли Использование высокоуровневых функций ввода и вывода данных Запись символов или цветов в последовательные ячейки Чтение и запись блоков символов и атрибутов Чтение событий буфера вводимых данных Очистка экрана Прокрутка окна экранного буфера Прокрутка содержания экранного буфера Регистрация функции управления обработчиком Проблемы консольных приложений Справочник по консоли Функции консоли Структуры консоли Механизм управления событиями WinEvents консольного окна О консольных приложенияхКонсоли обеспечивают высокоуровневую поддержку для простых консольных приложений, взаимодействующих с пользователем, используя функции, которые читают из стандартного ввода данных и записывают в стандартный вывод или стандартную ошибку. Консоли также предусматривают сложную низкоуровневую поддержку, которая дает прямой доступ к экранному буферу консоли, а это дает возможность прикладным программам получать расширенную входную информацию (такую, как ввод данных от мыши). Консоли оригинал на английскомКонсоль (console) ― интерфейс, который обеспечивает ввод-вывод данных консольным приложениям. Этот независимый от процессора механизм делает её легкой для поддержания в готовности существующих консольных приложений или создание новых консольных инструментальных средств и прикладных программ. Консоль состоит из буфера вводимых данных и одного или нескольких экранных буферов. Буфер вводимых данных (input buffer) содержит очередь записей введенных данных, каждая из которых содержит информацию о событии ввода. Входная очередь всегда включает в себя события отпуска и нажатия клавиши. Она может также включать в себя события с мышью (перемещение указателя и нажатие и отпускание кнопки) и события, в течение которых действия пользователя воздействуют на размер активного экранного буфера. Экранный буфер (screen buffer) ― двухмерный массив символьных данных и данных о цвете для вывода информации в консольном окне. Любое число процессов может совместно использовать консоль. Функции Windows API дают возможность разного уровня доступа к консоли. Высокоуровневые консольные функции I/O дают возможность приложению читать из стандартного ввода данных, чтобы получать ввод информации от клавиатуры, сохраненный в буфере ввода консоли. Функции дают также возможность прикладной программе записывать в стандартный вывод или показать на экране текст стандартной ошибки в экранном буфере консоли. Высокоуровневые функции также поддерживают переназначение стандартных дескрипторов и управление режимами работы консоли для разных функциональных возможностей ввода-вывода (I/O). Низкоуровневые консольные функции I/O дают возможность прикладным программам получить подробный ввод данных о событиях с клавиатурой и мышью, также как и о событиях, включающих взаимодействие пользователя с консольным окном. Низкоуровневые функции к тому же включают большую часть управления выводом на экран. Создание консоли оригинал на английскомСистема создает новую консоль тогда, когда она запускает консольный процесс (console process), процесс символьного режима, точка входа которого ― функция main. Например, система создает новую консоль, когда она запускает командный процессор. Когда командный процессор запускает новый консольный процесс, пользователь может установить, создает ли система новую консоль для нового процесса или она наследует консоль командного процессора. Процесс может создать консоль, используя один из следующих способов: GUI или консольный процесс может использовать функцию CreateProcess с флажком CREATE_NEW_CONSOLE, чтобы создать консольный процесс с новой консолью. (По умолчанию, консольный процесс наследует консоль своего родителя, однако нет гарантии, что вводимые данные получит процесс, для которого они были предназначены). Графический интерфейс пользователя (GUI) или консольный процесс, который в настоящее время не связан с консолью могут использовать функцию AllocConsole для создания новой консоли. (Процесс, который вызывает функцию AllocConsole, не должен подключаться к существующей консоли. Процессы GUI, когда они создаются, не подключаются к консоли. Консольные процессы не связываются с консолью, если они созданы с использованием функции CreateProcess с флажком DETACHED_PROCESS). Как правило, процесс использует функцию AllocConsole, чтобы создать консоль, когда происходит ошибка, требующая взаимодействия с пользователем. Например, процесс GUI может создать консоль, когда происходит ошибка, которая препятствует ему использовать его нормальный графический интерфейс, или консольный процесс, который обычно не взаимодействует с пользователем, может создать консоль, чтобы показать на экране ошибку. Процесс может также создать консоль, устанавливая флажок CREATE_NEW_CONSOLE при вызове функции CreateProcess. Этот метод создает новую консоль, которая является доступной для дочернего процесса, но не для родительского процесса. Отдельные консоли дают возможность, и родительским и дочерним процессам взаимодействовать с пользователем без конфликта. Если этот флажок не установлен, когда создается консольный процесс, оба процесса присоединяются на одну ту же консоль, и нет никакой гарантии, что корректный процесс получит ввод данных, предназначенный для него. Прикладные программы могут предотвратить, беспорядок, создавая дочерние процессы, которые не наследуют дескрипторы буфера вводимых данных, или включать одновременно только один дочерний процесс, который наследует дескриптор буфера вводимых данных, в тоже время предотвращая чтение родительским процессом введенных данных консоли, до тех пор, пока не дочерний процесс не закончил. Создание новой консоли заканчивается созданием консольного окна, а также отдельных экранных буферов ввода-вывода. Процесс связывается с новой консолью, используя функцию GetStdHandle, чтобы получить дескрипторы экранных буферов и буфера ввода данных новой консоли. Эти дескрипторы дают возможность процессу обращаться к консоли. Когда процесс использует функцию CreateProcess, он может определить структуру STARTUPINFO, члены которой управляют характеристиками первой новой консоли (если таковая имеется) созданной для дочернего процесса. Структура STARTUPINFO, определяемая при вызове функции CreateProcess воздействует на созданную консоль, если установлен флажок CREATE_NEW_CONSOLE. Она также воздействует на созданную консоль, если дочерний процесс впоследствии использует функцию AllocConsole. Ниже перечислены параметры консоли, которые могут быть заданы: Размер окна новой консоли, в знакоместах Размещение окна новой консоли в пиксельных экранных координатах Размер экранного буфера консоли, в знакоместах Атрибуты цвет текста и фона экранного буфера новой консоли Экранное имя в строке заголовка нового консольного окна Система использует значения по умолчанию, если значения STARTUPINFO не определены. Дочерний процесс может использовать функцию GetStartupInfo, чтобы установить значения в своей структуре STARTUPINFO. Процесс не может изменить местоположение своего консольного окна на экране, но нижеследующим консольным функциям доступно устанавливать или извлекать другие параметры, определяемые в структуре STARTUPINFO. ФункцияОписаниеGetConsoleScreenBufferInfoИзвлекает размер окна, размер экранного буфера и атрибуты цвета.SetConsoleWindowInfoИзменяет размер окна консоли.SetConsoleScreenBufferSizeИзменяет размер экранного буфера консоли.SetConsoleTextAttributeУстанавливает атрибуты цвета.SetConsoleTitleУстанавливает заголовок окна.GetConsoleTitleИзвлекает заголовок окна консоли.Процесс может использовать функцию FreeConsole, чтобы отключить себя от унаследованной консоли или от консоли, созданной функцией AllocConsole. Присоединение к консоли оригинал на английскомПроцесс может использовать функцию AttachConsole, чтобы подключиться к консоли. Процесс может быть подключен к одной консоли. Консоль может иметь много процессов связанных с ней. Чтобы получить список процессов, связанных с консолью, вызовите функцию GetConsoleProcessList. Закрытие консоли оригинал на английскомПроцесс может использовать функцию FreeConsole, чтобы отключить себя от ее консоли. Если другие процессы совместно используют консоль, консоль не разрушается, но процесс, который обратился к функции FreeConsole не сможет обратиться к ней. После вызова FreeConsole, процесс может использовать функцию AllocConsole, чтобы создать новую консоль или функцию AttachConsole, чтобы подключиться к другой консоли. Консоль закрывается, когда последний процесс, связанный с ней завершает работу или вызывает функцию FreeConsole. Дескрипторы консоли оригинал на английскомКонсольный процесс использует дескрипторы для того, чтобы обратиться к буферу ввода данных и экранным буферам своей консоли. Процесс может использовать функцию GetStdHandle, CreateFile или функцию CreateConsoleScreenBuffer, чтобы открыть один из этих дескрипторов Функция GetStdHandle обеспечивает механизм для получения дескрипторов стандартного ввода данных (STDIN), стандартного вывода данных (STDOUT) и стандартной ошибки (STDERR), связанных с процессом. В ходе создания консоли, система генерирует эти дескрипторы. Вначале, дескриптор STDIN для буфера вводимых данных консоли, а затем дескрипторы STDOUT и STDERR активного экранного буфера консоли. Однако функция SetStdHandle может переназначать стандартные дескрипторы, изменяя дескриптор, связанный с STDIN, STDOUT или STDERR. Поскольку стандартные дескрипторы родительского элемента наследуются любым дочерним процессом, последующие вызовы к GetStdHandle возвращают переназначенный дескриптор. Дескриптор, возвращенный функцией GetStdHandle, по этой причине может сослаться на что-либо другое, а не на консольный ввод-вывод (I/O). Например, перед созданием дочернего процесса, родительский процесс может использовать SetStdHandle, чтобы установить дескриптор канала, который должен быть дескриптором STDIN и который будет унаследован дочерним процессом. Когда дочерний процесс вызывает функцию GetStdHandle, он получает дескриптор канала. Это означает, что родительский процесс может управлять стандартными дескрипторами дочернего процесса. Дескрипторы, возвращенные функцией GetStdHandle, имеют доступ GENERIC_READ | GENERIC_WRITE, если функция SetStdHandle не была использована для установки стандартного дескриптора, имеющего меньший доступ. Значение дескрипторов, возвращенных функцией GetStdHandle ― не 0, 1 и 2, как стандартные предопределенные константы потока в файле Stdio.h (STDIN, STDOUT и STDERR), не могут быть использованы в функциях, которые требуют дескриптора консоли. Функция CreateFile дает возможность процессу получить дескриптор для буфера вводимых данных его консоли и активного экранного буфера, даже если STDIN и STDOUT были переназначены. Чтобы открыть дескриптор буфера вводимых данных консоли, при вызове функции CreateFile установите значение CONIN$. Чтобы открыть дескриптор активного экранного буфера консоли, при вызове CreateFile установите значение CONOUT$. Функция CreateFile дает возможность Вам, чтобы определять доступ для чтения ― записи дескриптора, который она возвращает. Функция CreateConsoleScreenBuffer создает новый экранный буфер и возвращает дескриптор. Этот дескриптор может быть использован в любой функции, которая принимает дескриптор для консольного вывода данных. Новый экранный буфер не активен до тех пор, пока его дескриптор не определится при вызове к функции SetConsoleActiveScreenBuffer. Обратите внимание на то, что этот изменяющийся активный экранный буфер не воздействует на дескриптор, возвращенный GetStdHandle. Точно так же использование функции SetStdHandle, чтобы изменить дескриптор STDOUT не воздействует на активный экранный буфер. Консольные дескрипторы, возвращенные функциями CreateFile и CreateConsoleScreenBuffer, могут быть использованы в любой из консольных функций, которые требуют дескриптора буфера вводимых данных или экранного буфера консоли. Дескрипторы, возвращенные функцией GetStdHandle могут быть использованы консольными функциями, если они не были переназначены, чтобы не сослаться на что-либо иное, чем консольный ввод-вывод. Однако, если стандартный дескриптор был переназначен, чтобы сослаться на файл или канал, он может быть использован только функциями ReadFile и WriteFile. Процесс может использовать функцию DuplicateHandle, чтобы создать дубликат консольного дескриптора, который имеет другой доступ или наследственность от исходного дескриптора. Обратите внимание на то, что, не смотря на это, процесс может создать дубликат дескриптора консоли только для своего собственного использования. Это его отличает от других типов дескрипторов, (таких как файла, канала или мьютекс-объекта), для которых функция DuplicateHandle может создавать дубликат, являющийся допустимым для другого процесса. Чтобы закрыть консольный дескриптор, процесс может использовать функцию CloseHandle. Буфер вводимых данных консолиКаждая консоль имеет буфер вводимых данных, который содержит очередь записей о событиях ввода. Когда окно консоли имеет фокус клавиатуры, консоль оформляет каждое событие ввода (типа отдельного нажатия клавиши, перемещение мыши или щелчка кнопки мыши) как введенное данное, которое оно помещает в буфер вводимых данных консоли. Прикладные программы могут обращаться к буферу вводимых данных консоли косвенно при помощи использования высокоуровневых консольных функций I/O или непосредственно при помощи использования низкоуровневых консольных функций ввода. Высокоуровневые функции ввода фильтруют и обрабатывают данные в буфере вводимых данных, возвращая только поток введенных символов. Низкоуровневые функции ввода дают возможность прикладным программам читать введенные данные непосредственно из буфера вводимых данных консоли, или помещать введенные данных в буфер вводимых данных. Чтобы открыть дескриптор буфера вводимых данных консоли, при вызове к функции CreateFile установите значение CONIN$. Запись ввода данных ― это структура, содержащая информацию о типе события, которое произошло (клавиатура, мышь, изменение размеров окна, фокус или событие меню), а также конкретные детали о событии. Поле EventType в структуре INPUT_RECORD содержит тип события в записи. Фокус и события меню помещаются в буфере вводимых данных консоли для внутреннего использования системой и должны быть игнорироваться прикладными программами. События клавиатурыСобытия клавиатуры генерируются тогда, когда любая клавиша нажимается или отпускается; это включает в себя управляющие клавиши. Однако клавиша ALT имеет специальное предназначение в системе, когда нажимается и отпускается без объединения с другим символом, и это не передается прямо в приложение. Комбинация клавиш CTRL+C также не передается непосредственно в программу, если введенный дескриптор находится в режиме обработки. Если событие ввода ― нажатие клавиши, поле Event в структуре INPUT_RECORD является структурой KEY_EVENT_RECORD, содержащей нижеследующую информацию: Булево значение, указывающее, была ли клавиша нажата или отпущена. Счет повторений, который может быть больше, чем один, когда клавиша удерживается. Код виртуальной клавиши, идентифицирующий данную клавишу не зависящим от устройства способом. Виртуальный ― скэн-код, обозначающий аппаратно-зависимое значение, созданное аппаратными средствами клавиатуры. Преобразованный символ UNICODE или ANSI. Флажковая переменная, которая указывает на состояние управляющих клавиш (клавиши ALT, CTRL, SHIFT, NUM LOCK, SCROLL LOCK и CAPS LOCK) и обозначает, была ли нажата дополнительная клавиша. Дополнительные клавиши для 101-клавишные и 102-клавишные клавиатуры имеют INS, DEL, HOME, END, PAGE UP, PAGE DOWN клавиши и клавиши со стрелкой в блоках слева от цифровой клавиатуры и клавиши делителя (/) и ENTER в цифровой клавиатуре. События мышиСобытия с мышью генерируются всякий раз, когда пользователь перемещает мышь или нажимает или отпускает одну из кнопок мыши. События с мышью помещаются в буфере вводимых данных, только в том случае, если выполнены нижеследующие условия: Режим ввода консоли установлен в значение ENABLE_MOUSE_INPUT (режим заданный по умолчанию). Консольное окно имеет фокус клавиатуры. Курсор мыши находится в пределах рамок окна консоли. Если событие ввода ― событие с мышью, поле Event в структуре INPUT_RECORD является структурой MOUSE_EVENT_RECORD, содержащей нижеследующую информацию: Координаты курсора мыши в переводе на строки и столбцы символьных знакоместа в системе координат экранного буфера консоли Флажковая переменная, обозначающая состояния кнопок мыши. Флажковая переменная, обозначающая состояния управляющих клавиш (клавиши ALT, CTRL, SHIFT, NUM LOCK, SCROLL LOCK и CAPS LOCK) и обозначает, была ли нажата дополнительная клавиша. Дополнительные клавиши для 101-клавишной и 102-клавишной клавиатуры имеют INS, DEL, HOME, END, PAGE UP, PAGE DOWN клавиши и клавиши со стрелкой в блоках слева от цифровой клавиатуры и клавиши делителя (/) и ENTER в цифровой клавиатуре. Флажковая переменная, обозначающая, было ли событие нормальным нажатием кнопки или событием отпуска кнопки, событием перемещения мыши, или вторым щелчком события двойного щелчка. Обратите внимание координаты позиции мыши ― в понятиях экранного буфера консоли, не консольное окно. Экранный буфер, может прокручиваться относительно окна, так что верхний левый угол окна ― это не обязательно координата (0,0) экранного буфера консоли. Чтобы отрегулировать координаты мыши относительно системы координат окна, вычтите начальные координаты окна из координат позиции мыши. Чтобы установить начало координат окна, используйте функцию GetConsoleScreenBufferInfo. Поле dwButtonState структуры MOUSE_EVENT_RECORD имеет битовое соответствие для каждой кнопки мыши. Бит равен 1, если кнопка нажата, и 0, если кнопка отпущена. Событие отпуска кнопки регистрируется как значение 0 в поле dwEventFlags структуры MOUSE_EVENT_RECORD и изменяется в бите кнопки с 1 на 0. Функция GetNumberOfConsoleMouseButtons получает число кнопок на мыши События изменения размера буфераМеню консольного окна дает возможность пользователю изменить размер активного экранного буфера; это изменение создает событие изменения размеров буфера. События изменения размеров буфера помещаются в буфере вводимых данных, если режим ввода данных консоли установлен в ENABLE_WINDOW_INPUT (то есть заданный по умолчанию режим заблокирован). Если событие ввода данных является событием, изменяющим размеры буфера, поле Event структуры INPUT_RECORD является структурой WINDOW_BUFFER_SIZE_RECORD, содержащей новый размер экранного буфера консоли, выраженного в столбцах и строках символьных знакомест. Если пользователь уменьшает размер экранного буфера консоли, любые данные в отброшенной части буфера теряются. Изменения размера экранного буфера консоли, как результат вызовов из прикладной программы функции SetConsoleScreenBufferSize, не создают событий изменения размера буфера. Экранный буфер консолиЭкранный буфер (screen buffer) ― двухмерный массив символов и данных о цвете для вывода данных в консольном окне. Консоль может иметь множество экранных буферов. Активный экранный буфер (active screen buffer) ― тот, который отображается на экране. Система создает экранный буфер всякий раз, когда она создает новую консоль. Чтобы открыть дескриптор активного экранного буфера консоли, при вызове к функции CreateFile установите значение CONOUT$. Процесс может использовать функцию CreateConsoleScreenBuffer, чтобы создать дополнительные экранные буферы для своей консоли. Новый экранный буфер не активен до тех пор, пока его дескриптор не будет определен при вызове к функции SetConsoleActiveScreenBuffer. Однако к экранным буферам можно обращаться для чтения и записи, независимо, являются ли они активными или неактивными. Каждый экранный буфер имеет свой собственный двухмерный массив записей текстовой информации. Данные для каждого символа сохраняются в структуре CHAR_INFO, которая определяет символы Unicode или ANSI, и цвет текста и цвета фона, на котором этот символ отображен. Ряд свойств, связанных с экранным буфером может быть установлен независимо для каждого буфера дисплея. Это означает, что изменяющийся активный экранный буфер может иметь негативное влияние на внешний вид консольного окна. Свойства, связанные с экранным буфером включают в себя: Размер экранного буфера, в строках и столбцах символов. Атрибуты текста (цвет текста и цвет фона для отображения на экране текста, который будет написан функцией WriteFile или WriteConsole). Размер окна и расположение (прямоугольная область экранного буфера консоли, которая отображается в консольном окне). Позиция, внешний вид и видимость курсора. Режимы вывода (ENABLE_PROCESSED_OUTPUT и ENABLE_WRAP_AT_EOL_OUTPUT). Для получения дополнительной информации о консольных режимах вывода, см. Высокоуровневые консольные режимы работы. Когда экранный буфер создается, он содержит пробелы. Его курсор видим и установлен в начало координат буфера (0,0), а окно устанавливается в его верхний левый угол в начало координат буфера. Размер экранного буфера консоли, размеры окна, текстовые атрибуты и внешний вид курсора определяется пользователем или системными значениями по умолчанию. Чтобы получить текущие значения различных свойств, связанных с экранным буфером консоли, используйте функции GetConsoleScreenBufferInfo, GetConsoleCursorInfo и GetConsoleMode. Прикладные программы, которые изменяют любое из свойств экранного буфера консоли, должны или создать свой собственный экранный буфер или сохранить состояние унаследованного буфера дисплея в ходе запуска и восстанавливать его при выходе. Внешний вид и позиция курсораКурсор экранного буфера может быть видим или скрыт. Когда он видим, его внешний вид может изменяться в пределах от полностью заполненного знакоместа символа до вида как горизонтальная линия внизу ячейки. Чтобы получить информацию о внешнем виде и видимости курсора, используйте функцию GetConsoleCursorInfo. Эта функция сообщает, является ли курсор видимым и описывает внешний вид курсора как процентное отношение от знакоместа символа, которое он заполняет. Чтобы установить внешний вид и видимость курсора, используйте функцию SetConsoleCursorInfo.
Символы, написанные высокоуровневыми консольными функциями I/O пишутся в текущем местоположении курсора, продвигая курсор к следующему местоположению. Чтобы определить текущую позицию курсора в системе координат экранного буфера, используйте функцию GetConsoleScreenBufferInfo. Вы можете использовать функцию SetConsoleCursorPosition, чтобы установить позицию курсора и, таким образом, управлять размещением текста, который написан или отображен на экране высокоуровневыми консольными функциями I/O функциями. Если Вы перемещаете курсор, текст в новом местоположении курсора переписывается. Позиция, внешний вид и видимость курсора устанавливаются независимо для каждого экранного буфера. Атрибуты символовАтрибуты символов могут быть поделены на два класса: класс цвета и класс DBCS (double-byte character set) ― набор двухбайтовых комбинаций символов. Нижеследующие атрибуты определяются в заголовочном файле Wincon.h. АтрибутПредназначениеFOREGROUND_BLUEСодержит синий цвет текстаFOREGROUND_GREENСодержит зеленый цвет текстаFOREGROUND_REDСодержит красный цвет текстаFOREGROUND_INTENSITYЦвет текста имеет повышенную интенсивностьBACKGROUND_BLUEСодержит синий цвет фонаBACKGROUND_GREENсодержит зеленый цвет фонаBACKGROUND_REDСодержит красный цвет фонаBACKGROUND_INTENSITYЦвет фона имеет повышенную интенсивностьCOMMON_LVB_LEADING_BYTEНачальный байтCOMMON_LVB_TRAILING_BYTEКонцевой байтCOMMON_LVB_GRID_HORIZONTALВерх горизонталиCOMMON_LVB_GRID_LVERTICALЛевая вертикальCOMMON_LVB_GRID_RVERTICALПравая вертикальCOMMON_LVB_REVERSE_VIDEOИзменяет на противоположные атрибуты цвета текста и цвета фонаCOMMON_LVB_UNDERSCOREПодчеркиваетАтрибуты цвета текста определяют его цвет. Атрибуты фона определяют цвет, который используется для закрашивания фона ячейки. Другие атрибуты используются DBCS. Приложение может комбинировать константы цвета текста и фона, чтобы получать разные цвета. Например, нижеследующая комбинация приводит к яркому синему тексту на синем фоне. Код (Text): FOREGROUND_BLUE + FOREGROUND_GREEN + FOREGROUND_INTENSITY + BACKGROUND_BLUE Если константа фона не определена, то фон черный, а если константа цвета текста не определена, текст черный. Например, нижеследующая комбинация производит черный текст на белом фоне. Код (Text): BACKGROUND_BLUE + BACKGROUND_GREEN + BACKGROUND_RED Каждое знакоместо символа экранного буфера сохраняет атрибуты цвета для цветов, используемых в прорисовке цвета текста (текст) и фона этой ячейки. Приложение может устанавливать данные о цвете для каждого знакоместа символа индивидуально, сохраняя информацию в поле Attributes структуры CHAR_INFO для каждой ячейки. Текущие атрибуты текста каждого экранного буфера используются для символов, впоследствии записываемых или отображаемых на экране высокоуровневыми функциями. Приложение может использовать функцию GetConsoleScreenBufferInfo, чтобы регулировать текущие текстовые атрибуты экранного буфера и функцию SetConsoleTextAttribute, чтобы установить атрибуты символов. Изменение атрибутов экранного буфера не воздействует на отображение символов, записанных перед этим. Эти текстовые атрибуты не затрагивают символы, написанные низкоуровневыми консольными функциями I/O (типа функции WriteConsoleOutput или WriteConsoleOutputCharacter), которые или явно устанавливают атрибуты для каждой ячейки, в которой есть запись, или оставляют атрибуты неизменными. Атрибуты шрифтаФункция GetCurrentConsoleFont извлекает информацию о текущем консольном шрифте. Информация, сохраненная в структуре CONSOLE_FONT_INFO включает в себя ширину и высоту каждого символа в шрифте. Функция GetConsoleFontSize получает данные о размере шрифта, используемого заданным экранным буфером консоли. Окно и размер экранного буфераРазмер экранного буфера выражается в понятиях координатной сетки, основанной на знакоместах символов. Ширина равна числу символьных знакомест в каждой строке, а высота ― числу строк. С каждым экранным буфером связано окно, которое обуславливает размер и расположение прямоугольной части экранного буфера консоли, отображенного в консольном окне. Окно экранного буфера определяется при помощи установки координат в символьных знакоместах верхней левой и нижней правой ячеек прямоугольника окна. Экранный буфер может быть любого размера, ограниченный только доступной памятью. Размеры окна экранного буфера, основанные на текущем размере шрифта (управляемым исключительно пользователем), не могут превышать соответствующие размеры или экранного буфера консоли, или максимального окна, которое может вместиться на экране. Функция GetConsoleScreenBufferInfo возвращает нижеследующую информацию об экранном буфере и его окне: Текущий размер экранного буфера консоли Текущее местоположение окна Максимальный размер данного окна при текущем размере экранного буфера, текущий размер шрифта и размер экрана. Функция GetLargestConsoleWindowSize возвращает значение максимального размера окна консоли, базирующейся на текущем шрифте и размеры экрана. Эти размеры отличаются от максимального размера окна, возвращаемого функцией GetConsoleScreenBufferInfo, в которой размер экранного буфера консоли игнорируется. Чтобы изменить размер экранного буфера, используйте функцию SetConsoleScreenBufferSize. Эта функция терпит неудачу, если любой габарит определяемого размера является меньше, чем соответствующий размер окна консоли. Чтобы изменить размер или расположение окна экранного буфера, используйте функцию SetConsoleWindowInfo. Эта функция не выполняет свою задачу, если координаты угла определяемого окна превышают пределы экранного буфера консоли или экрана. Изменение размера окна активного экранного буфера изменяет размер консольного окна, отображенного на экране. Процесс может изменить режим ввода данных своей консоли, чтобы дать возможность вводить данные окна так, чтобы процесс был в состоянии получить вводимую информацию, когда пользователь изменяет размер экранного буфера консоли. Если приложение дает возможность ввод данных окна, оно может использовать функцию GetConsoleScreenBufferInfo, чтобы получить окно и размер экранного буфера при автозагрузке. Эта информация может затем использоваться, чтобы определить способ, которым информация будет показана на экране в окне. Если пользователь изменяет размер экранного буфера консоли, приложение может в ответ изменить способ, которым информация показывается на экране. Например, приложение может откорректировать способ автоматического переноса текста на новую строку в конце строки, если число символов в строке изменяется. Если приложение не дает возможности ввод данных в окно, оно должно или использовать унаследованное окно, а экранный буфер изменяет размер, или привести их к желательному размеру в течение запуска и восстанавливать унаследованный буфер, изменяя размер при выходе. Для дополнительной информации о режиме ввода данных окна, смотри раздел Низкоуровневые консольные режимы работы. Прокрутка экранного буфераКонсольное окно показывает на экране часть активного экранного буфера. Каждый экранный буфер поддерживает свой собственный текущий прямоугольник окна, который задает координаты верхних левых и нижних правых символьных знакомест, которые будут показаны на экране в консольном окне. Чтобы установить текущий прямоугольник окна экранного буфера, используйте функцию GetConsoleScreenBufferInfo. Когда экранный буфер создается, верхний левый угол его окна находится в верхнем левом угле экранного буфера консоли в (0,0). Прямоугольник окна может изменяться, чтобы отображать различные части экранного буфера консоли. Прямоугольник окна экранного буфера может изменяться в нижеследующих ситуациях: Когда вызывается функция SetConsoleWindowInfo, чтобы установить новый прямоугольник окна, она прокручивает вид экранного буфера консоли, изменяя позицию прямоугольника окна без изменения размеров окна. Примеры прокрутки содержания окна, смотри раздел Прокрутка окна экранного буфера. Когда используется функция WriteFile, чтобы сделать запись в экранный буфер, тогда в режиме вывода включается переход в конце строки (EOL) на новую строку, который автоматически перемещает прямоугольник окна, так, что курсор всегда отображается на экране. Когда функция SetConsoleCursorPosition устанавливает новую позицию курсора, которая находится вне границ текущего прямоугольника окна, тогда прямоугольник окна перемещается автоматически, чтобы показать на экране курсор. Когда пользователь изменяет размер консольного окна или использует линейки прокрутки окна, тогда прямоугольник окна активного экранного буфера может измениться. Об этом изменении не сообщается, как о событии, изменяющем размеры окна в буфере вводимых данных. В каждой из этих ситуаций, прямоугольник окна перемещается, чтобы показать на экране разные части экранного буфера консоли, но содержание экранного буфера консоли остается в той же самой позиции. Нижеследующие ситуации могут заставить переместить содержание экранного буфера консоли: Когда вызывается функция ScrollConsoleScreenBuffer, прямоугольный блок копируется из одной части экранного буфера в другой Когда используется функция WriteFile, чтобы сделать запись в экранный буфер, тогда в режиме вывода включается переход в конце строки (EOL) на новую строку, содержание экранного буфера консоли автоматически прокручивается Когда используется функция WriteFile, чтобы записать в экранный буфер с автоматическим переходом на новую строку, в случае если встречается конец экранного буфера консоли. Эта прокрутка сбрасывает верхнюю строку экранного буфера консоли. Функция ScrollConsoleScreenBuffer устанавливает прямоугольник экранного буфера консоли, который перемещается и новые верхние левые координаты, в которые прямоугольник копируется. Эта функция может прокручивать часть или взятое в целом содержание экранного буфера консоли. Иллюстрация показывает действие функции ScrollConsoleScreenBuffer, которая прокручивает несколько верхних строк взятого в целом содержания экранного буфера консоли. Содержание верхних строк отвергается, а строки внизу заполняются заданными символами и цветом. Действия функции ScrollConsoleScreenBuffer могут быть ограничены, при помощи установки необязательного прямоугольника отсечения по границам так, чтобы содержание экранного буфера консоли вне прямоугольника отсечения было неизменно. Действие отсечения по границам должно создать подокно (прямоугольник отсечения), содержание которого прокручивается без воздействия на остальную часть экранного буфера консоли. Пример, в котором используется, ScrollConsoleScreenBuffer, рассматривается в статье Прокрутка экранного буфера. Методы ввода и вывода данныхWin32 API предоставляет два разных подхода к консольному вводу ― выводу (I/O), выбор которого зависит от того, сколько гибкости и управляемости необходимо приложению. Высокоуровневый метод включает простой символьный поток ввода-вывода, но он ограничивает доступ к буферу ввода данных консоли и экранным буферам. Низкоуровневый метод требует, чтобы разработчики писали большее количество кода и выбирали среди большего количества функций, однако это придает приложению большую гибкость. Приложение может использовать функции файлового ввода-вывода, ReadFile и WriteFile, и консольные функции, ReadConsole и WriteConsole, для высокоуровневого ввода-вывода, которые обеспечивают косвенный доступ к вводу данных консоли и экранным буферам. Высокоуровневые функции ввода данных фильтруют и обрабатывают информацию в буфере вводимых данных консоли, чтобы возвратить их как поток символов, не учитывая вводимой информации от мыши и при изменении размеров буфера. Точно так же, высокоуровневые функции вывода данных записывают поток символов, который отображается на экране в текущем местоположении курсора в экранном буфере. Приложение управляет способом работы этой функций, устанавливая режимы ввода-вывода консоли. Низкоуровневые функции I/O обеспечивают прямой доступ к вводу данных консоли и экранным буферам, давая возможность приложению обращаться к событиям мыши и событиям изменения размера буфера ввода и к расширенной информации для событий клавиатуры. Низкоуровневые функции вывода данных дают возможность приложению читать или записывать в экранном буфере заданное число последовательных символьных знакомест, или читать, или записывать в прямоугольные блоки символьные знакоместа в заданном месте в экранном буфере. Режимы ввода данных консоли воздействуют на низкоуровневый ввод данных, разрешая приложению устанавливать, чьи это события в буфере вводимых данных, мыши или изменения размера буфера. Режимы вывода информации консоли не воздействуют на низкоуровневый вывод данных. Высокоуровневая и низкоуровневая методики ввода-вывода не являются взаимоисключающими и приложение может использовать любую комбинацию этих функций. Тем не менее, как правило, прикладная программа использует исключительно один или другой способ. Нижеследующие разделы описывают консольные режимы работы и высокоуровневые и низкоуровневые функции I/O. Режимы консолиСвязанная с каждым консольным буфером вводимых данных установка режимов ввода, воздействует на операции ввода информации. Точно так же, каждый экранный буфер консоли имеет установку режимов вывода, который воздействует на операции вывода данных. Режимы ввода данных могут быть разделены на две группы: которые воздействуют на высокоуровневые функции ввода данных и которые воздействуют на низкоуровневые функции ввода. Режимы вывода воздействуют только на прикладные программы, которые используют высокоуровневые функции вывода данных. Функция GetConsoleMode сообщает о текущем режиме ввода данных буфера ввода консоли или текущего режима вывода экранного буфера. Функция SetConsoleMode устанавливает текущий режим или консольного буфера вводимых данных или экранного буфера. Если консоль имеет множество экранных буферов, режимы вывода каждого могут быть разными. Приложение может изменять режимы ввода-вывода (I/O) в любое время. Для получения дополнительной информации о консольных режимах работы, которые находятся под влиянием высокоуровневых и низкоуровневых операций ввода-вывода, смотрите статью Высокоуровневые консольные режимы работы и Низкоуровневые консольные режимы работы. Функция GetConsoleDisplayMode сообщает, находится ли текущая консоль в полноэкранном режиме и связывается ли она непосредственно с аппаратными средствами. Высокоуровневый консольный ввод-выводФункции высокоуровневого ввода-вывода (I/O) обеспечивают простой способ чтения потока символов из консольного ввода данных или записи потока символов в консольном выводе информации. Высокоуровневая операция чтения получает введенные символы из буфера вводимых данных консоли и сохраняет их в заданном буфере. Высокоуровневая операция записи берет символы из заданного буфера и записывает их в экранный буфер в текущем местоположении курсора, продвигая курсор, по мере того, как записывается символ. Высокоуровневый ввод-вывод дает Вам выбор между функциями ReadFile и WriteFile и функциями ReadConsole и WriteConsole. Они были бы идентичны, если бы не два важных различия. Консольные функции поддерживают использование или символов Unicode или набора символов ANSI; функции файлового ввода-вывода не поддерживают Unicode. К тому же, функции файлового ввода-вывода могут быть использованы для обращения к файлам, каналам и последовательным устройствам связи; консольные функции могут быть использованы только с консольными дескрипторами. Это различие важно, если приложение опирается на стандартные дескрипторы, которые, могут быть переназначены. При использовании любого набора высокоуровневых функций, приложение может управлять цветом текста и фона используемыми символами дисплея, впоследствии записанными в экранном буфере. Прикладная программа может также использовать и консольные режимы работы, которые воздействуют на высокоуровневый консольный ввод-вывод (I/O), чтобы включать или отключать нижеследующие свойства: Эхо-контроль ввода информации с клавиатуры в активном экранном буфере Построчный ввод данных, в котором операция чтения не возвращается до тех пор, пока не нажата клавиша ENTER. Автоматические процессы ввода информации с клавиатуры, которые манипулируют возвратом каретки, CTRL+C и другими частностями ввода данных Автоматические действия вывода данных, которые управляют переносом строки, возвратом каретки, возвратом на один символ и другими частностями вывода информации Высокоуровневые консольные режимы работыХарактер работы высокоуровневых консольных функций находится под влиянием консольного режима ввода и вывода. Когда консоль создана, для ее буфера вводимых данных разрешены все из ниже перечисленных консольных режимов ввода: Режим построчного ввода данных Режим обработки ввода данных Режим отражения ввода данных Для обоих из ниже перечисленных консольных режимов вывода, когда они создаются, разрешены действия экранного буфера консоли: Режим обработки вывода данных Режим переноса выводимых данных в конце строки (EOL) Все три режима ввода данных, наряду с режимом обработки вывода, предназначены, чтобы работать вместе. Самое лучшее или включать, или отключить все эти режимы, как группу. Когда все они включены, приложение, как говорится, находится в "приготовленном" режиме, который означает то, что большинство действий являются управляемыми для приложения. Когда все отключены, прикладная программа находится в "неприготовленном" режиме, который означает, что ввод данных не фильтруется и любая его обработка оставлена приложению. Прикладная программа может использовать функцию GetConsoleMode, чтобы установить текущий режим буфера вводимых данных консоли или экранного буфера. Вы можете включать или отключать любой из этих режимов при помощи использования нижеследующих значений в функции SetConsoleMode. Обратите внимание на то, что установка режима вывода в одном из экранных буферов не воздействует на режим вывода других экранных буферов РежимОписаниеENABLE_PROCESSED_INPUTДескриптор используется консольным вводом, чтобы заставить систему обрабатывать любое системное редактирование или ввод данных от управляющей клавиши, а не возвращать его как введенное данное при операции чтения буфера. Если к тому же включается построчный ввод данных, возвраты на один символ и возвраты каретки обрабатываются правильно. Возврат на один символ заставляет курсор, двигаться назад на один пробел без воздействия на символ в позиции курсора. Возврат каретки преобразуется в комбинацию кодов возврата каретки ASCII 13 и конца строки ASCII 10, представляемые как пустая строка. Если включен отраженный режим ввода данных, а вывод данных должен отразить системное редактирование, должна быть включена обработка вывода информации для активного экранного буфера. Если включается обработка ввода данных, комбинация клавиш CTRL+C пересылается на соответствующий обработчик независимо от того, включен или нет построчный ввод данных. Для получения дополнительной информации об управляющих обработчиках, см. статью Консольное управление обработчиками.ENABLE_LINE_INPUTИспользуется с дескриптором консольного ввода данных, чтобы заставить функции ReadFile и ReadConsole возвращать значение, когда нажата клавиша ENTER. Если режим построчного ввода данных заблокирован, функции возвращают значение тогда, когда один или несколько символов доступны в буфере вводимых данных.ENABLE_ECHO_INPUTИспользуется с дескриптором консольного ввода данных, чтобы заставить ввод информации с клавиатуры читать при помощи функций ReadFile или ReadConsole, которая будет отображаться на экране активным экранным буфером. Символы отображаются на экране только в том случае, если процесс, который вызывает ReadFile или ReadConsole имеет открытый дескриптор активного экранного буфера. Эхо-режим не может быть разрешен, если также не включен построчный ввод данных. Режим вывода активного экранного буфера воздействует на способ, которым отображаемый на экране ввод данных показывается на экране.ENABLE_PROCESSED_OUTPUTИспользуется с дескриптором экранного буфера консоли, чтобы заставить систему выполнить соответствующее действие для управляющих символов ANSI, которые пишутся в экранном буфере. Обрабатываются возврат на один символ, перемещение при помощи клавиши TAB, звонковая сигнализация, возврат каретки и символы перевода строки. Символ табуляции перемещает курсор в следующую позицию табуляции, которая установлена через каждые восемь символов. Звонковая сигнализация издает звук краткой длительности.ENABLE_WRAP_AT_EOL_OUTPUTИспользуется с дескриптором экранного буфера консоли, чтобы заставить текущую позицию вывода данных (позицию курсора) переместиться в первый столбец следующей строки, когда текущая строка достигла конца. Если достигается низ области окна, начало координат окна перемещается вниз на одну строку. Это перемещение имеет действие прокрутки содержания окна на одну строку. Если достигается низ экранного буфера консоли, содержание экранного буфера консоли прокручивается на одну строку, а верхняя строка экранного буфера консоли сбрасывается.Если этот режим заблокирован, последний символ в строке переписывается поверх любого последующего символа. Высокоуровневые консольные функции ввода и выводаФункции ReadFile и WriteFile или функции ReadConsole и WriteConsole, дают возможность приложению читать ввод данных консоли и записывать консольный вывод информации как поток символов. ReadConsole и WriteConsole ведут себя точно подобно ReadFile и WriteFile за исключением того, что они могут быть использованы или как функции расширенного 16-битного алфавита (в которой текстовые параметры должны использовать Unicode) или как функции ANSI (в которой текстовые параметры должны использовать символы из набора символов Windows). Прикладные программы, которым нужно поддерживать один набор источников, чтобы поддержать или Unicode или набор символов ANSI, должны использовать ReadConsole и WriteConsole. Функции ReadConsole и WriteConsole могут быть использованы только с дескрипторами консоли; функции ReadFile и WriteFile могут быть использованы с другими дескрипторами (такими как дескрипторы файлов или каналов). Функции ReadConsole и WriteConsole завершаются с ошибкой, если используются со стандартным дескриптором, который был переназначен и больше не является консольным дескриптором. Чтобы получать ввод информации с клавиатуры, процесс может использовать функции ReadFile или ReadConsole с дескриптором буфера вводимых данных консоли, или он может использовать ReadFile, чтобы читать ввод данных из файла или канала, если был переназначен STDIN. Эти функции возвращают только события клавиатуры, которые могут быть преобразованы в символы ANSI (или в символы Unicode в случае ReadConsole). Ввод данных, который может быть возвращен, включает в себя комбинации управляющих клавиш. Функции не возвращают события клавиатуры, включающие функциональные клавиши или клавиши со стрелкой. События ввода, созданные мышью, окном, фокусом или вводом меню не учитываются. Если включен режим построчного ввода данных (режим по умолчанию), функции ReadFile и ReadConsole не возвращают значения вызывающей программе до тех пор, пока не будет нажата клавиша ENTER. Если режим построчного ввода данных заблокирован, функции не возвращают значения до тех пор, пока, по меньшей мере, не будет доступен один символ. В любом режиме, все доступные символы читаются до тех пор, пока, или к набору на клавиатуре, больше нет доступа, или было прочитано заданное число символов. Непрочитанные символы буферизируются до следующей операции чтения. Функции сообщают об общем количестве фактически прочитанных символов. Если включается эхо-режим ввода данных, символы, читаемые этими функциями, записываются в текущую позицию курсора активного экранного буфера. Процесс может использовать функцию WriteFile или WriteConsole, чтобы записать в или активный или неактивный экранный буфер, или, если STDOUT был переназначен, он может использовать функцию WriteFile, чтобы записать в файл или канал. Обработка режима вывода и автоматического перехода в режиме вывода на новую строку в конце строчки EOL управляется путем записи символов или отображения в экранном буфере. Символы, написанные функцией WriteFile или WriteConsole, или повторенные на экране функцией ReadFile или ReadConsole, вставляются в экранный буфер в текущей позиции курсора. По мере того, как пишется символ, позиция курсора продвигается на следующее символьное знакоместо; однако поведение ее в конце строки зависит от режима автоматического перехода на новую строку в режиме вывода экранного буфера консоли (EOL). Приложение может использовать функцию GetConsoleScreenBufferInfo, чтобы получить текущую позицию курсора и функцию SetConsoleCursorPosition, чтобы установить позицию курсора. За примером, в котором используются высокоуровневые консольные функции I/O, обратитесь к статье Высокоуровневый консольный ввод-вывод. Низкоуровневый консольный ввод-вывод (I/O)Низкоуровневые консольные функции I/O расширяют контроль приложения над консольным вводом ― выводом (I/O), разрешая прямой доступ к вводу данных консоли и экранным буферам. Эти функции дают возможность прикладной программе выполнять нижеследующие задачи: Принимать ввод информации о событиях мыши и изменениях размеров буфера. Принимать расширенную информацию о событиях ввода с клавиатуры. Фиксировать запись ввода данных в буфере ввода. Читать запись вводимых данных без их удаления из буфера ввода. Выяснять число ждущих обработки событий в буфере ввода. Сбрасывать на диск данные буфера ввода. Читать и писать строки символами Unicode или ANSI в заданном месте экранного буфера. Читать и писать строчки текста и атрибуты цвета фона в заданном месте экранного буфера. Читать и писать прямоугольные блоки символов и данные цвета в заданном месте экранного буфера. Читать одиночные символы Unicode или ANSI, или комбинацию текста и атрибутов фона, которые определяют последовательность ячеек, начинающихся в заданном месте экранного буфера. Низкоуровневые консольные режимы работыСобытия ввода с клавиатуры записываются в буфере вводимых данных консоли в зависимости от режима ввода данных мышью и окном консоли. Режим обработки ввода данных консоли устанавливает, как система обрабатывает комбинацию клавиш CTRL+C. Чтобы установить или получить состояние режимов ввода данных консоли, приложение может определить дескриптор буфера вводимых данных консоли при вызове функции SetConsoleMode или GetConsoleMode. Ниже перечисленные режимы используются с дескрипторами консольного ввода данных.
РежимОписаниеENABLE_MOUSE_INPUTОпределяет, фиксировать ли события с мышью в буфере вводимых данных. По умолчанию, ввод информации от мыши включен, а ввод данных окна заблокирован. Изменение любого из этих режимов воздействует только на ввод данных, который происходит после того, как режим установлен; ждущие обработки события мыши или окна в буфере вводимых данных не сбрасываются. Курсор мыши показывается на экране независимо от режима работы мыши.ENABLE_WINDOW_INPUTОпределяет, фиксировать ли события изменения размера буфера в буфере вводимых данных. По умолчанию, ввод информации от мыши включен, а ввод данных окна заблокирован. Изменение любого из этих режимов воздействует только на ввод данных, который происходит после того, как режим установлен; ждущие обработки события мыши или окна в буфере вводимых данных не сбрасываются. Курсор мыши отображается на экране независимо от режима работы мыши.ENABLE_PROCESSED_INPUTУправляет обработкой ввода данных для прикладных программ, используя высокоуровневые консольные функции I/O. Однако, если режим обработки ввода данных включен, комбинация клавиш CTRL+C не фиксируется в буфере вводимых данных консоли. Вместо этого, комбинация пересылается соответствующей функции, управляющей обработчиком. Для получения дополнительной информации об управлении обработчиками см. статью Консольное управление обработчиками.Низкоуровневые консольные функции ввода данныхБуфер вводимых данных консоли содержит записи вводимых данных, которые могут включать в себя информацию о событиях клавиатуры, мыши, изменения размера буфера, фокуса и меню. Низкоуровневые функции обеспечивают прямой доступ к буферу вводимых данных, в отличие от высокоуровневых функций, которые фильтруют и обрабатывают информацию буфера вводимых данных, сбрасывая все, кроме ввода информации с клавиатуры. Имеется пять низкоуровневых функций для доступа к буферу вводимых данных консоли: ReadConsoleInput PeekConsoleInput GetNumberOfConsoleInputEvents WriteConsoleInput FlushConsoleInputBuffer Функции ReadConsoleInput, PeekConsoleInput и WriteConsoleInput используют структуру INPUT_RECORD, чтобы читать из или записывать в буфер вводимых данных. Ниже описания низкоуровневых консольных функций ввода. ФункцияОписаниеReadConsoleInputЧитает и удаляет записи вводимых данных из буфера ввода. Функция не возвращает значение до тех пор, пока, по меньшей мере, не будет доступна хотя бы одна запись для чтения. Далее все доступные записи передаются в буфер вызывающего процесса до тех пор, пока или не окажется больше записей, которые доступны, или заданное число записей было прочитано. Непрочитанные записи остаются в буфере ввода для следующей операции чтения. Функция сообщает об общем количестве записей, которые были прочитаны. Пример, который использует функцию ReadConsoleInput, смотри в статье Чтение событий буфера вводимых данных.PeekConsoleInputЧитает без удаления ждущих обработки записей вводимых данных в буфере ввода. Все доступные записи до заданного числа копируются в буфер вызывающего процесса. Если доступных записей нет, функция немедленно возвращает значение. Функция сообщает об общем количестве записей, которые были прочитаны.GetNumberOfConsoleInputEventsВыясняет число непрочитанных записей вводимых данных в буфере ввода.WriteConsoleInputПомещает записи вводимых данных в буфер ввода позади любых ждущих обработки записей в буфере. В случае необходимости, буфер ввода растет динамически, чтобы вместить столько записей, сколько записывается. Чтобы использовать эту функцию, определяемый дескриптор буфера ввода должен иметь право доступа GENERIC_READ.FlushConsoleInputBufferСбрасывает все непрочитанные события в буфере ввода. Чтобы использовать эту функцию, определяемый дескриптор буфера ввода должен иметь право доступа GENERIC_READ.Поток процесса прикладной программы может выполнить операцию "занять", чтобы ждать ввод данных, который будет доступным в буфере ввода. Чтобы инициализировать операцию "занять", определите дескриптор буфера ввода при вызове любой из функций ожидания. Эти функции могут возвратить значение тогда, когда сообщается о состоянии одного или нескольких объектов. Состояние дескриптора консольного ввода становится сигнальным тогда, когда имеются непрочитанные записи в его буфере ввода. Состояние дескриптора сбрасывается в несигнальное тогда, когда буфер ввода становится пустым. Если не имеется доступного ввода данных, вызывающий поток входит в рациональное состояние ожидания, расходуя очень небольшое процессорное время при ожидании условия удовлетворяющего операцию "занять". Низкоуровневые консольные функции вывода данныхНизкоуровневые консольные функции вывода данных обеспечивают прямой доступ к символьным знакоместам экранного буфера. Один набор функций читает из или записывает в последовательные ячейки, начинающиеся в любом месте в экранном буфере консоли. Другой набор функций читает из или записывает в прямоугольные блоки ячеек. Нижеследующие функции чтения из или записи в заданное число последовательных символьных знакомест в экранном буфере, начинающихся с определенной ячейки. ФункцияОписаниеReadConsoleOutputCharacterКопирует строку символов Unicode или ANSI из экранного буфера.WriteConsoleOutputCharacterЗаписывает строку символов Unicode или ANSI в экранный буфер.ReadConsoleOutputAttributeКопирует строку текста и атрибуты цвета фона из экранного буфера дисплея.WriteConsoleOutputAttributeЗаписывает строку текста и атрибуты цвет фона в экранном буфере дисплея.FillConsoleOutputCharacterЗаписывает одиночный символ Unicode или ANSI в заданном числе последовательных ячеек в экранном буфере.FillConsoleOutputAttributeЗаписывает текст и комбинацию атрибутов цвета фона в заданном числе последовательных ячеек в экранном буфере.Для всех этих функций, когда подходит последняя ячейка строки, операции чтения или записи автоматически переходят на новую строку обратно в первую ячейку следующей строки. Когда подходит конец последней строки экранного буфера консоли, функции записи сбрасывают все не записанные символы или атрибуты, а функции чтения сообщают о числе символов или атрибутах, действительно записанных. Нижеследующие функции читают из или записывают в прямоугольные блоки символьных знакомест, в заданном месте экранного буфера. ФункцияОписаниеReadConsoleOutputКопирует символ и данные о цвете от заданного блока ячеек экранного буфера в данный блок в буфере назначения.WriteConsoleOutputЗаписывает символ и данные о цвете в заданном блоке ячеек экранного буфера из данного блока в исходном буфере.Эти функции рассматривают экранные буферы и буфер источника или буферы назначения, как двухмерные массивы структур CHAR_INFO (содержащих символы и данные атрибутов цвета для каждой ячейки). Функции устанавливают ширину и высоту, в символьных знакоместах, буфера источника или буфера назначения, а указатель на буфер рассматривается как указатель на начальную ячейку с координатами (0,0) двухмерного массива. Функции используют структуру SMALL_RECT, которая определяет, какой прямоугольник доступен в экранном буфере консоли, и обуславливает координаты левой верхней ячейки в буфере источнике или буфере назначения в месте соответствующего прямоугольника в этом буфере. Эти функции автоматически ограничивают определяемый прямоугольник экранного буфера, чтобы вместить его в пределах границ экранного буфера консоли. Например, если прямоугольник устанавливает нижние правые координаты, которые являются (столбец 100, строка 50), а экранный буфер консоли устанавливается шириной только 80 столбцов, координаты отсекаются так, чтобы они были (столбец 79, строка 50). Точно так же этот откорректированный прямоугольник снова отсекается, чтобы вместиться в пределах границ буфера назначения или источника. Координаты экранного буфера фактического прямоугольника, в котором происходит чтение из или запись в является установленным. Пример, который использует эти функции, посмотрите в статье Чтение и запись блоков символов и атрибутов. Иллюстрация показывает операцию ReadConsoleOutput, где происходит отсечение по границам, когда блок читается из экранного буфера консоли, и снова, когда блок копируется в буфер назначения. Функция сообщает о фактическом прямоугольнике экранного буфера, который она скопировала. Кодовые страницы консолиКодовая страница (code page) является отображением 256 символьных кодов для каждого отдельного символа. Разные кодовые страницы включают в себя разные специальные символы, обычно настраиваемые для языка или группы языков. Каждая консоль связана с двумя кодовыми страницами: одна для ввода данных и один для вывода информации. Консоль использует свою кодовую страницу ввода, чтобы преобразовать ввод информации с клавиатуры в соответствующее символьное значение. Свою кодовую страницу вывода данных она использует, чтобы преобразовать символьные значения, записанные различными функциями вывода в изображение, отображаемое в консольном окне. Приложение может использовать функции SetConsoleCP и GetConsoleCP, чтобы устанавливать и получать кодовые страницы ввода консоли, а функции SetConsoleOutputCP и GetConsoleOutputCP, чтобы устанавливать и получать свои кодовые страницы вывода данных. Идентификаторы кодовых страниц, доступных на локальном компьютере сохраняются в системном реестре под нижеследующим ключом. Код (Text): HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage Консольное управление обработчикамиКаждый консольный процесс имеет свой собственный перечень функций управления обработчиками, которые вызываются системой, когда процесс получает сигнал CTRL+C, CTRL+BREAK или CTRL+CLOSE. Вначале, перечень управления обработчиками для каждого процесса содержит только заданную по умолчанию функцию обработчика, которая вызывает функцию ExitProcess. Консольный процесс может добавлять или удалять дополнительные функции HandlerRoutine путем вызова функции SetConsoleCtrlHandler. Эта функция не находится под влиянием перечней управления обработчиками для других процессов. Когда консольный процесс получает какой-либо из управляющих сигналов он вызывает функции обработчика. Основа для вызова ― последняя из зарегистрированных и первая из вызываемых функций, до тех пор, пока один из обработчиков не возвратит значение 1 (TRUE). Если ни один из обработчиков не возвращает значение 1 (TRUE), вызывается заданный по умолчанию обработчик. Нижеследующее объявление typedef иллюстрирует формат управляющей функции обработчика. Код (C): typedef BOOL (*PHANDLER_ROUTINE)(DWORD dwCtrlType); Параметр dwCtrlType функции идентифицирует, какой управляющий сигнал был принят, а величина возвращаемого значения указывает, был ли сигнал обработан. Пример функции управления обработчиком, см. в статье Регистрация функции управления обработчиком. Сигналы CTRL+C и CTRL+BREAK Сигнал CTRL+CLOSE Группы консольных процессов Защита буфера и права доступа в консоли оригинал на английскомМодель системы безопасности Windows NT дает Вам возможность управлять доступом к консольным буферам ввода и экранным буферам консоли. Для получения дополнительной информации о системе безопасности, смотри раздел Модель контроля доступа. Вы можете определить дескриптор защиты для консольного ввода данных и экранных буферов консоли, когда Вы вызываете функцию CreateFile или CreateConsoleScreenBuffer. Если Вы определяете значение NULL, объект получает заданный по умолчанию дескриптор защиты. ACL, в заданном по умолчанию дескрипторе защиты для консольного буфера, исходят из первичного права или маркера заимствования прав создателя. Обработанные возвращенные значения функций CreateFile, CreateConsoleScreenBuffer и GetStdHandle имеют права доступа GENERIC_READ и GENERIC_WRITE. Правильные права доступа включают в себя GENERIC_READ и GENERIC_WRITE универсальные права доступа. ЗначениеПредназначениеGENERIC_READЗапрашивает доступ для чтения в экранном буфере консоли, включая процесс, который читает данные из буфера.GENERIC_WRITEЗапрашивает доступ для записи в экранный буфер консоли, включая процесс, который записывает данные в буферИспользование консоли Использование высокоуровневых функций ввода и вывода данныхНижеследующий пример использует высокоуровневые консольные функции I/O для консольного ввода-вывода. Для получения дополнительной информации о высокоуровневых консольных функциях I/O, см. статью Высокоуровневый консольный ввод-вывод. В примере предполагается, что заданные по умолчанию режимы ввода-вывода (I/O) являются по существу вначале для первого вызова функций ReadFile и WriteFile. Затем для второго вызова ReadFile и WriteFile режим ввода данных изменяется, выключается режим построчного ввода данных и отраженный режим ввода данных. Функция SetConsoleTextAttribute используется для, установки цвета, которым впоследствии письменный текст будет показан на экране. Перед выходом, программа восстанавливает исходный консольный режим ввода данных и атрибуты цвета. Функция NewLine примера используется тогда, когда отключается режим построчного ввода данных. Она обрабатывает возвраты каретки, перемещая позицию курсора в первую ячейку следующей строки. Если курсор находится уже в последней строке экранного буфера консоли, содержание экранного буфера консоли прокручивается вверх на одну строку. Обратите внимание на то, что MyErrorExit ― групповой символ ― заместитель для определяемой программой функции, которая показывает на экране и обрабатывает аварийные ситуации. Код (C): #include <windows.h> void NewLine(void); void ScrollScreenBuffer(HANDLE, INT); HANDLE hStdout, hStdin; CONSOLE_SCREEN_BUFFER_INFO csbiInfo; void main(void) { LPSTR lpszPrompt1 = "Type a line and press Enter, or q to quit: "; LPSTR lpszPrompt2 = "Type any key, or q to quit: "; CHAR chBuffer[256]; DWORD cRead, cWritten, fdwMode, fdwOldMode; WORD wOldColorAttrs; // Получим дескрипторы для STDIN и STDOUT hStdin = GetStdHandle(STD_INPUT_HANDLE); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE) { MessageBox(NULL, "GetStdHandle", "Console Error", MB_OK); return; } // Сохраним текущий цвет текста if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) { MessageBox(NULL, "GetConsoleScreenBufferInfo", "Console Error", MB_OK); return; } wOldColorAttrs = csbiInfo.wAttributes; // Установим атрибуты текста которые пишут красный текст по черному фону. if (! SetConsoleTextAttribute(hStdout, FOREGROUND_RED|FOREGROUND_INTENSITY)) { MessageBox(NULL, "SetConsoleTextAttribute", "Console Error", MB_OK); return; } // Запишем в STDOUT и прочитаем из STDIN, используя режим по умолчанию. // При вводе данных эхо-режим осуществляется автоматически, а функция ReadFile // не возвращает значения до тех пор, пока не напечатается каретка возврата. // // Режим ввода по умолчанию -- построчный, обрабатываемый и эхо-режим. // Режим вывода по умолчанию -- обрабатываемый и с автопереносом в конце строки EOL. while (1) { if (! WriteFile( hStdout, // дескриптор вывода lpszPrompt1, // строка приглашения к вводу lstrlen(lpszPrompt1), // длина строки &cWritten, // записано байтов NULL) ) // не перекрывающееся { MessageBox(NULL, "WriteFile", "Console Error", MB_OK); return; } if (! ReadFile( hStdin, // дескриптор ввода chBuffer, // буфер для передачи 255, // размер буфера &cRead, // действительно прочитанные байты NULL) ) // не перекрывающееся break; if (chBuffer[0] == 'q') break; } // Выключим построчный режим ввода и эхо-режим if (! GetConsoleMode(hStdin, &fdwOldMode)) { MessageBox(NULL, "GetConsoleMode", "Console Error", MB_OK); return; } fdwMode = fdwOldMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); if (! SetConsoleMode(hStdin, fdwMode)) { MessageBox(NULL, "SetConsoleMode", "Console Error", MB_OK); return; } // Без эхо-режима и построчного ввода, ReadFile возвращает значение, // когда доступен какой либо ввод данных. Возврат каретки должен // обрабатываться, а WriteFile используется в эхо-режиме для ввода данных NewLine(); while (1) { if (! WriteFile( hStdout, // дескриптор вывода lpszPrompt2, // строка приглашения к вводу lstrlen(lpszPrompt2), // длина строки &cWritten, // записано байтов NULL) ) // не перекрывающееся { MessageBox(NULL, "WriteFile", "Console Error", MB_OK); return; } if (! ReadFile(hStdin, chBuffer, 1, &cRead, NULL)) break; if (chBuffer[0] == '\r') NewLine(); else if (! WriteFile(hStdout, chBuffer, cRead, &cWritten, NULL)) break; else NewLine(); if (chBuffer[0] == 'q') break; } // Восстанавливаем исходный режим консоли SetConsoleMode(hStdin, fdwOldMode); // Восстанавливаем исходный режим текста SetConsoleTextAttribute(hStdout, wOldColorAttrs); } // Функция NewLine обрабатывает возврат каретки тогда, когда режим обработки // вводимых данных отключается. Она получает текущую позицию курсора // и сбрасывает ее до позиции первой ячейки следующей строки void NewLine(void) { if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) { MessageBox(NULL, "GetConsoleScreenBufferInfo", "Console Error", MB_OK); return; } csbiInfo.dwCursorPosition.X = 0; // Если это последняя строка в буфере экрана, прокручивает буфер вверх if ((csbiInfo.dwSize.Y-1) == csbiInfo.dwCursorPosition.Y) { ScrollScreenBuffer(hStdout, 1); } // Иначе, продвигает вперед курсор к следующей строке else csbiInfo.dwCursorPosition.Y += 1; if (! SetConsoleCursorPosition(hStdout, csbiInfo.dwCursorPosition)) { MessageBox(NULL, "SetConsoleCursorPosition", "Console Error", MB_OK); return; } } void ScrollScreenBuffer(HANDLE h, INT x) { SMALL_RECT srctScrollRect, srctClipRect; CHAR_INFO chiFill; COORD coordDest; srctScrollRect.Left = 0; srctScrollRect.Top = 1; srctScrollRect.Right = csbiInfo.dwSize.X - x; srctScrollRect.Bottom = csbiInfo.dwSize.Y - x; // Назначение для прямоугольника прокрутки - одна строка вверх coordDest.X = 0; coordDest.Y = 0; // Прямоугольник отсечения по границам тот же самый, что и прокручивающийся прямоугольник. // Строка назначения оставлена неизменной srctClipRect = srctScrollRect; // Установим символ - заполнитель и атрибуты chiFill.Attributes = FOREGROUND_RED|FOREGROUND_INTENSITY; chiFill.Char.AsciiChar = ' '; // Прокрутим вверх на одну строку ScrollConsoleScreenBuffer( h, // дескриптор экранного буфера &srctScrollRect, // прямоугольник прокрутки &srctClipRect, // прямоугольник отсечения coordDest, // верхняя левая ячейка назначения &chiFill); // символ-заполнитель и цвет } Запись символов или цветов в последовательные ячейкиСимволы или атрибуты цвета могут быть записаны в заданные символьные знакоместа в экранном буфере. Нижеследующий пример использует функцию WriteConsoleOutputCharacter, чтобы записать строку символов, начинающихся в верхнем левом угле экранного буфера. Далее пример использует функцию WriteConsoleOutputAttribute, чтобы записать строку атрибутов цвета для первых 51 ячейки той же самой строки. Параметр coord для обеих функций устанавливает символьное знакоместо в экранном буфере консоли, в котором начинается запись. Местоположение в консольном окне, где эти символы или цвета появляются, зависит от прямоугольника текущего окна экранного буфера консоли. За дополнительной информацией о соотношениях между экранным буфером и его окнами, обратитесь к статьям Окно и размер экранного буфера и Прокрутка экранного буфера. Обратите внимание на то,что MyErrorExit ― групповой символ ― заместитель для определяемой программой функции, которая показывает на экране и обрабатывает аварийные ситуации. Код (C): HANDLE hOutput; LPTSTR lpszString = "Character String"; DWORD cWritten; BOOL fSuccess; COORD coord; WORD wColors[3], wColor; CHAR chFillChar; // Запишем строку символов в буфер экрана coord.X = 0; // начало на первую ячейку coord.Y = 0; // первой строки fSuccess = WriteConsoleOutputCharacter( hOutput, // дескриптор экранного буфера lpszString, // указатель на строку ― источник lstrlen(lpszString), // длина строки coord, // первая ячейка для записи &cWritten); // действительное число записей if (! fSuccess) MyErrorExit("WriteConsoleOutputCharacter"); // Запишем строку цветов в экранный буфер wColors[0] = BACKGROUND_RED; wColors[1] = BACKGROUND_RED | // белый фон BACKGROUND_GREEN | BACKGROUND_BLUE; wColors[2] = BACKGROUND_BLUE; for (;fSuccess && coord.X < 50; coord.X += 3) { fSuccess = WriteConsoleOutputAttribute( hOutput, // дескриптор экранного буфера wColors, // указатель на строку ― источник 3, // длина строки coord, // первая ячейка для записи &cWritten); // действительное число записей } if (! fSuccess) MyErrorExit("WriteConsoleOutputAttribute"); Те же самые символы или атрибуты цвета можно записать в заданное число последовательных ячеек экранного буфера, начинающихся в заданном местоположении. Нижеследующий пример использует функцию FillConsoleOutputCharacter, чтобы очистить область экранного буфера 80 на 50 символов, а затем он использует функцию FillConsoleOutputAttribute, чтобы установить атрибуты цвета в тех же самых ячейках. Код (C): // Заполним область экранного буфера 80-на-50 символов пробелами coord.X = 0; // начнем с первой ячейки coord.Y = 0; // первой строки chFillChar = ' '; fSuccess = FillConsoleOutputCharacter( hStdout, // дескриптор экранного буфера chFillChar, // заполнение пробелами 80*50, // число ячеек для заполнения coord, // первая ячейка для записи &cWritten); // фактическое число записей if (! fSuccess) MyErrorExit("FillConsoleOutputCharacter"); // Установим в области экранного буфера 80-на-50 символов цвета для белого текста на красном wColor = BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; fSuccess = FillConsoleOutputAttribute( hStdout, // дескриптор экранного буфера wColor, // цвет для заполнения 80*50, // число заполняемых ячеек coord, // первая ячейка для записи &cWritten); // фактическое число записей if (! fSuccess) MyErrorExit("FillConsoleOutputAttribute"); Чтение и запись блоков символов и атрибутов оригинал на английскомФункция ReadConsoleOutput копирует прямоугольный блок символьных и цветных атрибутов данных из экранного буфера консоли в буфер назначения. Функция рассматривает буфер назначения как двухмерный массив структур CHAR_INFO. Точно так же функция WriteConsoleOutput копирует прямоугольный блок символьных и цветных атрибутов данных из исходного буфера в экранный буфер консоли. Для получения дополнительной информации о чтении или записи в прямоугольных блоках ячеек экранного буфера, смотри раздел Методы ввода и вывода данных. Нижеследующий пример использует функцию CreateConsoleScreenBuffer, чтобы создать новый экранный буфер. После того, как функция SetConsoleActiveScreenBuffer сделает этот экранный буфер активным, во временный буфер скопируется блок символов и атрибутов цвета верхних двух строк SDTOUT экранного буфера. Данные далее копируются из временного буфера в новый активный экранный буфер. Когда приложение завершает работу, используя новый экранный буфер, оно вызывает SetConsoleActiveScreenBuffer, чтобы восстановить исходный STDOUT экранный буфер. Код (C): #include <windows.h> VOID main(void) { HANDLE hStdout, hNewScreenBuffer; SMALL_RECT srctReadRect; SMALL_RECT srctWriteRect; CHAR_INFO chiBuffer[160]; // [2][80]; COORD coordBufSize; COORD coordBufCoord; BOOL fSuccess; // Получим дескриптор STDOUT экранного буфера из которого будем копировать и создадим // новый экранный буфер, в который будем копировать. hStdout = GetStdHandle(STD_OUTPUT_HANDLE); hNewScreenBuffer = CreateConsoleScreenBuffer( GENERIC_READ | // доступ к чтению/записи GENERIC_WRITE, 0, // совместно не используется NULL, // атрибутов защиты нет CONSOLE_TEXTMODE_BUFFER, // должен быть TEXTMODE NULL); // зарезервирован, должен быть NULL if (hStdout == INVALID_HANDLE_VALUE || hNewScreenBuffer == INVALID_HANDLE_VALUE) { MyErrorExit("CreateConsoleScreenBuffer"); } // Сделаем новый экранный буфер активным экранным буфером. if (! SetConsoleActiveScreenBuffer(hNewScreenBuffer) ) MyErrorExit("SetConsoleActiveScreenBuffer"); // Установим прямоугольник источника. srctReadRect.Top = 0; // верхний левый: строчка 0, колонка 0 srctReadRect.Left = 0; srctReadRect.Bottom = 1; // нижний правый: строчка 1, колонка 79 srctReadRect.Right = 79; // Размер временного буфера равен 2 строчки x 80 колонок. coordBufSize.Y = 2; coordBufSize.X = 80; // Верхняя левая ячейка назначения временного буфера равна строка 0, колонка 0. coordBufCoord.X = 0; coordBufCoord.Y = 0; // Скопируем блок из экранного буфера во временный буфер. fSuccess = ReadConsoleOutput( hStdout, // экранный буфер, из которого читаем chiBuffer, // буфер, в который копируем coordBufSize, // размер колонки/строки chiBuffer coordBufCoord, // верхняя левая ячейка назначения в chiBuffer &srctReadRect); // экранного буфер прямоугольника, из которого читаем if (! fSuccess) MyErrorExit("ReadConsoleOutput"); // Установим прямоугольник назначения. srctWriteRect.Top = 10; // верхний левый: строка 10, колонка 0 srctWriteRect.Left = 0; srctWriteRect.Bottom = 11; // нижний правый: строка 11, колонка 79 srctWriteRect.Right = 79; // Копируем из временного буфера в новый экранный буфер. fSuccess = WriteConsoleOutput( hNewScreenBuffer, // экранный буфер, в который будем записывать chiBuffer, // буфер, из которого копируем coordBufSize, // размер колонки/строки chiBuffer coordBufCoord, // верхняя левая ячейка источника в chiBuffer &srctWriteRect); // прямоугольник назначения экранного буфера if (! fSuccess) MyErrorExit("WriteConsoleOutput"); Sleep(10000); // Восстановление исходного активного экранного буфера. if (! SetConsoleActiveScreenBuffer(hStdout)) MyErrorExit("SetConsoleActiveScreenBuffer"); }
Чтение событий буфера вводимых данных оригинал на английскомФункция ReadConsoleInput может быть использована для непосредственного обращения к буферу ввода консоли. Когда консоль создается, включается ввод информации от мыши, а ввод данных окна отключается. Чтобы гарантировать, что процесс получает все события ввода, этот пример использует функцию SetConsoleMode, чтобы включить ввод информации от окна и мыши. Затем он входит в цикл, который читает и обрабатывает консольные события ввода. Код (C): VOID MouseEventProc(MOUSE_EVENT_RECORD); VOID ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD); VOID KeyEventProc(KEY_EVENT_RECORD); VOID GetInputEvents(VOID); DWORD main(VOID) { HANDLE hStdin; DWORD cNumRead, fdwMode, fdwSaveOldMode, i; INPUT_RECORD irInBuf[128]; // Получим стандартный дескриптор ввода. hStdin = GetStdHandle(STD_INPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE) MyErrorExit("GetStdHandle"); // Сохраним текущий режим ввода для будущего восстановления при // выходе из программы. if (! GetConsoleMode(hStdin, &fdwSaveOldMode) ) MyErrorExit("GetConsoleMode"); // Включим события ввода от мыши и окна. fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT; if (! SetConsoleMode(hStdin, fdwMode) ) MyErrorExit("SetConsoleMode"); // Цикл чтения и обработки событий ввода. while (1) { // Ожидание событий. if (! ReadConsoleInput( hStdin, // дескриптор буфера ввода irInBuf, // буфер, в котором читаем 128, // размер буфера чтения &cNumRead) ) // число прочитанных записей MyErrorExit("ReadConsoleInput"); // Направляем события соответствующим обработчикам. for (i = 0; i < cNumRead; i++) { switch(irInBuf[i].EventType) { case KEY_EVENT: // ввод с клавиатуры KeyEventProc(irInBuf[i].Event.KeyEvent); break; case MOUSE_EVENT: // ввод от мыши MouseEventProc(irInBuf[i].Event.MouseEvent); break; case WINDOW_BUFFER_SIZE_EVENT: // изменение размера // экранного буфера ResizeEventProc( irInBuf[i].Event.WindowBufferSizeEvent); break; case FOCUS_EVENT: // игнорирование событий фокуса case MENU_EVENT: // игнорирование событий меню break; default: MyErrorExit("unknown event type"); break; } } } return 0; } Очистка экрана оригинал на английскомИмеется два способа очистки экрана в консольной программе. Первый способ состоит в том, чтобы использовать системную функцию языка C во время выполнения как ниже указано: Код (C): #include <stdlib.h> void main() { system("cls"); } Системная функция вызывает команду cls, предусмотренную интерпретатором команд, чтобы очистить экран. Второй ― состоит в том, чтобы записать, что функция программно очищает экран, используя функции FillConsoleOutputCharacter и FillConsoleOutputAttribute . Ниже код, который демонстрирует эту методику. Код (C): void cls( HANDLE hConsole ) { COORD coordScreen = { 0, 0 }; // исходная позиция для курсора DWORD cCharsWritten; CONSOLE_SCREEN_BUFFER_INFO csbi; DWORD dwConSize; // Получим число символьных ячеек в текущем буфере. if( !GetConsoleScreenBufferInfo( hConsole, &csbi )) return; dwConSize = csbi.dwSize.X * csbi.dwSize.Y; // Заполним полностью экран пробелами. if( !FillConsoleOutputCharacter( hConsole, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten )) return;