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. 原创->CommonsCollections1-DefaultMap链

    今天我打算整点儿不一样的内容,通过之前学习的TransformerMap和LazyMap链,想搞点不一样的,所以我关注了另外一条链DefaultedMap链,主要调用链为: 调用链详细描述: Obje ...

  2. 我们小公司,哪像华为一样,用得上IPD(集成产品开发)?

    在一些咨询或活动现场,我们经常听到有朋友说:我们是小公司,IPD(集成产品开发)太厚重了,不适合我们.但--到底哪里不合适? 提及IPD,成功的案例多以大公司为主:20世纪90年代,IBM在激烈的市场 ...

  3. c# 获得变量名称

    string GetVariableName<T>(Expression<Func<T>> expr)        {            var body = ...

  4. 如何更加优雅的使用 SSH 进行登录

    引言 我们在日常的开发过程中,很多时候需要连接服务器查看日志或者在服务器上调试代码.但是,使用 ssh 命令登录服务器每次都需要输出密码,就比较繁琐.因此我们可以使用 sshpass 通过参数指定密码 ...

  5. 初步搭建一个自己的对象存储服务---Minio

    docker安装 1.拉取镜像 docker pull minio/minio 2.启动镜像 docker run -p 9000:9000 -p 9001:9001 --name minio -d ...

  6. docker ——网络配置和管理

    docker网络基础 了解docker网络 两种docker网络 单主机与多主机的docker网络 网络驱动 网络驱动 介绍 bridge 桥接网络,这是默认的网络驱动程序 host 主机网络 ove ...

  7. 【现代 CSS】标准滚动条控制规范 scrollbar-color 和 scrollbar-width

    Chrome 在 121 版本开始,原生支持了两个滚动条样式相关的样式 scrollbar-color 和 scrollbar-width. 要知道,在此前,虽然有 ::-webkit-scrollb ...

  8. MySQL插入中文数据时发生错误或者乱码的一些坑

    最近新入职的工作,火急火燎就下了个mysql,没想到安装时配置没弄好.今天在测试数据时,插入中文数据到mysql都是问号,先后查了半天修改表结构,数据库编码,my.ini文件都没有用. 首先第一步,打 ...

  9. 什么是JDBC的最佳实践?

    a.数据库资源是非常昂贵的,用完了应该尽快关闭它.Connection,   Statement,    ResultSet等JDBC对象都有close方法,调用它就好了. b.养成在代码中显式关闭掉 ...

  10. OFBiz RCE漏洞复现(CVE-2023-51467)

    漏洞名称 Apache OFBiz 鉴权绕过导致命令执行 漏洞描述 Apache OFBiz是一个非常著名的电子商务平台,是一个非常著名的开源项目,提供了创建基于最新J2EE/XML规范和技术标准,构 ...