Microsoft Message Queuing介绍

http://msdn2.microsoft.com/en-us/library/ms711472.aspx

1目的

Message Queuing (MSMQ) 消息队列技术可以实现应用系统间的网络数据传输。应用程序可以发送消息给队列,或从队列中读取消息。

Microsoft Message Queuing介绍_第1张图片

消息队列保证消息的传递,路由和安全。它可以实现高性能的异步数据传输。

Message Queuing应用程序可以使用C++ API或者COM对象。最新版MSMQ 3.0可安装到Windows XP ProfessionalWindows Server 2003 family

 

2.队

队列是一种逻辑容器,可被用来保存和转发消息。应用程序可以创建一个队列,指定一个已有队列,打开一个队列,发送消息给队列,也可以从队列中读取消息, 设置,获取队列属性。

目标队列是一种消息队列。用来保存消息。目标队列被设置在服务器中,客户端程序发送消息给服务器计算机的目标队列,服务器程序则可以接收消息。

2.1 列路径名

队列路径名提供创建消息队列的信息。队列路径名指定了消息将要保存到队列的计算机名。要创建一个队列,必须要指定队列路径名。

2.2 队列查询

查询一个队列时,可以通过directory service

Microsoft Message Queuing介绍_第2张图片

消息队列提供了两个结构体来设置查询条件MQPROPERTYRESTRICTION MQRESTRICTION.

 

2.3 消息体类型

VT_I11个字符(1 byte)

VT_I2short integer.

VT_I4long integer.

VT_R4A float (4-byte floating point).

VT_R8A double-float (8-byte floating point).

VT_CYA CURRENCY type (8-byte).

VT_DATEAn OLE DATE (8-byte) type.

VT_BSTRUnicode的字符串

VT_ARRAY | VT_UI11bytes.

2.4 Format名称

              Format名称提供了需要打开队列的信息。Format名称是在队列被创建时生成的唯一名称。获得Format名称的方法是:

1.当创建队列,会返回一个Format名称。

2.当查询一个队列时,应用程序可以使用API函数获得队列路径名或者队列标识(GUID).,然后可以通过MQPathNameToFormatNameMQInstanceToFormatName把它们转换为format名称。

3.实例

开发消息队列应用程序之前保证:

l         已经部署了消息队列。

l         应用程序已经引用了相应的头文件和mqrt.lib库。

3.1创建一个队列

1. 定一个MQQUEUEPROPS结构体;

2. 设置队列属性PROPID_Q_PATHNAME

3. 初始化MQQUEUEPROPS结构体;

4. 调用MQCreateQueue创建队列。

参考4.1 代码实现

3.2 寻找一个队列

1. 指定寻找条件,使用查询结构体MQPROPERTYRESTRICTION MQRESTRICTION.

2. 使用MQCOLUMNSET指定队列的属性;

3. 调用MQLocateBegin开始查询;

4. 循环中调用MQLocateNext查找下一个;

5. 调用MQLocateEnd释放资源。

参考4.2 代码实现

3.3 打开队列

1.获得队列的Format名;

2.调用MQOpenQueue

3.返回队列句柄。

参考4.3 代码实现。

3.4 读取消息

读取消息有两种,1是同步读取,2时异步读取

同步读取消息时

1.定义队列属性最大值;

2.定义MQMSGPROPS结构体;

3.指定消息属性。如LABELLABEL长度,BODYBODY长度,和BODY类型;

4.实例化MQMSGPROPS结构体;

5.创建队列的format名称;

6.调用MQOpenQueue打开队列;

7.循环调用MQReceiveMessage

8.调用MQCloseQueue释放资源。

参考4.4代码实现

3.5 发送消息

              发送消息时:

1. 定义需要的常量和变量;

2. 定义MQMSGPROPS结构体;

3. 指定消息属性,例如LABEL

4. 初始化MQMSGPROPS结构体;

5. 创建format名称打开队列;

6. 调用MQSendMessage发送消息;

7. 调用MQCloseQueue关闭资源。

参考4.5代码实现


4.代码实现

 

4.1建一个

HRESULT CreateMSMQQueue(

                        LPWSTR wszPathName,

                        PSECURITY_DESCRIPTOR pSecurityDescriptor,

                        LPWSTR wszOutFormatName,

                        DWORD *pdwOutFormatNameLength

                        )

{

 

  // 定义队列最大属性.

  const int NUMBEROFPROPERTIES = 2;

 

 

  // 定义属性

  MQQUEUEPROPS   QueueProps;

  MQPROPVARIANT  aQueuePropVar[NUMBEROFPROPERTIES];

  QUEUEPROPID    aQueuePropId[NUMBEROFPROPERTIES];

  HRESULT        aQueueStatus[NUMBEROFPROPERTIES];

  HRESULT        hr = MQ_OK;

 

 

  // Validate the input parameters.

  if (wszPathName == NULL || wszOutFormatName == NULL || pdwOutFormatNameLength == NULL)

  {

    return MQ_ERROR_INVALID_PARAMETER;

  }

 

 

  // 设置属性

  DWORD cPropId = 0;

  aQueuePropId[cPropId] = PROPID_Q_PATHNAME;

  aQueuePropVar[cPropId].vt = VT_LPWSTR;

  aQueuePropVar[cPropId].pwszVal = wszPathName;

  cPropId++;

 

  WCHAR wszLabel[MQ_MAX_Q_LABEL_LEN] = L"Test Queue";

  aQueuePropId[cPropId] = PROPID_Q_LABEL;

  aQueuePropVar[cPropId].vt = VT_LPWSTR;

  aQueuePropVar[cPropId].pwszVal = wszLabel;

  cPropId++;

 

 

  // 初始化MQQUEUEPROPS 结构体.

  QueueProps.cProp = cPropId;               // Number of properties

  QueueProps.aPropID = aQueuePropId;        // IDs of the queue properties

  QueueProps.aPropVar = aQueuePropVar;      // Values of the queue properties

  QueueProps.aStatus = aQueueStatus;        // Pointer to the return status

 

 

  // 调用MQCreateQueue创建队列

  WCHAR wszFormatNameBuffer[256];

  DWORD dwFormatNameBufferLength = sizeof(wszFormatNameBuffer)/sizeof(wszFormatNameBuffer[0]);

  hr = MQCreateQueue(pSecurityDescriptor,         // Security descriptor

                     &QueueProps,                 // Address of queue property structure

                     wszFormatNameBuffer,         // Pointer to format name buffer

                     &dwFormatNameBufferLength);  // Pointer to receive the queue's format name length

 

 

  // Return the format name if the queue is created successfully.

  if (hr == MQ_OK || hr == MQ_INFORMATION_PROPERTY)

  {

    if (*pdwOutFormatNameLength >= dwFormatNameBufferLength)

    {

      wcsncpy(wszOutFormatName, wszFormatNameBuffer, *pdwOutFormatNameLength - 1);

      wszOutFormatName[*pdwOutFormatNameLength - 1] = L'/0';

      *pdwOutFormatNameLength = dwFormatNameBufferLength;

    }

    else

    {

      wprintf(L"The queue was created, but its format name cannot be returned./n");

    }

  }

  return hr;

}

 

4.2寻找一个队列

// Define the MQPROPERTYRESTRICTION

// and MQRESTRICTION structures.

const int MAX_PROPERTIES = 13;   // 13 possible queue properties

CLSID PRINTER_SERVICE_TYPE =     // Dummy GUID

      {0x1, 0x2, 0x3, {0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb}};

HRESULT hr = MQ_OK;

MQPROPERTYRESTRICTION PropertyRestriction;

MQRESTRICTION Restriction;

 

//////////////////////////////////////////

// Set search criteria according to the

// type of service provided by the queue.

/////////////////////////////////////////

 

 

// Set the queue restriction to PROPID_Q_TYPE = PRINTER_SERVICE_TYPE.

PropertyRestriction.rel = PREQ;

PropertyRestriction.prop = PROPID_Q_TYPE;

PropertyRestriction.prval.vt = VT_CLSID;

PropertyRestriction.prval.puuid = &PRINTER_SERVICE_TYPE;

 

 

// Specify one property restriction.

Restriction.cRes = 1;

Restriction.paPropRes = &PropertyRestriction;

 

 

// Set a MQCOLUMNSET structure to specify

// the properties to be returned:        

// PROPID_Q_INSTANCE and PROPID_Q_CREATE_TIME.

MQCOLUMNSET Column;

PROPID aPropId[2];     // Only two properties to retrieve

DWORD dwColumnCount = 0;

 

aPropId[dwColumnCount] = PROPID_Q_INSTANCE;

dwColumnCount++;

 

aPropId[dwColumnCount] = PROPID_Q_CREATE_TIME;

dwColumnCount++;

 

Column.cCol = dwColumnCount;

Column.aCol = aPropId;

 

 

// Call MQLocateBegin to start a query.

HANDLE         hEnum = NULL;

hr = MQLocateBegin(

                   NULL,           //Start search at the top

                   &Restriction,   //Search criteria

                   &Column,        //Properties to return

                   NULL,           //No sort order

                   &hEnum          //Enumeration handle

                   );

 

if (FAILED(hr))

{

  //

  // Error handling.

  //

}

 

 

// Call MQLocateNext in a loop to examine the

// query results.

MQPROPVARIANT aPropVar[MAX_PROPERTIES];

DWORD cProps, index;

 

do

{

  cProps = MAX_PROPERTIES;

  hr = MQLocateNext(

                    hEnum,         // Handle returned by MQLocateBegin

                    &cProps,       // Size of aPropVar array

                    aPropVar       // An array of MQPROPVARIANT for results

                    );

 

  if (FAILED(hr))

  {

    break;

  }

 

  for (index = 0; index < cProps; index += dwColumnCount)

 

  {

     // Process properties of a queue stored in:

     // aPropVar[index], aPropVar[index + 1], …,

     // aPropVar[index + dwColumnCount - 1].

  }

 

} while (cProps > 0);

 

 

// Call MQLocateEnd to end query.

hr = MQLocateEnd(hEnum);   // Handle returned by MQLocateBegin.

if (FAILED(hr))

{

  //

  //Error handling

  //

}

4.3打开队列

int OpenMyQueue(

                LPWSTR wszPathName,

                DWORD dwAccess,

                DWORD dwShareMode,

                QUEUEHANDLE *phQueue

                )

{

  HRESULT hr = MQ_OK;

 

 

  // Validate the input parameters.

  if ((wszPathName == NULL) || (phQueue == NULL))

  {

    return MQ_ERROR_INVALID_PARAMETER;

  }

 

 

  // Call MQPathNameToFormatName to obtain the format name required

  // to open the queue.

  DWORD dwFormatNameBufferLength = 256;               // Length of the format name buffer

  WCHAR wszFormatNameBuffer[256];                     // Format name buffer

  

  hr = MQPathNameToFormatName(wszPathName,

                              wszFormatNameBuffer,

                              &dwFormatNameBufferLength);

  if (FAILED(hr))

  {

     fprintf(stderr, "An error occurred in MQPathNameToFormatName (error: 0x%x)./n", hr);

     return hr;

  }

 

 

  // Call MQOpenQueue to open the queue with the access and

  // share mode provided by the caller.

  hr = MQOpenQueue(

                   wszFormatNameBuffer,               // Format name of the queue

                   dwAccess,                          // Access mode

                   dwShareMode,                       // Share mode

                   phQueue                            // OUT: Queue handle

                   );

  if (FAILED(hr))

  {

     fprintf(stderr, "An error occurred in MQOpenQueue (error: 0x%x.)/n",hr);

     return hr;

  }

  return hr;

}

 

4.4 读取消息

 

HRESULT ReadingDestQueue(

                         WCHAR * wszQueueName,

                         WCHAR * wszComputerName

                         )

{

 

  // Define the required constants and variables.

  const int NUMBEROFPROPERTIES = 5;

  DWORD cPropId = 0;

  HRESULT hr = MQ_OK;                                 // Return code

  HANDLE hQueue = NULL;                               // Queue handle

  ULONG ulBufferSize = 2;

 

 

  // Define an MQMSGPROPS structure.

  MQMSGPROPS msgprops;

  MSGPROPID aMsgPropId[NUMBEROFPROPERTIES];

  MQPROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES];

  HRESULT aMsgStatus[NUMBEROFPROPERTIES];

 

 

  // Specify the message properties to be retrieved.

  aMsgPropId[cPropId] = PROPID_M_LABEL_LEN;           // Property ID

  aMsgPropVar[cPropId].vt = VT_UI4;                   // Type indicator

  aMsgPropVar[cPropId].ulVal = MQ_MAX_MSG_LABEL_LEN;  // Length of label

  cPropId++;

 

  WCHAR wszLabelBuffer[MQ_MAX_MSG_LABEL_LEN];         // Label buffer

  aMsgPropId[cPropId] = PROPID_M_LABEL;               // Property ID

  aMsgPropVar[cPropId].vt = VT_LPWSTR;                // Type indicator

  aMsgPropVar[cPropId].pwszVal = wszLabelBuffer;      // Label buffer

  cPropId++;

 

  UCHAR * pucBodyBuffer = NULL;

  pucBodyBuffer = (UCHAR*)malloc(ulBufferSize);

  if (pucBodyBuffer == NULL)

  {

    return MQ_ERROR_INSUFFICIENT_RESOURCES;

  }

  memset(pucBodyBuffer, 0, ulBufferSize);

  aMsgPropId[cPropId] = PROPID_M_BODY_SIZE;           // Property ID

  aMsgPropVar[cPropId].vt = VT_NULL;                  // Type indicator

  cPropId++;

 

  aMsgPropId[cPropId] = PROPID_M_BODY;                // Property ID

  aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1;       // Type indicator

  aMsgPropVar[cPropId].caub.pElems = (UCHAR*)pucBodyBuffer;  // Body buffer

  aMsgPropVar[cPropId].caub.cElems = ulBufferSize;    // Buffer size

  cPropId++;

 

  aMsgPropId[cPropId] = PROPID_M_BODY_TYPE;           // Property ID

  aMsgPropVar[cPropId].vt = VT_NULL;                  // Type indicator

  cPropId++;

 

 

  // Initialize the MQMSGPROPS structure.

  msgprops.cProp = cPropId;                           // Number of message properties

  msgprops.aPropID = aMsgPropId;                      // IDs of the message properties

  msgprops.aPropVar = aMsgPropVar;                    // Values of the message properties

  msgprops.aStatus = aMsgStatus;                      // Error reports

 

 

  // Validate the input strings.

  if (wszQueueName == NULL || wszComputerName == NULL)

  {

    return MQ_ERROR_INVALID_PARAMETER;

  }

 

 

  // Create a direct format name.

  WCHAR * wszFormatName = NULL;

  DWORD dwFormatNameLength = 0;

  dwFormatNameLength = wcslen(wszQueueName) + wcslen(wszComputerName) + 12;

  wszFormatName = new WCHAR[dwFormatNameLength];

  if (wszFormatName == NULL)

  {

    return MQ_ERROR_INSUFFICIENT_RESOURCES;

  }

  memset(wszFormatName, 0, dwFormatNameLength);

 

  if (_snwprintf(

                 wszFormatName,

                 dwFormatNameLength - 1,

                 L"DIRECT=OS:%s//%s",

                 wszComputerName,

                 wszQueueName

                 ) < 0)

  {

    wprintf(L"The format name is too long for the buffer specified./n");

    return FALSE;

  }

  else

  {

    wszFormatName[dwFormatNameLength - 1] = L'/0';

  }

 

 

  // Open the queue with receive access.

  hr = MQOpenQueue(

                   wszFormatName,                      // Format name of the queue

                   MQ_RECEIVE_ACCESS,                  // Access mode

                   MQ_DENY_NONE,                       // Share mode

                   &hQueue                             // OUT: Queue handle

                   );

  // Free the memory that was allocated for the format name string.

  if (wszFormatName)

  {

    delete [] wszFormatName;

  }

 

 

  // Handle any error returned by MQOpenQueue.

  if (FAILED(hr))

  {

    return hr;

  }

 

  for ( ; ; )

  {

    aMsgPropVar[0].ulVal = MQ_MAX_MSG_LABEL_LEN;

    hr = MQReceiveMessage(

                          hQueue,                     // Queue handle

                          1000,                       // Max time to (msec) to receive the message

                          MQ_ACTION_RECEIVE,          // Receive action

                          &msgprops,                  // Message property structure

                          NULL,                       // No OVERLAPPED structure

                          NULL,                       // No callback function

                          NULL,                       // No cursor handle

                          MQ_NO_TRANSACTION           // Not in a transaction

                          );

 

    if (hr == MQ_ERROR_BUFFER_OVERFLOW)

    {

      ulBufferSize = aMsgPropVar[2].ulVal*sizeof(UCHAR);

      pucBodyBuffer = (UCHAR*)realloc(pucBodyBuffer, ulBufferSize);

      if (pucBodyBuffer == NULL)

      {

        return MQ_ERROR_INSUFFICIENT_RESOURCES;

      }

      memset(pucBodyBuffer, 0, ulBufferSize);

      aMsgPropVar[3].caub.pElems = (UCHAR*)pucBodyBuffer;

      aMsgPropVar[3].caub.cElems = ulBufferSize;

      continue;

    }

 

    if (FAILED(hr))

    {

      wprintf(L"No messages. Closing queue/n");

      break;

    }

 

    // If the message contains a label, print it.

    if (msgprops.aPropVar[0].ulVal == 0)

    {

      wprintf(L"Removed message from queue./n");

    }

    else

    {

      wprintf(L"Removed message '%s' from queue./n", wszLabelBuffer);

    }

 

 

    // If the message body is a string, display it.

    if (msgprops.aPropVar[4].ulVal == VT_BSTR)

    {

      wprintf(L"Body: %s", (WCHAR*)pucBodyBuffer);

      wprintf(L"/n");

    }

  }

 

 

  // Close the queue and free the memory allocated for the body buffer.

  hr = MQCloseQueue(hQueue);

  free(pucBodyBuffer);

 

  return hr;

}

4.5 发送消息

 

HRESULT SendMessage(

                    WCHAR * wszQueueName,

                    WCHAR * wszComputerName

                    )

{

 

  // Validate the input strings.

  if (wszQueueName == NULL || wszComputerName == NULL)

  {

    return MQ_ERROR_INVALID_PARAMETER;

  }

 

 

  // Define the required constants and variables.

  const int NUMBEROFPROPERTIES = 5;                   // Number of properties

  DWORD cPropId = 0;                                  // Property counter

  HRESULT hr = MQ_OK;                                 // Return code

  HANDLE hQueue = NULL;                               // Queue handle

 

  // Define an MQMSGPROPS structure.

  MQMSGPROPS msgProps;

  MSGPROPID aMsgPropId[NUMBEROFPROPERTIES];

  MQPROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES];

  HRESULT aMsgStatus[NUMBEROFPROPERTIES];

 

 

  // Specify the message properties to be sent.

  aMsgPropId[cPropId] = PROPID_M_LABEL;               // Property ID

  aMsgPropVar[cPropId].vt = VT_LPWSTR;                // Type indicator

  aMsgPropVar[cPropId].pwszVal = L"Test Message";     // The message label

  cPropId++;

 

 

  // Initialize the MQMSGPROPS structure.

  msgProps.cProp = cPropId;

  msgProps.aPropID = aMsgPropId;

  msgProps.aPropVar = aMsgPropVar;

  msgProps.aStatus = aMsgStatus;

 

 

  // Create a direct format name for the queue.

  WCHAR * wszFormatName = NULL;

  DWORD dwBufferLength = 0;

  dwBufferLength = wcslen(wszQueueName) + wcslen(wszComputerName) + 12;

  wszFormatName = new WCHAR[dwBufferLength];

  if (wszFormatName == NULL)

  {

    return MQ_ERROR_INSUFFICIENT_RESOURCES;

  }

  memset(wszFormatName, 0, dwBufferLength*sizeof(WCHAR));

 

  if (_snwprintf(

                 wszFormatName,

                 dwBufferLength - 1,

                 L"DIRECT=OS:%s//%s",

                 wszComputerName,

                 wszQueueName

                ) < 0)

  {

    wprintf(L"The format name is too long for the buffer specified./n");

    return FALSE;

  }

  else

  {

    wszFormatName[dwBufferLength - 1] = L'/0';

  }

 

 

  // Call MQOpenQueue to open the queue with send access.

  hr = MQOpenQueue(

                   wszFormatName,                     // Format name of the queue

                   MQ_SEND_ACCESS,                    // Access mode

                   MQ_DENY_NONE,                      // Share mode

                   &hQueue                            // OUT: Queue handle

                   );

  // Free the memory that was allocated for the format name string.

  delete [] wszFormatName;

 

 

  // Handle any error returned by MQOpenQueue.

  if (FAILED(hr))

  {

    return hr;

  }

 

 

  // Call MQSendMessage to send the message to the queue.

  hr = MQSendMessage(

                     hQueue,                          // Queue handle

                     &msgProps,                       // Message property structure

                     MQ_NO_TRANSACTION               // Not in a transaction

                     );

  if (FAILED(hr))

  {

    MQCloseQueue(hQueue);

    return hr;

  }

 

 

  // Call MQCloseQueue to close the queue.

  hr = MQCloseQueue(hQueue);

 

  return hr;

}

 

 

你可能感兴趣的:(properties,Microsoft,null,buffer,Descriptor,structure)