最近用到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();
問題解決!!