Iniciar sesión

Ver la versión completa : Duda C#: Lanzar Forms desde servicio windows?



crossmax
18/06/2012, 10:20
Buenas,
Por aqui vuelvo a lo mismo de siempre, absorver parte de vuestro conocieminto...

Normalmente no toco C#, pero me han encasquetado hacer un servicio con el Visual Studio y no sé si se pueden lanzar ventanas desde él. Es decir, tengo un servicio que comprueba desde un webservices si ha cambiado un estado cada cierto tiempo. Si ha cambiado me gustaria lanzar una ventana que preguntara al usuario si desea cancelar una accion. Si no cancela o no contesta se realiza la accion.

Por lo que, ¿Desde una clase en C# que hereda de ServiceBase se pueden lanzar Windows.Forms?

Muchas gracias por la ayuda!

^MiSaTo^
18/06/2012, 10:40
Yo de c# se sólo lo justo para hacer aplis de WP7 así que de forms ni idea, pero buscando por google un poco...
http://stackoverflow.com/questions/418119/c-sharp-run-windows-form-application-from-service-and-in-vista

No se si te vale pero en stackoverflow aparecen como 200 hilos preguntando cosas parecidas ;)

crossmax
18/06/2012, 10:48
:brindis:
Gracias! No me habia decantado aún por las busqueda en ingles... jejeje.

A ver si saco algo en claro, que como bien dices, en esa foro hay bastantes hilos sobre ello.

Gracias

^MiSaTo^
18/06/2012, 10:51
O_o No buscas en inglés?
Yo vamos, stackoverflow es donde primero busco normalmente. Para todo. Es la mayor comunidad de programadores que hay ;)
Y bueno todo lo que sea documentación y demás... en inglés hijo xD No esperes que en Español haya mucha info (en general)

Malenko
18/06/2012, 11:18
No es posible.

GameMaster
18/06/2012, 11:22
como que no es posible ?

javu61
18/06/2012, 11:47
Bueno, si tenemos en cuenta que un servicio se ejecuta en segundo plano, y no tiene acceso a pantalla ni teclado, es un poco dificil que pueda ni lanzar una ventana, ni esperar una acción por parte de un usuario, por tanto asumo que no es eso lo que quieres hacer, si lo que quieres es que el programa se ejecute en el área de notificación, y saque avisos, como hace por ejemplo el Outlook, sería un tema completamente diferente.

Saludos

GameMaster
18/06/2012, 11:59
se puede hacer llamadas a la shell y llamar aplicaciones

---------- Post añadido a las 09:59 ---------- Post anterior a las 09:56 ----------

http://stackoverflow.com/questions/1294526/unable-to-execute-a-program-from-a-service

Malenko
18/06/2012, 12:12
se puede hacer llamadas a la shell y llamar aplicaciones

---------- Post añadido a las 09:59 ---------- Post anterior a las 09:56 ----------

http://stackoverflow.com/questions/1294526/unable-to-execute-a-program-from-a-service

Eso ya lo conocia y lo uso,pero lo que no puede un servicio por si mismo es crear un winform y que el usuario pueda interactuar.

nandove
18/06/2012, 12:22
Como te han dicho, no se puede, un servicio está pensado para lanzarse de manera interna y sin supervision, si quieres otra cosa, te recomiendo un proceso exe que lance un "if msgbox" y que lo llames desde una tarea programada... eso si,que sepas que las tareas programadas solo se ejecutan si está iniciada la sesión de la cual depende.

javu61
18/06/2012, 13:28
Ten en cuenta que el servicio se ejecuta en la capa del sistema, los servicios arrancan junto al windows y antes de indicar el usuario, por lo que puede que quieras sacar una ventana al usuario, pero este no esté logeado todavía, por lo que le será imposible verla.

La mejor opción es lo que te he indicado, lanza el proceso de interacción con el usuario en el inicio del windows, lo que te creará un programa en ejecución cuando se logee el usuario, le dices al programa que se ejecute desde la barra de estado, y ese programa si que puede interactuar con el usuario, sacando un pop-up o abriendo una ventana.

crossmax
19/06/2012, 10:35
Por lo que he leido en stackoverflow se puede lanzar ventanas desde un servicio, pero haciendolo a traves de una aplicacion externa y estableciendo una conexion con ella un tanto especial, por no decir complicada.
Al final me decantado por conectar la aplicacion visual con un socket al servicio, y de esa forma pasarme los mensajes que necesito. Si la aplicacion visual no está lanzada, por timer el servicio realiza las tareas por defecto.
A ver si me funciona...

