Notice: This website is an unofficial Microsoft Knowledge Base (hereinafter KB) archive and is intended to provide a reliable access to deleted content from Microsoft KB. All KB articles are owned by Microsoft Corporation. Read full disclaimer for more details.

How to write to and read from Microsoft Message Queuing in Visual C++ .NET or in Visual C++ 2005


View products that this article applies to.

Summary

This article describes how to create a message and send the message to Microsoft Message Queuing in a Windows application. This article also describes how to read from a private queue and how to deserialize the message contents for display.

Requirements

The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:One of the following operating systems with Message Queuing installed (Message Queuing is included with the operating systems as an option):
  • Microsoft Windows 2000 Professional or Microsoft Windows 2000 Server
  • Microsoft Windows XP Professional
  • Microsoft Windows Server 2003
This article assumes that you are familiar with the following topics:
  • Microsoft Message Queuing
  • Using tools from the command prompt

Write to and Read from Message Queuing

The System.Messaging namespace in the .NET Framework has the classes that you must read from and write to Message Queuing. To create a small Windows application that mimics an online bill payment system, follow these steps:
  1. Start Microsoft Visual Studio .NET or Microsoft Visual Studio 2005.
  2. On the File menu, point to New, and then click Project.
  3. Click Visual C++ Projects under Project Types, and then click Windows Form Application under Templates.

    Note In Visual Studio 2005, click Visual C++ under Project Types, and then click Windows Form Application under Templates.
  4. Name the project MSMQ.
  5. In Solution Explorer, right-click References, and then click Add Reference.

    Note In Solution Explorer, right-click MSMQ, click References, and then click Add New Reference.
  6. On the .NET tab, click System.Messaging.dll file from the list of .dll files. Click Select, and then click OK.
  7. In Solution Explorer, double-click Form1.h(design).
  8. Press the CTRL+ALT+X key combination to open the toolbox. Click the Windows Forms tab.
  9. Add the following to the middle of Form1.h (design):
    • 4 rows each of a Label and a Textbox (positioned to the right of each label).
    • Under the labels and text boxes, add two Button controls to Form1.h (design).
  10. Right-click the controls, click Properties, and then set the Text property for the labels to the following (in order):
    • Pay To:
    • Your Name:
    • Amount:
    • Due Date:
  11. In the Properties dialog box, set the Text property of the button1 control to Send Payment, and then set the Text property of the button2 control to Process Payment.
  12. This application works with a private queue that you must first create in the Computer Management console. To do this, follow these steps:
    1. On the desktop, right-click My Computer, and then click Manage.
    2. Expand Services and Applications to find Message Queuing.

      Note You may not find the Messaging Queuing, when it is not installed.
    3. Expand Message Queuing, right-click Private Queues, point to New, and then click Private Queue.
    4. In the Queue name text box, type billpay, and then click OK.

      Note Click to clear the Transactional check box. Leave the Computer Management console open for viewing messages.
  13. At the top of the code in the Form1.h file, add two USING NAMESPACE statements before the class declaration to include the additional classes that reside in the System::Messaging namespace and the System::Text namespace. (The StringBuilder class, a new .NET Framework class that it is best to use when you concatenate strings, uses the System.Text namespace.)
    using namespace System::Messaging;
    using namespace System::Text;
    
  14. Create a structure that contains variables to hold the data that defines a payment. To create the structure, add the following code above the declaration of the Form1 class::
    __gc public struct Payment
    {
    System::String __gc* Payor;
    System::String __gc* Payee;
    int Amount;
    System::String __gc* DueDate;
    };
  15. Add the code in the following steps to the Click event of button1:
    1. Set the properties of the structure to values of the form elements as follows:
      Payment* myPayment = new Payment; 
      myPayment->Payor = textBox1->Text;
      myPayment->Payee = textBox2->Text;
      myPayment->Amount = Convert::ToInt32(textBox3->Text);
      myPayment->DueDate = textBox4->Text;
    2. Create an instance of the Message class, and then set the Body property to the payment structure:
      System::Messaging::Message *msg = new System::Messaging::Message();
      msg->Body=myPayment;
    3. To send a message to Message Queuing, create an instance of the MessageQueue class and call the Send method that passes in the Message object. The MessageQueue class is the wrapper that manages the interaction with Message Queuing.

      Notice the syntax for setting the path of the private queue that you created in the Computer Management console. Private queues take the following form:
      computername\Private$\queuename
      Local host computers are referenced with a dot or a period ( ".") as follows:
      MessageQueue *msgQ =new MessageQueue(S".\\Private$\\billpay");
      msgQ->Send(msg);

      The code now exists to send a message to Microsoft Message Queuing. The .NET Framework automatically serializes the message by using an XMLMessageFormatter object. This object is implicitly created when messages are sent.
  16. Add the following code to the Click event of the button2 control. The button2_Click event handler receives and processes the payment message that is sent in the button1 event handler.
    1. The first line of code is the same as the line of code that is in the first event handler:
      MessageQueue *msgQ = new MessageQueue(S".\\Private$\\billpay");
    2. Create an array of types to pass to the XMLMessageFormatter class.
      Note This class must be explicitly created when receiving messages. The constructor of the XMLMessageFormatter class takes either a string array of type names or, more preferably, a Type array of types:
      Payment  *myPayment=new Payment();
      Object *o=new Object();
      System::Type *arrTypes[] = new System::Type* [2] ;
      arrTypes[0] = myPayment->GetType();
      arrTypes[1] = o->GetType();
      msgQ->Formatter = new XmlMessageFormatter(arrTypes);
      myPayment= static_cast<Payment*>(msgQ->Receive()->Body);
      These types tell the XMLMessageFormatter how to deserialize the message.
    3. Messages are received by calling the Receive method. Access the Body property to read the message contents. The Body property returns an object. Therefore, the object is cast to the payment type to retrieve the contents in a usable form:
      StringBuilder *sb = new StringBuilder();
      sb->Append(S"Payment paid to: ");
      sb->Append(myPayment->Payor);
      sb->Append(S"\n");
      sb->Append(S"Paid by: ");
      sb->Append(myPayment->Payee);
      sb->Append(S"\n");
      sb->Append(S"Amount: $");
      sb->Append(myPayment->Amount.ToString());
      sb->Append(S"\n");
      sb->Append(S"Due Date: ");
      sb->Append(Convert::ToString(Convert::ToDateTime(myPayment->DueDate)));
    4. Create a message box to display the results:
      MessageBox::Show(sb->ToString(), S"Message Received!");

