Будильник из спящего режима для вашего ПК

Елена Бадло, Сергей Бадло (г. Запорожье)

<img src=»picture1.jpg» width=»128″ height=»128″ border=»0″ align=»right» hspace=»10″ alt=»»>Многие опытные пользователи наверняка успели по достоинству оценить преимущества спящего режима – это и практически мгновенная загрузка машины (так как не тратится время на загрузку всех программ, которые подгружаются при старте ОС Windows) и экономия времени. А знаете-ли вы, что ваша «рабочая лошадка» может будить вас или играть любимую мелодию (и даже видео) из спящего режима в назначенное время? Нет-нет, для этого не понадобится активация WOL и дополнительная машина в сетке и не понадобиться копание в настройках биоса. Нужны лишь так называемые таймеры пробуждения. Сегодня мы с вами узнаем, что это такое, и создадим простейший консольный будильничек из спящего режима ПК/ноутбука. Интересно? Тогда материал ниже для вас…

BIGITALRU-01

Вообще, таймеры пробуждения, или ожидающие таймеры, – это объекты ядра, предназначенные для отсчета интервалов времени. Таймеры эти могут работать как в непрерывном, так и основном для них режиме – режиме запуска и доступны в одном из режимов электропитания. Основное их достоинство, благодаря столь низкому уровню – возможность работы даже в спящем режиме. При этом не следует забывать, что ОС Windows не realtime и ожидать от них высокой точности (стабильности) не стоит, но для нашей-то задачи это не особо важно. Как проверить доступные состояния электропитания? Наберите в командной строке ‘powercfg /a’.

BIGITALRU_2

Проверка поддерживаемых режимов

При этом в настройках электропитания ОС должно быть:

1. Активировано использование спящего режима.

2. Активирован так называемый таймер пробуждения (который, по умолчанию, в портативных компьютерах деактивирован).

Мало того, по умолчанию на вкладке настроек схемы электропитания эти таймеры не показываются. О чем подробнее можно почитать на сайте самого Microsoft http://technet.microsoft.com/ru-ru/library/ff977084.aspx[1].

В семерке с этим проще, но и там аналогично эти таймеры отключены. Но сначала немного о самих режимах сна и гибернации…

Краткий экскурс…

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

BIGITALRU-3

Общее меню перехода в спящий режим

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

Гибернация (Hibernate) – все тоже самое, но с теми отличиями, что состояние рабочего стола, запущенных приложений и документов сохраняется на винчестер (под Windows в файл hiberfil.sys), после чего компьютер выключается. Именно поэтому данный режим работает медленнее и больше предназначен для мобильных систем: ноутбуков, нетбуков.

Как включается спящий режим?

Для включения спящего режима в меню выключения компьютера необходимо нажать клавишу ‘Shift’. По-умолчанию этот режим требуется предварительно активировать, для чего по правой кнопке мыши заходим в настройки рабочего стола и переходим на вкладку «Заставка».

На данной вкладке внизу справа нажмите кнопку «Питание» для открытия окна свойств электропитания.

Теперь переходим на внутреннюю вкладку «Спящий режим».

BIGITALRU-4

Окно свойств электропитания

Настройка режимов энергопитания

Теперь переходим на внутреннюю вкладку «Спящий режим» и активируем галочку «Разрешить использование спящего режима», после чего жмем кнопку «Применить». В дальнейшем мы будем работать именно со спящим режимом. Все, подготовка завершена.

Предпосылки программной реализации будильника

Для того, чтобы ваш ноутбук а-ля компьютер просыпался тогда, когда необходимо, зайдите в: “Панель управления / Электропитание / Настройка плана электропитания / Изменить дополнительные параметры питания / Сон” и в открывшемся окне выберите ”Разрешить таймеры пробуждения”.

BIGITALRU_5

Активация спящего режима

Уж мы не разбирали, насколько глубоко они лезут в биос и используют ли биос вообще, но факт остается фактом – данная фича при активации этих «таймеров пробуждения» выводит ПК из состояния сна. Что нам потребуется для работы с этими таймерами? Обратимся к MSDN. Всю черную работу будут выполнять пять WinAPI-шных функциий [2…7]: CreateWaitableTimer(), SetWaitableTimer(), WaitForSingleObject(), MciSendString(), CancelWaitableTimer(). Синтаксис вызова функции создания таймера CreateWaitableTimer() следующий:

