windows服务开发demo
0、写在前面
windows7开始,windows服务运行在session 0, 用户程序都运行在session x (x >= 1)
而session之间是有隔离的,实践发现是无法在服务中直接访问到用户应用程序的窗口句柄的,也无法直接在服务中创建带UI的程序,相关资料可以检索such as 服务突破session 0之类的关键字。
可在cmd下用query session命令查看当前计算机上的session,【可能】统一时刻只有一个session 是活动的。
又,在远程桌面下,session name是 rdp-tcp#x 这种形式,获取活动sessionid的时候使用函数 WTSGetActiveConsoleSessionId 拿到的可能不对,可以尝试如下代码段

1 PWTS_SESSION_INFO pSessionInfo = nullptr;
2 DWORD dwSessionCnt = 0;
3 WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwSessionCnt);
4 for (int i = 0; i < dwSessionCnt; ++i)
5 {
6 wsprintf(szBuf, TEXT("Session[ %d ]:id = %u, name = %s, state = %d"), i, pSessionInfo[i].SessionId, pSessionInfo[i].pWinStationName, pSessionInfo[i].State);
7 OutputDebugString(szBuf);
8 ZeroMemory(szBuf, sizeof(szBuf));
9 if (WTS_CONNECTSTATE_CLASS::WTSActive == pSessionInfo[i].State)
10 {
11 dwSessionId = pSessionInfo[i].SessionId;
12 }
13 }
参考:
https://learn.microsoft.com/zh-cn/windows/win32/api/winsvc/nf-winsvc-createservicea?redirectedfrom=MSDN
https://learn.microsoft.com/zh-cn/windows/win32/services/service-entry-point
https://learn.microsoft.com/zh-cn/windows/win32/services/writing-a-service-program-s-main-function
https://learn.microsoft.com/zh-cn/windows/win32/services/installing-a-service
https://learn.microsoft.com/zh-cn/windows/win32/services/writing-a-control-handler-function
完整服务 https://learn.microsoft.com/zh-cn/windows/win32/services/svc-cpp
1、main函数
main函数的原型就是普通的main函数原型
int main(int argc, char* argv[])
在函数内部做两件事:
(1)处理命令行参数
install安装服务和uninstall卸载服务,可选,可以使用sc create service_name binPath= "xxxx\xx.exe" 和 sc delete service_name 代替
安装服务即在注册表 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services 下添加服务名的配置项。
(2)调用 StartServiceCtrlDispatcher 生成任务派发线程
BOOL
WINAPI
StartServiceCtrlDispatcherW(
_In_ CONST SERVICE_TABLE_ENTRYW *lpServiceStartTable
);
在一个进场里可以开启多个服务,体现在这个函数的参数上,如下,g_szServiceName_x 是服务名,ServiceMain_x 是这个服务对应的主逻辑函数,服务运行期间不可以退出ServiceMain_x函数,而对于服务的【暂停】、【恢复】、【停止】都是针对 ServiceMain_x来说的,【停止】即结束ServiceMain_x, 【暂停】【恢复】可以通过现场同步实现,【启动】即进入main 函数。
SERVICE_TABLE_ENTRY st[] =
{
{ g_szServiceName_1, (LPSERVICE_MAIN_FUNCTION)ServiceMain_1 },
{ g_szServiceName_2, (LPSERVICE_MAIN_FUNCTION)ServiceMain_2 },
{ NULL, NULL }
};
3、编写 ServiceMain_x 函数逻辑
在这段逻辑里主要做几件事:
①注册服务控制函数(RegisterServiceCtrlHandler),即用来响应如下右键菜单中的【启动】【暂停】【恢复】【结束】等动作的函数。
②向服务报告状态 ,使用SetServiceStatus 函数
③主业务逻辑,包括可能存在的线程同步逻辑

