MSMQ Triggers and COM Components

The other day I found that any emails you were sending me weren’t
getting through.  One of the emails sitting purgatory was a
request for more info on how to make MSMQ triggers call a COM
component.   I tried to reconfigure my  email and
in  the process lost the email.  All I know is that it was a
bloke from Mystic Logistics.  Well mate, hope this helps out.

I’m well past working on the first version of the MSMQ portion of our software project.  As I’d mentioned before,
I am going to post more info on the use of Invocation Parameters and
their use when calling COM components.  I should prefix this with
the fact that all my experience is with MSMQ v3.0 on Windows 2003

There are a number of things that you must do to even have a shot at getting the MSMQ Trigger service to call a COM component.

1.  If you are writing the component in .NET you will need to make it strongly named.

2.  The class and the public function/methods in the component will need to be marked with[ComVisible(true)]

3.  Your code will need to swallow all exception.  If it does
not the MSMQ Trigger service will stop.  Not a good scenario.

4.  When installing or upgrading the COM component you will need to perform a regasm <componentname.ext> /unregister and a regasm <componentname.ext>

5  After installing the component it will be in your best interest
to restart the MSMQ Trigger service.  I have run into situations
where the install will complete successfully but the messages will just
pile up in the queue not getting processed.  Restarting the
Trigger service will solve this.
Regardless of if you are working with a COM component or not, if you
use the MessageQueue.Exists(QueuePath) method it will always throw an
error/exception when the QueuePath points at a private queue. I, and
Microsoft, guarantee this.

There are also a number of coding situations that you will most likely
need to accomodate when you are having the MSMQ Trigger service call
your component.  Probably the one thing that you will most
commonly do is have the Trigger service pass the Message Body to your
component when it is called.  What good is calling the component
if you aren’t going to be able to get the info from the message. 
A couple of other things that I have needed to work with are the
Message ID and the Sending Queue.  So how, you ask, does one
configure the interface of the function that the Trigger service is
calling?  I don’t know for sure how to call all the different
Invocation Parameters so I will only concentrate on these three.

As with most of my luck, three different parameters equals three
different incoming data types.  Here’s how I ended up coding the
interface to my function (code changed to protect innocent programmers):

    public void ProcessMessage(object objMessageBody, object objMessageID, string strSendingQueue)
Okay.  We see here that two of the three values are being passed as object and the third is passed as a string.  The third one is the easiest.  The value coming into that parameter is a simple string that is all inclusive of the data that you would need to do the following:
    MessageQueue objMsgQueue =  new MessageQueue(strSendingQueue)
The other two parameter are substantially different than the Sending Queue.  Lets continue with Message ID.  This value comes from ojbMessageID as a byte array ( byte[] )  If you look at the MSMQ Queue listing in MMC, you will see that all the messages appear in that UI having a Message ID that is the equivalent of <GUID>\#####....  At first glance the byte array is longer than the 16 bytes that make up a GUID, but it doesn't appear to have enough bytes to hold the number suffix either.  I played around and found out that the first 16 ( byte[0] to byte[15] ) can be used to create the GUID and the remaining bytes can be used to create the suffix number as follows:
        byte[] arrMessageID = (byte[])objMessageID;        

        const int GUIDLENGTH = 16;
        string strMsgID;
        int intMsgSuffix;
        byte[] arrMsgGuid = new byte[GUIDLENGTH];

        for(int i = 0; i < GUIDLENGTH; i++)
            arrMsgGuid[i] = arrMessageID[i];

        intMsgSuffix = 0;
        for (int i = 0; i < (arrMessageID.Length - GUIDLENGTH);i++)
            intMsgSuffix += arrMessageID[GUIDLENGTH + i] * Convert.ToInt32(Math.Pow(Convert.ToDouble(GUIDFACTOR), Convert.ToDouble(i * 2)));        


        strMsgID = new System.Guid(arrMsgGuid).ToString();

        return strMsgID.ToString() + "\\" + intMsgSuffix.ToString();

Right…..so now we have the Sending Queue and the Message ID. 
Next stop bodyville.  I only had one value to pull from the body
of the message and it was always going to be an integer.  Probably
the most simple scenario that I could have to fight with.  The
Message Body arrives in our object parameter as an XML stream. 
Here’s the code I used to grab my one integer value from the body.

        int intValueFromBody;

        Message objMsg = new Message();
        objMsg.BodyStream = new System.IO.MemoryStream((Byte[])objMessageBody);
        objMsg.Formatter = new XmlMessageFormatter(new Type[] { typeof(int) });
        intValueFromBody = (int) objMsg.Body;

Like I said earlier, I have not had the pleasure of grabbing multiple
values from the Message Body, but I’m guessing that I’m pretty close
with this code.

Well folks, that’s all that I have.