HANDLE WINAPI CreateWaitableTimer(

  _In_opt_  LPSECURITY_ATTRIBUTES lpTimerAttributes,

  _In_      BOOL bManualReset,

  _In_opt_  LPCTSTR lpTimerName

);

где: lpTimerAttributes –  указатель на структуру SECURITY_ATTRIBUTES  http://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx, определяющую дескриптор безопасности для нового объекта таймера (можно задать nil), bManualReset – тип таймера (с ручным сбросом или автосбросом), lpTimerName – имя объекта таймера.

Синтаксис вызова функции задания времени выдержки таймера SetWaitableTimer() следующий:

BIGITALRU_6

Настройка ОС Windows 7. Активация таймеров пробуждения

BOOL WINAPI SetWaitableTimer(

  _In_      HANDLE hTimer,

  _In_      const LARGE_INTEGER *pDueTime,

  _In_      LONG lPeriod,

  _In_opt_  PTIMERAPCROUTINE pfnCompletionRoutine,

  _In_opt_  LPVOID lpArgToCompletionRoutine,

  _In_      BOOL fResume

);

где: hTimer – дескриптор таймера, pDueTime – абсолютное или относительное время (первое определяет момент первого запуска и является величиной положительной, второе является отрицательной, выраженной в 100 наносекундных интервалах), lPeriod – режим работы и период повторения срабатываний таймера в миллисекундах (если равен нулю, таймер сработает однократно). Параметр ‘pfnCompletionRoutine’ – указатель на необязательную функцию асинхронного вызова. Параметр ‘ lpArgToCompletionRoutine’ передает произвольный аргумент, например указатель на объект или структуру, а ‘bResume’ выводит компьютер из спящего состояния по срабатыванию таймера.

Синтаксис вызова функции WaitForSingleObject() следующий:

DWORD WINAPI WaitForSingleObject(

  _In_  HANDLE hHandle,

  _In_  DWORD dwMilliseconds

);

где: hObject – идентифицирует объект синхронизации, сигнала от которого нужно дождаться, dwTimeout – время ожидания в миллисекундах.

Синтаксис вызова функции перевода таймера в неактивное состояние CancelWaitableTimer() следующий:

BOOL WINAPI CancelWaitableTimer(

  _In_  HANDLE hTimer

);

где: hTimer – дескриптор таймера, полученный при создании таймера CreateWaitableTimerW().

Синтаксис вызова функции WaitForSingleObject() следующий:

DWORD WINAPI WaitForSingleObject(

  _In_  HANDLE hHandle,

  _In_  DWORD dwMilliseconds

);

где: hObject – идентифицирует объект синхронизации, сигнала от которого нужно дождаться, dwTimeout – время ожидания в миллисекундах.

Синтаксис вызова функции перевода таймера в неактивное состояние CancelWaitableTimer() следующий:

BOOL WINAPI CancelWaitableTimer(

  _In_  HANDLE hTimer

);

где: hTimer – дескриптор таймера, полученный при создании таймера CreateWaitableTimerW().

Но какой же будильник без мелодии пробуждения? Как заставить звучать наше приложение? На помощь приходит интерфейс управления устройствами MCI (Media Control Interface), позволяющий программам под Windows работать с различными устройствами мультимедиа, в том числе и воспроизвести аудио. Конкретный набор команд соответствует каждому устройству свой. Нас интересует синтаксис вызова функции команд строк MciSendString():

MCIERROR mciSendString(

  LPCTSTR lpszCommand,

  LPTSTR lpszReturnString,

  UINT cchReturn,

  HANDLE hwndCallback

);

где: lpszCommand – команда в виде [команда][устройство][параметры], lpszReturnString – буфер для получения информации о результате, cchReturn – размер буфера, hwndCallback – каллбэк на окно отклика.

Последовательность действий в алгоритме видится следующей:

1. Задается время будильника в виде количества тиков 100 наносекундных интервалов. Сколько таких интервалов в 1 секунде? Посчитаем. Одна секунда равна 1000 мс, тогда количество таких интервалов равно 1000 * 10^-3 / 100 * 10^-9 = 10 миллионов, а при задании количества миллисекунд их будет 10 000. Причем положительные значения будут равны абсолютному времени, а отрицательные равны относительному, т.е. от начала текущего момента.

