Reading Messages Asynchronously

When reading messages asynchronously using ActiveX components, EnableNotification must be called for each message that is read from the queue.

Typically, EnableNotification is called for the first message to be read and then again in the event handler after you read the arrived message. The subsequent calls to EnableNotification are needed to read the next message in the queue. Notification returns a single Arrived event for each message found in the queue.

The following diagram shows the basic programming model used for reading messages asynchronously. It includes two calls to EnableNotification, plus a call to read the message from the queue.

The model in the diagram shows that there are many ways to combine the two calls to EnableNotification and the call to read the message in the queue. For example, to purge all the messages in a queue, you could call EnableNotification with Cursor set to MQMSG_FIRST, call Receive, and call EnableNotification with Cursor set to MQMSG_FIRST.

However, not all combinations necessarily make good programming sense. For example, it is possible to write an event handler that would only read every other message in the queue.

The initial call to EnableNotification and the subsequent call from the event handler can tell MSMQ to check if a message is in the queue at all (Cursor = MQMSG_FIRST), if a message is at the current cursor location (Cursor = MQMSG_CURRENT), or if a message is at the next position after the cursor (Cursor = MQMSG_NEXT). The default is to trigger the Arrived event when MSMQ finds any message in the queue (Cursor = MQMSG_FIRST).

The calls to read the message in the queue include: Receive, ReceiveCurrent, Peek, PeekCurrent, or PeekNext.

Note  Each call to EnableNotification, plus the calls to ReceiveCurrent, PeekCurrent, or PeekNext, provide numerous ways to navigate through the queue. Each call can affect how the implied cursor is moved through the queue.

    To find a specific message asynchronously
  1. Call Open to open queue with receive access and call EnableNotification to start notification.
    Set queue = qInfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE)
    queue.EnableNotification Event:=Event, Cursor:=MQMSG_CURRENT, ReceiveTimeout:=1000
     
  2. Write Arrived event handler. The following event handler calls PeekCurrent to look at the current message and then uses EnableNotification (Cursor = MQMSG_NEXT) to start notification with the cursor pointing to the next location.
    Private Sub TheEvent_Arrived(ByVal Queue As Object, ByVal Cursor As Long)
    Dim msgrec As MSMQMessage
    On Error GoTo Error_TheEvent_Arrived
        Set msgrec = queue.PeekCurrent(ReceiveTimeout:=0)
        If msgrec.AppSpecific = 34 Then
            Set msgrec = queue.ReceiveCurrent(ReceiveTimeout:=0)
            MsgBox "Found a message with AppSpecific = 34", vbOKOnly, "Inside the Arrived Event handler"
        Else
            queue.EnableNotification TheEvent, MQMSG_NEXT, 1000
        End If
        Exit Sub
    Error_TheEvent_Arrived:
        MsgBox Err.Description + " in TheEvent_Arrived sub"
    End Sub
     
  3. Write ArrivedError event handler.
    Private Sub TheEvent_ArrivedError(ByVal Queue As Object, ByVal ErrorCode As Long, ByVal Cursor As Long)
        MsgBox Err.Description + " in TheEvent_ArrivedError sub"
    End Sub
    

Example

This example sends several messages with different application-specific identifiers to a queue, and searches the queue for the message whose application-specific identifier equals 34.

Option Explicit
Dim queue As MSMQQueue
Dim WithEvents TheEvent As MSMQEvent

Private Sub Form_Click()
Dim qinfo As New MSMQQueueInfo
Dim msgSend As New MSMQMessage
Dim i As Integer
On Error Resume Next
    Set TheEvent = New MSMQEvent
    qInfo.PathName = ".\AsyncSearchDemo"
    qInfo.Create
On Error GoTo Error_Form_Click
    Set queue = qinfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE)
    msgSend.AppSpecific = 24
    msgSend.Send queue
    msgSend.AppSpecific = 34
    msgSend.Send queue
    msgSend.AppSpecific = 44
    msgSend.Send queue
    msgSend.AppSpecific = 54
    msgSend.Send queue
    msgSend.AppSpecific = 64
    msgSend.Send queue
    queue.Close

'****************************
'* Open queue and start 
'* notification.
'****************************
    Set queue = qinfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE)
    queue.EnableNotification Event:=Event, Cursor:=MQMSG_CURRENT, ReceiveTimeout:=1000
    Exit Sub
Error_Form_Click:
    MsgBox Err.Description
End Sub

'****************************
'* Define Arrived event handler.
'****************************
Private Sub TheEvent_Arrived(ByVal Queue As Object, ByVal Cursor As Long)
Dim msgrec As MSMQMessage
On Error GoTo Error_TheEvent_Arrived
    Set msgrec = queue.PeekCurrent(ReceiveTimeout:=0)
    If msgrec.AppSpecific = 34 Then
        Set msgrec = queue.ReceiveCurrent(ReceiveTimeout:=0)
        MsgBox "Found a message with AppSpecific = 34", vbOKOnly, "Inside the Arrived Event handler"
    Else
        queue.EnableNotification TheEvent, MQMSG_NEXT, 1000
    End If
    Exit Sub
Error_TheEvent_Arrived:
    MsgBox Err.Description + " in TheEvent_Arrived sub"
End Sub

Private Sub TheEvent_ArrivedError(ByVal Queue As Object, ByVal ErrorCode As Long, ByVal Cursor As Long)
    MsgBox Err.Description + " in TheEvent_ArrivedError sub"
End Sub