Win API
Работа с мультимедийным таймером на Win API

:: Меню ::
:: На главную ::
:: FAQ ::
:: Заметки ::
:: Практика ::
:: Win API ::
:: Проекты ::
:: Скачать ::
:: Секреты ::
:: Ссылки ::

:: Сервис ::
:: Написать ::

:: MVP ::

:: RSS ::

Яндекс.Метрика


Мы уже знакомы с системным таймером, сегодня познакомимся с мультимедийным, основное отличие которого, более высокая скорость (точность) работы. Мультимедийный таймер способен работать с интервалом вплоть до 1 ms, в то время как, интервалы работы системного таймера больше, и зависят от версии ОС. Для Windows95/98 интервал составляет ~50 ms, в Windows2000/XP интервал может быть меньше (у меня он равен ~10 ms).

Сейчас мы убедимся в этом на примере, для чего создадим два таймера: системный и мультимедийный. Оба таймера будут показывать, сколько раз в секунду им удалось сработать.

const
  IDTimer1 = 1;
  IDLabelTimer = 2;
  IDLabelMMTimer = 3;

var
  Wc: TWndClassEx;
  Wnd: HWND;
  Msg: TMsg;
  LabelTimer: HWND;
  LabelMMTimer: HWND;

  TimerBegin: Cardinal;
  TimerCount: Cardinal = 0;
  TimerOld: Cardinal = 0;
  MMTimerID: Cardinal;
  MMTimerBegin: Cardinal;
  MMTimerCount: Cardinal = 0;
  MMTimerOld: Cardinal = 0;

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

(* CallBack функция для системного таймера *)
procedure TimerProc( Wnd: HWND; uMsg: UINT; idEvent: UINT; dwTimer: UINT ); stdcall;

(* CallBack функция для мультимедийного таймера *)
procedure MMTimerProc( uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD ); stdcall;

Обратим внимание на то, что функция использует соглашение о передаче параметров stdcall.

Определим эти функции.

procedure TimerProc( Wnd: HWND; uMsg: UINT; idEvent: UINT; dwTimer: UINT ); stdcall;
var
 tmpTimer: string;
 tmpTimerCount: string;
begin
   Inc( TimerCount );
   Str( TimerOld, tmpTimer );
   Str( TimerCount, tmpTimerCount );
   SetWindowText( LabelTimer, PChar( 'Timer: ' + tmpTimerCount + '   [' + tmpTimer + ']' ) );
   if GetTickCount - TimerBegin >= 1000 then
   begin
      TimerOld := TimerCount;
      TimerBegin := GetTickCount;
      TimerCount := 0;
   end;
end;

procedure MMTimerProc( uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD ); stdcall;
var
 tmpMMTimer: string;
 tmpMMTimerCount: string;
begin
   Inc( MMTimerCount );
   Str( MMTimerOld, tmpMMTimer );
   Str( MMTimerCount, tmpMMTimerCount );
   SetWindowText( LabelMMTimer, PChar( 'MMTimer: ' + tmpMMTimerCount + '   [' + tmpMMTimer + ']' ) );
   if GetTickCount - MMTimerBegin >= 1000 then
   begin
      MMTimerOld := MMTimerCount;
      MMTimerBegin := GetTickCount;
      MMTimerCount := 0;
   end;
end;

Как видим, все просто. Каждый тик таймера мы увеличиваем на единицу переменную, которая показывает, сколько уже раз сработал таймер. Каждую секунду обнуляем счетчик, предварительно сохранив его значение (это значение мы будем показывать всю следующую секунду).

Перейдем к созданию таймеров.

SetTimer( Wnd, IDTimer1, 1, @TimerProc );
TimerBegin := GetTickCount;

MMTimerID := timeSetEvent( 1, 2, @MMTimerProc, 0, TIME_PERIODIC );
MMTimerBegin := TimerBegin;

С созданием системного таймера мы уже знакомы. Единственное отличие от предыдущего примера заключается в том, что в качестве последнего параметра мы вместо nil передаем указатель на CallBack функцию. Сразу после его создания запоминаем текущее время, от него начнем отсчет интервалов, длинной в секунду. Затем создаем мультимедийный таймер, для чего воспользуемся функцией timeSetEvent. Рассмотрим ее параметры. 1 - интервал таймера (в миллисекундах). 2 - разрешающая способность (количество миллисекунд, ограничивающее время на отработку каждого тика таймера). Если задать 0, точность будет максимальной. 3 - адрес CallBack функции. 4 - Параметр пользователя. Этот параметр передается в обработчик lpFunction и может использоваться по усмотрению программиста. 5 - одна из двух констант: TIME_ONESHOT (обработчик таймера вызывается один раз) или TIME_PERIODIC (обработчик таймера вызывается периодически).

Уничтожение таймеров выглядит следующим образом.

KillTimer( Wnd, IDTimer1 );
timeKillEvent( MMTimerID );

Пара слов о работе этих таймеров. Системный таймер: Если обработчик таймера не успевает закончить все действия в установленный интервал, то последующие вызовы этого обработчика становятся в очередь. Это приводит к тому, что на разных компьютерах приложение работает с разной скоростью. Сама же CallBack функция вызывается в контексте основного потока. Мультимедийный таймер: Если обработчик таймера не успевает закончить все действия в установленный интервал, то последующие вызовы накапливаться не будут. Сама же CallBack функция вызывается в контексте отдельного потока.

На сегодня это все, удачи в программировании.

.: Пример к данной статье :.


При использовании материала - ссылка на сайт обязательна