3.1.4.1 RemoteQMStartReceive (Opnum 0)

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

If RemoteQMStartReceive is invoked with a Peek action type, as specified in the ulAction member of the lpRemoteReadDesc parameter, the operation completes when RemoteQMStartReceive returns.

If RemoteQMStartReceive is invoked with a Receive action type, as specified in the ulAction member of the lpRemoteReadDesc parameter, the client MUST pair each call to RemoteQMStartReceive with a call to RemoteQMEndReceive to complete the operation, or to RemoteQMCancelReceive to cancel the operation.

For each call to RemoteQMCancelReceive, the dwRequestID parameter MUST match the dwRequestID member of the lpRemoteReadDesc parameter in a previous call to RemoteQMStartReceive.

If the client specifies a nonzero value for the ulTimeout member of the lpRemoteReadDesc 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 RemoteQMCancelReceive with a matching REMOTEREADDESC.dwRequestID to cancel the pending RemoteQMStartReceive request.

Before calling this method, the client MUST have already called RemoteQMOpenQueue.

 HRESULT RemoteQMStartReceive(
   [in] handle_t hBind,
   [out] PCTX_REMOTEREAD_HANDLE_TYPE* pphContext,
   [in, out] REMOTEREADDESC* lpRemoteReadDesc
 );

hBind: An RPC binding handle parameter, as specified in [MS-RPCE] section 2, that MUST be specified.

pphContext: The server MUST return a non-NULL value for this handle upon success for receive calls. This handle will be used by the client in subsequent calls to RemoteQMEndReceive. This handle MUST NOT be set upon failure, or for peek calls. If this method returns an error, pphContext is undefined and MUST NOT be used as an argument for a call to RemoteQMEndReceive.

lpRemoteReadDesc: A pointer to an instance of a REMOTEREADDESC (section 2.2.2.1) structure.

In addition, the ulAction member of the lpRemoteReadDesc parameter MUST be one of the following values.

Value of ulAction

Meaning

MQ_ACTION_RECEIVE

0x00000000

If hCursor is nonzero, read and remove the first message available at the current cursor's location walking towards the end of the queue.

If hCursor is zero, read and remove the message from the front of the queue.

MQ_ACTION_PEEK_CURRENT

0x80000000

If hCursor is nonzero, read the message at the current cursor location, but do not remove it from the queue. The cursor location does not change after the operation.

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

MQ_ACTION_PEEK_NEXT

0x80000001

Read the message following the message at the current cursor location, but do not remove it. The cursor location will then change to the next available message, walking towards the end of the queue.

The hCursor parameter MUST be set to a nonzero cursor handle.

The hCursor member of lpRemoteReadDesc specifies a handle to an opened cursor. A value of zero indicates that a cursor is not used for this operation.

The dwRequestID member of the lpRemoteReadDesc parameter is used in a subsequent call to RemoteQMCancelReceive to correlate that call with the call to RemoteQMStartReceive.

Return Values: The method MUST return MQ_OK (0x00000000) on success; otherwise, it MUST return a failure HRESULT, and the client MUST treat all failure HRESULTs identically.

MQ_OK (0x00000000)

MQ_ERROR_INVALID_HANDLE (0xC00E0007)

MQ_ERROR_INVALID_PARAMETER (0xC00E0006)

STATUS_INVALID_PARAMETER (0xC000000D)

Exceptions Thrown: None except those thrown by the underlying RPC protocol, as specified in [MS-RPCE].

