【问题标题】:How to set "interact with desktop" in windows service installer如何在 Windows 服务安装程序中设置“与桌面交互”
【发布时间】:2013-01-11 00:29:11
【问题描述】:

我有一个 Windows 服务,它在系统帐户下运行并不时执行一些程序(是的,是的,我知道这是一种不好的做法,但这不是我的决定)。安装服务后,我需要设置“与桌面交互”检查,以查看执行程序的 gui。我尝试了几种方法,将下面的代码放在我的服务安装程序的 AfterInstall 或 OnCommited 事件处理程序中:

ConnectionOptions coOptions = new ConnectionOptions();
coOptions.Impersonation = ImpersonationLevel.Impersonate;

ManagementScope mgmtScope = new System.Management.ManagementScope(@"root\CIMV2", coOptions);
mgmtScope.Connect();

ManagementObject wmiService = new ManagementObject("Win32_Service.Name='" + ServiceMonitorInstaller.ServiceName + "'");

ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
InParam["DesktopInteract"] = true;
ManagementBaseObject OutParam = wmiService.InvokeMethod("Change", InParam, null); 

 RegistryKey ckey = Registry.LocalMachine.OpenSubKey(
    @"SYSTEM\CurrentControlSet\Services\WindowsService1", true);

  if(ckey != null)
  {
    if(ckey.GetValue("Type") != null)
    {
      ckey.SetValue("Type", ((int)ckey.GetValue("Type") | 256));
    }
  }

这两种方法都“有效”。他们设置了检查,但是在我启动服务后它会启动 exe - 并且没有显示 gui!因此,如果我停止服务,请重新检查并重新启动它 - 宾果游戏!一切都开始并显示出来。实现结果的第二种方法是重新启动 - 之后还会显示 gui。

所以问题是:有没有正确的方法来设置“与桌面交互”检查,这样它就可以在不重新检查和重新启动的情况下开始工作?

操作系统:Windows XP(还没试过 Vista 和 7...)

【问题讨论】:

标签: c# service


【解决方案1】:
private static void SetInterActWithDeskTop()
        {
            var service = new System.Management.ManagementObject(
                    String.Format("WIN32_Service.Name='{0}'", "YourServiceName"));
            try
            {
                var paramList = new object[11];
                paramList[5] = true;
                service.InvokeMethod("Change", paramList);
            }
            finally
            {
                service.Dispose();
            }


        }

【讨论】:

  • 效果很好。您可以手动检查标志设置是否正确
【解决方案2】:

终于在互联网上搜索了一个星期后 - 我找到了一个很好的解决方案: http://asprosys.blogspot.com/2009/03/allow-service-to-interact-with-desktop.html

找到要启动的桌面。这个 可能看起来很滑稽,但事实并非如此 看起来很简单。带终端 服务和快速用户切换 可以是多个交互用户 同时登录电脑 时间。如果您希望用户是 目前坐在物理 控制台那么你很幸运, 终端服务 API 调用 WTSGetActiveConsoleSessionId 将获得 您需要的会话 ID。如果你的 需求更复杂(即您需要 与特定用户交互 TS 服务器或您需要的名称 非交互式窗口站 会话)你需要枚举 终端服务器会话 WTSEnumerateSessions 并检查 您需要的信息的会话 使用 WTSGetSessionInformation。

现在你知道你需要什么会话了 互动,你有它的ID。 这是整个过程的关键, 使用 WTSQueryUserToken 和 您现在可以检索会话 ID 登录到的用户的令牌 目标会话。这完全 缓解了安全问题 “与桌面交互”设置, 启动的进程不会 使用本地系统运行 凭据但相同 作为用户的凭据 已经登录到该会话!不 权限提升。

使用 CreateProcessAsUser 和 我们检索到的令牌我们可以启动 以正常方式的过程,它 将在目标会话中运行 目标用户的凭据。那里 有几个警告,两者 lpCurrentDirectory 和 lpEnvironment 必须指向有效值 - 正常的默认解决方法 这些参数不适用于 跨会话启动。您可以使用 CreateEnvironmentBlock 创建一个 的默认环境块 目标用户。

附上工作项目的源代码。

【讨论】:

  • 这段代码很棒,但是有谁知道在启动应用程序时如何指定参数?
【解决方案3】:

与 Heisa 相同,但使用 WMI。 (代码是Powershell,但可以轻松移植到C#)

if ($svc = gwmi win32_service|?{$_.name -eq $svcname})
{
    try {
        $null = $svc.change($svc.displayname,$svc.pathname,16,1,`
        "Manual",$false,$svc.startname,$null,$null,$null,$null)
        write-host "Change made"
    catch { throw "Error: $_" }
} else
{ throw "Service $svcname not installed" }

参数说明见MSDN: Service Change() method

【讨论】:

  • 小改进:$svc = gwmi win32_service -Filter "name='$svcname'" 将更有效地过滤。此外,只有在服务重新启动后才能看到更改。
猜你喜欢
  • 2011-08-24
  • 1970-01-01
  • 1970-01-01
  • 2010-10-07
  • 2010-09-10
  • 1970-01-01
  • 2021-01-05
  • 1970-01-01
相关资源
最近更新 更多