2010-07-28 32 views
5

Tengo un servicio de Windows que se ejecuta bajo la cuenta del sistema y ejecuta algunos programas de vez en cuando (sí, sí, sé que es una mala práctica, pero ese no es mi decisión). Necesito configurar la verificación "interactuar con el escritorio" para ver la guía de los programas ejecutados, después de instalar el servicio. He intentado varias maneras, poniendo el código de abajo en AfterInstall o OnCommited controladores de eventos de mi instalador de servicio:Cómo configurar "interactuar con el escritorio" en el instalador de servicio de Windows

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

o

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

estos dos métodos de "trabajo". Establecieron el cheque, pero después de que inicie el servicio, ejecuta el exe y no se muestra la interfaz gráfica de usuario. Por lo tanto, si detengo el servicio, vuelva a revisarlo y comience nuevamente: ¡bingo! todo comienza y se muestra. La segunda forma de lograr el resultado es reiniciar, después de esto también se muestra la GUI.

Entonces, la pregunta es: ¿hay una forma correcta de establecer la verificación de "interactuar con el escritorio", por lo que comenzará a funcionar sin volver a comprobar y reiniciar?

SO: Windows XP (no hemos probado Vista y 7 sin embargo ...)

+0

intentado utilizar el comando "sc config" - de ninguna manera ... –

+0

intentado utilizar las exportaciones de winapi desde http://www.codeproject.com/KB/vb/WindowsServiceInstall.aspx - sin suerte ... –

Respuesta

2

Y finalmente, después de buscar en Internet por una semana - He encontrado una gran solución de trabajo: http://asprosys.blogspot.com/2009/03/allow-service-to-interact-with-desktop.html

Encuentra el escritorio para iniciar. Este puede parecer jocoso pero no es tan simple como parece . Con la Terminal Servicios y el Cambio rápido de usuario allí pueden ser múltiples usuarios interactivos que iniciaron sesión en la computadora al mismo tiempo . Si desea que el usuario que es actualmente sentado en la consola física , tenga suerte, la API de servicios de terminal llamada WTSGetActiveConsoleSessionId obtendrá la ID de sesión que necesita. Si sus necesidades son más complejas (es decir, que necesita para interactuar con un usuario específico en el servidor TS o necesita que el nombre de la estación ventana en una sesión no interactiva ) que necesita para enumerar la Terminal Sesiones de servidor con WTSEnumerateSessions y compruebe la sesión para obtener la información que necesita con WTSGetSessionInformation.

Ahora sabes con qué sesión necesitas interactuar con y tienes su ID. Esta es la clave para todo el proceso, usando WTSQueryUserToken y la ID de sesión , ahora puede recuperar el token del usuario que inició sesión en la sesión de destino . Esta completamente mitiga el problema de seguridad de la 'interactuar con el escritorio' establecer, el proceso puesto en marcha no será corriendo con el sistema local credenciales pero con las mismas credenciales que el usuario que es ya iniciado la sesión en que se ¡sesión! No elevación de privilegios.

Usando CreateProcessAsUser y el token hemos recuperado podemos lanzar el proceso de la forma habitual y se se ejecutará en la sesión de destino con credenciales del usuario de destino. Hay son un par de advertencias, tanto lpCurrentDirectory y lpEnvironment debe apuntar a valores válidos - los métodos normales de resolución predeterminada para estos parámetros no funcionan para cruzada sesión de puesta en marcha. Puede usar CreateEnvironmentBlock para crear un bloque de entorno predeterminado para el usuario de destino .

Hay un código fuente del proyecto de trabajo adjunto.

+0

Este código es genial, pero ¿alguien sabe cómo especificar argumentos al iniciar la aplicación? –

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


     } 
+0

Este método funciona. Establece la bandera correctamente. –

+0

funciona bien. Puede verificarlo manualmente para que la bandera esté configurada correctamente – Mefhisto1

1

Igual que Heisa pero con WMI. (Código es Powershell, pero puede ser fácilmente portado a 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" } 

Ver MSDN: Service Change() method para la descripción parámetro.

Cuestiones relacionadas