3.11.4.1.9 EnableNotification (Opnum 15)

The EnableNotification method is received by the server in an RPC_REQUEST packet. In response, the server starts event notification for asynchronously receiving or peeking messages.

 HRESULT EnableNotification(
   [in] IMSMQEvent3* Event,
   [in, optional] VARIANT* Cursor,
   [in, optional] VARIANT* ReceiveTimeout
 );

Event: A pointer to an IMSMQEvent3 interface. If Event is NULL, the server MUST return an error E_INVALIDARG (0x80070057).

Cursor: A VARIANT pointer to a signed integer that corresponds to one of the MQMSGCURSOR ( section 2.2.2.8) enumeration values.

If this parameter is not specified by the client, the server MUST use the default value MQMSG_FIRST (0x00000000).

ReceiveTimeout: A pointer to a VARIANT that contains a long value (VT_I4) that specifies the time, in milliseconds, that the server MUST NOT exceed while waiting for a new message to arrive.

If this parameter is not specified by the client, the server MUST use the default value INFINITE (0xFFFFFFFF).

Return Values: The method MUST return S_OK (0x00000000) on success or an implementation-specific error HRESULT on failure.

When processing this call, the server MUST follow these guidelines:

  • If the Cursor input parameter is not equal to MQMSG_FIRST, MQMSG_CURRENT, or MQMSG_NEXT:

    • Return E_INVALIDARG (0x80070057), and take no further action.

  • If the IsInitialized instance variable equals False:

    • Return an error OLE_E_BLANK (0x80040007), and take no further action.

  • If the IsClosed instance variable equals True:

    • Return an error MQ_ERROR_INVALID_HANDLE (0xC00E0007), and take no further action.

  • If the Event input parameter is NULL:

    • Return E_INVALIDARG (0x80070057), and take no further action.

  • If refQueue.AccessType is not equal to PeekAccess or PeekAdminAccess:

    • Return an error MQ_ERROR_ACCESS_DENIED (0xC00E0025), and take no further action.

  • If the Cursor input parameter equals MQMSG_NEXT:

    • Advance the cursor represented by the Cursor instance variable.

  • Return S_OK (0x00000000), and take no further action.

Asynchronously:

  • If the Cursor input parameter equals MQMSG_NEXT or MQMSG_CURRENT:

    • Define suitable message as a Message, identified by the cursor represented by the Cursor instance variable, in the MessagePositionList of the referenced queue for which the MessagePosition.State attribute does not equal Locked or Message.AllowPeekWhenLocked equals True.

    • Starting from the Message identified by the cursor represented by the Cursor instance variable, continually advance the cursor, seeking a suitable message. If the cursor reaches EndQueue state, wait for more messages to arrive. The cursor is advanced seeking a suitable message by doing the following:

  • While a suitable message is not found:

    • The Peek Next Message event MUST be generated with the following arguments:

      • iQueueDesc: MUST be set to a reference to the OpenQueueDescriptor object that specifies the referenced queue.

      • iTimeout: MUST be set to ReceiveTimeout.

      • iCursor: MUST be set to a reference to the Cursor instance variable.

      • If the returned rStatus is not MQ_OK:

        • If the returned rStatus is MQ_ERROR_ILLEGAL_CURSOR_ACTION, and the ReceiveTimeout input parameter equals 0:

          • Fire the ArrivedError (section 3.16.4.4.2) event on the MSMQEvent object that is identified by the Event input parameter. Specify the ErrorCode parameter as MQ_ERROR_MESSAGE_NOT_FOUND (0xc00e0008), and take no further action.

      • If the returned rStatus is MQ_ERROR_IO_TIMEOUT, and the ReceiveTimeout input parameter is greater than 0 and does not equal INFINITE, and the time-out identified by the ReceiveTimeout input parameter expires:

        • Fire the ArrivedError event on the MSMQEvent object identified by the Event input parameter. Specify the ErrorCode parameter as MQ_ERROR_IO_TIMEOUT (0xc00e001b), and take no further action.

    • Else, if the returned rStatus is MQ_OK:

      • If the Message returned in rMessage is a suitable message:

        • Fire the Arrived (section 3.16.4.4.1) event on the MSMQEvent object identified by the Event input parameter, and take no further action.

      • If iCursor.MessagePositionReference is equivalent to iQueue.MessagePositionList.End:

        • The Wait for New Message event MUST be raised with the following arguments:

          • iQueueDesc: Reference to an OpenQueueDescriptor that specifies the queue that this event will wait on.

          • iTimeout: The amount of time to wait in seconds.

          • iDestructiveRead: This value MUST be set to False.

          • iCursor: Reference to a Cursor object that is associated with this wait request.

        • If the returned rStatus equals Success:

      • Set iCursor.MessagePositionReference to the returned rMessagePosition.

  • Else:

    • Define suitable message as the Message at the head of the MessagePositionList of the referenced queue for which the MessagePosition.State attribute does not equal Locked or Message.AllowPeekWhenLocked equals True.

    • Attempt to retrieve the suitable message.

      • If no suitable message can be located:

        • If the ReceiveTimeout input parameter is 0:

          • Fire the ArrivedError event on the MSMQEvent object identified by the Event input parameter. Specify the ErrorCode parameter as MQ_ERROR_MESSAGE_NOT_FOUND (0xc00e0008), and take no further action.

        • If the ReceiveTimeout input parameter is INFINITE (0xFFFFFFFF):

          • Wait until a suitable message is available.

          • Fire the Arrived event on the MSMQEvent object identified by the Event input parameter, and take no further action.

          • If the ReceiveTimeout input parameter is neither 0 nor INFINITE (0xFFFFFFFF):

          • Wait until either of the following events occurs:

            • The time-out specified by the ReceiveTimeout input parameters expires:

              • Fire the ArrivedError event on the MSMQEvent object that is identified by the Event input parameter. Specify the ErrorCode parameter as MQ_ERROR_IO_TIMEOUT (0xc00e001b), and take no further action.

            • A suitable message becomes available:

          • Fire the Arrived event on the MSMQEvent object identified by the Event input parameter, and take no further action.

      • Else, if one or more suitable messages are available:

        • Fire the Arrived event on the MSMQEvent object identified by the Event input parameter, and take no further action.