在开发守护进程时,遇到一个问题,发了一天时间,才找到问题的思路。特记录下:
[问题]
将A.exe注册为服务,通过执行WinExec("B.exe的完整路径"{非注册服务}, SW_HIDE),启动B.exe时,在任务管理器中也存在相应进程,但是**无法显示界面**,这是什么原因?
[原因]
因为A.exe是系统权限,它在session 0,而B.exe他是session1.当A程序运行在session0,也就是系统服务窗口,所以你当前桌面上是看不到的。这种情况你需要用CreateProcessAsUser()API等方式模拟当前登陆用户方式。
[解决方案]
virtual bool DoStart(int tryInterval, int tryTime) {
int error;
bool result;
HANDLE hToken = NULL;
HANDLE hDupedToken = NULL;
// HANDLE hUserToken = NULL;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = L"winsta0\\default";
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
DWORD dwSessionId, winlogonPid;// Loag the client on to the local computer
dwSessionId = WTSGetActiveConsoleSessionId();
/////////////////////////////////////////////////////
// Find the FSI.SnifferClient.UI.exe process
/////////////////////////////////////////////////
PROCESSENTRY32 procEntry;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE) {
return false;
}
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &procEntry)) {
error = GetLastError();
return false;
}
do {
char output[256];
WCHAR* wc = procEntry.szExeFile;
sprintf(output, "%ws", wc);
if (_stricmp(output, "winlogon.exe") == 0) {
// We found a winlogon process...
// make sure it's running in the console session
DWORD fsiSnifferClientSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, &fsiSnifferClientSessId)
&& fsiSnifferClientSessId == dwSessionId) {
winlogonPid = procEntry.th32ProcessID;
break;
}
}
} while (Process32Next(hSnap, &procEntry));
HANDLE hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, winlogonPid);
if (!::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
| TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID
| TOKEN_READ | TOKEN_WRITE, &hToken)) {
error = GetLastError();
return false;
}
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
error = GetLastError();
return false;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
result = DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDupedToken);
SetTokenInformation(hDupedToken, TokenSessionId, (void*)dwSessionId, sizeof(DWORD));
if (!AdjustTokenPrivileges(hDupedToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL, NULL)) {
error = GetLastError();
return false;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
error = GetLastError();
return false;
}
string ClientAppPath = ""; // APP的完整路径
Util::GetRegValue(GetSubKey().c_str(), "AppPath", ClientAppPath);
ClientAppPath += "\\xxx.exe";
LPVOID pEnv = NULL;
DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
if (CreateEnvironmentBlock(&pEnv, hDupedToken, TRUE)) {
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
result = CreateProcessAsUser(
hDupedToken,
ConvertCharToLPWSTR(ClientAppPath.c_str()),
NULL,
NULL,
NULL,
FALSE,
dwCreationFlags,
pEnv,
NULL,
&si,
&pi);
CloseHandle(hProcess);
CloseHandle(hDupedToken);
CloseHandle(hToken);
int ret;do {
Sleep(tryInterval);
ExeInfo info;
info.ProcessName = GetExeName();
ret = FindProcess(info);
} while (--tryTime && (ret != 1));
return ret == 1;
}
参考链接:
(1) https://blog.csdn.net/findsafety/article/details/45971161
(2) https://www.codeproject.com/Articles/18367/Launch-your-application-in-Vista-under-the-local-s
(3) http://ask.csdn.net/questions/192521
(4) https://blog.csdn.net/tpriwwq/article/details/45221301
(5) https://blog.csdn.net/theone10211024/article/details/14001943
(6) https://blog.csdn.net/jeanphorn/article/details/45745739