На этом шаге мы рассмотрим применение таймера в консольном приложении.
Надо сказать, что мы несколько опережаем события и рассматриваем таймер в консольном приложении раньше, чем в приложении GUI.
Основным способом создания таймера является использование функции SetTimer. Таймер может быть установлен в двух режимах. Первый режим - это когда последний параметр равен нулю. В этом случае на текущее окно (его функцию) через равные промежутки времени, определяемые третьим параметром, будет приходить сообщение WM_TIMER. Во втором режиме последний параметр указывает на функцию, которая будет вызываться опять через равные промежутки времени. Однако для консольного приложения эта функция не подходит, так как сообщение WM_TIMER пересылается окну функцией DispatchMessage, которая используется в цикле обработки сообщений. Но использование этой функции для консольных приложений проблематично.
Для консольных приложений следует использовать функцию timeSetEvent. Вот параметры этой функции:
Если функция завершилась удачно, то в ЕАХ возвращается идентификатор таймера.
Сама вызываемая процедура получает также 5 параметров:
Для удаления таймера используется функция timeKillEvent, параметром которой является идентификатор таймера.
.386P ;Плоская модель памяти. .MODEL FLAT, STDCALL ;Константы. STD_OUTPUT_HANDLE equ -11 STD_INPUT_HANDLE equ -10 TIME_PERIODIC equ 1 ;Тип вызова таймера. ;Тип события. KEY_EV equ 1h MOUSE_EV equ 2h ; атрибуты цветов FOREGROUND_BLUE equ 1h ;Синий цвет букв. FOREGROUND_GREEN equ 2h ;Зеленый цвет букв. FOREGROUND_RED equ 4h ;Красный цвет букв. FOREGROUND_INTENSITY equ 8h ;Повышенная интенсивность. BACKGROUND_BLUE equ 10h ;Синий цвет фона. BACKGROUND_GREEN equ 20h ;Зеленый цвет фона. BACKGROUND_RED equ 40h ;Красный цвет фона. BACKGROUND_INTENSITY equ 80h ;Повышенная интенсивность. COL1 = 2h+8h ;Цвет выводимого текста. ;Прототипы внешних процедур EXTERN wsprintfA:NEAR EXTERN GetStdHandle@4:NEAR EXTERN WriteConsoleA@20:NEAR EXTERN SetConsoleCursorPosition@8:NEAR EXTERN SetConsoleTitleA@4:NEAR EXTERN FreeConsole@0:NEAR EXTERN AllocConsole@0:NEAR EXTERN CharToOemA@8:NEAR EXTERN SetConsoleTextAttribute@8:NEAR EXTERN ReadConsoleA@20:NEAR EXTERN timeSetEvent@20:NEAR EXTERN timeKillEvent@4:NEAR EXTERN ExitProcess@4:NEAR ;Директивы компоновщику для подключения библиотек. includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib includelib c:\masm32\lib\winmm.lib ;------------------------------------------------ COOR STRUC X WORD ? Y WORD ? COOR ENDS ;Сегмент данных. _DATA SEGMENT DWORD PUBLIC USE32 'DATA' HANDL DWORD ? HANDL1 DWORD ? STR2 DB "Пример таймера в консольном приложении",0 STR3 DB 100 dup(0) FORM DB "Число вызовов таймера: %lu",0 BUF DB 200 dup(?) NUM DWORD 0 LENS DWORD ? ;Количество выведенных символов. CRD COOR <?> ID DWORD ? ;Идентификатор таймера. HWND DWORD ? _DATA ENDS ;Сегмент кода. _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ;Образовать консоль. ;Вначале освободить уже существующую. CALL FreeConsole@0 CALL AllocConsole@0 ;Получить HANDL1 ввода. PUSH STD_INPUT_HANDLE CALL GetStdHandle@4 MOV HANDL1,EAX ;Получить HANDL вывода. PUSH STD_OUTPUT_HANDLE CALL GetStdHandle@4 MOV HANDL,EAX ;Задать заголовок окна консоли. PUSH OFFSET STR2 PUSH OFFSET STR2 CALL CharToOemA@8 PUSH OFFSET STR2 CALL SetConsoleTitleA@4 ;Задать цветовые атрибуты выводимого текста. PUSH COL1 PUSH HANDL CALL SetConsoleTextAttribute@8 ;Установить таймер. PUSH TIME_PERIODIC ;Периодический вызов. PUSH 0 PUSH OFFSET TIME ;Вызываемая таймером процедура. PUSH 0 ;Точность вызова таймера. PUSH 1000 ;Вызов через одну секунду. CALL timeSetEvent@20 MOV ID,EAX ;Ждать ввод строки. PUSH 0 PUSH OFFSET LENS PUSH 200 PUSH OFFSET BUF PUSH HANDL1 CALL ReadConsoleA@20 ;Закрыть таймер. PUSH ID CALL timeKillEvent@4 ;Закрыть консоль. CALL FreeConsole@0 PUSH 0 CALL ExitProcess@4 ;Процедура определения длины строки. ;Строка - [EBP+08H]. ;Длина в ЕВХ LENSTR PROC ENTER 0,0 PUSH EAX ;---------------------- CLD MOV EDI,DWORD PTR [EBP+08H] MOV EBX,EDI MOV ECX,100 ;Ограничить длину строки. XOR AL,AL REPNE SCASB ;Найти символ 0. SUB EDI,EBX ;Длина строки, включая 0. MOV EBX,EDI DEC EBX ;---------------------- POP EAX LEAVE RET 4 LENSTR ENDP ;Процедура вызывается таймером. TIME PROC PUSHA ;Сохранить все регистры. ;Установить позицию курсора. MOV CRD.X,0 MOV CRD.Y,10 PUSH CRD PUSH HANDL CALL SetConsoleCursorPosition@8 ;Заполнить строку STR3. PUSH NUM PUSH OFFSET FORM PUSH OFFSET STR3 CALL wsprintfA ADD ESP,12 ;Восстановить стек. ;Перекодировать строку STR3. PUSH OFFSET STR3 PUSH OFFSET STR3 CALL CharToOemA@8 ;Вывести строку с номером вызова таймера. PUSH OFFSET STR3 CALL LENSTR PUSH 0 PUSH OFFSET LENS PUSH EBX PUSH OFFSET STR3 PUSH HANDL CALL WriteConsoleA@20 INC NUM POPA ;Восстановить все регистры. RET 20 ;Выход с освобождением стека. TIME ENDP _TEXT ENDS END START
Результат работы приложения изображен на рисунке 1:
Рис.1. Результат работы приложения
На следующем шаге мы приведем пример работы с параметрами командной строки.