none
Abrir un formulario desde otro hilo (thread)

    Pregunta

  • <p>Buenos días,</p><p>Tengo un proyecto en el que necesito tener un socket servidor que esté continuamente a la escucha por si a través del protocolo tpc/ip le envia información.</p><p></p><p>Para que ese socket servidor no me bloquee el programa tengo un formulario en el que ejecuto diferentes procesos. Al iniciar ese formulario llamo a la función para que inicialice el nuevo hilo (thread)&nbsp;y el socket servidor. </p><p>Cuando a través del puerto me envia un texto quiero abrir un <span style="text-decoration:underline;">nuevo formulario </span>y presentar ese texto. Para eso, me he creado una clase con las diferentes funciones para inciar el hilo y el socket y cuando me envia información intento abrir el formulario de la siguiente manera:</p><p><em></em></p><p><em>frmError=new frmError();</em></p><p><em>frmError.Text1.Text = "Texto de error";</em></p><p><em>frmError.Show();</em></p><p><em></em></p><p>Cuando ejecuta la primera línea, y se ejecuta el "InitializeComponent" del formulario frmError me salta el siguiente error:</p><p><em>"System.Threading.ThreadStateException: No se puede crear una instancia del control ActiveX '8856f961-340a-11d0-a96b-00c04fd705a2' porque el subproceso actual no está en un apartamento de un solo subproceso."</em></p><p><span style="font-face:Consolas;font-size:small;"><span style="font-face:Consolas;font-size:small;"> </span></span></p><p><span style="font-face:Consolas;font-size:small;"><span style="font-face:Consolas;font-size:small;"><p></p></span></span></p>
    martes, 22 de mayo de 2012 12:28

