Windows服务开发和脚本介绍

来源:互联网 发布:淘宝宝贝详情页文字 编辑:程序博客网 时间:2024/04/30 14:38

Windows服务开发和脚本介绍

Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算

机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。这种服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上

工作的其他用户,需要长时间运行功能时使用。还可以在不同于登录用户的特定用户帐户或默认计算机帐户的安全上下文中运行服务。(摘自百度百科)

主要使用到两个Windows函数,即RegisterServiceCtrlHandler和SetServiceStatus。

1、RegisterServiceCtrlHandler

Registers a function to handle service control requests.

This function has been superseded by the RegisterServiceCtrlHandlerEx function. A service can use either function, but the new function supports user-defined context data, and the new handler function supports additional extended control codes.

SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandler(  _In_ LPCTSTR            lpServiceName,  _In_ LPHANDLER_FUNCTION lpHandlerProc);

Parameters

lpServiceName [in]

The name of the service run by the calling thread. This is the service name that the service control program specified in the CreateServicefunction when creating the service.

If the service type is SERVICE_WIN32_OWN_PROCESS, the function does not verify that the specified name is valid, because there is only one registered service in the process.

lpHandlerProc [in]

A pointer to the handler function to be registered. For more information, see Handler.

Return value

If the function succeeds, the return value is a service status handle.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager.

2、SetServiceStatus

Updates the service control manager's status information for the calling service.
BOOL WINAPI SetServiceStatus(  _In_ SERVICE_STATUS_HANDLE hServiceStatus,  _In_ LPSERVICE_STATUS      lpServiceStatus);

Parameters

hServiceStatus [in]

A handle to the status information structure for the current service. This handle is returned by the RegisterServiceCtrlHandlerExfunction.

lpServiceStatus [in]

A pointer to the SERVICE_STATUS structure the contains the latest status information for the calling service.

Return value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

以上摘自msdn,更详细的可以直接访msdn进行查看
1、https://msdn.microsoft.com/en-us/library/ms685054.aspx
2、https://msdn.microsoft.com/en-us/library/windows/desktop/ms686241(v=vs.85).aspx

服务代码示例:

// ServerForTest.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <Windows.h>#include "..\Server\Server.h"#include <io.h>#ifdef _DEBUG#pragma comment(lib, "..\\Debug\\Server.lib")#else#pragma comment(lib, "..\\Release\\Server.lib")#endif#define SERVICE_NAME "ServerForTest"SERVICE_STATUS ServiceStatus;SERVICE_STATUS_HANDLE hServiceStatusHandle;void WINAPI Handler(DWORD fdwControl);VOID WINAPI ServiceMain( DWORD dwArgc,LPTSTR* lpszArgv);const char kTailer[] = "\r\n";void GetWorkPath(char (&szWorkPath)[260]) //(char pWorkPath[260]){char path[260] = {0};GetModuleFileName(NULL, path, 260);for(int i=strlen(path); i>=0; i--){if(path[i]=='\\'){path[i]=0;break;}}memset(szWorkPath, 0, sizeof(szWorkPath));sprintf_s(szWorkPath, 260 - 1, "%s", path);return;}void PrintLog(char* pMsg = NULL){if(pMsg != NULL){char szWorkPath[260] = { 0 };char szLogPath[260] = { 0 };GetWorkPath(szWorkPath);sprintf_s(szLogPath, 260 -1, "%s\\%s", szWorkPath, "log.txt");FILE* pf = fopen(szLogPath, "a+");if(pf != NULL){fwrite(pMsg, sizeof(char), strlen(pMsg), pf);fwrite(kTailer, sizeof(char), strlen(kTailer), pf);fflush(pf);fclose(pf);pf = NULL;}}}int _tmain(int argc, _TCHAR* argv[])//每次启动服务都会调用这里{PrintLog("_tmain");SERVICE_TABLE_ENTRY ServiceTable[2];ServiceTable[0].lpServiceName = (SERVICE_NAME);ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;ServiceTable[1].lpServiceName = NULL;ServiceTable[1].lpServiceProc = NULL;// 启动服务的控制分派机线程StartServiceCtrlDispatcher(ServiceTable);return 0;}VOID WINAPI ServiceMain( DWORD dwArgc,LPTSTR* lpszArgv){      PrintLog("ServiceMain");ServiceStatus.dwServiceType        = SERVICE_WIN32; ServiceStatus.dwCurrentState       = SERVICE_START_PENDING; ServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE; ServiceStatus.dwWin32ExitCode      = 0; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCheckPoint         = 0; ServiceStatus.dwWaitHint           = 0;  hServiceStatusHandle = RegisterServiceCtrlHandler((SERVICE_NAME), Handler); if (hServiceStatusHandle==0) {DWORD nError = GetLastError();}  Server_Init();Server_Start();// Initialization complete - report running status ServiceStatus.dwCurrentState       = SERVICE_RUNNING; ServiceStatus.dwCheckPoint         = 0; ServiceStatus.dwWaitHint           = 9000;  if(!SetServiceStatus(hServiceStatusHandle, &ServiceStatus)) { DWORD nError = GetLastError();} } VOID WINAPI Handler(DWORD fdwControl){ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCheckPoint    = 0; ServiceStatus.dwWaitHint      = 0;char szTemp[1044] = { 0 };sprintf_s(szTemp, 1024, "Handler,fdwControl:%d", fdwControl);PrintLog(szTemp);switch(fdwControl) {case SERVICE_CONTROL_STOP:case SERVICE_CONTROL_SHUTDOWN:ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState  = SERVICE_STOPPED; ServiceStatus.dwCheckPoint    = 0; ServiceStatus.dwWaitHint      = 0;Server_Stop();Server_UnInit();break; default:return;};if (!SetServiceStatus(hServiceStatusHandle,  &ServiceStatus)) { DWORD nError = GetLastError();} }

下面介绍安装、启动、停止和卸载指令内容,主要使用sc和net命令。

如下是sc命令说明,摘自cmd。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////C:\Users\Abc>sc /?错误:  未知命令描述:        SC 是用来与服务控制管理器和服务进行通信        的命令行程序。用法:        sc <server> [command] [service name] <option1> <option2>...        <server> 选项的格式为 "\\ServerName"        可通过键入以下命令获取有关命令的更多帮助: "sc [command]"        命令:          query-----------查询服务的状态,                          或枚举服务类型的状态。          queryex---------查询服务的扩展状态,                          或枚举服务类型的状态。          start-----------启动服务。          pause-----------向服务发送 PAUSE 控制请求。          interrogate-----向服务发送 INTERROGATE 控制请求。          continue--------向服务发送 CONTINUE 控制请求。          stop------------向服务发送 STOP 请求。          config----------更改服务的配置(永久)。          description-----更改服务的描述。          failure---------更改失败时服务执行的操作。          failureflag-----更改服务的失败操作标志。          sidtype---------更改服务的服务 SID 类型。          privs-----------更改服务的所需特权。          managedaccount--更改服务以将服务帐户密码                          标记为由 LSA 管理。          qc--------------查询服务的配置信息。          qdescription----查询服务的描述。          qfailure--------查询失败时服务执行的操作。          qfailureflag----查询服务的失败操作标志。          qsidtype--------查询服务的服务 SID 类型。          qprivs----------查询服务的所需特权。          qtriggerinfo----查询服务的触发器参数。          qpreferrednode--查询服务的首选 NUMA 节点。          qmanagedaccount-查询服务是否将帐户                          与 LSA 管理的密码结合使用。          qprotection-----查询服务的进程保护级别。          quserservice----查询用户服务模板的本地实例。          delete ----------(从注册表中)删除服务。          create----------创建服务(并将其添加到注册表中)。          control---------向服务发送控制。          sdshow----------显示服务的安全描述符。          sdset-----------设置服务的安全描述符。          showsid---------显示与任意名称对应的服务 SID 字符串。          triggerinfo-----配置服务的触发器参数。          preferrednode---设置服务的首选 NUMA 节点。          GetDisplayName--获取服务的 DisplayName。          GetKeyName------获取服务的 ServiceKeyName。          EnumDepend------枚举服务依赖关系。        以下命令不需要服务名称:        sc <server> <command> <option>          boot------------(ok | bad)指示是否应将上一次启动另存为                          最近一次已知的正确启动配置          Lock------------锁定服务数据库          QueryLock-------查询 SCManager 数据库的 LockStatus示例:        sc start MyServiceQUERY 和 QUERYEX 选项:        如果查询命令带服务名称,将返回        该服务的状态。其他选项不适合这种        情况。如果查询命令不带参数或        带下列选项之一,将枚举此服务。    type=    要枚举的服务的类型(driver, service, userservice, all)             (默认 = service)    state=   要枚举的服务的状态 (inactive, all)             (默认 = active)    bufsize= 枚举缓冲区的大小(以字节计)             (默认 = 4096)    ri=      开始枚举的恢复索引号             (默认 = 0)    group=   要枚举的服务组             (默认 = all groups)语法示例sc query                - 枚举活动服务和驱动程序的状态sc query eventlog       - 显示 eventlog 服务的状态sc queryex eventlog     - 显示 eventlog 服务的扩展状态sc query type= driver   - 仅枚举活动驱动程序sc query type= service  - 仅枚举 Win32 服务sc query state= all     - 枚举所有服务和驱动程序sc query bufsize= 50    - 枚举缓冲区为 50 字节sc query ri= 14         - 枚举时恢复索引 = 14sc queryex group= ""    - 枚举不在组内的活动服务sc query type= interact - 枚举所有不活动服务sc query type= driver group= NDIS     - 枚举所有 NDIS 驱动程序C:\Users\Abc>sc create /?描述:        在注册表和服务数据库中创建服务项。用法:        sc <server> create [service name] [binPath= ] <option1> <option2>...选项:注意: 选项名称包括等号。      等号和值之间需要一个空格。 type= <own|share|interact|kernel|filesys|rec|userown|usershare>       (默认 = own) start= <boot|system|auto|demand|disabled|delayed-auto>       (默认 = demand) error= <normal|severe|critical|ignore>       (默认 = normal) binPath= <.exe 文件的 BinaryPathName> group= <LoadOrderGroup> tag= <yes|no> depend= <依存关系(以 / (斜杠)分隔)> obj= <AccountName|ObjectName>       (默认= LocalSystem) DisplayName= <显示名称> password= <密码>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
如下是net指令说明,摘自cmd。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
C:\Users\Abc Zhao>net /?此命令的语法是:NET    [ ACCOUNTS | COMPUTER | CONFIG | CONTINUE | FILE | GROUP | HELP |      HELPMSG | LOCALGROUP | PAUSE | SESSION | SHARE | START |      STATISTICS | STOP | TIME | USE | USER | VIEW ]
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
sc和net在启动和停止时区别为sc是异步的,net是同部的。(来自网络,不知道对不对,测试两种命令都可以达到目的)

完整服务工程见:http://download.csdn.net/detail/zhaodongdong2012/9782614。

0 0
原创粉丝点击