C# 调用其他的动态库开发应注意的问题

1.背景

程序开发语言可以说是五花八门,这就引出了一个新问题 ,不同语言开发的系统进行对接时相关调用的问题。

下面我主要说一下我自己在做接口开发时遇到的问题及解决方法仅供参考,我使用的C#开发进行对接其他程序。

2.具体做法

首先,谈一下目前系统对接的几种常见对接方式。a.通过非托管的动态库dll文件导入。b.通过对方提供的COM组件调用。c.通过webService进行调用。

目前比较常用的就这个几种。下面一起看看都是如何具体调用实现以及遇到的问题。

a.通过非托管的动态库dll文件导入

此种方式在C#中的通用声明方式如下 。假如提供的dll 是InterfaceHN.dll   里面提供的方法        long init( char *Addr, int Port, char *Servlet)

[DllImport("InterfaceHN.dll")]  这里面还可以用  EntryPoint = "init",  CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true 属性指定更详细的信息 大家可以尝试一下 ,一般情况下只要指定函数入口点就行例如[DllImport("InterfaceHN.dll", EntryPoint = "init")]

public static extern Int32 init( [MarshalAs(UnmanagedType.VBByRefStr)] ref string addr, Int32 port, [MarshalAs(UnmanagedType.VBByRefStr)] ref string servlet);

public static extern Int32 init( [ StringBuilder  addr, Int32 port,  StringBuilder servlet);

在这种方式中,我以前遇到过的问题是内存保护,没有改方法 ,调用方法返回的值不正确等等问题。

这块就要注意参数的类型是不是两种语言都支持的,或者说是两种语言共有的 ,上面我就遇到过 ,文档上描述的是返回long  值 ,但是实际上返回的是Int32  导致这边出现内存保护提示。还有一点就是对于,带有参数返回值的这种情况 ,在C#一般字符串使用 StringBuilder  就可以 ,不行的话试一试[MarshalAs(UnmanagedType.VBByRefStr)] ref string  paras  这种方式。出问题之后,首先自己检查参数类型对不对,一般对方是不会有问题的,但也不排除对方给的dll本身就有问题。

b.通过对方提供的COM组件调用。

这种方式比较简单,因为他本身就是一种接口标准。使用时只要注册它,然后添加引用把它引入你的程序。实例化相关的对象就可以使用了。

具体注册方法 :在系统运行窗口中输入regsvr32 +com组件的地址 例如regsvr32 D:公共程序集\RM.ReportEngine.dll   取消注册是在后面添加/u 开关。

c.通过webService进行调用。

此种调用也是目前比较方便流行的一种。只要给出服务的地址就可以进行 。但是有些环境你没法访问。例如vpn ,专网等等。这时就不能直接通过添加服务的方式进行访问了,但是可以通过得到他们的服务描述xml文件进行访问,如果还不行,就自己通过反射的方式建立客户端代理具体如下:

public class WebServiceHelper
{
#region InvokeWebService 动态调用web服务

/// <summary>
/// 动态调用WebService
/// </summary>
/// <param name="url">WebService地址</param>
/// <param name="methodname">方法名(模块名)</param>
/// <param name="args">参数列表</param>
/// <returns>object</returns>
public static object InvokeWebService(string url, string methodname, object[] args)
{
return WebServiceHelper.InvokeWebService(url, null, methodname, args);
}
/// <summary>
/// 动态调用WebService
/// </summary>
/// <param name="url">WebService地址</param>
/// <param name="classname">类名</param>
/// <param name="methodname">方法名(模块名)</param>
/// <param name="args">参数列表</param>
/// <returns>object</returns>
public static object InvokeWebService(string url, string classname, string methodname, object[] args)
{
try
{

string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling";
if ((classname == null) || (classname == ""))
{
classname = WebServiceHelper.GetWsClassName(url);
}

//获取WSDL
WebClient wc = new WebClient();
Stream stream = wc.OpenRead(url + "?WSDL");
ServiceDescription sd = ServiceDescription.Read(stream);
ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
sdi.AddServiceDescription(sd, "", "");
CodeNamespace cn = new CodeNamespace(@namespace);

//生成客户端代理类代码
CodeCompileUnit ccu = new CodeCompileUnit();
ccu.Namespaces.Add(cn);
sdi.Import(cn, ccu);
CSharpCodeProvider csc = new CSharpCodeProvider();
ICodeCompiler icc = csc.CreateCompiler();

//设定编译参数
CompilerParameters cplist = new CompilerParameters();
cplist.GenerateExecutable = false;
cplist.GenerateInMemory = true;
cplist.ReferencedAssemblies.Add("System.dll");
cplist.ReferencedAssemblies.Add("System.XML.dll");
cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
cplist.ReferencedAssemblies.Add("System.Data.dll");

//编译代理类
CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);
if (true == cr.Errors.HasErrors)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
{
sb.Append(ce.ToString());
sb.Append(System.Environment.NewLine);
}
throw new Exception(sb.ToString());
}

//生成代理实例,并调用方法
System.Reflection.Assembly assembly = cr.CompiledAssembly;
Type t = assembly.GetType(@namespace + "." + classname, true, true);
object obj = Activator.CreateInstance(t);
System.Reflection.MethodInfo mi = t.GetMethod(methodname);
if (args == null)
return mi.Invoke(obj, null);
else
return mi.Invoke(obj, args);
}
catch (Exception ex)
{
throw new Exception(ex.InnerException.Message, new Exception(ex.InnerException.StackTrace));
}
}

private static string GetWsClassName(string wsUrl)
{
string[] parts = wsUrl.Split(‘/‘);
string[] pps = parts[parts.Length - 1].Split(‘.‘);

return pps[0];
}
#endregion
}

通过类WebServiceHelper这的方法  InvokeWebService(string url, string methodname, object[] args) 完成对方webservice 的调用。

一般在调用其他系统的东西时经常出现内存问题,找不到方法问题,无法连接问题,返回值不是值期望的值问题。这些问题只要仔细认真的分析

就可以解决,没有啥太难的东西。希望对你有帮助。

C# 调用其他的动态库开发应注意的问题

时间: 2024-09-30 09:02:57

C# 调用其他的动态库开发应注意的问题的相关文章

Android NDK开发及调用标准linux动态库.so文件

源:Android NDK开发及调用标准linux动态库.so文件 预备知识及环境搭建 1.NDK(native development Kit)原生开发工具包,用来快速开发C.C++动态库,并能自动将so文件和java应用一起打包成apk.对应:jni层c++开发 2.Cygwin:是windows平台上模拟Linux运行环境的工具,即window平台上的linux环境工具,so文件需要在linux平台上编译运行.对应:arm linux平台 3.CDT:eclipse下的C/C++开发工具,

C#调用C/C++动态库 封送结构体,结构体数组

因为公司一直都是做C++开发的,因客户需要要提供C#版本接口,研究了一下C#,发现其强大简洁, 在跨语言调用方面封装的很彻底,提供了强大的API与之交互.这点比JNA方便多了. Java与C#都只能调用C格式导出动态库,因为C数据类型比较单一,容易映射. 两者都是在本地端提供一套与之映射的C#/java描述接口,通过底层处理这种映射关系达到调用的目的. 一. 结构体的传递 Cpp代码   #define JNAAPI extern "C" __declspec(dllexport) /

C#调用非托管动态库中的函数方法

C#如何调用一个非托管动态库中的函数呢,比如用VC6写的动态库,总之C#调用动态库的过程是比Java调用DLL动态库方便快捷多了,下面举例说明这个过程. 1.创建一个非托管动态库 代码如下: 代码如下: //这一句是声明动态库输出一个可供外不调用的函数原型. extern   "C"  __declspec(dllexport)  int  add( int ,  int ); int  add( int  a, int  b) { //实现这个函数returna+b; } 除声明外,

C#调用C/C++动态库 封送结构体,结构体数组

因为实验室图像处理的算法都是在OpenCV下写的,还有就是导航的算法也是用C++写的,然后界面部分要求在C#下写,所以不管是Socket通信,还是调用OpenCV的DLL模块,都设计到了C#和C++数据类型的对应,还有结构体的封装使用.在夸语言调用方面,Java和C#都只能调用C格式导出的动态库,因为C数据类型比较单一,容易映射,两者都是在本地端提供一套与之映射的C#或者Java的描述接口,通过底层处理这种映射关系达到调用的目的. 5月19日学习内容: http://www.cnblogs.co

C#调用c++的动态库dll演示例程

1.首先编写c++动态库 extern "C" __declspec(dllexport) int __stdcall add(int x, int y) { return x + y; } extern "C" __declspec(dllexport) extern "C"使得在C++中使用C编译方式成为可能.在"C++"下定义"C"函数,需要加extern "C"关键词.用exte

python调用C/C++动态库

目录 1. 背景知识 1.1 动态链接库 1.2 extern "C"作用 1.3 动态链接库加载方式 1.3.1 隐式链接 1.3.2 显式链接 2. python操作动态库 2.1 加载动态库 2.2 指定函数命名 2.3 参数类型 2.3.1 值类型 2.3.2 指针类型 2.3.3 引用类型 2.3.4 结构体类型 本文以windows环境下的.dll动态链接库为背景展开,有关linux下的.so动态链接库的相关用法会在另外一篇文章中展开讲解. 1. 背景知识 一直以来pyth

动态调用动态库方法 .so

关于动态调用动态库方法说明 一.       动态库概述 1.  动态库的概念 日常编程中,常有一些函数不需要进行编译或者可以在多个文件中使用(如数据库输入/输 出操作或屏幕控制等标准任务函数).可以事先对这些函数进行编译,然后将它们放置在一些特殊的目标代码文件中,这些目标代码文件就称为库.库文件中的函数 可以通过连接程序与应用程序进行链接,这样就不必在每次开发程序时都对这些通用的函数进行编译了. 动态库是一种在已经编译完毕的程序开始启动运行时,才被加载来调用其中函数的库.其加载方式与静态库截然

thrift 编译调用boost动态库

In the project properties you must also set HAVE_CONFIG_H as force include the config header: "windows/confg.h" By default lib/cpp/windows/force_inc.h defines: #define BOOST_ALL_NO_LIB 1 #define BOOST_THREAD_NO_LIB 1 This has for effect to have

C语言 动态库简单开发

动态库项目 //简单的动态库开发----报文发送 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> //定义上下文结构体 typedef struct _SCK_HANDLE{ //定义报文IP char ipaddress[30]; //定义报文端口 char port[10]; //定义报文接受数组 unsigned char * buf;