Welcome to this tutorial. You may have a project or application that is client/server, and you have decided to use DCOM to implement your functionality. So, you open up Visual Studio .NET 2003 and choose to start a new project. Which type of project would you start, in order to develop DCOM software? Server EXE or Windows Service? Which wizard adds what code where? And where can you fill in your application's implementation?
I am not here to tell you the underlying theory of what DCOM is and how it works. There are several other great articles here on The Code Project which can help you in that department.
Some of the features of VS.NET - and Windows system programming concepts - we'll use and explore here are:
- the ATL project wizard
- implementation of a Windows Service
- smart pointers
- connection points
- MFC support for connection points
- MFC support for implementing connection points
These will be used to develop a sample client/server system to say "Hello, world from < machine >" to the user. Just as the basic "Hello, World!" sample can enlighten one as to what the starting point for development of a wide array of application types is, so too will this example serve to walk you through developing the most basic of DCOM client/server systems.
My purpose in writing this tutorial series is to document exactly which steps are followed and which Visual Studio .NET 2003 features come into play while developing a DCOM client/server system. There is a long list of actions to be taken; and, in some cases, leaving out an action or doing steps out of order can lead to incorrect results.
Follow Along or Reference the Sample Code
There are two parallel means by which this tutorial can be followed. The first and the recommended means is to open up Visual Studio .NET 2003, and reference this tutorial on your screen alongside your development (or print the tutorial pages as you like) and simply complete the tutorial's steps in the Visual Studio .NET 2003 environment as you read along.
The other means to follow this tutorial is to reference the sample code, accessible via the download link at the top of each step of the tutorial (e.g. the download links at the top of this page). However, it's best to only use the sample code to check your work as you do the steps in this tutorial.
It has been my experience - with previous versions of this series - that those who simply skip to the end of the tutorial end up having the most difficulty, because they are not aware of the interplay of the various stages of the development process and how the final results fit together.
The development environment for the production of this tutorial is thus:
- Operating system: Microsoft Windows XP Professional, Service Pack 2
- Development environment: Microsoft Visual Studio .NET 2003
The recommended action is to do the development all in one machine, and - for production purposes - to use two network-connected computers (one as the 'server' and the other as the 'client') to execute the final results. One of the said computers can be the machine also used for development; in this case, it is recommended you make the said machine the 'server'. It is recommended that both computers have Windows installed, and that the 'server' computer be the machine with the more up-to-date and advanced Windows version installed. Take a moment, before you begin, to note the host names or network addresses of each of your testing computers.
What this Tutorial Assumes
I have a motto: never write anything if it asks too much of the reader, and not enough of the writer. To this end, I am going to tell you straight away what this tutorial assumes that you know. I would also include a 'Who needs this tutorial" section, much like they include a "Who needs to read this book," but I'll let you be the judge of whether or not you need something.
This tutorial assumes that:
- You know how to use a Windows-based computer;
- You know how to use Visual Studio .NET 2003 (although only beginner-level knowledge is needed);
- You're familiar with basic MFC programming;
- You're familiar with COM concepts and realize that ATL is a helpful tool for implementing COM programs and components;
- You know how services work under Windows 2000 and XP;
- And that you're developing all this on Windows 2000 and XP or higher.
This tutorial is designated as a beginner-level tutorial; i.e. beginners at using COM/DCOM. If you have any questions, post the question to the message doards, shown below each step's article. Please favor me by posting your questions to the appropriate step's message board. I will also be sent an email with your question. No general COM/DCOM programming questions, please.
Conventions used in this tutorial are given below.
Code fragments will appear in their own yellowish blocks in the page, and in monospaced font. Lines of code that I ask you to add will appear in bold, as is shown below:
CAnotherClass class; class.AnotherFunc();
If a code snippet is fairly long, ellipses (. . .) will be added to the code listing in place of the omitted code, for compactness. For example:
HRESULT hResult = S_OK;
hResult = class.Func();
In this tutorial, I have adopted the Microsoft variable name and notation conventions, including Hungarian notation. Variables which are members of a class will be prefixed with an 'm_', such as
m_szDisplayName. Names of all the user-defined types are initial-caps, and class names are prefixed with 'C', interface names with 'I', and the names of event source interfaces (so-called dispinterfaces) are prefixed with 'D' instead of Microsoft's convention, '_I'. For example:
dispinterface DHelloWorldEvents instead of
Function names, method names, variables, symbols, and compiler keywords in the text will all be shown in a fixed-width font. Here are some examples:
Client/server System Design
We will proceed step by step. In this tutorial, you will develop:
- A DCOM server, implemented as a Windows Service. This server will expose a '
SayHello()' method which will say hello to the client user with a connection point.
- An MFC client, with support for smart pointers and connection points. We'll even use the ClassWizard (the VS.NET version) to implement the connection point handling (!).
The design for what we'll develop in this tutorial is as shown in Figure 1 below:
Figure 1: The way things will work.
As you can see in Figure 1, our software will follow a simple pattern:
- The client will call a
- The server will say hello to the client by firing an event over the network.
- The client will show the user a message in response to this event to indicate that the server did indeed say, "Hello!"
We'll start by doing step 1 of the tutorial in this article, and then you can go on to the next step of the tutorial by simply clicking the Next >> link at the bottom of this page.
- Step 1: Create the server, HelloWorldServ.NET, using the ATL project wizard.
- Step 2: Modify the starter files provided by the ATL project wizard.
- Step 3: Add a simple ATL object,
HelloWorld, to the server, to expose our functionality.
- Step 4: Add a method,
SayHello(), to the server, which fires the event that the client handles.
- Step 5: We look at the connection points and set up the server's end of one.
- More steps coming soon - this tutorial series is still being finished.
When the steps above are done - including those which are coming soon, we should have a working system as per the design in Figure 1. We start our tutorial series with Step 1, where we have the ATL project wizard in Visual Studio .NET 2003 generating the skeleton code and starter files for the server project, which we'll call HellWorldServ.NET.
Step 1: Create the Skeleton HelloWorldServ.NET Server with the ATL Project Wizard
Close anything you're working on in Visual C++ .NET and save the changes. Then close any open solution(s) too. Unlike in VS6, there is no single "File > New" command to choose to start a new __________. Instead, as shown in Figure 2, below, click the File menu, point to New, and then click Project:
Figure 2: Selecting the new project command in Visual Studio .NET 2003.
The command opens up the New Project dialog box, which is shown below in Figure 3. Open the Visual C++ Projects folder, and then the ATL folder, and then click ATL Project. Note how the selections on the right hand pane of the New Project dialog box are ATL Project, ATL Server Project, and ATL Server Web Service. Here are the types of projects the three options generate:
- ATL Project: A traditional ATL/COM server project, just like you'd get with VC6's ATL COM AppWizard. This choice is the one we want.
- ATL Server Project: A web application project which is hosted on a web server.
- ATL Server Web Service: An XML web service which also exposes functionality from COM objects. See a future tutorial for more on this.
Figure 3: Selecting an ATL server for the type of project we want to create.
I've typed the name "HelloWorldServ.NET" for this project; however, you may feel free to give the project whatever name (and folder on your computer) suits you. The figure below shows the dialog box as I have filled it out. Note the More button on the lower-left hand corner of the dialog box. Click the More button to reveal other settings. We want to actually put our client and server both in the same workspace, or, in Visual Studio .NET-ease, the same solution. One solution can host several projects, just like workspaces did in VC6. Since we're going to make both a server and a client in this tutorial, we'd better give the solution and the projects different name(s), and let the solution have its own directory, as shown in Figure 4, below:
Figure 4: Clicking the More button, and then filling in the settings for the project's solution.
As you can see, I called the solution "HelloWorld.NET," and asked Visual Studio .NET to create a special directory just for the solution. Note how I then changed the project's name to "HelloWorldServ.NET" since this is a project created with Visual Studio .NET, this is a "Hello, World!" example, and we're creating the server side of the application. Click OK to continue once you're satisfied. This displays the ATL Project Wizard, as shown below in Figure 5. The wizard opens with the Overview tab selected. To change the wizard's settings, click the Application Settings tab, and choose settings as shown:
Figure 5: Choosing settings for our server.
Notice that I left the 'Attributes' checkbox unchecked above. Just what are attributes? Well, as the documentation explains, starting with Visual C++ .NET, the compiler recognizes the presence of attributes in a source file and is able to dynamically parse and verify them during compilation. So the attributes help you specify special elements of the programs without the attendant code and declarations that used to go along with it.
However, let's not use attributes here since this is a tutorial, and what good would it be to hide things from you while you're doing the tutorial? So leave the Attributes box unchecked, as shown above in Figure 5.
Why a Service?
A Windows Service is a great type of process to have as your ATL/COM server. Windows Services, in my experience, have performed better as DCOM servers. Services can live while the machine is not logged on, whereas most EXE programs may not run. Also, services are totally non-interactive, which is just fine when all you want your components to do is perform routine system tasks, such as reading files or running programs, or providing monitoring services. You don't want Windows popping up all the willy-nilly, say, in your server computer sitting in a room in Ireland when you are running the client over in India. Plus, services are able to be started and stopped, and kept track of, using the Control Panel.
And for that Matter, Why an EXE and not DLL?
See above as far as the standalone EXE is concerned. A DLL is not very utilitarian as a remote server, because all the DLLs *must* be mapped into the address space of an EXE process on the server system. A special EXE process which maps the DCOM server DLL into its address space, and then remotes the DLL's component(s), is known as a surrogate. DLLs and surrogates are altogether complicated beasts to maintain and configure when you need remote access to your components. Especially since these are not reference-counted or monitored by the system, in case the number of clients drops to zero or if the surrogate hangs, leaving you dead in the water. So a service is my favorite choice.
Figure 6: Reviewing our settings in the ATL project wizard of Visual Studio .NET 2003.
To review our settings, click the Overview tab. The settings displayed should look like those shown in Figure 6. If they're different, then go back. Click Finish to have the ATL project wizard generate the HelloWorldServ.NET starter program. If all is well, the Visual Studio Solution Explorer window should display contents similar to those shown below, in Figure 7:
Figure 7: What the Solution Explorer should look like after finishing the ATL project wizard.
Now we are ready to go on to the next step, modifying the source files. We'll start with modifying in step 2, which is the next step of this tutorial. Click the Next >> link below to proceed to step 2. Click Questions and Answers (coming soon!) to go to the tutorial's FAQ and source code download archive.
Next >>Questions and Answers - coming soon!
Tip: If you're having trouble or can't understand something, it's often the case that you just went ahead as far as you could in this tutorial without following thoroughly, and downloaded the code for the latest step that was done. Perhaps if you go back to the previous steps, and work through the tutorial in the places where it wasn't clear, may help. Also, it could be because there are still more steps to be written! Stay tuned!
Tip: Also, if you have a question, go ahead and post it to the message board, below, which is at the bottom of this article page. I will get an email when you do so, and then everyone can see your question and my answer. Don't forget to rate this article either! If you gave it anything less than 5, then post to the message board the reason why, so I can make these articles better for everyone.
Acknowledgements and Attributions
Thanks go to Dr. Richard Grimes, whose book, Professional DCOM Programming (1998, Wrox Press) was an invaluable technical reference and sourcebook on all things DCOM. Reading of this book should not be necessary to understand or complete this tutorial series.
I would like to acknowledge the contributors to various articles and columns in MSDN Magazine (formerly Microsoft Systems Journal, or MSJ), whose work, reprinted in the MSDN Library, helped me through the jungle of DCOM. This included columns by George Shepard and Don Box, two very knowledgeable COM experts. Thanks also go to Charles Steinhardt, and Tony Smith, two authors who have written for Pinnacle publishing's Visual C++ .NET Developer.