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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)