Функция MyServiceCtrlHandler в следующем примере - это функция Handler. Когда эту функцию вызывает поток - диспетчер, то она обрабатывает управляющий код, переданный в параметре Opcode, а затем вызывает функцию SetServiceStatus, чтобы обновить состояние службы. Каждый раз, когда функция Handler получает управляющий код, она возвращает соответствующее состояние с помощью вызова функции SetServiceStatus независимо от того, воздействует ли служба на управление.
Когда получена пауза в управлении, функция MyServiceCtrlHandler просто устанавливает член dwCurrentState структуры SERVICE_STATUS в значение SERVICE_PAUSED. Аналогично, когда получено продолжение управления, состояние устанавливается в SERVICE_RUNNING. Поэтому, MyServiceCtrlHandler не лучший пример того, как обработать паузу и продолжить управление. Поскольку MyServiceCtrlHandler - это шаблон функции Handler, код для паузы и продолжения управления включен для полноты изложения. Служба, которая поддерживает или паузу, или продолжение управления, должна обработать эти управления способом, который делает считывание. Много служб не поддерживают ни пауз, ни продолжений управления. Если служба указывает, что она не поддерживает паузу или продолжение в параметре dwControlsAccepted, то Диспетчер управления службами (SCM) не будет отправлять паузу или продолжение управления в функцию Handler службы.
Чтобы выводить на экран информацию отладки, MyServiceCtrlHandler вызывает функцию SvcDebugOut. Исходный код для SvcDebugOut приводится в статье Запись главной функции сервисной программы. Кроме того, обратите внимание! на то, что переменная MyServiceStatus - это глобальная переменная и должна быть инициализирована как это показано в статье Запись функции ServiceMain.
#include <windows.h> SERVICE_STATUS MyServiceStatus; SERVICE_STATUS_HANDLE MyServiceStatusHandle; VOID SvcDebugOut(LPSTR String, DWORD Status); VOID WINAPI MyServiceCtrlHandler (DWORD Opcode) { DWORD status; switch(Opcode) { case SERVICE_CONTROL_PAUSE: // Делается то, что требуется, чтобы сделать паузу здесь. MyServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: // Делается то, что требуется, чтобы продолжить работу службы здесь. MyServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: // Делается то, что требуется, чтобы остановить службу здесь. MyServiceStatus.dwWin32ExitCode = 0; MyServiceStatus.dwCurrentState = SERVICE_STOPPED; MyServiceStatus.dwCheckPoint = 0; MyServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus)) { status = GetLastError(); SvcDebugOut(" [MY_SERVICE] SetServiceStatus error %ld\n", status); } SvcDebugOut(" [MY_SERVICE] Leaving MyService \n",0); return; case SERVICE_CONTROL_INTERROGATE: // Передадим управление вниз, чтобы отправить текущее состояние. break; default: SvcDebugOut(" [MY_SERVICE] Unrecognized opcode %ld\n", Opcode); } // Отправим текущее состояние. if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus)) { status = GetLastError(); SvcDebugOut(" [MY_SERVICE] SetServiceStatus error %ld\n", status); } return; } |