StartServiceCtrlDispatcher выполнится только после того, как все сервисы будут остановлены.
Функция LogError протоколирует ошибки - напишите ее сами.
Функция ServiceMain
ServiceMain - основная функция сервиса. Если в ехешнике несколько сервисов, но для каждого сервиса пишется своя ServiceMain функция. Имя функции может быть любым! и передается в DispatchTable.lpServiceProc:=@ServiceMain (см.предыдущущий абзац). У меня она называется ServiceProc и описывается так:
procedure ServiceProc(argc : DWORD;var argv : array of PChar);stdcall;
argc кол-во аргументов и их массив argv передаются менеджером сервисов из настроек сервиса. НЕ ЗАБЫВАЙТЕ STDCALL!!! Такая забывчивость - частая причина ошибки в программе.
В ServiceMain требуется выполнить подготовку к запуску сервиса и зарегистрировать обработчик сообщений от менеджера сервисов (Handler). Опять после запуска ServiceMain и до запуска RegisterServiceCtrlHandler должно пройти минимум времени. Если сервису надо делать что-нибудь очень долго и обязательно до вызова RegisterServiceCtrlHandler, то надо посылать сообщение SERVICE_START_PENDING функией SetServiceStatus.
Итак, в RegisterServiceCtrlHandler передаем название нашего сервиса и адрес функции Handler'а (см.далее). Далее выполняем подготовку к запуску и настройку сервиса. Остановимся на настройке поподробнее.
Эта самая настройка var ServiceStatus : SERVICE_STATUS;
(ServiceStatusHandle : SERVICE_STATUS_HANDLE и ServiceStatus надо сделать глобальными переменными и поместить их выше всех функций).
dwServiceType - тип сервиса |
|
|
SERVICE_WIN32_OWN_PROCESS |
Одиночный сервис |
|
SERVICE_WIN32_SHARE_PROCESS |
Несколько сервисов в одном процессе |
|
SERVICE_INTERACTIVE_PROCESS |
интерактивный сервис (может взаимодействовать с пользователем). |
|
Остальные константы - о драйверах. Если надо - смотрите их в MSDN.
dwControlsAccepted - принимаемые сообщения (какие сообщения мы будем обрабатывать)
SERVICE_ACCEPT_PAUSE_CONTINUE приостановка/перезапуск
SERVICE_ACCEPT_STOP остановка сервиса
SERVICE_ACCEPT_SHUTDOWN перезагрузка компьютера
SERVICE_ACCEPT_PARAMCHANGE изменение параметров сервиса без перезапуска (Win2000 и выше)
Остальные сообщения смотрите опять же в MSDN (куда уж без него ;-)
dwWin32ExitCode и dwServiceSpecificExitCode - коды ошибок сервиса. Если все идет нормально, то они должны быть равны нулю, иначе коду ошибки.
dwCheckPoint - если сервис выполняет какое-нибудь долгое действие при остановке, запуске и т.д. то dwCheckPoint является индикатором прогресса (увеличивайте его, чтобы дать понять, что сервис не завис), иначе он должен быть равен нулю.
dwWaitHint - время, через которое сервис должен послать свой новый статус менеджеру сервисов при выполнении действия (запуска, остановки и т.д.). Если dwCurrentState и dwCheckPoint через это кол-во миллисекунд не изменится, то менеджер сервисов решит, что произошла ошибка.
dwCurrentState - см. где-то здесь Ставим его в SERVICE_RUNNING, если сервис запущен
После заполнения этой структуры посылаем наш новый статус функцией SetServiceStatus и мы работаем :).
После этого пишем код самого сервиса. Я вернусь к этому попозже.
Вот так выглядит моя ServiceMain :
Code: |
procedure ServiceProc(argc : DWORD;var argv : array of PChar);stdcall; var Status : DWORD; SpecificError : DWORD; begin ServiceStatus.dwServiceType := SERVICE_WIN32; ServiceStatus.dwCurrentState := SERVICE_START_PENDING; ServiceStatus.dwControlsAccepted := SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_PAUSE_CONTINUE; ServiceStatus.dwWin32ExitCode := 0; ServiceStatus.dwServiceSpecificExitCode := 0; ServiceStatus.dwCheckPoint := 0; ServiceStatus.dwWaitHint := 0;
ServiceStatusHandle := RegisterServiceCtrlHandler(ServiceName,@ServiceCtrlHandler); if ServiceStatusHandle = 0 then WriteLn('RegisterServiceCtrlHandler Error');
Status :=ServiceInitialization(argc,argv,SpecificError); if Status <> NO_ERROR then begin ServiceStatus.dwCurrentState := SERVICE_STOPPED; ServiceStatus.dwCheckPoint := 0; ServiceStatus.dwWaitHint := 0; ServiceStatus.dwWin32ExitCode:=Status; ServiceStatus.dwServiceSpecificExitCode:=SpecificError;
SetServiceStatus (ServiceStatusHandle, ServiceStatus); LogError('ServiceInitialization'); exit; end;
ServiceStatus.dwCurrentState :=SERVICE_RUNNING; ServiceStatus.dwCheckPoint :=0; ServiceStatus.dwWaitHint :=0;
if not SetServiceStatus (ServiceStatusHandle,ServiceStatus) then begin Status:=GetLastError; LogError('SetServiceStatus'); exit; end; // WORK HERE //ЗДЕСЬ БУДЕТ ОСНОВНОЙ КОД ПРОГРАММЫ end;
|
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!