3

我正在尝试使用 gSOAP 在 C++ 中创建 Web 服务。我从 ONVIF wsdl 生成了几个标头:

wsdl2h -x -o dm.h http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl -tC:\gsoap-2.8\gsoap\typemap.dat
wsdl2h -x -o an.h http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl -tC:\gsoap-2.8\gsoap\typemap.dat

之后,我编译了生成 C++ 服务代理和对象的头文件:

soapcpp2.exe -j -S dm.h -IC:\gsoap-2.8\gsoap\import;C:\gsoap-2.8\gsoap -x -qDm
soapcpp2.exe -j -S an.h -IC:\gsoap-2.8\gsoap\import;C:\gsoap-2.8\gsoap -x -qAn

为了获得类似于 gSOAP 文档描述的应用程序:http ://www.cs.fsu.edu/~engelen/soapdoc2.html#tth_sEc7.2.8

在 Visual Studio 中编译,我得到以下错误:

error C3861: 'soap_in_PointerToSOAP_ENV__Fault': identifier not found
error C3861: 'soap_in_PointerToSOAP_ENV__Header': identifier not found
error C3861: 'soap_out_PointerToSOAP_ENV__Fault': identifier not found
error C3861: 'soap_out_PointerToSOAP_ENV__Header': identifier not found

我试图按照文档所说的(http://www.cs.fsu.edu/~engelen/soapdoc2.html#tth_sEc19.35)关于由于 WITH_NOGLOBAL 的定义而根本没有编译序列化程序并编译了一个空的环境.h 文件,但这并没有解决问题。

我在网上搜索,但找不到任何解决方案。问题似乎与 Header 和 Fault 本身无关,而是与指针有关。正确的?我应该怎么办?

4

3 回答 3

2

这是解决方案。

  1. 运行wsdl2h -x -Nan -o an.h http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl。请注意,我在-Nan这里使用选项让soapcpp2 为该WSDL 中的两个绑定定义的两个服务生成两个服务/代理类。否则,您将获得一个服务/代理类,它将两者结合在一个类中,这并不优雅(但无论哪种方式都可以)。
  2. wsdl2h -x -o dm.h http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl
  3. 创建一个新文件env.h
  4. 编辑env.h并添加#import "xop.h"#import "wsa5.h"。基本上,您希望在此处导入所有基于插件的标头,因为插件必须使用全局(非 C++ 命名空间)结构。此外,env.h可以通过添加struct SOAP_ENV__Header和/或struct SOAP_ENV__Detail结构来自定义文件。这是交换 SOAP 标头和特定 SOAP 故障详细信息所必需的。在这种情况下就不需要了,因为#import "wsa5.h"已经为 WS-Addressing 定义了我们的 SOAP Headers。
  5. 运行soapcpp2 -penv env.h以生成全局 SOAP Header 和 SOAP Fault 序列化代码(envStub.henvH.henvC.cpp)。
  6. 编辑an.h并添加 SOAP Header 和 Faults 的以下定义

an.h:

struct SOAP_ENV__Header_
{
  // place SOAP Header elements here, if any
};
struct SOAP_ENV__Fault_
{
  char *faultcode;
  char *faultstring;
  char *faultactor;
  struct SOAP_ENV__Detail_ *detail;
  struct SOAP_ENV__Code_ *SOAP_ENV__Code;
  struct SOAP_ENV__Reason_ *SOAP_ENV__Reason;
  char *SOAP_ENV__Node;
  char *SOAP_ENV__Role;
  struct SOAP_ENV__Detail_ *SOAP_ENV__Detail;
};
struct SOAP_ENV__Detail_
{
  char *__any;
  int __type;
  void *fault;
};
struct SOAP_ENV__Code_
{
  char *SOAP_ENV__Value;
  struct SOAP_ENV__Code_ *SOAP_ENV__Subcode_;
};
struct SOAP_ENV__Reason_
{
  char *SOAP_ENV__Text;
};
  1. 通过使用而不是an.h更改行。struct SOAP_ENV__Envelope { struct SOAP_ENV__Header_ *SOAP_ENV__Header; _XML SOAP_ENV__Body; };struct SOAP_ENV__Header_struct SOAP_ENV__Header
  2. 通过使用而不是an.h更改行。struct SOAP_ENV__Fault_* Faultstruct SOAP_ENV__Fault_struct SOAP_ENV__Fault
  3. 对 .重复步骤 6-8 dm.h
  4. 现在您可以使用 C++ 命名空间,因此运行soapcpp2 -j -x -qAn -I $GSOAPPATH/gsoap/import -I $GSOAPPATH/gsoap an.h以在命名空间中生成 C++ 服务和代理类An(带有选项-qAn)。
  5. 运行soapcpp2 -j -S -x -qDm -I $GSOAPPATH/gsoap/import -I $GSOAPPATH/gsoap dm.h
  6. 由于我们使用的是duration插件(此自定义序列化程序是可选的,typemap.dat如果需要,可以编辑以将其删除,然后重新运行 wsdl2h),复制$GSOAPPATH/custom/duration.c到本地duration.cpp(注意 .cpp 扩展名,因为 MSVC++ 不喜欢将 .c 与 .cpp 源混合)。
  7. 编辑duration.cpp并更改#include "soapH.h"#include "anH.h".
  8. 然后用你的代码编译整个东西,例如 client-sidec++ yourclientapp.cpp DmC.cpp AnC.cpp envC.cpp DmDeviceBindingProxy.cpp AnRuleEngineBindingProxy.cpp AnAnalyticsEngineBindingProxy.cpp stdsoap2.cpp dom.cpp duration.cpp或 server-side c++ yourserviceapp.cpp DmC.cpp AnC.cpp envC.cpp DmDeviceBindingService.cpp AnRuleEngineBindingService.cpp AnAnalyticsEngineBindingService.cpp stdsoap2.cpp dom.cpp duration.cpp
  9. 如果您使用的是 WS-Addressing 插件,也$GSOAPPATH/gsoap/plugin/wsaapi.c请使用您的代码进行编译(但重命名wsaapi.c为,wsaapi.cpp因为 MSVC++ 不喜欢将 .c 与 .cpp 源混合)。

编辑

如果您typemap.dat进行如下更改,您可以跳过步骤 6-8,然后使用修改后的重新运行 wsdl2h typemap.dat

SOAP_ENV__Envelope  = struct SOAP_ENV__Envelope { struct SOAP_ENV__Header_ *SOAP_ENV__Header; _XML SOAP_ENV__Body; }; | struct SOAP_ENV__Envelope
SOAP_ENV__Header    = struct SOAP_ENV__Header_ { /* place SOAP Header elements here, if any */ }; | struct SOAP_ENV__Header_
SOAP_ENV__Fault     = \
struct SOAP_ENV__Fault_\
{\
  char *faultcode;\
  char *faultstring;\
  char *faultactor;\
  struct SOAP_ENV__Detail_ *detail;\
  struct SOAP_ENV__Code_ *SOAP_ENV__Code;\
  struct SOAP_ENV__Reason_ *SOAP_ENV__Reason;\
  char *SOAP_ENV__Node;\
  char *SOAP_ENV__Role;\
  struct SOAP_ENV__Detail_ *SOAP_ENV__Detail;\
};\
struct SOAP_ENV__Detail_\
{\
  char *__any;\
  int __type;\
  void *fault;\
};\
struct SOAP_ENV__Code_\
{\
  char *SOAP_ENV__Value;\
  struct SOAP_ENV__Code_ *SOAP_ENV__Subcode_;\
};\
struct SOAP_ENV__Reason_\
{\
  char *SOAP_ENV__Text;\
};\
| struct SOAP_ENV__Fault_
于 2017-10-26T14:23:09.353 回答
0

我遇到了这个问题,几乎失去了寻找解决方案的想法。我注意到一个指令 using#ifndef WITH_NOIDREF封装了一些soap_(out|in)_PointerToSOAP_ENV__(Fault|Header)标识符。然后,当使用WITH_NOIDREF定义的编译时,错误消息会减少一点。所以我手动封装了所有soap_(out|in)_PointerToSOAP_ENV__(Fault|Header)标识符并且它起作用了!

例子:

#ifndef WITH_NOIDREF
/// The soap_(out|in)_PointerToSOAP_ENV__(Fault|Header) indentifiers
// ...

#endif //WITH_NOIDREF

恐怕您正在使用 Windows,但我制作了一些脚本来自动化整个过程:

https://github.com/yudi-matsuzake/onvif-mkmakefile

于 2016-02-04T15:05:29.747 回答
0

使用该-q选项生成的代码似乎与soap_in_PointerToSOAP_ENV__Fault和存在命名空间问题soap_in_PointerToSOAP_ENV__Header。只有 1 个 wsdl 也会出现同样的问题。

另一种方法是使用这样的-p选项:

soapcpp2.exe -j -S dm.h -IC:\gsoap-2.8\gsoap\import;C:\gsoap-2.8\gsoap -x -pDm
soapcpp2.exe -j -S an.h -IC:\gsoap-2.8\gsoap\import;C:\gsoap-2.8\gsoap -x -pAn
于 2016-02-02T19:51:45.537 回答