2. Задается длительность мелодии будильника в миллисекундах.

3. Задается путь к аудиофайлу и его имя.

4. Через функцию CreateWaitableTimerW() создаем таймер, работающий в ждущем режиме.

5. Через функцию SetWaitableTimer() устанавливаем длительность таймера.

6. Полученный дескриптор из последней функции используем для задания интервала задержки через функцию WaitForSingleObject() с флагом ожидания выполнения INFINITE.

7. Воспроизводим заданную мелодию через функцию MCISendString().

<li>Переводим таймер в неактивное состояние через фукнцию CancelWaitableTimer(). Последнее, при закрытии приложения, является необязательным.

8. Запускаем спящий режим.

Таким образом, уже можем сформировать основные требования к нашему будильнику:

1. Возможность работы при активации аппаратных таймеров пробуждения.

2. Возможность задания пользователем времени пробуждения, длительности воспроизведения и медиафайла для воспроизведения.

3. Реализация приложения на WinAPI в виде консольной утилиты с поддержкой параметров командной строки.

4. Открытые исходники.

Практика. Разработка ПО и средства отладки

Итак, не растекаясь мысли по древу, приступим к основной задаче. Для работы нам понадобится следующее:

1. Бесплатная IDE среда разработки – TurboDelphi-Lite портабле (флэшечная версия) [8];

2. Наличие аудиокарты.

BIGITALRU_7

IDE среда TurboDelphi-Lite. Создание приложения

Ввиду ограниченности места в журнале рассмотрим только основные моменты реализации. Прежде всего, запустим IDE среду Delphi и создадим пустой проект. Разработку осуществим на WinAPI в консоли без всяких форм.

Создадим приложение, которое будет вести отсчет времени до пробуждения согласно вышеозначенному алгоритму. Код приложения-будильника будет минималистичным и простым:

program to_sleep_alarm;

{$APPTYPE CONSOLE}

uses windows, sysutils, classes, mmsystem;

function CreateWaitableTimerW(lpTimerAttributes: PSecurityAttributes;

                              bManualReset: BOOL;

                              lpTimerName: PWideChar): THandle; stdcall;

                              external ‘kernel32.dll’ name ‘CreateWaitableTimerW';

function SetWaitableTimer(hTimer: THandle;

                          var lpDueTime: TLargeInteger;

                          lPeriod: Longint;

                          pfnCompletionRoutine: TFNTimerAPCRoutine;

                          lpArgToCompletionRoutine: Pointer;

                          fResume: BOOL): BOOL; stdcall;

                          external ‘kernel32.dll’ name ‘SetWaitableTimer';

const INFINITE = $FFFFFFFF;

var no, musik: string;

    wnd: hwnd;

    tmr : TLargeInteger;

    tmr2: TFileTime;

    signal, dlit: integer;

