Creating Web Services Using ATL

ATL Server is a set of native—not managed—C++ classes that developers can use to create Web-based applications, Web services, and other server applications.

Writing a Web Service in ATL

Now that I’ve introduced ATL and its role in writing Web server components, let’s move on to see how to write a Web service in ATL. So that you can compare and contrast managed C++ Web services and those written in ATL, the following exercise creates another version of the TemperatureConverter Web service from Chapter 23 written in ATL.

Creating the Code Skeleton

  1. On the File menu, select New and then Project to open the New Project dialog box.

  2. Expand the Visual C++ Projects folder in the left pane, and click on the ATL subfolder. Select ATL Server Web Service in the right pane. Call the project AtlConverter.

    click to expand

  3. Click OK to bring up the ATL Server Project Wizard.

    click to expand

    This wizard has several pages that let you configure the ATL Server code and build options; some of the most important options are described in the sidebar “ATL Server Project Options” earlier in this chapter. In this case, you’ll use the default options, so simply click Finish to tell the wizard to generate the files.

Modifying the Interface

If you open Solution Explorer, you’ll see that the solution contains two projects, one for the ISAPI part and one for the COM ATL part. We’ll concentrate on the ATL part of the project because no changes need to be made to the ISAPI project.

As I’ve explained, the behavior of COM objects is defined by the interfaces they expose. When you create a COM object in an ATL project, the wizard creates a single custom interface for you that will define the methods your COM object will expose. Here’s the listing from AtlConverter.h for the skeleton interface created by the wizard:

