Выбрать главу

С одним сигналом могут быть ассоциированы несколько обработчиков, причем обработчики можно добавлять и удалять. Функция, которая используется для добавления и удаления обработчиков, имеет следующий вид:

BOOL SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add) 

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

Процедура обработчика возвращает булевское значение и принимает единственный параметр типа DWORD, идентифицирующий фактический сигнал. Использованное в объявлении имя обработчика (HandlerRoutine) является заменителем, и программист может выбирать его по своему усмотрению.

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

• Если значение параметра HandlerRoutine равно NULL, а параметра Add — TRUE, то сигналы Ctrl-c будут игнорироваться.

• Если при вызове функции SetConsoleMode был задан параметр ENABLE_PROCESSED_INPUT (глава 2), то комбинация <Ctrl+C> будет обрабатываться не как сигнал, а как клавиатурный ввод.

• Процедура обработчика фактически выполняется как независимый поток (см. главу 7) внутри процесса. При этом выполнение основной программы, как показано в следующем примере, не приостанавливается.

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

Между исключениями и сигналами существует важное отличие. Сигналы применяются к процессу в целом, тогда как исключения — только к потоку, выполняющему код, в котором возникло исключение. 

BOOL HandlerRoutine(DWORD dwCtrlType)

dwCtrlType идентифицирует фактический сигнал (или событие) и может принимать одно из следующих пяти значений:

1. CTRL_C_EVENT указывает на то, что комбинация <Ctrl+C> должна восприниматься как клавиатурный ввод.

2. CTRL_CLOSE_EVENT указывает на закрытие окна консоли.

3. CTRL_BREAK_EVENT указывает на сигнал Ctrl-break.

4. CTRL_LOGOFF_EVENT указывает на выход пользователя из системы.

5. CTRL_SHUTDOWN_EVENT указывает на завершение работы системы. 

Обработчик сигналов может выполнять операции по "уборке мусора" точно так же, как это делают обработчики исключений и завершения. В случае успешной обработки сигнала обработчик должен вернуть значение TRUE. Если обработчик возвращает значение FALSE, выполняется следующая функция обработчика из числа тех, что указаны в списке. Обработчики сигналов выполняются в порядке, обратном порядку их установки, так что первым будет выполняться самый последний из установленных обработчиков, а системный обработчик будет выполняться самым последним.

Пример: обработчик управляющих сигналов консоли

В программе 4.5 организован бесконечный цикл, в котором каждые 5 секунд вызывается функция Веер, подающая звуковой сигнал. Пользователь может завершить выполнение программы, нажав комбинацию клавиш <Ctrl+C> или закрыв консоль. Процедура обработчика выводит на экран сообщение, выжидает 10 секунд, после чего, казалось бы, выполнение программы должно завершиться с возвратом значения TRUE. Однако в действительности основная программа обнаруживает флаг Exit и останавливает процесс. Это демонстрирует параллельную природу выполнения процедуры обработчика; заметьте, что объем выходной информации обработчика сигналов зависит от временных характеристик сигнала. Обработчики управляющих сигналов консоли будут использоваться также в примерах, приводимых в следующих главах.

Обратите внимание на использование макроса WINAPI; он применяется к пользовательским функциям, передаваемым в качестве аргументов функциям Windows, чтобы гарантировать выполнение соответствующих соглашений о вызовах. Этот макрос определен в заголовочном файле Microsoft С WTYPES.Н.

Программа 4.5. Ctrlc: программа обработки сигналов 

/* Глава 4. Ctrlc.с */

/* Перехватчик событий консоли. */

#include "EvryThng.h"

static BOOL WINAPI Handler(DWORD CtrlEvent); /* См. WTYPES.H. */

volatile static BOOL Exit = FALSE;

int _tmain(int argc, LPTSTR argv[])

 /* Периодическая подача звукового сигнала до поступления сигнала о прекращении выполнения. */