十万火急!超值大奉送!有关如何编程启动或停止NT服务的问题
我用Resoue kit中的srvany.exe将我的程序作为Nt的服务运行,我这里想问的是,除了
从控制面板中的服务标签启动或停止我的服务,我该如何编一个外面的程序来启动或停止我的服务,请各位大虾点拨一二,告诉我去查哪一个函数,或更改注册表中哪一项?
问题点数:60、回复次数:6Top
1 楼vcmfc(【痛苦的虫虫】)回复于 2001-01-04 11:58:00 得分 20
Windows NT 下Service 的 编 程
江 苏 省 电 信 传 输 局
周 晓
---- Windows NT Server 提 供 多 种 功 能 强 大 的 服 务(Service), 例 如FTP,WWW 或 远 程 登 录 服 务, 另 外 常 用 的 数 据 库 服 务 器 也 是 以Service 的 形 式 存 在 于NT Server 上 的, 如Sybase SQL Server For NT。Service 一 般 在NT 启 动 时 自 动 启 动, 在NT 关 机 时 停 止。 但 是 有 时 用 户 可 能 想 手 工 启 动﹑ 暂 停﹑ 停 止 某 项Service, 这 就 需 要 在 控 制 面 板 中 进 行 配 置, 对 于 不 太 熟 悉NT 的 用 户 来 说 比 较 困 难; 对 于 软 件 开 发 人 员, 有 时 需 要 在 软 件 中 访 问 和 操 作 某 项Service, 甚 至 可 能 需 要 开 发 新Service 的 提 供 给 用 户 使 用。 上 面 两 种 情 况 都 可 以 通 过 对Service 的 编 程 来 解 决。 对Service 的 编 程 涉 及 到NT 的 内 核, 比 较 复 杂 且 相 关 资 料 较 少, 给 软 件 开 发 人 员 带 来 很 多 困 难, 笔 者 通 过 对Windows NT 的API 的 分 析 找 到 了 相 应 的 编 程 方 法, 再 此 介 绍 给 大 家。
---- 在Windows NT 下, 各 种Service 都 存 在service control manager database 中, 因 此 我 们 可 以 通 过 对service control manager database 进 行 操 作 来 实 现 对Service 的 编 程。 下 面 介 绍 常 用 的 函 数:
1:SC_HANDLE OpenSCManager
(LPCTSTR lpszMachineName,
LPCTSTR lpszDatabaseName,
DWORD fdwDesiredAccess);
---- OpenSCManager 函 数 打 开 指 定 计 算 机 上 的service control manager database 。 其 中 参 数lpszMachineName 指 定 计 算 机 名, 若 为 空 则 指 定 为 本 机。 参 数lpszDatabaseName 指 定 要 打 开 的service control manager database, 默 认 为 空。
---- 参 数fdwDesiredAccess 指 定 操 作 的 权 限, 可 以 为 下 面 取 值 之 一
SC_MANAGER_ALL_ACCESS //所有权限
SC_MANAGER_CONNECT
//允许连接service control manager
SC_MANAGER_CREATE_SERVICE
//允许创建服务对象并把它加入
service control manager database
SC_MANAGER_ENUMERATE_SERVICE
//允许枚举service control manager database中的服务
SC_MANAGER_LOCK
//允许锁住service control manager database
SC_MANAGER_QUERY_LOCK_STATUS
//允许获取service control manager database的封锁信息
---- 函 数 返 回 值: 函 数 执 行 成 功 则 返 回 一 个 指 向service control manager database 的 句 柄, 失 败 则 返 回NULL。
2:SC_HANDLE OpenService
(SC_HANDLE schSCManager,
LPCTSTR lpszServiceName,
DWORD fdwDesiredAccess);
---- OpenService 函 数 打 开 指 定 的Service。
---- 其 中 参 数schSCManager 是 指 向service control manager database 的 句 柄, 由OpenSCManager 函 数 返 回。
---- 参 数lpszServiceName 要 打 开 的 服 务 的 名 字, 注 意 大 小 写。
---- 参 数fdwDesiredAccess 指 定 操 作 的 权 限, 可 以 为 下 面 取 值 之 一
SERVICE_ALL_ACCESS
//所有权限
SERVICE_CHANGE_CONFIG
//允许更改服务的配置
SERVICE_ENUMERATE_DEPENDENTS
//允许获取依赖于该服务的其他服务
SERVICE_INTERROGATE
//允许立即获取服务状态
SERVICE_PAUSE_CONTINUE
//允许暂停和唤醒服务
SERVICE_QUERY_CONFIG
//允许获取服务配置
SERVICE_QUERY_STATU
//允许通过访问service control manager获取服务状态
SERVICE_START
//允许启动服务
SERVICE_STOP
//允许停止服务
SERVICE_USER_DEFINE_CONTROL
//允许用户指定特殊的服务控制码
---- 函 数 返 回 值: 函 数 执 行 成 功 则 返 回 指 向 某 项 服 务 的 句 柄, 失 败 则 返 回NULL。
3:BOOL QueryServiceStatus
(SC_HANDLE schService,
LPSERVICE_STATUS lpssServiceStatus);
---- QueryServiceStatus函数返回指定服务的当前状态。
---- 其中参数schService是指向某项服务的句柄,由OpenService函数返回,且必须SERVICE_QUERY_STATUS的权限。
---- 参数lpssServiceStatus中存放返回的服务状态信息,结构如下
typedef struct _SERVICE_STATUS {
DWORD dwServiceType;
//服务类型
DWORD dwCurrentState;
//当前状态
DWORD dwControlsAccepted;
//服务可接受的控制码
DWORD dwWin32ExitCode;
//Win32出错代码
DWORD dwServiceSpecificExitCode;
//服务出错代码
DWORD dwCheckPoint;
//用于跟踪服务长时间操作
DWORD dwWaitHint;
//服务某一操作的最大允许时间,以毫秒为单位
} SERVICE_STATUS, *LPSERVICE_STATUS;
---- 函 数 返 回 值: 函 数 执 行 成 功 则 返 回True, 失 败 则 返 回False。
4:BOOL StartService(SC_HANDLE schService,
DWORD dwNumServiceArgs,
LPCTSTR *lpszServiceArgs);
---- StartService 函 数 启 动 指 定 的 服 务。
---- 其 中 参 数schService 是 指 向 某 项 服 务 的 句 柄, 由OpenService 函 数 返 回, 且 必 须 有SERVICE_START 的 权 限。
---- dwNumServiceArgs 为 启 动 服 务 所 需 的 参 数 的 个 数。
---- lpszServiceArgs 为 启 动 服 务 所 需 的 参 数。 函 数 返 回 值: 函 数 执 行 成 功 则 返 回True, 失 败 则 返 回False。
5:BOOL ControlService(
SC_HANDLE hService,
DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus);
---- ControlService 函 数 向Win32 service 发 送 控 制 码。
---- 其 中 参 数hService 是 指 向 某 项 服 务 的 句 柄, 由OpenService 函 数 返 回。
---- 参 数dwControl 为 控 制 码, 常 用 的 有
SERVICE_CONTROL_STOP
//停止服务
SERVICE_CONTROL_PAUSE
//暂停服务
SERVICE_CONTROL_CONTINUE
//唤醒暂停的服务
SERVICE_CONTROL_INTERROGATE
//刷新某服务的状态
---- 参 数lpServiceStatus 指 向SERVICE_STATUS 结 构, 用 于 存 放 该 服 务 最 新 的 状 态 信 息。
---- 函 数 返 回 值: 函 数 执 行 成 功 则 返 回True, 失 败 则 返 回False。
6:BOOL EnumServicesStatus
(SC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
LPENUM_SERVICE_STATUS lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned,
LPDWORD lpResumeHandle);
---- EnumServicesStatus 函 数 用 于 枚 举NT 下 存 在 的Service。
---- 其 中 参 数hSCManager 是 指 向service control manager database 的 句 柄, 由OpenSCManager 函 数 返 回, 且 必 须 有SC_MANAGER_ENUMERATE_SERVICE 的 权 限。
---- 参 数dwServiceType 指 定 按 服 务 的 类 型 枚 举。
---- 参 数dwServiceState 指 定 按 服 务 的 状 态 枚 举。
---- 参 数lpServices 指 向ENUM_SERVICE_STATUS 结 构, 用 于 存 放 返 回 的 服 务 的 名 字 和 状 态 信 息。
---- 参 数cbBufSize 返 回 参 数lpServices 的 长 度, 以 字 节 为 单 位。
---- 参 数pcbBytesNeeded 返 回 获 取 剩 余 的Service 所 需 字 节 的 个 数。
---- 参 数lpServicesReturned 返 回 服 务 的 个 数。
---- 参 数lpResumeHandle, 当 第 一 次 调 用 时 该 参 数 为0, 当 该 函 数 再 次 被 调 用 以 获 取 另 外 的 信 息 时, 该 参 数 表 示 下 一 个 被 读 的Service。
---- 函 数 返 回 值: 函 数 执 行 成 功 则 返 回True, 失 败 则 返 回False。
---- 值 得 注 意 的 是 通 常 情 况 下 该 函 数 返 回 的 结 果 为FALSE, 我 们 可 以 调 用GetLastError() 来 获 取 进 一 步 信 息。 因 为 一 台 机 器 上 有 多 种 服 务 存 在, 所 以GetLastError() 应 为ERROR_MORE_DATA, 此 时 应 再 次 调 用EnumServicesStatus 函 数 以 获 取 正 确 的Service 列 表。
---- 下 面 有 一 个 用Delphi 编 的 一 个 程 序 例 子, 用 其 他 开 发 工 具 如VC,VB 也 可 实 现。 程 序 运 行 时, 单 击 按 钮Button1 枚 举NT 中 的Service 并 显 示 在 列 表 框ListBox1 中。 在ListBox1 选 中 某 个Service, 单 击 按 钮Button2 则 启 动 该Service, 单 击 按 钮Button3 则 停 止 该Service。
unit Unit1;
interface
uses
Windows,Messages, SysUtils, Classes,
Graphics,Controls,Forms,
Dialogs,StdCtrls,Winsvc;
type
TForm1 = class(TForm)
ListBox1: TlistBox;
Button1: Tbutton;
Button2: Tbutton;
Button3: Tbutton;
procedure Button1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClose
(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
hscmanager,hService:SC_HANDLE;
returnstatus:TServiceStatus;
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
BytesNeeded,serviceReturned,resumeHandle:Dword;
returnflag:Bool;
lpservice:Array[0..100] of TEnumServiceStatus;
service:TEnumServiceStatus;
i,bytes:Dword;
begin
ListBox1.Items.Clear;
returnflag:=false;
resumeHandle:=0;
hscmanager:=OpenSCManager(nil,nil,SC_MANAGER
_ENUMERATE_SERVICE);// 打开
service control manager database
if hscmanager<0 then
Begin
showmessage('无法打开
service control manager database');
exit;
End;
returnflag:=EnumServicesStatus(hscmanager,
SERVICE_DRIVER,SERVICE_ACTIVE,
service,sizeof(service),BytesNeeded,serviceR
eturned,resumeHandle);
//枚举Service
if (returnflag=false) and (GetLastError()
=ERROR_MORE_DATA) then
begin
bytes:=BytesNeeded+sizeof(TEnumServiceStatus);
EnumServicesStatus(hscmanager,SERVICE_
DRIVER,SERVICE_ACTIVE,
lpservice[0],bytes,BytesNeeded,service
Returned,resumeHandle);
for i:=0 to serviceReturned-1 do
begin
ListBox1.Items.Add(lpservice[i].lpServiceName);
end;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
i:integer;
lpServiceArgVectors:Pchar;
begin
lpServiceArgVectors:=nil;
for i :=0 to (ListBox1.Items.Count-1) do
if ListBox1.Selected[i] then
begin
hService:=OpenService(hscmanager,Pchar
(ListBox1.Items[i]),SERVICE_ALL_ACCESS);
//打开该Service
if hService<0 then
begin
showmessage('无法打开该Service');
exit;
end;
QueryServiceStatus(hService,returnstatus);
//查看该Service的状态
if returnstatus.dwCurrentState=SERVICE_STOPPED
then //如果该Service已停止则启动它
StartService(hService,0,lpServiceArgVectors);
CloseServiceHandle(hService);//关闭该Service
end;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
i:integer;
begin
for i :=0 to (ListBox1.Items.Count-1) do
if ListBox1.Selected[i] then
begin
hService:=OpenService(hscmanager,Pchar
(ListBox1.Items[i]),SERVICE_ALL_ACCESS);
//打开该Service
if hService<0 then
begin
showmessage('无法打开该Service');
exit;
end;
QueryServiceStatus(hService,returnstatus);
查看该Service的状态
if returnstatus.dwCurrentState=
SERVICE_RUNNING then
//如果该Service正在运行则停止它
ControlService(hService,SERVICE
_CONTROL_STOP,returnstatus);
CloseServiceHandle(hService);//关闭该Service
end;
end;
procedure TForm1.FormClose
(Sender: TObject; var Action: TCloseAction);
begin
CloseServiceHandle(hscmanager);
//关闭service control manager database
End;
end.Top
2 楼ab(ab)回复于 2001-01-04 12:13:00 得分 0
好像用命令行也行。Top
3 楼vcmfc(【痛苦的虫虫】)回复于 2001-01-04 13:12:00 得分 0
那是最简单的方法。Top
4 楼adrianx(蓝色心情)回复于 2001-01-04 13:27:00 得分 0
to ab
命令行不 一定对所有的服务有用,要是服务程序与服务控制程序是写在一起,且支执命令行的,就可以Top
5 楼taolei(实在无聊)回复于 2001-01-04 14:59:00 得分 20
给你个VC的例子
// service.cpp : Defines the entry point for the console application.
//
// Written By TaoLei 2000.11
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
inline const char* FormatError(char * buffer, DWORD cbbuffer,DWORD nErr=0)
{
if (nErr==0)
nErr=::GetLastError();
if (nErr == 0)
return NULL;
DWORD dwLen = ::FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,NULL,
nErr,NULL,buffer,cbbuffer,NULL);
buffer[dwLen] = NULL;
return buffer;
}
inline int PrintError(DWORD nErr=0)
{
if (nErr == 0)
nErr = ::GetLastError();
char temp[1024];
const char* s = FormatError(temp,sizeof(temp),nErr);
printf("Win32 Error(%d) %s\n",nErr,s);
return (int)nErr;
}int usage()
{
printf("usage service start|stop|status|pause|continue [machine\\]servicename\n");
printf("or service list [machine]\n");
return -1;
}
char temp[8];
const char* ServiceType(DWORD type)
{
if (type & SERVICE_DRIVER)
return "Driver";
else if(type & SERVICE_WIN32)
return "";
else
{
sprintf(temp,"%d",type);
return temp;
}
}
const char* StatusText(DWORD st)
{
switch(st)
{
case SERVICE_STOPPED:
return "Stopped";
case SERVICE_START_PENDING:
return "Start Pending";
case SERVICE_STOP_PENDING:
return "Stop Pending";
case SERVICE_RUNNING:
return "Running";
case SERVICE_CONTINUE_PENDING:
return "Continue Pending";
case SERVICE_PAUSE_PENDING:
return "Service Pause";
case SERVICE_PAUSED:
return "Paused";
default:
sprintf(temp,"%d",st);
return temp;
}
}
int listservices(char* Machine)
{
SC_HANDLE hManager = ::OpenSCManager(Machine,NULL,SC_MANAGER_ALL_ACCESS);
ENUM_SERVICE_STATUS ss[1024];
DWORD cbn=0;
DWORD svs=0;
DWORD rh=0;
BOOL bOK = ::EnumServicesStatus(
hManager,
SERVICE_WIN32|SERVICE_DRIVER,
//SERVICE_STATE_ALL,
SERVICE_ACTIVE,
ss,sizeof(ss),&cbn,&svs,&rh);
if (bOK)
{
for(DWORD i=0;i<svs;i++)
{
printf("%s\t%s\t%s\t%s\n",
ss[i].lpServiceName,
ss[i].lpDisplayName ,
StatusText(ss[i].ServiceStatus.dwCurrentState),
ServiceType(ss[i].ServiceStatus.dwServiceType));
}
}
else
{
PrintError();
}
return 0;
}
int main(int argc, char* argv[])
{
int cmd=-1;
DWORD Flag = 0;
if ((argc == 2 || argc == 3)
&& strcmp(argv[1],"list")==0)
{
return listservices((argc == 3)?argv[2]:NULL);
}
if (argc != 3)
return usage();
if (strcmp(argv[1],"start")==0)
{
cmd = 0;
Flag = SERVICE_START|SERVICE_QUERY_STATUS;
}
else if (strcmp(argv[1],"stop")==0)
{
cmd = 1;
Flag = SERVICE_STOP|SERVICE_QUERY_STATUS;
}
else if (strcmp(argv[1],"status")==0)
{
cmd = 2;
Flag = SERVICE_QUERY_STATUS;
}
else if (strcmp(argv[1],"pause")==0)
{
cmd = 3;
Flag = SERVICE_PAUSE_CONTINUE|SERVICE_QUERY_STATUS;
}
else if (strcmp(argv[1],"continue")==0)
{
cmd = 4;
Flag = SERVICE_PAUSE_CONTINUE|SERVICE_QUERY_STATUS;
}
else
return usage();
char Machine[_MAX_PATH];
char Service[_MAX_PATH];
char *p = strchr(argv[2],'\\');
if (p == NULL)
{
Machine[0] = NULL;
strcpy(Service,argv[2]);
}
else
{
strcpy(Machine,argv[2]);
p += Machine-argv[2];
*p = NULL;
strcpy(Service,p+1);
}
SC_HANDLE hManager = ::OpenSCManager(Machine,NULL,SC_MANAGER_ALL_ACCESS);
if (hManager == NULL)
{
PrintError();
return -1;
}
SC_HANDLE hService = ::OpenService(hManager,Service,Flag);
if (hService == NULL)
{
PrintError();
return -1;
}
BOOL bOK=TRUE;
SERVICE_STATUS status;
switch(cmd)
{
case 0:
bOK = ::StartService(hService,0,NULL);
break;
case 1:
bOK = ::ControlService(hService,SERVICE_CONTROL_STOP,&status);
break;
case 2:
bOK = ::QueryServiceStatus(hService,&status);
break;
case 3:
bOK = ::ControlService(hService,SERVICE_CONTROL_PAUSE,&status);
break;
case 4:
bOK = ::ControlService(hService,SERVICE_CONTROL_CONTINUE,&status);
break;
default:
break;
}
if (bOK)
{
if (cmd != 2)
{
int n = 50;
while(n-- > 0 && bOK)
{
::Sleep(100);
bOK = ::QueryServiceStatus(hService,&status);
if (status.dwCurrentState == SERVICE_STOPPED
|| status.dwCurrentState == SERVICE_RUNNING
|| status.dwCurrentState == SERVICE_PAUSED)
break;
}
}
if (bOK)
printf("Service Status = %s\n",StatusText(status.dwCurrentState));
}
if (!bOK)
{
PrintError();
return -1;
}
return 0;
}
Top
6 楼adrianx(蓝色心情)回复于 2001-01-04 15:15:00 得分 20
void StartService(LPCTSTR lpRemoteName,LPCTSTR lpszServiceName)
{
SC_HANDLE hSCMang = OpenSCManager(lpRemoteName,//服务在哪台机器上"\\ComputerName",NULL是指本机
SERVICES_ACTIVE_DATABASE,SC_MANAGER_ALL_ACCESS);
if(hSCMan==NULL)
return ;
SC_HANDLE hService = OpenService(hSCMang,lpszServiceName,
SERVICE_QUERY_STATUS|SERVICE_START,//允许调用QueryServiceStatus 查询与允许启动
);
if(hService==NULL)
{
CloseServiceHandle(hSCMang);
return ;
}
SERVICE_STATUS server_S
BOOL b = QueryServiceStatus(hService,&server_S);
if(b)
{
if(server_S.dwCurrentState == SERVICE_STOPPED)
{
b = StartService(hService,
0,NULL);//由于不需要运行参数所以指定
if(b)
{
OutputDebugString("Service Started by you!!!");
}
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCMang);
}
void StopService(LPCTSTR lpRemoteName,LPCTSTR lpszServiceName)
{
SC_HANDLE hSCMang = OpenSCManager(lpRemoteName,//服务在哪台机器上"\\ComputerName",NULL是指本机
SERVICES_ACTIVE_DATABASE,SC_MANAGER_ALL_ACCESS);
if(hSCMan==NULL)
return ;
SC_HANDLE hService = OpenService(hSCMang,lpszServiceName,
SERVICE_QUERY_STATUS|SERVICE_STOP,//允许调用QueryServiceStatus 查询与允许停止
);
if(hService==NULL)
{
CloseServiceHandle(hSCMang);
return ;
}
SERVICE_STATUS server_S
BOOL b = QueryServiceStatus(hService,&server_S);
if(b)
{
if(server_S.dwCurrentState == SERVICE_RUNNING)
{
b = ControlService(hService,
SERVICE_CONTROL_STOP,&server_S);//由于不需要运行参数所以指定
if(b)
{
OutputDebugString("Service stopped by you!!!");
}
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCMang);
}
================================Top