Complete Code Listing (msmq.h)

#pragma once

using namespace System::Messaging;
using namespace System::Text;

namespace MSMQ
{
	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	__gc public struct Payment
	{
		System::String __gc* Payor;
		System::String __gc* Payee;
		int Amount;
		System::String __gc* DueDate;	
	};
	
	/// <summary> 
	/// Summary for Form1
	///
	/// WARNING: If you change the name of this class, you must change the 
	///          'Resource File Name' property for the managed resource compiler tool 
	///          that is associated with all .resx files that this class depends on.  Otherwise,
	///          the designers cannot interact correctly with localized
	///          resources that are associated with this form.
	/// </summary>
	public __gc class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
		}
  
	protected:
		void Dispose(Boolean disposing)
		{
			if (disposing && components)
			{
				components->Dispose();
			}
			__super::Dispose(disposing);
		}
	private: System::Windows::Forms::Label *  label1;
	private: System::Windows::Forms::Label *  label2;
	private: System::Windows::Forms::Label *  label3;
	private: System::Windows::Forms::Label *  label4;
	private: System::Windows::Forms::TextBox *  textBox1;
	private: System::Windows::Forms::TextBox *  textBox2;
	private: System::Windows::Forms::TextBox *  textBox3;
	private: System::Windows::Forms::TextBox *  textBox4;
	private: System::Windows::Forms::Button *  button1;
	private: System::Windows::Forms::Button *  button2;

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container * components;

		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->label1 = new System::Windows::Forms::Label();
			this->label2 = new System::Windows::Forms::Label();
			this->label3 = new System::Windows::Forms::Label();
			this->label4 = new System::Windows::Forms::Label();
			this->textBox1 = new System::Windows::Forms::TextBox();
			this->textBox2 = new System::Windows::Forms::TextBox();
			this->textBox3 = new System::Windows::Forms::TextBox();
			this->textBox4 = new System::Windows::Forms::TextBox();
			this->button1 = new System::Windows::Forms::Button();
			this->button2 = new System::Windows::Forms::Button();
			this->SuspendLayout();
			// 
			// label1
			// 
			this->label1->Location = System::Drawing::Point(16, 32);
			this->label1->Name = S"label1";
			this->label1->TabIndex = 0;
			this->label1->Text = S"Pay To:";
			// 
			// label2
			// 
			this->label2->Location = System::Drawing::Point(16, 72);
			this->label2->Name = S"label2";
			this->label2->TabIndex = 1;
			this->label2->Text = S"Your Name:";
			// 
			// label3
			// 
			this->label3->Location = System::Drawing::Point(16, 112);
			this->label3->Name = S"label3";
			this->label3->TabIndex = 2;
			this->label3->Text = S"Amount:";
			// 
			// label4
			// 
			this->label4->Location = System::Drawing::Point(16, 152);
			this->label4->Name = S"label4";
			this->label4->TabIndex = 3;
			this->label4->Text = S"Due Date:";
			// 
			// textBox1
			// 
			this->textBox1->Location = System::Drawing::Point(136, 32);
			this->textBox1->Name = S"textBox1";
			this->textBox1->TabIndex = 4;
			this->textBox1->Text = S"ABC";
			// 
			// textBox2
			// 
			this->textBox2->Location = System::Drawing::Point(136, 72);
			this->textBox2->Name = S"textBox2";
			this->textBox2->TabIndex = 5;
			this->textBox2->Text = S"DEF";
			// 
			// textBox3
			// 
			this->textBox3->Location = System::Drawing::Point(136, 112);
			this->textBox3->Name = S"textBox3";
			this->textBox3->TabIndex = 6;
			this->textBox3->Text = S"12";
			// 
			// textBox4
			// 
			this->textBox4->Location = System::Drawing::Point(136, 152);
			this->textBox4->Name = S"textBox4";
			this->textBox4->TabIndex = 7;
			this->textBox4->Text = S"9/9/2003";
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(24, 208);
			this->button1->Name = S"button1";
			this->button1->Size = System::Drawing::Size(88, 23);
			this->button1->TabIndex = 8;
			this->button1->Text = S"Send Payment";
			this->button1->Click += new System::EventHandler(this, button1_Click);
			// 
			// button2
			// 
			this->button2->Location = System::Drawing::Point(152, 208);
			this->button2->Name = S"button2";
			this->button2->Size = System::Drawing::Size(104, 23);
			this->button2->TabIndex = 9;
			this->button2->Text = S"Process Payment";
			this->button2->Click += new System::EventHandler(this, button2_Click);
			// 
			// Form1
			// 
			this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
			this->ClientSize = System::Drawing::Size(292, 266);
			this->Controls->Add(this->button2);
			this->Controls->Add(this->button1);
			this->Controls->Add(this->textBox4);
			this->Controls->Add(this->textBox3);
			this->Controls->Add(this->textBox2);
			this->Controls->Add(this->textBox1);
			this->Controls->Add(this->label4);
			this->Controls->Add(this->label3);
			this->Controls->Add(this->label2);
			this->Controls->Add(this->label1);
			this->Name = S"Form1";
			this->Text = S"Form1";
			this->ResumeLayout(false);

		}	
private: System::Void button1_Click(System::Object *  sender, System::EventArgs *  e)
			 {
				 try
				 {
					Payment* myPayment = new Payment;  
					myPayment->Payor = textBox1->Text;
					myPayment->Payee = textBox2->Text;
					myPayment->Amount = Convert::ToInt32(textBox3->Text);
					myPayment->DueDate = textBox4->Text;

					System::Messaging::Message *msg = new System::Messaging::Message();
					msg->Body=myPayment;

					MessageQueue *msgQ =new MessageQueue(S".\\Private$\\billpay");
					msgQ->Send(msg);
				 }
				 catch(Exception *e)
				 {
					 MessageBox::Show(e->Message);
				 }
			 }

private: System::Void button2_Click(System::Object *  sender, System::EventArgs *  e)
		 {
			 try
			 {
				MessageQueue *msgQ = new MessageQueue(S".\\Private$\\billpay");

				Payment  *myPayment=new Payment();
				Object *o=new Object();
				System::Type *arrTypes[] = new System::Type* [2] ;
				arrTypes[0] = myPayment->GetType();
				arrTypes[1] = o->GetType();
				msgQ->Formatter = new XmlMessageFormatter(arrTypes);
				myPayment= static_cast<Payment*>(msgQ->Receive()->Body);

				StringBuilder *sb = new StringBuilder();
				sb->Append(S"Payment paid to: ");
				sb->Append(myPayment->Payor);
				sb->Append(S"\n");
				sb->Append(S"Paid by: ");
				sb->Append(myPayment->Payee);
				sb->Append(S"\n");
				sb->Append(S"Amount: $");
				sb->Append(myPayment->Amount.ToString());
				sb->Append(S"\n");
				sb->Append(S"Due Date: ");
				sb->Append(Convert::ToString(Convert::ToDateTime(myPayment->DueDate)));

				MessageBox::Show(sb->ToString(), S"Message Received!");
			 }
			 catch(Exception *e)
			 {
				 MessageBox::Show(e->Message);
			 }
		 }
	};
}

Note You must add the common language runtime support compiler option (/clr:oldSyntax) in Visual C++ 2005 to successfully compile the previous code sample. To add the common language runtime support compiler option in Visual C++ 2005, follow these steps:
  1. Click Project, and then click <ProjectName> Properties.

    Note <ProjectName> is a placeholder for the name of the project.
  2. Expand Configuration Properties, and then click General.
  3. Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting in the right pane, click Apply, and then click OK.
For more information about the common language runtime support compiler option, visit the following Microsoft Web site:
/clr (Common Language Runtime Compilation)
http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx

Verify the Code

  1. On the Debug menu, click Start.
  2. Type values in each text box, and then click Send Payment.
  3. Return to the Computer Management console. In Private Queues under billpay, click the Queue messages folder, and then verify that Message Queuing received a message. An envelope icon indicates a new message.
  4. Right-click the message, click Properties, and then click the Body tab. You notice the payment message.

    Note The contents of the payment message are serialized as XML.
  5. Return to the bill payment Windows application, and then click Process Payment. You receive a message box that confirms the receipt of a message and that displays the message.

Troubleshooting

  • The lack of a private queue is generally an issue only on computers that are running Windows 2000 Professional or Windows XP Professional. Windows 2000 Server and Windows Server 2003 permit the use of the public queue.
  • Passing the correct arguments to XMLMessageFormatter() can be tricky. In this example, exceptions are thrown if either the object or the Payment Types are not included in the Type array that is passed to the constructor.

↑ Back to the top


Keywords: KB815809, kbhowtomaster, kbserver, kbwindowsforms, kbforms

↑ Back to the top

Article Info
Article ID : 815809
Revision : 8
Created on : 11/8/2006
Published on : 11/8/2006
Exists online : False
Views : 559