⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atlmq.h

📁 Visual C++.net编成指南一书的源代码
💻 H
📖 第 1 页 / 共 2 页
字号:
// This is a part of the Active Template Library.
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// This source code is only intended as a supplement to the
// Active Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Active Template Library product.

#ifndef __ATLMQ_H__
#define __ATLMQ_H__

#pragma once

#include <atlbase.h>
#include <mq.h>                             // MSMQ header file
#include <atlcoll.h>

namespace ATL {

#ifndef _ATL_NO_DEFAULT_LIBS
#pragma comment(lib, "mqrt.lib")			// import lib for MSMQ runtime
#endif  // !_ATL_NO_DEFAULT_LIBS

// class CMQPropertyHolder
// Base class for variable MSMQ property structures
// PropT is the base MSMQ structure to derive from
// example: MQMSGPROPS
// Note, this class does NOT free any of the pointer
// values embedded in MQPROPVARIANTs contained
// in m_rgProps
template <class PropT>
class CMQPropertyHolder : public PropT
{
protected:

public:
	CSimpleArray<PROPID> m_rgIds;			// array of property ids
	CSimpleArray<MQPROPVARIANT, CSimpleArrayEqualHelperFalse<MQPROPVARIANT> > m_rgProps;	// array of MQPROPVARIANT property values
	CSimpleArray<HRESULT> m_rgStatus;		// array of HRESULT property status values

	// constructor
	CMQPropertyHolder() throw()
	{
		cProp = 0;
		aPropID = 0;
		aPropVar = NULL;
		aStatus = NULL;
	}


	int Add(PROPID msgPropId, VARTYPE vt, void *pData = NULL, int nElems=0, int nElemSize=0) throw()
	{
		MQPROPVARIANT propVar;
		propVar.vt = vt;
		return Add(msgPropId, &propVar, pData, nElems, nElemSize);
	}


	int Add(PROPID msgPropId, MQPROPVARIANT *pPropVar, void *pData = NULL, int nElems=0, int nElemSize=0) throw()
	{
		ATLASSERT(pPropVar);

		DWORD dw = msgPropId;
		if (!m_rgIds.Add(dw))
			return -1;

		if (!m_rgProps.Add(*pPropVar))
			return -1;
		int nIndex = m_rgProps.GetSize()-1;

#ifdef _DEBUG
		if (pPropVar->vt & VT_VECTOR)
		{
			ATLASSERT(nElemSize != 0);
			ATLASSERT(pData != NULL);
			ATLASSERT(nElems != 0);
		}
		else if (pPropVar->vt == VT_BSTR ||
			pPropVar->vt == VT_CLSID ||
			pPropVar->vt == VT_BLOB ||
			pPropVar->vt == VT_LPSTR ||
			pPropVar->vt == VT_LPWSTR)
		{
			ATLASSERT(pData != NULL);
		}
#endif

		if (pData)
		{
			if (nElemSize)
			{
				m_rgProps[m_rgProps.GetSize()-1].caub.cElems = nElems;
				m_rgProps[m_rgProps.GetSize()-1].caub.pElems = (BYTE*) pData;
			}
			else
				m_rgProps[m_rgProps.GetSize()-1].pwszVal = (WCHAR *) pData;
		}
		HRESULT hr = S_OK;
		if (!m_rgStatus.Add(hr))
			return -1;
		cProp++;
		aPropID = m_rgIds.GetData();
		aPropVar = m_rgProps.GetData();
		aStatus = m_rgStatus.GetData();
		
		return nIndex;
	}

	MQPROPVARIANT &GetProperty(int nIndex) throw()
	{
		return m_rgProps[nIndex];
	}

