为非托管 C 客户端创建 WCF 服务

新手上路,请多包涵

我需要让非托管 Windows C++ 客户端与 WCF 服务通信。 C++ 客户端可以在 Win2000 及更高版本上运行。我可以控制 WCF 服务和正在使用的 C++ API。由于它是用于专有应用程序,因此最好尽可能使用 Microsoft 的东西,绝对不是 GNU 许可的 API。那些有它工作的人,你能分享一个如何让它工作的分步过程吗?

到目前为止,我已经研究了以下选项:

  • WWSAPI - 不好,不能在 Win 2000 客户端上工作。
  • ATL Server,使用 以下指南 作为参考。我遵循了概述的步骤(删除策略引用并展平 WSDL),但是生成的 WSDL 仍然不能被 sproxy 使用

还有什么想法吗?请仅在您自己实际使用时才回答。

Edit1 :我为任何我可能感到困惑的人道歉:我正在寻找的是一种从没有安装 .NET 框架的客户端调用 WCF 服务的方法,因此不能选择使用基于 .NET 的帮助程序库,它必须是纯非托管 C++

原文由 galets 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 509
2 个回答

对于那些感兴趣的人,我找到了一个半工作的 ATL Server 解决方案。以下是主机代码,注意它使用的是 BasicHttpBinding,它是唯一与 ATL Server 一起工作的代码:

         var svc =  new Service1();
        Uri uri = new Uri("http://localhost:8200/Service1");
        ServiceHost host = new ServiceHost(typeof(Service1), uri);

        var binding = new BasicHttpBinding();
        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService1), binding, uri);
        endpoint.Behaviors.Add(new InlineXsdInWsdlBehavior());

        host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });
        var mex = host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
        host.Open();

        Console.ReadLine();

InlineXsdInWsdlBehavior 的代码可以在 这里 找到。需要对 InlineXsdInWsdlBehavior 进行一项重要更改,以便在涉及复杂类型时它可以与 sproxy 一起正常工作。它是由 sproxy 中的错误引起的,它没有正确限定命名空间别名,因此 wsdl 不能有重复的命名空间别名,否则 sproxy 会出错。以下是需要更改的功能:

     public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
    {
        int tnsCount = 0;

        XmlSchemaSet schemaSet = exporter.GeneratedXmlSchemas;

        foreach (WsdlDescription wsdl in exporter.GeneratedWsdlDocuments)
        {
            //
            // Recursively find all schemas imported by this wsdl
            // and then add them. In the process, remove any
            // <xsd:imports/>
            //
            List<XmlSchema> importsList = new List<XmlSchema>();
            foreach (XmlSchema schema in wsdl.Types.Schemas)
            {
                AddImportedSchemas(schema, schemaSet, importsList, ref tnsCount);
            }
            wsdl.Types.Schemas.Clear();
            foreach (XmlSchema schema in importsList)
            {
                RemoveXsdImports(schema);
                wsdl.Types.Schemas.Add(schema);
            }
        }
    }

    private void AddImportedSchemas(XmlSchema schema, XmlSchemaSet schemaSet, List<XmlSchema> importsList, ref int tnsCount)
    {
        foreach (XmlSchemaImport import in schema.Includes)
        {
            ICollection realSchemas = schemaSet.Schemas(import.Namespace);
            foreach (XmlSchema ixsd in realSchemas)
            {
                if (!importsList.Contains(ixsd))
                {
                    var new_namespaces = new XmlSerializerNamespaces();
                    foreach (var ns in ixsd.Namespaces.ToArray())
                    {
                        var new_pfx = (ns.Name == "tns") ? string.Format("tns{0}", tnsCount++) : ns.Name;
                        new_namespaces.Add(new_pfx, ns.Namespace);
                    }

                    ixsd.Namespaces = new_namespaces;
                    importsList.Add(ixsd);
                    AddImportedSchemas(ixsd, schemaSet, importsList, ref tnsCount);
                }
            }
        }
    }

下一步是生成 C++ 头文件:

 sproxy.exe /wsdl http://localhost:8200/Service1?wsdl

然后 C++ 程序看起来像这样:

 using namespace Service1;

CoInitializeEx( NULL, COINIT_MULTITHREADED  );

{
    CService1T<CSoapWininetClient> cli;
    cli.SetUrl( _T("http://localhost:8200/Service1") );

    HRESULT hr = cli.HelloWorld(); //todo: analyze hr
}

CoUninitialize();
return 0;

生成的 C++ 代码可以很好地处理复杂类型,只是它不能将 NULL 分配给对象。

原文由 galets 发布,翻译遵循 CC BY-SA 2.5 许可协议

我将创建一个 C# 托管类来完成 WCF 工作并将该类作为 COM 对象公开给 C++ 客户端。

原文由 kenny 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题