c# - 从服务启动用户 session 中的进程

标签 c# vb.net windows winapi windows-services

在 Windows Vista/7/2008/2008R2 中,是否可以通过服务在用户 session 中启动进程?具体而言,本地 session 最有用。

我一直在阅读的所有内容似乎都在说这是不可能的,但我想在完全放弃之前我会在这里问一下。

我正在用 VB.NET 编写代码,但会接受任何建议。

最佳答案

这真的有可能。您遇到的主要问题是 Windows 应被视为终端服务器,而用户 session 应被视为远程 session 。您的服务应该能够启动在属于用户的远程 session 中运行的进程。

顺便说一句,如果您编写的服务在未添加到域的 Windows XP 下运行并且激活了快速用户切换,则在第二个(第三个和第二个)上启动进程时可能会遇到相同的问题等等)登录用户桌面。

我希望您有一个用户 token ,例如您收到关于模拟的用户 token ,或者您有一个 dwSessionId session 。如果您没有它,您可以尝试使用一些 WTS 函数(远程桌面服务 API http://msdn.microsoft.com/en-us/library/aa383464.aspx,例如 WTSEnumerateProcessesWTSGetActiveConsoleSessionId)或 LSA-API 来查找输出相应的用户 session (LsaEnumerateLogonSessions 请参阅 http://msdn.microsoft.com/en-us/library/aa378275.aspxLsaGetLogonSessionData 请参阅 http://msdn.microsoft.com/en-us/library/aa378290.aspx )或 ProcessIdToSessionId (请参阅 http://msdn.microsoft.com/en-us/library/aa382990.aspx )。

您可以使用带有参数 TokenSessionIdGetTokenInformation 函数(参见 http://msdn.microsoft.com/en-us/library/aa446671.aspx )来接收用户 session 的 session ID dwSessionId 如果你知道用户 token hClient

BOOL bSuccess;
HANDLE hProcessToken = NULL, hNewProcessToken = NULL;
DWORD dwSessionId, cbReturnLength;

bSuccess = GetTokenInformation (hClient, TokenSessionId, &dwSessionId,
                                sizeof(DWORD), &cbReturnLength);
bSuccess = OpenProcessToken (GetCurrentProcess(), MAXIMUM_ALLOWED, &hProcessToken);
bSuccess = DuplicateTokenEx (hProcessToken, MAXIMUM_ALLOWED, NULL,
                             SecurityImpersonation,
                             TokenPrimary, &hNewProcessToken);
EnablePrivilege (SE_TCB_NAME);
bSuccess = SetTokenInformation (hNewProcessToken, TokenSessionId, &dwSessionId,
                                sizeof(DWORD));
bSuccess = CreateProcessAsUser (hNewProcessToken, NULL, szCommandToExecute, ...);

此代码只是一个架构。 EnablePrivilege 是一个简单的函数,使用 AdjustTokenPrivileges 来启用 SE_TCB_NAME 权限(参见 http://msdn.microsoft.com/en-us/library/aa446619.aspx 作为模板)。重要的是,您从中启动的进程具有 TCB 权限,但如果您的服务在本地系统下运行,您就有足够的权限。顺便说一下,下面的代码片段不仅适用于本地系统帐户,而且该帐户必须具有 SE_TCB_NAME 权限才能切换当前终端服务器 session 。

再多说一句。在上面的代码中,我们使用与当前进程相同的帐户(例如本地系统)启动新进程。您更改代码以使用另一个帐户,例如用户 token hClient。唯一重要的是拥有一个 primary token。如果您有模拟 token ,您可以将其转换为主 token ,就像上面的代码一样。

CreateProcessAsUser 中使用的 STARTUPINFO 结构中,您应该使用 lpDesktop = WinSta0\Default"。

根据您的要求,可能还需要使用 CreateEnvironmentBlock 创建一个您将传递给新进程的新环境 block 。

我建议您也阅读 How to ensure process window launched by Process.Start(ProcessStartInfo) has focus of all Forms?我在其中描述了如何强制该进程在用户桌面的前台启动。

关于c# - 从服务启动用户 session 中的进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3128017/

相关文章:

c# - 我应该在 DropCreateDatabaseIfModelChanges 中还是在 DbMigrationsConfiguration 中播种数据库?

c - 如何使用 MSVC 在 Windows 上针对 "cdylib"Rust lib 编译+链接一个简单的 hello_world.c

java - 如何从网络摄像头拍摄单张快照?

java - 为 Installanywhere2010 安装程序设置 UAC 'Publisher' 字段

c# - 允许使用 LINQ 查询中的 ToDictionary() 重复键

c# - 使用简单注入(inject)器注入(inject)控制台应用程序

c# - 如何构造函数注入(inject)仅在运行时已知的字符串? (温莎城堡)

c# - 在 EXE 安装后保持提升的权限并在重启期间自动启动?

asp.net - 从多个表中删除 ASP.NET

c# - ASP.NET:获取自 1/1/1970 以来的毫秒数