有个项目用到了webserivce,在这里做个记录。
2种方法实现VC++调用webservice。
这里我们直接调用网络上免费的webserivce服务来做为用例:http://webservice.webxml.com.cn/webservices/DomesticAirline.asmx
1、需要安装微软的soapsdk3开发包,可以从微软网站下载。
2、首先在工程的BOOL CWHRepeaterApp::InitInstance()里添加::CoInitialize(NULL);
在intCWHRepeaterApp::ExitInstance()里添加::CoUninitialize();用来初始化COM环境。
2、代码如下
#pragma once
#ifndef __CWSWrapper_H__
#define __CWSWrapper_H__
classCWSWrapper
{
public:
CWSWrapper(const char *szURL,const char *szNameSpace,const char*szMethodName);
virtual ~CRocWSWrapper(void);
CStringReceiveXMLData(CString strStartCity,CString strLastCity,CString strDate,CStringstrUserID);
private:
CStringm_strURL;
CStringm_strNameSpace;
CStringm_strMethodName;
};
#endif
#include "StdAfx.h"
#include "RocWSWrapper.h"
#import "msxml4.dll"
#import "C:\Program Files(x86)\Common Files\MSSoap\Binaries\mssoap30.dll" \
exclude("IStream", "IErrorInfo","ISequentialStream", "_LARGE_INTEGER", \
"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")
#include
using namespace MSXML2;
using namespace MSSOAPLib30;
usingstd::string;
CWSWrapper::CRocWSWrapper(constchar *szURL,constchar *szNameSpace,constchar *szMethodName)
:m_strURL(szURL),m_strNameSpace(szNameSpace),m_strMethodName(szMethodName)
{
}
CString CWSWrapper::ReceiveXMLData(CString strStartCity,CStringstrLastCity,CString strDate,CString strUserID)
{
HRESULT hr;
ISoapSerializerPtrSerializer;
ISoapReaderPtrReader;
ISoapConnectorPtrConnector;
try
{
hr= Connector.CreateInstance(__uuidof(HttpConnector30));
if (FAILED(hr))
{
return CString("Error:1");
}
hr= Serializer.CreateInstance(__uuidof(SoapSerializer30));
if (FAILED(hr))
{
return CString("Error:2");
}
hr= Reader.CreateInstance(__uuidof(SoapReader30));
if (FAILED(hr))
{
return CString("Error:3");
}
Connector->Property["EndPointURL"] = (_bstr_t)m_strURL;
//Connector->Property["EndPointURL"] ="http://webservice.webxml.com.cn/webservices/DomesticAirline.asmx";
Connector->Connect();
Connector->Property["SoapAction"] =_bstr_t(m_strNameSpace+m_strMethodName);
//Connector->Property["SoapAction"] ="http://WebXml.com.cn/getDomesticAirlinesTime";
//创建webservice的请求soap包
Connector->BeginMessage();
// 将serializer连接到connector的输入字符串
Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
// 创建soap消息
Serializer->StartEnvelope("SOAP", "http://schemas.xmlsoap.org/soap/envelope/","");
Serializer->SoapAttribute("xsi", "","http://www.w3.org/2001/XMLSchema-instance","xmlns");
Serializer->SoapAttribute("xsd", "","http://www.w3.org/2001/XMLSchema","xmlns");
Serializer->StartBody("");
Serializer->StartElement((_bstr_t)m_strMethodName,(_bstr_t)m_strNameSpace, "", "Soap"); //第三个参数不能填写NONE
//下面传入四个参数,StartElement和EndElement成对出现,用WriteString传入参数
Serializer->StartElement("startCity", "","", "Soap");
Serializer->WriteString((_bstr_t)strStartCity);
Serializer->EndElement();
//
Serializer->StartElement("lastCity", "","", "Soap");
Serializer->WriteString((_bstr_t)strLastCity);
Serializer->EndElement();
//
Serializer->StartElement("theDate", "","", "Soap");
Serializer->WriteString((_bstr_t)strDate);
Serializer->EndElement();
//
Serializer->StartElement("userID", "","", "Soap");
Serializer->WriteString((_bstr_t)strUserID);
Serializer->EndElement();
//
Serializer->EndElement();
Serializer->EndBody();
Serializer->EndEnvelope();
_variant_tvar = _variant_t((IUnknown*)Connector->InputStream);
Connector->EndMessage();
//解析返回的soap包
Reader->Load(_variant_t((IUnknown*)Connector->OutputStream),"");
CStringstrOutput= CString((const char*)Reader->RpcResult->text);
return strOutput;
}
catch(_com_error &e)
{
ATLTRACE(("error info: %s; \n"), e.ErrorMessage());
}
catch(...)
{
}
return CString("Error");
}
调用方法:
CRocWSWrapper wrapper("http://webservice.webxml.com.cn/webservices/DomesticAirline.asmx","http://WebXml.com.cn/","getDomesticAirlinesTime");
CString strName = wrapper.ReceiveXMLData(CString("天津"), CString("北京"), CString("2015-1-1"),CString(""));
这里我们直接调用网络上免费的webserivce服务来做为用例:http://fy.webxml.com.cn/webservices/EnglishChinese.asmx?op=TranslatorString
http://fy.webxml.com.cn/webservices/EnglishChinese.asmx?wsdl
在页面里可以看到服务的SOAP 请求和响应示例。(这对于第一种实现方法很直观)
1、首先下载gsoap,下载后直接解压缩即可。这里我们放到C盘下。
2、在VC工程下建立一个目录EnglishChinese,把C:\gsoap-2.8\gsoap\bin\win32目录下的wsdl2h.exe和soapcpp2.exe文件拷贝到EnglishChinese目录下,把C:\gsoap-2.8\gsoap目录下的stdsoap2.cpp和stdsoap2.h文件也拷贝到EnglishChinese目录下。此步骤可以省略。
3、在目录下建立一个批处理文件。wsdl2h和soapcpp2如何使用可以查看网络。
@echo off
wsdl2h.exe -s -otestEnCn.h http://fy.webxml.com.cn/webservices/EnglishChinese.asmx?wsdl
soapcpp2.exe -C-IC:\gsoap-2.8\gsoap\import testEnCn.h
pause
如果第二步不拷贝文件也可以直接在gsoap目录下进行操作。CMD命令行下执行同样可以。
4、调用批处理或在CMD下运行wsdl2h.exe和soapcpp2.exe。在EnglishChinese目录下生成了一些文件。把生成的文件添加到工程里,包括soapStub.h,soapH.h,soapC.cpp和soapClient.cpp,另外把stdsoap2.cpp和stdsoap2.h文件也添加到工程里。soapClientLib.cpp文件不需要添加。此时在工程的类视图里可以看到很多以ns1__为前缀的类或接口函数等。
注意:这些添加的cpp文件由于是其它软件生成的,可能会提示错误信息:fatal errorC1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "stdafx.h。
修改对应文件的“属性”下“C/C++”下“预编译头”下“创建/使用预编译头”为“不使用预编译头”即可。
编译时如遇到1>stdsoap2.obj : error LNK2001: 无法解析的外部符号 _namespaces,请在stdsoap2.cpp中加上 #include "本例对应的.nsmap"文件即可通过编译。
5、添加代码,在工程的全局函数和变量中可以看到gsoap生成的函数接口。
#include "StdAfx.h"
#include "EnCn.h"
#include "EnglishChinese\soapH.h"
#include "EnglishChinese\EnglishChineseSoap.nsmap"
voidCEnCn::Test()
{
//
struct soap soap;
struct _ns1__TranslatorString ns1__TranslatorString;
struct _ns1__TranslatorStringResponse_ns1__TranslatorStringResponse;
soap_init(&soap);
soap_set_mode(&soap,SOAP_C_UTFSTRING);
ns1__TranslatorString.wordKey= "love";
soap_call___ns1__TranslatorString(&soap,"http://fy.webxml.com.cn/webservices/EnglishChinese.asmx","TranslatorString",&ns1__TranslatorString,_ns1__TranslatorStringResponse);
if (soap.error)
{
;
}
else
{
ns1__ArrayOfString*arrStr = _ns1__TranslatorStringResponse.TranslatorStringResult;
int iSize = arrStr->__sizestring;
char **string = arrStr->string;
}
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);
}