Abstract: XML Web Services is rapidly becoming the technology of choice for distributed application and application-integration, over Internet. The caller application uses the standard protocol (such as HTTP or SMTP) to send specially-formatted XML messages (known as SOAP request envelope); the server application in turn does the processing and sends back the results also as specially formatted XML message (known as SOAP response envelope). The standards-based notion of Web Services enables these two applications; possibly residing on two totally different platforms, and written using varied programming languages and tools; to interact without and platform- or programming language-worries. XML Web Services is receiving more and more vendor and tools support, and the technology itself is maturing rapidly. Microsoft, IBM, and others are working to define the essential layers (such as security, transaction-support, Web Services reliability, coordination and routing) over Web Services.
This article illustrates writing XML Web Services client applications in Visual C++, using Microsoft XML Core Services (or MSXML), Microsoft SOAP Toolkit Version 3, and PocketSOAP.
- The first example uses the MSXML XMLHTTP component to invoke a Web Service written using Apache SOAP.
- The second example uses the MSXML ServerXMLHTTP component to invoke a Web Service written using (ASP).NET. This example illustrates calling a Web Service using HTTP GET, HTTP POST, and SOAP.
- The third example uses Microsoft SOAP Toolkit Version 3 high-level API to invoke a Web Service written using GLUE.
- The fourth example uses Microsoft SOAP Toolkit Version 3 low-level API to invoke a Web Service written using (ASP).NET.
- The fifth, and final, C++ sample application illustrates using PocketSOAP to call a .NET Web Service.
Author: Darshan Singh (Managing Editor, {域名已经过期}) Last Updated: February 02, 2003 Download: CPPSOAP.zip (353 KB ZIP file)
1. Using MSXML XMLHTTP
MSXML, the premier XML processing component from Microsoft, is shipped with various versions of Internet Explorer (for example, IE 6.0 ships MSXML version 3 SP2); and is also available as a separate download from the MSDN Web site. If you are writing a C++ desktop client application and need to call a Web Service, one option is to use the XMLHTTP component inside MSXML.
XMLHTTP, a COM wrapper around WinInet (the core HTTP API used by Internet Explorer), allows sending HTTP GET and POST requests and process the response. XMLHTTP is designed to be used on the client-side, and should not be used inside server applications to send HTTP requests to other servers. If you are writing a server-side application, and need to call a Web Service, refer to example 2 below, which uses ServerXMLHTTP.
This first sample application uses MSXML XMLHTTP to POST a SOAP request to the Weather ?Temperature Web Service on the XMethods Web site.
The header file (XMLHTTP1.h):
#ifndef _XMLHTTP1_H_
#define _XMLHTTP1_H_
#include <atlbase.h>
#import <msxml4.dll> named_guids
using namespace MSXML2;
#define CHECK_HR(hr) { if (FAILED(hr)) { throw -1; } }
// SOAP Endpoint URL
static const TCHAR* const g_lpszSOAPEndpointURL =
_T("http://{域名已经过期}:80/soap/servlet/rpcrouter");
// SOAP Request to be posted
static const TCHAR* const g_lpszSOAPReq = _T(
"<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://{域名已经过期}/soap/envelope/' "
"xmlns:xsi='http://{域名已经过期}/1999/XMLSchema-instance' "
"xmlns:xsd='http://{域名已经过期}/1999/XMLSchema'> "
"<SOAP-ENV:Body> "
"<ns1:getTemp xmlns:ns1='urn:xmethods-Temperature' "
" SOAP-ENV:encodingStyle='http://{域名已经过期}/soap/encoding/'> "
"<zipcode xsi:type='xsd:string'>%s</zipcode> "
"</ns1:getTemp> "
"</SOAP-ENV:Body> "
"</SOAP-ENV:Envelope> ");
#endif // _XMLHTTP1_H_
The source code file (XMLHTTP1.cpp)
#include "stdafx.h"
#include "XMLHTTP1.h"
//------------------------------------------------------------------------------
// Function uses XMLHTTP to POST a SOAP request to the Temprature Web Service
// and then uses MSXML DOM to process the SOAP response XML text.
//------------------------------------------------------------------------------
float CallWebService(LPCTSTR szZipCode)
{
float fTemprature = -999;
USES_CONVERSION;
// SOAP Request Envelop to be posted
TCHAR szSOAPReq[MAX_PATH*2] = {0};
sprintf(szSOAPReq, g_lpszSOAPReq, szZipCode);
//printf(szSOAPReq);
// Create an instance of XMLHTTP Class
CComPtr<IXMLHTTPRequest> spXMLHTTP;
HRESULT hr = spXMLHTTP.CoCreateInstance(CLSID_XMLHTTP40);
CHECK_HR(hr);
// Initialize the Synchronous HTTP POST request
hr = spXMLHTTP->open(_bstr_t(_T("POST")), g_lpszSOAPEndpointURL, VARIANT_FALSE);
CHECK_HR(hr);
// Set the required Content-Type header
hr = spXMLHTTP->setRequestHeader(_bstr_t(_T("Content-Type")), _bstr_t(_T("text/xml")));
CHECK_HR(hr);
// Send the POST request, along with the SOAP request envelope text
hr = spXMLHTTP->send(_bstr_t(szSOAPReq));
CHECK_HR(hr);
if(200 == spXMLHTTP->status) //Success
{
// using MSXML DOM to process SOAP response XML text
CComQIPtr <IXMLDOMDocument2> spResponseXMLDoc;
CComPtr <IXMLDOMNode> spResultNode;
spResponseXMLDoc = spXMLHTTP->responseXML;
spResultNode = spResponseXMLDoc->selectSingleNode(_bstr_t(_T("//return")));
if(spResultNode.p != NULL)
{
fTemprature = spResultNode->nodeTypedValue;
}
}
else
{
printf(_T("\nError: %s\n"), W2A(spXMLHTTP->statusText));
}
return fTemprature;
}
// main, The entry point function
int main(int argc, char* argv[])
{
if(argc < 2)
{//insufficient parameters
printf(_T("\nXMLHTTP1.exe: Sample Web Service client to get the temprature for the given Zipcode.\n"));
printf(_T("\nUsage:\tXMLHTTP1.exe <US_Zipcode>\nExample: XMLHTTP1.exe 98007\n"));
return -1;
}
try
{
HRESULT hr = CoInitialize(NULL);
CHECK_HR(hr);
float fTemp = CallWebService((LPCTSTR)argv[1]);
if(fTemp != -999)
printf(_T("The temprature at zipcode %s is %.2f Fahrenheit.\nPress Enter to continue..."),
argv[1],fTemp);
else
printf(_T("\nError: Invalid Zipcode or failed to get the temprature at zipcode %s. "
"\nPress Enter to continue..."), argv[1]);
}
catch(int)
{
//TODO: Error handling
printf(_T("Exception raised!"));
}
CoUninitialize();
getchar();
return 0;
}
Output:

The header file declares the #import statement so that we can use MSXML4, and declares couple of constant strings (the SOAP endpoint URL and the SOAP request envelope). The main function in the CPP file calls a supporting function CallWebService and passes it the value of the command line parameter (the zip code). The supporting function CallWebService then formats the request SOAP envelope and posts it to the SOAP endpoint URL. The responseXML property contains the response SOAP envelope and the above application uses MSXML DOM and XPath to get the result value.
2. Using MSXML ServerXMLHTTP
If you are writing a server-side application (such as an ISAPI DLL or a COM DLL to be loaded on the server side), and need to invoke a XML Web Service, you can use MSXML ServerXMLHTTP component.
The following sample C++ application illustrates using MSXML ServerXMLHTTP to invoke a .NET Web Service, either by sending HTTP GET request, or HTTP POST request, or posting SOAP and processing the SOAP response.
This sample application invokes the Weather Info XML Web Service to get the detailed weather information for any given valid US zip code.
The header file (ServerXMLHTTP1.h):
#ifndef _SERVERXMLHTTP1_H_
#define _SERVERXMLHTTP1_H_
#include <atlbase.h>
#import <msxml4.dll> named_guids
using namespace MSXML2;
#define CHECK_HR(hr) { if (FAILED(hr)) { throw -1; } }
// --------------------------------------------------------
static const TCHAR* const g_lpszGetURL =
_T("http://{域名已经过期}/WeatherService/Service.asmx/GetWeatherInfo?zipCode=%s");
// --------------------------------------------------------
static const TCHAR* const g_lpszPostURL =
_T("http://{域名已经过期}/WeatherService/Service.asmx/GetWeatherInfo");
// --------------------------------------------------------
static const TCHAR* const g_lpszSOAPEndpointURL =
_T("http://{域名已经过期}/WeatherService/Service.asmx");
static const TCHAR* const g_lpszSOAPAction =
_T("http://{域名已经过期}/WeatherService/GetWeatherInfo");
static const TCHAR* const g_lpszSOAPReq =
_T("<?xml version='1.0' encoding='utf-8'?> "
"<soap:Envelope xmlns:xsi='http://{域名已经过期}/2001/XMLSchema-instance' "
" xmlns:xsd='http://{域名已经过期}/2001/XMLSchema' "
" xmlns:soap='http://{域名已经过期}/soap/envelope/'>"
" <soap:Body>"
" <GetWeatherInfo xmlns='http://{域名已经过期}/WeatherService/'>"
" <zipCode>%s</zipCode>"
" </GetWeatherInfo>"
" </soap:Body>"
"</soap:Envelope>");
// --------------------------------------------------------
static const TCHAR* const g_lpszXPathSelNS =
_T("xmlns:ns1='http://{域名已经过期}/WeatherService/'");
// --------------------------------------------------------
//TODO: Move to resource file
static const TCHAR* const g_lpszOutputMsg =
_T("Weather Information - Last Updated %s\n\n"
"\tLocation: %s (%s)\n\tTemprature: %s\n\tForecast: %s\n\t"
"Visibility: %s\n\tHumidity: %s\n\tPressure: %s\n");
// --------------------------------------------------------
#endif // _SERVERXMLHTTP1_H_
The source code file (ServerXMLHTTP1.cpp)
#include "stdafx.h"
#include "ServerXMLHTTP1.h"
// Utility function
void GetXPathExprValue(CComQIPtr<IXMLDOMDocument2> &spResponseXMLDoc,
LPCTSTR lpszXPathExpr,
LPSTR lpszResultValue)
{
USES_CONVERSION;
CComPtr <IXMLDOMNode> spResultNode;
spResultNode = spResponseXMLDoc->selectSingleNode(_bstr_t(lpszXPathExpr));
if(spResultNode.p != NULL)
_tcscpy(lpszResultValue, W2A(_bstr_t(spResultNode->nodeTypedValue)));
}
//------------------------------------------------------------------------------
// Function uses ServerXMLHTTP to send a GET/POST/SOAP request to a .NET Web Services,
// and then uses MSXML DOM to process the response XML text.
//
// Illustrates calling a .NET Web Service either by sending a GET request,
// or a HTTP POST or by using the SOAP method.
//
// iMethod parameter:
// 0 : (Default) HTTP GET
// 1 : HTTP POST
// 2 : SOAP
//------------------------------------------------------------------------------
void CallWebService(LPCTSTR szZipCode, int iMethod = 0)
{
float fTemprature = -999;
USES_CONVERSION;
// Create an instance of ServerXMLHTTP Class
CComPtr<IServerXMLHTTPRequest> spServerXMLHTTP1;
HRESULT hr = spServerXMLHTTP1.CoCreateInstance(CLSID_ServerXMLHTTP40);
CHECK_HR(hr);
TCHAR szGetURL[MAX_PATH*2]={0};
TCHAR szPostValue[MAX_PATH*2]={0};
TCHAR szSOAPReq[MAX_PATH*2]={0};
int iPostDataLen =0;
TCHAR szDataLen[10]={0};
switch(iMethod)
{
case 0: // HTTP GET
sprintf(szGetURL, g_lpszGetURL, szZipCode);
// Initialize the Synchronous HTTP GET request
hr = spServerXMLHTTP1->open(_bstr_t(_T("GET")), szGetURL, VARIANT_FALSE);
CHECK_HR(hr);
// Send the HTTP GET request
hr = spServerXMLHTTP1->send();
CHECK_HR(hr);
break;
case 1: // HTTP POST
_tcscpy(szPostValue, _T("zipCode="));
_tcscat(szPostValue, szZipCode);
iPostDataLen = _tcslen(szPostValue);
itoa(iPostDataLen, szDataLen, 10);
// Initialize the Synchronous HTTP GET request
hr = spServerXMLHTTP1->open(_bstr_t(_T("POST")), g_lpszPostURL, VARIANT_FALSE);
CHECK_HR(hr);
spServerXMLHTTP1->setRequestHeader(_T("Content-Type"),
_T("application/x-www-form-urlencoded"));
spServerXMLHTTP1->setRequestHeader(_T("Content-Length"), szDataLen);
// Send the HTTP POST request, along with the SOAP request envelope text
hr = spServerXMLHTTP1->send(szPostValue);
CHECK_HR(hr);
break;
case 2: // SOAP
sprintf(szSOAPReq, g_lpszSOAPReq, szZipCode);
hr = spServerXMLHTTP1->open(_bstr_t(_T("POST")), g_lpszSOAPEndpointURL, VARIANT_FALSE);
CHECK_HR(hr);
// Set the required SOAPAction and Content-Type headers
hr = spServerXMLHTTP1->setRequestHeader(_T("SOAPAction"), g_lpszSOAPAction);
CHECK_HR(hr);
hr = spServerXMLHTTP1->setRequestHeader(_bstr_t(_T("Content-Type")),
_bstr_t(_T("text/xml")));
CHECK_HR(hr);
// Send the POST request, along with the SOAP request envelope text
hr = spServerXMLHTTP1->send(_bstr_t(szSOAPReq));
CHECK_HR(hr);
break;
}
if(200 == spServerXMLHTTP1->status) //Success
{
// using MSXML DOM to process the response XML text
CComQIPtr <IXMLDOMDocument2> spResponseXMLDoc;
spResponseXMLDoc = spServerXMLHTTP1->responseXML;
spResponseXMLDoc->setProperty(_bstr_t(_T("SelectionNamespaces")), g_lpszXPathSelNS);
TCHAR szLastUpdated[MAX_PATH] = {0};
TCHAR szLocation[MAX_PATH] = {0};
TCHAR szReportedAt[MAX_PATH] = {0};
TCHAR szTemprature[MAX_PATH] = {0};
TCHAR szForecast[MAX_PATH] = {0};
TCHAR szVisibility[MAX_PATH] = {0};
TCHAR szHumidity[MAX_PATH] = {0};
TCHAR szPressure[MAX_PATH] = {0};
GetXPathExprValue(spResponseXMLDoc, _T("//ns1:LastUpdated"), szLastUpdated);
GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Location"), szLocation);
GetXPathExprValue(spResponseXMLDoc, _T("//ns1:ReportedAt"), szReportedAt);
GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Temprature"), szTemprature);
GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Forecast"), szForecast);
GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Visibility"), szVisibility);
GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Humidity"), szHumidity);
GetXPathExprValue(spResponseXMLDoc, _T("//ns1:Pressure"), szPressure);
printf(g_lpszOutputMsg, szLastUpdated, szReportedAt, szLocation,
szTemprature, szForecast, szVisibility, szHumidity, szPressure);
}
else
{
printf(_T("\nError: %s\n"), W2A(spServerXMLHTTP1->statusText));
}
}
// main, The entry point function
int main(int argc, char* argv[])
{
if(argc < 2)
{//insufficient parameters
printf(_T("\nServerXMLHTTP1.exe: Sample Web Service client to get "
" the weather information for a valid given U.S. zipcode\n"));
printf(_T("\nUsage:\tServerXMLHTTP1.exe <US_Zipcode> [<Method (0=GET, 1=POST, 2=SOAP)>]\n"
"Examples:\n\tServerXMLHTTP1.exe 98007\n\t"
"ServerXMLHTTP1.exe 98007 1"));
printf(_T("\n\nPress Enter to continue..."));
getchar();
return -1;
}
try
{
HRESULT hr = CoInitialize(NULL);
CHECK_HR(hr);
// The Method (GET[0]/POST[1]/SOAP[2])
int iCallMethod = 0;
if(argc >= 3 && argv[2] != NULL)
iCallMethod = atoi(argv[2]);
CallWebService((LPCTSTR)argv[1], iCallMethod);
}
catch(int)
{
//TODO: Error handling
printf(_T("Exception raised!"));
}
CoUninitialize();
printf(_T("\n\nPress Enter to continue..."));
getchar();
return 0;
}
Output:

