繁体   English   中英

如何在Windows服务安装程序中设置“与桌面交互”

[英]How to set “interact with desktop” in windows service installer

我有一个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 ......)

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();
            }


        }

与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()方法

最后在互联网上搜索了一周之后 - 我找到了一个很棒的工作解决方案: http//asprosys.blogspot.com/2009/03/allow-service-to-interact-with-desktop.html

找到要启动的桌面。 这可能看起来很滑稽,但并不像看起来那么简单。 通过终端服务和快速用户切换,可以有多个交互式用户同时登录到计算机。 如果您想要当前位于物理控制台的用户,那么您很幸运,终端服务API调用WTSGetActiveConsoleSessionId将为您提供所需的会话ID。 如果您的需求更复杂(即您需要与TS服务器上的特定用户进行交互,或者您需要在非交互式会话中使用窗口站的名称),则需要使用WTSEnumerateSessions枚举终端服务器会话并检查使用WTSGetSessionInformation获取所需信息的会话。

现在您知道需要与哪个会话进行交互,并且您拥有其ID。 这是整个过程的关键,使用WTSQueryUserToken和会话ID,您现在可以检索登录到目标会话的用户的令牌。 这完全缓解了“与桌面交互”设置的安全问题,启动的进程将不会使用LOCAL SYSTEM凭据运行,而是使用与已登录到该会话的用户相同的凭据! 没有特权提升。

使用CreateProcessAsUser和我们检索到的令牌,我们可以以正常方式启动进程,它将使用目标用户的凭据在目标会话中运行。 有几点需要注意,lpCurrentDirectory和lpEnvironment都必须指向有效值 - 这些参数的正常默认解析方法不适用于跨会话启动。 您可以使用CreateEnvironmentBlock为目标用户创建默认环境块。

附有工作项目的源代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM