windows服务守护界面程序

windows服务守护界面程序

2023年6月23日发(作者:)

windows服务守护界⾯程序编写windows服务与普通控制台程序相⽐,⼊⼝不同,需要重写某些函数。基本套路都差不多,不过我按照的例⼦写完,服务⼀直卡在正在启动。是在外⽹找到的⼀个简单的服务例⼦,下⾯程序就是在这个基础上编写的。服务程序写起来⽐较简单,不过⼀般⼤家编写服务都是为了作为守护程序。当主程序挂了后再给它带起来,或在开机时带起主程序(注意: 注销不是重启,注销后服务保持注销前状态,因为注销不影响session0)。然⽽⼤部分的主程序都是界⾯程序,直接⽤ShellExecuteA等windows接⼝启动界⾯程序,在任务管理器中能看到进程,但并没有界⾯。原理:⽤户登录后,会创建多个会话。所有会话都有多个窗⼝、桌⾯、⼯作站。但这些会话中的所有⼯作中同时仅有⼀个交互⼯作站(交互⼯作中可切换),也可以叫做winsta0,winsta0的有三个标准的桌⾯: 登录桌⾯,默认界⾯(交互桌⾯)、disconnect,这⾥是。WinSta0 是唯⼀的⼀个可以显⽰⽤户界⾯和接收⽤户输⼊的窗⼝站。其他所有的窗⼝站都是⾮交互的,也就说它们不能显⽰⽤户界⾯,也不能接收⽤户输⼊。⽽我们的服务⼀般都处于其他session下(原因下⾯介绍)。⽽在服务进程中启动我们的主程序,那么主程序也会放在相同windo station中。但是当前的⽤户交互界⾯是在session y下的某⼀⼯作站中,因此只创建出了主程序进程,⽽没有界⾯。那么在session x中如何创建出界⾯程序:这⾥提⼀下:以跨时代意义的系统为分界线,之前的服务启动后会由操作系统分配到合适的session和station中。⽽vista及之后系统,session0作为⼀个没有交互的会话,存储着windows服务以及其他不需要与⽤户交互的程序。vista之前系统⽬前存在极少,在最后的链接1 中也有解决⽅案,这⾥不详谈。vista之后,由于windows单独出⼀个session0,就是为了分隔出不需要交互的程序。所以需要通过session0通知session x,然后开启界⾯程序.

主要函数代码如下。//层级:session/station(winsta0)/desktop//服务属于session0,没有名为winsta0的station,也就没有其下的交互界⾯//需要通过session0通知当前交互界⾯的session,开启界⾯程序DWORD _stdcall LaunchAppIntoDifferentSession(LPTSTR lpFileName, LPTSTR lpCommand){ DWORD dwRet = 0; HANDLE hUserToken = NULL; HANDLE hUserTokenDup = NULL; HANDLE hPToken = NULL; // Log the client on to the local computer. DWORD dwSessionId; dwSessionId = WTSGetActiveConsoleSessionId(); std::string sessionLogStr = std::string("LaunchAppIntoDifferentSession: Active console session id: ") + std::to_string(dwSessionId); writeLog(sessionLogStr); do { WTSQueryUserToken(dwSessionId, &hUserToken); WTSQueryUserToken(dwSessionId, &hUserToken); DWORD dwCreationFlags; dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(STARTUPINFO)); = sizeof(STARTUPINFO); top = "winsta0default"; //indow = SW_SHOW; //s = STARTF_USESHOWWINDOW /*|STARTF_USESTDHANDLES*/; ZeroMemory(&pi, sizeof(pi)); TOKEN_PRIVILEGES tp; LUID luid; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, &hPToken)) { dwRet = GetLastError(); break; } if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { dwRet = GetLastError(); break; } egeCount = 1; eges[0].Luid = luid; eges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hUserTokenDup)) { dwRet = GetLastError(); break; } //Adjust Token privilege if (!SetTokenInformation(hUserTokenDup, TokenSessionId, (void*)& dwSessionId, sizeof(DWORD))) { dwRet = GetLastError(); break; } if (!AdjustTokenPrivileges(hUserTokenDup, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, NULL)) { dwRet = GetLastError(); break; } LPVOID pEnv = NULL; if (CreateEnvironmentBlock(&pEnv, hUserTokenDup, TRUE)) { dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; } else pEnv = NULL; // Launch the process in the client's logon session. if (!CreateProcessAsUser(hUserTokenDup, // client's access token lpFileName, // file to execute lpCommand, // command line NULL, // pointer to process SECURITY_ATTRIBUTES NULL, // pointer to thread SECURITY_ATTRIBUTES FALSE, // handles are not inheritable dwCreationFlags,// creation flags pEnv, // pointer to new environment block NULL, // name of current directory NULL, // name of current directory &si, // pointer to STARTUPINFO structure &pi // receives information about new process )) { dwRet = GetLastError(); break; } if (pEnv){ DestroyEnvironmentBlock(pEnv); } } while (0); //Perform All the Close Handles task if (NULL != hUserToken) { CloseHandle(hUserToken); } if (NULL != hUserTokenDup) { CloseHandle(hUserTokenDup); } if (NULL != hPToken) { CloseHandle(hPToken); } return dwRet;}通过这样的⽅式确实可以在服务中启动界⾯程序了.这样的作法有个问题,当你使⽤远程桌⾯连接时,WTSGetActiveConsoleSessionId返回的是你登录进⼊的session,⽽⾮显⽰界⾯的session.解决:使⽤函数WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessionInfo, &sessionInfoCount);遍历所有session。当获得active的session时,通过WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionInfo[i].SessionId, WTSUserName, &pBuffer,&dwBufferLen);得到session的userName。结果如下:远程机器:本机:可以看出来,当你处于远程连接状态时,WTSGetActiveConsoleSessionId返回的sessionID是1,⽽真正的交互界⾯session为2。⽽且windows把session0的winstationName设置为Services,把当前登录的⽤户的winstationName设置为了Console。因此可以通过遍历session,判断session的State,当其等于WTSActive时,表明是交互界⾯。

初次接触windows服务的⼈员可能不清楚后续要做的事:1、打开cmd,sc create XXX(服务名) binPath= "c:/test/" binPath后不能有空格,=后需要有空格。创建成功后,打开任务管理器可以在服务中看到改服务2、sc start XXX; 开启服务,如果需要开机⾃启,可以右键打开服务,找到服务右键属性,设置启动类型为⾃动。 sc stop XXX;关闭服务sc delete XXX;删除服务

。参考链接1:参考链接2:参考链接3:参考链接4:参考链接5:

发布者:admin,转转请注明出处:http://www.yc00.com/web/1687516364a16244.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信