簡體   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