[ uuid("2863F2DA-E84A-4B14-8FDF-3C1669558950"), object ] __interface IAtlConverterService { // HelloWorld is a sample ATL Server web service method. // It shows how to declare a web service method and its // in-parameters and out-parameters [id(1)] HRESULT HelloWorld([in] BSTR bstrInput, [out, retval] BSTR *bstrOutput); // TODO: Add additional web service methods here };

The __interface keyword introduces an interface definition, and the interface is called IAtlConverterService.


By convention, COM interface names begin with the letter I.

The interface has two attributes; in this case, they are part of the metadata needed by the COM object rather than by the .NET Framework. The UUID is the unique identifier that COM uses to identify this interface; it is automatically generated by the wizard. The object attribute is used to identify this interface as a COM interface.

Interfaces provide the definition of functionality without providing any implementation, so all the interface contains is a function prototype. Notice how this function uses COM types rather than .NET Framework types; this is because Web services will not necessarily be talking to .NET clients, so they cannot use .NET types.

The id(1) attribute before HRESULT assigns a dispatch ID, so this method can be used as an Automation object, and the in, out, and retval attributes control the marshaling of data into and out of the method.

The following example shows how to add the temperature conversion methods to the interface.

  1. Open the AtlConverter.h header file and locate the IAtlConverterService interface definition. Comment out or remove the existing definition of the HelloWorld method.

  2. Add two method definitions to the IAtlConverterService definition so it looks like this:

    __interface IAtlConverterService { [id(1)] HRESULT ConvertF2C([in] double dFahr, [out, retval] double* dCelsius); [id(2)] HRESULT ConvertC2F([in] double dCelsius, [out, retval] double* dFahr); };

These are typical COM method definitions: both return HRESULT values, the only type that COM methods are allowed to return. Input parameters are marked with in attributes, and anything that is returned must be declared as a pointer and have the out attribute. You can’t use the return value from a COM method to return anything other than a COM status return, so if you want a method that will act like a function in languages such as Microsoft Visual Basic, you have to mark an out parameter with the retval attribute to show that it can be used as a function return value.

The two id attributes are used to allow these methods to be called via automation from languages that need automation support.

Providing the Implementation

Now you need to add the implementation of the methods. All the implementation is in the CAtlConverterService class, which is derived from IAtlConverterService. This means that it has to implement all the methods defined in the interface.


A C++ class can inherit from an interface, which means it inherits the function definitions defined by the interface. Because the interface itself doesn’t provide any implementation, it is up to the derived class to implement all the necessary methods.

Note the attributes at the top of the CAtlConverterService class implementation:

[ request_handler(name="Default", sdl="GenAtlConverterWSDL"), soap_handler( name="AtlConverterService", namespace="urn:AtlConverterService", protocol="soap" ) ] 

The request_handler attribute is added to a class to make it an ATL Server class that can handle HTTP requests, and it causes the compiler to add the correct base classes to the code. The name parameter specifies the name of the handler, and the sdl parameter gives the name of the compiler-generated handler that will return the WSDL for this request handler.

The soap_handler attribute is applied to a class to provide the methods for handling SOAP method calls and for exposing information about the class by means of WSDL. The name parameter specifies the name of the Web service; the default is to use the project name with Service appended. The namespace parameter provides a unique namespace for the service; if none is provided, the name of the class is used instead. The protocol parameter defines the protocol that will be used to access this service; the only one supported at present is SOAP, and it is taken as the default.

  1. Open the AtlConverter.h header file if it isn’t already open, and locate the CAtlConverterService class definition. Comment out or remove the existing implementation of the HelloWorld method.

  2. Add the implementation for the ConvertF2C and ConvertC2F methods to the class, as shown here:

    [soap_method] HRESULT ConvertF2C(/*[in]*/ double dFahr, /*[out, retval]*/ double* dCelsius) { // Check the return value if (dCelsius == 0) return E_POINTER; *dCelsius = ((dFahr - 32) * 5) / 9.0; return S_OK; } [soap_method] HRESULT ConvertC2F(/*[in]*/ double dCelsius, /*[out, retval]*/ double* dFahr) { // Check the return value if (dFahr == 0) return E_POINTER; *dFahr = (9/5.0 * dCelsius) + 32; return S_OK; }

    Both methods are prefixed with the soap_method attribute, which is attached to methods in a Web service. Adding this attribute exposes the method as a Web method with a corresponding WSDL description. The calculations are the same for the .NET Web service, but the results are returned through the out parameters. Because these are pointers, both output parameters are checked before assignment, and a COM E_POINTER error code is returned if either pointer has a null value.

    Both methods also return the S_OK COM return code, indicating that the function completed successfully.

  3. Build the project. Provided you haven’t made any coding errors, you’ll find that the project is compiled, linked, and automatically deployed to the virtual directory of the Web server. Here are the appropriate entries from the build log for the ATL Server project part of the service:

    Compiling... AtlConverter.cpp Linking... Creating library Debug/AtlConverter.lib and object Debug/AtlConverter.exp Deploying the web files... Copied file from c:\AtlConverter\AtlConverter.disco to c:\inetpub\wwwroot\AtlConverter\AtlConverter.disco Copied file from c:\AtlConverter\AtlConverter.htm to c:\inetpub\wwwroot\AtlConverter\AtlConverter.htm Copied file from c:\AtlConverter\Debug\AtlConverter.dll to c:\inetpub\wwwroot\AtlConverter\AtlConverter.dll

The files that are copied over are slightly different from those copied for a .NET Web service. There are two DLLs, one for each of the ATL Server and ISAPI parts of the project, a DISCO file that contains details of how to get the WSDL for the service, and an HTML page that provides basic information about the service.

If you open the DISCO file, you’ll see that it looks like this:

<?xml version="1.0" ?> <discovery xmlns=""> <contractRef xmlns="" ref="http://myhost/AtlConverter/AtlConverter.dll? Handler=GenAtlConverterWSDL" docRef="http://myhost/AtlConverter/AtlConverter.htm"/> </discovery>

The name myhost is the name of the machine on which the service is installed. When a client wants the WSDL, the ATL Server DLL is asked to provide it by passing it the name of the compiler-generated WSDL handler, and the name given is the same as in the request_handler attribute for the CAtlConverterService class.

Using ATL Server

You can now use the Web service in the same way you’d use a .NET Web service. The following steps show you how to access an ATL Server Web service from code.

  1. Create a new Visual C++ Console Application (.NET) project, and call it UseAtlServer.

  2. Add a Web Reference to the project by right-clicking on the project name in Solution Explorer and selecting Add Web Reference from the context menu. This displays the Add Web Reference dialog box, which is illustrated in Chapter 23.

  3. Click on the Web Services On The Local Machine link in the left pane. This might take a few minutes to refresh.

  4. The top part of the left pane displays the ASP.NET Web applications on the local machine. Scroll down the list in the left pane until you come to the section headed Discovery Documents, and look for the AtlConverter entry. Check that the URL is http://localhost/AtlConverter/AtlConverter.disco.

  5. Click on the AtlConverter link to display the Discovery Page for the
    service. You can then click on View Service to see what methods the service exposes:

    click to expand

    When you’re satisfied that this is the service you require, click the Back button in the navigate toolbar to go back to the Discovery page. From there you can simply click Add Reference to add a reference to the project.

    When the code generation has finished, you’ll find that your project has a new header file, WebService.h, which in turn includes a file named after the machine on which the Web service is installed. Because the service is installed on the local machine, the include file is called localhost.h. If you haven’t already read it, refer to Chapter 23 for details about how the proxy class is generated in C++ and added to the client project. You must add the following #include directive to the top of UseAtlServer.cpp so code in that module can use the proxy class. The using directive lets you use the proxy class without having to qualify it with the namespace name:

    #include "WebService.h" using namespace localhost;
  6. To use the Web service, modify the _tmain function in UseAtlServer.cpp as follows:

    try { AtlConverterService* ps = new AtlConverterService(); double d = ps->ConvertF2C(47.5); Console::WriteLine(S"47.5F is {0}C", __box(d)); } catch(Exception* pc) { Console::WriteLine(pc->Message); }

    The proxy class is called AtlConverterService, which was the name given for the service in the soap_handler attribute of the ATL Server class. You can call the methods exposed by the service in the same way you would any COM object.

  7. Build the project and run it from the command line. If all is working correctly, you should see the converted temperature displayed as the program’s output.

Microsoft Visual C++  .NET(c) Step by Step
Microsoft Visual C++ .NET(c) Step by Step
ISBN: 735615675
Year: 2003
Pages: 208 © 2008-2017.
If you may any questions please contact us: