Turn COM Objects Into Web Services
Expose existing ActiveX DLLs to users at other locations and on other platforms with Microsoft's SOAP Toolkit.
by Marc Mercuri

Web Services in the Enterprise 2002

Technology Toolbox: XML, VB6, SOAP Toolkit 3.0

Many development shops have the luxury of moving to VB.NET and C#. However, your corporate development team might be required to use VB6 to ensure compatibility with existing applications. Thanks to Microsoft's Simple Object Access Protocol (SOAP) Toolkit, though, you don't have to miss out on the benefits of Web services. The SOAP Toolkit provides an easy-to-use tool for taking ActiveX DLLs you've created in VB6 and enabling them for use with SOAP. This lets you make your component functionality available as a service over the Web, turning existing COM components into Web services.

SOAP revolutionizes your ability to write distributed applications. You can use it to invoke components in a way that's platform-neutral and location-agnostic. SOAP sends a request message to a server to execute a component function. The server processes the request, executes the function, and returns a response message to the client. The messages are written in XML, and several protocols can transport them to and from the server. The most common (and my focus here) is HTTP—the same protocol existing Web servers use.

SOAP's ability to employ HTTP as a transport mechanism enables you to create apps that service clients on the same PC, the same network, or across the Internet. XML is platform-neutral, so you can write and run those clients under Windows, under Unix, or on a handheld/wireless device.

Figure 1. Build a VB6 DLL.

Begin with a simple ActiveX DLL you can use with the SOAP Toolkit. One common scenario is a survey on a Web page that asks end users questions and records responses. Then expand this scenario to make a survey component that's available to other apps and Web pages. The sample DLL—TestSurvey—exposes three functions: RequestSurvey, RespondToSurvey, and SurveyResults.

Create a new ActiveX DLL project in VB6 and call it TestSurvey. VB adds a class named Class1 by default; rename it to Survey. The SOAP Toolkit requires you to mark DLLs for unattended execution and retention in memory. Open the Project Properties and set those values (see Figure 1).

Continue by hard-coding the return values. Enter this code into the Survey class, then make TestSurvey.dll:

Option Explicit
Public Function RequestSurvey( _
   intSurveyID As Integer) As String
Dim strSurvey As String
strSurvey = "Do you believe Web " & _
   "Services will revolutionize " & _
   "development?"
RequestSurvey = strSurvey
End Function
Public Sub RespondToSurvey(intSurveyID _
   As Integer, blnAgree As Boolean)
'Database code to save values goes here
End Sub

The first routine returns the survey question for survey number intSurveyID, followed by one that populates the database with the return value for Survey number intSurveyID. Then you read responses from the database and populate a text response to the caller:

Public Function DisplaySurveyResults() As String
Dim strSurveyResults As String
strSurveyResults = "Out of 20 total " & _
   "respondents, 18 people agreed," & _
   "while 2 people disagreed."
DisplaySurveyResults = strSurveyResults
End Function

Open Up the SOAP Toolkit
Now that you have an ActiveX DLL, run the SOAP Toolkit's Web Services Description Language (WSDL) generator wizard. Find it under Programs | Microsoft Soap Toolkit Version 3 | WSDL generator. The generator examines the COM interface of an existing DLL and generates several files with the same base name and WSDL, Web Services Meta Language (WSML), and ASP extensions. These files expose the functions of your DLL and allow SOAP-enabled clients to call them.

The generator greets you with a welcome screen. Click on the Next button to bring up the first input screen. It reveals a new option in the Toolkit's 3.0 version that lets you select a configuration file. A configuration file lets you reload and change settings for components you've used already with the generator. Although you won't use configuration files for this article's sample app, they can help if you develop additional methods for your component or move the component to a different server.

Figure 2. Expose Your Methods.

The next screen prompts you to enter a name for your Web service and the location of your existing DLL. Enter TestSurvey as the name of the service, identify the location of TestSurvey.dll in the local-path field, and click on the Next button. The wizard asks you to choose which classes and methods you want to expose as part of your Web service. You should expose all the TestSurvey component's methods (see Figure 2).

