delphi注册一个程序为系统服务后无法启动,错误1053???

tass0115 2010-02-22 10:04:35
我将一个普通程序注册为一个系统服务,使用代码见http://www.cnblogs.com/iinsnian/archive/2008/06/06/1214998.html
能成功创建服务,但调用启动服务的函数StartService失败;手动进入控制面板的服务窗口启动该服务,执行的到一半的时候提示错误1053:服务没有及时响应启动或控制请求。请高手看一下,是这段服务控制程序的问题吗?

另外,我在使用delphi的Service Application时,怎么创建一个可视化的服务程序?不希望在OnStart中创建窗口,这样只有在服务启动后才能看见窗口,不能作为普通程序使用;不知道为什么在OnCreate中创建窗口时,启动服务的时候会重复创建?

我的最终目的就是想创建一个可视化的程序,可以在其界面上注册、卸载服务(程序本身),就像FTP服务器Serv-U菜单里就有这样的选项。它既可以是一个普通程序,也可以作为服务运行。
...全文
2268 10 打赏 收藏 举报
写回复
10 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
FDZhong 2010-12-22
  • 打赏
  • 举报
回复
rels
tass0115 2010-02-26
  • 打赏
  • 举报
回复
谢谢 kuangning。我先研究一下
SQLDebug_Fan 2010-02-26
  • 打赏
  • 举报
回复
给你一篇说明文档,原帖地址:http://hi.baidu.com/sqldebug/blog/item/8e2749213082c0589922ed61.html

一、服务程序和桌面程序的区别

Windows 2000/XP/2003等支持一种叫做“系统服务程序”的进程,系统服务和桌面程序的区别是:
系统服务不用登陆系统即可运行;系统服务是运行在System Idle Process/System/smss/winlogon/services下的,而桌面程序是运行在Explorer下的;系统服务拥有更高的权限,系统服务拥有Sytem的权限,而桌面程序只有Administrator权限;在Delphi中系统服务是对桌面程序进行了再一次的封装,既系统服务继承于桌面程序。因而拥有桌面程序所拥有的特性;系统服务对桌面程序的DoHandleException做了改进,会自动把异常信息写到NT服务日志中;普通应用程序启动只有一个线程,而服务启动至少含有三个线程。(服务含有三个线程:TServiceStartThread服务启动线程;TServiceThread服务运行线程;Application主线程,负责消息循环);
摘录代码:
procedure TServiceApplication.Run;
begin
.
.
.
StartThread := TServiceStartThread.Create(ServiceStartTable);
try
while not Forms.Application.Terminated do
Forms.Application.HandleMessage;
Forms.Application.Terminate;
if StartThread.ReturnValue <> 0 then
FEventLogger.LogMessage(SysErrorMessage(StartThread.ReturnValue));
finally
StartThread.Free;
end;
.
.
.
end;

procedure TService.DoStart;
begin
try
Status := csStartPending;
try
FServiceThread := TServiceThread.Create(Self);
FServiceThread.Resume;
FServiceThread.WaitFor;
FreeAndNil(FServiceThread);
finally
Status := csStopped;
end;
except
on E: Exception do
LogMessage(Format(SServiceFailed,[SExecute, E.Message]));
end;
end;
在系统服务中也可以使用TTimer这些需要消息的定时器,因为系统服务在后台使用TApplication在分发消息;

二、如何编写一个系统服务

打开Delphi编辑器,选择菜单中的File|New|Other...,在New Item中选择Service Application项,Delphi便自动为你建立一个基于TServiceApplication的新工程,TserviceApplication是一个封装NT服务程序的类,它包含一个TService1对象以及服务程序的装卸、注册、取消方法。
TService属性介绍:
AllowPause:是否允许暂停;
AllowStop:是否允许停止;
Dependencies:启动服务时所依赖的服务,如果依赖服务不存在则不能启动服务,而且启动本服务的时候会自动启动依赖服务;
DisplayName:服务显示名称;
ErrorSeverity:错误严重程度;
Interactive:是否允许和桌面交互;
LoadGroup:加载组;
Name:服务名称;
Password:服务密码;
ServiceStartName:服务启动名称;
ServiceType:服务类型;
StartType:启动类型;
事件介绍:
AfterInstall:安装服务之后调用的方法;
AfterUninstall:服务卸载之后调用的方法;
BeforeInstall:服务安装之前调用的方法;
BeforeUninstall:服务卸载之前调用的方法;
OnContinue:服务暂停继续调用的方法;
OnExecute:执行服务开始调用的方法;
OnPause:暂停服务调用的方法;
OnShutDown:关闭时调用的方法;
OnStart:启动服务调用的方法;
OnStop:停止服务调用的方法;

三、编写一个两栖服务

采用下面的方法,可以实现一个两栖系统服务(既系统服务和桌面程序的两种模式)
工程代码:
program FleetReportSvr;

uses
SvcMgr,
Forms,
SysUtils,
Windows,
SvrMain in 'SvrMain.pas' {FleetReportService: TService},
AppMain in 'AppMain.pas' {FmFleetReport};

{$R *.RES}

const
CSMutexName = 'Global\Services_Application_Mutex';
var
OneInstanceMutex: THandle;
SecMem: SECURITY_ATTRIBUTES;
aSD: SECURITY_DESCRIPTOR;
begin
InitializeSecurityDescriptor(@aSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(@aSD, True, nil, False);
SecMem.nLength := SizeOf(SECURITY_ATTRIBUTES);
SecMem.lpSecurityDescriptor := @aSD;
SecMem.bInheritHandle := False;
OneInstanceMutex := CreateMutex(@SecMem, False, CSMutexName);
if (GetLastError = ERROR_ALREADY_EXISTS)then
begin
DlgError('Error, Program or service already running!');
Exit;
end;
if FindCmdLineSwitch('svc', True) or
FindCmdLineSwitch('install', True) or
FindCmdLineSwitch('uninstall', True) then
begin
SvcMgr.Application.Initialize;
SvcMgr.Application.CreateForm(TSvSvrMain, SvSvrMain);
SvcMgr.Application.Run;
end
else
begin
Forms.Application.Initialize;
Forms.Application.CreateForm(TFmFmMain, FmMain);
Forms.Application.Run;
end;
end.
然后在SvrMain注册服务:
unit SvrMain;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs, MsgCenter;

type
TSvSvrMain = class(TService)
procedure ServiceStart(Sender: TService; var Started: Boolean);
procedure ServiceStop(Sender: TService; var Stopped: Boolean);
procedure ServiceBeforeInstall(Sender: TService);
procedure ServiceAfterInstall(Sender: TService);
private
{ Private declarations }
public
function GetServiceController: TServiceController; override;
{ Public declarations }
end;

var
SvSvrMain: TSvSvrMain;

implementation

const
CSRegServiceURL = 'SYSTEM\CurrentControlSet\Services\';
CSRegDescription = 'Description';
CSRegImagePath = 'ImagePath';
CSServiceDescription = 'Services Sample.';

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
SvSvrMain.Controller(CtrlCode);
end;

function TSvSvrMain.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;

procedure TSvSvrMain.ServiceStart(Sender: TService;
var Started: Boolean);
begin
Started := dmPublic.Start;
end;

procedure TSvSvrMain.ServiceStop(Sender: TService;
var Stopped: Boolean);
begin
Stopped := dmPublic.Stop;
end;

procedure TSvSvrMain.ServiceBeforeInstall(Sender: TService);
begin
RegValueDelete(HKEY_LOCAL_MACHINE, CSRegServiceURL + Name, CSRegDescription);
end;

procedure TSvSvrMain.ServiceAfterInstall(Sender: TService);
begin
RegWriteString(HKEY_LOCAL_MACHINE, CSRegServiceURL + Name, CSRegDescription,
CSServiceDescription);
RegWriteString(HKEY_LOCAL_MACHINE, CSRegServiceURL + Name, CSRegImagePath,
ParamStr(0) + ' -svc');
end;

end.
这样,双击程序,则以普通程序方式运行,若用服务管理器来运行,则作为服务运行。
例如公共模块:
dmPublic,提供Start,Stop方法。

在主窗体中,调用dmPublic.Start,dmPublic.Stop方法。
同样在Service中,调用dmPublic.Start,dmPublic.Stop方法。
kuangning 2010-02-23
  • 打赏
  • 举报
回复
建议你搜索下 两栖系统的相关帖子。手里面没delphi 上面代码是参照以前一些代码改出来了,还不知道能否编译
kuangning 2010-02-23
  • 打赏
  • 举报
回复
我的最终目的就是想创建一个可视化的程序,可以在其界面上注册、卸载服务(程序本身),就像FTP服务器Serv-U菜单里就有这样的选项。它既可以是一个普通程序,也可以作为服务运行。
------------------
两栖系统服务。你可以在工程文件中来进行判断。


program Test;

uses
SvcMgr,
Forms,
SysUtils,
Windows,
SvrMain in 'SvrMain.pas' {TestService: TService},
AppMain in 'AppMain.pas' {MainFM};

{$R *.RES}

const
CSMutexName = 'Global\Services_Application_Mutex';
var
OneInstanceMutex: THandle;
SecMem: SECURITY_ATTRIBUTES;
aSD: SECURITY_DESCRIPTOR;
begin
InitializeSecurityDescriptor(@aSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(@aSD, True, nil, False);
SecMem.nLength := SizeOf(SECURITY_ATTRIBUTES);
SecMem.lpSecurityDescriptor := @aSD;
SecMem.bInheritHandle := False;
OneInstanceMutex := CreateMutex(@SecMem, False, CSMutexName);
if (GetLastError = ERROR_ALREADY_EXISTS)then
begin
//抛出异常 :'出错, 程序或者服务以及运行'
Exit;
end;
if FindCmdLineSwitch('svc', True) or
FindCmdLineSwitch('install', True) or
FindCmdLineSwitch('uninstall', True) then
begin
SvcMgr.Application.Initialize;
SvcMgr.Application.CreateForm(TTestService, TestService);
SvcMgr.Application.Run;
end
else
begin
Forms.Application.Initialize;
Forms.Application.CreateForm(TMainFM, MainFM);
Forms.Application.Run;
end;
end.


不希望在OnStart中创建窗口,这样只有在服务启动后才能看见窗口,不能作为普通程序使用;不知道为什么在OnCreate中创建窗口时,启动服务的时候会重复创建?

根据上面的两栖系统,你这个问题也不将存在。因为在作为应用程序直接运行的时候 你的服务根本不会创建 也就谈不上启动了。
说白了 上面的代码就是 作为服务的时候把TTestService看作主窗体创建,他要来控制可视化界面的启动。作为桌面应用程序,MainFM就是主窗体类。TTestService更不不会创建。所以你程序的主要功能不能和TTestService耦合。
下面是在onstart中创建MainFM的代码

procedure TXXXXX.ServiceStart(Sender: TService; var Started: Boolean);
begin
Started := True;
try
Svcmgr.Application.CreateForm(TMainFM, MainFM);
except
Started:=False;
Exit;
end;
Mainfm.Show;
end;
tass0115 2010-02-22
  • 打赏
  • 举报
回复
Up 顶一下 !!!
tass0115 2010-02-22
  • 打赏
  • 举报
回复
引用 1 楼 gyk120 的回复:
你没有设置成与系统交互吧?把属性的Interactive设置成True

已设置过了
gyk120 2010-02-22
  • 打赏
  • 举报
回复
你没有设置成与系统交互吧?把属性的Interactive设置成True
tass0115 2010-02-22
  • 打赏
  • 举报
回复
Up Up Up 再顶一下 !!!
相关推荐
发帖
Windows SDK/API

1177

社区成员

Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
帖子事件
创建了帖子
2010-02-22 10:04
社区公告
暂无公告