Click here to Skip to main content
Click here to Skip to main content
Go to top

The Simplest COM Tutorial in Visual Studio 2008

, 23 Feb 2009
Rate this:
Please Sign up or sign in to vote.
A beginner's guide to creating COM/DCOM server and client under .NET 2008 environment.

1. Introduction

I was new to COM/DCOM programming when I started learning this "old-fashioned" technology a month ago. I found it was very hard to find helpful tutorials on the Internet. I did find some tutorials out there, but I felt that they were not good resources to learn from because they were either "too old" or too hard to re-generate the claimed results. These resources were mostly developed under Visual Studio 6, they generally focused on some in-depth technical details of COM/DCOM and were not written for absolute beginners.

This tutorial has three goals: firstly, developing COM/DCOM server/client under the latest development environment; secondly, making the implementation as simple as possible; thirdly, providing elaborate description on the procedure of the implementation.

2. The Simplest Chat Server

This tutorial will create a simple COM-based chat server and a console application will consume the service provided by the server. The server is the simplest one I have ever implemented because:

  1. It is an in-process server. It is loaded into the client's address space and therefore no proxy/stub is necessary. Proxy/stub are the tools used by COM/DCOM to achieve communication between server and client running in different address spaces or even on different hosts.
  2. The server allows only one client to connect to it.
  3. The server has only one interface, the interface has only one method and the method has the simplest functionality I have ever imagined under client/server environment. By "simplest", I do not mean something like "void FunctionName(void)", these kind of functions are useless for client/server architecture. If client doesn't send something to server and server doesn't send something back to client, how do you know whether the two-way communication is achieved? So the method has the following form:
SimplestMethod(client_send_something_to_server, server_send_something_to_client)

The Server takes four steps to implement.

2.1 Creating ATL Project

A simple shell is created to hold COM object via "ATL project" wizard. To start the wizard, please follow the steps: click the "File" menu, choose the "New" -> "Project..." menu item. The "New Project" window will show as follows.

We choose "ATL Project", input the solution name as "SimpleCOM" and click "OK" button to open the "ATL Project" wizard as follows:

Nothing needs to be changed for the wizard, so we simply click "Finish" button and let our server code be generated on the fly. Although we don't care about the details under the hood, there are several things worth being mentioned here.

  1. The wizard created a DLL.
  2. The DLL will be registered to the system once it is successfully compiled.
  3. The DLL provides all the functionalities needed by COM object to function, these functionalities are common to all COM objects and therefore they are sufficient for either this simple example or some other more complex cases.

2.2 Adding COM Class to Server

A COM class is a class inherited from a COM interfaces. A COM interface is a struct (there is no difference between struct and class in Visual C++) inherited from IUnknown, directly or indirectly. At this step, a COM class and an interface from which the COM class is derived are generated at the same time.

To add a new COM class to the server, open the "Class View" of the project just created, right click the "SimpleCOM" project, click "Add" -> "Class..." to open "New Class" wizard. The SimpleCOM class is one of the two "New ATL" wizard generated classes. The other class SimpleCOMPS is used to create Proxy/Stub and will not be discussed here.

At the "New Class" wizard below, we choose "ATL" -> "ATL simple object" and click "Add" button.

The "ATL Simple Object" wizard is displayed as below:

We simply type "SimpleChatServer" in the "Short name" field and all the other fields will be populated automatically. There is no need to change these names in this simple example. One thing that needs to be mentioned here is: at the bottom half of the window, the COM section, we can see that a COM class "SimpleChatServer" and an interface "ISimpleChatServer" will be created.

To continue the wizard, we click the "Next>" button and the "Options" window will show up. We simply set the options of the "ATL object" to the most commonly used ones as shown in the picture below. There are four categories for the options and each category worth a whole chapter to explain. As this tutorial is intended for beginners, what I can tell you at the moment is to click the "Finish" button at the following screen and close the wizard.

2.3 Adding Method to Interface

In the class view of the project, expanding the "SimpleCOM" project and right-clicking the "ISimpleChatServer" interface, click "Add" -> "Add Method...".

The new method is named "CallMe" and has the following signature:

The first parameter "BSTR name" is the name of client, it will be passed to server when client calls the method. The other parameter "BSTR** helloMessage" is the message returned to client. The method can testify whether the duplex communication has been achieved. Click "Finish" button to go back to class view of the project.

2.4 Coding Method

In the class view window below, choose the COM class "CSimpleChatServer" at the upper pane and double click the "CallMe" method to open the SimpleChatServer.cpp file.

At the SimpleChatServer.cpp file, the final CallMe method is as follows. To include the definition of class "CString", you need to include the <atlstr.h> header at the beginning of the "SimpleChatServer.cpp" file.

STDMETHODIMP CSimpleChatServer::CallMe(BSTR name, BSTR** helloMessage)
{
    // TODO: Add your implementation code here
    CString temp = _T("Hi ");
    temp += name;
    temp += ", welcome to the simple chat server!";
    BSTR str = temp.AllocSysString();
    *helloMessage = &str;
    return S_OK;
}

2.5 Compiling the Server

The compilation of the server is as simple as pressing "F7" or choosing "Build" menu and clicking "Build Solution" menuitem. Visual Studio 2008 will compile the server and register the COM class and interface with the operating system. Consequently, we can find corresponding entries and ClassID/InterfaceID at the Registry. This information will be used by the client to locate and consume the service provided by the server, the CallMe() method more specifically.

3. The Simplest Client

We'll add the client project at the solution within which we created the server project. To do this, please open "Solution Explorer" and right click the solution "SimpleCOM" and choose "Add" -> "NewProject...".

