Windows服务编程

先说明,本文不是编写服务,而是编程控制已有的服务。

服务是一种程序类型,它在后台运行,服务程序通常可以在本地和通过网络为用户提供一些功能。服务程序可能是EXE程序,具有其单独的进程,也有可能是DLL文件依附于某个进程,更有可能是SYS文件而处于系统的内核之中。

在Windows下,可以在“我的电脑”上单击鼠标右键,然后再弹出的菜单上选择“管理”,打开“计算机管理工具”,单击左面树形列表的“服务和应用程序”会打开子列表,选择“服务”,则在右侧出现服务列表项。也可以直接在“运行”窗口输入“services.msc”,打开服务管理器。服务管理器主要用于显示系统中已经存在的应用程序服务,显示对服务的描述,还可以控制服务的启动状态和启动方式。服务管理器界面如下图示:

服务编程常用API如下:

1. 打开服务管理器

SC_HANDLEOpenSCManager(
 LPCTSTR lpMachineName,//指向欲打开服务控制器数据库的目标主机名,本机则设置为NULL
LPCTSTRlpDatabaseName,//指向目标主机SCM数据库名字字符串
DWORD dwDesiredAccess//指定对SCM数据库的访问权限
);

2. 关闭服务句柄

BOOL CloseServiceHandle(
SC_HANDLEhSCObject//要关闭的服务或服务管理器句柄
);

3.服务的枚举

BOOL EnumServicesStatus(
  SC_HANDLE hSCManager,//OpenSCManager函数返回的句柄
  DWORD dwServiceType,//指定枚举服务类型
  DWORD dwServiceState,//枚举指定状态的服务
  LPENUM_SERVICE_STATUS lpServices,//结构体指针
  DWORD cbBufSize,//指定缓冲区大小
  LPDWORD pcbBytesNeeded,//返回实际使用的内存空间大小
  LPDWORD lpServicesReturned,//返回枚举服务的个数
  LPDWORD lpResumeHandle//返回枚举是否成功
);

4.打开指定服务

SC_HANDLEOpenService(
  SC_HANDLE hSCManager,//指定由OpenSCManager函数打开的服务句柄
  LPCTSTR lpServiceName,//指定要打开的服务名称
  DWORD dwDesiredAccess//打开服务的访问权限,为了方便,可指定为SC_MANAGER_ALL_ACCESS。
);

5.启动服务

BOOL StartService(
  SC_HANDLE hService,//指定要启动服务的句柄,该句柄由OpenService函数返回
  DWORD dwNumServiceArgs,//指向启动服务所需的参数个数
  LPCTSTR* lpServiceArgVectors//指向启动服务的参数
);

6.停止服务

BOOL ControlService(
  SC_HANDLE hService,//指定一个由OpenService打开的服务句柄
  DWORD dwControl,//指定要发送的控制码
  LPSERVICE_STATUS lpServiceStatus//返回服务的状态
);

ControlService()可以对服务进行多种控制,每种控制操作对应一种控制码。当要停止服务时,使用的控制码是SERVICE_CONTROL_STOP。

下面我们就写一个工程,实现电脑上Win32程序服务与驱动服务的分别展示,并且可以停止或者启动其中指定的服务。

用MFC搭建一个有如下界面的Dialog程序:

每个控件的作用相信大家都看得出来,界面方面的知识就不一一介绍了,直接上关键的控制代码。

其中CListCtrl控件的初始化可以参考注册表操作那篇博客。

实现服务枚举的代码如下:

VOID CMyDlg::ShowServiceList(DWORD dwServiceType)//参数是要枚举的服务类型
{
	m_ServiceList.DeleteAllItems();
	//打开服务管理器
	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(NULL == hSCM)
	{
		AfxMessageBox("Open SCManager Error!");
		return;
	}

	DWORD ServiceCount = 0;
	DWORD dwSize = 0;
	LPENUM_SERVICE_STATUS lpInfo;

	//第一次调用
	BOOL bRet = EnumServicesStatus(hSCM,
				dwServiceType, SERVICE_STATE_ALL,
				NULL,0,&dwSize,
				&ServiceCount,NULL);

	/*
	由于没有给定接收服务列表的缓冲区,这里必定会调用失败
	失败的返回值时ERROR_MORE_DATA
	说明需要更大的缓冲区来保存数据
	*/

	if(!bRet && GetLastError() == ERROR_MORE_DATA)
	{
		//分配缓冲区保存服务列表
		lpInfo = (LPENUM_SERVICE_STATUS)(new BYTE[dwSize]);
		bRet = EnumServicesStatus(hSCM,
				dwServiceType, SERVICE_STATE_ALL,
				(LPENUM_SERVICE_STATUS)lpInfo,
				dwSize,&dwSize,
				&ServiceCount,NULL);
		if(!bRet)
		{
			CloseServiceHandle(hSCM);
			return;
		}

		//逐个获取数据,添加至列表控件
		for(DWORD i = 0; i < ServiceCount; ++i)
		{
			CString str;
			m_ServiceList.InsertItem(i, lpInfo[i].lpServiceName);
			m_ServiceList.SetItemText(i, 1, lpInfo[i].lpDisplayName);
			switch(lpInfo[i].ServiceStatus.dwCurrentState)
			{
			case SERVICE_PAUSED:
				{
					m_ServiceList.SetItemText(i, 2, "暂停");
					break;
				}
			case SERVICE_STOPPED:
				{
					m_ServiceList.SetItemText(i, 2, "停止");
					break;
				}
			case SERVICE_RUNNING:
				{
					m_ServiceList.SetItemText(i, 2, "运行");
					break;
				}
			default:
				{
					m_ServiceList.SetItemText(i, 2, "其它");
				}
			}
		}

		//释放申请的空间
		delete lpInfo;
	}

	//关闭服务管理器句柄
	CloseServiceHandle(hSCM);
}

启动服务的代码:

void CMyDlg::OnBtnStart()
{
	//选择服务的索引
	POSITION Pos = m_ServiceList.GetFirstSelectedItemPosition();
	int nSelect = -1;

	while(Pos)
	{
		nSelect = m_ServiceList.GetNextSelectedItem(Pos);
	}

	if(-1 == nSelect)
	{
		AfxMessageBox("请选择要启动的服务");
		return;
	}

	//获取选择的服务的服务名
	char szServiceName[MAXBYTE] = {0};
	m_ServiceList.GetItemText(nSelect, 0, szServiceName, MAXBYTE);

	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(NULL == hSCM)
	{
		AfxMessageBox("Open SCManager Eorror");
		return;
	}

	//打开指定的服务
	SC_HANDLE hCService = OpenService(hSCM, szServiceName, SERVICE_ALL_ACCESS);

	//启动服务
	BOOL bRet = StartService(hCService, 0, NULL);
	if(bRet == TRUE)
	{
		m_ServiceList.SetItemText(nSelect, 2, "运行");
	}else{
		AfxMessageBox("启动失败");
	}

	CloseServiceHandle(hCService);
	CloseServiceHandle(hSCM);

}

停止服务的代码:

void CMyDlg::OnBtnStop()
{
	//选择服务的索引
	POSITION Pos = m_ServiceList.GetFirstSelectedItemPosition();
	int nSelect = -1;

	while(Pos)
	{
		nSelect = m_ServiceList.GetNextSelectedItem(Pos);
	}

	if(-1 == nSelect)
	{
		AfxMessageBox("请选择要停止的服务");
		return;
	}

	//获取选择的服务的服务名
	char szServiceName[MAXBYTE] = {0};
	m_ServiceList.GetItemText(nSelect, 0, szServiceName, MAXBYTE);
	//
	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(NULL == hSCM)
	{
		AfxMessageBox("Open SCManager Eoor");
		return;
	}

	//打开指定的服务
	SC_HANDLE hSCService = OpenService(hSCM, szServiceName, SERVICE_ALL_ACCESS);
	SERVICE_STATUS ServiceStatus;
	//停止服务
	BOOL bRet = ControlService(hSCService, SERVICE_CONTROL_STOP, &ServiceStatus);
	if(bRet == TRUE)
	{
		m_ServiceList.SetItemText(nSelect, 2, "停止");
	}else{
		AfxMessageBox("服务停止失败");
	}

	CloseServiceHandle(hSCService);
	CloseServiceHandle(hSCM);
}

最后再亲情奉上本项目源码供大家参考,当然,我得收5积分的敲代码辛苦费。可以在我上传的资源上查:服务编程(blog)

时间: 2024-11-12 16:00:44

Windows服务编程的相关文章

Windows服务编程集合

http://zyan.cc/windows_mstsc/ Optionname--Optionvalues描述 type=----own, share, interact, kernel, filesys 关于建立服务的类型,选项值包括驱动程序使用的类型,默认是share. start=----boot, sys tem, auto, demand, disabled 关于启动服务的类型,选项值包括驱动程序使用的类型,默认是demand(手动). error=----normal, sever

(转)C#创建windows服务

原文地址:http://blog.itpub.net/23109131/viewspace-688117/ 第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(Windows Service)选项,给工程一个新文件名,然后点击确定.现在项目中有个Service1.cs类: 查看其各属性的含意是: Autolog                          是否自动写入系统的日志文件         CanHandlePo

用C#创建Windows服务(Windows Services)

学习:  第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(Windows Service)选项,给工程一个新文件名 ,然后点击 确定.现在项目中有个Service1.cs类: 查看其各属性的含意是: Autolog                 是否自动写入系统的日志文件         CanHandlePowerEvent     服务时候接受电源事件         CanPauseAndContinue    

C# Windows服务开发从入门到精通

一.课程介绍 大家都知道如果想要程序一直运行在windows服务器上,最好是把程序写成windows服务程序:这样程序会随着系统的自动启动而启动,自动关闭而关闭,不需要用户直接登录,直接开机就可以启动. 今天将给大家带来实际项目中经常运用的技术-C# 如何使用创建Windows服务进行应用程序开发. 本课程适合人群如下: 1.有一定的NET开发基础并对Windows服务编程技术有一定了解和认识. 2.进一步加深提高和扩展对Windows服务编程技术的认识视野. 3.喜欢阿笨的干货分享课程的童鞋们

C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(上)

译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 39 章 Windows 服务(上)),不对的地方欢迎指出与交流. 章节出自<Professional C# 6 and .NET Core 1.0>.水平有限,各位阅读时仔细分辨,唯望莫误人子弟. 附英文版原文:Professional C# 6 and .NET Core 1.0 - Chapter 39 Windows Services --------------------------------

《C#高级编程》读书笔记(十九):Windows服务

1,Windows 服务 Windows 服务是可以在系统启动时自动打开的程序.如果需要在没有用户交互操作情况下运行程序,或者在权限比交互式用户更大的用户下运行程序,就可以创建 Windows 服务. 2,Windows 服务的体系架构 操作 Windows 服务需要3种程序: • 服务程序 • 服务控制程序 • 服务配置程序 服务程序本身用于提供需要的实际功能. 服务控制程序可以把控制请求发送给服务,如开始.停止.暂停和继续. 使用服务配置程序可以安装服务,也可以在以后改变服务的配置. 3,服

【转】《windows核心编程》读书笔记

这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入,但应该是合理的.开头几章由于我追求简洁,往往是很多单独的字句,后面的内容更为连贯. 海量细节. 第1章    错误处理 1.         GetLastError返回的是最后的错误码,即更早的错误码可能被覆盖. 2.         GetLastError可能用于描述成功的原因(CreatEvent)

Windows Socket编程示例-TCP示例程序

前面一部分是介绍,后面有示例 1.网络中进程之间如何通信? 首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问题,网络层的"ip地址"可以唯一标识网络中的主机,而传输层的"协议+端口"可以唯一标识主机中的应用程序(进程).这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互. 使用TCP

RDIFramework.NET框架SOA解决方案(集Windows服务、WinForm形式与IIS形式发布)-分布式应用

RDIFramework.NET框架SOA解决方案(集Windows服务.WinForm形式与IIS形式发布)-分布式应用 RDIFramework.NET,基于.NET的快速信息化系统开发.整合框架,给用户和开发者最佳的.Net框架部署方案.该框架以SOA范式作为指导思想,作为异质系统整合与互操作性.分布式应用提供了可行的解决方案. 1.SOA平台简介 1.1.概述 SOA(service-oriented architecture,也叫面向服务的体系结构或面向服务架构)是指为了解决在Inte