vc++调用webservice

        正在看着AV(AreCont)SDK的时候,老大突然让我转到soap上,原因是刚进公司的我,第一项任务便是研究ONVIF(so many specifications),当然主要的还是看core specification,这是一个axis,bosch and sony 三大牛x整出来的标准规范,为开发网络视频设备软件开发商提供一个标准规范,但是至今为止仍只是少数公司加入了标准规范的行列,可能是他们不求上进吧 。

         在core specification中最主要的还是提到了webservice,兼容RTSP,RTCP, RTP 实现实时流传输,采用vc++实现,所以公司还是考虑通过vc++调用webservice,所以老大便给了我这个任务,先熟悉一下。整了一天,才搞了个差不多,感觉很是纳闷,其实程序看起来很简单,但是细节往往能让人迷糊一大段时间。

         其实看了阿瑞得文章后,基本上差不多,当然先装soap toolkit3.0是前提,不过中间还是遇到很多问题的,又通过不断的查阅才得以解决,其中总是发生中断的情况,这个主要是因为webservice得URL没有写正确或者没有搞清URL和Namespace Uri的原因吧。不多说了,还是先看我做的流程吧。

First step: New a Asp.net Web Service Application project.

The following is the  content of  Service1.asmx.cs:

using System;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
namespace TestWebService
{
    [SoapDocumentService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)]

    [WebService(Namespace = "http://localhost/WebService/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
    // [System.Web.Script.Services.ScriptService]
    public class Service : System.Web.Services.WebService
    {
        public Service()
        {
            //CODEGEN: 该调用是 ASP.NET Web 服务设计器所必需的
            InitializeComponent();
        }


        #region 组件设计器生成的代码
 

        //Web 服务设计器所必需的
        private System.ComponentModel.IContainer components = null;


        /**/
        /// <summary>
        /// 设计器支持所需的方法 - 不要使用代码编辑器修改
        /// 此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {

        }

        /**/
        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing && components != null)
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #endregion

        // WEB 服务示例
        // HelloWorld() 示例服务返回字符串 Hello World
        // 若要生成,请取消注释下列行,然后保存并生成项目
        // 若要测试此 Web 服务,请按 F5 键

        [WebMethod]
        public int Hello(int strName, int strPwd)
        {
            int temp = strName * strPwd;
            return temp;
        }

        [WebMethod]
        public string HelloWorld(int strName, int strPwd)
        {
            return "我是shawn!";
        }

        [WebMethod]
        public string GetStringName()
        {
            return "shawn,rock!!!";
        }
    }
}

Then F5 debug mode test the application.

Second step:

New a win32 console application:

New a WSWrapper class:

WSWrapper.h


#ifndef _WS_WRAPPER_H_
#define _WS_WRAPPER_H_
#import "msxml4.dll"
#import "C:/Program Files/Common Files/MSSoap/Binaries/mssoap30.dll" /
    exclude("IStream", "IErrorInfo", "ISequentialStream", "_LARGE_INTEGER", /
    "_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")

#include <string>
#include <Windows.h>
using namespace MSXML2;
using namespace MSSOAPLib30; 
using std::string;

typedef struct
{
    char * sParamName;
    char * sParamValue;
}WSPARAM;

class WSWrapper
{
public:   
    WSWrapper();
    virtual ~WSWrapper();   
    bool InvokeSoap(string wsURL,
                  string wsNameSpace,
                  string wsMethod,
                  WSPARAM  *wsParam,
                  int wsCount,
                  char *sEmsg,
                  char *sRmsg,
                  bool wsXML);

private:
/*  const char *_wsURL;
    const char * _wsNameSapce;
    const char *_wsMethodName;  */
};

#endif

WSWrapper.cpp
#include"WSWrapper.h"
#include<cstdlib>
#include<cstdio>
using namespace std;

WSWrapper::WSWrapper()
{
}
 

WSWrapper::~WSWrapper()
{
    try
    {
       CoUninitialize();
    }
    catch(...)
    {

    }  
}

 

//   参数说明:
//   wsURL:WEBSERVICE的链接地址
//   wsNameSpace:在页面中定义的命名空间,一般地使用:http://tempuri.org/
//   wsMethod:要访问的WEBSERVICE 方法名
//   wsParam: 要使用的参数,见WSPARAM定义,
//   wsCount: 参数总数
//   sEmsg://要返回给调用函数的错误码率信息
//   sRmsg: //要返回的捃执行结果信息
//   wsXML:要返回的是XML值还是TEXT
//   返回值:
//   如果正常执行返回true,中间有问题就返回false;
bool WSWrapper::InvokeSoap(string wsURL,
                        string wsNameSpace,
                        string wsMethod,
                        WSPARAM  *wsParam,
                        int wsCount,
                        char *sEmsg,
                        char *sRmsg,
                        bool wsXML)
{   
       HRESULT hr = CoInitialize(NULL);//初始化com环境
       if(FAILED(hr))
       {
           strcpy(sEmsg,"初始化COM失败");
           printf("initialized com failed.");
           return false;
       }

       ISoapSerializerPtr Serializer;
       ISoapReaderPtr Reader;
       ISoapConnectorPtr Connector;

       //连接到WebService
       hr = Connector.CreateInstance(__uuidof(HttpConnector30));
       if(FAILED(hr))
       {
           //创建com对象出错,一般是因为没有安装com
           strcpy(sEmsg,"创建HttpConnector FAILED");
           printf("create HttpConnector failed.");
           return false;
       }

       Connector->Property["EndPointURL"] = wsURL.c_str();
       hr = Connector->Connect();
       if (FAILED(hr))
       {
           strcpy(sEmsg,"连接WEBSERVICE FAILED");
           printf("connecting webservice failed.");
           return false;
       }

       Connector->Property["SoapAction"] = (wsNameSpace + wsMethod).c_str();     

       //开始创建webservice的请求Soap包
       Connector->BeginMessage();
       hr = Serializer.CreateInstance(__uuidof(SoapSerializer30));
       if (FAILED(hr))
       {
           strcpy(sEmsg,"CreateInstance Serializer FAILED");
           printf("create instance Serializer failed.");
          return false;
       }

 
       Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
       Serializer->StartEnvelope("SOAP", "http://schemas.xmlsoap.org/soap/envelope/", "");
       Serializer->SoapAttribute("xsi", "", "http://www.w3.org/2001/XMLSchema-instance", "xmlns");
       Serializer->SoapAttribute("xsd", "", "http://www.w3.org/2001/XMLSchema", "xmlns");
       //Serializer->StartEnvelope("","","");
       Serializer->StartBody(L"NONE");
       Serializer->StartElement(wsMethod.c_str(), wsNameSpace.c_str(), "NONE", "");

       for (int i = 0; i < wsCount; i++)
       {
           Serializer->StartElement(wsParam[i].sParamName,wsNameSpace.c_str(),"NONE","");
           Serializer->WriteString(wsParam[i].sParamValue);
           Serializer->EndElement();
       }

       Serializer->EndElement();
       Serializer->EndBody();
       Serializer->EndEnvelope();       

       try
       {
           Connector->EndMessage();
       }
       catch (...)
       {
           strcpy(sEmsg,"提交SOAP消息出错");
           printf("提交SOAP消息出错");
           return false;
       }


       //解析返回的soap包
       hr = Reader.CreateInstance(__uuidof(SoapReader30));
       if(FAILED(hr))
       {
           strcpy(sEmsg,"CreateInstance READER FAILED");
           printf("create instance reader failed.");
           return false;
       }
 

       Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "");

       if (wsXML)
       {
           strcpy(sRmsg,(const char*)Reader->RpcResult->xml);
       }
       else
           strcpy(sRmsg,(const char*)Reader->RpcResult->text);
       return true;
}

The last file is TestApp.cpp:

#include "WSWrapper.h"
int main()
{
    string url = "http://localhost:1451/Service1.asmx";
    string uri = "http://localhost/WebService/";
    string methodName = "HelloWorld";

    WSPARAM *params = new WSPARAM[2];
    params[0].sParamName = "strName";
    params[0].sParamValue = "3";
    params[1].sParamName = "strPwd";
    params[1].sParamValue = "4";
    char errorMessage[20];
    char revMessage[100];
    WSWrapper wsWrapper;
    int wsParaCount = 2;
    bool retValue = wsWrapper.InvokeSoap(url,uri,methodName,params,wsParaCount,errorMessage,revMessage,false);

    if (retValue)
    {
       printf("%s",revMessage);
    }

    getchar();
    getchar();
    return 0;
}

其实我遇到的一个最大的问题就是没有返回值的问题,最终还是不小心找到了解决方案,就是:

       Serializer->StartElement("strName", _wsNameSapce.c_str(), "NONE", "");
       //Serializer->SoapAttribute("xsi:type", "", "xsd:string", "");
       Serializer->WriteString("3");       
       Serializer->EndElement();
       Serializer->StartElement("strPwd",_wsNameSapce.c_str(),"NONE","");
       Serializer->WriteString("4");
       Serializer->EndElement();

一开始的时候,并没有指定strName和strPwd的namespace,最好是跟method的namespace是一致的,就是_wsNameSapce.c_str()。还有一个就是注意当运行webservice的时候把TestApp.cpp中的url改成运行测试webservice的url路径。当然还遇到了其他很多方面的问题,欢迎有需要的人跟我交流。



你可能感兴趣的:(vc++调用webservice)