| Tenouk C & C++ | MFC Home | Another ATL Tutorial 2 | ATL Attributes 2 | Download | Site Index |


 

 

 

 

 

ATL - Attributes Tutorial on Visual C++ .Net part 1

 

 

 

 

 

 

Program examples compiled using Visual Studio/C++ .Net 2003 compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this tutorial are listed below. Don’t forget to read Tenouk’s small disclaimer. The supplementary note for this tutorial is the early stage of .NET.

 

 

Using Visual C++ and attributes, you can speed up and simplify the process of COM programming. This tutorial uses attributes to implement both a client and a server application. During the course of this tutorial, you will use attributes and events.

The tutorial develops a singleton server object (an object that can have only one instance) that has its own dual interface and a dispatch interface used for firing off events. The server object takes data, given to it through the Send() method of its dual interface, and transmits it to all connected components through the Transfer() event on its dispatch interface.

In addition, the tutorial implements a client (an ActiveX control) that contains a server object. The control responds to the Transfer() event fired by the server object and has its own dual interface that implements several methods: Connect(), Send(), and Disconnect(). If the Transfer() event is fired with a variant containing a BSTR, the string is displayed in the center of the control.

The tutorial is divided into seven steps, each building on the application developed in the previous step. Keep in mind that all the coding part was done manually, copy and paste, instead of using 'wizard'.

  1. Step 1: Creating the Projects.

  2. Step 2: Adding the Server Object.

  3. Step 3: Implementing the Server.

  4. Step 4: Adding the Client Object.

  5. Step 5: Adding the Client Interfaces.

  6. Step 6: Implementing the Client.

  7. Step 7: Using the Client Control.

 

Step 1: Creating the Projects

 

In this step, you will create an initial solution containing two ATL projects. The two projects will implement the server and client objects of the tutorial.

 

To create a new solution

 

  1. In the Visual Studio environment, click New from the File menu and then click Blank Solution.

 

Figure 1: Creating a new Visual C++ .Net project, starting with blank solution.

 

Figure 1: Creating a new Visual C++ .Net project, starting with blank solution.

 

  1. In the Name box, type DispSink.

 

 

Figure 2: Entering the blank solution name.

 

Figure 2: Entering the blank solution name.

 

  1. Click OK to create a blank solution.

 

Once the solution has been created, add the two ATL projects to the empty solution.

 

To create a new project

 

  1. In Solution Explorer, right-click the DispSink solution node.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 3: Adding new project to Visual C++ .Net solution.

 

Figure 3: Adding new project to Visual C++ .Net solution.

 

  1. On the shortcut menu, click Add and then click New Project. The New Project dialog box appears.

  2. From the Visual C++ Projects folder, select ATL Project.

 

Figure 4: Adding DispClient, a new ATL project to solution.

 

Figure 4: Adding DispClient, a new ATL project to solution.

 

  1. In the Name box, type DispClient.

  2. Click OK to start the ATL Project Wizard. The ATL Project Wizard offers several choices to configure the initial project. Because the wizard creates an attributed project by default, you do not have to change any wizard settings.

 

Figure 5: ATL Project Wizard Application Settings page.

 

Figure 5: ATL Project Wizard Application Settings page.

 

  1. Click Finish to generate the DispClient project. The files generated by the wizard are listed in the following table.

 

Figure 6: The generated files and resources for DispClient ATL project.

 

Figure 6: The generated files and resources for DispClient ATL project.

 

File

Description

DispClient.cpp

Contains the module attribute, which implements DLLMain(), DLLRegisterServer(), and DLLUnregisterServer(). The module type also defines the GUID for the type library. Notice that the GUID and helpstring have been automatically generated.

DispClient.h

A MIDL-generated file that will contain interface definitions. For purposes of this tutorial, this file will be unnecessary.

DispClient.rc

The resource file, which initially contains the version information and a string containing the project name.

DispClient.rgs

Contains entries that are added to the registry, which will register your COM object.