begin

 // считываем и проверяем первый параметр командной строки

 no:= paramstr(1);

 if no=» then exit;

 if no=’?’ or no=’h’  then begin

  writeln(»);

  writeln(‘========================================’);

  writeln(‘HELP console SLEEP-ALARM’);

  writeln(‘http://raxp.radioliga.com’);

  writeln(‘========================================’);

  writeln(»);

  writeln(‘Startup options:’);

  writeln(‘to_sleep_alarm [timer] [duration_musik] [path_musik]’);

  writeln(»);

  writeln(‘Timer, ms:’);

 

writeln(‘negative values = relative time’);

  writeln(‘positive values = absolute time’);

  writeln(»);

  writeln(‘The remaining parameters:’);

  writeln(‘- duration_musik, ms (default 1000)’);

  writeln(‘- path_musik, MCI MP3/WAV/OGG (default current dir)’);

  writeln(‘========================================’);

  exit

 end;

  // время будильника из 1-го параметра командной строки

 // кол-во 100 нс интервалов

 // 1000 мс = 1000 * 10^-3 / 100 * 10^-9 = 1000 * 10 000

 // положительные значения = абсолютному времени

 // отрицательные = относительному

 tmr := 10000 * strtointdef(paramstr(1), 1000);

 // длительность будильника из 2-го параметра командной строки

 dlit:= strtointdef(paramstr(2), 1000);

 // мелодия будильника из 3-го параметра командной строки

 musik:= paramstr(3);

 // создаем таймер, работающий в ждущем режиме-

 wnd:= CreateWaitableTimerW(nil, true, ‘SLEEP-ALARM’);

 // устанавливаем длительность таймера-

 SetWaitableTimer(wnd, tmr, 0, nil, nil, true);

 signal:= WaitForSingleObject(wnd, INFINITE);

 // воспроизводим заданную мелодию-

 MCISendString(PChar(‘play ‘ + musik), nil, 0, 0);

 sleep(dlit); // ожидаем заданное время

 // деактивируем задачу и завершаем работу

 CancelWaitableTimer(wnd);

end.

После компиляции тестового приложения по клавише <F9> и задания в консоли команды ‘?’ мы увидим окно краткой справки по работе с будильником.

Параметры управления следующие:

to_sleep_alarm [timer]

[duration_musik] [path_musik]

где: timer, ms – отрицательные значения задают относительное время, положительные – абсолютное; duration_musik, ms – время ожидания до завершения приложения (определяет длительность звучания мелодии); path_musik – путь-имя к медиа-файлу.

Как быстро управлять приложением? Откройте блокнот и напишите следующую команду для запуска нашей утилиты:

%cd%to_sleep_alarm -5000 12000 nw.mp3

Написали? Теперь сохраните в batch-файл с именем ‘test.bat’. Что произойдет при выполнении данного скрипта? Тут мы командой %cd% задаем путь к текущей директории и, через пробел, параметры командной строки, а именно: время отсчета будильника равное 5000 мс (знак минус определяет, что оно будет относительным от момента начала сна), длительность воспроизведения мелодии равное 12000 мс (задержка до закрытия приложения) и путь-имя аудиофайла, который служит в качестве мелодии будильника. Формат данного аудиофайла может быть как MP3, WAV или OGG. Впрочем, сие не столь важно, поскольку задачу воспроизведения и поддержки мы возложили на стандартный программный интерфейс MCI от Windows. Таким образом, если в системе присутствует кодек на заданный формат, то будет и поддержка его воспроизведения. Возможно также задание в качестве медиафайлов – видеофайла.

Как быстро перейти в спящий режим?

Тут все просто. Достаточно написать следующий batch-файл, а еще лучше просто создать по правой кнопке мыши новый ярлык на рабочем столе со следующей командной строкой управления энергопитанием:

BIGITALRU_9

Создание нового ярлыка на рабочем столе; Записываем команду для перехода в “спящий” режим 

После чего назначить на ярлык любимую комбинацию “горячих клавиш” и вызывать при необходимости.

Назначаем кнопки быстрого вызова (“горячую комбинацию” клавиш)

Послесловие

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

Полные исходные тексты и ресурсы проекта (файл alarm-sleep.zip) вы можете загрузить с сайта автора http://raxp.radioliga.com. Если тема представляет для вас интерес – пишите, задавайте вопросы. Приятных вам снов!

Ресурсы

1. О параметрах схемы управления питанием

http://technet.microsoft.com/ru-ru/library/ff977084.aspx

2. Джеффри Рихтер, Кристоф Назар. Windows via C/C++.

Программирование на языке Visual C++. – Питер, Русская Редакция, 896 с.

3. MSDN. CreateWaitableTimer function

<http://msdn.microsoft.com/en-us/library/windows/desktop/ms682492(v=vs.85).aspx

4. MSDN. SetWaitableTimer function

http://msdn.microsoft.com/ru-RU/library/windows/desktop/ms686289(v=vs.85).aspx

5. MSDN. WaitForSingleObject function

http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx

6. MSDN. MciSendString function

http://msdn.microsoft.com/en-us/library/windows/desktop/dd757161(v=vs.85).aspx

7. MSDN. CancelWaitableTimer function

http://msdn.microsoft.com/en-us/library/windows/desktop/ms681985(v=vs.85).aspx

8. IDE среда разработки TurboDelphi-Lite портабле

http://www.andyaska.com/?act=download&mode=detail&id=34

9. Исходники и компиляция тестового будильника из спящего режима

http://raxp.radioliga.com/cnt/s.php?p=alarm-sleep.zip,

зеркало http://raxp.radioliga.com/mpc/alarm-sleep.zip

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>