MSMQ en Compact-Framework

Por Unai Zorrilla Castro

downlanim.gif Descargar ejemplos de este artículo (1 MB).

Contenido

 Introducción
 System.Messaging
 Instalación de MSMQ en el cliente Pocket PC
 Implementando una aplicación con MSMQ
 Conclusión

Introducción

Hace ya un tiempo leí por primera vez el termino OCC; éste hacía referencia a las aplicaciones ocasionalmente conectadas (Occasionaly Connected Applications); al leer la documentación sobre MSMQ en Compact Framework se incidía mucho en este término, ¿Porqué?

 

System.Messaging

Para la comunicación entre procesos en una misma o distinta máquina no siempre se requiere tener presente un vínculo de comunicación (comunicación ocasional); MSMQ representa esta filosofía junto con la asincronía asociada a la misma. La llegada de MSMQ a Compact Framework es una gran noticia para todos aquellos desarrolladores que demandaban este tipo de soluciones en movilidad y que no disponían de los medios en la plataforma.

System.Messaging es el espacio de nombres donde tenemos el conjunto de clases para implementar soluciones con MSMQ. La clase básica de trabajo con MSMQ es MessageQueue, que está contenida en este espacio de nombres y nos facilita tanto el envío como la recepción de mensajes asíncronos.

El primer paso para la construcción de una aplicación con mensajería asíncrona comienza con la instalación de MSMQ en el dispositivo móvil, proceso que veremos a continuación.

 

Instalación de MSMQ en el cliente Pocket PC

Si bien el proceso de instalación no es sencillo, una vez hecho el primero, el resto nos resultarán más fáciles. Empezaremos por crear una nueva solución Windows Forms para Pocket PC (Ver Figura 1):

Bb972250.art242-img01-570x415(es-es,MSDN.10).gif
Figura 1. Volver al texto.

El primer paso será incorporar los componentes MSMQ necesarios a nuestra solución; para ello realizamos la siguiente tarea: Los componentes necesarios para realizar la instalación de MSMQ en nuestro cliente se encuentran en la ruta C:\Program Files\Microsoft Visual\ Studio8\SmartDevices\SDK\SDKRedist\MSMQ\Arm4. Para agregarlos, nos situamos en la ventana de soluciones; sobre la solución hacemos clic en Add exisiting Item y seleccionamos todos los archivos que se encuentran en la ruta anterior (Ver Figura 2):

Bb972250.art242-img02-570x324(es-es,MSDN.10).gif
Figura 2. Volver al texto.

Con esto tendremos en nuestra solución todos los componentes necesarios para la instalación de MSMQ. Crearemos el método de instalación de los componentes en nuestro PocketPC; para ello agregamos un Label y un Button, el Clic del botón llamará a nuestro método de instalación, al cual llamaremos StartMSMQ():

            private const string MSMQ_ADM = @"\windows\msmqadm.exe"; 
            private const string MSMQ_DRIVER_REG = @"Drivers\BuiltIn\MSMQD"; 
            private void btInstallMSMQ_Click(object sender, EventArgs e) 
            { 
                  StartMSMQ(); 
            } 
            private void StartMSMQ () 
            { 
                  CopyFilesRequired(); 
 
                  if (!(CreateProcess(MSMQ_ADM, "status"))) 
                  { 
                        CreateProcess(MSMQ_ADM, "register cleanup"); 
 
                        if (CreateProcess(MSMQ_ADM, "register install")) 
                             MessageBox.Show("Drivers instalados correctamente"); 
                        else 
                        { 
                             MessageBox.Show("Error al instalar MSMQ"+ GetLastError().Tostring()); 
                             return; 
                        } 
 
                        if (CreateProcess(MSMQ_ADM, "register")) 
                             MessageBox.Show("MSMQ registrado"); 
                        else 
                             MessageBox.Show("Error = " + GetLastError().Tostring()); 
 
                        if (CreateProcess(MSMQ_ADM, "enable binary")) 
                             MessageBox.Show("Activado"); 
                        else 
                        { 
                             MessageBox.Show("Error = " + GetLastError().Tostring()); 
                             return; 
                        } 
 
                        if (CreateProcess(MSMQ_ADM, "start")) 
                             MessageBox.Show("Comienzo de MSMQ"); 
                        else 
                        { 
            
                             IntPtr handle = ActivateDevice(MSMQ_DRIVER_REG, 0); 
                             CloseHandle(handle); 
                             if (CreateProcess(MSMQ_ADM, "status")) 
                                   MessageBox.Show("MSMQ corriendo");
                         else 
                                   MessageBox.Show("Error = " + GetLastError().Tostring()); 
                        } 
                  } 
                  else 
                        MessageBox.Show("MSMQ ya esta corriendo"); 
            } 
 
            private static void CopyFilesRequired() 
            { 
                  string[] fileList = {"msmqadm.exe", "msmqadmext.dll", "msmqd.dll","msmqrt.dll",
 "visadm.exe" }; 
                  string path=Path.GetDirectoryName 
                        (System.Reflection.Assembly.GetExecutingAssembly().GetName().Code  Base) + "\\"; 
                  for (int i = 0; i < fileList.Length; i++) 
                  { 
                        if (!File.Exists(@"\windows\" + fileList[i])) 
                        { 
                             File.Copy(path + fileList[i], @"\windows\" + fileList[i]); 
                              File.Delete(path + fileList[i]); 
                        } 
                  } 
 
            } 
 
            public class ProcessInfo 
            { 
                  public IntPtr hProcess; 
                  public IntPtr hThread; 
                  public Int32 ProcessId; 
                  public Int32 ThreadId; 
            } 
 
            [DllImport("CoreDll.DLL", SetLastError = true)] 
            private extern static 
                  int CreateProcess(string imageName,
                      string cmdLine,
                      IntPtr lpProcessAttributes,
                      IntPtr lpThreadAttributes,
                      Int32    boolInheritHandles,
                      Int32 dwCreationFlags,
                       IntPtr lpEnvironment,
                      IntPtr lpszCurrentDir, 
                       IntPtr lpsiStartInfo, 
                       ProcessInfo pi); 
 
            [DllImport("CoreDll.dll")] 
            private extern staticInt32 GetLastError(); 
            [DllImport("CoreDll.dll")] 
            private extern static Int32 GetExitCodeProcess(IntPtr hProcess, out Int32 exitcode); 
 
            [DllImport("CoreDll.dll")] 
            private extern static 
                  Int32 CloseHandle(IntPtr hProcess); 
            [DllImport("CoreDll.dll")] 
            private extern static 
                  IntPtr ActivateDevice( 
                  string lpszDevKey, 
                  Int32 dwClientInfo); 
 
 
            [DllImport("CoreDll.dll")] 
            private extern static 
                  Int32 WaitForSingleObject(IntPtr Handle,Int32 Wait); 
            public static bool CreateProcess(string ExeName, string CmdLine) 
            { 
                  Int32 INFINITE; 
                  unchecked { INFINITE = (int)0xFFFFFFFF; } 
                  ProcessInfo pi = new ProcessInfo(); 
 
                  if (CreateProcess(ExeName, CmdLine, IntPtr.Zero, IntPtr.Zero, 
                        0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero,pi) == 0) 
                        return false; 
 
                  WaitForSingleObject(pi.hProcess, INFINITE); 
                  Int32 exitCode; 
 
                  if (GetExitCodeProcess(pi.hProcess, out exitCode) == 0) 
                  { 
                        MessageBox.Show("Error en GetExitCodeProcess"); 
                        CloseHandle(pi.hThread);
                          CloseHandle(pi.hProcess); 
                        return false; 
                  } 
 
                  CloseHandle(pi.hThread);                        
                  CloseHandle(pi.hProcess); 
 
                  if (exitCode != 0) 
                        return false; 
                  else 
                        return true; 
            }

Una vez terminada la implementación de StartMSMQ , generamos la solución en el emulador de Pocket PC 2003 y hacemos clic en Instalar. Una vez instalados, detenemos la depuración conservando el estado del emulador (Ver Figura 3):

Bb972250.art242-img03-275x399(es-es,MSDN.10).gif
Figura 3. Volver al texto.

 

Implementando una aplicación con MSMQ

En el paso anterior hemos visto cómo instalar MSMQ en el cliente, por lo tanto estamos en posición de empezar la implementación de nuestra primera aplicación. Agregamos al formulario los siguientes elementos:

  • 2 etiquetas

    • Enviar

    • Recibir

  • 2 cajas de texto

    • Caja de texto enviar

    • Caja de texto recibir

  • 2 botones

    • Botón enviar

    • Botón recibir

La estructura del formulario queda de la siguiente forma (Ver Figura 4):

Bb972250.art242-img04-275x402(es-es,MSDN.10).gif
Figura 4. Volver al texto.

Como ejemplo de implementación vamos a instanciar el objeto de acceso a las colas de MSMQ (MessageQueue) y realizar los procesos de envío y recepción de mensajes asíncronos. En el método Enviar comprobaremos la existencia de la cola de trabajo, creándola si es necesario:

            private void btSend_Click(object sender, EventArgs e) 
            { 
                  if (deviceQ == null) 
                  { 
                        string qName = @".\Private$\myQ"; 
 
                        if (!MessageQueue.Exists(qName)) 
                             MessageQueue.Create(qName); 
                        deviceQ = new MessageQueue(qName); 
                  } 
                  deviceQ.Send(txtSend.Text); 
            }

En el método Recibir esperamos por un mensaje en la cola de mensajes; una vez recibido se recupera su cuerpo y se muestra en la caja de texto correspondiente:

            private void btRecv_Click(object sender, EventArgs e) 
            { 
                  Message msg = deviceQ.Receive(); 
                  string strMsg = (string)msg.Body; 
                  txtRecv.Text = strMsg; 
 
            }

 

Conclusión

La nueva versión de la plataforma .Net nos trae muchas novedades, tanto en el entorno de desarrollo como en la mejora de técnicas existentes y nuevas funcionalidades. Sin lugar a dudas la llegada de MSMQ a Compact Framework es algo que muchos estábamos esperando y que por fin tenemos a nuestro alcance.

Unai Zorrilla Castro está radicado en Ourense, España; es Analista Programador de soluciones .NET especializado en aplicaciones C# y actualmente se encarga del desarrollo de componentes y herramientas .net orientadas al desarrollo de aplicaciones para la gestión y manejo de comunicaciones (IVR, FOIP, VOIP, TTS).