The above sample application uses MSXML ServerXMLHTTP component to call a XML Web Service either by sending a HTTP GET, HTTP POST or a SOAP request. The iMethod parameter to the CallWebService supporting function decides which method to use while invoking the Web Service.
The header file imports the MSXML type library, and declares few strings used for sending the Web Service request and to process the response XML. The CPP source code file, first creates an instance of ServerXMLHTTP class, and then based on iMethod parameter, the switch statement sends the HTTP GET, POST, or SOAP request, and if the request was successful (HTTP status code = 200), responseXML DOM object and XPath expressions are used to get the returned weather information.
3. Using Microsoft SOAP Toolkit 3.0 (High-Level API)
The Microsoft SOAP Toolkit is a set of COM components used to:
- invoke Web Services on the client-side,
- map Web Service method calls to the COM object methods, and to
- marshal and unmarshal (that is to create, transmit, read and process) SOAP messages
The following sample application uses the Microsoft SOAP Toolkit version 3.0 high-level API to invoke Domain Name Checker Web Service to see if the specified domain name is availabe or not. Note that the SOAP Tookit has the dependancy on the MSXML, and hence the following header file imports MSXML typelib in addition to the SOAP toolkit type library.
The header file (SOAPToolkit1.h):
#ifndef _SOAPTOOLKIT1_H_
#define _SOAPTOOLKIT1_H_
#include "atlbase.h"
#import <msxml4.dll>
using namespace MSXML2;
#import "C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" named_guids \
exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", \
"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")
using namespace MSSOAPLib30;
#define CHECK_HR(hr) { if (FAILED(hr)) { throw -1; } }
// -----------------------------------------------------------------------
static const TCHAR* const g_lpszWSDL_URL =
_T("http://{域名已经过期}/soap/urn:xmethods-DomainChecker.wsdl");
// -----------------------------------------------------------------------
#endif // _SOAPTOOLKIT1_H_
The source code file (SOAPToolkit1.cpp)
#include "stdafx.h"
#include "SOAPToolkit1.h"
void CallWebService(_bstr_t bstrDomainName)
{
USES_CONVERSION;
CComPtr<ISoapClient> spSOAPClient;
HRESULT hr = spSOAPClient.CoCreateInstance(CLSID_SoapClient30);
CHECK_HR(hr);
hr = spSOAPClient->MSSoapInit(_bstr_t(g_lpszWSDL_URL),
L"", L"", L"");
CHECK_HR(hr);
// Call the Web Service method
WCHAR *pwcMethodName = L"checkDomain";
DISPID dispidFn = 0;
hr = spSOAPClient->GetIDsOfNames(IID_NULL, &pwcMethodName, 1,
LOCALE_SYSTEM_DEFAULT, &dispidFn);
CHECK_HR(hr);
unsigned int uArgErr;
VARIANT varg[1];
varg[0].vt = VT_BSTR;
varg[0].bstrVal = bstrDomainName;
DISPPARAMS params;
params.cArgs = 1;
params.rgvarg = varg;
params.cNamedArgs = 0;
params.rgdispidNamedArgs = NULL;
_variant_t result;
uArgErr = -1;
EXCEPINFO excepInfo;
memset(&excepInfo, 0, sizeof(excepInfo));
hr = spSOAPClient->Invoke(dispidFn, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, ¶ms, &result, &excepInfo, &uArgErr);
CHECK_HR(hr);
if(result.vt = VT_BSTR)
{
printf(_T("Domain %s is %s."), W2A(bstrDomainName), W2A(result.bstrVal));
printf(_T("\n\nPress Enter to continue..."));
getchar();
}
}
int main(int argc, char* argv[])
{
if(argc < 2)
{//insufficient parameters
printf(_T("\nSOAPToolkit1.exe: Sample Web Service client to check "
" whether a domain name is available or not\n"));
printf(_T("\nUsage:\tSOAPToolkit1.exe <DomainName>\n"
"Examples:\n\tSOAPToolkit1.exe {域名已经过期}\n\t"
"SOAPToolkit1.exe {域名已经过期}"));
printf(_T("\n\nPress Enter to continue..."));
getchar();
return -1;
}
try
{
HRESULT hr = CoInitialize(NULL);
CHECK_HR(hr);
CallWebService(_bstr_t(argv[1]));
}
catch(int)
{
//TODO: Error handling
printf(_T("Exception raised!"));
}
CoUninitialize();
return 0;
}
Output:

