从服务启动用户会话中的进程 [英] Launching a process in user’s session from a service

查看:25
本文介绍了从服务启动用户会话中的进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Windows Vista/7/2008/2008R2 中,是否有可能从服务启动用户会话中的进程?具体来说,本地会话将是最有用的.

In Windows Vista/7/2008/2008R2, is it at all possible to launch a process in a user's session from a service? Specifically, the local session would be most useful.

我读过的所有内容似乎都说这是不可能的,但我想在完全放弃之前我应该​​在这里问一下.

Everything I've been reading seems to say this isn't possible, but I figured I'd ask here before giving up completely.

我在 VB.NET 中编码,但会接受任何建议.

I'm coding in VB.NET, but will take suggestions in anything.

推荐答案

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

It is really possible. The main problem which you have is that Windows should be seen as a terminal server and a users session as a remote session. Your service should be able to start a process which run in the remote session belongs to the user.

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

By the way, if you write a service which run under Windows XP which is not added to a domain and the fast user switching is activated, you can have the same problems to start a process on running on the second (third and so on) logged users desktop.

我希望您有一个用户令牌,例如您收到的关于模拟的用户令牌,或者您拥有会话的 dwSessionId.如果您没有它,您可以尝试使用一些 WTS 功能(远程桌面服务 API http://msdn.microsoft.com/en-us/library/aa383464.aspx,例如 WTSEnumerateProcessesWTSGetActiveConsoleSessionId) 或 LSA-API找出相应的用户会话(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).

I hope you have a user token, which you receive for example with respect of impersonation or you have a dwSessionId of session. If you don't have it you can try use some WTS-function (Remote Desktop Services API http://msdn.microsoft.com/en-us/library/aa383464.aspx, for example WTSEnumerateProcesses or WTSGetActiveConsoleSessionId) or LSA-API to find out the corresponding users session (LsaEnumerateLogonSessions see http://msdn.microsoft.com/en-us/library/aa378275.aspx and LsaGetLogonSessionData see http://msdn.microsoft.com/en-us/library/aa378290.aspx) or ProcessIdToSessionId (see http://msdn.microsoft.com/en-us/library/aa382990.aspx).

您可以使用带有参数 TokenSessionIdGetTokenInformation 函数(请参阅 http://msdn.microsoft.com/en-us/library/aa446671.aspx) 以接收用户的会话 ID dwSessionId如果您知道用户令牌 hClient.

You can use GetTokenInformation function with the parameter TokenSessionId (see http://msdn.microsoft.com/en-us/library/aa446671.aspx) to receive the session id dwSessionId of the users session if you knows the users 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 权限才能切换当前终端服务器会话.

This code only a schema. EnablePrivilege is a simple function used AdjustTokenPrivileges to enable SE_TCB_NAME privilege (see http://msdn.microsoft.com/en-us/library/aa446619.aspx as a template). It is important that the process from which you are start a process you have TCB privilege, but if your service run under the Local System you have enough permissions. By the way, following code fragment work with not only Local System account, but the account must have SE_TCB_NAME privilege to be able to switch current terminal server session.

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

One more remark. In the code above we start new process with the same account as the current process have (for example Local System). You change change a code to use another account for example the users token hClient. It is only important to have a primary token. If you have an impersonation token you can convert it to the primary token exactly like in the code above.

CreateProcessAsUser 中使用的 STARTUPINFO 结构中,您应该使用 lpDesktop = WinSta0Default".

In the STARTUPINFO structure used in CreateProcessAsUser you should use lpDesktop = WinSta0Default".

根据您的要求,可能还需要使用 CreateEnvironmentBlock 来创建您将传递给新进程的新环境块.

Depend on your requirements it could be also needed to use CreateEnvironmentBlock to create an new environment block that you will be passing to the new process.

我建议您也阅读 如何确保 Process.Start(ProcessStartInfo) 启动的进程窗口具有所有 Forms 的焦点? 我描述了如何强制该进程在用户桌面的前台启动.

I recommend you also to read How to ensure process window launched by Process.Start(ProcessStartInfo) has focus of all Forms? where I describe how to force that the process will be started in foreground on the users desktop.

这篇关于从服务启动用户会话中的进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