Форум: "WinAPI";
Текущий архив: 2004.09.26;
Скачать: [xml.tar.bz2];
ВнизГлюк с завершением сервиса... Найти похожие ветки
← →
Rouse_ © (2004-08-11 11:39) [0]Пишу 2 сервиса находящихся в одном ЕХЕ файле.
Делаю все по Рихтеру и Кнуту.
Заполняется массив типа TServiceTableEntry, последний элемент массива обнуляется.
Оба сервиса имеют тип SERVICE_WIN32_SHARE_PROCESS.
Вызывается StartServiceCtrlDispatcher.
Далее в MainProc каждого сервиса делаю RegisterServiceCtrlHandlerEx.
Каждый сервис при старте сначала оповещает SERVICE_START_PENDING и после него SERVICE_RUNNING.
При необходимости на запрос от SCM о SERVICE_CONTROL_INTERROGATE возвращается текущее
состояние через SetServiceStatus.
При завершении по SERVICE_CONTROL_STOP возвращаю SERVICE_STOPPED.
Проблема заключается в следующем.
Если запускать каждый сервис по отдельности и останавливать его, то все отрабатывает нормально.
Но если запустить оба сервиса и потом остановить любой из них то после остановки этого сервиса
вываливается ошибка ("имя приложения.ехе" - обнаружена ошибка. Приложение будет закрыто) и второй
сервис естественно тоже вырубается (причем никаких завершающих действий не происходит,
просто банальный TerminateProcess самому ЕХЕ делается).
Все функции отрабатываются верно (проверял). Значит что-то я по всей видимости забыл сделать,
или где-то не правильно что-то определил или вызвал. Но что именно никак не могу найти.
Перечитал третью главу Рихтера и Кнута уже от корки до корки, перепроверил построчно весь код,
никак не могу найти где заковыка.
Ниже демо-код приложения содержащего два пустых сервиса, если бы не этот глюк с завершением,
то в принципе нормальная заготовка...
← →
Rouse_ © (2004-08-11 11:39) [1]
program twoservicedemo;
{$DEFINE SERVICE_DEBUG}
uses
Windows,
SysUtils,
WinSvc;
const
InfoStr = "Use:"#13#10"%s [ -install | -uninstall ]";
ServiceFileName = "twoservicedemo.exe";
FirstName = "TSvcFirst";
FirstDisplayName = "Test Service First";
SecondName = "TSvcSecond";
SecondDisplayName = "Test Service Second";
FirstContext = 1;
SecondContext = 2;
type
LPHANDLER_FUNCTION_EX = function (dwControl, dwEventType: DWORD;
lpEventData, lpContext: Pointer): DWORD; stdcall;
THandlerFunctionEx = LPHANDLER_FUNCTION_EX;
function RegisterServiceCtrlHandlerEx(lpServiceName: LPCWSTR;
lpHandlerProc: LPHANDLER_FUNCTION_EX; lpContext: Pointer):
SERVICE_STATUS_HANDLE; stdcall; external "advapi32.dll" name "RegisterServiceCtrlHandlerExW";
var
ServicesTable: packed array [0..2] of TServiceTableEntry;
FirstStatusHandle: SERVICE_STATUS_HANDLE = 0;
SecondStatusHandle: SERVICE_STATUS_HANDLE = 0;
FirstStatus: TServiceStatus;
SecondStatus: TServiceStatus;
{$R *.res}
// ** Служебные процедуры и функции ********************************************
// Вывод информации (при работе сервиса не применяется)
procedure ShowMsg(Msg: string; Flags: integer = -1);
begin
if Flags < 0 then Flags := MB_ICONSTOP;
MessageBox(0, PChar(Msg), ServiceFileName, MB_OK or MB_TASKMODAL or MB_TOPMOST or Flags)
end;
// Инсталяция сервисов в SCM
function Install: Boolean;
const
StartType =
{$IFDEF SERVICE_DEBUG}
SERVICE_DEMAND_START;
{$ELSE}
SERVICE_AUTO_START;
{$ENDIF}
var
SCManager, Service: SC_HANDLE;
begin
SCManager := OpenSCManager(nil, nil, SC_MANAGER_CREATE_SERVICE);
if SCManager <> 0 then
try
// инсталируем первый сервис
Service := CreateService(SCManager, FirstName, FirstDisplayName, SERVICE_ALL_ACCESS,
SERVICE_WIN32_SHARE_PROCESS or SERVICE_INTERACTIVE_PROCESS, StartType, SERVICE_ERROR_NORMAL,
PChar(""" + ParamStr(0) + "" -service"), nil, nil, nil, nil, nil);
if Service <> 0 then
try
Result := ChangeServiceConfig(Service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, nil, nil,
nil, nil, nil, nil, nil);
finally
CloseServiceHandle(Service);
end
else
Result := GetLastError = ERROR_SERVICE_EXISTS;
// инсталируем второй сервис
Service := CreateService(SCManager, SecondName, SecondDisplayName, SERVICE_ALL_ACCESS,
SERVICE_WIN32_SHARE_PROCESS or SERVICE_INTERACTIVE_PROCESS, StartType, SERVICE_ERROR_NORMAL,
PChar(""" + ParamStr(0) + "" -service"), nil, nil, nil, nil, nil);
if Service <> 0 then
try
Result := ChangeServiceConfig(Service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, nil, nil,
nil, nil, nil, nil, nil);
finally
CloseServiceHandle(Service);
end
else
Result := GetLastError = ERROR_SERVICE_EXISTS;
finally
CloseServiceHandle(SCManager);
end
else
Result := False;
end;
// деинсталяция сервисов в SCM
function Uninstall: Boolean;
var
SCManager, Service: SC_HANDLE;
begin
SCManager := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if SCManager <> 0 then
try
// Удаляем первый сервис
Service := OpenService(SCManager, FirstName, _DELETE);
if Service <> 0 then
try
Result := DeleteService(Service);
finally
CloseServiceHandle(Service);
end
else
Result := GetLastError = ERROR_SERVICE_DOES_NOT_EXIST;
// Удаляем второй сервис
Service := OpenService(SCManager, SecondName, _DELETE);
if Service <> 0 then
try
Result := DeleteService(Service);
finally
CloseServiceHandle(Service);
end
else
Result := GetLastError = ERROR_SERVICE_DOES_NOT_EXIST;
finally
CloseServiceHandle(SCManager);
end
else
Result := False;
end;
// *** Непосредственно работа сервисов *****************************************
// Инициализация первого сервиса
function FirstInitialize: Boolean;
begin
with FirstStatus do
begin
dwServiceType := SERVICE_WIN32_SHARE_PROCESS;
dwCurrentState := SERVICE_START_PENDING;
dwControlsAccepted := SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_SHUTDOWN;
dwWin32ExitCode := NO_ERROR;
dwServiceSpecificExitCode := 0;
dwCheckPoint := 1;
dwWaitHint := 5000
end;
Result := SetServiceStatus(FirstStatusHandle, FirstStatus);
end;
// Оповещение SCM что первый сервис работает
function FirstNotifyIsRunning: Boolean;
begin
with FirstStatus do
begin
dwCurrentState := SERVICE_RUNNING;
dwWin32ExitCode := NO_ERROR;
dwCheckPoint := 0;
dwWaitHint := 0
end;
Result := SetServiceStatus(FirstStatusHandle, FirstStatus);
end;
// Завершение работы первого сервиса
procedure FirstStop(Code: DWORD = NO_ERROR);
begin
with FirstStatus do
begin
dwCurrentState := SERVICE_STOPPED;
dwWin32ExitCode := Code;
end;
SetServiceStatus(FirstStatusHandle, FirstStatus); // Результатом True - проверял
end;
// Инициализация второго сервиса
function SecondInitialize: Boolean;
begin
with SecondStatus do
begin
dwServiceType := SERVICE_WIN32_SHARE_PROCESS;
dwCurrentState := SERVICE_START_PENDING;
dwControlsAccepted := SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_SHUTDOWN;
dwWin32ExitCode := NO_ERROR;
dwServiceSpecificExitCode := 0;
dwCheckPoint := 1;
dwWaitHint := 5000
end;
Result := SetServiceStatus(SecondStatusHandle, SecondStatus);
end;
// Оповещение SCM что второй сервис работает
function SecondNotifyIsRunning: Boolean;
begin
with SecondStatus do
begin
dwCurrentState := SERVICE_RUNNING;
dwWin32ExitCode := NO_ERROR;
dwCheckPoint := 0;
dwWaitHint := 0
end;
Result := SetServiceStatus(SecondStatusHandle, SecondStatus);
end;
// Завершение работы второго сервиса
procedure SecondStop(Code: DWORD = NO_ERROR);
begin
with SecondStatus do
begin
dwCurrentState := SERVICE_STOPPED;
dwWin32ExitCode := Code;
end;
SetServiceStatus(SecondStatusHandle, SecondStatus); // Результатом True - проверял
end;
← →
Rouse_ © (2004-08-11 11:40) [2]
// Через эту функцию с нашими сервисами общается SCM
function ServicesCtrlHandler(dwControl, dwEventType: DWORD;
lpEventData, lpContext: Pointer): DWORD; stdcall;
begin
Result := 1;
case DWORD(lpContext^) of
FirstContext:
begin
case dwControl of
SERVICE_CONTROL_STOP, SERVICE_CONTROL_SHUTDOWN:
FirstStop;
SERVICE_CONTROL_INTERROGATE:
FirstNotifyIsRunning;
end;
end;
SecondContext:
begin
case dwControl of
SERVICE_CONTROL_STOP, SERVICE_CONTROL_SHUTDOWN:
SecondStop;
SERVICE_CONTROL_INTERROGATE:
SecondNotifyIsRunning;
end;
end;
end;
end;
// Главная процедура первого сервиса
procedure FirstMainProc(ArgCount: DWORD; var Args: array of PChar); stdcall;
var
Context: DWORD;
begin
Context := FirstContext;
FirstStatusHandle := RegisterServiceCtrlHandlerEx(FirstName,
@ServicesCtrlHandler, @Context);
if (FirstStatusHandle <> 0) and FirstInitialize and FirstNotifyIsRunning then
while FirstStatus.dwCurrentState <> SERVICE_STOPPED do
try
// Собственно работа сервиса
Sleep(10);
except
// Обработка ошибок сервиса
end
end;
// Главная процедура второго сервиса
procedure SecondMainProc(ArgCount: DWORD; var Args: array of PChar); stdcall;
var
Context: DWORD;
begin
Context := SecondContext;
SecondStatusHandle := RegisterServiceCtrlHandlerEx(SecondName,
@ServicesCtrlHandler, @Context);
if (SecondStatusHandle <> 0) and SecondInitialize and SecondNotifyIsRunning then
while SecondStatus.dwCurrentState <> SERVICE_STOPPED do
try
// Собственно работа сервиса
Sleep(10);
except
// Обработка ошибок сервиса
end
end;
// Main
begin
if ParamCount > 0 then
begin
// Инсталяция
if AnsiUpperCase(ParamStr(1)) = "-INSTALL" then
begin
if not Install then ShowMsg(SysErrorMessage(GetLastError));
Exit;
end;
// Деинсталяция
if AnsiUpperCase(ParamStr(1)) = "-UNINSTALL" then
begin
if not Uninstall then ShowMsg(SysErrorMessage(GetLastError));
Exit;
end;
// Работа сервисов
if AnsiUpperCase(ParamStr(1)) = "-SERVICE" then
begin
ServicesTable[0].lpServiceName := FirstName;
ServicesTable[0].lpServiceProc := @FirstMainProc;
ServicesTable[1].lpServiceName := SecondName;
ServicesTable[1].lpServiceProc := @SecondMainProc;
ServicesTable[2].lpServiceName := nil;
ServicesTable[2].lpServiceProc := nil;
// Запускаем сервисы, дальше работа едет в их главных процедурах
if not StartServiceCtrlDispatcher(ServicesTable[0]) and
(GetLastError <> ERROR_SERVICE_ALREADY_RUNNING) then
ShowMsg(SysErrorMessage(GetLastError));
end
else
ShowMsg(Format(InfoStr, [ServiceFileName]), MB_ICONINFORMATION);
end
else
ShowMsg(Format(InfoStr, [ServiceFileName]), MB_ICONINFORMATION);
end.
← →
Rouse_ © (2004-08-11 11:59) [3]> Делаю все по Рихтеру и Кнуту.
Рихтеру и Кларку, конечно :))
← →
Rouse_ © (2004-08-11 12:32) [4]Изменил чтобы у каждого сервиса был свой CtrlHandler и вместо RegisterServiceCtrlHandlerEx вызов произвожу через RegisterServiceCtrlHandler (который продекларирован в WinSvc) тоже такая же пертушка...
// Через эту функцию с первым сервисом общается SCM
function FirstServiceCtrlHandler(dCode: DWORD): DWORD; stdcall;
begin
case dCode of
SERVICE_CONTROL_STOP, SERVICE_CONTROL_SHUTDOWN:
FirstStop;
SERVICE_CONTROL_INTERROGATE:
FirstNotifyIsRunning;
end;
end;
// Через эту функцию со вторым сервисом общается SCM
procedure SecondServicesCtrlHandler(dCode: DWORD); stdcall;
begin
case dCode of
SERVICE_CONTROL_STOP, SERVICE_CONTROL_SHUTDOWN:
SecondStop;
SERVICE_CONTROL_INTERROGATE:
SecondNotifyIsRunning;
end;
end;
// Главная процедура первого сервиса
procedure FirstMainProc(ArgCount: DWORD; var Args: array of PChar); stdcall;
var
Context: DWORD;
begin
Context := FirstContext;
FirstStatusHandle := RegisterServiceCtrlHandler(FirstName,
@FirstServiceCtrlHandler);
if (FirstStatusHandle <> 0) and FirstInitialize and FirstNotifyIsRunning then
while FirstStatus.dwCurrentState <> SERVICE_STOPPED do
try
// Собственно работа сервиса
Sleep(10);
except
// Обработка ошибок сервиса
end
end;
// Главная процедура второго сервиса
procedure SecondMainProc(ArgCount: DWORD; var Args: array of PChar); stdcall;
var
Context: DWORD;
begin
Context := SecondContext;
SecondStatusHandle := RegisterServiceCtrlHandler(SecondName,
@SecondServicesCtrlHandler);
if (SecondStatusHandle <> 0) and SecondInitialize and SecondNotifyIsRunning then
while SecondStatus.dwCurrentState <> SERVICE_STOPPED do
try
// Собственно работа сервиса
Sleep(10);
except
// Обработка ошибок сервиса
end
end;
← →
Rouse_ © (2004-08-11 14:43) [5]Фффух...
Спасибо Digitman-у за подсказку в каком направлении нужно копать...
Вот верный вариант кода:// Главная процедура первого сервиса
procedure FirstMainProc(ArgCount: DWORD; var Args: array of PChar); stdcall;
var
Context: DWORD;
begin
Context := FirstContext;
FirstStatusHandle := RegisterServiceCtrlHandlerEx(FirstName,
@ServicesCtrlHandler, @Context);
if (FirstStatusHandle <> 0) and FirstInitialize and FirstNotifyIsRunning then
try
while FirstStatus.dwCurrentState <> SERVICE_STOP do
try
// Собственно работа сервиса
Sleep(10);
except
// Обработка ошибок сервиса
end;
finally
SetServiceStatus(FirstStatusHandle, FirstStatus);
end;
end;
// Главная процедура второго сервиса
procedure SecondMainProc(ArgCount: DWORD; var Args: array of PChar); stdcall;
var
Context: DWORD;
begin
Context := SecondContext;
SecondStatusHandle := RegisterServiceCtrlHandlerEx(SecondName,
@ServicesCtrlHandler, @Context);
if (SecondStatusHandle <> 0) and SecondInitialize and SecondNotifyIsRunning then
try
while SecondStatus.dwCurrentState <> SERVICE_STOP do
try
// Собственно работа сервиса
Sleep(10);
except
// Обработка ошибок сервиса
end
finally
SetServiceStatus(SecondStatusHandle, SecondStatus);
end;
end;
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2004.09.26;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.034 c