解决方案实际上取决于您的需求,并且可能非常复杂(完全感谢 Windows Vista)。这可能超出您的需要,但这将有助于通过搜索找到此页面的其他人。
- 如果您不需要使用 GUI 运行该过程并且您不需要提升
- 如果您要运行的用户已经登录到会话
- 如果您需要使用 GUI 运行该过程,并且用户可能已登录,也可能未登录
- 如果您需要使用海拔运行流程
关于 1:
在 Windows Vista 中存在称为会话 0 隔离的东西。所有服务都作为会话 0 运行,并且您不应该在会话 0 中有 GUI。第一个登录的用户登录到会话 1。在以前版本的 windows(Vista 之前)中,第一个登录的用户也完全运行在会话 0。
您可以在同一会话中使用不同的用户名运行多个不同的进程。您可以在此处找到有关会话 0 隔离的好文档。
由于我们正在处理选项 1),因此您不需要 GUI。因此,您可以在会话 0 中开始您的进程。
您需要一个类似这样的调用序列:LogonUser、ExpandEnvironmentStringsForUser、GetLogonSID、LoadUserProfile、CreateEnvironmentBlock、CreateProcessAsUser。
可以通过任何搜索引擎或通过Google 代码搜索找到此示例代码
关于 2: 如果您希望运行该进程的用户已经登录,您可以简单地使用:WTSEnumerateSessions 和 WTSQuerySessionInformation 来获取会话 ID,然后使用 WTSQueryUserToken 来获取用户令牌。从那里您可以在 CreateProcessAsUser Win32 API 中使用用户令牌。
这是一个很好的方法,因为您甚至不需要以用户身份登录,也不知道用户的用户名/密码。我相信这只能通过服务作为本地系统帐户运行。
您可以通过 WTSGetActiveConsoleSessionId 获取当前会话。
关于 3:
您将遵循与 #1 相同的步骤,但此外您将使用 STARTUPINFO 的 lpDesktop 字段。将此设置为 winsta0\Default。您还需要尝试使用 OpenDesktop Win32 API,如果失败,您可以使用 CreateDesktop。在使用工作站和桌面句柄之前,您应该使用 SE_WINDOW_OBJECT 和 GROUP_SECURITY_INFORMATION | 在每个句柄上使用 SetSecurityInfo。DACL_SECURITY_INFORMATION。
如果有问题的用户稍后尝试登录,他实际上会看到正在运行的进程。
关于 4:
这也可以完成,但它要求您已经在运行提升的进程。作为本地系统帐户运行的服务确实以提升的身份运行。我也只能通过我想要启动的验证码签名过程来让它工作。您要启动的进程还必须具有与其关联的清单文件,其中 requestedExecutionLevel level="requireAdministrator"
其他注意事项:
- 您可以通过 SetTokenInformation 和 TokenSessionId 设置令牌的会话
- 您不能更改已运行进程的会话 ID。
- 如果 Vista 不在等式中,整个过程将变得更加简单。