The two most important components in the MSMQ set are MSMQMessage
and MSMQQueue
. Unsurprisingly, the former represents a message, whilst the latter represents a queue. As it happens though, you never actually instantiate a MSMQQueue
component; to do this, you need to use one of the methods of the MSMQQueueInfo
interface. The MSMQQueueInfo
is a component that describes the static aspects of a queue, whereas the MSMQQueue
component describes the dynamic aspects of it.
You can instantiate your own MSMQQueueInfo
object, or you can get one by enumerating through a list by using a MSMQQueueInfos
object. You can’t, however, instantiate a MSMQQueueInfos
object: the only way to get hold of one of these is by using the LookupQueue()
method of a MSMQQuery
object.
Confused? Don’t worry — it’s a lot more straightforward in practice. Let’s put together our SimpleMail
application. We’ll start off by including the MSMQ header file at the top of the SimpleMailDlg.h
file and — because we'll be using the Visual C++ compiler COM support classes — setting up a few smart pointer typedef
s for the interfaces that we'll be using. (The MSMQ library and header files can be found in the sdk
folder of your MSMQ installation directory):
#include <comdef.h> // Compiler COM support classes
#define SMARTPTR_TYPEDEF(x) \
typedef _com_ptr_t<_com_IIID<x, &IID_##x> > x##Ptr;
#include <mqoai.h> // MSMQ interfaces/GUIDs
SMARTPTR_TYPEDEF(IMSMQQueueInfos);
SMARTPTR_TYPEDEF(IMSMQQueueInfo);
SMARTPTR_TYPEDEF(IMSMQQueue);
SMARTPTR_TYPEDEF(IMSMQQuery);
SMARTPTR_TYPEDEF(IMSMQMessage);
To get the full definitions of the GUIDs from mqoai.h
, we'll also need to #include
this file in StdAfx.cpp
after including initguid.h
.
// Get the definitions of the MSMQ GUIDs (to avoid linker errors)
#include <initguid.h>
#include <mqoai.h>
The first change that we make is at the end of OnInitDialog()
:
SetIcon(m_hIcon, FALSE); // Set small icon
// Make sure COM has been initialized in CSimpleMailApp::InitInstance()
// with a call to AfxOleInit()
ShowQueues();
OnRefresh();
return TRUE; // return TRUE unless you set the focus to a control
}
Let’s take a look at that ShowQueues()
function; this is the piece of code that populates the three combo boxes that contain lists of the available queues.
void CSimpleMailDlg::ShowQueues()
{
// Create query
IMSMQQueryPtr pQuery;
HRESULT hr = pQuery.CreateInstance(CLSID_MSMQQuery, NULL, CLSCTX_SERVER);
if (FAILED(hr))
{
DisplayComError(_T("Failed to create message query"), hr);
return;
}
// Get information on all queues
VARIANT vEmpty;
vEmpty.vt = VT_ERROR;
IMSMQQueueInfosPtr pInfos;
hr = pQuery->LookupQueue(&vEmpty, &vEmpty, &vEmpty, &vEmpty, &vEmpty,
&vEmpty, &vEmpty, &vEmpty, &vEmpty, &pInfos);
if (FAILED(hr))
{
DisplayComError(_T("Failed to look up queues"), hr);
return;
}
pInfos->Reset();
CComboBox* pOutgoing = ComboPtr(IDC_OUTGOING); // ComboPtr() returns
CComboBox* pIncoming = ComboPtr(IDC_INCOMING); // a CComboBox* when given
CComboBox* pAdmin = ComboPtr(IDC_ADMIN); // a resource ID
pOutgoing->ResetContent();
pIncoming->ResetContent();
pAdmin->ResetContent();
// Loop through queues, extracting path names
while (1)
{
IMSMQQueueInfoPtr pInfo;
pInfos->Next(&pInfo);
if (pInfo == NULL)
break;
BSTR bstrQueue;
pInfo->get_PathName(&bstrQueue);
CString csQueue = bstrQueue;
SysFreeString(bstrQueue);
pOutgoing->AddString(csQueue);
pIncoming->AddString(csQueue);
pAdmin->AddString(csQueue);
}
pOutgoing->SetCurSel(0);
pIncoming->SetCurSel(0);
pAdmin->SetCurSel(0);
}
OK, that’s how we get a list of the pathnames of all the available queues; how do we actually send a message to one of them?