Blog. Just Blog

Образ мышления: Assembler

То, что не удается запрограммировать на Ассемблере, приходится паять
Образ мышления: Assembler - RSS-канал Образ мышления: Assembler - Карта сайта

Использование мультимедийного таймера

16.08.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Интересная разновидность системных событий - высокоточный мультимедийный таймер. Гарантированный интервал срабатывания мультимедийных таймеров - около 10 миллисекунд против 50 миллисекунд обычных таймеров, устанавливаемых при помощи функции SetTimer. Кроме того, мультимедийные таймеры позволяют использовать обработчики, которые будут срабатывать в нужные интервалы, тогда как сообщения WM_TIMER от обычных таймеров идут через общую очередь. Если главный поток подвис, заснул или продолжительное время реагирует на какое-нибудь тяжелое сообщение, то таймеру придется ожидать, пока обработчик дойдет до него. Таким образом, добиться предсказуемой периодичности таймера будет очень сложно. Мультимедийные таймеры выполняются в собственном потоке, поэтому лишены перечисленных недостатков.

Слова словами, но давайте проверим это на практике. Для этого в простом оконном приложении установим обычный таймер на интервал 1 миллисекунду, вместе с этим создадим мультимедийный таймер с таким же интервалом срабатывания. При каждом срабатывании каждого из этих таймеров будет увеличен соответствующий счетчик. По истечении определенного времени, например, 5 секунд, сравним результаты.

Обработчик окна будет выглядеть примерно так. Для удобства я оставил только минимально необходимый код.
  1.         cmp     [msg],WM_INITDIALOG
  2.         je      wminitdialog
  3.         cmp     [msg],WM_TIMER
  4.         je      wmtimer
  5.         ...
  6.         ...
  7. wminitdialog:
  8.         ; Обнулить счетчики
  9.         mov     [dCntTim],0
  10.         mov     [dCntMM],0
  11.  
  12.         ; Получить начальное время
  13.         invoke  GetTickCount
  14.         mov     [dTime],eax
  15.  
  16.         ; Установить обычный таймер на интервал 1 мс
  17.         invoke  SetTimer,[hwnddlg],1,1,NULL
  18.  
  19.         ; Установить мультимедийный таймер на интервал 1 мс
  20.         TIME_PERIODIC = 0x0001
  21.         invoke  timeSetEvent,1,1,TimeProc,777,TIME_PERIODIC
  22.  
  23.         ...
  24.         ...
  25. wmtimer:
  26.         ; Увеличить счетчик по событию WM_TIMER
  27.         inc     [dCntTim]
  28.  
  29.         ; Прошло 5 секунд?
  30.         invoke  GetTickCount
  31.         sub     eax,[dTime]
  32.         cmp     eax,5000
  33.         jb      processed
  34.         jmp     wmclose
  35.  
  36. wmclose:
  37.         ; Удалить оба счетчика
  38.         invoke  KillTimer,[hwnddlg],1
  39.         invoke  timeKillEvent,[hTimer]
При инициализации окна устанавливается обычный и мультимедийный таймеры, при получении сообщения WM_TIMER увеличиваем обычный счетчик, а в функции-обработчике высокоточного таймера увеличиваем мультимедийный счетчик.
  1. ;-----------------------------------------------------------
  2. ; Обработчик высокоточного таймера
  3. ;-----------------------------------------------------------
  4. proc TimeProc uTimerID:DWORD,uMsg:DWORD,dwUser:DWORD,dw1:DWORD,dw2:DWORD
  5.         ; Увеличить счетчик по системному событию
  6.         inc     [dCntMM]
  7.         ret
  8. endp
Ну и момент истины. По результатам тестирования выяснилось, что за 5 секунд обычный таймер вызывается всего около 320 раз, тогда как обработчик мультимедийного таймера вызывается четко не менее 5000 раз. Что и требовалось доказать.

Читать статью целиком »
Просмотров: 428 | Комментариев: 3

Прячем ярлыки на рабочем столе

05.08.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Очередная мелкая развлекушка на Ассемблере. Сегодня будем прятать все ярлыки на рабочем столе. Нам не понадобится никаких громоздких структур, объектов, интерфейсов и прочей паранормальщины. И что хорошо, фактически все ярлыки остаются на своих местах, ничего не надо потом восстанавливать, ведь при прятании просто скрывается дочерний элемент окна десктопа, в котором ярлыки находятся.
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. szProg db 'ProgMan',0
  5.  
  6. ; Сегмент кода
  7. section '.code' code readable executable
  8.         ...
  9.         invoke  FindWindow,szProg,NULL
  10.         invoke  GetWindow,eax,GW_CHILD
  11.         invoke  GetWindow,eax,GW_CHILD
  12.         ; Сохранить хэндл окна с ярлыками
  13.         mov     ebx,eax
  14.         ; Ярлыки показываются?
  15.         invoke  IsWindowVisible,ebx
  16.         or      eax,eax
  17.         jne     @f
  18.         ; Нет, показать
  19.         invoke  ShowWindow,ebx,SW_SHOW
  20.         jmp     loc_exit
  21. @@:
  22.         ; Да, скрыть
  23.         invoke  ShowWindow,ebx,SW_HIDE
  24. loc_exit:
При запуске первым делом ищется окно с названием класса "ProgMan", затем поочередно находятся его первое дочернее окно и дочернее окно этого окна. Именно в нем находится Listbox со всеми ярлыками. Затем проверяется видимость этого окна. Если ярлыки отображаются, то они будут спрятаны, ну и наоборот. Если повесить такую программу на какую-нибудь горячую клавишу, то получится этакий ультра-лайтовый вариант блокировки компьютера, чтобы временно скрыть содержимое рабочего стола от излишне любопытных глаз, не запрещая при этом возможность работы за компьютером. Или можно использовать как программу-шутку для пугания юзеров. Естественно, после перезагрузки все возвращается на свои места.

Читать статью целиком »
Просмотров: 514 | Комментариев: 3

Перехват и обработка изменения заголовка окна другого приложения

03.08.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
В предыдущих примерах обработки системных событий мы рассматривали глобальные события, которые происходят во всей системе. Чтобы завершить эту тему, хотелось бы рассказать о системных событиях, ограниченных конкретным приложением. В качестве примера возьмем перехват и обработку изменения заголовка окна какого-нибудь приложения. Немного констант, некоторые из которых вы уже знаете.
  1. EVENT_OBJECT_NAMECHANGE = 0x800C
  2. WINEVENT_OUTOFCONTEXT   = 0x0000
  3. OBJID_WINDOW            = 0x0000
  4. CHILDID_SELF            = 0x0000
Процесс установки хука немного отличается по используемым параметрам. Чтобы связать обработчик с конкретным процессом, сперва надо получить идентификаторы этого процесса и потока. Для дочерних процессов это вообще не проблема, а для стороннего придется воспользоваться функцией GetWindowThreadProcessId, ведь хэндл обрабатываемого окна мы знаем. В SetWinEventHook указываем полученные идентификаторы.
  1.         ; Найти нужное окно
  2.         invoke  FindWindow,NULL,szName
  3.         ; Сохранить хэндл найденного окна
  4.         mov     [hExample],eax
  5.  
  6.         ; Получить идентификаторы процесса и потока, относящиеся к окну
  7.         invoke  GetWindowThreadProcessId,[hExample],pID
  8.         mov     [tID],eax
  9.  
  10.         ; Установить хук на системные события
  11.         invoke  SetWinEventHook,EVENT_OBJECT_NAMECHANGE,\
  12.                 EVENT_OBJECT_NAMECHANGE,NULL,WinEventProc,\
  13.                 [pID],[tID],WINEVENT_OUTOFCONTEXT
А вот обработчик изменился не сильно. Проверяем, что изменяемый объект - окно, что это действительно нужное нам окно, после этого каким-то образом реагируем на изменение его заголовка.
  1. proc WinEventProc hWinEventHook:DWORD, event:DWORD, hwnd:DWORD,\
  2.                   idObject:DWORD, idChild:DWORD, idEventThread:DWORD,\
  3.                   dwmsEventTime:DWORD
  4.         pusha
  5.         ; Изменяемый объект - окно?
  6.         cmp     [idObject],OBJID_WINDOW
  7.         jne     .loc_ret
  8.  
  9.         ; Изменяется само окно?
  10.         cmp     [idChild],CHILDID_SELF
  11.         jne     .loc_ret
  12.  
  13.         ; Точно-точно изменяется?
  14.         cmp     [event],EVENT_OBJECT_NAMECHANGE
  15.         jne     .loc_ret
  16.  
  17.         ; И меняется именно нужное окно?
  18.         mov     eax,[hwnd]
  19.         cmp     eax,[hExample]
  20.         jne     .loc_ret
  21.         ... 
  22.         ...
  23.         ; Выполняются какие-то действия по факту события
  24.         ... 
  25.         ... 
  26. .loc_ret:
  27.         popa
  28.         ret
  29. endp
