MSMQ - C++ or COM?
Asked Answered
P

1

6

I need to start writing some MSMQ code that will interface with WCF code on other machines. Does someone with MSMQ experience make recommendations about pros and cons of MSMQ using straight C++ versus using COM?

Paella answered 23/12, 2010 at 17:11 Comment(2)
By straight C++ you mean WinAPI?Dickie
Well, not in the sense of being just windows.h. All the examples on msdn have two versions: using C++ and using COM, Follow any of the topic links on msdn.com/en-us/library/ms705205(v=VS.85).aspx and there are C++ examples and COM examples. The C++ examples use an mq.h header.Paella
D
10

Actually you don't have to decide. You can combine.

Here is a code sample for a full send/recv implementation.

Just let me know if you improved it...

h file:

#pragma once

#include <tchar.h>

// ==========================================================================
// MSMQWrapper - wrappes the COM object used to send and receive messages through the MSMQ
class CMSMQWrapper
{
    HANDLE m_hQ;

public:
    CMSMQWrapper()
    {
        m_hQ= INVALID_HANDLE_VALUE;
        ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    }

    ~CMSMQWrapper()
    {
        ::CoUninitialize();
    }

    bool InitLocalQueue (const WCHAR* wczQueueName     ); // [i] .\private$\queue_name
    bool InitDestQueue  (const WCHAR* wczDestQueueName ); // [i] comp_name\private$\queue_name

    bool ReadQueue      (const WCHAR* wczQueueName    ,   // [i]
                               BYTE*  pBuf            ,   // [i]
                               size_t nBufLen         ,   // [i]
                               int&   nBytesRead       ); // [o]

    bool SendToDestQueue(const BYTE*  pBuf            ,
                               size_t nBufLen          );
};

cpp file:

#include "stdafx.h"
#include "msmqwrap.h"

#include <windows.h>
#include <AtlBase.h>
#import "mqoa.dll" named_guids // no_namespace

#pragma comment (lib, "Mqrt.lib")
#include "mq.h"

using namespace MSMQ;

// ==========================================================================
// CMSMQWrapper
// ==========================================================================

bool CMSMQWrapper::InitLocalQueue(const WCHAR* wczQueueName)
{
    CComQIPtr<IMSMQQueueInfo, &IID_IMSMQQueueInfo> ipQueueInfo;

    HRESULT hr= ::CoCreateInstance(CLSID_MSMQQueueInfo     ,
                                   NULL                    ,
                                   CLSCTX_SERVER           ,
                                   IID_IMSMQQueueInfo      ,
                                   (void**)(&ipQueueInfo.p) );
    if (S_OK != hr)
        return false;

    hr= ipQueueInfo->put_PathName(_bstr_t(wczQueueName));
    if (S_OK != hr)
        return false;

    hr= ipQueueInfo->put_Label(_bstr_t(wczQueueName));
    if (S_OK != hr)
        return false;

    VARIANT vtFalse;
    VariantInit(&vtFalse);
    vtFalse.vt     = VT_BOOL;
    vtFalse.boolVal= FALSE  ;

    try
    {
        hr= ipQueueInfo->Create(&vtFalse, &vtFalse);
    }
    catch (_com_error& er)
    { 
        if (MQ_ERROR_QUEUE_EXISTS == er.Error()) // queue already exists
            hr= S_OK;
        else
        {
            // report error - Failed receiving, (WCHAR*)er.Description()
            return false;
        }
    }

    return true;
}

// --------------------------------------------------------------------------
bool CMSMQWrapper::ReadQueue(const WCHAR* wczQueueName,  // [i]
                             BYTE*        pBuf        ,  // [i]
                             size_t       nBufLen     ,  // [i]
                             int&         nBytesRead   ) // [o]
{
    // set value of ReceiveTimout parameter
    _variant_t vtReceiveTimeout;
    vtReceiveTimeout= (long)INFINITE;

    try
    {
        IMSMQQueueInfoPtr qinfo("MSMQ.MSMQQueueInfo");
        qinfo->PathName= wczQueueName;

        IMSMQQueuePtr qRec;
        qRec= qinfo->Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE); // open queue to retrieve message

        // retrieve messages from queue
        IMSMQMessagePtr msgRec("MSMQ.MSMQMessage");
        msgRec= qRec->Receive(&vtMissing, &vtMissing, &vtMissing, &vtReceiveTimeout);
        if (NULL == msgRec)
        {
            nBytesRead= 0; // there are no messages in the queue
            return true;
        }

        nBytesRead           = msgRec->BodyLength;
        _variant_t recVariant= msgRec->Body      ;

        // close queue
        qRec->Close();

        SAFEARRAY* psa= recVariant.parray;
        nBytesRead    = __min(psa->rgsabound->cElements, nBufLen);

        for (LONG ind= 0; ind< nBytesRead; ind++)
            SafeArrayGetElement(psa, &ind, &pBuf[ind]);

        return true;
    }
    catch (_com_error comerr)
    {
        // report error - failed receiving, (WCHAR*)comerr.Description());
        return false;
    }
}

// --------------------------------------------------------------------------
bool CMSMQWrapper::InitDestQueue(const WCHAR* wczDestQueueName) // comp_name\private$\queue_name
{
    // validate the input strings
    if (NULL == wczDestQueueName)
        return false;

    // create a direct format name for the queue
    WCHAR wczFormatName[1000];
    str_cat(wczFormatName, 1000, L"DIRECT=OS:", wczDestQueueName);

    HRESULT hr;
    hr = ::MQOpenQueue(wczFormatName, MQ_SEND_ACCESS, MQ_DENY_NONE, &m_hQ);
    if (MQ_OK != hr) //MQ_ERROR_QUEUE_NOT_FOUND
        return false;

    return true;
}

// --------------------------------------------------------------------------
bool CMSMQWrapper::SendToDestQueue(const BYTE* pBuf, size_t nBufLen)
{
    MQMSGPROPS  MsgProps         ;
    const UINT  _nProps= 1       ;
    MSGPROPID   aPropId [_nProps];
    PROPVARIANT aVariant[_nProps];

    aPropId [0]            = PROPID_M_BODY   ; // msg to send
    aVariant[0].vt         = VT_VECTOR|VT_UI1;
    aVariant[0].caub.pElems= (BYTE*)pBuf     ;
    aVariant[0].caub.cElems= nBufLen         ;

    MsgProps.cProp         = _nProps         ; // number of props to set
    MsgProps.aPropID       = aPropId         ;
    MsgProps.aPropVar      = aVariant        ;
    MsgProps.aStatus       = 0               ;

    if (MQ_OK != ::MQSendMessage(m_hQ, &MsgProps, MQ_NO_TRANSACTION))
        return false;

    return true;
}
Dickie answered 23/12, 2010 at 18:49 Comment(1)
where's mqoa.dll? and mqoa.tlhOddfellow

© 2022 - 2024 — McMap. All rights reserved.