Todas las respuestas

  • hola

    podrias editar el mensaje proque ha quedado con problemas de redaccion


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    martes, 22 de mayo de 2012 12:42
  • Perdón, no me había dado cuenta.

    Buenos días,

    Tengo un proyecto en el que necesito tener un socket servidor que esté continuamente a la escucha por si a través del protocolo tpc/ip le envia información

    Para que ese socket servidor no me bloquee el programa tengo un formulario en el que ejecuto diferentes procesos. Al iniciar ese formulario llamo a la función para que inicialice el nuevo hilo (thread) y el socket servidor.

    Cuando a través del puerto me envia un texto quiero abrir un nuevo formulario y presentar ese texto. Para eso, me he creado una clase con las diferentes funciones para inciar el hilo y el socket y cuando me envia información intento abrir el formulario de la siguiente manera

    frmError=new frmError();

    frmError.Text1.Text = "Texto de error";

    frmError.Show();

    Cuando ejecuta la primera línea, y se ejecuta el "InitializeComponent" del formulario frmError me salta el siguiente error:

    "System.Threading.ThreadStateException: No se puede crear una instancia del control ActiveX '8856f961-340a-11d0-a96b-00c04fd705a2' porque el subproceso actual no está en un apartamento de un solo subproceso."

    Muchas gracias.

    martes, 22 de mayo de 2012 13:57
  • Hola,

    Eso suele pasar porque esto.

    static class Program
        {
            /// <summary>
            /// Punto de entrada principal para la aplicación.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }

    fijate en el STAThread. Lo tienes así.

    Utiliza para tu nuevo hilo esta opción "SetApartmentState" tal y como te muestro.

                System.Threading.Thread tr;
                tr.SetApartmentState(System.Threading.ApartmentState.STA);
                //o
                tr.SetApartmentState(System.Threading.ApartmentState.MTA);

    Saludos,


    phurtado
    Mi Blog Blog
    Sigueme en Twitter

    martes, 22 de mayo de 2012 14:34
  • el tema es que ante un error de socket no deberias mostrar un formulario

    sino que deberias loguear o enviar un mail informando de la situacion, eso es lo correcto cuando procesar mensajes del socket desde un thread

    por supuesto puede despues crear un forma que lance el usuario para procesar esto mensajes de error  en pantalla, pero es separado

    el tema es que desde un thread debes lanzar algo de otro thread haciandolo de forma indirecta

    http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/f07a135c-4cca-49b5-be98-de226755b9b9

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    martes, 22 de mayo de 2012 14:41
  • Leandro,

    Donde está el error de socket?

    No me digas que tú nunca has ejecutado un Formulario y un socket?

    Pero es que no te das cuenta que el problema es con el modelo de subproceso del hilo y algún activeX que está utilizando.

    Tu crees que no se soluciona con 

    Tread tr = new Trhead(()=>

    {

     //Los sockets que quieras

    };

    tr.SetApartmentState(System.Threading.ApartmentState.STA);

    tr.Start();

    Piensalo, que yo creo que tiene que ver más con esto http://msdn.microsoft.com/en-us/library/system.threading.thread.setapartmentstate.aspx

    Saludos,


    phurtado
    Mi Blog Blog
    Sigueme en Twitter

    martes, 22 de mayo de 2012 15:08
  • No me digas que tú nunca has ejecutado un Formulario y un socket?

    ni loco abro un form desde logica de socket, lo que hago es loguear y luego analizo los problemas de forma desatendida

    es como desde un desarrollo web en els erver lanzar un form con un mensaje, es la misma locura

    se queda el emsnaje y detienes todo el proceso de thread, se loguea y continua, (o sis e queire se envia un mail) pero algo que no corte el proceso

    Tu crees que no se soluciona con

    si no se si lo soluciona igual no lo veo correcto el abrir un form si se piensa usar thread, si se quiere abrir un form que se procese el socket sin thread de forma sincrona


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina


    martes, 22 de mayo de 2012 15:24
  • Hola,

    Vamos a ver, igual de locura que a ti me parece a mí, pero mi pregunta es la siguiente.

    ¿Quien está cortando el proceso? En algún momento se hace ShowDialog.

    Otra cosa bien distinta es lo que comenta Luis y es tener un Formulario y lanzar el Socket desde el y entonces comunicar al Formulario los mensajes del socket. 

    no me importa como se soluciona porque no esta corrrecto abrir un form si se piensa usar thread

    A no cuando haces una pantalla de espera como lo haces.

    Revisa esta pregunta.

    http://social.msdn.microsoft.com/Forums/en/winforms/thread/1ce85ee2-9884-40e4-bf56-490f9b1022de

    Saludos,


    phurtado
    Mi Blog Blog
    Sigueme en Twitter

    martes, 22 de mayo de 2012 15:38
  • Antes de nada muchas gracias por las rápidas respuestas.

    Os explico mas detenidamente lo que quiero hacer porque no termino de ver cuál puede ser la solución. Lo siento, pero estoy un poco perdida en este tema de los threads.

    Al iniciar el formulario principal de la aplicación, inicio el socket para que se quede a la escucha. En ese socket voy a estar recibiendo información sobre errores y datos para mostrar en el formulario pero mientras que está escuchando quiero ir haciendo operaciones en ese formulario o en otros formularios que la aplicación vaya abriendo. Si no inicio el thread, el formulario principal no llega a cargarse nunca ya que está continuamente el socket escuchando. He probado un ejemplo de un socket asíncrono y me hace lo mismo.

    Ya que solo con el socket no veo cómo hacerlo, intento lo del thread. Estoy intentando crear un función que sea pública para desde cualquier formulario llamarla, la idea es cuando entro a un formulario inicio el thread y el socket y cuando me salgo lo cierro todo.

    Este es el código donde inicializo el thread y el socket:

            public void thread_init()
            {
                if (objListenThread == null)
                {
                    objListenThread = new System.Threading.Thread(thread_start);
                    objListenThread.SetApartmentState(System.Threading.ApartmentState.STA);             }
                if (objListenThread.ThreadState == System.Threading.ThreadState.Stopped)
                {
                    objListenThread = new System.Threading.Thread(thread_start);
                    objListenThread.SetApartmentState(System.Threading.ApartmentState.STA);
                }
                objListenThread.IsBackground = true;
                objListenThread.Start();
            }

            public void thread_start()
            {
                Encoding enc = Encoding.UTF8;
                IPAddress DirecIP = new IPAddress(new byte[4] { 192, 168, 0, 0 });
                listener = new System.Net.Sockets.TcpListener(DirecIP, 55561);
            ListenReStart:
                listener.Start();
                System.Net.Sockets.TcpClient tcp;
                tcp = listener.AcceptTcpClient();
                System.Net.Sockets.NetworkStream ns = tcp.GetStream();
                int resSize;
                string cmd = "";
                while (true)
                {
                    byte[] bytes = new byte[(tcp.ReceiveBufferSize + 1)];
                    resSize = ns.Read(bytes, 0, Convert.ToInt32(tcp.ReceiveBufferSize));
                    if (resSize == 0)
                    {
                        goto CloseSock;
                    }
                    int s = 0;
                    int e = 0;
                    for (e = 0; e < resSize; e++)
                    {
                        if (bytes[e] == 0x0)
                        {
                            cmd += Encoding.ASCII.GetString(bytes, s, e - s);
                            CheckRecvComand(cmd);
                            s = e + 1;
                            cmd = "";
                        }
                        else if (e == resSize - 1)
                        {
                            cmd += Encoding.ASCII.GetString(bytes, s, e - s + 1);
                        }
                    }
                }
            CloseSock:
                listener.Stop();
                goto ListenReStart;
            }

    Está es la función en la que cargo las variables en el otro formulario:

              private void CheckRecvComand(string returndata)
            {
                frmError formu = new frmError();
                formu.lblErrorCode.Text = returndata;
                formu.Show();
            }

    Ahora ya no me da error al abrir el formulario pero como el hilo sigue ejecutándose no se termina de cargar el formulario. ¿Puede abrir el formulario utilizando otro thread y no el thread del socket? Si es así creo que con eso se solucionaría ¿no? ¿o hay otra manera mejor de gestionar esto?

    Muchas gracias de nuevo.

    miércoles, 23 de mayo de 2012 7:47