目的是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及使用說明