We add a new Win32 Console Application called "ConsoleComClient" to the solution and click "OK". At the following window, we simply click "Finish" to accept all the default settings for the new project:

The new Win32 console application is fairly straightforward. The simplest client takes seven steps. Its code is fully documented, so I simply put the code here.

/*
** This client shows the procedure of creating the simplest COM client.
** This client is a CONSOLE application and uses IN-PROCESS COM server.
** The server serves ONLY one client.
** Two-way communication is achieved in a synchronous manner by passing
** pointer to server so that server can pass something back to client.
*/
#include "stdafx.h"
/*
**                STEP 1
** including two files created by the server
** these files contain the information about ATL object and interfaces
** such as CLASSID and INTERFACEID.
*/
#include "../SimpleCOM/SimpleCOM_i.h"
#include "../SimpleCOM/SimpleCOM_i.c"

int _tmain(int argc, _TCHAR* argv[])
{
    BSTR* message;                //used to accept return value from server.
    HRESULT hr;                    //COM error code;
    ISimpleChatServer *chat;    //pointer to the interface
    /*
    **            STEP 2
    ** Initialize COM and check for success
    */
    hr = CoInitialize(0);
    if(SUCCEEDED(hr))
    {
        /*
        **        STEP 3
        ** Create an instance of the COM server object.
        ** The most important result of this function call
        ** is that we get a pointer to the server interface.
        ** The function takes 5 parameters
        ** param #1: class ID of server COM class
        ** param #2: outer interface(used in aggregation)
        ** param #3: class context.
        ** param #4: interface ID.
        ** param #5: pointer to the interface of interest.
        */
        hr = CoCreateInstance(
            CLSID_SimpleChatServer,
            NULL,
            CLSCTX_INPROC_SERVER,
            IID_ISimpleChatServer,
            (void**) &chat);
        if(SUCCEEDED(hr))
        {
            /*
            **    STEP 4
            ** call method via Interface ID.
            */  
            
            hr = chat -> CallMe(_T("Zhiwei"), &message);
            MessageBox(NULL,*message, _T("Message returned from chat server"),0);
            /*
            **  STEP 5
            ** de-allocation of BSTR to prevent memory leak
            ** string handling is big topic in COM
            */
            ::SysFreeString(*message);
            /*
            **    STEP 6
            ** Decrease server's object reference counter.
            ** this is a important step and has been done at client side,
            ** so that server knows that it can de-allocate an object.
            */
            hr = chat -> Release();
        }
    }
    /*
    **            STEP 7
    ** close COM.
    */
    CoUninitialize();

    return 0;
}

Finally, you need to set the "ConsoleComClient" as the "StartUp project" and compile it. The very last stage of the tutorial is to run the project and you'll see a window pop up with the welcome message.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Zhiwei Liu
Software Developer Gallagher Group Ltd.
New Zealand New Zealand
No Biography provided

Comments and Discussions

 
Questionbonne relation PinmemberMember 1005429015-May-13 3:32 
GeneralGreat Article PinmemberPandit_G12-Apr-13 9:35 
GeneralMy vote of 4 PinmemberRoshan S. Deshmukh6-Apr-13 22:17 
QuestionBravo Pinmembercristogesu10-Jul-12 23:33 
Questionhow to get further from here PinmemberAlex Ten10-May-12 4:40 
GeneralMy vote of 4 PinmemberJan Vratislav26-Oct-11 12:47 
GeneralMy vote of 5 Pinmemberadamwloczykij29-Jun-10 4:47 
GeneralRe: My vote of 5 PinmemberJohn Husebty15-Sep-10 6:13 
GeneralHelp me - how can i change this project for using client on remote PC. Pinmemberamigosss15-Jun-10 21:54 
GeneralRe: Help me - how can i change this project for using client on remote PC. PinmemberDebojyoti Majumder13-May-11 1:51 
GeneralRe: Help me - how can i change this project for using client on remote PC. PinmemberMember 86144341-Feb-12 17:36 
QuestionHelp Please - Defining a FUNCTION in a COM object PinmemberRicardoEnergy1-Feb-10 1:08 
AnswerRe: Help Please - Defining a FUNCTION in a COM object PinmemberZhiwei Liu1-Feb-10 10:43 
GeneralRe: Help Please - Defining a FUNCTION in a COM object PinmemberRicardoEnergy1-Feb-10 23:21 
GeneralThe Simplest COM Tutorial in Visual Studio 2008 PinmemberRichard MacCutchan3-Mar-09 11:33 
GeneralMy vote of 2 PinmemberJonathan Davies26-Feb-09 5:42 
GeneralBugfixes PinmemberCristian Adam24-Feb-09 0:04 
Question*helloMessage = &str; WHAT?? Pinmemberaxelriet23-Feb-09 23:51 
AnswerRe: *helloMessage = &str; WHAT?? PinmemberZhiwei Liu3-Mar-09 11:46 
Questioncan't find SimpleCOM_i.h Pinmemberrobullelk21-Feb-09 13:10 
AnswerRe: can't find SimpleCOM_i.h Pinmemberrobullelk21-Feb-09 13:34 
Generalbuilding solution PinmemberAHTOXA9-Feb-09 3:27 
GeneralGood article for beginners PinmemberNicolas Bauland27-Sep-08 3:45 
GeneralRe: Good article for beginners PinmemberZhiwei Liu22-Feb-09 11:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140921.1 | Last Updated 23 Feb 2009
Article Copyright 2008 by Zhiwei Liu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid