通过 C# 库(.NET 互操作)从 C 语言引用 WebService





4.00/5 (6投票s)
2005年5月5日
5分钟阅读

63073
提供了从 C 项目通过 C# 库访问 WebService 的分步指南。
引言
在本篇文章中(这是对我上一篇已发布文章的修改!),我将举例说明如何使用 C# 库从 C 项目访问 WebService。此外,WebService 的 URL 也可以从 C 项目中的初始化文件(.ini)动态读取。
因此,这是一个典型的 .NET 互操作场景。C 项目将与 C# 库通信,C# 库再访问 WebService,并将必要的数据检索到 C# 库中。反过来,C# 库应解析返回的 XML,然后将返回的数据序列化为相应的结构,以便 C 项目可以使用它。
解决方案
首先,这是完成此任务的分步指南。
- 创建一个新的 C# 库 解决方案资源管理器 -> 添加 -> 添加新项目 -> Visual C# -> 类库。为项目命名(我们称之为 Library)。
- 添加对 WebService 的引用,解决方案资源管理器 -> C# 类库的添加引用 -> 添加 Web 引用,然后输入公开的 WebService 的 URL(例如:https://:8080/axis/service1/GmsWs?wsdl)并点击“转到”。一旦 WSDL 显示出来,为 WebService 指定一个描述性名称,然后点击“添加引用”。(我们称此引用为 WebService。)
- 现在,已添加 WebService,并创建了一个包装类来与服务交互。右键单击服务的 Web 引用,将 URL 行为从静态更改为动态,因为我们的程序将从初始化文件中动态读取服务 URL,并且构造函数也必须进行修改,使其接受一个字符串(WebService 的 URL)。
- 点击解决方案资源管理器选项卡上的“显示所有文件”图标,然后导航到服务引用部分下的 Reference.cs 文件,用自定义构造函数替换 WebService 的构造函数,该构造函数旨在动态读取 URL 并创建包装器。
[System.Web.Services.WebServiceBindingAttribute(Name="WsSoapBinding", Namespace="urn:GmsWs")] public class WsAPIService : System.Web.Services.Protocols. SoapHttpClientProtocol { /// <REMARKS /> /*public WsAPIService() { string urlSetting = System.Configuration.ConfigurationSettings.AppSettings ["Library.WebService.WsAPIService"]; if ((urlSetting !=null)) { this.Url = string.Concat(urlSetting, ""); } else { this.Url = https://:8080/axis/services/GmsWs; } */ //For generating dynamic wrapper classes based on the supplied URL public WsAPIService(string szURL) { this.Url = szURL; }
- 接下来,勾画 C# 库以调用 WebService,在访问方法之前创建 WebService 实例。
Library.WebService.WsAPIService myService = new Library.WebService.WsAPIService(URL);
Library
是我们的 C# 库的名称,WebService
是我们引用的 Web Service 的名称。WsAPIService
是服务器端 WebService 的名称。这可以在 WebService 生成的 WSDL 文件的 wsdl:service name =" " 标签中找到。此外,在实例化 WebService 时,必须将其 URL 传递给构造函数,因为我们已将其定义为动态的。 - 请记住为需要从 C DLL 访问的所有函数编写接口,因为它将仅通过创建的接口引用 C# 库的方法。
//Creating interfaces to the C# Library functions which //inturn access the webservice public interface IMyInterface { int LfindName2(string name, string URL); string LgetStandardName(string name,string URL); }
- 此外,在执行 .NET 互操作时,我们必须为创建的接口和类提供 GUID,因为 COM 依赖于注册表。我们必须为公开的接口和类提供唯一的 GUID。这相当于注册组件时生成的 CLSID。工具 -> 创建 GUID -> 注册表格式,这将生成可以合并到代码中的唯一 GUID。现在点击“复制”,然后将其粘贴到接口和其他类声明的上方。
Guid("876B4EAD-C5C2-4bd2-86C5-E132B1320006")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IMyInterface {..; .. }
- 还要记住创建与 COM 兼容的数据结构(参考Microsoft 开发人员网络库)。
- 在类中编写用于访问 WebService 的函数,请记住为类添加 GUID。
[Guid("59B6BA59-A296-4b38-AD6E-D0896C5D3FE8")] [ClassInterface(ClassInterfaceType.None)] public class LibraryImplementation : IMyInterface { public int LfindName2(string name, string URL) { try { //access webservice from here } catch { ... } } }
- 一旦 C# 库被勾画并成功编译,将其注册到 GAC,同时将其转换为类型库供 C DLL 导入。
regasm Library.dll /tlb Library.tlb
(Library 是我们 C# 库的名称;此命令可以放在 Visual Studio IDE 的生成后选项中。)
- 请记住程序集的强命名,是的,如果您需要进行 .NET 互操作,则必须这样做,所以请执行
sn -k Library.snk
这将生成一个密钥,您需要将其添加到您的项目中。
- 转到 assembly.cs 文件并填写标题、描述、公司、产品等。最重要的是,为程序集指定一个特定的版本号,而不是默认的 1.1.*.*,否则每次在进行小型更改后编译 DLL 时,修订号都会递增并在注册表中注册为新库。因此,指定一个像 1.1.1.1 这样的数字将停止不必要地填充注册表。在 assembly.cs 文件中也进行这些更改,将生成的强命名密钥添加到
AssemblyKeyFile
。[assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile("Library.snk")] [assembly: AssemblyKeyName("")]
- 将生成的 Library.tlb 文件导入到 C 项目的头文件中,并创建对 C# 库中声明的托管接口的引用。
///////////////////////////////////////////////////// // .NET Specific Header which is included in the C Project ////////////////////////////////////////////////////////// #pragma warning (disable: 4278) #include <string.h> #import <mscorlib.tlb> raw_interfaces_only // Ignoring the server namespace and using named guids: #if defined (USINGPROJECTSYSTEM) #import "..\Library\Library.tlb" no_namespace named_guids #else // Compiling from the command line, all files in the same directory #import "Library.tlb" no_namespace named_guids #endif using namespace std; /////////////////////////////////////////////////////////////// // End .NET Specific Header, #include this header to the C Main ///////////////////////////////////////////////////////////////
- C 代码只能通过托管接口访问 C# 库。
IMyInterface *test = NULL; CoInitialize(NULL); //Enter Single Threaded Apartment (STA)-STA Thread //Instantiate the COM object in the appropriate apartment HRESULT hr = CoCreateInstance(CLSID_LibraryImplementation,NULL,CLSCTX_INPROC_SERVER, IID_IManagedInterface,reinterpret_cast (&test)); if (FAILED(hr)) { MessageBox(NULL,"Couldn't create the instance!","C# Library",MB_OK); }
- 通过创建的托管指针访问相应的 C# 库函数。
string str; //getName is a function in the C# Library which inturn calls an exposed //function on the web service str = test->LfindName2(szSearchName,szURL);
- 在函数中使用托管接口后,我们必须清理 COM 以释放内存。
CoUninitialize(); test->Release();
- 好了,在那之前,我将告诉您如何从 C 中的 .INI 文件读取 WebService 的 URL。
//Reading the .INI file and getting the url of the webservice //ini file contains URL=https://:8080/axis/service/GmsWs?wsdl void CheckWebService(LPCSTR szIniFile) { CHAR wsURL[128]; GetPrivateProfileString("Central GMS","URL","", wsURL,sizeof(wsURL),szIniFile); if(strcmp(wsURL,"") != 0) { szURL = (_bstr_t) wsURL; } else { //default webservice running on localhost szURL = (_bstr_t) "https://:8080/axis/services/GmsWs?wsdl"; } }
- 最后,处理抛出或接收的错误和异常以及两个库之间的通信。
- 将 C# 库转换为类型库也可以通过命令实现
tlbexp Library.dll /out:Library.tlb
在客户端 PC 上安装生成的 DLL。
最后一步是在目标 PC 上安装生成的 DLL。这可以通过将生成的 C DLL 和 C# 库(Library.dll)复制到目标 PC 的应用程序目录,然后执行以下命令来实现:
regasm Library.dll /tlb:Library.tlb
gacutil /I Library.dll
目标 PC 所需的软件
目标 PC 应安装 .NET Framework 可再发行组件包。您可以从 Microsoft 网站下载。
摘要
本文介绍了一种通过创建 C# 库来在 WebService 和 C 项目之间进行接口,从而从 C 语言访问 WebService 的方法。如需进一步澄清,请给我发送电子邮件。
使用的命名空间
using System;
using System.Runtime.InteropServices; // for interop services
using System.IO;
using System.Xml; //for parsing the xml
using System.Collections; // in case you are using collection to hold data
using System.ComponentModel;
using System.Text;
using System.Data;