2009-01-06 97 views
7

Estoy escribiendo una aplicación en C# que necesita ejecutarse como un servicio pero también tiene interacción del usuario. Entiendo que los servicios no tienen UI, etc., así que he dividido mi programa en una aplicación de formulario de Windows y un servicio que puede comunicarse entre sí.C# Ejecutar Windows Form Application desde Service (y en Vista)

El problema que tengo es que necesito el servicio para asegurarme de que la aplicación de formularios de Windows esté siempre en ejecución y reiniciarla si no es así. Soy capaz de detectar si se está ejecutando, y reiniciarlo con el siguiente código en Windows 2000/XP:

System.Diagnostics.Process.Start("ExePath"); 

pero en Vista, se ejecuta el nuevo proceso como un proceso local/Sistema que es invisible a el usuario. ¿Alguien lo esquivo? ¿Hay alguna forma de detectar qué usuario está actualmente conectado y ejecutar el nuevo proceso como ese usuario? No necesito dar cuenta del cambio de usuario rápido en este punto. Algo, cualquier cosa, bastaría.

Le agradecería cualquier ayuda o consejo que tenga sobre el tema.

Necesito aclarar que estoy configurando la opción "Permitir que el servicio interactúe con el escritorio" cuando se instala el servicio. Esto es lo que le permite trabajar en 2000/XP. Sin embargo, Vista todavía tiene el problema antes mencionado.

+0

¿Echo de menos algo? Si tiene un servicio que siempre se está ejecutando ... ¿por qué es importante si su aplicación de formulario de Windows se está ejecutando? – bobwienholt

+0

Porque necesito una forma para que el servicio se comunique directamente con el usuario. Hay muchas razones para esto, pero el ejemplo más básico es para los avisos de actualización. –

+1

Estoy con los demás aquí ... Sospecho que estás tomando el enfoque equivocado para cualquier problema que estés tratando de resolver. Si * debes * tener una UI, entonces probablemente no deberías estar usando un modelo de servicio. Tal vez algo que reside en la bandeja del sistema ...? –

Respuesta

13

La idea general de este tipo de cosas es que, si el usuario necesita interactuar con un servicio, debería iniciar una aplicación por separado. Si desea ayudarlos, puede configurar esa aplicación por separado para comenzar con Windows, colocando un acceso directo en el menú de inicio. También puede crear una recuperación de fallos en su aplicación para que pueda reiniciarse automáticamente.

En realidad, no debe confiar en la supervisión de la aplicación de formularios, ¿qué pasa si nadie ha iniciado sesión? ¿Qué ocurre si hay varias personas conectadas? Simplemente se pone complicado haciendo las cosas de esta manera.

Tener el servicio sentado y transmitir a los oyentes es el camino a seguir. Cuando se inicia la aplicación de formularios, puede notificar al servicio que desea escuchar los eventos.

+0

Como mencioné en mis comentarios anteriores, necesito que el servicio pueda notificar al usuario de ciertos eventos directamente. Seré feliz de dos maneras: si hay una manera de resolver el problema que describí, o si hay una mejor manera de lograr este objetivo. –

+1

Debe hacer que la aplicación de formularios se inicie automáticamente. Luego notificará al servicio que está escuchando si hay actualizaciones. – Bob

+0

Supongo que tendré que aceptar eso. Realmente esperaba que hubiera una forma de relanzarlo desde el servicio. –

2

En este caso, tendrá que tener un tercer proceso de monitor que detecta si el programa falla y reinícielo en ese caso.

Sin embargo, termina aquí con un problema sin solución, ya que habrá que vigilar el proceso del monitor para asegurarse de que no se cierre, y así sucesivamente, y así sucesivamente.

Es posible que desee reconsiderar este enfoque.

0

En Windows 2000 y XP, hay una opción (casilla de verificación) en la pestaña Inicio de sesión de la ventana de propiedades del servicio para permitir que el servicio interactúe con el escritorio. Creo que esto es lo que estás buscando. Acabo de escribir un servicio rápido en VB.NET con Process.Start ("calc.exe") y la Calculadora de Windows abrió bien.

No estoy 100% seguro de que esto funciona de la misma manera en Vista.

+0

