Sending a Message

Here’s the code that gets triggered when the user hits the Send button:

void CSimpleMailDlg::OnSend() 
{
   // Open up the outgoing queue
   IMSMQQueuePtr pQueue = OpenQueue(IDC_OUTGOING, MQ_SEND_ACCESS);
   if (pQueue == NULL)
      return;

   // Create message and populate label and body
   IMSMQMessagePtr pMessage;
   HRESULT hr = pMessage.CreateInstance(CLSID_MSMQMessage, NULL,
                                        CLSCTX_SERVER);
   if (FAILED(hr))
   {
      DisplayComError(_T("Failed to create message"), hr);
      return;
   }

   pMessage->put_Label(GetDlgItemBSTR(IDC_TITLE));

   CString csText;
   GetDlgItemText(IDC_TEXT, csText);
   pMessage->put_Body(_variant_t(csText));

   // Set journal flag
   int journal = MQMSG_JOURNAL_NONE;

   if (GetDlgItemCheck(IDC_DEADLETTER))
      journal += MQMSG_DEADLETTER;

   if (GetDlgItemCheck(IDC_JOURNAL))
      journal += MQMSG_JOURNAL;

   pMessage->put_Journal(journal);

   // Set up acknowledgement flag
   int ack = MQMSG_ACKNOWLEDGMENT_NONE;

   if (GetDlgItemCheck(IDC_FULLREACH))
      ack |= MQMSG_ACKNOWLEDGMENT_FULL_REACH_QUEUE;

   if (GetDlgItemCheck(IDC_NAKREACH))
      ack |= MQMSG_ACKNOWLEDGMENT_NACK_REACH_QUEUE;

   if (GetDlgItemCheck(IDC_FULLRECV))
      ack |= MQMSG_ACKNOWLEDGMENT_FULL_RECEIVE;

   if (GetDlgItemCheck(IDC_NAKRECV))
      ack |= MQMSG_ACKNOWLEDGMENT_NACK_RECEIVE;

   pMessage->put_Ack(ack);

   // Set up timeouts for reaching queue and message receipt
   int timeout = GetDlgItemInt(IDC_REACHTIME);
   if (timeout)
      pMessage->put_MaxTimeToReachQueue(timeout);
   timeout = GetDlgItemInt(IDC_RECVTIME);
   if (timeout)
      pMessage->put_MaxTimeToReceive(timeout);

   // Define administration queue
   IMSMQQueueInfoPtr pInfo = GetInfoPtr(IDC_ADMIN);
   if (pInfo)
   {
      pInfo->Refresh();
      hr = pMessage->putref_AdminQueueInfo(pInfo);
   }

   // Send message
   hr = pMessage->Send(pQueue, &_variant_t());
   if (FAILED(hr))
   {
      DisplayComError(_T("Failed to send message"), hr);
      return;
   }
}

As you can see, sending a message is largely a question of creating the message object, populating whichever properties you want and then invoking the Send() method, specifying the queue you want to send the message to. One small item worth mentioning is that call to Refresh() on the administration queue MSMQQueueInfo object. We need this because we’ve instantiated the object, and set up the pathname (which is enough to identify it uniquely). However, we haven’t filled in the rest of the object. That’s what the call to Refresh() does.

Notice all those different options for returning an acknowledgement to us? If the MQMSG_ACKNOWLEDGMENT_FULL_XXX version is selected, we get told whatever happened. If only the MQMSG_ACKNOWLEDGMENT_NACK_XXX version is selected, we only get told if something goes wrong.

The work of actually opening up the queue is done by a helper function. Here it is :

IMSMQQueuePtr CSimpleMailDlg::OpenQueue(int nID, int mode)
{
   // Open queue specified in field
   IMSMQQueueInfoPtr pInfo = GetInfoPtr(nID);
   if (pInfo == NULL)
      return NULL;

   IMSMQQueuePtr pQueue;
   HRESULT hr = pInfo->Open(mode, NULL, &pQueue);
   if (FAILED(hr))
   {
      DisplayComError(_T("Failed to open message queue"), hr);
      return NULL;
   }

   return pQueue;
}

Notice that we don’t open the queue directly; we use a QueueInfo object to get to it. This is the helper function that sets that up:

IMSMQQueueInfoPtr CSimpleMailDlg::GetInfoPtr(int nID)
{
   // Set up info object based on specified field
   IMSMQQueueInfoPtr pInfo;
   HRESULT hr = pInfo.CreateInstance(CLSID_MSMQQueueInfo, NULL,
                                     CLSCTX_SERVER);
   if (FAILED(hr))
   {
      DisplayComError(_T("Failed to create message queue info"), hr);
      return NULL;
   }

   pInfo->put_PathName(GetDlgItemBSTR(nID));
   return pInfo;
}

 

Notice that the only information necessary to specify the queue is its pathname — remember that this was unique? We get the pathname using another helper that we've created, GetDlgItemBSTR(), which works just like GetDlgItemText() except it returns a _bstr_t object.

We actually have three options available for opening a queue: sending, receiving or peeking. The last two are pretty similar, except that when you open a queue for peeking, you can’t actually remove a message from it — we’ll look at the peeking operation in a minute. We’ve already seen the sending operation in the OnSend() function above.

Once we’ve invoked the Send() method on the MSMQMessage object, it’s up to MSMQ to handle the delivery of the message. It’s out of our hands.

© 1998 by Wrox Press. All rights reserved.