首先我们到 http://sourceforge.net/project/showfiles.php?group_id=52781链接去下载gSoap工具集,gSoap工具集不需要安装,直接解压就可以了。在gsoap-2.8\gsoap\bin\win32目录下我们可以看到两个可执行文件:
soapcpp2.exe: gSoap编译器,编译头文件生成服务器和客户端都需要的 c/c++文件。soapcpp2.exe和wsdl2h.exe的参数的意思自己在命令行输入 soapcpp2 -h来查看
2、根据WSDL生成 .h文件
我用搜索中国邮政编码的WebService来做例子,网址是http://www.webxml.com.cn/WebServices/ChinaZipSearchWebService.asmx。
2.1、在命令行执行:
wsdl2h -s -o AlyPostCode.h http://www.webxml.com.cn/WebServices/ChinaZipSearchWebService.asmx?wsdl生成 AlyPostCode.h文件,参数中使用 -s说明不要使用stl代码, -o后面接着的是根据wsdl生产的头文件名称
关于wsdl2h.exe中各个参数的含义如下:
-o 文件名,指定输出的头文件名称 -n 命名空间前缀,代替默认的ns -c 产生纯C代码,否则是C++代码 -s 不要使用stl代码 -t 文件名,指定type map文件,默认为typemap.dat -e 禁止为enum成员加上命名空间前缀3、执行:soapcpp2.exe -C -L -i -x -I[import的路径] AlyPostCode .h
即可以生成客户端存根程序和框架了。
-C 选项是只生成客户端的,默认是生成客户端和服务器端的,如果你在程序中使用了vector还要加上 –limport选项来指定import的路径,或者把需要的文件从gsoap-2.8\gsoap\import拷贝到编译目录下。
soapcpp2.exe各个参数的含义如下:
-C 仅生成客户端代码 -S 仅生成服务器端代码 -L 不要产生soapClientLib.c和soapServerLib.c文件 -c 产生纯C代码,否则是C++代码(与头文件有关) -I 指定import路径 -x 不要产生XML示例文件 -i 生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)
soapClient.cpp:编译客户端需要的存根例程。
soapC.cpp,soapH.h:用来序列化和反序列化C/C++不同数据类型。
soapServer.cpp: 编译服务器端需要的存根例程。
soapXXXProxy.h: 生成的代理类的头文件,使用代理类时需要此文件。
本程序为soapChinaZipSearchWebServiceSoapProxy.h。
上面的命令执行完成后,会生产下面的6个文件,如下:
soapC.cpp soapChinaZipSearchWebServiceSoapProxy.cpp soapChinaZipSearchWebServiceSoapProxy.h soapH.h soapStub.h ChinaZipSearchWebServiceSoap.nsmap到此,所需的文件准备完毕。
4、建立基于对话框的MFC工程
4.1、把第三步生产的6个文件和gsoap-2.8\gsoap目录下的stdsoap2.cpp\stdsoap2.h一共8个文件添加到工程
4.2、给工程添加socket支持 Project -> Setting 在对话框中的Link选项卡种 Object/library modules:下添加ws2_32.lib
4.3、设置soapChinaZipSearchWebServiceSoapProxy.cpp\stdsoap2.cpp\soapC.cpp三个文件不适用预编译头,方法:Project->Setting 选中上述的3个文件在C/C++选项卡中的Category 中选择Precompiled Headers,然后点击下面的单选框Not using precompiled headers。
4.4、在Stdafx.h文件中增加我们刚才加入到工程中的头文件,如下:
#include "soapChinaZipSearchWebServiceSoapProxy.h" #include "ChinaZipSearchWebServiceSoap.nsmap"4 .5、顺利的话,编译没有错误。
4.6、在对话框上增加测试按钮,单击按钮,请求邮编所对应的地址,代码如下:
void CMy123Dlg::OnButton1() { // TODO: Add your control notification handler code here ChinaZipSearchWebServiceSoapProxy zipProxy("http://www.webxml.com.cn/WebServices/ChinaZipSearchWebService.asmx", SOAP_C_UTFSTRING); _ns1__getAddressByZipCode zipCode; CString strCode = "116000"; zipCode.theZipCode = strCode.GetBuffer(0); CString strUserID = ""; zipCode.userID = strUserID.GetBuffer(0); _ns1__getAddressByZipCodeResponse zipAddr; int result = zipProxy.getAddressByZipCode(&zipCode, &zipAddr); if (SOAP_OK != result) { AfxMessageBox(_T("出错了")); } else { string strAddr = zipAddr.getAddressByZipCodeResult->__any;///< 获取邮编对应的地址 wchar_t* ch = MulityByteToWideChar(zipAddr.getAddressByZipCodeResult->__any); AfxMessageBox(CString(ch)); AfxMessageBox(CString(strAddr.c_str())); } }4.7、传回的数据为乱码,下面的函数把它转化成UTF8,以便正常显示中文:
wchar_t* CMy123Dlg::MulityByteToWideChar(char* str) { DWORD dwNum = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); wchar_t *pwText = new wchar_t[dwNum]; MultiByteToWideChar(CP_UTF8, 0, str, -1, pwText, dwNum); return pwText; }
4.8、圆满完成......
4.9、调用webService时,传给相关函数的参数和和获取的数据通常需要进行编码类型的转换,在Visual C++6.0编程环境下,常用的转换函数如下:
UnicodeToUTF8函数具体实现如下:
char* UnicodeToUTF8(const wchar_t *str) { char * result; int textlen = 0; // wide char to multi char textlen = WideCharToMultiByte( CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL ); result =(char *)malloc((textlen+1)*sizeof(char)); memset( result, 0, sizeof(char) * ( textlen + 1 ) ); WideCharToMultiByte( CP_UTF8, 0, str, -1, result, textlen, NULL, NULL ); return result; }UTF8ToUnicode函数的具体实现如下:
wchar_t* UTF8ToUnicode(const char *str) { int textlen = 0; wchar_t * result; textlen = MultiByteToWideChar( CP_UTF8, 0, str,-1, NULL,0 ); result = (wchar_t *)malloc((textlen+1)*sizeof(wchar_t)); memset(result,0,(textlen+1)*sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0,str,-1,(LPWSTR)result,textlen ); return result; }
在Visual c++ 6.0环境中,当要从webService端获取数据时,通常会给wsdl中描述的函数传递参数,该参数要是中文的话,需要从unicode转换为Unicode,就需要调用上面提到的函数UnicodeToUTF8,该函数需要wchar_t类型的参数,我们得到的CString类型的参数要转换为wchar_t类型的参数,需要CString类的成员函数AllocSysString,具体使用方法如下:
((CWnd*)GetDlgItem(IDC_EDIT_USERNAME))->GetWindowText(strName); strTDJInfo.strName = UnicodeToUTF8(strName.AllocSysString()); ((CWnd*)GetDlgItem(IDC_EDIT_ACCOUNT))->GetWindowText(strAccount); strTDJInfo.strAccount = UnicodeToUTF8(strAccount.AllocSysString());
----------------------------------------------------------------------------------------------------------------
gSoap中文乱码问题相关。
1、wchar_t类型简介:
wchar_t是C/C++的字符数据类型,是一种扩展的字符存储方式,wchar_t类型主要用在国际化程序的实现中,但它不等同于unicode编码。unicode编码的字符一般以wchar_t类型存储。
char是8位字符类型,最多只能包含256种字符,许多外文字符集所含的字符数目超过256个,char型无法表示。wchar_t数据类型一般为16位或32位,但不同的C或C++库有不同的规定,如GNU Libc规定wchar_t为32位[1],总之,wchar_t所能表示的字符数远超char型。标准C++中的wprintf()函数以及iostream类库中的类和对象能提供wchar_t宽字符类型的相关操作。