4、编写服务控制函数
即 根据动作代码 SERVICE_CONTROL_STOP / SERVICE_CONTROL_PAUSE / SERVICE_CONTROL_CONTINUE / SERVICE_CONTROL_SHUTDOWN 等动作来控制主业务逻辑。
5、demo
1 #include <Windows.h>
2 #include <iostream>
3 #include <tchar.h>
4 #include <shlwapi.h>
5 using namespace std;
6
7 #pragma comment(lib, "Shlwapi.lib")
8
9 /*
10 BOOL IsInstalled();
11 BOOL Install();
12 BOOL Uninstall();
13 void LogEvent(LPCTSTR pszFormat, ...);
14 void WINAPI ServiceMain();
15 void WINAPI ServiceCtrlHandler(DWORD dwOpcode);
16 TCHAR g_szServiceName[] = _T("MyService");
17 BOOL g_bInstalled;
18 SERVICE_STATUS_HANDLE g_hServiceStatus;
19 SERVICE_STATUS g_status;
20 DWORD g_dwThreadID;
21 SC_HANDLE hSCM;
22 SC_HANDLE hService;
23 */
24
25 /*
26 OpenSCManager 用于打开服务控制管理器;
27 CreateService 用于创建服务;
28 OpenService用于打开已有的服务,返回该服务的句柄;
29 ControlService则用于控制已打开的服务状态,这里是让服务停止后才删除;
30 DeleteService 用于删除指定服务。
31 RegisterServiceCtrlHandler 注册服务控制
32 */
33
34 // 定义全局函数变量
35 void Init();
36 BOOL IsInstalled();
37 BOOL Install();
38 BOOL Uninstall();
39 void LogEvent(LPCTSTR pszFormat, ...);
40 void WINAPI ServiceMain();
41 void WINAPI ServiceCtrlHandler(DWORD dwOpcode);
42
43 TCHAR g_szServiceName[] = _T("servicename");
44 BOOL g_bInstalled = FALSE;
45 SERVICE_STATUS_HANDLE g_hServiceStatus;
46 SERVICE_STATUS g_status;
47 DWORD g_dwThreadID = 0;
48 BOOL volatile g_bRunning = FALSE;
49 HANDLE g_hPauseContinueEvent = NULL;
50 HANDLE g_hStopEvent = NULL;
51
52
53 int main(int argc, char* argv[])
54 {
55 OutputDebugString(TEXT("[Service] main running..."));
56 LPCTSTR lpCmdLine = nullptr;
57 Init();
58 g_dwThreadID = ::GetCurrentThreadId();
59 SERVICE_TABLE_ENTRY st[] =
60 {
61 { g_szServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
62 { NULL, NULL }
63 };
64
65 if (argc > 1)
66 {
67 if (_stricmp(argv[1], "/install") == 0)
68 {
69 OutputDebugString(TEXT("[Service] install..."));
70 Install();
71 }
72 else if (_stricmp(argv[1], "/uninstall") == 0)
73 {
74 OutputDebugString(TEXT("[Service] uninstall"));
75 Uninstall();
76 }
77 else if (_stricmp(argv[1], "/help") == 0)
78 {
79 std::cout << "usage: servicedemo.exe [/install | /uninstall]";
80 }
81 }
82 else
83 {
84 OutputDebugString(TEXT("[Service] StartServiceCtrlDispatcher"));
85 if (!::StartServiceCtrlDispatcher(st))
86 {
87 OutputDebugString(TEXT("[Service] StartServiceCtrlDispatcher Failed!"));
88 LogEvent(_T("Register Service Main Function Error!"));
89 }
90 }
91
92 return 0;
93 }
94
95 //初始化
96 void Init()
97 {
98 g_hServiceStatus = NULL;
99 g_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
100 g_status.dwCurrentState = SERVICE_START_PENDING;
101 g_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_INTERACTIVE_PROCESS; // 可以响应的服务控制
102 g_status.dwWin32ExitCode = NO_ERROR;
103 g_status.dwServiceSpecificExitCode = 0;
104 g_status.dwCheckPoint = 0;
105 g_status.dwWaitHint = 0;
106 }
107
108 //服务主函数,这在里进行控制对服务控制的注册
109 void WINAPI ServiceMain()
110 {
111 OutputDebugString(TEXT("[HookForADService]ServiceMain begin..."));
112
113 // 注册服务控制
114 g_hServiceStatus = RegisterServiceCtrlHandler(g_szServiceName, ServiceCtrlHandler);
115 if (g_hServiceStatus == NULL)
116 {
117 LogEvent(_T("Handler not installed"));
118 return;
119 }
120 SetServiceStatus(g_hServiceStatus, &g_status);
121
122 g_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
123 OutputDebugString(TEXT("[HookForADService]ServiceMain will Install hook"));
124
125 ///////////////////////业务逻辑/////////////////////////////////////////
126 // do something
127
128 g_status.dwWin32ExitCode = S_OK;
129 g_status.dwCheckPoint = 0;
130 g_status.dwWaitHint = 0;
131 g_status.dwCurrentState = SERVICE_RUNNING;
132 SetServiceStatus(g_hServiceStatus, &g_status);
133
134 if (WAIT_OBJECT_0 == WaitForSingleObject(g_hStopEvent, INFINITE))
135 {
136 // do something
137 g_status.dwCurrentState = SERVICE_STOPPED;
138 SetServiceStatus(g_hServiceStatus, &g_status);
139 }
140 CloseHandle(g_hStopEvent);
141 OutputDebugString(TEXT("[HookForADService]ServiceMain finished..."));
142 }
143
144 //Description: 服务控制主函数,这里实现对服务的控制,
145 // 当在服务管理器上停止或其它操作时,将会运行此处代码
146 void WINAPI ServiceCtrlHandler(DWORD dwOpcode)
147 {
148 switch (dwOpcode)
149 {
150 case SERVICE_CONTROL_STOP:
151 g_status.dwCheckPoint = 1;
152 g_status.dwCurrentState = SERVICE_STOP_PENDING;
153 SetEvent(g_hStopEvent);
154 SetServiceStatus(g_hServiceStatus, &g_status);
155 OutputDebugString(TEXT("SERVICE_CONTROL_STOP"));
156 g_status.dwCheckPoint = 0;
157 g_status.dwCurrentState = SERVICE_STOPPED;
158 SetServiceStatus(g_hServiceStatus, &g_status);
159 PostThreadMessage(g_dwThreadID, WM_CLOSE, 0, 0);
160 break;
161 case SERVICE_CONTROL_PAUSE:
162 g_status.dwCheckPoint = 1;
163 g_status.dwCurrentState = SERVICE_PAUSE_PENDING;
164 SetEvent(g_hPauseContinueEvent);
165 SetServiceStatus(g_hServiceStatus, &g_status);
166 OutputDebugString(TEXT("SERVICE_CONTROL_PAUSE"));
167 g_status.dwCheckPoint = 0;
168 g_status.dwCurrentState = SERVICE_PAUSED;
169 SetServiceStatus(g_hServiceStatus, &g_status);
170 break;
171 case SERVICE_CONTROL_CONTINUE:
172 g_status.dwCheckPoint = 1;
173 g_status.dwCurrentState = SERVICE_CONTINUE_PENDING;
174 ResetEvent(g_hPauseContinueEvent);
175 SetServiceStatus(g_hServiceStatus, &g_status);
176 Sleep(500);
177 OutputDebugString(TEXT("SERVICE_CONTROL_CONTINUE"));
178 g_status.dwCheckPoint = 0;
179 g_status.dwCurrentState = SERVICE_RUNNING;
180 SetServiceStatus(g_hServiceStatus, &g_status);
181 break;
182 case SERVICE_CONTROL_INTERROGATE:
183 break;
184 case SERVICE_CONTROL_SHUTDOWN:
185 g_status.dwCurrentState = SERVICE_STOP_PENDING;
186 SetServiceStatus(g_hServiceStatus, &g_status);
187 SetEvent(g_hStopEvent);
188 OutputDebugString(TEXT("SERVICE_CONTROL_SHUTDOWN"));
189 g_status.dwCurrentState = SERVICE_STOPPED;
190 SetServiceStatus(g_hServiceStatus, &g_status);
191 PostThreadMessage(g_dwThreadID, WM_CLOSE, 0, 0);
192 break;
193 default:
194 LogEvent(_T("Bad service request"));
195 }
196 }
197
198 //判断服务是否已经被安装
199 BOOL IsInstalled()
200 {
201 BOOL bResult = FALSE;
202 // 打开服务控制管理器
203 SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
204 if (hSCM != NULL)
205 {
206 //打开服务
207 SC_HANDLE hService = ::OpenService(hSCM, g_szServiceName, SERVICE_QUERY_CONFIG);
208 if (hService != NULL)
209 {
210 bResult = TRUE;
211 ::CloseServiceHandle(hService);
212 }
213 ::CloseServiceHandle(hSCM);
214 }
215 return bResult;
216 }
217
218 // 安装服务函数
219 BOOL Install()
220 {
221 // 检测是否安装过
222 if (IsInstalled())
223 return TRUE;
224
225 // 打开服务控制管理器
226 SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
227 if (hSCM == NULL)
228 {
229 MessageBox(NULL, _T("Couldn't open service manager"), g_szServiceName, MB_OK);
230 return FALSE;
231 }
232
233 // 获取程序目录
234 TCHAR szFilePath[MAX_PATH];
235 ::GetModuleFileName(NULL, szFilePath, MAX_PATH);
236
237 // 创建服务
238 SC_HANDLE hService = ::CreateService(hSCM, g_szServiceName, g_szServiceName,
239 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
240 szFilePath, NULL, NULL, _T(""), NULL, NULL);
241
242 SERVICE_DESCRIPTION SvrDes;
243 TCHAR szDesc[] = TEXT("服务管理器里的服务描述");
244 SvrDes.lpDescription = szDesc;
245 ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &SvrDes);
246
247 // 检测创建是否成功
248 if (hService == NULL)
249 {
250 ::CloseServiceHandle(hSCM);
251 MessageBox(NULL, _T("Couldn't create service"), g_szServiceName, MB_OK);
252 return FALSE;
253 }
254
255 // 释放资源
256 ::CloseServiceHandle(hService);
257 ::CloseServiceHandle(hSCM);
258 return TRUE;
259 }
260
261 //删除服务函数
262 BOOL Uninstall()
263 {
264 //检测是否安装过
265 if (!IsInstalled())
266 return TRUE;
267
268 //打开服务控制管理器
269 SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
270 if (hSCM == NULL)
271 {
272 MessageBox(NULL, _T("Couldn't open service manager"), g_szServiceName, MB_OK);
273 return FALSE;
274 }
275
276 //打开具体服务
277 SC_HANDLE hService = ::OpenService(hSCM, g_szServiceName, SERVICE_STOP | DELETE);
278 if (hService == NULL)
279 {
280 ::CloseServiceHandle(hSCM);
281 MessageBox(NULL, _T("Couldn't open service"), g_szServiceName, MB_OK);
282 return FALSE;
283 }
284
285 // 先停止服务
286 SERVICE_STATUS status;
287 ::ControlService(hService, SERVICE_CONTROL_STOP, &status);
288
289 //删除服务
290 BOOL bDelete = ::DeleteService(hService);
291 ::CloseServiceHandle(hService);
292 ::CloseServiceHandle(hSCM);
293
294 LogEvent(_T("Service could not be deleted"));
295 return bDelete;
296 }
297
298 //记录服务事件
299 void LogEvent(LPCTSTR pFormat, ...)
300 {
301 TCHAR chMsg[256];
302 HANDLE hEventSource;
303 LPTSTR lpszStrings[1];
304 va_list pArg;
305
306 va_start(pArg, pFormat);
307 _vstprintf(chMsg, _countof(chMsg), pFormat, pArg);
308 va_end(pArg);
309
310 lpszStrings[0] = chMsg;
311
312 hEventSource = RegisterEventSource(NULL, g_szServiceName);
313 if (hEventSource != NULL)
314 {
315 ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (LPCTSTR*)&lpszStrings[0], NULL);
316 DeregisterEventSource(hEventSource);
317 }
318 }
windows服务开发demo的更多相关文章
- C# Windows服务开发从入门到精通
一.课程介绍 大家都知道如果想要程序一直运行在windows服务器上,最好是把程序写成windows服务程序:这样程序会随着系统的自动启动而启动,自动关闭而关闭,不需要用户直接登录,直接开机就可以启动 ...
- ASP.NET Core Windows服务开发技术实战演练
一.课程介绍 人生苦短,我用.NET Core!大家都知道如果想要程序一直运行在Windows服务器上,最好是把程序写成Windows服务程序:这样程序会随着系统的自动启动而启动,自动关闭而关闭,不需 ...
- Topshelf 一个简化Windows服务开发的宿主服务框架
Topshelf是 基于.net框架开发的宿主服务框架.该框架简化了服务的创建,开发人员只需要使用 Topshelf编写一个控制台程序,就能安装为Windows服务.之所以这样原因非常简单:调试一个控 ...
- .NET Windows服务开发流程
前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总结下, ...
- c#写windows服务 小demo
前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总结下, ...
- 记一次windows服务开发中遇到的问题
最近在研究windows service和quartz.net,所以迅速在园子大神那里扒了一个demo,运行,安装一切顺利. 但在在App.config配置中增加了数据库连接字符串配置后,服务安装后无 ...
- Windows服务编程Demo
实现一个开机自动启动的关机程序,具体代码如下: #include <Windows.h> void ServiceMain(); void ControlHandler(DWORD req ...
- WindowsService(Windows服务)开发步骤附Demo
1.打开VS,新建项目,选择Windows服务,然后设置目录及项目名称后点击确定. 2.展开Service1服务文件,编写service1.cs类文件,不是Service1[设计].然后修改OnSta ...
- WindowsService(Windows服务)开发步骤附Demo 【转】
转http://www.cnblogs.com/moretry/p/4149489.html 1.打开VS,新建项目,选择Windows服务,然后设置目录及项目名称后点击确定. 2.展开Service ...
- C# 创建Windows服务demo
一.准备工作 1.操作系统:Windows 10 X64 2.开发环境:VS2017 3.编程语言:C# 4. .NET版本:.NET Framework 4.5 二.创建Windows Servic ...
随机推荐
- PageOffice6 实现 word 全文检索
在文档服务器中存储有成千上万个文档的情况下,用户想要找到并打开包含特定关键字的文档,无疑是一项艰巨的任务.如何高效地管理和检索大量的Word文档呢? 在现有的技术解决方案中,许多方法都依赖于服务器端的 ...
- ChannelInboundHandlerAdapter 类
在 ChannelInboundHandlerAdapter 类中,除了 channelActive 和 channelRead 方法之外,还有其他方法用于处理不同类型的入站事件.以下是这些方法的解释 ...
- Windows Server 2022 安装
获取 Windows Server 2022 https://www.microsoft.com/zh-cn/evalcenter/evaluate-windows-server-2022 查看 Wi ...
- openssl 生成多域名 多IP 的数字证书
openssl.cnf 文件内容: [req] default_bits = 2048 distinguished_name = req_distinguished_name copy_extensi ...
- Jenkins 项目构建平台
引言 Jenkins是一个开源的.提供友好操作界面的持续集成(CI)工具,主要用于持续.自动的构建/测试软件项目.监控外部任务的运行.Jenkins 用 Java 语言编写,可在 Tomcat 等流行 ...
- Supervisor 守护进程管理工具
引言 Supervisor 是基于 Python 编程语言开发的一套通用的进程管理程序,它是通过 fork/exec 的方式把需要管理的进程作为子进程来管理. 安装 pip3 安装 superviso ...
- kubernetes(k8s)
应用程序部署的演变过程 在部署应用程序的方式上,主要经历了三个时代 传统部署 互联网早期,会直接将应用程序部署在物理机上 优点: 简单,不需要其他技术的参与 缺点: 不能为应用程序定义资源使用边界,很 ...
- 使用eNSP配置灵活QinQ
参考链接:https://blog.csdn.net/xu119718/article/details/55260519 在"使用eNSP配置端口QinQ"实验中是基于端口划分的用 ...
- 浅谈ChatGPT模型中的惩罚机制
本文由ChatMoney团队出品 在探讨ChatGPT模型的文本生成能力时,除了采样算法,惩罚机制同样扮演着至关重要的角色.这些机制不仅影响生成文本的多样性和创意性,还为我们提供了调整文本风格和质量的 ...
- .NET5 ASP.NET Core 使用 EF Core MS SQL SERVER DB First
.NET5 ASP.NET Core 使用 EF Core MS SQL SERVER DB First 开发工具:VS2019 1.修改appsettings.json,增加一项. "Co ...