Muchas gracias por vuestras respuestas

crossmax
22/06/2012, 11:05
A ver si me podeis ayudar con un temita que me esta pasando con el socket de comunicacion entre el Form y el servicio.
El form es el cliente y el servicio el servidor.
En el servidor, al arrancar el servicio creo un socket y le hago un Bind() y un Listen(10) y lanzo un timer cada 2 segundos. Ademas creo un socket cliente para despues usar en el timer.
En el timer (con cerrojo) hago un:
sck_cliente= sck.Accept();
sck_cliente.Receive(buff); y trato lo recibido si es que hay.

Mi problema es que de esta forma el servidor solo acepta la primera trama que le llega, contestando a ella correctamente. Pero despues se queda esperando indefinidamente en el sck_cliente.Accept() la segunda vez que entra en el timer.
Este socket cliente (sck_cliente) no lo desconecto ni cierro, porque quiero mantener la conexion con el Form, para cada x segundos se intercambien tramas.

¿Sabeis que puedo estar haciendo mal para que se quede esperando en el Accept()??

Muchas gracias

GameMaster
22/06/2012, 12:12
tienes que usar threads, hacerlo en una thread, porque sino el processo principal se te congela con eso

crossmax
26/06/2012, 08:05
tienes que usar threads, hacerlo en una thread, porque sino el processo principal se te congela con eso
Se me olvido decirte: Gracias! parace que tira

GameMaster
26/06/2012, 09:16
me alegro, yo ya habia pasao por lo mismo xD Como nota apuntar que esto funciona en windows forms, pero no en aspx porque no se puede acceder a controles de threads fuera de ellos

Haohmaru
26/06/2012, 09:17
Creo que no se puede. Lo que puedes hacer es preparar una clase y que esta sea llamada desde el servicio, siempre y cuando se este ejecutando desde un pc el servicio..Otra opción es crear un formulario web, te será más cómodo de llamar quizás i lo lanzada en el navegador.

crossmax
27/06/2012, 13:47
Pues lo tomaré en cuenta, tanto lo del aspx que no creo que use nunca como lo del webservices. Pero ahora ya no quiero empezar de cero ;-) aunque a veces me pregunto si merecería la pena, jajaja.
Solo me queda una cosa por resolver.
Ya tengo el servicio que hace todo lo que quiero si no hay ningun formulario conectado a él.
Tambien me funciona si lanzo un formulario he intractuo con el servicio.
El problema me surge cuando desconecto el formulario del servicio (server), que esté se peta. Tenga o no tenga mas formularios simultaneos, peta y se cierra.

El servicio ejecuta en OnStart()

this.tcpListener = new TcpListener(ipEnd);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();


private void ListenForClients()
{
this.tcpListener.Start();

while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();

//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}


private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();

byte[] message = new byte[4096];
int bytesRead;

while (true)
{
bytesRead = 0;

try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}

if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}

//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
System.Diagnostics.Debug.WriteLine(encoder.GetStri ng(message, 0, bytesRead));
}

tcpClient.Close();
}

Porque cuando cierro el formulario desconectandose correctamente (sale del while en HandleClientComm y cierra su tcpClient.Close()) el hilo principal ListenForClients() se cierra y ni acepta nuevas conexiones ni continua con el resto que estan abiertas?¿??¿

Como veis no me manejo nada con sockets ni hilos, soy mas de ansi C :-|

Muchas gracias

GameMaster
27/06/2012, 13:54
tienes un while(true), con lo cual su contenido siempre se esta ejecutando....

crossmax
27/06/2012, 14:06
tienes un while(true), con lo cual su contenido siempre se esta ejecutando....

Si te refieres al while(true) de HandleClientComm, cuando cierro un formulario (conexion tcp con el servicio) hago un break y despues colo cierro ese mismo cliente tcpClient.Close().
Supongo que de ese modo cierro el socket correctamente y al salirme del while se acaba de ejecutar el hilo de ese cliente que se está desconectando. Por que despues de eso no vuelve al while(true) del ListenForClients() para seguir escuchando conexiones existentes o futuras????

crossmax
29/06/2012, 07:48
Yo creo que puedo estar manejando mal los hilos, y cuando cierro un hilo me cargo el resto.
¿Algun catacrack experto en hilos? :lamer:

GameMaster
29/06/2012, 09:23
de ese while solo sales cuando cierras la aplicación, tienes que controlar todos los loops

crossmax
29/06/2012, 09:46
Si yo hago un socket.Disconnect() desde el cliente, el servidor al hacer el Read en el HandleClientComm obtiene 0 bytes y se sale por el break de ese while. Despues hace el tcpClient.Close() y entiendo que mata ese hilo (ya que el cliente se ha desconctado). Lo que no entiendo es lo que pasa despues de eso.
Entiendo que el hilo que lanzo el el OnStart() con:
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();

que es el que escucha al resto de clientes o a futuras conexiones debería seguir ejecutandose, no??? Porque no lo hace? Debo de matarlo sin quererlo [chuck3] y no sé cómo

Muchas gracias por el tiempo que te estas tomando

GameMaster
29/06/2012, 10:01
luego lo miro a lupa cuando pillé tiempo

XWolf
29/06/2012, 10:59
Puedes generar el Windows forms de manera normal, como si fuese una aplicación corriente, pero tienes que configurar el servicio para que tenga acceso al escritorio, para ello te vas al listado de servicios, Doble click sobre el sericio, y en la pestaña "Iniciar sesion", tienes que habilitar el check "permitir que el servicio interactrue con el escritorio".

para crear el formulario, y dado que no tienes el bucle de aplicación por defecto (los servicios tienen uno que se le parece mucho), lo mejor es hacer que el formulario se controle a si mismo, yo suelo usar esta técnica:

Pon el constructor del windowsForm como privado, y crea el siguiente metodo



public static bool Execute(){
using(Form f=new TUFORMULARIO())
{
return f.ShowDialog()==DialogResult.OK;
}
}



llama a .Execute() para mostrar la ventana, y pon un temporizador para el timeout

para los retornos creo que mejor en el boton ce cancelar accion hagas un


DialogResult = DialogResult.Cancel;


y en el resto un


DialogResult = DialogResult.OK;


Ten en cuanta que el cierre en el aspa del formulario retorna un "Dialogresult.Close"

Espero que te sirva de algo.

crossmax
29/06/2012, 12:47
He dado permisos de interaccion con el escritorio.
He puesto como private el constructor y añadido el metodo Execute()
He llamado desde el main al Form con MIFORMULARIO.Execute();
Y en el evento del aspa del Form he puesto:
DialogResult = DialogResult.Cancel;
tcpClient.Close();

Me sigue petando el servicio al cerrar la conexion establecidad desde el Form.

Probé tambien con el Socket Workbench, conectandome al servicio desde 2 ventanas del workbench. Si desconecto una, la otra conexion peta. Digo esto porque como ando perdido en el tema de servicios, y en C# en general, no sé que relacion puede tener que mi servicio tenga o no permisos de interactuar con el escritorio, para que éste (el servicio) se pete cuando se cierra uno de los tcpClient.

Gracias por el consejo. Seguiré mirando a ver que beneficios me proporciona (y qué sidnifica) que el servicio tenga estos permisos

---------- Post añadido a las 10:47 ---------- Post anterior a las 09:21 ----------

Acabo de portar el codigo del servicio a un form y funciona perfectamente !!!:confused:
Asique basicamente algo debe de tener de especial el servicio que no le gusta lo que le hago.
La pregunta puede ser:
¿Porque al matar o acabar un thread en un Service el resto de threads activos mueren??

Caca WCF [Ahhh]

GameMaster
29/06/2012, 13:38
en lugar de while(true) pon:

try
{

...

listening = true;

while(listening)
{

...

}

this.tcp.Stop();

}
catch
{
listening = false;
}

crossmax
29/06/2012, 14:36
Gracias GameMaster pero no ha habido suerte. Se sale del while tan "bien" como antes pero el hilo principal se queda muerto y no retoma el resto de conexiones :(
... que le vamos a hacer ... al menos es viernes!!

GameMaster
29/06/2012, 15:06
Pasamelo por privado y te lo arreglo, tengo uno similar y vere que te falta

crossmax
06/07/2012, 14:57
Gracias GameMaster pero no ha habido suerte. Se sale del while tan "bien" como antes pero el hilo principal se queda muerto y no retoma el resto de conexiones :(
... que le vamos a hacer ... al menos es viernes!!

GameMaster!!! Tienes casi siempre el buzon lleno!! No te puedo mandar mp!