DispClient.vcproj

A file containing the project settings.

DispClientps.def

The module definition file for the proxy/stub DLL. For purposes of this tutorial, this is unnecessary.

ReadMe.txt

A file containing an explanation of the files generated by the application wizard.

Resource.h

The header file for the resource file.

StdAfx.cpp

The file that will #include the ATL implementation files.

StdAfx.h

The file that will #include the ATL header files.

 

Table 1.

 

You will also notice a DispClientPS project. This project creates the proxy and stub that allow your object to be accessed from outside of its COM apartment.

 

To create a new server project

 

  1. In Solution Explorer, right-click the DispSink solution node.

  2. On the shortcut menu, click Add, and then click New Project. The New Project dialog box appears.

 

Figure 7: Adding another new project to solution.

 

Figure 7: Adding another new project to solution.

 

  1. From the Visual C++ Projects folder, select ATL Project.

  2. In the Name box, type DispServer.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 8: Adding new DispServer, an ATL project to solution.

 

Figure 8: Adding new DispServer, an ATL project to solution.

 

  1. Click OK to start the ATL Project Wizard. The ATL Project Wizard appears.

  2. Click the Application Settings tab to display the current options for the initial project.

  3. Select the Executable server type.

 

Figure 9: Modifying Application Settings options.

 

Figure 9: Modifying Application Settings options.

 

  1. Click Finish to generate the DispServer project.

 

For the DispServer project, the application wizard creates a similar set of files compared to the DispClient project. The only difference is in the file DispServer.cpp, where the module type is exe instead of dll.

The next step focuses on the implementation of the server object.

 

Step 2: Adding the Server Object

 

In this step, you will use Class View to add objects to the project. You need to add a single ATL object (named CDispServ) to the server. This object also serves as an event source.

 

To add a class to the project

 

  1. In Class View, right-click the DispServer project. On the shortcut menu, click Add and then click Add Class. The Add Class dialog box appears.

 

Figure 10: Adding new class to DispServer.  

 

Figure 10: Adding new class to DispServer.

 

  1. Select ATL Simple Object and click Open. The ATL Simple Object Wizard appears.

 

Figure 11: Adding an ATL Simple Object template to DispServer.

 

Figure 11: Adding an ATL Simple Object template to DispServer.

 

  1. In the Short name field, type DispServ. The remaining fields are automatically completed. The additional fields contain information on the name of the class as well as the names of the files that should be created. The Type field is a description of the object, while the ProgID field is the readable name that can be used to look up the CLSID of the object. Note that the Attributed box is selected and unavailable. An ATL object created by the wizard in an attributed project is always attributed.

 

Figure 12: An ATL Simple Object Wizard, Names page.

 

Figure 12: An ATL Simple Object Wizard, Names page.

 

  1. Click the Options tab in the wizard.

  2. On the Options tab, select Connection points support. This allows the object to act as an event source.

 

Figure 13: ATL Simple Object Wizard, Options page.

 

Figure 13: ATL Simple Object Wizard, Options page.

 

  1. Click Finish to generate the DispServ class.

Note in Class View that the CDispServ class, as well as the IDispServ and _IDispServEvents interfaces, have been created and are now visible. To implement the new class, the wizard added two new files to the project:

 

Figure 14: The added interfaces and events (of course respective files also added)

 

Figure 14: The added interfaces and events (of course respective files also added)

 

You can build the application by clicking Build DispServer from the Build menu, though DispServer does not actually do anything interesting yet. However, it does have the capability to register itself. This is done automatically when the project is built. The next step implements the functionality of the DispServer object.

 

Step 3: Implementing the Server

 

In this step, you will add the functionality to make the class do something interesting. In the last two steps, you have created the CDispServ class, which now exposes a custom interface (IDispServ), and an event source (the _IDispServEvents event interface). Beyond this implementation, however, it does not actually do anything.

The main purpose of the CDispServ class is to receive data using the Send() method and transmit the information using the Transfer() event. Therefore, a DispClient object connected to a DispServer object can call Send() through the IDispServ interface, passing it data. The Send() method then fires the Transfer() event, propagating the data to all connected DispClient objects. Previously, this required creating a connection point proxy class to fire the events. With the new events feature, the situation is simplified; you will add the Transfer() event to the _IDispServEvents interface.

 

To add and define the Transfer event

 

  1. In Class View, click the DispServer project to expand the node.

  2. Double-click the _IDispServEvents interface. This opens the interface definition in the Code editor.

  3. Define the Transfer() event for the _IDispServEvents interface by adding the following code to the _IDispServEvents interface definition:

 

[id(1), helpstring("method Transfer")] HRESULT Transfer(VARIANT data);

 

  1. Make IDispatch a base class of the interface.

 

Your interface definition should now match the following definition:

 

__interface _IDispServEvents : public IDispatch

{

   [id(1), helpstring("method Transfer")] HRESULT Transfer(VARIANT data);

};

 

Attributes Tutorial on Visual C++ .Net

 

Listing 1.

 

To fire the Transfer() event, make a call to _IDispServEvents_Transfer() from your event source. The form for firing an event is always InterfaceName_EventName.

 

To add and define the Send method

 

  1. In Class View, double-click the IDispServ interface. This opens the interface definition in the Code editor.

  2. Define the Send() method for the IDispServ interface by adding the following code to the IDispServ interface definition:

 

[id(1), helpstring("method Send")] HRESULT Send(VARIANT data);

 

Your interface definition should now match the following definition:

 

__interface IDispServ : IDispatch

{

   [id(1), helpstring("method Send")] HRESULT Send(VARIANT data);

};

 

Attributes Tutorial on Visual C++ .Net

 

Listing 2.

 

To implement the Send() method for the CDispServ class, scroll down to the bottom of DispServ.h and add the following code directly below the last public: section of the class:

 

STDMETHOD(Send)(VARIANT data)

{

   _IDispServEvents_Transfer(data);

   return (S_OK);

}

 

Attributes Tutorial on Visual C++ .Net

 

Listing 3.

 

The full CDispServ class should now look like this:

 

class ATL_NO_VTABLE CDispServ : public IDispServ

{

public:

   CDispServ()

   {

   }

 

   __event __interface _IDispServEvents;

 

   DECLARE_PROTECT_FINAL_CONSTRUCT()

 

   HRESULT FinalConstruct()

   {

      return S_OK;

   }

  

   void FinalRelease()

   {

   }

 

public:

   STDMETHOD(Send)(VARIANT data)

   {

      _IDispServEvents_Transfer(data);

      return S_OK;

   }

};

 

The final task implements the CDispServ class as a singleton server, which means that all clients will connect to the same server.

 

To define CDispServ as a singleton server

 

  1. In Class View, double-click the CDispServ node.

  2. Add the following lines directly below the DECLARE_PROTECT_FINAL_CONSTRUCT() in class CDispServ:

 

DECLARE_CLASSFACTORY_SINGLETON(CDispServ);

 

Attributes Tutorial on Visual C++ .Net

 

Listing 4.

 

The server is now complete. You can build the server by selecting Build DispServer from the Build menu. Once the server is successfully built, it will register itself. The Visual Studio development environment also provides wizards that let you add properties and methods. Just right click on the interface node in Class View and select a wizard from the context menu. The next step adds a simple client object to the DispClient project.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

  1. MSDN MFC 7.0 class library online documentation.

  2. MSDN MFC 9.0 class library online documentation - latest version.

  3. Porting & Migrating your older programs.

  4. MSDN Library

  5. DCOM at MSDN.

  6. COM+ at MSDN.

  7. COM at MSDN.

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 

 

 

 


 

| Tenouk C & C++ | MFC Home | Another ATL Tutorial 2 | ATL Attributes 2 | Download | Site Index |