The next screen in the wizard asks you to identify your server's location and the mechanism it'll use to listen for requests from SOAP clients. For your testing, set the Listener Uniform Resource Identifier (URI) field to http://localhost/testsurveylisten. (If you prefer, you can replace localhost with the IP address or Web address of the server that'll house the service.)

The wizard presents two options for listener type—Active Server Pages (ASP) or Internet Server API (ISAPI). ISAPI—the default—provides better performance overall. However, use the ASP listener if you'd like to examine the requests as they arrive. The wizard generates an ASP file that uses VBScript to call the SoapServer30 object. You can modify the page readily, adding in your own code. This lets you examine the contents of incoming messages and/or execute code as clients send requests to the server.

Now select the ASP listener. Accept the defaults when you see a prompt for URI information to place in the WSDL file. Next, specify a location for the generated files and configuration information. This completes the wizard, which now reads the interface from the COM component you specified earlier and generates four new files—TestSurvey.wsdl, TestSurvey.wsml, TestSurveyClient.wsml, and TestSurvey.asp. The wizard places them in the directory you specified in the previous screen.

The generator saves all the values you entered on the previous screens and stores them in the configuration file TestSurvey.WGen. The generator's first screen had asked for an optional configuration file. If you need to rerun the generator, you can use this file to prepopulate all the screens, making it easier to add methods or point the WSDL file to a new server. (To test this on a secondary server, copy and register TestSurvey.dll on a server that has the SOAP Toolkit installed. Then copy the files the wizard generated to a directory on that machine.)

Examine the Files
Next, examine the files from the generator. The ASP page contains interpreted VB code that invokes your Web service's methods. The WSDL file is an XML definition for use by clients outside your intranet. A SOAP-enabled client that wants to access your Web service must be able to understand what the method and parameter names are. The WSDL file makes this possible by exposing the request and response definitions for your service in XML.

The server uses a WSML file internally for its XML definitions. The Toolkit's 3.0 version generates two WSML files. TestSurvey.wsml identifies the ProgID of your TestSurvey DLL and also contains mappings of the request messages displayed in the WSDL file to the COM interface (see Listing 1). TestSurveyClient.wsml contains any complex data-type mappings that the client uses and provides no server-based information. You can delete TestSurveyClient.wsml—it contains no mappings because your TestSurvey component deals only with simple data types.

The WSDL file breaks out all your methods into the separate request and response XML message elements the service exposes (download the code project here). In SOAP, the client sends the Web service a request message that provides a name attribute comprising the class name, a period, and the method name. The file contains the Survey.RequestSurvey request-message element. The generator created this message name automatically by combining the class name (Survey) and method name (RequestSurvey) in your DLL.

When it receives the request message, the server executes the functionality of the Web service and returns a response message to the client. The name element is almost identical to that of the request message, with the generator appending the word Response. For example, the response to the RequestSurvey method is Survey.RequestSurveyResponse.

The generator assigns each parameter as an XML part element, matching the name attribute to your DLL function's parameter. The generator also translates the parameter's data type to the equivalent in SOAP, if one exists. The request message contains the parameters the Web service's method signature requires, and the response message contains both the parameters and the return value. (If the method is a subroutine, it returns only the parameters.)

The generator tries to map component parameters to simple types when it creates the WSDL file. If the generator can't map the data type a method uses, it represents the parameter type with seven question marks (see Table 1 and the sidebar, "Handle ADO Recordsets With the SOAP Toolkit," to see how the Toolkit supports common types).

Create a Virtual Directory
Now make the files you've generated available using your Internet Information Server (IIS) Web server. Simply create a virtual directory in IIS that points to the files. You can add the virtual directory using Control Panel | Administrative Tools | Internet Information Services. Expand the view and select the Web server from which you'd like to provide the service. (This is normally the Default Web Server on nonproduction Web servers.)

Right-click on the server name and select New Virtual Directory. This fires up the Virtual Directory creation wizard. The wizard first prompts you for an alias, which should map to what you provided in the WSDL generator as the directory of the Web service. Use the alias testsurveylisten to mirror the example.

When the wizard asks for the path to the directory, provide the location of your generated WSDL file, WSML file, and ASP page. Continue through the remaining dialogs and complete the wizard. Your Web service is now online and available.

Now create a sample SOAP client to consume the services. Start by creating a new VB application project:

