Advertisement
HEX0x29A

WinAPI Timers unit

Aug 8th, 2013
460
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 8.71 KB | None | 0 0
  1. unit Timers;
  2. (*
  3.   Timer class, based on WinAPI SetTimer
  4.   Version: 1.1
  5.   Date:    08.08.2013
  6.   Author:  HEX0x29A
  7.  
  8.   History:
  9.   07.08.2013 - 1.0
  10.   *First version
  11.   08.08.2013 - 1.1
  12.   *Added KillTimer injection into lpTimerFunc instead of user callback
  13. *)
  14. interface
  15.  
  16. uses
  17.   Windows;
  18.  
  19. type
  20.   TTimer = class
  21.   private
  22.     ATimerInterval: UINT;
  23.     ATimerId      : UINT;
  24.     ATimerProc    : Pointer;
  25.     ATimerEvent   : Pointer;
  26.     function  TimerProcToMem(TimerProc: Pointer): Pointer;
  27.     function  GetTimerEnabled: BOOL;
  28.     procedure TimerFreeMem;
  29.     procedure SetTimerInterval(const Value: UINT);
  30.     procedure SetTimerEnabled(const Value: BOOL);
  31.     procedure SetTimerEvent(const Value: Pointer);
  32.   public
  33.     constructor Create(const Interval : UINT    = 1000;
  34.                        const TimerProc: Pointer = nil;
  35.                        const Enabled  : BOOL    = False);
  36.     destructor  Destroy; override;
  37.     property    Enabled: BOOL       read GetTimerEnabled write SetTimerEnabled;
  38.     property    Interval: UINT      read ATimerInterval  write SetTimerInterval;
  39.     property    TimerEvent: Pointer read ATimerEvent     write SetTimerEvent;
  40.   end;
  41.  
  42. implementation
  43.  
  44. type
  45.   //Структура - переходник с системного обработчика lpTimeFunc на пользовательский
  46.   TTimerProcAsm = packed record  //E8 FF FF FF FF 83 C4 10 C3
  47.     _call: BYTE;  //E8          | CALL
  48.     _addr: DWORD; //FF FF FF FF | TimerProc / (DestAddr(TimerProc)-CallAddr(ThisCallInMemory)-5(BinCallLengthInBytes))
  49.     _end : DWORD; //83 C4 10 C3 | ADD ESP, 10 / RET (Pop 4x4 bytes from stack and return)
  50.   end;
  51.  
  52. { TTimer }
  53.  
  54. //Создание объекта с возможностью быстрого старта таймера
  55. //Interval - Интервал срабатывания таймера
  56. //TimerProc - Функция-обработчик пользователя
  57. //Enabled - Активация/Деактивация таймера
  58. constructor TTimer.Create(const Interval : UINT    = 1000;
  59.                           const TimerProc: Pointer = nil;
  60.                           const Enabled  : BOOL    = False);
  61. begin  
  62.   ATimerProc := nil;           //Очищаем адрес обработчика
  63.   ATimerId   := 0;             //Обнуляем Id таймера
  64.   if Interval > 0 then         //Если интервал положительный
  65.     ATimerInterval := Interval //Сохраняем его
  66.   else                         //иначе
  67.     ATimerInterval := 0;       //выставляем 0
  68.   SetTimerInterval(Interval);  //Устанавливаем интервал
  69.   SetTimerEvent(TimerProc);    //Устанавливаем пользовательский обработчик
  70.   SetTimerEnabled(Enabled);    //Активируем таймер
  71. end;
  72.  
  73. //Деструктор
  74. destructor TTimer.Destroy;
  75. begin
  76.   TimerFreeMem; //убиваем таймер, если включен, и чистим память
  77.   inherited;
  78. end;
  79.  
  80. //Возвращает состаяние таймера
  81. function TTimer.GetTimerEnabled: BOOL;
  82. begin
  83.   //Если ATimerId не ноль, значит таймер работает
  84.   Result := (ATimerId <> 0);
  85. end;
  86.  
  87. //Активация/Деактивация таймера
  88. procedure TTimer.SetTimerEnabled(const Value: BOOL);
  89. begin
  90.   //Если "Включить", не включен сейчас и обработчик с интервалом заданы
  91.   if (Value)and(not Enabled)and(ATimerProc <> nil)and(ATimerInterval > 0) then
  92.   begin
  93.     TimerProcToMem(ATimerEvent); //Восстанавливаем обработчик
  94.     if ATimerProc <> nil then    //Если всё успешно
  95.       //Пускаем новый таймер с установленными параметрами и текущим Id
  96.       ATimerId := SetTimer(0, ATimerId, ATimerInterval, ATimerProc);
  97.   end else                       //Иначе
  98.     if Enabled then              //Если таймер включен
  99.       TimerFreeMem;              //чистим память
  100. end;
  101.  
  102. //Установка функции-обработчика пользователя
  103. procedure TTimer.SetTimerEvent(const Value: Pointer);
  104. begin
  105.   ATimerEvent := Value;        //сохраняем обработчик
  106.   TimerProcToMem(ATimerEvent); //устанавливаем новый обработчик
  107. end;
  108.  
  109. //Установка интервала срабатывания таймера
  110. procedure TTimer.SetTimerInterval(const Value: UINT);
  111. begin
  112.   //Если интервал положительный и не равен текущему
  113.   if (Value > 0)and(value <> ATimerInterval) then
  114.   begin
  115.     ATimerInterval := Value;        //устанавливаем новый интервал
  116.     if Enabled then                 //Если таймер включен
  117.     begin
  118.       TimerFreeMem;                 //чистим память
  119.       TimerProcToMem(ATimerEvent);  //Восстанавливаем обработчик
  120.       if ATimerProc <> nil then     //Если всё успешно
  121.         //Пускаем новый таймер с новым интервалом и текущим Id
  122.         ATimerId := SetTimer(0, ATimerId, ATimerInterval, ATimerProc);
  123.     end;
  124.   end else                          //иначе
  125.     ATimerInterval := Value;        //устанавливаем новый интервал
  126. end;
  127.  
  128. //Функция освобождения памяти с предварительной остановкой таймера
  129. procedure TTimer.TimerFreeMem;
  130. begin
  131.   if ATimerProc = nil then                     //Если обработчик ведёт вникуда
  132.     Exit;                                      //выходим
  133.   if (ATimerProc <> nil)or(ATimerId <> 0) then //Если память выделена или таймер работает
  134.   begin
  135.     //Убиваем таймер
  136.     if not KillTimer(0, ATimerId) then begin   //Если не убился
  137.       //Инжектим вместо обработчика юзера KillTimer без параметров, т.к.
  138.       //нужные hWnd и nIDEvent уже в стеке, остались от lpTimeFunc
  139.       TimerProcToMem(@KillTimer);
  140.     end;
  141.     VirtualFree(ATimerProc, SizeOf(TTimerProcAsm), MEM_RELEASE); //Освобождаем память
  142.     ATimerId   := 0;                           //Обнуляем id
  143.     ATimerProc := nil;                         //обнуляем обработчик
  144.   end;
  145. end;
  146.  
  147. //Функция выделения памяти с последующей записью в неё
  148. //переходника с lpTimeFunc на обработчик юзера
  149. //TimerProc - VA обработчика пользователя (@UserProc)
  150. function TTimer.TimerProcToMem(TimerProc: Pointer): Pointer;
  151. var
  152.   BytesWritten: DWORD;
  153.   TimerProcAsm: TTimerProcAsm;
  154. begin
  155.   Result := nil;
  156.   if TimerProc = nil then       //Если обработчик ведёт вникуда
  157.   begin
  158.     TimerFreeMem;               //чистим всё
  159.     Exit;                       //и выходим
  160.   end;
  161.   if ATimerProc = nil then      //Если обработчик ведёт вникуда
  162.     //выделяем память под переходник с lpTimeFunc на обработчик юзера
  163.     ATimerProc := VirtualAlloc(nil, SizeOf(TTimerProcAsm), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  164.   if ATimerProc <> nil then     //Если память выделена
  165.   begin
  166.     with TimerProcAsm do        //Заполняем структуру - переходник
  167.     begin
  168.       _call := $E8;             //call
  169.       _addr := DWORD(DWORD(TimerProc) - 5 - DWORD(ATimerProc)); //offset обработчика юзера
  170.       if not (TimerProc = @KillTimer) then                      //Если обработчик не KillTimer
  171.         _end:= $C310C483        //add esp, 10 / ret чистим стек от 4x параметров по соглашению stdcall и делаем возврат системе
  172.       else                      //иначе
  173.         _end:= $C308C483;       //add esp, 08 / ret чистим стек от 2x параметров, т.к. 2 взял KillTimer
  174.     end;
  175.     //Пишем в выделенную память текущего процесса структуру - переходник
  176.     if WriteProcessMemory(GetCurrentProcess, ATimerProc, @TimerProcAsm, SizeOf(TTimerProcAsm), BytesWritten)
  177.     and(BytesWritten <> 0) then //если записалось
  178.       Result := ATimerProc      //сохраняем адрес памяти
  179.     else                        //иначе
  180.       TimerFreeMem;             //чистим память
  181.   end;
  182. end;
  183.  
  184. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement