第一部分
突然要在c++里调用webservice,一时还不知道从何下手,又想起了.net的好了,直接用wsdl命令生成一个代理类就搞定了,于是又开始了在网上寻觅的历程。这年代没有google,估计要少活10年。
搜索"vc6"+Webservice,出来了一大堆,不过内容基本上一样(又让我体会了一把“天下文章一大抄”的经典论据,到头来都不知道谁抄谁)也有博客园里的兄弟写的,但拷下来总是不好用,不过知道了要用到soapsdk3.0,于是down了一个,安装完了就是一堆com,又开始google"mssoap30.dll"+"vc",这次搜索所有网页,出来了一堆英文页面,翻了好几页,看了一大堆的英文后,终于找到了点眉目,也稍微整理一下。
1:先安装soapsdk3.0(http://download.microsoft.com/download/2/e/0/2e068a11-9ef7-45f5-820f-89573d7c4939/soapsdk.exe)
2:当然就是写代码
WSWrapper.h
1#ifndef _WS_WRAPPER_H_
2#define _WS_WRAPPER_H_
3
4#import "msxml4.dll"
5#import "C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" \
6 exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", \
7 "_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")
8#include <string>
9#include <Windows.h>
10
11using namespace MSXML2;
12using namespace MSSOAPLib30;
13using std::string;
14
15class WSWrapper
16{
17public:
18 WSWrapper(const char *wsURL,
19 const char *wsNameSapce,
20 const char *wsMethodName);
21 virtual ~WSWrapper();
22 string Hello(const string &strName);
23
24private:
25 const string _wsURL;
26 const string _wsNameSapce;
27 const string _wsMethodName;
28};
29
30
31#endif
WSWrapper.cpp
1#include "WSWrapper.h"
2
3WSWrapper::WSWrapper(const char *wsURL,
4 const char *wsNameSapce,
5 const char *wsMethodName)
6 : _wsURL(wsURL),
7 _wsNameSapce(wsNameSapce),
8 _wsMethodName(wsMethodName)
9{
10
11}
12
13WSWrapper::~WSWrapper()
14{
15
16}
17
18string WSWrapper::Hello(const string &strName)
19{
20 try
21 {
22 HRESULT hr = CoInitialize(NULL);//初始化com环境
23 if(FAILED(hr))
24 {
25 //出错了
26 }
27
28 ISoapSerializerPtr Serializer;
29 ISoapReaderPtr Reader;
30 ISoapConnectorPtr Connector;
31
32 //连接到WebService
33 hr = Connector.CreateInstance(__uuidof(HttpConnector30));
34 if(FAILED(hr))
35 {
36 //创建com对象出错,一般是因为没有安装com
37 }
38
39 Connector->Property["EndPointURL"] = _wsURL.c_str();
40 Connector->Connect();
41 Connector->Property["SoapAction"] = (_wsNameSapce + _wsMethodName).c_str();
42
43 //开始创建webservice的请求Soap包
44 Connector->BeginMessage();
45 hr = Serializer.CreateInstance(__uuidof(SoapSerializer30));
46 if(FAILED(hr))
47 {
48 //创建com对象出错,一般是因为没有安装com
49 }
50 Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
51 Serializer->StartEnvelope("SOAP", "http://schemas.xmlsoap.org/soap/envelope/", "");
52 Serializer->SoapAttribute("xsi", "", "http://www.w3.org/2001/XMLSchema-instance", "xmlns");
53 Serializer->SoapAttribute("xsd", "", "http://www.w3.org/2001/XMLSchema", "xmlns");
54
55 Serializer->StartBody(L"NONE");
56 Serializer->StartElement(_wsMethodName.c_str(), _wsNameSapce.c_str(), "NONE", "");
57 Serializer->StartElement(L"strName", "", "NONE", "");
58 Serializer->SoapAttribute("xsi:type", "", "xsd:string", "");
59 Serializer->WriteString(strName.c_str());
60 Serializer->EndElement();
61 Serializer->EndElement();
62 Serializer->EndBody();
63 Serializer->EndEnvelope();
64
65 Connector->EndMessage();
66
67 //解析返回的soap包
68 hr = Reader.CreateInstance(__uuidof(SoapReader30));
69 if(FAILED(hr))
70 {
71 //创建com对象出错,一般是因为没有安装com
72 }
73 Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "");
74 string strResult((const char*)Reader->RpcResult->text);
75
76 return strResult;
77
78
79 }
80 catch()
81 {
82 //got a exception
83 }
84 return "error";
85}
86
87
TestApp.cpp
1#include "WSWrapper.h"
2
3int main()
4{
5
6 WSWrapper wsWrapper("http://localhost/TestWebService/Service1.asmx",
7 "http://localhost/TestWebService/",
8 "Hello");
9
10 string strName = "Lucy";
11 string strResult = wsWrapper.Hello(strName);
12
13 printf("%s", strResult.c_str());
14
15 getchar();
16
17 return 0;
18}
19
C#写的一个测试WebService
1using System.ComponentModel;
2using System.Web.Services;
3
4namespace TestWebService
5{
6 /**//// <summary>
7 /// Service1 的摘要说明。
8 /// </summary>
9 [WebService(Namespace="http://localhost/TestWebService/")]
10 [System.Web.Services.Protocols.SoapRpcService]
11 public class Service1 : System.Web.Services.WebService
12 {
13 public Service1()
14 {
15 //CODEGEN: 该调用是 ASP.NET Web 服务设计器所必需的
16 InitializeComponent();
17 }
18
19 组件设计器生成的代码#region 组件设计器生成的代码
20
21 //Web 服务设计器所必需的
22 private IContainer components = null;
23
24 /**//// <summary>
25 /// 设计器支持所需的方法 - 不要使用代码编辑器修改
26 /// 此方法的内容。
27 /// </summary>
28 private void InitializeComponent()
29 {
30 }
31
32 /**//// <summary>
33 /// 清理所有正在使用的资源。
34 /// </summary>
35 protected override void Dispose( bool disposing )
36 {
37 if(disposing && components != null)
38 {
39 components.Dispose();
40 }
41 base.Dispose(disposing);
42 }
43
44 #endregion
45
46 // WEB 服务示例
47 // HelloWorld() 示例服务返回字符串 Hello World
48 // 若要生成,请取消注释下列行,然后保存并生成项目
49 // 若要测试此 Web 服务,请按 F5 键
50
51 [WebMethod]
52 public string Hello(string strName)
53 {
54 return "Hello, " + strName;
55 }
56 }
57}
58
第二部分
一、VC++6.0调用WebServices(可以是c#,java,vc++.net等提供的服务都可以)!
本文主要讲述VC++6.0调用WebServices的方法,其中web services可以是c#,java,vc++.net等提供的服务都可以调用!主要的大致过程如下:
需要装SoapToolkit3.0,电脑上一般自带Soap Toolkit1.0,以下代码在VC++6.0中测试成功。
在stdafx.h加上
//WEB_SERVICE
#include<stdio.h>
#import"msxml4.dll"
using namespaceMSXML2;
#import"C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" \
exclude("IStream","IErrorInfo", "ISequentialStream","_LARGE_INTEGER", \
"_ULARGE_INTEGER","tagSTATSTG", "_FILETIME")
using namespaceMSSOAPLib30;
//END
SoapTestDlg.h里面
/
CStringBeginSoap(CString,CString,CString);
ISoapConnectorPtrSoapConnector;
ISoapSerializerPtrSerializer;
ISoapReaderPtrReader;
///
SoapTestDlg.cpp里面
///
voidCSoapTestDlg::OnButton1()
{
CString str,strWord;
GetDlgItem(IDC_EDIT1)->GetWindowText(strWord);
str=BeginSoap("EnglishTOChinese",strWord,"http://www.webservicex.net/translateservice.asmx");
AfxMessageBox(str);
}
CStringCSoapTestDlg::BeginSoap(CString UserName,CString Password,CString WebUrl)
{
HRESULT hr;
try
{
//创建SoapConnector类的对象
SoapConnector.CreateInstance(__uuidof(HttpConnector30));
//指定Web服务的地址
SoapConnector->Property["EndPointURL"] =(LPSTR)(LPCTSTR)WebUrl;
//与Web服务连接
hr=SoapConnector->Connect();
if(FAILED(hr)) return "";
//指定Web服务完成的操作
SoapConnector->Property["SoapAction"] =_T("http://www.webservicex.net/Translate");
//准备发送消息给Web服务
SoapConnector->BeginMessage();
// 创建SoapSerializer对象
Serializer.CreateInstance(__uuidof(SoapSerializer30));
// 将serializer连接到connector的输入字符串
Serializer->Init(_variant_t((IUnknown*)SoapConnector->InputStream));
// 创建SOAP消息
Serializer->StartEnvelope("soap","","");
Serializer->StartBody("");
Serializer->StartElement("Translate","http://www.webservicex.net","","soap");
Serializer->StartElement("LanguageMode","","","soap");
Serializer->WriteString((_bstr_t)(LPCTSTR)UserName);
Serializer->EndElement();
Serializer->StartElement("Text","","","soap");
Serializer->WriteString((_bstr_t)(LPCTSTR)Password);
Serializer->EndElement();
Serializer->EndElement();
Serializer->EndBody();
Serializer->EndEnvelope();
//消息真正地发给Web服务
hr=SoapConnector->EndMessage();
if(FAILED(hr)) return "";
// 读取响应
Reader.CreateInstance(__uuidof(SoapReader30));
// 将reader联接到connector的输出字符串
Reader->Load(_variant_t((IUnknown*)SoapConnector->OutputStream),_T(""));
return CString((const char*)Reader->RpcResult->text);
}
catch (_com_error e)
{
return (CString)(char*)e.Description();
}
}
//OVER///
当然用Soap Toolkit1.0调用也可以,大致代码跟上面的一样,需要改动的有:
1.包含库文件代码改为下面
#import "msxml4.dll"
using namespaceMSXML2;
#import"C:\Program Files\Common Files\MSSoap\Binaries\MSSOAP1.dll" \
exclude("IStream","ISequentialStream", "_LARGE_INTEGER", \
"_ULARGE_INTEGER","tagSTATSTG", "_FILETIME")
using namespaceMSSOAPLib;
2. 函数代码上包含30数字的全将30去掉,如
SoapConnector.CreateInstance(__uuidof(HttpConnector));
Serializer.CreateInstance(__uuidof(SoapSerializer));
Reader.CreateInstance(__uuidof(SoapReader));
3.将
Serializer->StartElement("Text","","","soap");
Serializer->WriteString((_bstr_t)(LPCTSTR)Password);
Serializer->EndElement();
Serializer->EndElement();
Serializer->EndBody();
Serializer->EndEnvelope();
改为:(第一个单词小写)
Serializer->writeString("laghari78");
Serializer->endElement();
Serializer->endElement();
Serializer->endBody();
Serializer->endEnvelope();
/OK/
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhoubl668/archive/2008/12/27/3624181.aspx
二、vc6.0连接webservice
需要安装Toolkit3.0 1.0只能看到VB和ASP的
VC6开发WebServices 客户端收藏
下面是个控制台的样例
Toolkit3.0 终于给出VC6的样例了,1.0只能看到VB和ASP的
#include<stdio.h>
#import"msxml4.dll"
using namespaceMSXML2;
#import"C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" \
exclude("IStream","IErrorInfo", "ISequentialStream","_LARGE_INTEGER", \
"_ULARGE_INTEGER", "tagSTATSTG","_FILETIME")
using namespaceMSSOAPLib30; //你机器得安装SOAP Toolkit3.0 ,1.0时,用usingnamespace时报错
void Add()
{
ISoapSerializerPtr Serializer;
ISoapReaderPtr Reader;
ISoapConnectorPtr Connector;
// Connect to the service.
Connector.CreateInstance(__uuidof(HttpConnector30)); //HttpConnector30 失败,无法这样创建Connector,CXX0017Error :Symbol “HttpConnector30“ not found(摇头、叹气!)
Connector->Property["EndPointURL"] ="http://MyServer/Soap3DocSamples/DocSample1/Server/DocSample1.wsdl"; //这个当然得改成您自己的拉
Connector->Connect();
// Begin the message.
//Connector->Property["SoapAction"] ="uri:AddNumbers";
Connector->Property["SoapAction"]= "http://tempuri.org/DocSample1/action/Sample1.AddNumbers";
Connector->BeginMessage();
// Create the SoapSerializer object.
Serializer.CreateInstance(__uuidof(SoapSerializer30));
// Connect the serializer object to theinput stream of the connector object.
Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
// Build the SOAP Message.
Serializer->StartEnvelope("","","");
Serializer->StartBody("");
Serializer->StartElement("AddNumbers","http://tempuri.org/DocSample1/message/","",""); //这是本地的WebServices,实际中要指定命名空间
Serializer->StartElement("NumberOne","","","");
Serializer->WriteString("5");
Serializer->EndElement();
Serializer->StartElement("NumberTwo","","","");
Serializer->WriteString("10");
Serializer->EndElement();
Serializer->EndElement();
Serializer->EndBody();
Serializer->EndEnvelope();
// Send the message to the XML Web service.
Connector->EndMessage();
// Read the response.
Reader.CreateInstance(__uuidof(SoapReader30));
// Connect the reader to the output streamof the connector object.
Reader->Load(_variant_t((IUnknown*)Connector->OutputStream),"");
// Display the result.
printf("Answer: %s\n", (constchar*)Reader->RpcResult->text);
}
int main()
{
CoInitialize(NULL);
Add();
CoUninitialize();
return 0;
}
更改 EndPointURL 属性的值. 在URL里指定你的服务器名.
OK
总结一下必要的关键步骤
1.导入类型库
2.需要创建一个SoapConnector
3.下一步创建SoapSerializer
4.下一步把消息附加到SoapConnector的输入流
5.下一步读取结果.要读取服务器的回复,客户端应用需要使用SoapReader,
6.SoapReader被连接到SoapConnector输出流
7.用IXMLDOMElement对象可以从SoapReader里读到服务器的回复
附:
SOAP ToolKit 3.0 下载地址:http://download.microsoft.com/download/xml/Install/3.0/W982KMeXP/EN-US/SoapToolkit30.EXE
第三部分
用Soap Toolkit调用WebService的一个问题。
问题描述:
在用非.NET客户端调用WebService中,按照使用Soap Toolkit中的指导实现起来很简单,但在实际使用过程中却发现一个问题。
假如Webservice提供的方法是:int SimpleMath.Add(int n1,int n2),返回值是n1+n2, 但按照soaptoolkit提供的例子,使用VC进行调用,得到的返回值却是0。
记录下我的解决过程,备忘。
试验环境:
OS:WindowsXPProfessional
WebService:VS.NET 2003
WebService运行环境:IIS
客户端:VC6.0,VS.NET中的VC
SoapToolkit SDK:3.0
问题再现:
看Toolkit中稍微修改一下之后的例子代码:
#include<stdio.h>
#import"msxml4.dll"
using namespaceMSXML2;
#import"C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" \
exclude("IStream","IErrorInfo", "ISequentialStream","_LARGE_INTEGER", \
"_ULARGE_INTEGER", "tagSTATSTG","_FILETIME")
using namespaceMSSOAPLib30;
int test2()
{
ISoapSerializerPtr Serializer;
ISoapReaderPtr Reader;
ISoapConnectorPtr Connector;
// Connect to the service
Connector.CreateInstance(__uuidof(HttpConnector));
Connector->Property["EndPointURL"]= "http://localhost/WSTest/SimpleMath.asmx?WSDL";
Connector->Connect();
// Begin message
Connector->Property["SoapAction"]= "http://tempuri.org/Add";
Connector->BeginMessage();
// Create the SoapSerializer
Serializer.CreateInstance(__uuidof(SoapSerializer));
// Connect the serializer to the input streamof the connector
Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
// Build the SOAP Message
Serializer->startEnvelope("","","");
Serializer->startBody("");
Serializer->startElement("Add","http://tempuri.org/","","");
Serializer->startElement("n1","","","");
Serializer->writeString("5");
Serializer->endElement();
Serializer->startElement("n2","","","");
Serializer->writeString("10");
Serializer->endElement();
Serializer->endElement();
Serializer->endBody();
Serializer->endEnvelope();
// Send the message to the web service
Connector->EndMessage();
// Let us read the response
Reader.CreateInstance(__uuidof(SoapReader));
// Connect the reader to the output stream ofthe connector
Reader->Load(_variant_t((IUnknown*)Connector->OutputStream),"");
// Display the result
printf("Answer: %s\n", (constchar*)Reader->RPCResult->text);
return 0;
}
返回结果应该是15,但实际却返回了0。
在网上搜索发现有人提议把WebService的方法的参数改为string,然后在方法内部转换,我觉得这不是一个好办法。事实上,我经过发现,这样的实现问题会更多。
返回结果应该是15,但实际却返回了0。
在网上搜索发现有人提议把WebService的方法的参数改为string,然后在方法内部转换,我觉得这不是一个好办法。事实上,我经过发现,这样的实现问题会更多。
分析过程:
用soap toolkit的跟踪工具MSSoapT看一下,客户端到底向WebService发送了什么数据:
<SOAP-ENV:EnvelopeSOAP-ENV:encodingStyle=""xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:BodySOAP-ENV:encodingStyle="">
<SOAPSDK1:Addxmlns:SOAPSDK1="http://tempuri.org/"SOAP-ENV:encodingStyle="">
<n1SOAP-ENV:encodingStyle="">5</n1>
<n2SOAP-ENV:encodingStyle="">10</n2>
</SOAPSDK1:Add>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
再看看vs.NET调试中,IE浏览器发出的数据(模板):
<?xmlversion="1.0" encoding="utf-8"?>
<soap:Envelopexmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Addxmlns="http://tempuri.org/">
<n1>int</n1>
<n2>int</n2>
</Add>
</soap:Body>
</soap:Envelope>
区别在哪里?soaptoolkit的数据中,多了个encodingStyle属性,尽管没有制定值。我们想办法屏蔽这个属性。
在SoapSerializer30的startElement方法中的参数中按照如下方式调用,可以不制定这个属性。
改代码如下:
...
Serializer->startElement("Add","http://tempuri.org/","NONE","");
Serializer->startElement("n1","","NONE","");
Serializer->writeString("5");
Serializer->endElement();
Serializer->startElement("n2","","NONE","");
Serializer->writeString("10");
Serializer->endElement();
Serializer->endElement();
...
但返回结果还是0,看来和encodingStyle无关。看看跟踪情况:
<SOAP-ENV:EnvelopeSOAP-ENV:encodingStyle="" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:BodySOAP-ENV:encodingStyle="">
<SOAPSDK1:Addxmlns:SOAPSDK1="http://tempuri.org/">
<n1>5</n1>
<n2>10</n2>
</SOAPSDK1:Add>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
问题解决:
比较一下vs.net中发出的请求,差别在哪里?认真看一下,n1和n2没有指定命名空间,那么就指定一下吧。
把代码改成:
Serializer->startElement("Add","http://tempuri.org/","NONE","");
Serializer->startElement("n1","http://tempuri.org/","NONE","");
Serializer->writeString("5");
Serializer->endElement();
Serializer->startElement("n2","http://tempuri.org/","NONE","");
Serializer->writeString("10");
Serializer->endElement();
Serializer->endElement();
测试结果正常了,返回15。
看看这时候发出的xml数据:
<SOAP-ENV:EnvelopeSOAP-ENV:encodingStyle="" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:BodySOAP-ENV:encodingStyle="">
<SOAPSDK1:Addxmlns:SOAPSDK1="http://tempuri.org/">
<SOAPSDK1:n1>5</SOAPSDK1:n1>
<SOAPSDK1:n2>10</SOAPSDK1:n2>
</SOAPSDK1:Add>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
原因:
我也无法总结到底是谁的问题:(
也许是VS.NET的问题,也许是SoapToolKit的问题,也许是他提供的例子自身就有问题,也许是我的运行环境有问题,当然,更也许是我还没有真正理解xml的命名空间或没有正确使用WebService。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zzyx/archive/2005/03/24/328997.aspx
转自:http://wenku.baidu.com/link?url=8aHvnszzYMYuXrr9XFgWnj6zvdukPDgEP47U6VeD6JgmDC6R4Tn8h5eGFy0Lr2j8BpSeSDg3YLMWG8ux3n-YlTJaUFdiqeOJrJTbSL59iDS