Функция ServiceMain
октября 12 2009 by admin in СлужбыКаждая служба в исполняемом файле должна иметь свою функцию ServiceMain-.
VOID WINAPI ServiceMain( DWORD dwArgc, PTSTR* pszArgv);
SCM запускает службу, создавая новый поток, который начинает свое выполнение с вызова ServiceMain. Как я уже говорил, я называю эту функцию именно ServiceMain, хотя ей можно дать любое имя. Имя не имеет значения, так как передается адрес этой функции элементом IpServiceProc стуктуры SERVICE_TAB-LE_ENTRY. Однако нельзя иметь две одноименные функции ServiceMain в одном исполняемом файле. Если это произойдет, компилятор или компоновщик выдадут ошибку, когда вы попытаетесь собрать свой проект.
В ServiceMain передаются два параметра. Они создают механизм, позволяющий администратору запустить службу с указанием параметров командной строки с помощью функции StartService (см. главу 4). Я лично не знаю служб, использующих эти параметры, и настоятельно рекомендую вам их не применять. Чем передавать необходимые для настройки службы параметры в Service-Main, лучше хранить и читать их из подраздела реестра (Имя_службы следует заменить на действительное имя службы):
HKEY_L0CAL_MACHINE\SYSTEM\CurrentControlSet\Services\^Mfl_Cfly*6w\Parameters
Со многими службами поставляются клиентские приложения, позволяющие администратору их настраивать. Эти клиентские приложения просто-напросто сохраняют соответствующие параметры в указанном подразделе реестра, и служба считывает их при запуске.
Если параметры конфигурации службы меняются в процессе ее работы, возможны три варианта реакции на это со стороны службы.
Служба игнорирует изменения конфигурационных параметров до следующего запуска. Этот простейший вариант применяется во многих существующих на сегодня службах.
Службе можно явно указать, что ей следует себя перенастроить. Это делает SCP с помощью функции ServiceControl, передавая ей значение SERVI-CE_CONTROL_PARAMCHANGE (о том, как это делается см. главу 4).
Служба может вызвать функцию RegNotifyChangeKeyValue, чтобы получать уведомления, когда внешние приложения изменяют ее параметры в реестре. Это позволяет службе перенастраиваться «на лету». Этот подход демонстрируется приложением RegNotify.
Первое, что должна сделать ServiceMain, — это указать SCM адрес функции обратного вызова HandlerEx службы. Это делает функция RegisterServiceCtrlHandlerEx-.
SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerEx( PCTSTR pszServiceName, // Внутреннее имя службы LPHANDLER_FUNCTION_EX pfnHandler, // Функция HandlerEx службы PVOID pvContext); // Определяемое пользователем значение
Первый параметр указывает службу, для которой устанавливается функция HandlerEx, а второй — это адрес HandlerEx. Параметр pszServiceName должен совпадать с именем, указанным в массиве SERVICE_TABLE_ENTRY, который был передан функции StartServiceCtrlDispatcher. Параметр pvContext — это определяемое пользователем значение, которое передается HandlerEx. Эту функцию мы подробней рассмотрим в следующем разделе.
Функция RegisterServiceCtrlHandlerEx возвращает описатель SERVICE_STA-TUS_HANDLE — уникальный идентификатор службы, используемый SCM. Все дальнейшее взаимодействие службы с SCM производится с использованием этого описателя, а не текстовой строки, определяющей внутреннее имя службы.