	int FindProperty(PROPID propId) throw()
	{
		int nSize = m_rgIds.GetSize();
		for (int i=0; i<nSize; i++)
		{
			if (m_rgIds[i]==propId)
				return i;
		}
		return -1;
	}
};

// s_MQMsgPropTypes is a map between MSMQ message property
// id to the type of the property
// the type can be retrieved by using s_MQMsgPropTypes[propId-PROPID_M_BASE]
extern "C" const __declspec(selectany) VARTYPE s_MQMsgPropTypes[] = 
{
	/*PROPID_M_BASE*/ VT_NULL,
	/*PROPID_M_CLASS*/ VT_UI2,
	/*PROPID_M_MSGID*/ VT_UI1|VT_VECTOR,
	/*PROPID_M_CORRELATIONID*/VT_UI1|VT_VECTOR,
	/*PROPID_M_PRIORITY*/ VT_UI1,
	/*PROPID_M_DELIVERY*/ VT_UI1,
	/*PROPID_M_ACKNOWLEDGE*/ VT_UI1, 
	/*PROPID_M_JOURNAL*/ VT_UI1,
	/*PROPID_M_APPSPECIFIC*/ VT_UI4,
	/*PROPID_M_BODY*/ VT_UI1|VT_VECTOR,
	/*PROPID_M_BODY_SIZE*/ VT_UI4,
	/*PROPID_M_LABEL*/ VT_LPWSTR,
	/*PROPID_M_LABEL_LEN*/ VT_UI4,
	/*PROPID_M_TIME_TO_REACH_QUEUE*/ VT_UI4,
	/*PROPID_M_TIME_TO_BE_RECEIVED*/ VT_UI4,
	/*PROPID_M_RESP_QUEUE*/ VT_LPWSTR,
	/*PROPID_M_RESP_QUEUE_LEN*/ VT_UI4,
	/*PROPID_M_ADMIN_QUEUE*/ VT_LPWSTR,
	/*PROPID_M_ADMIN_QUEUE_LEN*/ VT_UI4,
	/*PROPID_M_VERSION*/ VT_UI4,
	/*PROPID_M_SENDERID*/ VT_UI1|VT_VECTOR,
	/*PROPID_M_SENDERID_LEN*/ VT_UI4,
	/*PROPID_M_SENDERID_TYPE*/ VT_UI4,
	/*PROPID_M_PRIV_LEVEL*/ VT_UI4,
	/*PROPID_M_AUTH_LEVEL*/ VT_UI4,
	/*PROPID_M_AUTHENTICATED*/ VT_UI1,
	/*PROPID_M_HASH_ALG*/ VT_UI4,
	/*PROPID_M_ENCRYPTION_ALG*/ VT_UI4,
	/*PROPID_M_SENDER_CERT*/ VT_UI1|VT_VECTOR,
	/*PROPID_M_SENDER_CERT_LEN*/ VT_UI4,
	/*PROPID_M_SRC_MACHINE_ID*/ VT_CLSID,
	/*PROPID_M_SENTTIME*/ VT_UI4,
	/*PROPID_M_ARRIVEDTIME*/ VT_UI4,
	/*PROPID_M_DEST_QUEUE*/ VT_LPWSTR,
	/*PROPID_M_DEST_QUEUE_LEN*/ VT_UI4,
	/*PROPID_M_EXTENSION*/ VT_UI1|VT_VECTOR,
	/*PROPID_M_EXTENSION_LEN*/ VT_UI4,
	/*PROPID_M_SECURITY_CONTEXT*/ VT_UI4,
	/*PROPID_M_CONNECTOR_TYPE*/ VT_CLSID,
	/*PROPID_M_XACT_STATUS_QUEUE*/ VT_LPWSTR,
	/*PROPID_M_XACT_STATUS_QUEUE_LEN*/ VT_UI4,
	/*PROPID_M_TRACE*/ VT_UI1,
	/*PROPID_M_BODY_TYPE*/ VT_UI4,
	/*PROPID_M_DEST_SYMM_KEY*/ VT_UI1|VT_VECTOR,
	/*PROPID_M_DEST_SYMM_KEY_LEN*/ VT_UI4,
	/*PROPID_M_SIGNATURE*/ VT_UI1|VT_VECTOR,
	/*PROPID_M_SIGNATURE_LEN*/ VT_UI4,
	/*PROPID_M_PROV_TYPE*/ VT_UI4,
	/*PROPID_M_PROV_NAME*/ VT_LPWSTR,
	/*PROPID_M_PROV_NAME_LEN*/ VT_UI4,
};


// class CMQMessageProps
// Simple class to eliminate having to pass the property
// type of message properties
class CMQMessageProps : public CMQPropertyHolder<MQMSGPROPS>
{
protected:

public:
	int Add(MSGPROPID msgPropId, void *pData = NULL, int nElems=0, int nElemSize=0) throw()
	{
		ATLASSERT(msgPropId - PROPID_M_BASE < sizeof(s_MQMsgPropTypes)/sizeof(VARTYPE));
		return CMQPropertyHolder<MQMSGPROPS>::Add(msgPropId, s_MQMsgPropTypes[msgPropId - PROPID_M_BASE], pData, nElems, nElemSize);
	}

