Sunday, November 2, 2008

Getting the message count from an MSMQ Queue

While at KaizenConf (http://www.kaizenconf.com) today, I was attending a session held by Chris Patterson (twitter: @PhatBoyG) & Dru Sellers (twitter @drusellers) on ESBs and MassTransit, their ESB implementation.

During the session, Dru complained that there wasn't a good way to get the message count from an MSMQ queue.  Of course, I was required to take that as a challenge, since that's the kind of guy I am :).  I found that as of the 3.0 API for MSMQ (apparently, that's the XP / Server 2003 vintage), there's a few ways to get the message count for a queue.

The available methods (that I found) for asking for the count of messages in a Queue were:

  • Call MQMgmtGetInfo API to query the queue for the PROPID_MGMT_QUEUE_MESSAGE_COUNT property.
  • Load up a MSMQManagement COM object, call it's Init method to associate with a Queue, and then ask for it's MessageCount property value.

It appears that the first method (which is an API call) is actually just a proxy for the second, so I'm not going to talk about it.  Calling the COM object from .NET is much easier than calling the API anyway, since it's not exactly a 'pretty' API for P/Invoke purposes.

Since I'm not really interested in investing a lot of time in this blog post, I'm just going to paste the code here and let you do with it as you please...  Here goes...

var path = @".\Private$\foo";
MessageQueue mq = MessageQueue.Exists(path)
? new MessageQueue(path)
: MessageQueue.Create(path);
try
{
// try to insert a few items into the queue...
mq.Send("foo");
mq.Send("bar");
mq.Send("foo");

var msmqMgmt = new MSMQManagement();
object machine = null; // mq.MachineName;
object queuename = mq.Path;
object formatname = null; //mq.FormatName;
msmqMgmt.Init(ref machine, ref queuename,
ref formatname);
int messageCount = msmqMgmt.MessageCount;

MessageBox.Show(string.Format("Queue has {0} items",
messageCount));
}
finally
{
string path2 = mq.Path;
mq.Close();
MessageQueue.Delete(path2);
}

Of course, this code requires a reference to the COM type library - namely the "Microsoft Message Queue 3.0 Object Library" on the COM list in VS2008 when you have MSMQ installed on your dev box.

I had some weird problems trying to test this code on my machine, hence the commented machinename and formatname.  I think the problem was probably related more to the configuration of my machine than it was the code.  I suspect, however, that there may be some complexities that require you to specify machine name, queue name, and format name differently depending on whether you are working with a local queue or a remote one.

I found that for a local queue, the easy way to reference it was the code snippet above (don't specify machine, don't specify format name, supply the "path").  For a remote queue, I suspect that it will be easier to pass the machine name, the format name, and omit (pass null for) the path.  Note, the API states that you should NOT pass both the format name and the path name, or it will give an exception.

As always, if you have questions regarding this code, please don't hesitate to contact me via the comments or my email.

No comments: