Шаг 29.
Таймер в консольном приложении

    На этом шаге мы рассмотрим применение таймера в консольном приложении.

    Надо сказать, что мы несколько опережаем события и рассматриваем таймер в консольном приложении раньше, чем в приложении GUI.

    Основным способом создания таймера является использование функции SetTimer. Таймер может быть установлен в двух режимах. Первый режим - это когда последний параметр равен нулю. В этом случае на текущее окно (его функцию) через равные промежутки времени, определяемые третьим параметром, будет приходить сообщение WM_TIMER. Во втором режиме последний параметр указывает на функцию, которая будет вызываться опять через равные промежутки времени. Однако для консольного приложения эта функция не подходит, так как сообщение WM_TIMER пересылается окну функцией DispatchMessage, которая используется в цикле обработки сообщений. Но использование этой функции для консольных приложений проблематично.

    Для консольных приложений следует использовать функцию timeSetEvent. Вот параметры этой функции:

  1. 1-й параметр - время задержки таймера, для нас это время совпадает со временем между двумя вызовами таймера;
  2. 2-й параметр - точность работы таймера (приоритет посылки сообщения);
  3. 3-й параметр - адрес вызываемой процедуры;
  4. 4-й параметр - параметр, посылаемый в процедуру;
  5. 5-й параметр - тип вызова: одиночный или периодический.

    Если функция завершилась удачно, то в ЕАХ возвращается идентификатор таймера.

    Сама вызываемая процедура получает также 5 параметров:

  1. 1-й параметр - идентификатор таймера;
  2. 2-й параметр - не используется;
  3. 3-й параметр - параметр Dat;
  4. 4-й и 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. Результат работы приложения

    На следующем шаге мы приведем пример работы с параметрами командной строки.




Предыдущий шаг Содержание Следующий шаг