Counting the number of messages in a queue

This question is maybe the most frequently asked question in the MSMQ newsgroup… It is not hard to understand why:

– Analyzing queue’s depth is the most common action for monitoring / alert tools

– MSMQ documentation is quite vague about the best way to solve the problem

– There is more than one answer…

There are actually two sources from which the number of message can be fetched:

1. MSMQ Performance counters

2. MSMQ Admin APIs

MSMQ performance counters were part of MSMQ since day 1 (I actually owned this part :-)). Performance counters are easy to approach through WMI interface, and many monitoring tools interface to them anyway. However, when using perf. counters you don’t get the most up-to-date data and they are not always accurate, especially when looking at remote machine.

MSMQ Admin APIs were introduced with NT4 SP6a (so you probably have them…) however a COM interface to them was not supplied until MSMQ 3.0 (WXP or W2003). If you have WinNT or Win2K, you will have to use the C APIs. On the other hand, the results from MSMQ Admin APIs are more current and reliable.

.NET managed code API (System.Messaging) does not support this feature yet.

What to use, is still up to you… However, if you are writing a commercial monitoring tool, where accuracy is important, I would recommend using the Admin APIs.

Code sample – MSMQ performance counters via WMI

The following VBS script lists all the queues in your machine and displays the number of messages in each using performance counters with WMI interface:

Option Explicit

Dim Locator ‘ As New WbemScripting.SWbemLocator
Set Locator = CreateObject("WbemScripting.SWbemLocator")

Dim Service ‘ As SWbemServices
Set Service = Locator.ConnectServer()

Dim Query ‘ As string
Query = "Select * From Win32_PerfRawData_MSMQ_MSMQQueue"

Dim objs ‘ As ISWbemObjectSet
Set objs = Service.ExecQuery(Query)
if objs.Count = 0 Then
   WScript.Echo "No queues found"
Else
   Dim Object ‘ As ISWbemObject
   for each object in objs
       WScript.Echo object.MessagesInQueue & " Messages in " & object.Name
   next
End if

To test the script, copy it to a file with ".VBS" extension (like NoMsgs.vbs) and run (from command line) "CScript NoMsgs.vbs" . You can also remove the comments and compile the script in Visual Basic.

Code sample – MSMQ Admin APIs in MSMQ 3.0

The following code does the same thing – list all the  queues in the computer and the number of messages in each – using the MSMQ 3.0 Admin object.

Option Explicit
Dim MSMQApp ‘ As MsmqApplication
Set MSMQApp = CreateObject("MSMQ.MSMQApplication")

Dim qFormat ‘ As String
For each qFormat in MSMQApp.ActiveQueues
   Dim Mgmt ‘ As new MSMQManagement
   Set Mgmt = CreateObject("MSMQ.MSMQManagement")
   Mgmt.Init ,,qFormat
   WScript.Echo CLng(Mgmt.MessageCount) & " Messages in " & qFormat
Next

Again – copy the text to a VBS file and it is ready to run.

Not that the two scripts do not yield the exact same result… Performance counters include MSMQ internal queues (admin_queue$, order_queue$, notify_queue$, and machine queues). In addition, it may include an active queue with 0 messages that was long ago deleted from the list for the Admin APIs. Anyway, both APIs do not give a full list of queues, just the active queues – that is, queues that are either open by an application or have messages in them.

If you run on NT4 or Win2K and still want to use the admin APIs to count the number of messags in a queue,you will have to use C/C++ and download the MSMQ Local Admin API package from http://support.microsoft.com/default.aspx?kbid=242471 . If you need a C sample code that does it (uses admin APIs to get the # of messages in a queue in NT4/W2K) please add a comment to this blog, and I will see what I can do.

Cheers,

Yoel

This entry was posted in Uncategorized. Bookmark the permalink.

8 Responses to Counting the number of messages in a queue

  1. Unknown says:

    Hi Yoel,Could you please give me a sample code to count the number of messages in a queue using C# and the .NET environment. I do have MSMQ 3.0 on my machine.Thanks much,John

  2. Yoel says:

    Hi John, thanks a lot for your comment!I just published a new blog (Mar. 21st) that covers someof the .NET ways to count messages in a queue and I hope you will find it usefull.All the best,Yoel

  3. Travis V says:

    I have been looking for information on this topic for a while.  Thanks for sharing you knowledge!!! 

  4. Julius says:

    hi john, you can use .GetAllMessages().Length to get the number of message in specific queue.            MessageQueue MessageInQueue = new System.Messaging.MessageQueue(PrivateQueues[i].Path);             MessageInQueue.GetAllMessages().Length;http://juliusr.freeweb7.com/qxplorer.html

  5. Yoel says:

    Hi Julius,.GetAllMessages().Length will work, but it will first read all the messages from the queue in order to count them… if you have a production queue with several thousand messages, that can be a huge performance issue.

  6. Pingback: MSMQ – Access statistics from .NET? | DeveloperQuestion.com

  7. sumit says:

    I cannot get the MSMQManagement.Init method to work if client and server are not in the same Domain. so INIT method works only if client and server are on same domain?

  8. irena says:

    I tried this script for counting messages in queue on different computer i just aded username and password and it returns error Invalid code class 80041010 source SWbemObjectSet
    Dim Locator ‘As New WbemScripting.SWbemLocator
    Set Locator = CreateObject(“WbemScripting.SWbemLocator”)
    strComputer = “x.x.x.x”
    Dim Service ‘As SWbemServices
    Set Service = Locator.ConnectServer(strComputer, “root\cimv2”, “x.x.x.x\administrator”, “Pa$$word”)
    Dim Query ‘As string
    Query = “Select * From Win32_PerfRawData_MSMQ_MSMQQueue”
    Dim objs ‘ As ISWbemObjectSet
    Set objs = Service.ExecQuery(Query)
    if objs.Count = 0 Then
    WScript.Echo “No queues found”
    Else
    Dim Object ‘ As ISWbemObject
    for each object in objs
    WScript.Echo object.MessagesInQueue & ” Messages in ” & object.Name
    next
    End if

Leave a comment