认识windows服务并使用VC++创建windows服务程序

实际中很多场景需要用到服务,如你的业务程序运行在windows系统,当系统重启时,无需用户登录系统要求启动你的程序,这个场景就需要用到windows服务。

windows服务能够在计算机重启时自动启动,不显示任何用户界面。

一:windows服务相关命令

创建windows服务可以使用sc命令

1.创建TestService服务,设置服务显示名称为TestService,开机自启动

sc create TestService binpath= "D:\\test.exe" start= auto displayname= "TestService"

2.设置服务的描述信息

sc description TestService "这是肉哥的测试服务"

3.启动服务

sc start TestService

4.停止服务

sc stop TestService

5.删除服务

sc delete TestService

6.服务恢复属性

服务运行过程中如有用户通过任务管理器把服务运行的进程给关闭了,为保证能够重启该服务进程,可通过配置恢复属性来实现

服务失败三次都是就行了重启,也可以把后续失败来改成运行一个程序。

该配置可以使用如下命令来实现:
sc failure TestService reset= 0 actions= restart/100000/restart/100000/restart/100000

设置服务失败时要运行的命令行
sc failure TestService reset= 0 command= d:\alert.exe actions= run/5000

二:查看服务

cmd命令行运行 services.msc打开服务管理器,界面如下:

三:服务程序实例

这里说下不是任何的win32应用都可以做成服务,需要在程序中加入相应的代码来满足服务的要求。

  1. main函数

main函数中主要分两步:

第一步:初始化一个SERVICE_TABLE_ENTRY 分配表结构体

第二步:调用StartServiceCtrlDispatcher系统函数,把调用进程的主线程转换为控制分派器。该分派器会启动一个新线程,线程运行服务中的ServiceMain()函数。

2.ServiceMain函数

ServiceMain函数是服务的工作函数,业务逻辑放到该函数中。函数格式为:void WINAPI ServiceMain(int argc, char** argv),名字可以任意定义。

ServiceMain执行任务前,由于还没开始执行任务,需要将服务状态设置为SERVICE_START_PENDING,表示正在初始化。
ervicestatus.dwCurrentState = SERVICE_START_PENDING

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/********************************************************
Copyright (C), 2016-2018,
FileName: main
Author: 肉哥
Email: CodeRoad666@163.com
Created: 2019/12/02
Description: 这是一个用于注册成服务的win32程序
********************************************************/
#include <stdio.h>
#include <iostream>
#include <windows.h>

using namespace std;

#define SERVICE_NAME "TestService"

SERVICE_STATUS g_serviceStatus; //服务状态
SERVICE_STATUS_HANDLE g_hServiceStatus; //服务状态句柄

void WINAPI ServiceMain(int argc, char** argv);
void WINAPI CtrlHandler(DWORD request);
int InitService();
int WriteToLog(char* str);
int main();

/************************************
@ Brief:
@ Author: woniu201
@ Created: 2019/12/02
@ Return:
************************************/
int WriteToLog(char* str)
{

FILE* pfile;
fopen_s(&pfile, "D:\\log.txt", "a+");
if (pfile==NULL)
{
return -1;
}
fprintf_s(pfile,"%s\n",str);
fclose(pfile);
return 0;
}

STARTUPINFO si;
PROCESS_INFORMATION pi;

/************************************
@ Brief: 服务工作函数
@ Author: woniu201
@ Created: 2019/12/02
@ Return:
************************************/
void WINAPI ServiceMain(int argc, char** argv)
{
WriteToLog("++++++++++++ServiceMain++++++++++++++++");
g_serviceStatus.dwServiceType = SERVICE_WIN32;
g_serviceStatus.dwCurrentState = SERVICE_START_PENDING;
g_serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_STOP;//在本例中只接受系统关机和停止服务两种控制命令
g_serviceStatus.dwWin32ExitCode = 0;
g_serviceStatus.dwServiceSpecificExitCode = 0;
g_serviceStatus.dwCheckPoint = 0;
g_serviceStatus.dwWaitHint = 0;

g_hServiceStatus = ::RegisterServiceCtrlHandler(SERVICE_NAME, CtrlHandler);
if (g_hServiceStatus==0)
{
WriteToLog("RegisterServiceCtrlHandler failed");
return;
}

WriteToLog("RegisterServiceCtrlHandler success");

//向SCM 报告运行状态
g_serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (g_hServiceStatus, &g_serviceStatus);

//执行任务
MEMORYSTATUS memstatus;
char str[100] = {0};
memset(str, 0 ,100);

while (true)
{
GlobalMemoryStatus(&memstatus);
int availmb=memstatus.dwAvailPhys/1024/1024;
sprintf_s(str,100,"Available memory is %dMB",availmb);
WriteToLog(str);
Sleep(5000);
}
}

/************************************
@ Brief: 服务管理器回调函数
@ Author: woniu201
@ Created: 2019/12/02
@ Return:
************************************/
void WINAPI CtrlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP:
WriteToLog("++++++++++++SERVICE_CONTROL_STOP++++++++++++++++");
g_serviceStatus.dwCheckPoint = 1;
g_serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(g_hServiceStatus, &g_serviceStatus);
Sleep(5000);
g_serviceStatus.dwCheckPoint = 0;
g_serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;

case SERVICE_CONTROL_SHUTDOWN:
WriteToLog("++++++++++++SERVICE_CONTROL_SHUTDOWN++++++++++++++++");
g_serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;

case SERVICE_CONTROL_PAUSE:
WriteToLog("++++++++++++SERVICE_CONTROL_SHUTDOWN++++++++++++++++");
break;

case SERVICE_CONTROL_INTERROGATE:
WriteToLog("++++++++++++SERVICE_CONTROL_INTERROGATE++++++++++++++++");
break;

default:
break;
}

SetServiceStatus (g_hServiceStatus, &g_serviceStatus);
}



int main()
{
WriteToLog("++++++++++++main++++++++++++++++");

SERVICE_TABLE_ENTRY entrytable[2];
entrytable[0].lpServiceName= SERVICE_NAME;
entrytable[0].lpServiceProc=(LPSERVICE_MAIN_FUNCTION)ServiceMain;
entrytable[1].lpServiceName=NULL;
entrytable[1].lpServiceProc=NULL;
StartServiceCtrlDispatcher(entrytable);

return 0;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×