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 的调用。

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

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

上一篇:How to use GitHub with Android Studio


下一篇:几个NAND/NOR门可以表示一个XOR门?