4

我正在使用 Windows 服务内部运行一个进程

ProcessStartInfo processStartInfo = new ....
Process.Start(processStartInfo);

问题是,如果我在本地系统帐户下运行服务,它运行正常,但它不显示程序的窗口。我尝试将用户凭据放入服务属性中,但随后“允许服务与桌面交互”复选框变为禁用状态。

我真的需要运行从服务调用它的应用程序,我真的需要查看应用程序的窗口。

请帮帮我。

UPD。好吧,您使用重载版本的 Process.Start 需要用户名、密码和域 - 它会将程序拉到桌面。但现在它在一个凭据下启动应用程序,但在不同用户的桌面上显示。怎么会?

UPD2:我有个主意!我可以使用 Sysinternals Suite 中的 psexec.exe。但问题是我需要“以管理员身份”默默地启动那个东西。而且我不知道怎么做。我的意思是即使您已经拥有管理员权限,有时您也必须手动说“以管理员身份运行”,确认 UAC,然后才可以开始使用。我不知道不带 UAC 的东西如何默默地运行一些东西....

UPD3:亲爱的主。我有那个东西!最后。

行。一开始,问题确实出在会话 0 隔离中。所以我需要构建一个可以从服务启动的中间应用程序,然后该应用程序又假设通过 RPC 启动我的应用程序并将其带到桌面。我决定使用 psexec 工具而不是构建中间层应用程序(无论如何它完全按照我需要的方式工作 - 通过 RPC)。当我尝试在本地系统帐户下使用该工具时,由于某种原因它不起作用。然后我意识到-原因是MS在每个pstool中都放了该死的EULA弹出对话框,并且无法单击按钮以在本地系统帐户下确认对话框。所以解决方案是在注册表中创建一个密钥 HKU.DEFAULT\Software\Sysinternals\PsExec 与 DWORD 值 EulaAccepted = 1

万岁,现在可以了!但!现在我需要把程序带到当前登录用户的屏幕上。为此,我需要会话 ID!

所以问题是:如何获取当前登录用户的会话 ID?如果还没有人登录会发生什么?那会是什么会话ID?

UPD4:就是这样!我得到了那个!

[DllImport("Kernel32.dll", EntryPoint = "WTSGetActiveConsoleSessionId")] public static extern int WTSGetActiveConsoleSessionId();

谢谢你们!

4

4 回答 4

4

您可以使用 WTSGetActiveConsoleSessionId(从终端服务 API)获取活动控制台会话 ID。您只能将它用于 WinXP/Win2K3 或更高版本,但这应该没问题,因为您可以在 Win2K 或更早版本上将会话 ID 硬编码为 0。这是它的 PInvoke 签名:

[DllImport("Kernel32.dll", SetLastError = true)]
[return:MarshalAs(UnmanagedType.U4)]
public static extern int WTSGetActiveConsoleSessionId ( );

至于在用户会话中启动进程,可以参考我这里给出的答案。它基本上涉及调用四个 API;WTSGEtConsoleSessionId、WTSQueryUserToken、DuplicateTokenEx,然后是 CreateProcessAsUser,它可以在任何运行 WinXP/Win2K3 或更高版本的机器上工作。

于 2010-09-04T05:58:52.500 回答
3

一种解决方案是让第三个进程充当中介,并告诉它通过 RPC/命名管道启动应用程序。

流程:

  • 视窗服务
  • 中介申请
  • 您要运行的应用程序

shim 创建一个通信端点(命名管道,WCF 端点)并监听它。当它收到要继续的消息时,它会启动您要运行的应用程序。

然后,当 Windows 服务要启动应用程序时,它会找到并打开端点(命名管道,WCF 端点),并发送消息以启动应用程序。然后中间应用程序负责启动业务的流程,并且没有Windows服务的任何限制。

让这个中间过程从登录开始,你就可以开始了。

当您需要运行与桌面交互的测试时,这类似于 Microsoft 测试代理/控制器的工作方式。

于 2010-07-07T17:35:51.873 回答
2

这可以在没有中间过程的情况下完成,但需要超过 500 行代码才能完成。基本上,您希望以当前登录用户的身份启动您的第二个进程。对于 Vista/7,此用户将拥有自己的 winlogon 进程,而对于 XP,他们将拥有资源管理器进程。您需要获取该运行进程的主令牌、环境块、安全属性和线程安全属性,然后使用所有这些信息调用 Windows API 函数 CreateProcessAsUser,确保您也选择了正确的窗口站(通常是“WinSta0\Default ”)。这一切都是可行的,但您可能会更好地考虑第二个流程和 IPC 的其他建议。

于 2010-07-07T18:06:05.213 回答
1

如果您在比 WindowsXP 更新的任何东西上尝试这个,这将不起作用。这是因为在 Vista / Windows 7 中引入了一个称为会话 0 隔离的新功能。http://msdn.microsoft.com/en-us/library/bb756986.aspx您将无法让服务启动的应用程序显示在用户桌面上。

于 2010-07-07T17:17:24.250 回答