Option Explicit
Private Sub Form_Load()
Dim soapClient As Object

Download the text for Survey #1 when the form loads. Create an instance of the SOAP Client object:

Set soapClient = CreateObject("MSSOAP.SoapClient30")

Next, initialize the SOAP client, using the WSDL the wizard generated:

Call soapClient.mssoapinit _
   ("http://localhost/testsurveylisten/testsurvey.wsdl", _
   "TestSurvey")

The soapClient object now references your Web service, so you can call soapClient as if it were an instance of the TestSurvey.Survey object, request the question for Survey #1, then assign it to lblSurveyQuestion:

lblSurveyQuestion.Caption = soapClient.RequestSurvey(1)
Set soapClient = Nothing
End Sub

When the user clicks on the Submit button, send the response to Survey #1. Also, request the text describing the survey response and display it in a message box. Start by creating and initializing an instance of the SOAP Client object:

Private Sub cmdSubmit_Click()
Dim soapClient As Object
Dim strSurveyResults As String
Set soapClient = CreateObject("MSSOAP.SoapClient30")
Call SoapClient.mssoapinit _
   ("http://localhost/testsurveylisten/testsurvey.wsdl", _
   "TestSurvey")

Now send the survey response and retrieve the survey results:

Call soapClient.RespondToSurvey _
   (1, optAgree.Value)
strSurveyResults = soapClient.DisplaySurveyResults(1)

Finally, display the results in a message box:

Call MsgBox(strSurveyResults, _
   vbInformation + vbOKOnly, "Survey Responses")
End Sub
Figure 3. Deploy Your Web Service.

In your production code, add a label control named lblSurveyQuestion, along with two radio buttons. Name one optAgree (with the caption "I Agree") and the other optDisagree (with the caption "I Disagree"). Add a command button named cmdSubmit with the caption "Submit Response" (see Figure 3).

Communicate With the Service
This client uses all three methods your service exposes. When you load the form, the client sends a request to the service for the survey question for Survey #1. The program displays the response from the service as the caption in the lblSurveyQuestion field.

The code in the Form_Load event shows how you communicate with the service. Download the text for Survey #1 when the form loads, create an instance of the SOAP client object, then initialize the SOAP client, using the WSDL the wizard generated:

Private Sub Form_Load()
Dim soapClient As Object
Set soapClient = CreateObject("MSSOAP.SoapClient30")
Call soapClient.mssoapinit _
   ("http://localhost/_
   testsurveylisten/testsurvey.wsdl", "TestSurvey")

The soapClient object now references your Web service, enabling you to call the soapClient as if it were an instance of the TestSurvey.Survey object. Then you can request the question for Survey #1 and assign it to lblSurveyQuestion:

lblSurveyQuestion.Caption = _
   soapClient.RequestSurvey(1)
Set soapClient = Nothing
End Sub

Accessing the service is straightforward. Create an instance of the SOAP client object, using the ProgID MSSOAP.SoapClient30. Next, initialize the client with the information you provided originally to the SOAP Toolkit Wizard—the URI for the WSDL file and the Web service name. As this line executes, the object downloads the WSDL file from the specified location, examines the XML, and identifies all the methods, method parameters, and method return values the service exposes.

You can now call the service's methods directly from VB code as if they were methods compiled into the MSSOAP.SoapClient30 object. This lets you call your service's RequestSurvey method through soapClient.RequestSurvey(1). You use the same RequestSurvey method twice in the cmdSubmit_Click event, calling both the SubmitResponse and DisplaySurveyResults methods of your service.

The SOAP Toolkit doesn't work miracles. If you didn't design and optimize your component to serve 10,000 hits per minute on your internal network, it won't fare any better on the Web. The SOAP wrapper only exposes your component; it doesn't enhance or optimize your code. However, the SOAP Toolkit is easy to use, and it can move you quickly into the world of Web services. If you're expecting a significant number of calls to your Web service component, consider placing it in COM+ and looking at points of performance optimization.

About the Author
Marc Mercuri is the vice president of applications development for Gazelle Systems Inc. He has architected, managed, and developed projects for the CRM, financial, educational, hospitality, entertainment, medical, POS, and publishing industries. Reach Marc at .