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的更多相关文章

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

    一.课程介绍 大家都知道如果想要程序一直运行在windows服务器上,最好是把程序写成windows服务程序:这样程序会随着系统的自动启动而启动,自动关闭而关闭,不需要用户直接登录,直接开机就可以启动 ...

  2. ASP.NET Core Windows服务开发技术实战演练

    一.课程介绍 人生苦短,我用.NET Core!大家都知道如果想要程序一直运行在Windows服务器上,最好是把程序写成Windows服务程序:这样程序会随着系统的自动启动而启动,自动关闭而关闭,不需 ...

  3. Topshelf 一个简化Windows服务开发的宿主服务框架

    Topshelf是 基于.net框架开发的宿主服务框架.该框架简化了服务的创建,开发人员只需要使用 Topshelf编写一个控制台程序,就能安装为Windows服务.之所以这样原因非常简单:调试一个控 ...

  4. .NET Windows服务开发流程

    前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总结下, ...

  5. c#写windows服务 小demo

    前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总结下, ...

  6. 记一次windows服务开发中遇到的问题

    最近在研究windows service和quartz.net,所以迅速在园子大神那里扒了一个demo,运行,安装一切顺利. 但在在App.config配置中增加了数据库连接字符串配置后,服务安装后无 ...

  7. Windows服务编程Demo

    实现一个开机自动启动的关机程序,具体代码如下: #include <Windows.h> void ServiceMain(); void ControlHandler(DWORD req ...

  8. WindowsService(Windows服务)开发步骤附Demo

    1.打开VS,新建项目,选择Windows服务,然后设置目录及项目名称后点击确定. 2.展开Service1服务文件,编写service1.cs类文件,不是Service1[设计].然后修改OnSta ...

  9. WindowsService(Windows服务)开发步骤附Demo 【转】

    转http://www.cnblogs.com/moretry/p/4149489.html 1.打开VS,新建项目,选择Windows服务,然后设置目录及项目名称后点击确定. 2.展开Service ...

  10. C# 创建Windows服务demo

    一.准备工作 1.操作系统:Windows 10 X64 2.开发环境:VS2017 3.编程语言:C# 4. .NET版本:.NET Framework 4.5 二.创建Windows Servic ...

随机推荐

  1. PPO近端策略优化玩cartpole游戏

    这个难度有些大,有两个policy,一个负责更新策略,另一个负责提供数据,实际这两个policy是一个东西,用policy1跑出一组数据给新的policy2训练,然后policy2跑数据给新的poli ...

  2. Authentication failed. Some common reasons include:

    问题无论是pull.clone还是push都报错 fatal: Out of memory, malloc failed (tried to allocate 301989888 bytes)fata ...

  3. iis worker process w3wp 进程 占用率100%

    今天电脑特别的卡,我没当回事,但是实在是卡得不行了,我打开任务管理器,发现 iis worker process 进程已经快100%了,我之前在iis上发布了一个webservice,我就把这个网站给 ...

  4. jQuery模态框原理

    <!-- 引入jQuery.js --> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquer ...

  5. 原生Django出现同源策略跨域的解决方式

    解决方式: 在返回数据的时候,添加响应头信息: 例如:

  6. equals && deepEquals

    equals && deepEquals 本文分为以下几个部分 equals deepEquals 总结 equals 首先说明:这里说的 equals 是 java.util.Arr ...

  7. ABP邮件发送

    ABP  Vnext发邮件要使用AbpMailKitModule的实现IEmailSender,要检查添加了Volo.Abp.MailKit,其dependon 要添加typeof() 它使用Sett ...

  8. 计算巢AppFlow-如何在钉钉群实现智能答疑

    随着大模型能力越来越强大,利用大语言模型进行智能答疑已经成为了一个非常普遍和常见的场景.然而,各个产品或业务方要能够准确有效地进行答疑,仅依靠大模型的通用能力是远远不够的,这时候利用私有领域FAQ文档 ...

  9. Swift全局变量的线程安全分析

    一.示例代码 import UIKit let obj = TestObj() class TestObj { init() { print("\(type(of: self)) init& ...

  10. Redis单线程

    Redis是基于Reactor模式开发的网络事件处理器,这个处理器是单线程的,所 以redis是单线程的. 为什么它是单线程还那么快呢? 主要有以下几个原因: 一.纯内存操作 由于Redis是纯内存操 ...