The header file imports MSXML and SOAP Toolkit type libraries, and declares the Web Service WSDL URL string.
The SoapClient30 class is used to invoke the Web Services and this class is the basis of the SOAP toolkit high-level API. The CPP source code file above creates an instance of SoapClient30 class, followed by calling MSSoapInit member function, passing it the WSDL URL.
The MSSoapInit member function is used to initialize the SoapClient30 object using the WSDL file, and once we do this, the SoapClient30 instance can be used to call the Web Service method, like any other COM object that implements IDispatch interface. Once the SoapClient30 object is initialized using the WSDL file, IDispatch methods (GetIDsOfNames and Invoke) can be called on this object for any of the Web Service method. The above code illustrates this for the checkDomain Web Service method.
4. Using Microsoft SOAP Toolkit 3.0 (Low-Level API)
The SOAP Toolkit low-level API provides the absolute control over the SOAP message serialization and transport. The SoapSerializer30 class is used to create the SOAP message. As in this example, we'll be calling a Web Service over HTTP, we use the HttpConnector30 class instance to send the SOAP request message and receive the SOAP response message, over HTTP. And finally, the SoapReader30 class is used to read the SOAP response message. The SoapReader30 class offers various methods and properties to easily read/parse/extract the information from the SOAP message.
The following sample application uses Microsoft SOAP Toolkit 3.0 low-level API classes to invoke the SearchMusicTeachers Web Service, to find out the music teachers details in the given US zip code. Only Zip code value is accepted as the command line parameter, other values (such as instrument, result count restriction, radius, skill level, etc.) are hard-coded in this sample application.
The source code file (SOAPToolkitLowLevel.cpp):
#include "stdafx.h"
#include <stdio.h>
#include "atlbase.h"
#import <msxml4.dll>
using namespace MSXML2;
#import "C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" \
exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", \
"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")
using namespace MSSOAPLib30;
void CallWebService(_bstr_t ZipCode)
{
ISoapSerializerPtr Serializer;
ISoapReaderPtr Reader;
ISoapConnectorPtr Connector;
HRESULT hr = S_OK;
hr = Connector.CreateInstance(__uuidof(HttpConnector30));
Connector->Property[_T("EndPointURL")] =
_T("http://{域名已经过期}/WebServices/MusicTeachers/MusicTeachers.asmx?wsdl");
hr = Connector->Connect();
Connector->Property[_T("SoapAction")] =
_T("http://{域名已经过期}/NETWebSvcs/MusicTeachers/FindMusicTeachers");
hr = Connector->BeginMessage();
hr = Serializer.CreateInstance(__uuidof(SoapSerializer30));
hr = Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
hr = Serializer->StartEnvelope(_T("soap"),_T("NONE"),_T(""));
hr = Serializer->StartBody(_T(""));
hr = Serializer->StartElement(_T("FindMusicTeachers"),
_T("http://{域名已经过期}/NETWebSvcs/MusicTeachers/"),
_T("NONE"),_T(""));
hr = Serializer->StartElement(_T("ZipCode"),
_T("http://{域名已经过期}/NETWebSvcs/MusicTeachers/"),
_T("NONE"),_T(""));
hr = Serializer->WriteString(ZipCode);
hr = Serializer->EndElement();
hr = Serializer->StartElement(_T("Instrument"),
_T("http://{域名已经过期}/NETWebSvcs/MusicTeachers/"),
_T("NONE"),_T(""));
hr = Serializer->WriteString(_T("0"));
hr = Serializer->EndElement();
hr = Serializer->StartElement(_T("SkillLevel"),
_T("http://{域名已经过期}/NETWebSvcs/MusicTeachers/"),
_T("NONE"),_T(""));
hr = Serializer->WriteString(_T("0"));
hr = Serializer->EndElement();
hr = Serializer->StartElement(_T("Style"),
_T("http://{域名已经过期}/NETWebSvcs/MusicTeachers/"),
_T("NONE"),_T(""));
hr = Serializer->WriteString(_T("0"));
hr = Serializer->EndElement();
hr = Serializer->StartElement(_T("Radius"),
_T("http://{域名已经过期}/NETWebSvcs/MusicTeachers/"),
_T("NONE"),_T(""));
hr = Serializer->WriteString(_T("10"));
hr = Serializer->EndElement();
hr = Serializer->StartElement(_T("RestrictResultsCount"),
_T("http://{域名已经过期}/NETWebSvcs/MusicTeachers/"),
_T("NONE"),_T(""));
hr = Serializer->WriteString(_T("5"));
hr = Serializer->EndElement();
hr = Serializer->EndElement();
hr = Serializer->EndBody();
hr = Serializer->EndEnvelope();
hr = Connector->EndMessage();
hr = Reader.CreateInstance(__uuidof(SoapReader30));
hr = Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), _T(""));
CComQIPtr<IXMLDOMDocument2> spResponseXMLDOM;
spResponseXMLDOM = Reader->Dom;
//TODO: Process the response SOAP XML and display the results
//For now, just printing the response XML text as it is.
USES_CONVERSION;
printf(_T("Response: %s\n"), (const char*)W2A(spResponseXMLDOM->xml));
printf(_T("\n\nPress Enter to continue..."));
getchar();
}
int main(int argc, char* argv[])
{
CoInitialize(NULL);
if(argc < 2)
{//insufficient parameters
printf(_T("\nSOAPToolkitLowLevel.exe: Sample Web Service client to find out "
" music teachers within 10-mile radius of a valid given U.S. zipcode\n"));
printf(_T("\nUsage:\tSOAPToolkitLowLevel.exe <US_Zipcode>\n"
"Examples:\n\tSOAPToolkitLowLevel.exe 98007\n\t"
"SOAPToolkitLowLevel.exe 60195"));
printf(_T("\n\nPress Enter to continue..."));
getchar();
return -1;
}
CallWebService(_bstr_t(argv[1]));
CoUninitialize();
return 0;
}
Output:

