VC++6.0调用Web Services(转)

80 篇文章 2 订阅
25 篇文章 0 订阅

第一部分

在vc6里调用WebService

 

突然要在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#javavc++.net等提供的服务都可以)!

 

本文主要讲述VC++6.0调用WebServices的方法,其中web services可以是c#javavc++.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只能看到VBASP     

         VC6开发WebServices 客户端收藏

下面是个控制台的样例

Toolkit3.0 终于给出VC6的样例了,1.0只能看到VBASP

 

 

#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 失败,无法这样创建ConnectorCXX0017Error :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

WebServiceVS.NET 2003

WebService运行环境:IIS

客户端:VC6.0VS.NET中的VC

SoapToolkit SDK3.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属性,尽管没有制定值。我们想办法屏蔽这个属性。

SoapSerializer30startElement方法中的参数中按照如下方式调用,可以不制定这个属性。

改代码如下:

 

 

...

 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中发出的请求,差别在哪里?认真看一下,n1n2没有指定命名空间,那么就指定一下吧。

把代码改成:

 

 

 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值