Msmq no Compact Framework 2.0

 

Num outro artigo vimos como utilizar o recurso de enfileiramento de mensagens do Windows, o MSMQ ( Microsoft Message Queuing ), no .Net Framework. Neste veremos como utilizar um dos novos recursos do .Net Compact Framework 2.0, o uso do MSMQ no Windows Mobile.

 

Preparando ambiente

Nós utilizaremos o Windows Mobile 2003, e a primeira coisa a fazer é baixar o seu SDK, cujo link se encontra logo abaixo:

http://www.microsoft.com/downloads/details.aspx?FamilyID=9996b314-0364-4623-9ede-

0b5fbb133652&DisplayLang=en

 

Criando o projeto

Agora no Visual Studio 2005 vamos criar nosso projeto ( Visual C# -> Smart Device -> Pocket PC 2003 -> Device Application ), o qual daremos o nome de MsmqCF.

 

Adicionando referências

O SDK que baixamos possui alguns arquivos os quais farão a instalação do Msmq no Windows Mobile. Esses arquivos devem está localizados no diretório “C:\Program Files\Windows CE Tools\wce420\POCKET PC 2003\Support\Msmq\armv4”, ou algo similar, dependendo do idioma do S.O .

 

Para isso vamos adicionar todos os arquivo deste diretório no nosso projeto ( Add->Existing Item..).

 

Em todos eles, a propriedade “Build Action” deve está como Content e a propriedade “Copy to Output Directoy” como Copy if newer.

 

Dividindo o desenvolvimento em duas etapas

Vamos dividir o desenvolvimento em duas etapas: a primeira será em relação ao processo de instalação automática do MSMQ no Pocket PC, e a segunda será a utilização realmente do serviço de enfileiramento de mensagens.

 

1 - Instalação automática do MSMQ no Windows Mobile

 

A seguir veremos o código responsável pela instalação do MSMQ no Pocket. Não entraremos em detalhe pois não é nosso objetivo e sua explicação tornaria o artigo demasiadamente longo.

No FORM ( Form1) criado no projeto, vamos  adicionar o código a seguir:

 

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 static Int32 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("Failure in GetExitCodeProcess");

                CloseHandle(pi.hThread);          

                // Liberando handles

                CloseHandle(pi.hProcess);

                return false;

            }

 

            CloseHandle(pi.hThread);

            // Liberando handles

            CloseHandle(pi.hProcess);

            if (exitCode != 0)

                return false;

            else

                return true;

        }

 

        //This is the MSMQAdm.exe utility we’ll be using

        private const String MSMQ_ADM = @"\windows\msmqadm.exe";

        private const String MSMQ_DRIVER_REG = @"Drivers\BuiltIn\MSMQD";

 

private static void CopyFilesRequired()

        {

            string _path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().

                      GetName().CodeBase);

            if (!File.Exists(@"\windows\msmqadm.exe"))

                File.Copy(_path + "\\msmqadm.exe", @"\windows\msmqadm.exe");

            if (!File.Exists(@"\windows\msmqadmext.dll"))

                File.Copy(_path + "\\msmqadmext.dll", @"\windows\msmqadmext.dll");

            if (!File.Exists(@"\windows\msmqd.dll"))

                File.Copy(_path + "\\msmqd.dll", @"\windows\msmqd.dll");

            if (!File.Exists(@"\windows\msmqrt.dll"))

                File.Copy(_path + "\\msmqrt.dll", @"\windows\msmqrt.dll");

 

            File.Delete(_path + "\\msmqadm.exe");

            File.Delete(_path + "\\msmqadmext.dll");

            File.Delete(_path + "\\msmqd.dll");

            File.Delete(_path + "\\msmqrt.dll");

        }

 

Adicionaremos no evento de Load do Form o código que irá verificar a presença do MSMQ no dispositivo, e instalá-lo caso este ainda não esteja presente .

 

//We need to move the MSMQ components deployed to the system folder

CopyFilesRequired();

//Check status of MSMQ (is it installed and running yet?

 

if (!(CreateProcess(MSMQ_ADM, "status")))

{

//Deletes the MSMQ registry key and store directory.

//All messages are lost.

 

        CreateProcess(MSMQ_ADM, "register cleanup");

       //Installs MSMQ as device drivcers.

       if (CreateProcess(MSMQ_ADM, "register install"))                  

       {

          MessageBox.Show("Registered Drivers Successfully");

        }

        else

        {

          MessageBox.Show("Failed to install MSMQ! System Error = " + GetLastError().ToString());

          return;

        }

 

//Creates the MSMQ Configuration in Registry

        if (CreateProcess(MSMQ_ADM, "register"))

        {

           MessageBox.Show("Registered MSMQ Successfully");

        }

        else

        {

           MessageBox.Show("Failed to Register MSMQ! System Error = " + GetLastError().ToString());

//  return;

        }

 

//Enables the native MSMQ protocol

        if (CreateProcess(MSMQ_ADM, "enable binary"))

        {

           MessageBox.Show("Enable Binary Successfully");

        }

        else

        {

        MessageBox.Show("Failed to enable Binary! System Error = " + GetLastError().ToString());

        return;

        }

 

//Starts the MSMQ service

        if (CreateProcess(MSMQ_ADM, "start"))

        {

           MessageBox.Show("Started MSMQ Successfully");

        }

        else

        {

 

//This is one additional step that is needed for PocketPCs

//The Device Drivers have to be loaded before the service

//can be started

//ActivateDevice will load the device drivers

 

        IntPtr handle = ActivateDevice(MSMQ_DRIVER_REG, 0);

        CloseHandle(handle);

 

//Let us check if MSMQ is running

 

        if (CreateProcess(MSMQ_ADM, "status"))

        {

           MessageBox.Show("MSMQ is up and running");

        }

        else

        {

            MessageBox.Show("Failed to start MSMQ! System Error = " + GetLastError().ToString());

         }

      }

}

else

     MessageBox.Show("MSMQ is already up and running");

 

2 – Utilização do MSMQ no dispositivo

 

Finalmente vamos adicionar o código para a utilização propriamente dita do MSMQ no dispositivo, pois até agora tudo que vimos foi em relação à instalação automática do serviço.

 

Adicionando os controles do Form

Adicione os controles a seguir (verificar o layout na figura ao lado):

 

 

Controle

ID

TextBox

txtSendMsg

TextBox

txtRecMsg

Button

btnSendMsg

Button

btnReceiveMsg

 gbmsmqcffig01.jpg

 

Agora vamos inserir o código do button (btnSendMsg) responsável por enviar a mensagem para a fila do MSMQ. Para isso dê um duplo-clique no Button e insira o seguinte código:

 

if (txtSendMsg.Text.Trim() == "") return;

string strDestQ = @".\private$\testq"; //nome da fila

try

{

    if (!MessageQueue.Exists(strDestQ))

    {

       MessageQueue.Create(strDestQ);

    }

 

    MessageQueue mq = new MessageQueue(strDestQ);

    mq.Send(txtSendMsg.Text);

    txtSendMsg.Text = "";

}

Catch

{

 

}

 

E por último vamos inserir o código do button (btnReceiveMsg) responsável por ler da fila do MSMQ as mensagens disponíveis. Para isso dê um duplo-clique no Button e insira o seguinte código:

 

lblReceiveMsg.Text = ""; Refresh();

            MessageQueue mq = new MessageQueue(@".\private$\testq");

            //especifica o formatter para des-serializar a mensagem

            mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });

            try

            {

                Message messageReceived = mq.Receive(new TimeSpan(0, 0, 1));//timeout em 1s

                txtRecMsg.Text = (string)messageReceived.Body;

            }

            catch { txtRecMsg.Text = "- timeout -"; }

 

Pronto, isso é tudo. Observe que código para utilização do MSMQ é muito pequeno, apenas algumas poucas linhas, lembrando que grande parte do código neste artigo foi para a instalação do MSMQ no dispositivo.

 

Agora é só executar e testar a aplicação. Vale ressaltar que ao rodar a aplicação pela  primeira, o MSMQ será instalado no dispositivo, o que resultará em um tempo maior no deploy.

 

É isso ai pessoal, até a próxima.

 

Gustavo Barros

 

OBS: Este artigo foi baseado no blog do Mark Ihimoyan´s:

http://blogs.msdn.com/ihimmar/archive/2004/06/14/154911.aspx