最近用到vc mfc 调用c#写的wcf 发布的webservice 上传文件.服务器端接收object 类型的byte[]数组。
我本来还以为vs2010中vc能象c#一样方便的使用web service(记得vs2005,vs2008的vc clr 可以直接增加引用),可是找了半天头大了!!
网上找了下,大家都是用的gsoap,但是能查到的资料,都是接收简单数据的,于是效仿,对gsoap生成的代理类,和数据类型研读,问题解决了。
1、 先了解一下Gsoap
gSOAP一种跨平台的C和 C++软件开发工具包。生成C/C++的RPC代码,XML数据绑定,对SOAP Web服务和其他应用形成高效的具体架构解析器,它们都受益于一个XML接口。
这个工具包提供了一个全面和透明的XML数据绑定解决方案,Autocoding节省大量开发时间来执行SOAP/XML Web服务中的C/C++。此外,使用XML数据绑定大大简化了XML自动映
射。应用开发人员不再需要调整应用程序逻辑的具体库和XML为中心的数据,如 交涉DOM。
我们可以使用gSOAP提供的工具直接根据wsdl文档,生成所需要的数据类型,并将底层实现完全封装,我们只需要简单的操作代理类,就可以很轻松的实现调用。
2、 Gsoap优点
夸平台。支持linux386(MAC OS X universal binaries),macosx(Linux i386 compatible),win32(Windows 386 compatible)等。
稳定性:该软件已经成熟。自2001年以来经过几年的发展和试验。许多工业项目和产品都在使用该软件。
开源:可选择自由和商业许可。
C和C++的支持:支持纯粹的ANSI C和混合的C/C++应用开发。
行业标准协议: SOAP 1.1/1.2 WSDL 1.1,v2和UDDI 。支持XML架构原始XSD结构类型等等。
3、 不废话了直接按地址下载:
下载地址:http://sourceforge.net/projects/gsoap2
解压gsoap_2.8.14.zip
在目录gsoap-2.8\gsoap\win32下,存在2个exe 文件:
soapcpp2.exe 该工具转换WSDL和XSD文件到带有注释的C/C++定义文件。
Wsdl2h.exe 该工具从带有注释的C/C/++定义文件生成RPC代码和XML序列化
在目录gsoap-2.8\gsoap\doc下帮助文裆。
首先用C# wcf写个测试用的服务端代码(wcf 3.5):
发布的方法如下:
public int testAdd(int intA, int intB) { Return intA+intB; } public string upDateFile(string ilename, object objfile) { Byte[] mt=(byte) objfile; ………………… }
然后启动,发布成web service .地址为http://127.0.0.1:2002/myBehavior?wsdl。
其次:用Vc进行调用完成客户端功能,实现步骤如下:
开始-运行-cmd进入dos模式,进入gsoap-2.8\gsoap\win32目录。
1、 根据wsdl文档生成头文件.
Wsdl2h -1 –t ..\..\typemap.dat -s -0 test.h http://127.0.0.1:2002/myBehavior?wsdl
参数只写了几个常用的,其他的可以查询帮助。
-t file |
use type map file instead of the default file typemap.dat |
-s |
don’t generate STL code (no std::string and no std::vector) |
-o file |
output to file |
2、 soapcpp2.exe -C -L -j -d "C:\test" -w -x "test.h"
注意:1、 如果不使用–t参数的话,默认soapcpp2相同的目录。
2、我所使用的服务端使用的是basehttpbinding 支持soap 1.0 (ws(*)HttpBinding 支持soap 2.0)所以使用参数 -1, 如果不设置此参数,将默认soap 1.2版本。
-C |
Generate client-side code only |
-L |
Do not generate soapClientLib/soapServerLib |
-j |
Generate C++ service proxies and objects that can share a soap struct |
-d <path> |
Save sources in directory specified by <path> |
-w |
Do not generate WSDL and schema files |
-x |
Do not generate sample XML message files |
-1 |
Generate SOAP 1.1 bindings |
-2 |
Generate SOAP 1.2 bindings |
将如下文件列表
BasicHttpBinding_USCOREIDataService.nsmap
soapBasicHttpBinding_USCOREIDataServiceProxy.cpp
soapBasicHttpBinding_USCOREIDataServiceProxy.h
soapC.cpp
soapH.h
soapStub.h
将生成文件及stdsoap2.c,soap12.h,stdsoap2.cpp,加入到工程,
1、右键选择soapC.cpp、soapBasicHttpBinding_USCOREIDataServiceProxy.cpp、stdsoap2.cpp,点击"属性",如下图所
2、选择 预编译-》预编译头设置为 不使用预编译头文件。
在使用代码中加入头文件:
#include "soap\ soapBasicHttpBinding_USCOREIDataServiceProxy.cpp "
#include "soap\ BasicHttpBinding_USCOREIDataService.nsmap"
代码实现部分如下:
struct soap clientSOAP; soap_init(&clientSOAP); //简单的传值没有什么疑问 struct _ns1__ testAdd testAdd; struct _ns1__ testAdd Response testAddResponse; xsd__int intA; intA. __item=5; xsd__int intB; intB. __item=3; testAdd. intA = intA; testAdd. intB = intB; BasicHttpBinding_USCOREIDataServiceProxy test; test.soap_endpoint=”http://127.0.0.1:2002/myBehavior?wsdl”; int soapResult= test. testAdd (&testAdd,& testAddResponse); if(soapResult==SOAP_OK) { Int result= testAddResponse. testAddResult; } else { int m=GetLastError(); ……… } /* web service 定义的object类型数据,在wsdl xml 中被定义为xsd:anyType, 而对应代理类中的xsd__anyType,要确认参数实际内容,需要获得接口的帮助,确定传值。本实例测试传输的是byte数组,二进制。 */ struct _ns1__ upDateFile upDateFile; struct _ns1__ upDateFileResponse upDateFileResponse; //先将数据传给基础byte类型 // vobjFile xsd__base64Binary v ; v.__ptr=new BYTE[vobjFileSize]; v.__size=vobjFileSize; memcpy(v.__ptr,vobjFile, vobjFileSize); v.soap=&clientSOAP; //将基础类型传给从,xsd__anytype派生来的byte xsd__base64Binary_ *v1 =new xsd__base64Binary_() ; v1->__item=v; upDateFile.objName=vFileName; //生成代理类的时候,xsd:anytype,对应生成 xsd__anytype upDateFile.objPgc=v1; BasicHttpBinding_USCOREIDataServiceProxy test; test.soap_endpoint=”http://127.0.0.1:2002/myBehavior?wsdl”; int soapResult= test.upDateFile(&upDateFile,& upDateFileResponse); if(soapResult==SOAP_OK) { char *result; result=new char[10]; result= upDateFileResponse. upDateFileResponseResult; delete result; if (atoi(result)==0) { ……… } } else { int m=GetLastError(); ……… } delete v1; upfile.destroy();
问题解决!!