3.1.4.7 R_StartReceive (Opnum 7)

The R_StartReceive method peeks or receives a message from an open queue.

If the R_StartReceive method is invoked with a Peek action type, as specified in the ulAction parameter, the operation completes when the R_StartReceive method returns.

If the R_StartReceive method is invoked with a Receive action type, as specified in the ulAction parameter, the client MUST pair each call to the R_StartReceive method with a call to the R_EndReceive (Opnum 9) (section 3.1.4.9) method to complete the operation, or to the R_CancelReceive (Opnum 8) (section 3.1.4.8) method to cancel the operation. The call to the R_EndReceive method or the R_CancelReceive method is correlated to a call to the R_StartReceive method through matching dwRequestId parameters.

If the client specifies a nonzero ulTimeout parameter, and a message is not available in the queue at the time of the call, the server waits up to the specified time-out for a message to become available in the queue before responding to the call. The client can call the R_CancelReceive method with a matching dwRequestId parameter to cancel the pending R_StartReceive method request.

The message to be returned can be specified in one of three ways:

  • LookupId: A nonzero LookupId parameter value specifies the unique identifier for the message to be returned. The ulAction parameter further specifies whether the message to be returned is the one identified by the LookupId parameter or the first unlocked message immediately preceding or following it. For more details, see the description of the ulAction parameter.

  • Cursor: A nonzero cursor handle specifies the cursor to be used to identify the message to be returned. The cursor specifies a location in the queue. The ulAction parameter further specifies whether the message to be returned is the one identified by the cursor or the first unlocked message immediately following it. For more details, see the description of the ulAction parameter.

  • First: if the LookupId parameter is set to zero and the hCursor parameter is set to zero, the first unlocked message in the queue can be returned. The ulAction parameter further specifies whether the first message is to be received or peeked.

The ppPacketSections parameter is the address of one or more pointers to one or more SectionBuffer (section 2.2.6) structures. The pSectionBuffer member of the first SectionBuffer structure points to the beginning of the message packet. If more than one SectionBuffer structure is present, the packet sections are concatenated in the order in which they appear in the array to form the entire packet. The size of each section is stored in the SectionSizeAlloc member of the SectionBuffer structure.

 HRESULT R_StartReceive(
   [in] handle_t hBind,
   [in] QUEUE_CONTEXT_HANDLE_NOSERIALIZE phContext,
   [in] ULONGLONG LookupId,
   [in] DWORD hCursor,
   [in] DWORD ulAction,
   [in] DWORD ulTimeout,
   [in] DWORD dwRequestId,
   [in] DWORD dwMaxBodySize,
   [in] DWORD dwMaxCompoundMessageSize,
   [out] DWORD* pdwArriveTime,
   [out] ULONGLONG* pSequenceId,
   [out] DWORD* pdwNumberOfSections,
   [out, size_is(, *pdwNumberOfSections)] 
     SectionBuffer** ppPacketSections
 );

hBind: MUST specify an RPC binding handle parameter, as specified in [MS-RPCE] section 2.

phContext: MUST be set by the client to a QUEUE_CONTEXT_HANDLE_NOSERIALIZE (section 2.2.4.1) handle of the queue from which to read a message. The handle MUST have been returned by the server in the pphQueue output parameter of a prior call to the R_OpenQueue (Opnum 2) (section 3.1.4.2) method and MUST NOT have been closed through a call prior to the R_CloseQueue (Opnum 3) (section 3.1.4.3) method. This value MUST NOT be NULL.

The handle MUST have been opened with a dwAccess parameter value that permits the operation specified by the ulAction parameter. For more details, see the dwAccess parameter in the R_OpenQueue method.

LookupId: If nonzero, specifies the lookup identifier of the message to be acted on.

If the client sets the LookupId parameter to a nonzero value, the valid values for other parameters are as follows:

  • ulTimeout set to 0x00000000.

  • hCursor set to 0x00000000.

  • ulAction set to one of the following:

    • MQ_LOOKUP_PEEK_PREV

    • MQ_LOOKUP_PEEK_CURRENT

    • MQ_LOOKUP_PEEK_NEXT

    • MQ_LOOKUP_RECEIVE_PREV

    • MQ_LOOKUP_RECEIVE_CURRENT

    • MQ_LOOKUP_RECEIVE_NEXT

      If the client sets the LookupId parameter to 0x0000000000000000, all of the preceding values of the ulAction parameter are invalid.

hCursor: If nonzero, specifies a handle to a cursor that MUST have been obtained from a prior call to the R_CreateCursor (Opnum 4) (section 3.1.4.4) method. The handle MUST NOT have been closed through a prior call to the R_CloseCursor (Opnum 5) (section 3.1.4.5) method.

If the client sets the hCursor parameter to a nonzero value, the valid values for other parameters are as follows:

  • LookupId set to 0x0000000000000000

  • ulAction set to one of the following:

    • MQ_ACTION_RECEIVE

    • MQ_ACTION_PEEK_CURRENT

    • MQ_ACTION_PEEK_NEXT

ulAction: Specifies the action to perform on the message. The following table lists possible actions.

Type / Value

Meaning

MQ_ACTION_RECEIVE

0x00000000

If the hCursor parameter is nonzero, read and remove the message for the current cursor location, and advance the cursor to the next position.

If the hCursor parameter is 0x00000000, read and remove the message from the front of the queue.

The valid values for other parameters are as follows:

  • LookupId set to 0x0000000000000000.

MQ_ACTION_PEEK_CURRENT

0x80000000

If the hCursor parameter is nonzero, read the message at the current cursor location, but do not remove it from the queue.

If the hCursor parameter is 0x00000000, read the message at the front of the queue, but do not remove it from the queue.

The valid values for other parameters are as follows:

  • LookupId set to 0x0000000000000000.

MQ_ACTION_PEEK_NEXT

0x80000001

If the hCursor parameter is nonzero, advance the cursor to the next position and read the message, but do not remove it from the queue.

The valid values for other parameters are as follows:

  • LookupId set to 0x0000000000000000.

  • hCursor set to a nonzero cursor handle obtained from the R_CreateCursor method.

MQ_LOOKUP_PEEK_CURRENT

0x40000010

Read the message specified by the LookupId parameter, but do not remove it from the queue.

The valid values for other parameters are as follows:

  • LookupId set to a nonzero value.

  • hCursor set to 0x00000000.

  • ulTimeout set to 0x00000000.

MQ_LOOKUP_PEEK_NEXT

0x40000011

Read the message following the message specified by the LookupId parameter, but do not remove it.

The valid values for other parameters are as follows:

  • LookupId set to a nonzero value.

  • hCursor set to 0x00000000.

  • ulTimeout set to 0x00000000.

MQ_LOOKUP_PEEK_PREV

0x40000012

Read the message preceding the message specified by the LookupId parameter, but do not remove it from the queue.

The valid values for other parameters are as follows:

  • LookupId set to a nonzero value.

  • hCursor set to 0x00000000.

  • ulTimeout set to 0x00000000.

MQ_LOOKUP_RECEIVE_CURRENT

0x40000020

Read the message specified by the LookupId parameter, and remove it from the queue.

The valid values for other parameters are as follows:

  • LookupId set to a nonzero value.

  • hCursor set to 0x00000000.

  • ulTimeout set to 0x00000000.

MQ_LOOKUP_RECEIVE_NEXT

0x40000021

Read the message following the message specified by the LookupId parameter, and remove it from the queue.

The valid values for other parameters are as follows:

  • LookupId set to a nonzero value.

  • hCursor set to 0x00000000.

  • ulTimeout set to 0x00000000.

MQ_LOOKUP_RECEIVE_PREV

0x40000022

Read the message preceding the message specified by the LookupId parameter, and remove it from the queue.

The valid values for other parameters are as follows:

  • LookupId set to 0x0000000000000000.

  • hCursor set to 0x00000000.

  • ulTimeout set to 0x00000000.

If the hCursor parameter is 0x00000000 and the LookupId parameter is 0x0000000000000000, the valid values for the ulAction parameter are as follows:

  • MQ_ACTION_RECEIVE

  • MQ_ACTION_PEEK_CURRENT

ulTimeout: Specifies the time-out, in milliseconds, to wait for a message to become available in the queue. The valid value for this parameter is 0x00000000 if the LookupId parameter value is nonzero or if the action is not MQ_ACTION_RECEIVE, MQ_ACTION_PEEK_CURRENT, or MQ_ACTION_PEEK_NEXT.

dwRequestId: MUST be set by the client to a unique correlation identifier for the receive request. This value MUST be used in a subsequent call to the R_EndReceive method or the R_CancelReceive method to correlate that call with the call to the R_StartReceive method. The value MUST NOT be used in another R_StartReceive method call on the same QUEUE_CONTEXT_HANDLE_NOSERIALIZE handle until a call to either the R_EndReceive method or the R_CancelReceive method with the same dwRequestId parameter value has been completed.

dwMaxBodySize: MUST be set by the client to the maximum size, in bytes, of the message body to be returned. The server SHOULD ignore this parameter when the message is not a Binary Message (section 2.2.5.1.1).

dwMaxCompoundMessageSize: MUST be set by the client to the maximum size, in bytes, of the CompoundMessageHeader (section 2.2.5.1.2.2). The server SHOULD ignore this parameter when the message is not an SRMP Message (section 2.2.5.1.2).

pdwArriveTime: The server MUST set this value to the time that the message was added to the queue ([MS-MQDMPR] section 3.1.7.3.1), expressed as the number of seconds elapsed since midnight 00:00:00.0, January 1, 1970 UTC.

pSequenceId: The server MUST set this parameter to the least significant 7 bytes of the Message.LookupIdentifier of the message that is received by this request.

pdwNumberOfSections: The server MUST set this parameter to the number of entries in the array pointed to by the ppPacketSections parameter.

ppPacketSections: The server MUST set this parameter to an array of pointers to SectionBuffer structures. The server MUST fill this array in the following manner:

  • Create two local variables of type DWORD called maxMessageSize and actualMessageSize. Assign the following values to these variables:

    If the message is a Binary Message (section 2.2.5.1.1):

    • maxMessageSize := dwMaxBodySize

    • actualMessageSize := message packet body size

      If the message is an SRMP Message (section 2.2.5.1.2):

    • maxMessageSize := dwMaxCompoundMessageSize

    • actualMessageSize := size in bytes of CompoundMessageHeader

  • If the value of maxMessageSize is greater than or equal to actualMessageSize, the ppPacketSections parameter MUST contain a single entry as follows:

    • SectionType (section 2.2.7) MUST be set to stFullPacket (0x00000000).

    • The SectionSize and SectionSizeAlloc elements MUST be set to the message packet size.

    • The pSectionBuffer member MUST contain the entire message packet.

  • If the value of maxMessageSize is less than actualMessageSize, the array MUST contain a first entry as follows:

    • SectionType MUST be set to one of the following:

      • stBinaryFirstSection if the message packet is a binary packet.

      • stSrmpFirstSection if the message packet is an SRMP packet.

    • The pSectionBuffer member MUST contain the message packet headers concatenated with the first maxMessageSize bytes of the message body.

    • The SectionSizeAlloc member MUST be set to the message packet header size plus actualMessageSize.

    • The SectionSize member MUST be set to the size of the pSectionBuffer member.

  • If the value of maxMessageSize is less than actualMessageSize and the message packet trailers are not empty, the array MUST contain a second entry as follows:

    • SectionType MUST be set to one of the following:

      • stBinarySecondSection if the message packet is a binary packet.

      • stSrmpSecondSection if the message packet is an SRMP packet.

    • The pSectionBuffer member MUST contain the message packet trailers.

    • The SectionSize member and the SectionSizeAlloc member MUST be equal and set to the message packet trailers size.

  • For the first entry in this array, the pSectionBuffer member points to a Message Packet Structure (section 2.2.5). Within this structure, set UserMessage.BaseHeader.TimeToReachQueue to UserHeader.SentTime + UserMessage.BaseHeader.TimeToReachQueue.

Return Values: On success, this method MUST return MQ_OK (0x00000000).

If an error occurs, the server MUST return a failure HRESULT, and the client MUST treat all failure HRESULTs identically. The client MUST disregard all output parameter values when any failure HRESULT is returned. For descriptions of the following error codes, see [MS-MQMQ] section 2.4. For error codes not described in [MS-MQMQ], refer to [MSDN-MQEIC].

Return value/code

Description

0x00000000

MQ_OK

0xC00E0007

MQ_ERROR_INVALID_HANDLE

0xC00E001B

MQ_ERROR_IO_TIMEOUT

0xC00E0088

MQ_ERROR_MESSAGE_NOT_FOUND

0xC00E001D

MQ_ERROR_MESSAGE_ALREADY_RECEIVED

0xC00E0008

MQ_ERROR_OPERATION_CANCELLED

0xC00E0006

MQ_ERROR_INVALID_PARAMETER

Exceptions Thrown:

No exceptions are thrown except those thrown by the underlying RPC protocol, as specified in [MS-RPCE].

While processing this method, the server MUST:

  • If any of the input parameter values is invalid, return MQ_ERROR_INVALID_PARAMETER (0xC00E0006).

  • Find the corresponding OpenQueueDescriptor ADM element instance by comparing the phContext parameter with the Handle ADM attribute for all OpenQueueDescriptor ADM element instances maintained by the local QueueManager ADM element instance.

  • If not found, return a failure HRESULT, and perform no further actions; otherwise, assign the found OpenQueueDescriptor ADM element instance to the local variable queueDesc.

  • If the hCursor parameter is a nonzero value, find the corresponding Cursor ADM element instance by comparing the hCursor parameter with the Handle ADM attribute for all Cursor ADM element instances maintained by the local QueueManager ADM element instance. If not found, or the Cursor ADM element instance has previously been closed by a call to the R_CloseCursor method, return STATUS_INVALID_HANDLE (0xC0000008); otherwise, assign the found Cursor ADM element instance to the local variable localCursor.

  • If the ulAction parameter is MQ_ACTION_RECEIVE, perform the following steps:

    • Create a new PendingRequestEntry (section 3.1.1.2) ADM element instance with:

      • The RequestId ADM attribute set to the dwRequestId parameter.

      • The QueueContextHandle ADM attribute set to the phContext parameter.

      • The LookupIdentifier ADM attribute set to zero.

      • The TimeStamp ADM attribute set to the current system time, in milliseconds, since the operating system was started.

    • The server MUST create a new instance of the Pending Request Cleanup Timer (section 3.1.2.2) associated with the new PendingRequestEntry ADM element instance and MUST start it.

    • Add the new PendingRequestEntry ADM element instance to the PendingRequestTable (section 3.1.1.3) ADM element.

    • Generate a Dequeue Message Begin ([MS-MQDMPR] section 3.1.7.1.11) event with the following inputs:

      • iQueueDesc := queueDesc

      • iTimeout := ulTimeout

      • iCursor := localCursor only if the hCursor parameter is a nonzero value

      • iTag := dwRequestId

    • If the rStatus value returned from the Dequeue Message Begin event is MQ_OK (0x00000000), the server MUST set the LookupIdentifier ADM attribute of the new PendingRequestEntry ADM element instance to rMessage.LookupIdentifier.

  • If the ulAction parameter is MQ_ACTION_PEEK_CURRENT, generate a Peek Message ([MS-MQDMPR] section 3.1.7.1.15) event with the following inputs:

    • iQueueDesc := queueDesc

    • iTimeout := ulTimeout

    • iCursor := localCursor only if the hCursor parameter is a nonzero value

  • If the ulAction parameter is MQ_ACTION_PEEK_NEXT, generate a Peek Next Message ([MS-MQDMPR] section 3.1.7.1.14) event with the following inputs:

    • iQueueDesc := queueDesc

    • iTimeout := ulTimeout

    • iCursor := localCursor

  • If the ulAction parameter is MQ_LOOKUP_PEEK_CURRENT, generate a Read Message By Lookup Identifier ([MS-MQDMPR] section 3.1.7.1.13) event with the following inputs:

    • iQueueDesc := queueDesc

    • iLookupId := LookupId

    • iPeekOperation := True

    • iLookupOperation := MessageSeekAction.SeekCurrent

  • If the ulAction parameter is MQ_LOOKUP_PEEK_NEXT, generate a Read Message By Lookup Identifier event with the following inputs:

    • iQueueDesc := queueDesc

    • iLookupId := LookupId

    • iPeekOperation := True

    • iLookupOperation := MessageSeekAction.SeekNext

  • If the ulAction parameter is MQ_LOOKUP_PEEK_PREV, generate a Read Message By Lookup Identifier event with the following inputs:

    • iQueueDesc := queueDesc

    • iLookupId := LookupId

    • iPeekOperation := True

    • iLookupOperation := MessageSeekAction.SeekPrev

  • If the ulAction parameter is MQ_LOOKUP_RECEIVE_CURRENT, generate a Read Message By Lookup Identifier event with the following inputs:

    • iQueueDesc := queueDesc

    • iLookupId := LookupId

    • iPeekOperation := False

    • iLookupOperation := MessageSeekAction.SeekCurrent

    • iTwoPhaseRead := True

  • If the ulAction parameter is MQ_LOOKUP_RECEIVE_NEXT, generate a Read Message By Lookup Identifier event with the following inputs:

    • iQueueDesc := queueDesc

    • iLookupId := LookupId

    • iPeekOperation := False

    • iLookupOperation := MessageSeekAction.SeekNext

    • iTwoPhaseRead := True

  • If the ulAction parameter is MQ_LOOKUP_RECEIVE_PREV, generate a Read Message By Lookup Identifier event with the following inputs:

    • iQueueDesc := queueDesc

    • iLookupId := LookupId

    • iPeekOperation := False

    • iLookupOperation := MessageSeekAction.SeekPrev

    • iTwoPhaseRead := True

If the rStatus value returned from the preceding events is MQ_OK (Ox00000000), the server MUST:

  • Use rMessage to fill the ppPacketSections array as specified in the ppPacketSections parameter description. If the ulAction type, as defined in the table under the ulAction parameter, is Receive, the server MUST do the following:

  • Set the pdwArriveTime parameter to rMessage.ArrivalTime.

Return rStatus.