Windows Service服务程序的原理及实现(1)实现对服务的控制和管理
来源:互联网 发布:mac安装axure出错 编辑:程序博客网 时间:2024/06/01 09:45
摘要:上一篇文章《Windows Service服务程序(0)服务主函数 & 控制处理函数》对Windows服务开发做了初步讲解。服务编写完成后,还需要服务管理程序才可以运行。一种方式是上篇文章中介绍的使用系统服务管理工具,如sc.exe等;另一种方式是使用Windows服务管理API自行编写服务管理程序。
目录:
- 创建服务
- 删除服务
- 启动服务
- 向服务发送控制请求
- 停止服务运行
- 服务控制与管理测试
本文介绍如何通过系统提供的API函数,对上一篇文章中开发的服务程序进行控制。
创建服务
向系统创建服务,创建时指定相应的服务属性,CreateService
函数参数基本上从名称就能知道具体意思了,原型如下:
CreateServiceA( _In_ SC_HANDLE hSCManager, //SCM句柄 _In_ LPCSTR lpServiceName, //服务名 _In_opt_ LPCSTR lpDisplayName, //显示的服务名 _In_ DWORD dwDesiredAccess, //存取权限 _In_ DWORD dwServiceType, //服务类别 _In_ DWORD dwStartType, //启动类别 _In_ DWORD dwErrorControl, //错误控制类别 _In_opt_ LPCSTR lpBinaryPathName, //服务的可执行文件路径 _In_opt_ LPCSTR lpLoadOrderGroup, //用户组 _Out_opt_ LPDWORD lpdwTagId, //标签 _In_opt_ LPCSTR lpDependencies, //服务独立性 _In_opt_ LPCSTR lpServiceStartName, //系统账户 _In_opt_ LPCSTR lpPassword //密码 );
CreateService被宏定义为两套函数,分别为CreateServiceW和CreateServiceA,主要区别是前面为Unicode编码,后面为ASCII编码。以下直接使用CreateServiceA
函数,一般不这么用,而用CreateService函数。
/*创建服务*/int createService(SC_HANDLE schSCManager, LPSTR szPath, LPSTR szServiceName){ SC_HANDLE schService = CreateServiceA(schSCManager, szServiceName, "demo_srv", SERVICE_ALL_ACCESS, //存取权限 SERVICE_WIN32_OWN_PROCESS, //服务类别 SERVICE_DEMAND_START, //启动类型 SERVICE_ERROR_NORMAL, //错误控制类别 szPath, NULL, NULL, NULL, NULL, NULL); if (schService == NULL){ printf("Create service failed (%d).\n", GetLastError()); return -1; } printf("Create service succeeded.\n"); CloseServiceHandle(schService); schService = NULL; return 0;}
删除服务
调用OpenService函数打开服务,获得服务句柄,然后使用DeleteService
删除服务,该原型如下:
DeleteService( _In_ SC_HANDLE hService );
删除服务是最简单的操作,可以封装成以下函数:
/*删除服务*/int deleteService(SC_HANDLE schSCManager, LPSTR szServiceName){ SC_HANDLE schService = OpenServiceA(schSCManager, szServiceName, DELETE); if (schService == NULL){ printf("OpenService failed (%d).\n", GetLastError()); return -1; } if (!DeleteService(schService)){ printf("Delete service failed (%d).\n", GetLastError()); return -2; } printf("Delete service succeeded.\n"); CloseServiceHandle(schService); schService = NULL; return 0;}
启动服务
启动服务StartService
,有三个参数:服务的句柄,参数个数,参数列表指针。具体函数原型如下:
StartServiceA( _In_ SC_HANDLE hService, //服务句柄 _In_ DWORD dwNumServiceArgs, //参数的个数 _In_reads_opt_(dwNumServiceArgs) LPCSTR *lpServiceArgVectors //参数列表指针 );
使用QueryServiceStatusEx API函数可以实时获取服务当前的状态。启动服务也较简单,其中多了个while循环对服务状态进行查询,确定PENDING ([‘pendɪŋ] adj.待定的;待决的;即将发生的)状态结束。启动服务实现如下:
/*启动服务*/int startService(SC_HANDLE schSCManager, LPSTR szServiceName){ SC_HANDLE schService; SERVICE_STATUS_PROCESS ssp; DWORD dwOldCheckPoint; DWORD dwStartTickCount; DWORD dwWaitTime; DWORD dwBytesNeeded; schService = OpenServiceA(schSCManager, szServiceName, SERVICE_ALL_ACCESS); if (schService == NULL){ printf("Open service failed (%d).\n", GetLastError()); return -1; } int ret = StartServiceA(schService, 0, //argc NULL //argv ); if (!ret){ printf("Service start failed (%d).\n", GetLastError()); return -2; } printf("Service start pending.\n"); //验证状态 if (!QueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)){ printf("Query service status failed (%d).\n", GetLastError()); return -3; } dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssp.dwCheckPoint; //查询状态,确定Pending状态结束 while (ssp.dwCurrentState == SERVICE_START_PENDING){ dwWaitTime = ssp.dwWaitHint / 10; if (dwWaitTime < 1000){ dwWaitTime = 1000; } else if (dwWaitTime > 10000){ dwWaitTime = 10000; } Sleep(dwWaitTime); //再次查询 if (!QueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)) { printf("Query service status failed (%d).\n", GetLastError()); break; } if (ssp.dwCheckPoint > dwOldCheckPoint){ //进程创建中 dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssp.dwCheckPoint; } else if (GetTickCount() - dwStartTickCount > ssp.dwWaitHint){ //WaitHint时间到 break; } } CloseServiceHandle(schService); schService = NULL; if (ssp.dwCurrentState != SERVICE_RUNNING){ printf("Start service failed (%d).\n", GetLastError()); return -4; } printf("Start service success.\n"); return 0;}
向服务发送控制请求
在服务管理程序向服务程序发送了控制码后,服务所注册的控制处理程序(回调函数),上一篇文章中的serviceCtrlHandlerProc函数就会被调用,并将对应的控制码发送给控制处理程序,由控制处理程序来决定作出何种相应。
ControlService函数原型如下:
ControlService( _In_ SC_HANDLE hService, //服务句柄 _In_ DWORD dwControl, //控制码 _Out_ LPSERVICE_STATUS lpServiceStatus //返回的服务状态 );
如需要停止服务,可以发送SERVICE_CONTROL_STOP控制码。
/*向服务发送控制码*/int controlService(SC_HANDLE schSCManager, DWORD fdwControl, LPSTR szServiceName){ SC_HANDLE schService; SERVICE_STATUS status; DWORD fdwAccess; switch (fdwControl){ case SERVICE_CONTROL_STOP: fdwAccess = SERVICE_STOP; break; case SERVICE_CONTROL_PAUSE: case SERVICE_CONTROL_CONTINUE: fdwAccess = SERVICE_PAUSE_CONTINUE; break; default: fdwAccess = SERVICE_INTERROGATE; break; } schService = OpenServiceA(schSCManager, szServiceName, fdwAccess); if (schService == NULL){ printf("Open service failed (%d).\n", GetLastError()); return -1; } //发送控制码 if (!ControlService(schService, fdwControl, &status)){ printf("Control service failed (%d).\n", GetLastError()); return -2; } printf("Control service success.\n"); return 0;}
停止服务运行
服务与服务之间所存在的依赖关系是指一个服务的运行需要其他服务的支持。EnumDependentServices
API函数可以列举出依赖于某服务的所有服务。故可以实现,暂停一个服务之前将所有依赖于该服务的其他服务全部终止掉。
EnumDependentServicesA函数原型如下:
EnumDependentServicesA( _In_ SC_HANDLE hService, _In_ DWORD dwServiceState, _Out_writes_bytes_opt_(cbBufSize) LPENUM_SERVICE_STATUSA lpServices, _In_ DWORD cbBufSize, _Out_ LPDWORD pcbBytesNeeded, _Out_ LPDWORD lpServicesReturned );
以下是一个完整的停止服务函数:
/*停止服务*/DWORD stopService(SC_HANDLE schSCManager, LPSTR szServiceName, bool fStopDependcies, DWORD dwTimeout){ SERVICE_STATUS_PROCESS ssp; SERVICE_STATUS status; DWORD dwStartTime = GetTickCount(); DWORD dwBytesNeeded; SC_HANDLE schService = OpenServiceA(schSCManager, szServiceName, SERVICE_ALL_ACCESS); if (schService == NULL){ printf("Open service failed (%d).\n", GetLastError()); return -2; } if (!QueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)){ printf("Query service status failed (%d).\n", GetLastError()); return -3; } if (ssp.dwCurrentState == SERVICE_STOPPED){ printf("Stop service success.\n"); return 0; } //正在结束,只需等待即可 while (ssp.dwCurrentState == SERVICE_STOP_PENDING){ Sleep(ssp.dwWaitHint); if (!QueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)){ printf("Query service status failed (%d).\n", GetLastError()); return -4; } if (ssp.dwCurrentState == SERVICE_STOPPED){ printf("Stop service success.\n"); return 0; } if (GetTickCount() - dwStartTime > dwTimeout){ printf("Time Out.\n"); return -5; } } //先结束依赖服务 if (fStopDependcies){ DWORD i; DWORD dwBytes; DWORD dwCount; LPENUM_SERVICE_STATUSA lpDependencies = NULL; ENUM_SERVICE_STATUSA ess; SC_HANDLE hDependentService; //如果EnumDependentService返回成功,说明没有依赖服务 if (!EnumDependentServicesA(schService, SERVICE_ACTIVE, lpDependencies, 0, &dwBytes, &dwCount)){ if (GetLastError() != ERROR_MORE_DATA){ printf("Enum depend service failed (%d).\n", GetLastError()); return -6; } //分配缓冲区存储依赖服务的的数据 lpDependencies = (LPENUM_SERVICE_STATUSA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytes); if (!lpDependencies){ printf("Heap alloc failed (%d).\n", GetLastError()); return -7; } __try{ if (!EnumDependentServicesA(schService, SERVICE_ACTIVE, lpDependencies, dwBytes, &dwBytes, &dwCount)){ printf("Enum dependent service failed (%d).\n", GetLastError()); return -8; } for (i = 0; i < dwCount; i++){ ess = *(lpDependencies + i); //打开服务 hDependentService = OpenServiceA(schSCManager, ess.lpServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS); if (!hDependentService){ printf("Open service failed (%d).\n", GetLastError()); return -9; } __try{ //结束服务 if (!ControlService(hDependentService, SERVICE_CONTROL_STOP, &status)){ printf("Control service failed (%d).\n", GetLastError()); return -10; } while (status.dwCurrentState != SERVICE_STOPPED){ Sleep(status.dwWaitHint); if (!QueryServiceStatusEx(hDependentService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytes)){ printf("Query service status failed (%d).\n", GetLastError()); return -11; } if (ssp.dwCurrentState == SERVICE_STOPPED){ printf("Stop service success.\n"); break; } if (GetTickCount() - dwStartTime > dwTimeout){ printf("Time Out.\n"); return -12; } } } __finally{ //关闭服务 CloseServiceHandle(hDependentService); } } } __finally{ //释放内存 HeapFree(GetProcessHeap(), 0, lpDependencies); } } } //所有的依赖服务已经结束,结束指定服务 if (!ControlService(schService, SERVICE_CONTROL_STOP, &status)){ printf("Control service failed (%d).\n", GetLastError()); return -13; } while (status.dwCurrentState != SERVICE_STOPPED){ Sleep(status.dwWaitHint); if (!QueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)){ printf("Query service status failed (%d).\n", GetLastError()); return -14; } if (status.dwCurrentState == SERVICE_STOPPED){ printf("Stop service success.\n"); break; } if (GetTickCount() - dwStartTime > dwTimeout){ printf("Time Out.\n"); return -15; } } if (status.dwCurrentState == SERVICE_STOPPED){ printf("Stop service success.\n"); return 0; } return -1;}
服务控制与管理测试
到此,已经基本实现了对服务的控制和管理的所有子函数,下面对其所有功能进行测试。
1. 首先给出服务执行体所在的exe地址;
2. 打开SCM获得句柄;
3. 创建服务;
4. 启动服务;
5. 发送控制请求;
6. 停止服务;
7. 删除服务;
int main(void){ char szBinFilePath[MAX_PATH] = "E:/Code/VS2013/Win32Service/Win32Service.exe"; DWORD dwStopError; LPSTR szServiceName = "demo_srv"; //打开SCM SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL){ printf("Open SCManager failed (%d).\n", GetLastError()); return -1; } //创建服务 int ret = createService(schSCManager, szBinFilePath, szServiceName); if (ret){ printf("Create service failed (%d).\n", GetLastError()); return -2; } //启动服务 ret = startService(schSCManager, szServiceName); if (ret){ printf("Start service failed (%d).\n", GetLastError()); return -3; } //发送请求控制 ret = controlService(schSCManager, SERVICE_CONTROL_INTERROGATE, szServiceName); if (ret){ printf("Control service failed (%d).\n", GetLastError()); return -4; } ret = controlService(schSCManager, SERVICE_CONTROL_CONTINUE, szServiceName); if (ret){ printf("Control service failed (%d).\n", GetLastError()); return -5; } dwStopError = stopService(schSCManager, szServiceName, TRUE, 1000); if (dwStopError){ printf("Stop service failed (%u).\n", dwStopError); return -6; } printf("Stop service success.\n"); //删除服务 ret = deleteService(schSCManager, szServiceName); if (ret){ printf("Delete service failed (%d).\n", ret); return -7; } CloseServiceHandle(schSCManager); schSCManager = NULL; return 0;}
- Windows Service服务程序的原理及实现(1)实现对服务的控制和管理
- Windows Service服务程序的原理及实现(0)服务主函数 & 控制处理函数
- Windows服务之实现对服务的控制管理
- Windows服务之实现对服务的控制管理
- Windows服务程序的原理及实现
- 本地服务(local Service)的实现
- android基础笔记:服务(Service):基础知识及本地服务的实现
- C#制作Windows service服务系列三--制作可控制界面的Windows服务(windows service)
- C#制作Windows service服务系列三--制作可控制界面的Windows服务(windows service)
- C#制作Windows service服务系列三--制作可控制界面的Windows服务(windows service)
- 用托盘控制windows服务的c#实现
- 摘:用托盘控制windows服务的c#实现
- 用托盘控制windows服务的c#实现
- 用托盘控制windows服务的c#实现 (转)
- C#实现用托盘控制windows服务的
- 关于服务程序(service)的命令(windows\linux)
- 制作可控制界面的windows服务(windows service)
- windows服务的简单实现(原创)
- java18_Collection
- 【图像处理】灰度映射(Gray Level Transformation)
- 指针数组
- Effective Java系列读后感(二)-对于所有对象都通用的方法
- 关于生存
- Windows Service服务程序的原理及实现(1)实现对服务的控制和管理
- 边城小猿——某小城程序员15年的工作经历(已转行)
- 四元数表示向量V1到V2的旋转
- 学习理论、模型选择、特征选择——斯坦福CS229机器学习个人总结(四)
- [掌盟+]RecycleView实现"英雄资料"页和"发现"页
- 《产品经理方法论》
- STM32笔记0428/建立模板
- 关于Android源码的获取
- 4.29面试总结