Skip to content

Instantly share code, notes, and snippets.

@Lercher
Last active July 25, 2017 20:38
Show Gist options
  • Save Lercher/5e1af6a2ba193b38be29 to your computer and use it in GitHub Desktop.
Save Lercher/5e1af6a2ba193b38be29 to your computer and use it in GitHub Desktop.
Counting messages in a Microsoft Message Queue (msmq). About 25k times per second on a 2011 core i7 box with ssd.
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Public Class MQCounter
' see https://github.com/hibernating-rhinos/rhino-esb/blob/master/Rhino.ServiceBus/Msmq/MsmqExtensions.cs
' see http://ayende.com/blog/3884/unmanaged-api-fun-finding-out-msmq-subqueues-names-in-c
Public Shared Function Count(Q As String, Host As String) As UInteger
Dim props = New MQMGMTPROPS With {.cProp = 1}
props.aPropid = Marshal.AllocHGlobal(4) : Marshal.WriteInt32(props.aPropid, PROPID_MGMT_QUEUE_MESSAGE_COUNT)
props.status = Marshal.AllocHGlobal(4) : Marshal.WriteInt32(props.status, 0)
props.aPropVT = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(MQPROPVariant))) : Marshal.StructureToPtr(New MQPROPVariant With {.vt = VT_NULL}, props.aPropVT, False)
Dim QQ = "queue=" & Q
dim vt As MQPROPVariant
Try
Dim result = MQMgmtGetInfo(Host, QQ, props)
If result <> 0 Then Throw New Win32Exception(result)
Dim statusVal = Marshal.ReadInt32(props.status)
If statusval <> 0 Then Throw New ApplicationException("MQMgmtGetInfo status " & statusval.ToString())
vt = DirectCast(Marshal.PtrToStructure(props.aPropVT, GetType(MQPROPVariant)), MQPROPVariant)
If vt.vt <> VT_UI4 then Throw New ApplicationException("MQMgmtGetInfo VT is not VT_UI4(19) but " & vt.vt.ToString())
Return vt.value.ulVal
Finally
' cleanup
Marshal.FreeHGlobal(props.aPropid) : props.aPropid = IntPtr.Zero
Marshal.FreeHGlobal(props.status) : props.status = IntPtr.Zero
Marshal.FreeHGlobal(props.aPropVT) : props.aPropVT = IntPtr.Zero
End Try
End Function
End Class
Public NotInheritable Class NativeMethods
Private Sub New()
End Sub
Public Const MQ_MOVE_ACCESS As Integer = 4
Public Const MQ_DENY_NONE As Integer = 0
<DllImport("mqrt.dll", CharSet:=CharSet.Unicode)> _
Public Shared Function MQOpenQueue(formatName As String, access As Integer, shareMode As Integer, ByRef hQueue As IntPtr) As Integer
End Function
<DllImport("mqrt.dll")> _
Public Shared Function MQCloseQueue(queue As IntPtr) As Integer
End Function
<DllImport("mqrt.dll")> _
Public Shared Function MQMoveMessage(sourceQueue As IntPtr, targetQueue As IntPtr, lookupID As Long, transaction As IntPtr) As Integer
'Public Shared Function MQMoveMessage(sourceQueue As IntPtr, targetQueue As IntPtr, lookupID As Long, transaction As IDtcTransaction) As Integer
End Function
<DllImport("mqrt.dll")> _
Friend Shared Function MQMgmtGetInfo(<MarshalAs(UnmanagedType.BStr)> computerName As String, <MarshalAs(UnmanagedType.BStr)> objectName As String, ByRef mgmtProps As MQMGMTPROPS) As Integer
End Function
Public Const VT_NULL As Byte = 1
Public Const VT_UI4 As Byte = 19
Public Const PROPID_MGMT_QUEUE_MESSAGE_COUNT As Integer = 7
Public Const PROPID_MGMT_QUEUE_SUBQUEUE_NAMES As Integer = 27
'size must be 16
<StructLayout(LayoutKind.Sequential, Size:=16)> _
Friend Structure MQPROPVariant
Public vt As UShort
Public reserved2 As UShort
Public reserved3 As UShort
Public reserved4 As UShort
Public value As UnionedVariant
End Structure
<StructLayout(LayoutKind.Explicit, Size:=8)>
friend Structure UnionedVariant
<FieldOffset(0)> public ulVal As UInteger ' VT_UI4 */
<FieldOffset(0)> public calpwstr As ULong ' VT_VECTOR | VT_LPWSTR */
end Structure
'size must be 16 in x86 and 28 in x64
<StructLayout(LayoutKind.Sequential)> _
Friend Structure MQMGMTPROPS
Public cProp As UInteger
Public aPropID As IntPtr
Public aPropVT As IntPtr
Public status As IntPtr
End Structure
End Class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment