Lesson 4: Explore the TestMessage client source code

Background

This section of the tutorial takes you on a brief tour of the source code behind the TestMessage client application.

A lot of the code implements the Windows interface, through which you can send, receive, and view the messages. This portion of the tutorial, however, focuses on the portions of the code given to QAnywhere.

You can find the TestMessage source code in Samples\QAnywhere.

Several versions of the TestMessage source code are provided. The following versions are provided for Windows 2000 and Windows XP:

  • A C++ version built using the Microsoft Foundation Classes is provided as Samples\QAnywhere\Windows\MFC\TestMessage\TestMessage.sln.

  • A C# version built on the .NET Framework is provided as Samples\QAnywhere\Windows\.NET\CS\TestMessage\TestMessage.sln.

  • A Java version is provided as Samples\QAnywhere\Java\TestMessage\TestMessage.java.

The following version is provided for .NET Compact Framework:

  • A C# version built on the .NET Compact Framework is provided as Samples\QAnywhere\Windows Mobile Classic\.NET\CS\TestMessage\TestMessage.sln.

Required software

Visual Studio 2005 or later is required to open the solution files and build the .NET Framework projects and the .NET Compact Framework project.

Exploring the C# source

This section takes you through the C# source code. The two versions are structured in a very similar manner.

Rather than look at each line in the application, this lesson highlights particular lines that are useful for understanding QAnywhere applications. It uses the C# version to illustrate these lines.

  1. Open the version of the TestMessage project that you are interested in.

    Double-click the solution file to open the project in Visual Studio. For example, Samples\QAnywhere\Windows\.NET\CS\TestMessage\TestMessage.sln is a solution file. There are several solution files for different environments.

  2. Ensure that Solution Explorer is open.

    You can open the Solution Explorer from the View menu.

  3. Inspect the Source Files folder.

    There are two files of particular importance. The MessageList file (MessageList.cs) receives messages and lets you view them. The NewMessage file (NewMessage.cs) allows you to construct and send messages.

  4. From Solution Explorer, open the MessageList file.

  5. Inspect the included namespaces.

    Every QAnywhere application requires the iAnywhere.QAnywhere.Client namespace. The assembly that defines this namespace is supplied as the DLL iAnywhere.QAnywhere.Client.dll. The files are in the following locations:

    • .NET Framework 2.0: install-dir\Assembly\v2
    • .NET Compact Framework 2.0: install-dir\ce\Assembly\v2

    For your own projects, you must include a reference to this DLL when compiling. The namespace is included using the following line at the top of each file:

    using iAnywhere.QAnywhere.Client;
  6. Inspect the startReceiver method.

    This method performs initialization tasks that are common to QAnywhere applications:

    • Create a QAManager object.

      _qaManager = 
      QAManagerFactory.Instance.CreateQAManager();

      QAnywhere provides a QAManagerFactory object to create QAManager objects. The QAManager object handles QAnywhere messaging operations: in particular, receiving messages (getting messages from a queue) and sending messages (putting messages on a queue).

      QAnywhere provides two types of manager: QAManager and QATransactionalManager. When using QATransactionalManager, all send and receive operations occur within a transaction, so that either all messages are sent (or received) or none are.

    • Write a method to handle messages.

      The onMessage() method is called by QAnywhere to handle regular non-system messages. The message it receives is encoded as a QAMessage object. The QAMessage class and its children, QATextMessage and QABinaryMessage, provide properties and methods that hold all the information QAnywhere applications need about a message.

      private void onMessage( QAMessage msg ) {
         Invoke( new onMessageDelegate( onMessageReceived ),
            new Object [] { msg } );
      }

      This code uses the Invoke method of the Form to cause the event to be processed on the thread that runs the underlying window so that the user interface can be updated to display the message. This is also the thread that created the QAManager. With some exceptions, the QAManager can only be accessed from the thread that created it.

    • Declare a MessageListener, as defined in the MessageList_Load method.

      _receiveListener = new 
          QAManager.MessageListener( onMessage );

      The OnMessage() method is called whenever a message is received by the QAnywhere Agent and placed in the queue that the application listens to.

      Message listeners and notification listeners

      Message listeners are different from the Listener component described in Scenario for messaging with push notifications. The Listener component receives notifications, while message listener objects retrieve messages from the queue.

    When you set a message listener for the queue, the QAnywhere Manager passes messages that arrive on that queue to that listener. Only one listener can be set for a given queue. Setting with a null listener clears out any listener for that queue.

    The MessageListener implementation receives messages asynchronously. You can also receive messages synchronously; that is, the application explicitly goes and looks for messages on the queue, perhaps in response to a user action such as clicking a Refresh button, rather than being notified when messages appear.

    Other initialization tasks include:

    • Open and start the QAManager object.

      _qaManager.Open( 
              AcknowledgementMode.EXPLICIT_ACKNOWLEDGEMENT );
      _qaManager.Start();

      The AcknowledgementMode enumeration constants determine how the receipt of messages is acknowledged to the sender. The EXPLICIT_ACKNOWLEDGEMENT constant indicates that messages are not acknowledged until a call to one of the QAManager acknowledge methods is made.

    • Load any messages that are waiting in the queue.

      loadMessages();
    • Assign a listener to a queue for future messages.

      The listener was declared in the MessageList_Load() method.

      _qaManager.SetMessageListener( 
        _options.ReceiveQueueName,
        _receiveListener );

      The Options ReceiveQueueName property contains the string testmessage, which is the TestMessage queue as set in the TestMessage Options window.

  7. Inspect the addMessage() method in the same file.

    This method is called whenever the application receives a message. It gets properties of the message such as its reply-to address, preferred name, and the time it was sent (Timestamp), and displays the information in the TestMessage user interface. The following lines cast the incoming message into a QATextMessage object and get the reply-to address of the message:

    text_msg = ( QATextMessage )msg;
    from = text_msg.ReplyToAddress;

    This completes a brief look at some of the major tasks in the MessageList file.

  8. From Solution Explorer, open the NewMessage file.

  9. Inspect the sendMessage() method.

    This method takes the information entered in the New Message window and constructs a QATextMessage object. The QAManager then puts the message in the queue to be sent.

    Here are the lines that create a QATextMessage object and set its ReplyToAddress property:

    qa_manager = MessageList.GetQAManager();
    msg = qa_manager.CreateTextMessage();
    msg.ReplyToAddress = MessageList.getOptions().ReceiveQueueName;

    Here are the lines that put the message in the queue to be sent. The variable dest is the destination address, supplied as an argument to the function.

    qa_manager.PutMessage( dest, msg );
See also