Debería haber sido más claro en mi pregunta. He hecho esto. Esto es lo que le permite iniciar la aplicación de formularios en 2000/xp. Sin embargo, Vista abre el programa como un proceso de sistema local y es invisible para el usuario. –

0

Parece que no es necesario que la mitad se ejecute como un servicio (a menos que haya un requisito de privilegios más altos), ya que su servicio tendría que funcionar cuando no haya ningún usuario interactivo conectado también.

+0

Gracias, pero necesito que sea un servicio de privilegios. Estoy contabilizando situaciones en las que la aplicación de formularios no se está ejecutando o no hay usuarios conectados (que lógicamente son los mismos en este momento). –

1

Es una situación difícil. Como se mencionó en un par de lugares, si tiene tiene una interfaz de usuario, entonces técnicamente no debe utilizar un servicio. Después de todo, los servicios se ejecutan sin que el usuario inicie sesión. Si nadie está conectado, no puede tener una IU.

Normalmente, cuando necesito un servicio para comunicarme con el mundo exterior, hay dos cosas que opto por. Puedo colocar una entrada en el registro de eventos o puedo colocar un mensaje en una cola.

En su caso usaría una cola. Cuando un usuario inicia sesión, puede iniciar automáticamente una aplicación que supervisa la cola. Si la aplicación se está ejecutando, cuando se recibe el mensaje, también reciben una alerta de esa manera. Sin embargo, si el usuario cierra la aplicación, ocurre lo mismo ... no lo sabrán.

+0

Ese es mi problema :-p –

1

Primero, una respuesta rápida: ¿La opción 'Permitir que el servicio interactúe con el escritorio' (servicio -> Propiedades -> Inicio de sesión) o especificar una cuenta permita lo que usted desea? De ser así, ambos pueden configurarse en su clase de instalador de servicio.

Como los demás, sospecho que hay un mejor enfoque para esto y cualquiera de los siguientes es cierto: -El código dentro del servicio podría incluirse en la aplicación de winforms (tal vez ejecutándose en un hilo de fondo), y agregado al inicio de Windows. Ambos se ejecutarán en : la aplicación de winforms solo puede escuchar el servicio cuando está activado y no necesita ser iniciado desde el servicio. O de manera similar, la aplicación podría agregarse al inicio.

+0

He editado mi pregunta original. He estado configurando esa opción cuando el servicio está instalado. Gracias por la sugerencia. Probablemente exploraré ambas opciones. Solo desearía que fuera posible hacer lo que estoy pidiendo. Haría mi vida mucho más fácil. –

3

Ver la pregunta: How can a Windows Service execute a GUI application?. Trata la misma pregunta de C/C++ (respuesta corta: CreateProcessAsUser), pero la respuesta sigue siendo válida (con algunos P/Invoke) para C#.

+0

Gracias. Después de mirar esa respuesta, creo que iré con el enfoque de proceso de fondo oculto mencionado por muchas respuestas/comentarios útiles. –

1

Para que el servicio de ejecutar la aplicación como un usuario (que parece ser lo que está tratando de hacer) que tiene que hacer lo siguiente:

System.Security.SecureString ss = new System.Security.SecureString(); 

foreach (char c in password) 
    ss.AppendChar(c); 

System.Diagnostics.Process proc = Process.Start(path, arguments, username, ss, domain); 

Dónde:

  • path = ruta completa (incluido el nombre de archivo) del ejecutable.
  • argumentos = cadena de argumentos (utilice una cadena vacía es ninguno)
  • nombre de usuario = El nombre de una cuenta de usuario en el servidor/ordenador
  • domain = dominio de red (si el uso de una red en blanco si cuenta- ninguno)

Además, para que su servicio tenga permiso para iniciar una aplicación, también debe estar ejecutándose como un servicio. Para hacer esto, necesita agregar estas líneas a su clase de instalador de servicio:

serviceProcessInstaller.Account = ServiceAccount.User; 

serviceProcessInstaller.Username = "yourdomain\\yourAccountName"; //Or just "AccountName" for local accounts..    

serviceProcessInstaller.Password = "yourPassword"; 
+0

¿Puede su marcial el nombre de usuario y la contraseña de un objeto de Active Directory? – SoftwareSavant

Cuestiones relacionadas