Таким образом, например, можно доработать автокликалку для Total Commander, чтобы она висела в фоне и модифицировала заголовок окна программы, мгновенно убирая из него надпись "UNREGISTERED" в случае ее появления.

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

Читать статью целиком »
Просмотров: 373 | Комментариев: 0

Как получить список ярлыков на рабочем столе

25.07.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter

Как получить список ярлыков на рабочем столе

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

Читать статью целиком »
Просмотров: 572 | Комментариев: 7

Перехват и обработка изменения курсора

24.07.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Закрепим материал по системным событиям. В сегодняшнем примере отработаем перехват изменения формы курсора. Начнем с описания отсутствующих структур и констант, которые будут использоваться в нашем коде.
  1. struct CURSORINFO
  2.     cbSize      dd ?
  3.     flags       dd ?
  4.     hCursor     dd ?
  5.     ptScreenPos POINT
  6. ends
  7.  
  8. EVENT_OBJECT_NAMECHANGE = 0x800C
  9. WINEVENT_OUTOFCONTEXT   = 0x0000
  10. OBJID_CURSOR            = 0xFFFFFFF7
Затем, как и в предыдущем примере, устанавливаем хук на системные события. В зависимости от ситуации, сделать это можно при инициализации приложения или в какой-нибудь другой определенный вами момент.
  1.         ; Установить хук на системные события
  2.         invoke  SetWinEventHook,EVENT_OBJECT_NAMECHANGE,\
  3.                 EVENT_OBJECT_NAMECHANGE,NULL,WinEventProc,\
  4.                 0,0,WINEVENT_OUTOFCONTEXT
Ну и сам обработчик системного события. Тут первым делом проверяется, что изменившийся объект является курсором, потом на всякий случай проверяем тип события, если их планируется несколько. Вся необходимая информация об изменившемся курсоре получается при помощи функции GetCursorInfo. Это хэндл нового курсора, его координаты и флаги отображения.
  1. proc WinEventProc hWinEventHook:DWORD, event:DWORD, hwnd:DWORD,\
  2.                   idObject:DWORD, idChild:DWORD, idEventThread:DWORD,\
  3.                   dwmsEventTime:DWORD
  4.         pusha
  5.         ; Изменяемый объект - курсор?
  6.         cmp     [idObject],OBJID_CURSOR
  7.         jne     .loc_ret
  8.  
  9.         ; Курсор изменяется?
  10.         cmp     [event],EVENT_OBJECT_NAMECHANGE
  11.         jne     .loc_ret
  12.  
  13.         ; Получить инфомрацию о курсоре
  14.         mov     [pci.cbSize],sizeof.CURSORINFO
  15.         invoke  GetCursorInfo,pci
  16.         ; Курсор изменился?
  17.         mov     eax,[pci.hCursor]
  18.         cmp     eax,[hCursor]
  19.         ; Нет, пропустить
  20.         je      .loc_ret
  21.         ; Да, сохранить хэндл нового курсора
  22.         mov     [hCursor],eax
  23.         ; В структуре CURSORINFO содержится информация о курсоре
  24.         ...
  25.         ...
  26. .loc_ret:
  27.         popa
  28.         ret
  29. endp
В обработчике проверяется хэндл старого и нового курсора, так как система щедро сыплет событиями даже когда курсор просто стоит на месте. Обработчик реагирует только когда хэндл курсора изменился, то есть изменилась его форма. Что интересно, хэндл курсора, возвращаемый в структуре CURSORINFO, не совпадает со стандартными хэндлами курсоров. Объяснить причину такого поведения системы я не могу. Если вам это необходимо, то можно составить табличку соответствия.

Читать статью целиком »
Просмотров: 352 | Комментариев: 0

prev 01 ... 05 06 07 08 09 10 11 ... 49 next
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2021
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.11 сек. / MySQL: 2 (0.0033 сек.) / Память: 4.75 Mb
Наверх