	template <typename T>
	int AddT(MSGPROPID msgPropId, T val)
	{
		ATLASSERT(msgPropId - PROPID_M_BASE < sizeof(s_MQMsgPropTypes)/sizeof(VARTYPE));
		CMQPropVariantIn var (val);
		ATLASSERT(var.vt == s_MQMsgPropTypes[msgPropId - PROPID_M_BASE]);
		return CMQPropertyHolder<MQMSGPROPS>::Add (msgPropId, &var);
	}
};

// s_MQQueuePropTypes is a map between MSMQ queue property
// id to the type of the property
// the type can be retrieved by using s_MQQueuePropTypes[propId-PROPID_Q_BASE]
extern "C" const __declspec(selectany)  VARTYPE s_MQQueuePropTypes[] = 
{
/*PROPID_Q_BASE*/ VT_NULL,
/*PROPID_Q_INSTANCE*/ VT_CLSID,
/*PROPID_Q_TYPE*/ VT_CLSID,
/*PROPID_Q_PATHNAME*/ VT_LPWSTR,
/*PROPID_Q_JOURNAL*/ VT_UI1,
/*PROPID_Q_QUOTA*/ VT_UI4,
/*PROPID_Q_BASEPRIORITY*/ VT_I2,
/*PROPID_Q_JOURNAL_QUOTA*/ VT_UI4,
/*PROPID_Q_LABEL*/ VT_LPWSTR,
/*PROPID_Q_CREATE_TIME*/ VT_I4,
/*PROPID_Q_MODIFY_TIME*/ VT_I4,
/*PROPID_Q_AUTHENTICATE*/ VT_UI1,
/*PROPID_Q_PRIV_LEVEL*/ VT_UI4,
/*PROPID_Q_TRANSACTION*/ VT_UI1
};

// class CMQQueueProps
// Simple class to eliminate having to pass the property
// type of queue properties
// When constructing the class you have to specify
// a transfer direction.  MQ_TRANSFER_DIR_GET means
// the class is being used to retrieve properties
// from MSMQ, so some properties are dynamically
// allocated and must be freed by MSMQ.
// MQ_TRANSFER_DIR_PUT means the class is being
// used to set properties and so the properties
// are allocated and freed by the user.
// 
class CMQQueueProps : public CMQPropertyHolder<MQQUEUEPROPS>
{
protected:

public:
	enum MQ_TRANSFER_DIR { MQ_TRANSFER_DIR_INVALID, MQ_TRANSFER_DIR_GET, MQ_TRANSFER_DIR_PUT };

	MQ_TRANSFER_DIR m_nDirection;

	CMQQueueProps(MQ_TRANSFER_DIR nDirection) throw()
	{
		m_nDirection = MQ_TRANSFER_DIR_INVALID;
		SetDirection(nDirection);
	}

	void SetDirection(MQ_TRANSFER_DIR nDirection) throw()
	{
		// if we're switching from GET to PUT
		// free allocated properties now

		if (m_nDirection == MQ_TRANSFER_DIR_GET && nDirection == MQ_TRANSFER_DIR_PUT)
			FreeAllocatedProperties();
		m_nDirection = nDirection;
	}
	
	void FreeAllocatedProperties() throw()
	{
		// this function should only be called when
		// the class is being used to retrieve queue properties
		ATLASSERT(m_nDirection == MQ_TRANSFER_DIR_GET);

		for (int i=0; i<m_rgProps.GetSize(); i++)
		{
			if (m_rgIds[i] == PROPID_Q_LABEL ||
				m_rgIds[i] == PROPID_Q_PATHNAME && m_rgProps[i].pwszVal)
			{
				MQFreeMemory(m_rgProps[i].pwszVal);
				m_rgProps[i].pwszVal = NULL;
			}
		}
	}

	~CMQQueueProps() throw()
	{
		if (m_nDirection == MQ_TRANSFER_DIR_GET)
			FreeAllocatedProperties();
	}

	int Add(QUEUEPROPID queuePropId, void *pData = NULL, int nElems=0, int nElemSize=0) throw()
	{
		ATLASSERT(queuePropId - PROPID_Q_BASE < sizeof(s_MQQueuePropTypes)/sizeof(VARTYPE));
		return Add(queuePropId, s_MQQueuePropTypes[queuePropId - PROPID_Q_BASE], pData, nElems, nElemSize);
	}

	int Add(PROPID propId, VARTYPE vt, void *pData = NULL, int nElems=0, int nElemSize=0) throw()
	{
		MQPROPVARIANT propVar;
		propVar.vt = vt;
		return Add(propId, &propVar, pData, nElems, nElemSize);
	}

	int Add(PROPID propId, MQPROPVARIANT *pPropVar, void *pData = NULL, int nElems=0, int nElemSize=0) throw()
	{
		if (m_nDirection == MQ_TRANSFER_DIR_GET && 
				(propId==PROPID_Q_LABEL || propId==PROPID_Q_PATHNAME))
		{
			// special handling for these two
			// when getting properties, vt should be set to VT_NULL

			ATLASSERT(pData == NULL);	// the result will be dynamially allocated by MSMQ
			pPropVar->vt = VT_NULL;
		}
		return CMQPropertyHolder<MQQUEUEPROPS>::Add(propId, pPropVar, pData, nElems, nElemSize);
	}
};

// s_MQMachinePropTypes is a map between MSMQ machine property
// id to the type of the property
// the type can be retrieved by using s_MQMachinePropTypes[propId-PROPID_QM_BASE]
extern "C" const __declspec(selectany)  VARTYPE s_MQMachinePropTypes[] = 
{
/*PROPID_QM_BASE*/ VT_NULL,
/*PROPID_QM_SITE_ID*/ VT_CLSID,
/*PROPID_QM_MACHINE_ID*/ VT_CLSID,
/*PROPID_QM_PATHNAME*/ VT_NULL,
/*PROPID_QM_CONNECTION*/ VT_LPWSTR|VT_VECTOR,
/*PROPID_QM_ENCRYPTION_PK*/ NULL,
};

// class CMQMachineProps
// Simple class to eliminate having to pass the property
// type of machine properties
// The class frees properties that are dynamically allocated
// by MSMQ
// 
class CMQMachineProps : public CMQPropertyHolder<MQQMPROPS>
{
protected:

public:
	~CMQMachineProps() throw()
	{
		FreeAllocatedProperties();
	}

	void FreeAllocatedProperties() throw()
	{
		for (int i=0; i<m_rgProps.GetSize(); i++)
		{
			// TODO: I haven't been able to get PROPID_QM_CONNECTION and PROPID_QM_ENCRYPTION_PK
			// to work, with any VT
			// the docs seem to indicate that they should be freed, but not very
			// clear about it!
			if ((m_rgIds[i] ==  PROPID_QM_PATHNAME && m_rgProps[i].pwszVal))
			{
				MQFreeMemory(m_rgProps[i].pwszVal);
				m_rgProps[i].pwszVal = NULL;
			}
		}
	}

	int Add(QMPROPID propId, void *pData = NULL, int nElems=0, int nElemSize=0) throw()
	{
		ATLASSERT(propId - PROPID_QM_BASE < sizeof(s_MQMachinePropTypes)/sizeof(VARTYPE));
		return CMQPropertyHolder<MQQMPROPS>::Add(propId, s_MQMachinePropTypes[propId - PROPID_QM_BASE], pData, nElems, nElemSize);
	}
};


class CMQQueue;


// struct CMQOverlapped
// This is the structure that will be used
// with IoCompletion port based io
struct CMQOverlapped : public OVERLAPPED
{
	CMQMessageProps *m_pProps;	// the message props associated with the request
	CMQQueue *m_pQueue;			// the queue associated with the request
};


// class CMQQueue
// This class encapsulates MSMQ queue related methods
class CMQQueue
{
protected:
	HANDLE m_hQueue;
	WCHAR m_wszFormatName[MQ_MAX_Q_NAME_LEN+1];
	
public:
	CMQQueue() throw()
	{
		m_hQueue = NULL;
		m_wszFormatName[0] = '\0';
	}

	HANDLE GetHandle() throw()
	{
		return m_hQueue;
	}

	operator HANDLE() throw()
	{
		return m_hQueue;
	}

	BOOL SetFormatName(LPCWSTR wszFormatName) throw()
	{
		int nLen = (int) wcslen(wszFormatName);
		if (nLen == 0 || nLen > MQ_MAX_Q_NAME_LEN)
			return FALSE;
		wcscpy(m_wszFormatName, wszFormatName);
		return TRUE;
	}

	HRESULT PathNameToFormatName(LPCWSTR wszPathName) throw()
	{
		DWORD dwDestFormatLen = sizeof(m_wszFormatName)/sizeof(WCHAR);
		return MQPathNameToFormatName(wszPathName, m_wszFormatName, &dwDestFormatLen);
	}

	HRESULT Open(
		LPCWSTR wszPathName,
		DWORD dwAccessMode=MQ_RECEIVE_ACCESS,
		DWORD dwShareMode=MQ_DENY_NONE) throw()
	{
		ATLASSERT(m_hQueue == NULL);	// You should the queue, before opening another one


		HRESULT hr = PathNameToFormatName(wszPathName);
		if (FAILED(hr))
			return hr;

		return Open(dwAccessMode, dwShareMode);
	}

	// open that uses the current format name
	HRESULT Open(DWORD dwAccessMode=MQ_RECEIVE_ACCESS, DWORD dwShareMode=MQ_DENY_NONE) throw()
	{
		ATLASSERT(m_wszFormatName[0]);
		return MQOpenQueue(m_wszFormatName, dwAccessMode, dwShareMode, &m_hQueue);
	}

	HRESULT FormatNameFromHandle(LPWSTR wszFormatName, LPDWORD pdwCount) throw()
	{
		ATLASSERT(m_hQueue);
		return MQHandleToFormatName(m_hQueue,  wszFormatName,  pdwCount);
	}

	HRESULT AssociateCompletionPort(HANDLE hIoCompletion, DWORD dwNumThreads=0) throw()
	{
		ATLASSERT(m_hQueue != NULL);

		HANDLE hIoCompletionRet = CreateIoCompletionPort(m_hQueue, hIoCompletion, (ULONG_PTR) this, dwNumThreads);
		if (!hIoCompletionRet)
			return AtlHresultFromLastError();
		return S_OK;
	}


	HRESULT Receive(MQMSGPROPS *pMsgProps) throw()
	{
		ATLASSERT(m_hQueue != NULL);
		return MQReceiveMessage(m_hQueue, 0, MQ_ACTION_RECEIVE, pMsgProps, NULL, NULL, NULL, NULL);
	}

	HRESULT Peek(MQMSGPROPS *pMsgProps, HANDLE hCursor) throw()
	{
		ATLASSERT(m_hQueue != NULL);
		return MQReceiveMessage(m_hQueue, 0, MQ_ACTION_PEEK_CURRENT, pMsgProps, NULL, NULL, hCursor, NULL);
	}

	HRESULT PeekNext(MQMSGPROPS *pMsgProps, HANDLE hCursor) throw()
	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -