前言

标题不知道怎么确切地命名,在.net的托管世界里,有时不得不使用c的某个动态库,比如ocr、opencv等,如果幸运,有前人已经包装出.net版本,但有些不非常流行的库,只能自己使用pinvoke或c++ cli包装了,比如笔者就遇到了一个,mqtt客户端库。

Pinvoke的多平台问题

如果您没有接触过如何调用非托管dll,没有了解过c#的DllImportAttribute,可以看看以下资料:

1、DllImportAttribute

2、Pinvoke

3、extern 关键字

多平台支持问题来源:

1、c的库是编译时确定了平台,比如x86或x64,一个dll不能在运行时既支持x86也支持x64,所以如果引用它的.net程序还想支持any cpu,只能在运行后根据平台去加载对应平台的c的库;

2、DllImport 特性要求传入string dllName参数,这个参数可以是相对路径或绝对路径,但.Net的特性有个要求:特性实参必须是特性形参类型的常量表达式、typeof 表达式或数组创建表达式。也就是说string dllName这个值必须在写代码的时候(编译时)就是常量的,而不能在运行时传给它;

3、DllImport 特性是密封的,我们不能继承它或修改它的什么逻辑,到达运行时得到与平台匹配的string dllName的值 ;

Pinvoke的多平台解决方案

1、绕过DllImport

InteropDotNet

这是开源在github上的一个项目,作者使用了LoadLibrary(c.dll) + GetProcAddress 转换为.Net委托的思想来完成,对于c.dll的所有函数的调用上,实际上已经完全脱离了.Net提供的DllImport特性,所以不受到上面问题2与3的约束,使用本项目,调用c.dll的.net程序也可是any cpu了。

2、笔者的方案

笔者的方案还是沿用.Net的DllImport特性,我们知道DllImport会帮我们自动查找到加载c.dll,然后大概才把DllImport声明的外部实现方法与c.dll的函数地址映射上,如果我们在准备调用c.dll的外部方法之前,通过LoadLibrary Api把c.dll加载到.net程序里,DllImport会不会就不再搜索c.dll而是直接使用?

实验开始

将c.dll对应的x86与x64两个版本都放在.net程序的子目录,构造如下:

dotnet.exe

x86\c.dll

x64\c.dll

dotnet.exe DllImport声明如下:

[DllImport("c.dll")]
static extern int MethodC ( );

实验结果

如果默认运行,一定会报找不到dll文件的异常,因为DllImport的本程序目录或系统目录或path环境下都没有找到c.dll;

如果我们在调用 MethodC 之前,检测当前进程是32位还是64位,使用windows api 的LoadLibrary 函数将x86\c.dll或x64\c.dll加载到本进程,就不会报找不到文件的异常,而且调用MethodC 也是正常的。

实验总结

可以一如既往的使用DllImport特性,如果想要any cpu的效果,在调用外部实现方法之前,先将它的dll手动加载。

以下是我的实现代码,在静态构造器里加载正确的dll就行,支持自动x86或x64,而且在asp.net里也能正确找到非托管的dll

    static class MQTTAsync
{
private const string mqtt3a_dll = "paho-mqtt3a.dll"; [DllImport(mqtt3a_dll, CallingConvention = CallingConvention.Cdecl)]
public static extern MqttError MQTTAsync_connect(
IntPtr handle,
ref MQTTAsync_connectOptions options); [DllImport("kernel32")]
private static extern IntPtr LoadLibraryA(
[MarshalAs(UnmanagedType.LPStr)] string fileName); static MQTTAsync()
{
var dllFile = Path.Combine(Environment.Is64BitProcess ? "x64" : "x86", mqtt3a_dll);
if (HttpContext.Current != null)
{
dllFile = Path.Combine("~\\bin", dllFile);
dllFile = HttpContext.Current.Server.MapPath(dllFile);
}
MQTTAsync.LoadLibraryA(dllFile);
}
}

笔者最近在搞mqtt,使用pinvoke将c版本的mqtt客户端包装,项目开源在github上,如果你感兴趣,可以过来看看

https://github.com/xljiulang/Paho.MqttDotnet