We do not make use of the header file in this sample application. The sample source code CPP file above, imports the MSXML and SOAP Toolkit type libraries. The supporting function CallWebService (which is called from the main function), creates instances of SoapSerializer, HttpConnector, and SoapReader classes. The HttpConnector instance is initialized by setting the EndPointURL and the SoapAction properties, and the Connect method is used to initialize the HttpConnector instance by using the WSDL.
Note how the SoapSerializer class is used to precisely create the SOAP request message. This class provides the full control over how the message should look like, by allowing us to specify the namespace value, namespaces prefixes to use, encoding style, and other structural details of the SOAP envelope. The SoapSerializer Init method is used above to associate the request envelope with the transport input stream. When the SOAP request envelope is fully created using the SoapSerializer members, the HttpConnector EndMessage method is called to indicate that the request envelope is ready, and to actually post the SOAP message and receive the response, synchronously.
The HttpConnector OutputStream is used to load the response message into the the SoapReader object. In this particular example, we just access the Dom property on the Reader, to load the response SOAP envelope into a MSXML DOMDocument object. You may parse and process this DOMDocument object to get the individual result values. For brevity, we just print the response XML text as it is in the above example.
5. Using PocketSOAP v1.4.1
PocketSOAP is a COM component that can be used to invoke Web Services. The following sample C++ application uses PocketSOAP v1.4.1 COM component to invoke SalesRankNPrice sample Web Service, to find out the {域名已经过期} sales rank and the price for any given ISBN value.
The source code file (PocketSOAP1.cpp):
#include "stdafx.h"
#include "atlbase.h"
#import "C:\Program Files\SimonFell\PocketSOAP\pSOAP32.dll" named_guids
using namespace PocketSOAP;
void CallWebService(_bstr_t bstrISBN)
{
CComPtr <ISOAPEnvelope> spEnvelope;
HRESULT hr = spEnvelope.CoCreateInstance(CLSID_CoEnvelope);
spEnvelope->SetMethod(_T("GetAmazonSalesRankNPrice"),
_T("http://{域名已经过期}/NETWebSvcs/BookService"));
spEnvelope->Parameters->Create(_T("ISBN"),
bstrISBN,
_T("http://{域名已经过期}/NETWebSvcs/BookService"),
_T(""), _T(""));
CComPtr <IHTTPTransportAdv> spHTTPTransport;
hr = spHTTPTransport.CoCreateInstance(CLSID_HTTPTransport);
spHTTPTransport->SOAPAction =
L"http://{域名已经过期}/NETWebSvcs/BookService/GetAmazonSalesRankNPrice";
_bstr_t bstrEnvelope = spEnvelope->Serialize();
hr = spHTTPTransport->Send(
_T("http://{域名已经过期}/WebServices/SalesRankNPrice/BookService.asmx"),
bstrEnvelope);
CComVariant cvTransport(spHTTPTransport);
spEnvelope->Parse(cvTransport, _T(""));
bstrEnvelope = spEnvelope->Serialize();
USES_CONVERSION;
printf(_T("Response:\n%s"), W2A(bstrEnvelope));
printf(_T("\n\nPress Enter to continue..."));
getchar();
}
int main(int argc, char* argv[])
{
if(argc < 2)
{//insufficient parameters
printf(_T("\nPocketSOAP1.exe: Sample Web Service client to find out "
" {域名已经过期} Sales Rank and Price for a given ISBN.\n"));
printf(_T("\nUsage:\tPocketSOAP1.exe <ISBN>\n"
"Examples:\n\tPocketSOAP1.exe 1861005318\n\t"
"PocketSOAP1.exe 0735712867"));
printf(_T("\n\nPress Enter to continue..."));
getchar();
return -1;
}
HRESULT hr = CoInitialize(NULL);
CallWebService(_bstr_t(argv[1]));
CoUninitialize();
return 0;
}
Output:

The above C++ code begins by importing the PocketSOAP type library, and then includes the supporting function CallWebService definition. This function uses the ISOAPEnvelope interface methods to initialize the SOAP request message (by defining the Web Service method to call, namespace to use, and defining the parameters). Next, it uses the IHTTPTransportAdv interface methods to set the SOAPAction, and to actually post the SOAP request. The resultant message is parsed and loaded into the ISOAPEnvelope object, which is then serialized as a string and written out to the console.
Summary
The goal of this article was to show you some of the ways in which you can build Web Services client applications, specifically using Visual C++. The first example illustrated using MSXML XMLHTTP for this purpose; next application used ServerXMLHTTP to invoke a Web Service; third sample application used Microsoft SOAP Toolkit high-level API, while the fourth application presented the code that used Microsoft SOAP Toolkit low-level API. Final, and fifth application, illustrated using PocketSOAP COM library to call a Web Service method.
Download: CPPSOAP.zip (353 KB ZIP file) Related Links:
- PerfectXML MSXML Focus Section
- Visual Basic Developer's Guide to SOAP
- Microsoft & Web Services (SOAP)
- SOAP Toolkit 3.0
- C++ Web services client using Systinet WASP Server for C++
- Simplified SOAP Development with SOAP::Lite - Part I
Discount Subscription Offer
10% Discount + Two FREE Issues of Web Services Journal
10% Discount + Two FREE Issues of XML-Journal










{域名已经过期} is a proud winner of

Best Educational Web Site (Finalist)