Visual Basic Code Example: Reading Messages Asynchronously

 

Updated: July 19, 2016

Applies To: Windows 10, Windows 7, Windows 8, Windows 8.1, Windows Server 2008, Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, Windows Server Technical Preview, Windows Vista

The following example provides three Sub procedures for asynchronously reading the messages already available in a specified queue and any messages arriving in the queue until a known time period elapses without the arrival of a new message. The first procedure enables notification of message-arrival (MSMQEvent.Arrived) and arrival-error (MSMQEvent.ArrivedError) events, and the second procedure is an Arrived event routine for reading the messages. In this example each message is read and removed from the queue. The third Sub procedure handles an ArrivedError event by displaying a message indicating the nature of the error and terminating the process.

An application implementing these three Sub procedures will continue to receive messages sent to the specified queue until the receive time-out period specified in the call to MSMQQueue.EnableNotification elapses without the arrival of a new message. In this example, the receive time-out period is 10 seconds, but it can be set to any number of milliseconds or to INFINITE.

For more information about reading messages asynchronously, see Asynchronous Reading.

To enable notification

  1. In the enable notification procedure, declare the objects needed to enable notification. Note that the MSMQEvent object is declared with events outside of the Sub procedure. The MSMQQueue object must also be declared outside of the scope of the Sub procedure; otherwise, it will be closed automatically and the arrival notification will not reach the applicable user-implemented event handler.

  2. Obtain an MSMQQueueInfo object. The following example obtains the MSMQQueueInfo object by attempting to create the queue, ignoring any errors if the queue already exists.

  3. Call MSMQQueueInfo.Open to open the queue with receive access. When opening a queue with receive access the application can peek at or retrieve the messages in the queue. As a result of this call, the opened queue is represented by the MSMQQueue object.

  4. Create the object providing the Arrived and ArrivedError events and call MSMQQueue.EnableNotification to start notification, specifying the MSMQEvent object and setting the receive time-out period to 10000 milliseconds.

To handle Arrived events

  1. In the Arrived event handler, declare the MSMQMessage object.
System_CAPS_ICON_note.jpg Note

The New keyword cannot be used when reading messages.

System_CAPS_ICON_note.jpg Note

The MSMQEvent object is declared outside of the Sub procedure with class-level scope because it must be available to both the part of the code that enables notification and both event handlers. Thus, the Arrived event handler remains active even after ReadDestinationQueueAsync has exited because the MSMQEvent object is owned by the form, which continues to run. If this code were to be cut and pasted into a class object, the lifetime of the class instance would determine the lifetime of the MSMQEvent object. The asynchronous handler would become unavailable as soon as the object is destroyed.

Similarly, the MSMQQueue object is declared outside of the scope of the event handlers so that it will not be closed automatically and the event notifications will reach the applicable user-implemented event handler.

  1. Call MSMQQueue.Receive to read the message that triggered the event.

  2. Cal MSMQQueue.EnableNotification to restart notification.

System_CAPS_ICON_note.jpg Note

This example uses the default setting for the optional cursor parameter. If the cursor parameter is set to another value, be sure to coordinate how the cursor changes when reading the message and when enabling notification. Both operations affect how the cursor is moved.

For information about cursor movement, see Cursors and COM Components.

To handle ArrivedError events

  1. In the ArrivedError event handler, ascertain whether the event was fired because the receive time-out period elapsed without the arrival of a new message or because some other error occurred.

  2. Display a message indicating the nature of the error causing the event.

  3. End the process.

The following code example can be run on all versions of Message Queuing.

' Declare Message Queuing objects  
Dim q As MSMQQueue  
Dim WithEvents qevent As MSMQEvent  
  
Private Sub ReadDestinationQueueAsync( _  
                                      strPathName As String _  
                                      )  
  Dim qinfo As New MSMQQueueInfo  
  
  ' Set the path name in the MSMQQueueInfo object.  
  qinfo.PathName = strPathName  
  On Error Resume Next  
  qinfo.Create  
  On Error GoTo ErrorHandler  
  
  ' Open the queue with receive access.  
  Set q = qinfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE)  
  
  ' Create the receiving event.  
  Set qevent = New MSMQEvent  
  q.EnableNotification Event:=qevent, ReceiveTimeout:=10000  
  
  ' Start a DoEvents loop to prevent the thread from exiting.  
  Dim wait As Long  
  For wait = 1 To 10000  
    DoEvents  
  Next  
  Exit Sub  
  
ErrorHandler:  
  MsgBox "Unexpected error!" + Chr(13) + "Reason: " + Err.Description _  
          + Chr(13) + "Error: " + Hex(Err.Number)  
End Sub  
  
Private Sub qevent_Arrived(ByVal q As Object, ByVal lCursor As Long)  
  Dim msg As MSMQMessage  
  
  On Error GoTo ErrorHandler  
  ' Read the message that fired the Arrived event from the queue.  
  Set msg = q.Receive(Transaction:=MQ_NO_TRANSACTION, ReceiveTimeout:=0)  
  If Not msg Is Nothing Then  
    MsgBox "Removed message from the queue."  
  End If  
  q.EnableNotification Event:=qevent, ReceiveTimeout:=10000  
  Exit Sub  
  
ErrorHandler:  
  MsgBox "Unexpected error!" + Chr(13) + "Reason: " + Err.Description _  
          + Chr(13) + "Error: " + Hex(Err.Number)  
  q.EnableNotification Event:=qevent, ReceiveTimeout:=1000  
End Sub  
  
Private Sub qevent_ArrivedError(ByVal q As Object, ByVal lError As Long, ByVal lCursor As Long)  
  On Error GoTo ErrorHandler  
  If lError = MQ_ERROR_IO_TIMEOUT Then  
    MsgBox "No message arrived during the time-out period."  
  Else  
    MsgBox "An arrived-error event occurred. Error: " + Hex(lError)  
  End If  
  End  
  Exit Sub  
  
ErrorHandler:  
  MsgBox "Unexpected error!" + Chr(13) + "Reason: " + Err.Description _  
          + Chr(13) + "Error: " + Hex(Err.Number)  
  End  
End Sub  

Community Additions

ADD
Show: