I was wondering if there is a way to programmatically check how many messages are in a private or public MSMQ using C#? I have code that checks if a queue is empty or not using the peek method wrapped in a try/catch, but I've never seen anything about showing the number of messages in the queue. This would be very helpful for monitoring if a queue is getting backed up.
10 Answers
You can read the Performance Counter value for the queue directly from .NET:
using System.Diagnostics;
// ...
var queueCounter = new PerformanceCounter(
"MSMQ Queue",
"Messages in Queue",
@"machinename\private$\testqueue2");
Console.WriteLine( "Queue contains {0} messages",
queueCounter.NextValue().ToString());

- 35,458
- 16
- 93
- 163

- 2,441
- 1
- 20
- 32
-
3Works fine for one queue, but for error queue I'm getting "Instance 'machinename\private$\error' does not exist in the specified Category.". Is that because the queue haven't had any items in queue for a while or do I need to write in a special way for error queue? – Christian Fredh Jun 11 '13 at 10:32
-
2I added a message in the error queue and then the code works fine for that queue as well. I guess you need to catch this exception (InvalidOperationException) and then it's empty. Bad thing is, the queue could also be non-existent if you get this exception. – Christian Fredh Jun 11 '13 at 11:22
-
1I have found that a syntax like ".\private$\testqueue2" which is what I get from someQueue.Path will cause an exception. I ended up using someQueue.FormatName and extracting "machinename\private$\testqueue2" from its content. I also found this approach not to be 100 percent reliable when the queue is just being started or retrieved which made me think that I would be better off with an implementation based on the com dll but I hadn't had time to invest in more testing. – pasx Mar 14 '14 at 04:35
-
I am getting 'Category does not exist.' when attempting to instantiate the PerformanceCounter(). Must there be > 0 messages in the queue? Christian, did you find another work around? I cannot guarantee messages being in the queue in my case. – Roger Nov 04 '14 at 20:30
-
this is the fastest method of the ones I tested so far – maracuja-juice Oct 31 '18 at 15:27
-
How can a question this "easy" be so hard to get right? I'm getting huge pauses or "does not exist in the specified category" error. So much for a "quick look at MSMQ" !! – Dave Sep 17 '20 at 16:31
There is no API available, but you can use GetMessageEnumerator2
which is fast enough. Sample:
MessageQueue q = new MessageQueue(...);
int count = q.Count();
Implementation
public static class MsmqEx
{
public static int Count(this MessageQueue queue)
{
int count = 0;
var enumerator = queue.GetMessageEnumerator2();
while (enumerator.MoveNext())
count++;
return count;
}
}
I also tried other options, but each has some downsides
- Performance counter may throw exception "Instance '...' does not exist in the specified Category."
- Reading all messages and then taking count is really slow, it also removes the messages from queue
- There seems to be a problem with
Peek
method which throws an exception

- 35,458
- 16
- 93
- 163
-
Isn't there a race condition here? What happens if stuff is being added/removed while you are enumerating? Or if stuff is added/removed after you have counted? Is there a way to suspend all interaction with the queue while you count? – Jon List Jan 20 '16 at 20:56
-
2This method seemed to be thread-safe in a sense it reflects dynamic changes to the queue. From [doc](https://goo.gl/GywJEn) *"For example, the enumerator can automatically access a lower-priority message placed beyond the cursor's current position, but not a higher-priority message inserted before that position."*. Personally I was testing it under load during inserts and deletes and didn't have threading issues. Obviously, this will reflect approx. count of messages if your queue is used. If you need to have exact count, you need to get a static snapshot by calling `GetAllMessages` – oleksii Jan 21 '16 at 10:50
If you need a fast method (25k calls/second on my box), I recommend Ayende's version based on MQMgmtGetInfo() and PROPID_MGMT_QUEUE_MESSAGE_COUNT:
for C# https://github.com/hibernating-rhinos/rhino-esb/blob/master/Rhino.ServiceBus/Msmq/MsmqExtensions.cs
for VB https://gist.github.com/Lercher/5e1af6a2ba193b38be29
The origin was probably http://functionalflow.co.uk/blog/2008/08/27/counting-the-number-of-messages-in-a-message-queue-in/ but I'm not convinced that this implementation from 2008 works any more.

- 391
- 4
- 8
-
2Don't look for another answer! Other than @Zartag's answer, any other method is either slow or unreliable (I have tested all of them, believe me!) – meraydin Aug 17 '16 at 10:06
-
2The nuget package [Rsft.Lib.Msmq.MessageCounter](https://www.nuget.org/packages/Rsft.Lib.Msmq.MessageCounter/) implements this. – Jeroen Maes Nov 23 '16 at 14:29
-
Slow is relative @meraydin But yes this is definitely the fastest. – maracuja-juice Oct 31 '18 at 15:40
-
-
1Also @JeroenMaes unfortunately when calling the GetCount method of the library I get an exception.. Filed an issue on their repository. – maracuja-juice Oct 31 '18 at 16:10
We use the MSMQ Interop. Depending on your needs you can probably simplify this:
public int? CountQueue(MessageQueue queue, bool isPrivate)
{
int? Result = null;
try
{
//MSMQ.MSMQManagement mgmt = new MSMQ.MSMQManagement();
var mgmt = new MSMQ.MSMQManagementClass();
try
{
String host = queue.MachineName;
Object hostObject = (Object)host;
String pathName = (isPrivate) ? queue.FormatName : null;
Object pathNameObject = (Object)pathName;
String formatName = (isPrivate) ? null : queue.Path;
Object formatNameObject = (Object)formatName;
mgmt.Init(ref hostObject, ref formatNameObject, ref pathNameObject);
Result = mgmt.MessageCount;
}
finally
{
mgmt = null;
}
}
catch (Exception exc)
{
if (!exc.Message.Equals("Exception from HRESULT: 0xC00E0004", StringComparison.InvariantCultureIgnoreCase))
{
if (log.IsErrorEnabled) { log.Error("Error in CountQueue(). Queue was [" + queue.MachineName + "\\" + queue.QueueName + "]", exc); }
}
Result = null;
}
return Result;
}

- 5,007
- 6
- 41
- 48
-
Thanks, but where is the MSMQ.ManagementClass? I read in another post that you have to include a COM library called "MSMQ 3.0" but I don't see this on the Com tab (using .NET 3.5.) – Justin Oct 07 '10 at 15:37
-
Do you have Interop.MSMQ.dll anywhere on your machine? We have it in our assembly collection. – My Other Me Oct 08 '10 at 07:05
-
-
1See this answer on how to add this reference: http://stackoverflow.com/a/8258952/16241 – Vaccano Mar 07 '12 at 15:22
-
Tried this method and got the following COMException which unfortunately I cannot resolve as this would require an infrastructure change: This operation is not supported for Message Queuing installed in workgroup mode. :( – Randy Burden May 10 '12 at 00:21
//here queue is msmq queue which you have to find count.
int index = 0;
MSMQManagement msmq = new MSMQManagement() ;
object machine = queue.MachineName;
object path = null;
object formate=queue.FormatName;
msmq.Init(ref machine, ref path,ref formate);
long count = msmq.MessageCount();
This is faster than you selected one. You get MSMQManagement class refferance inside "C:\Program Files (x86)\Microsoft SDKs\Windows" just brows in this address you will get it. for more details you can visit http://msdn.microsoft.com/en-us/library/ms711378%28VS.85%29.aspx.

- 343
- 3
- 14
-
Where in the Windows folder exactly? There are 4 direct subfolders and each of the subfolders have more subfolders... What file do I have to search for? – maracuja-juice Oct 31 '18 at 16:05
I had real trouble getting the accepted answer working because of the xxx does not exist in the specified Category
error. None of the solutions above worked for me.
However, simply specifying the machine name as below seems to fix it.
private long GetQueueCount()
{
try
{
var queueCounter = new PerformanceCounter("MSMQ Queue", "Messages in Queue", @"machineName\private$\stream")
{
MachineName = "machineName"
};
return (long)queueCounter.NextValue();
}
catch (Exception e)
{
return 0;
}
}

- 26,744
- 48
- 193
- 345
This worked for me. Using a Enumarator to make sure the queue is empty first.
Dim qMsg As Message ' instance of the message to be picked
Dim privateQ As New MessageQueue(svrName & "\Private$\" & svrQName) 'variable svrnme = server name ; svrQName = Server Queue Name
privateQ.Formatter = New XmlMessageFormatter(New Type() {GetType(String)}) 'Formating the message to be readable the body tyep
Dim t As MessageEnumerator 'declared a enumarater to enable to count the queue
t = privateQ.GetMessageEnumerator2() 'counts the queues
If t.MoveNext() = True Then 'check whether the queue is empty before reading message. otherwise it will wait forever
qMsg = privateQ.Receive
Return qMsg.Body.ToString
End If
The fastest method I have found to retrieve a message queue count is to use the peek method from the following site:
protected Message PeekWithoutTimeout(MessageQueue q, Cursor cursor, PeekAction action)
{
Message ret = null;
try
{
ret = q.Peek(new TimeSpan(1), cursor, action);
}
catch (MessageQueueException mqe)
{
if (!mqe.Message.ToLower().Contains("timeout"))
{
throw;
}
}
return ret;
}
protected int GetMessageCount(MessageQueue q)
{
int count = 0;
Cursor cursor = q.CreateCursor();
Message m = PeekWithoutTimeout(q, cursor, PeekAction.Current);
{
count = 1;
while ((m = PeekWithoutTimeout(q, cursor, PeekAction.Next)) != null)
{
count++;
}
}
return count;
}

- 4,042
- 4
- 26
- 35
-
2System.Messaging.MessageQueueException: MQ_ACTION_PEEK_NEXT specified to MQReceiveMessage cannot be used with the current cursor position. at System.Messaging.MessageQueue.ReceiveCurrent(TimeSpan timeout, Int32 action, CursorHandle cursor, MessagePropertyFilter filter, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType) at System.Messaging.MessageQueue.Peek(TimeSpan timeout, Cursor cursor, PeekAction action) – Justin Oct 11 '10 at 15:36
-
We are using this exact method, and find that the method GetMessageCount is failing because it is peeking while messages are consumed from the queue. By merely adding a 10ms thread.sleep command after count++ this operates much more smoothly but takes a lot longer. I still think there must be a better way to get count that to insistantly peek a million times... (are we there yet, are we there yet, are we there yet - doh) – barrypicker May 20 '14 at 18:27
-
This code will fail if the queue contains 0 messages, because it will try PeekWithoutTimeout with PeekAction.Next even though PeekWithTimeout with PeekAction.Current returned null. Added null check to answer – Per-Frode Pedersen Nov 18 '14 at 09:10
-
This is definitely not the fastest method. Highest Voted answer: 6x times faster. Second Highest Voted Answer: 3x times faster – maracuja-juice Oct 31 '18 at 15:30
If you want a Count of a private queue, you can do this using WMI. This is the code for this:
// You can change this query to a more specific queue name or to get all queues
private const string WmiQuery = @"SELECT Name,MessagesinQueue FROM Win32_PerfRawdata_MSMQ_MSMQQueue WHERE Name LIKE 'private%myqueue'";
public int GetCount()
{
using (ManagementObjectSearcher wmiSearch = new ManagementObjectSearcher(WmiQuery))
{
ManagementObjectCollection wmiCollection = wmiSearch.Get();
foreach (ManagementBaseObject wmiObject in wmiCollection)
{
foreach (PropertyData wmiProperty in wmiObject.Properties)
{
if (wmiProperty.Name.Equals("MessagesinQueue", StringComparison.InvariantCultureIgnoreCase))
{
return int.Parse(wmiProperty.Value.ToString());
}
}
}
}
}
Thanks to the Microsoft.Windows.Compatibility
package this also works in netcore/netstandard.

- 994
- 2
- 14
- 33
The message count in the queue can be found using the following code.
MessageQueue messageQueue = new MessageQueue(".\\private$\\TestQueue");
var noOFMessages = messageQueue.GetAllMessages().LongCount();

- 1
- 1
-
1In this case you get all messages from queue. It is too expensive. – Kirill Bestemyanov May 23 '17 at 08:13