![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Запуск программы как службы. Очень нужна помощь. [D5, Win2k, WinXP]
m52 © (2005-05-24 10:17:00)Здравствуйте!
--------------
Я написал программу на дельфи, которая при старте Windows загружается и сворачивается в SysTray. Возникла необходимость сделать возможность загрузки и работы этой программы как службы Windows.
Что для этого нужно?
Что нужно переделать в программе, чтобы она работала как служба?
Чем отличается код, написанный просто как приложение и код, написанный для работы приложения как службы.
Очень нужна помощь.
Заранее благодарен.
Warlock (2005-06-10 06:15:00) [1]Создаешь ServiceApplication. Код ServiceExecute:
procedure THaspRunnerService.ServiceExecute(Sender: TService);
var hwndHandle : THANDLE;
begin
WinExec('Путь и имя программы которую хочешь запускать',SW_SHOWMINNOACTIVE);
while not Terminated do
ServiceThread.ProcessRequests(True);
hwndHandle:=FindWindow(Nil, 'Тут заголовок главного окна программы');
if hwndHandle<>0 then
PostMessage(hwndHandle, WM_QUIT, 0, 0);
end;
Способ может не лучший, но работал
Digitman (2005-05-25 08:17:00) [2]
> ORMADA
NtQuerySystemInformation() infoclass = SystemProcessThreadInfo
ORMADA (2005-05-25 07:19:00) [3]тоже заинтересовала данная тема но только не понял как проанализировать что при старте сервис-процесса выступает процесс svchost.exe ?
==>Digitman © (24.05.05 11:17) [5]
вероятно, можно обойтись и без анализа ком.строки при принятии решения о ветвлении родительским процессом для вновь стартуемого сервис-процесса, по идее, должен выступать процесс svchost.exe .. это условие, вероятно, и следует анализировать в dpr при принятии решения
Игорь Шевченко (2005-05-24 18:07:00) [4]Digitman © (24.05.05 17:09) [16]
> а вроде ком.строка, имеющая в своем контексте ключи вида
> /install, не обязана быть ком.строкой, имеющей ОБЯЗАТЕЛЬНОЕ
> отношение к сервисам ?
Абсолютно не обязана. Я навскидку могу написать программу, которая по ключу /Install будет выполнять форматирование винчестера.
Я к другому - сервис, он обязан придерживаться протокола взаимодействия с менеджером сервисов, и прочая и прочая. И запускаться он (сервис) будет ТОЛЬКО services.exe и никем более.
Digitman (2005-05-24 17:10:00) [5]
> Eraser © (24.05.05 17:09) [15]
> Digitman © (24.05.05 17:04) [13]
>
> Так значит самый надёжный вариант определения сервис/несервис
> - проверять родительский процесс?
мне так показалось.
думаю, ИШ прояснит ситуацию ..
Digitman (2005-05-24 17:09:00) [6]
> Игорь Шевченко © (24.05.05 17:06) [14]
а вроде ком.строка, имеющая в своем контексте ключи вида /install, не обязана быть ком.строкой, имеющей ОБЯЗАТЕЛЬНОЕ отношение к сервисам ?
Eraser (2005-05-24 17:09:00) [7]Digitman © (24.05.05 17:04) [13]
Так значит самый надёжный вариант определения сервис/несервис - проверять родительский процесс?
имхо наверное тогда стОит проверять по параметру при запуске и не парить себе мОзги... )
Игорь Шевченко (2005-05-24 17:06:00) [8]Digitman © (24.05.05 12:16) [11]
> в BSS решение о ветвлении принимается опять же либо по наличию
> ключа в ком.строке либо по наличию соотв.записи в реестре.
А вроде без записи в реестре сервисом стать не получится ? Или я чего не понимаю ?
Digitman (2005-05-24 17:04:00) [9]
> Соответственно решение о том сервис/не_сервис принимается
> в ф-ии StartService...
да галиматья !!)
мало ли чего в реестре прописано !?)
я туда накидать всякой похожей дряни могу и безо всякого /INSTALL .. но от этого всяка дрянь, на которую я опять же могу сослаться из реестра, вовсе не обязана быть натурально сервисом ...
Eraser (2005-05-24 16:54:00) [10]Digitman © (24.05.05 12:16) [11]
Вот код загрузки приложения/сервиса:
begin
if not Installing then
begin
CreateMutex(nil, True, 'SCKTSRVR');
if GetLastError = ERROR_ALREADY_EXISTS then
begin
MessageBox(0, PChar(SAlreadyRunning), SApplicationName, MB_ICONERROR);
Halt;
end;
end;
if Installing or StartService then
begin
SvcMgr.Application.Initialize;
SocketService := TSocketService.CreateNew(SvcMgr.Application, 0);
SvcMgr.Application.CreateForm(TSocketForm, SocketForm);
SvcMgr.Application.Run;
end else
begin
Forms.Application.ShowMainForm := False;
Forms.Application.Initialize;
Forms.Application.CreateForm(TSocketForm, SocketForm);
SocketForm.Initialize(False);
Forms.Application.Run;
end;
end.
вот код ф-ии Installing
function Installing: Boolean;
begin
Result := FindCmdLineSwitch('INSTALL',['-','\','/'], True) or
FindCmdLineSwitch('UNINSTALL',['-','\','/'], True);
end;
Installing используется чисто для установки деинсталляции сервиса.
Соответственно решение о том сервис/не_сервис принимается в ф-ии StartService...
Или я что-то не допонял...
Тема интересная... самому в скором времени понадобится.
Digitman (2005-05-24 12:16:00) [11]
> Eraser
в BSS решение о ветвлении принимается опять же либо по наличию ключа в ком.строке либо по наличию соотв.записи в реестре.
Digitman (2005-05-24 12:08:00) [12]
> Eraser © (24.05.05 11:52) [9]
ты "смотришь в книгу - видишь фигу")
Eraser (2005-05-24 11:52:00) [13]Digitman © (24.05.05 11:48) [8]
Не! Это как раз по сабжу, просто название ф-ии с толку сбивает, надо было её называть IsStartService.
Digitman (2005-05-24 11:48:00) [14]
> Eraser © (24.05.05 11:40) [7]
ерунду городишь
это - из другой оперы и к сабжу никакого отношения не имеет
Eraser (2005-05-24 11:40:00) [15]Digitman © (24.05.05 11:17) [5]
В Borland Socket Server'e анализируется так:
function StartService: Boolean;
var
Mgr, Svc: Integer;
UserName, ServiceStartName: string;
Config: Pointer;
Size: DWord;
begin
Result := False;
Mgr := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
if Mgr <> 0 then
begin
Svc := OpenService(Mgr, PChar(SServiceName), SERVICE_ALL_ACCESS);
Result := Svc <> 0;
if Result then
begin
QueryServiceConfig(Svc, nil, 0, Size);
Config := AllocMem(Size);
try
QueryServiceConfig(Svc, Config, Size, Size);
ServiceStartName := PQueryServiceConfig(Config)^.lpServiceStartName;
if CompareText(ServiceStartName, 'LocalSystem') = 0 then
ServiceStartName := 'SYSTEM';
finally
Dispose(Config);
end;
CloseServiceHandle(Svc);
end;
CloseServiceHandle(Mgr);
end;
if Result then
begin
Size := 256;
SetLength(UserName, Size);
GetUserName(PChar(UserName), Size);
SetLength(UserName, StrLen(PChar(UserName)));
Result := CompareText(UserName, ServiceStartName) = 0;
end;
end;
m52 (2005-05-24 11:38:00) [16]Спасибо. Попробую.
Digitman (2005-05-24 11:17:00) [17]вероятно, можно обойтись и без анализа ком.строки при принятии решения о ветвлении
родительским процессом для вновь стартуемого сервис-процесса, по идее, должен выступать процесс svchost.exe .. это условие, вероятно, и следует анализировать в dpr при принятии решения
Digitman (2005-05-24 11:09:00) [18]это - в качестве комментария к ветвлению :
uses
Forms,
SvcMgr,
FormMain in 'SvcMain.pas' {MainForm: TMainForm},
SvcMain in 'SvcMain.pas' {MainForm: TForm},
{$R *.RES}
begin
//если в ком.строке обнаружен 1-й параметр '/GUI'
//стартуем как обычное приложение
if ParamStr(1) = '/GUI' then
begin
Forms.Application.Initialize;
Forms.Application.CreateForm(TMainForm, MainForm);
Forms.Application.Run;
end
//иначе как сервис-приложение
else
begin
SvcMgr.Application.Initialize;
SvcMgr.Application.CreateForm(TMainService, MainService);
SvcMgr.Application.Run;
end;
end.
Digitman (2005-05-24 10:46:00) [19]
> m52 (24.05.05 10:40) [2]
> Т.е. получается так, что нельзя сделать так, чтобы приложение
> запускалось опционально
> 1) как служба
> 2) как приложение
почему нельзя ? можно !
> Видимо нужно жестко завязывать код программы либо под службу,
> либо под приложение
.. либо реализовать такой алгоритм, который будет универсален, т.е. при запуске обычным образом пойдет по ветви для обычного приложения, а при запуске по соглашениям системы для сервисов - по иной ветви
m52 (2005-05-24 10:40:00) [20]Т.е. получается так, что нельзя сделать так, чтобы приложение запускалось опционально
1) как служба
2) как приложение
Видимо нужно жестко завязывать код программы либо под службу, либо под приложение.