Определение времени бездействия системы
Иногда приложениям требуется узнать время бездействия системы, то есть интервал времени, прошедший с момента когда пользователь последний раз пошевелил мышкой или нажал какую-нибудь кнопку на клавиатуре. Для определения время бездействия системы в системах Windows 2000 и старше используется функция API GetLastInputInfo. Она возвращает количество миллисекунд (тиков таймера), прошедшее от старта системы до момента последнего ввода. Время бездействия вычисляется как арифметическая разница между данными, возвращаемыми функцией GetTickCount и данными из GetLastInputInfo. В FASM, как обычно, ничего из нужных структур не определено, лезем в MSDN:Code (Assembler) : Убрать нумерацию
- section '.data' data readable writeable
- struct LASTINPUTINFO
- cbSize dd ? ; Размер структуры
- dwTime dd ? ; Время бездействия
- ends
- lii LASTINPUTINFO
Code (Assembler) : Убрать нумерацию
- ...
- ; Получить время последнего ввода
- mov [lii.cbSize],sizeof.LASTINPUTINFO
- invoke GetLastInputInfo,lii
- ; Получить текущее время в миллисекундах
- invoke GetTickCount
- ; EAX - время бездействия системы в миллисекундах
- sub eax,[lii.dwTime]
- ...
Чтобы перехват получился глобальным, придется загружать в память DLL с нужными функциями и устанавливать хуки уже на нее. Хуки будем ставить двух типов: через WH_MOUSE на мышь и через WH_KEYBOARD на клавиатуру. При наступлении любого из этих событий в переменную, находящуюся в shared-памяти DLL, будет записываться значение из функции GetTickCount, а при вызове какой-нибудь заранее определенной функции, это значение будет передаваться нашему приложению. Полный текст DLL я тут приводить не буду, можете посмотреть его, скачав прилагаемый файл с исходниками. В основное приложение DLL подгружается через импорт, при инициализации DLL ставятся глобальные хуки, а при выходе из приложения хуки должны обязательно сниматься.
Code (Assembler) : Убрать нумерацию
- ...
- ; Получить время последнего ввода
- invoke GetLastInputTime
- mov ebx,eax
- ; Получить текущее время в миллисекундах
- invoke GetTickCount
- ; EAX - время бездействия системы в миллисекундах
- sub eax,ebx
- ...
- ...
- ...
- .wmclose:
- ; Снять глобальные хуки
- invoke UnloadDll
- ...
Следующий способ считается устаревшим и не рекомендуется к использованию. Но знать о нем, как мне кажется, будет полезным. Он основан на использовании функции BeginIdleDetection. Функция BeginIdleDetection не импортируется по имени, ее адрес надо получать из библиотеки msidle.dll с помощью функции GetProcAddress, причем использовать ее ординал 3.
Code (Assembler) : Убрать нумерацию
- ; Загрузить библиотеку msidle.dll
- invoke LoadLibrary,msidle
- ; Получить адрес функции BeginIdleDetection
- invoke GetProcAddress,eax,3
- ; Установить обработчик бездействия на 1 минуту
- stdcall eax,IdleCallback,1,0
Code (Assembler) : Убрать нумерацию
- STATE_USER_IDLE_BEGIN = 1
- STATE_USER_IDLE_END = 2
- ;---------------------------------------------------
- ; Обработчик бездействия системы
- ;---------------------------------------------------
- proc IdleCallback dwState:DWORD
- pusha
- cmp [dwState],STATE_USER_IDLE_BEGIN
- jne @f
- ; Получить текущее время в миллисекундах
- invoke GetTickCount
- mov [old_tick],eax
- ; Активировать счетчик
- mov [idlestate],1
- jmp .loc_ret
- @@:
- cmp [dwState],STATE_USER_IDLE_END
- jne .loc_ret
- ; Деактивировать счетчик
- mov [idlestate],0
- .loc_ret:
- popa
- ret
- endp
Еще один интересный способ определения времени бездействия системы основан на ядерной структуре KUSER_SHARED_DATA. Она едина для всех процессов и всегда располагается по фиксированному адресу в памяти. Структура огромная, в ней содержится информация о ресурсах системы и пользователе, который сейчас активен. Но из всего объема данных нас интересует только одно поле TickCountLowDeprecated, в нем записано значение системного таймера. Главная его ценность заключается в том, что значение таймера обновляется только в том случае, когда был выполнен пользовательский ввод, то есть нажата какая-нибудь клавиша на клавиатуре или было выполнено какое-то действие с мышью. Счетчик находится по фиксированному адресу 7FFE02E4h.
Code (Assembler) : Убрать нумерацию
- .wminitdialog:
- ; Получить начальные значения
- mov eax,dword [ds:7FFE02E4h]
- mov [old_timer],eax
- invoke GetTickCount
- mov [old_tick],eax
- ...
- ...
- .wmidle:
- ; Получить время последнего ввода
- mov eax,dword [ds:7FFE02E4h]
- sub eax,[old_timer]
- ; Таймеры равны, пользовательского ввода не было
- jz @f
- ; Записать новые значения
- mov eax,dword [ds:7FFE02E4h]
- mov [old_timer],eax
- invoke GetTickCount
- mov [old_tick],eax
- @@:
- ; Получить текущее время в миллисекундах
- invoke GetTickCount
- ; EAX - время бездействия системы в миллисекундах
- sub eax,[old_tick]
В приложении программы с исходными текстами, реализующие оба описанных выше метода. В диалоговом окне они показывают счетчик секунд, прошедших с момента последней активности пользователя. Чтобы сбросить счетчик пошевелите мышкой или нажмите любую клавишу.
Просмотров: 8299 | Комментариев: 11
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Лёха
(12.04.2023 в 11:35):
Спасибо! Помогло.
ManHunter
(06.04.2021 в 13:24):
Добавлен способ определения бездействия через BeginIdleDetection. Архив обновлен.
ManHunter
(06.04.2021 в 11:19):
Добавлен еще один интересный пример с ядерным таймером, архив обновлен.
ManHunter
(09.08.2019 в 17:45):
Стандартный виндовый планировщик прекрасно справляется с этой задачей. Триггер задачи на условие "При простое", "Условия" - установить на нужный интервал время бездействия, "Действия" - запуск программы. И не надо ничего городить.
Kylo
(09.08.2019 в 17:34):
Уважаемый ManHunter, ознакомился со списком Ваших программ, нашел для себя много интересного. Спасибо за Ваш труд! И возникло у меня к Вам предложение по использованию определения времени бездействия системы в Вашей же программе Delayed Start. Дополнительный параметр командной строки, например -hNNN, который запускал бы приложение на определенную секунду времени бездействия. Сразу расширяются возможности применения Delayed Start. Ну а дальше можно фантазировать еще больше - "ds -h600 -c winamp.exe" - запуск музыки после 10мин бездействия пользователя и закрытие winamp.exe (параметр -c) при активности пользователя. Минус примера, нельзя оставлять громкость наполную уходя далеко от компа))
ManHunter
(08.08.2019 в 16:53):
За доработками лучше обратиться куда-нибудь на фриланс. Задача не космическая, за мелкий прайс студенты с радостью нарисуют что угодно, тем более вся теория расписана.
Kylo
(08.08.2019 в 16:35):
Мне бы было полезно использовать эту наработку как таймер для запуска каких либо задач. Полдня сегодня просидел в поисках реализации такого "таймера", ничего толкового не нашел. Исходники C++, VB, PS, AutoIt, у уважаемого ManHunter здесь на ASM, но уже готового решения нет. Если бы я в этом понимал, конечно использовал бы эти наработки для создания того, что мне нужно, но увы, мозгами не вышел. А так бы можно было сделать с GUI и без, оснастить дополнительными параметрами, взятием настроек из файлов и реестра. Если у Вас, уважаемый ManHunter, есть возможность, желание и время расширить функционал Вашей наработки, буду очень благодарен!
Tekton
(15.10.2015 в 10:13):
Я например частенько вечером "рублюсь" при просмотре какого нибудь фильма.
Просыпаюсь под утро, а комп во всю пашет.
Вот можно применить эту наработку.
Сделать скажем таймер часа на 2 если юзер не пошевелил мыш, или клаву не потискал, чтоб комп отрубался сам.
Просыпаюсь под утро, а комп во всю пашет.
Вот можно применить эту наработку.
Сделать скажем таймер часа на 2 если юзер не пошевелил мыш, или клаву не потискал, чтоб комп отрубался сам.
Vovka
(09.08.2010 в 22:15):
Вызов скорой помощи для онлайновых параноиков...
ManHunter
(06.08.2010 в 08:01):
Дефрагментация диска при простое компа, автоблокировка оставленного без присмотра компа, мониторинг работы сотрудников. Это так, навскидку.
Isaev
(06.08.2010 в 01:55):
"Определение времени бездействия системы"
А в каких случаях эта информация используется?
Что-то так и не придумал ничего полезного (
А в каких случаях эта информация используется?
Что-то так и не придумал ничего полезного (
Добавить комментарий
Заполните форму для добавления комментария