【发布时间】:2011-11-09 06:48:24
【问题描述】:
我正在寻找示例代码:
对于调用 CreateProcessAsUser() 的服务,我希望进程在用户会话中运行,而不是在会话 0 中运行
到目前为止,创建的进程仅像会话 0 中的服务一样运行
【问题讨论】:
标签: windows winapi windows-7 windows-services createprocessasuser
我正在寻找示例代码:
对于调用 CreateProcessAsUser() 的服务,我希望进程在用户会话中运行,而不是在会话 0 中运行
到目前为止,创建的进程仅像会话 0 中的服务一样运行
【问题讨论】:
标签: windows winapi windows-7 windows-services createprocessasuser
这是从一些从服务启动控制台应用程序的旧代码中删除的。它在 NT4 下工作,但我没有在现代版本的 Windows 上测试过它,所以不能保证它会像在 NT4 上一样工作。
编辑:不,这不会按原样工作。需要添加找到here的代码来创建桌面、设置SID等
if (!LogonUser(userId,
domain,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&hUserToken))
{
return GetLastError();
}
if (!ImpersonateLoggedOnUser(hUserToken))
{
DWORD rc = GetLastError();
CloseHandle(hUserToken);
return rc;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
rc = CreateProcessAsUser(hUserToken, // user token
0, // app name
"foo.exe", // command line
0, // process attributes
0, // thread attributes
FALSE, // don't inherit handles
DETACHED_PROCESS, // flags
0, // environment block
0, // current dir
&si, // startup info
&pi); // process info gets put here
if (!rc)
{
DWORD rc = GetLastError();
RevertToSelf();
CloseHandle(hUserToken);
return rc;
}
RevertToSelf();
CloseHandle(hUserToken);
return 0;
【讨论】:
STARTUPINFO 结构中指定现有桌面,例如用户的交互式WinSta0\Default 桌面(如Microsoft 示例所示)。而且你也不需要乱搞 SID。没有它们,服务中的CreateProcessAsUser() 可以正常工作。我多年来一直在服务中使用它,没有任何问题,并且我不会为它操作 SID。另一方面,我不使用LogonUser() 或ImpersonateLoggedOnUser(),而是使用WTSQueryUserToken() 和DuplicateTokenEx()。
CreateProcessAsUser()之前先拨打CreateEnvironmentBlock()。
WTSQueryUserToken获取的用户token。它已经返回给你一个主令牌
我知道这是一篇古老的帖子,但我碰巧正在研究这个,所以这里有一些适合我的代码。
确定当前登录用户的会话 ID
DWORD GetCurrentSessionId ()
{
WTS_SESSION_INFO *pSessionInfo;
DWORD n_sessions = 0;
BOOL ok = WTSEnumerateSessions (WTS_CURRENT_SERVER, 0, 1, &pSessionInfo, &n_sessions);
if (!ok)
return 0;
DWORD SessionId = 0;
for (DWORD i = 0; i < n_sessions; ++i)
{
if (pSessionInfo [i].State == WTSActive)
{
SessionId = pSessionInfo [i].SessionId;
break;
}
}
WTSFreeMemory (pSessionInfo);
return SessionId;
}
以当前登录用户身份启动进程
bool LaunchProcess (const char *process_path)
{
DWORD SessionId = GetCurrentSessioId ();
if (SessionId == 0) // no-one logged in
return false;
HANDLE hToken;
BOOL ok = WTSQueryUserToken (SessionId, &hToken);
if (!ok)
return false;
void *environment = NULL;
ok = CreateEnvironmentBlock (&environment, hToken, TRUE);
if (!ok)
{
CloseHandle (hToken);
return false;
}
STARTUPINFO si = { sizeof (si) } ;
PROCESS_INFORMATION pi = { } ;
si.lpDesktop = "winsta0\\default";
// Do NOT want to inherit handles here
DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT;
ok = CreateProcessAsUser (hToken, process_path, NULL, NULL, NULL, FALSE,
dwCreationFlags, environment, NULL, &si, &pi);
DestroyEnvironmentBlock (environment);
CloseHandle (hToken);
if (!ok)
return false;
CloseHandle (pi.hThread);
CloseHandle (pi.hProcess);
return true;
}
【讨论】:
WTSActive 和 WTS_CURRENT_SERVER 的未定义错误
WTSQueryUserToken 令牌模拟登录用户吗?
ImpersonateLoggedOnUser会接受这样的令牌,是的。我建议你试一试。