DllImport 自动选择x64或x86 dll的更多相关文章

  1. VS中自动选择x86或x64的dll

    http://www.cnblogs.com/lzjsky/archive/2010/09/06/1819321.html 原来使用Win7的32位系统,进行C#工程的开发,后来重装系统,换成了win ...

  2. 转:x64与x86的改变

    http://tieba.baidu.com/p/1250470248 x64与x86的改变 硬件要求就是64位的CPU.操作系统也必须是64位的,如果在64位的CPU上安装了32位的操作系统,就算编 ...

  3. js单击自动选择文本

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  4. ECshop网点程序优化-后台添加类目自动选择上次父类目并计算Sort Order

    如果在ECshop后台批量添加过大量类目的人都能体会到是多么的不方便(这点还是要说一下ECshop的产品经理,细节上还是要多注意),每次添加都需要在几百个类目里面找到要添加的父类目也是一个麻烦事,比如 ...

  5. Android自定义垂直滚动自动选择日期控件

    ------------------本博客如未明正声明转载,皆为原创,转载请注明出处!------------------ 项目中需要一个日期选择控件,该日期选择控件是垂直滚动,停止滚动时需要校正日期 ...

  6. C#自动选择出系统中最合适的IP地址

    写这个是因为很长时间以来,碰到过很多次这个问题,但都没当回事,这次又碰到了这个老问题,无奈百度了一圈儿未果,身边又没有大牛可以请教,就自己先“总结”了一套方法,一来给自己记录,二来如果碰巧能有朋友看到 ...

  7. JS-加载页面的时候自动选择刚才所选择option

    <body class="no-skin" onload="option_auto(${pd.PACK_SORT})"> <select na ...

  8. 解决:IE中不能自动选择UTF-8编码的解决方法

    IE中不能自动选择UTF-8编码的解决办法 在windows操作系统上使用IE作为浏览器时.常常会发生这样的问题:在浏览使用UTF-8编码的网页时,浏览器无法自动侦测(即没有设定“自动选择”编码格式时 ...

  9. PS中如何提高修改psd图片的效率(自动选择工具)

    在photoshop中制作图片的时候,一般要养成保留psd格式的习惯,纵然普通时候jpg,png格式常用,考虑到以后可能需要修改,也应该备份一下.如果考虑到以后需要修改,可每次成品保存成两个,一个ps ...

随机推荐

  1. 在国内使用maven下载jar包非常慢的解决方法

    在国内使用maven下载jar包非常慢的解决方法 1.原因: 很多jar包在国外环境,所以会很慢. 2.解决方法 maven支持镜像环境下载,所以首先找到maven的conf目录中的settings. ...

  2. 【WPF】学习笔记(一)——做一个简单的电子签名板

    参加实习(WPF)已经有两个多周的时间了,踩了一些坑,也算积累了一些小东西,准备慢慢拿出来分享一下.(●'◡'●) 这次呢就讲讲一个简单的电子签名板的实现. 先上张图(PS:字写得比较丑,不要太在意哈 ...

  3. iOS APP打包分发给远程的手机测试

    APP要打包给远程的朋友或客户测试,但又不是企业账号的情况下,我们只能根据手机的udid进行描述证书的配置,再打包分发给提供了udid的手机进行安装 一.如何得到udid? 手机连接到mac电脑,打开 ...

  4. Windows上Ruby开发环境的配置

    最近公司项目上有需要,需要开发一个puppet的自动化工具,这个工具需要操作存储设备上的各种资源,而鉴于puppet不是善于完成这个任务的首选语言,于是我们选择了puppet的“爹”,Ruby. 熟悉 ...

  5. 最准确的单点登录SSO图示和讲解(有代码范例)|手把手教做单点登录(SSO)系列之二

    写第一篇博客<手把手教做单点登录(SSO)系列之一:概述与示例>,就获得了园子里朋友们热情的评论和推荐,感谢各位. 我那篇文章同时发了CSDN和博客园.对比一下,更感受到博客园童鞋们的技术 ...

  6. coding.net及git的使用方式

    一般部分测试的公司里可能会用到代码管理工具,这里可能不得不推荐coding.net和git这个工具,类似于svn,不过用命令行的情况多点 这里简单介绍下 1.建立coding.net 首先新建一个co ...

  7. PHP获得上(两)周时间

    就不手写了

  8. [js笔记整理]DOM 篇

    一.节点类型 1.元素节点:HTML元素 2.文本节点:元素标签中的内容 3.属性节点:元素的属性 (检测节点类型:node.nodeType //元素=1,属性=2,文本=3) 二.使用DOM获取元 ...

  9. Asp.net mvc 小试牛刀一:多语言支持

    最近因为项目需要又从UWP开发转到了Asp.net mvc 开发,由于也不是什么老手,所以就将项目常见的一些技术问题记录一下自己的解决方案. 第一个需求:用户可以自由切换界面显示语言. 解决方案一:界 ...

  10. Java7中的ForkJoin并发框架初探(下)—— ForkJoin的应用

    前两篇文章已经对Fork Join的设计和JDK中源码的简要分析.这篇文章,我们来简单地看看我们在开发中怎么对JDK提供的工具类进行应用,以提高我们的需求处理效率. Fork Join这东西确实用好了 ...