![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Не могу остановить свой сервис [D6, WinXP]
novill © (2006-06-23 10:48:00)Написал сервис по описанию в хелпе.
При попытке остановить процесс Винда выдает ошибку: "не удалось остановить службу. Эта служба не возвращала код ошибки. Возможно это внутренняя ошибка Windows или службы."
После этого службу нельзя удалить (uninstall). Windows говорит что пометила ее на удаление, но до перезагрузки служба висит: ни запустить , ни остановить.
unit ServU;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
DB, IBCustomDataSet, IBQuery, IBDatabase;
type
TDS = class(TService)
procedure ServiceExecute(Sender: TService);
private
{ Private declarations }
public
function GetServiceController: TServiceController; override;
{ Public declarations }
end;
var
DS: TDS;
implementation
uses mainU;
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
DS.Controller(CtrlCode);
end;
function TDS.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
procedure TDS.ServiceExecute(Sender: TService);
begin
while not Self.Terminated do
begin
{мои процедуры}
end;
end;
end
Nickla (2006-10-13 10:01:00) [1]Удалено модератором
Примечание: Создание пустых сообщений
Сергей М. (2006-10-11 15:43:00) [2]
> Nickla (11.10.06 15:27) [32]
Делфи-отладчик писан борландом не для Пушкина
Nickla (2006-10-11 15:36:00) [3]Нашел интереснейшую ссылку
http://www.achatfs.narod.ru/create_services_api.html
Nickla (2006-10-11 15:27:00) [4]У меня другая проблема
procedure TWebShotService.ServiceExecute(Sender: TService);
begin
while not Terminated do
begin
CameraEngine.WorkCamera;
ServiceThread.ProcessRequests(False);
Sleep(10);
end;
end;
Так вот все равно ошибка вылазиет при останове. Добавил Stoped := true все равно вылазиет.
CameraEngine.WorkCamera; работает максимум 1-10мс. То есть большой задержки нет. Но ошибка периодически вылазиет.
Гдето видел альтернативный способ создания приложения. Просто ощущение что это баг ДНК TServise
Сергей М. (2006-07-11 12:01:00) [5]
> мне тело сервиса надо выполнять раз в минуту или реже
Значит нужно организовать таймер и обрабатывать сообщение WM_TIMER
tesseract (2006-07-11 11:58:00) [6]> Как сделать "толковый" цикл?
> Если мне тело сервиса надо выполнять раз в минуту или реже
Делается два потока, один основной который ожидает сообщения - на исполнение или завершение, и второй, который по таймеру эти сообщения посылает основному.
Вроде на пальцах просто :-)
novill (2006-07-11 11:52:00) [7]
> Сергей М.
> Но это - для "бестолкового" цикла.
>
> "Толковый" же цикл может и должен использовать kernel time
> гораздо эффективней, нежели в "бестолковом" Sleep[Ex]
Как сделать "толковый" цикл?
Если мне тело сервиса надо выполнять раз в минуту или реже
isasa (2006-06-27 17:04:00) [8]Я так понял, идея такая. Поток при стопе, все-таки, должен "ответить"(завершиться)(вызвать SetServiceStatus (...) ) в течении ~1-2 сек.
Прибольшем интервале - проблемы.
При простейшем потоке - Sleep(3000) дает устойчивую ошибку завершения
тело ф-ции потока
swprintf_s(locbuf, MAX_LOG_STRLEN, L"%s Still running ...", pThData->srvName);
LogMsg(IDS_MSG111); //Main Thread Enter
while (pThData->goThread==0)
{
LogMsg(locbuf);
::Sleep(1000); // По задержке уже проблемы со стопом -> ::Sleep(3000);
}
LogMsg(IDS_MSG108); //Main Thread Exit
где
void WINAPI ServiceCtrlHandler (DWORD Opcode)
{
...
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
if (thData.goThread==0) {
thData.goThread = -1; // Нормальное завершение главного потока
if (Opcode==SERVICE_CONTROL_STOP) {
LogMsg(IDS_MSG109); //Stoped by system
} else {
LogMsg(IDS_MSG110); //SHUTDOWN by system
}
} else { // Ну если добрались до выполнения ветки - проблемы с логикой!
srvStat.dwCurrentState = SERVICE_STOPPED; //С принудительным сносом главного потока?
srvStat.dwWin32ExitCode = 0;
srvStat.dwCheckPoint = 0;
srvStat.dwWaitHint = 0;
LogMsg(IDS_MSG112); //Stoped by system. Call the ExitThread function for Main Thread(memory may be lost)
if (!SetServiceStatus (srvStatHandle, &srvStat))
LogMsg(IDS_MSG102, GetLastError());
}
return;
...
и, соответственно, в ф-ции сервиса
void WINAPI ServiceProc(DWORD argc, LPTSTR *argv)
{
...
//LogMsg(IDS_MSG104); //Create Main Thread
mhThread = CreateThread(NULL, 0, srvMainThread, &thData, 0, &mThId);
if (mhThread!=NULL) {
//LogMsg(IDS_MSG113); //Main Thread Created
WaitForSingleObject(mhThread, INFINITE);
CloseHandle(mhThread);
LogMsg(IDS_MSG105); //Leaving DiSpy
srvStat.dwCurrentState = SERVICE_STOPPED;
srvStat.dwWin32ExitCode = 0;
srvStat.dwCheckPoint = 0;
srvStat.dwWaitHint = 0;
if (!SetServiceStatus (srvStatHandle, &srvStat))
LogMsg(IDS_MSG102, GetLastError());
} else
LogMsg(IDS_MSG107); //Error Create Main Thread
return;
Сергей М. (2006-06-27 16:01:00) [9]
> по уму "рабочее тело" надо в отдельный поток выносить
Оно и так уже в отдельном потоке работает.
> novill © (27.06.06 10:11) [23]
В цикле этом достаточно сделать
ServiceThread.ProcessRequests(False);
..
Sleep(0);
Но это - для "бестолкового" цикла.
"Толковый" же цикл может и должен использовать kernel time гораздо эффективней, нежели в "бестолковом" Sleep[Ex]
han_malign (2006-06-27 13:44:00) [10]а-а-а - не поможет, погорячился...
по уму "рабочее тело" надо в отдельный поток выносить, либо действительно "квант" уменьшать...
han_malign (2006-06-27 13:40:00) [11]
> У меня методом "научного тыка" получилось чуть больше
- у меня, в таких случаях, существует Event (hStop: THandle)(:=CreateEvent(...)) который устанавливается в OnStop, и WaitForSingleObject - хоть INFINITE...
И "тело" обрабатывается только если (WaitForSingleObject(hStop, dwLatency) = WAIT_TIMEOUT)...
isasa (2006-06-27 13:10:00) [12]У меня методом "научного тыка" получилось чуть больше - SleepEx(1000,True).
200 - это слишком часто. :)
novill (2006-06-27 10:11:00) [13]Может понадобится кому...
Проблема остановки сервиса окончательно решена только заменой
SleepEx(<большое число>,True)
на цикл
for i:=1 to CheckPeriodSec*5 do
begin
ServiceThread.ProcessRequests(False);
if Self.Terminated then break;
SleepEx(200,True);
Сергей М. (2006-06-25 19:10:00) [14]Давай-ка, друг ситный, бросай свои эксперименты, читай уже справку и учись использовать встр.отладчик для отладкисервисов.
си. "Debugging service applications"
isasa (2006-06-24 11:31:00) [15]Отвлекли.
Или если надо выдержать именно 5000(по сну :) ), то что-то, вроде этого
<делаем что-то>
if Self.Terminated then break;
SleepEx(1000,true);
<делаем что-то>
if Self.Terminated then break;
SleepEx(1000,true);
<делаем что-то>
if Self.Terminated then break;
SleepEx(1000,true);
<делаем что-то>
if Self.Terminated then break;
SleepEx(1000,true);
<делаем что-то>
if Self.Terminated then break;
SleepEx(1000,true);
напоминает маразм, но помогает
isasa (2006-06-24 11:16:00) [16]
procedure TDS.ServiceExecute(Sender: TService);
while not Self.Terminated do
begin
...
SleepEx(5000,true);
end;
Долго спим. Хотя умные люди пишут, что интервал ожидания ответа ~20сек.
У меня на болванке сервиса проблемы с закрютием начинаются со Sleep(3000).
Попробуй уменьшить время сна.
novill (2006-06-23 17:34:00) [17]С доступом оказывается я ошибался - я локально подключался, а сервисы только через сеть работают, надо было через 127.0.0.1
Но не могу понять, почему выскакивает ошибка при останове сервиса :(
При попытки останова сервиса, процедура ServiceStop не выполняется, несмотря на то что повешена на событие onStop.
unit Unit1;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs;
type
TService1 = class(TService)
procedure ServiceExecute(Sender: TService);
procedure ServiceStop(Sender: TService; var Stopped: Boolean);
procedure ServiceStart(Sender: TService; var Started: Boolean);
procedure ServiceShutdown(Sender: TService);
public
function GetServiceController: TServiceController; override;
end;
var
Service1: TService1;
implementation
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
Service1.Controller(CtrlCode);
end;
function TService1.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
procedure TService1.ServiceExecute(Sender: TService);
var statfile:Text;
begin
AssignFile(statfile,'event.log');
while not Self.Terminated do
begin
ServiceThread.ProcessRequests(False);
Append(statfile); Writeln(statfile,DateTimeToStr(Now));
Flush(statfile);
SleepEx(5000,False);
end;
CloseFile(statfile);
end;
procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
var statfile:Text;
begin
Stopped:=true;
AssignFile(statfile,'event.log');
Append(statfile);
Writeln(statfile,'ServiceStop(');
Flush(statfile);
CloseFile(statfile);
end;
procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
var statfile:Text;
begin
AssignFile(statfile,'event.log');
Append(statfile);
Writeln(statfile,'ServiceStart(');
Flush(statfile);
CloseFile(statfile);
Started:=True;
end;
procedure TService1.ServiceShutdown(Sender: TService);
var statfile:Text;
begin
AssignFile(statfile,'event.log');
Append(statfile);
Writeln(statfile,'ServiceShutdown(');
Flush(statfile);
CloseFile(statfile);
end;
end.
Сергей М. (2006-06-23 14:25:00) [18]Какие компоненты доступа к IB используешь ?
novill (2006-06-23 14:20:00) [19]Сначала запускал как локальную службу, потом создал запись с админскими правами и запустил от ее имени - та же история :(
Сергей М. (2006-06-23 14:04:00) [20]Сервис с какими правами запущен ? От имени какого пользователя ?