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 }
复制代码

 

posted on   崔好好  阅读(39)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)

导航

< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5
点击右上角即可分享
微信分享提示