While processing this method, the server MUST:

  • Return MQ_ERROR_INVALID_HANDLE (0xC00E0007) if lpRemoteReadDesc is NULL.

  • Return MQ_ERROR_INVALID_PARAMETER (0xC00E0006) if lpRemoteReadDesc.dwQueue is set to 0x00000000 or lpRemoteReadDesc.dwQueue is not equal to  lpRemoteReadDesc.hRemoteQueue.

  • The server SHOULD return MQ_ERROR_INVALID_PARAMETER (0xC00E0006) if the  lpRemoteReadDesc.dwRequestID does not uniquely identify the receive request. This duplicate detection is performed by searching for a RemoteReadEntry (section 3.1.1.2) ADM element instance, referred to as rRemoteReadEntry, in rRemoteReadEntryCollection such that rRemoteReadEntry.OpenQueueDescriptorHandlelpRemoteReadDesc.hRemoteQueue and rRemoteReadEntry.RequestId = lpRemoteReadDesc.dwRequestID.<10>

  • Return STATUS_INVALID_PARAMETER (0xC000000D) if lpRemoteReadDesc.hCursor is set to 0x00000000 and the  lpRemoteReadDesc.ulAction is set to MQ_ACTION_PEEK_NEXT.

  • Search the rOpenQueueEntryCollection where OpenQueueEntry.OpenQueueDescriptorHandle = lpRemoteReadDesc.hRemoteQueue.

  • If the OpenQueueDescriptorHandle is not found, return MQ_ERROR_INVALID_PARAMETER (0xc00e0006).

  • Find the OpenQueueDescriptor, referred to as rOpenQueueDescriptor, in the Queue.OpenQueueDescriptorCollection of each queue object in QueueManager.QueueCollection such that rOpenQueueDescriptor.Handle = lpRemoteReadDesc.hRemoteQueue.

  • If  lpRemoteReadDesc.hCursor is not 0x00000000, find the cursor object, referred to as rCursor, in the rOpenQueueDescriptor.CursorCollection with a Handle property equal to  lpRemoteReadDesc.hCursor.

  • If no cursor object is found, return STATUS_INVALID_PARAMETER.

  • If lpRemoteReadDesc.hCursor is 0x00000000, set rCursor to NULL.

  • Create a new RemoteReadEntry ADM element instance, referred to as rrEntry, with the following attributes:

    • OpenQueueDescriptorHandlelpRemoteReadDesc.hRemoteQueue

    • Timeout = lpRemoteReadDesc.ulTimeout

    • UserMessagePacket = lpRemoteReadDesc.lpBuffer

    • Action = lpRemoteReadDesc.ulAction

    • RequestId = lpRemoteReadDesc.dwRequestID

  • Add rrEntry to rRemoteReadEntryCollection.

  • If the ulAction member of the lpRemoteReadDesc parameter is MQ_ACTION_RECEIVE, generate a Dequeue Message Begin event ([MS-MQDMPR] section 3.1.7.1.11) with the following inputs:

    • iQueueDesc := reference to OpenQueueDescriptor obtained earlier.

    • iTimeout := lpRemoteReadDesc.ulTimeout

    • iTag := lpRemoteReadDesc.dwRequestID

    • iCursor := rCursor

  • If the ulAction member of the lpRemoteReadDesc parameter is MQ_ACTION_PEEK_CURRENT, generate a Peek Message event with the following inputs:

    • iQueueDesc := reference to OpenQueueDescriptor obtained earlier.

    • iTimeout := lpRemoteReadDesc.ulTimeout

    • iCursor := rCursor

  • If the ulAction member of the lpRemoteReadDesc parameter is MQ_ACTION_PEEK_NEXT, generate a Peek Next Message event with the following inputs:

    • iQueueDesc := reference to OpenQueueDescriptor obtained earlier.

    • iTimeout := lpRemoteReadDesc.ulTimeout

    • iCursor := rCursor

  • If the rStatus value returned from the preceding events is MQ_OK (0x00000000), the server MUST process the returned rMessage as follows:

    • Generate a Construct a UserMessage Packet ([MS-MQDMPR] section 3.1.7.1.30) event with the following argument:

      • iMessage := rMessage

    • Generate a Serialize Message to Buffer ([MS-MQDMPR] section 3.1.7.1.32) event with the following arguments:

      • iMessage := rMessage

      • iBuffer := rUserMessage returned by the Construct a UserMessage Packet event.

    • Assign rUserMessage to the lpBuffer member of the lpRemoteReadDesc parameter.

    • Assign rUserMessage.BaseHeader.PacketSize to lpRemoteReadDesc.dwSize.

  • Remove the RemoteReadEntry ADM element instance from rRemoteReadEntryCollection for which RemoteReadEntry.RequestId equals lpRemoteReadDesc.dwRequestID and RemoteReadEntry.OpenQueueDescriptorHandle equals lpRemoteReadDesc.hRemoteQueue.

  • If rStatus is MQ_OK (0x00000000) and lpRemoteReadDesc.ulAction is MQ_ACTION_RECEIVE, set pphContext to rrEntry; otherwise, delete rrEntry.

  • Return rStatus.