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.