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. 在 Chromebook 上使用 Word 的最佳方法

    Splashtop 允许您从 Chromebook 远程控制 Windows 和 Mac 计算机,从而可以访问 Word 的桌面版本和所有文件. 对于远程工作者和学生,Chromebook 可以是一种 ...

  2. 关于URP14绘制全屏Blit后处理的改动

    最近用回URP,发现RendererFeature这部分改动很大,启用了之前HDRP的RTHandle,RTHandle的设计类似于优化版本的RenderTexture, 可以统一控制缩放或者并非一对 ...

  3. AI 一键生成高清短视频,视频 UP 主们卷起来...

    现在短视频越来越火,据统计,2023年全球短视频用户数量已达 10 亿,预计到2027年将突破 24 亿.对于产品展示和用户营销来说,短视频已经成为重要阵地,不管你喜不喜欢它,你都得面对它,学会使用它 ...

  4. Python:conda install 和pip install的区别

    pip是个安装包的软件,conda是个环境管理的工具.conda能够安装多个python解释器,pip不行.因此conda在实际开发中是主要用来隔离不同的python版本和Tensorflow& ...

  5. PHP 有哪些常用的魔术变量 ?

    引言 PHP 向它运行的任何脚本提供了大量的预定义常量. 魔术变量 __LINE__ 文件中的当前行号. __FILE__ 文件的完整路径和文件名. 如果用在被包含文件中,则返回被包含的文件名. __ ...

  6. js 中你不知道的各种循环测速

    在前端 js 中,有着多种数组循环的方式: for 循环: while 和 do-while 循环: forEach.map.reduce.filter 循环: for-of 循环: for-in 循 ...

  7. Wpf虚拟屏幕键盘

    在Wpf使用虚拟键盘有基于osk和tabtip,后者只能在win8和win10之后电脑使用,而且两者在wpf中调用时都必须提升为管理员权限,实际应用中还是不方便. 今天介绍的方法是使用第三方库oskl ...

  8. github无法访问的问题

    Windows10 通过nslookup命令获取GitHub域名服务器地址,然后ping该地址 nslookup github.com ping 域名服务器地址 发现20.205.243.166能稳定 ...

  9. 15种pod的状态

    15种pod的状态 调度失败 常见错误状态(Unschedulable) pod被创建后进入调度阶段,k8s调度器依据pod声明的资源请求量和调度规则,为pod挑选一个适合运行的节点.当集群节点不满足 ...

  10. EF,lambda 反向模糊查询

    SELECT * FROM table as t WHERE "张三的偶像" LIKE t.userName; bool thisMchBelong = _mch_blackSer ...