目的是service中检查某个exe是否运行了,没有则启动程序。
启动的程序有界面。网上不少是使用ShellExecute来实现的,发现有问题,在win7下实现之后,service启动该程序时会出现一个提示,点击查看会切换到一个奇怪的界面来运行程序。这是因为已经调到session0了,如下图所示:
出现这个现象的原因是:
在Windows XP、Windows Server 2003 或早期Windows 系统时代,当第一个用户登录系统后服务和应用程序是在同一个Session 中运行的。但是这种运行方式提高了系统安全风险,因为服务是通过提升了用户权限运行的,而应用程序往往是那些不具备管理员身份的普通用户运行的,其中的危险显而易见。 从Vista 开始Session 0 中只包含系统服务,其他应用程序则通过分离的Session 运行,将服务与应用程序隔离提高系统的安全性。如下图所示:
这样使得Session 0 与其他Session 之间无法进行交互,不能通过服务向桌面用户弹出信息窗口、UI 窗口等信息。所以会弹出那个窗口。
所以ShellExecute适用于Vista之前的系统。Vista之后,则需要穿过session隔离来启动一个程序。方法是取得当前Session Id,然后以此id创建令牌,再调用CreateProcessAsUser以当前用户来启动程序。
代码示例如下:
BOOL bSuccess = TRUE;
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
if(dwSessionId == 0xFFFFFFFF)
{
bSuccess = FALSE;
//logger->TraceInfo("no active console session");
continue;
}
HANDLE hToken = NULL;
if(!WTSQueryUserToken(dwSessionId,&hToken))
{
bSuccess = FALSE;
//logger->TraceInfo("WTSQueryUserToken erong %d",GetLastError());
continue;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si,sizeof(STARTUPINFO));
ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
wchar_t desktopName[] = L"WinSta0\\Default";
si.lpDesktop = desktopName;
si.wShowWindow = TRUE;
si.dwFlags = STARTF_USESHOWWINDOW;
std::wstring wstr;
//这里是想启动的程序的路径
std::string str = (QCoreApplication::applicationDirPath()+"/"+PROGRAMNAME).toStdString();
wstr = std::wstring(str.begin(),str.end());
LPWSTR lp = (LPWSTR)wstr.c_str();
LPVOID pEnv = NULL;
if(FALSE == CreateEnvironmentBlock(&pEnv,hToken,FALSE))
{
bSuccess = FALSE;
//logger->TraceInfo("CreateEnvironmentBlock failed");
continue;
}
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE|CREATE_UNICODE_ENVIRONMENT;
if(!CreateProcessAsUser(hToken,NULL,lp,NULL,NULL,FALSE,dwCreationFlag,pEnv,NULL,&si,&pi))
{
bSuccess = FALSE;
//logger->TraceInfo("CreateProcessAsUser erong %d",GetLastError());
continue;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (hToken != NULL)
CloseHandle(hToken);
if (pEnv != NULL)
DestroyEnvironmentBlock(pEnv);
注意:
1.如果是非管理员用户,服务是无法调用管理员用户的程序,只能启动普通用户的程序。
2.service只能启动普通用户权限的程序,不能启动以管理员权限运行(UAC)的程序。
demo及使用说明