DllImport 自动选择x64或x86 dll

前言

标题不知道怎么确切地命名,在.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

原文地址:http://www.cnblogs.com/kewei/p/7011387.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325187.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《金色梦乡》金句摘抄(八)

System.out.println("《金色梦乡》"); System.out.println("小说类型的书就是比散文类型的书好看"); System.out.println("通俗易懂"); System.out.println("这周能看完");他转身背对着安保探头,有种被看门人或看门狗盯上了…

JavaFX官方教程(八)之JavaFX中的动画和视觉效果

翻译自 JavaFX中的动画和视觉效果 您可以使用JavaFX快速开发具有丰富用户体验的应用程序。在本入门教程中,您将学习如何使用非常少的编码创建动画对象并获得复杂的效果。 图7-1显示了要创建的应用程序。 图7-1彩色圆圈应用 图7-2显示了该ColorfulCircles应用程序…

《金色梦乡》金句摘抄(九)

System.out.println("《金色梦乡》"); System.out.println("小说类型的书就是比散文类型的书好看"); System.out.println("通俗易懂"); System.out.println("这周能看完");他在观察,就像饲养员为了掌握动物的情况和习性而观…

广搜(初见)

以下是广搜水题 题意:输入一个n*n的迷宫,输入从起点到终点的最短路 输入: 12 //迷宫大小 2 9 11 8 //起点和终点 1 1 1 1 1 1 1 1 1 1 1 1 //邻接矩阵,0表示通,1表示不通 1 0 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 0 …

.Net Core 图片文件上传下载

当下.Net Core项目可是如雨后春笋一般发展起来,作为.Net大军中的一员,我热忱地拥抱了.Net Core并且积极使用其进行业务的开发,我们先介绍下.Net Core项目下实现文件上传下载接口。 一、开发环境 毋庸置疑,宇宙第一IDE VisualStu…

JavaFX官方教程(九)之转换

翻译自 Transformations Overview 本章介绍JavaFX中支持的转换。 所有转换都位于javafx.scene.transform包中,并且是类的子Transform类。 介绍转换 变换根据某些参数改变坐标系中图形对象的位置。JavaFX支持以下类型的转换: 翻译 回转 缩放 剪毛 …

《金色梦乡》金句摘抄(十)

System.out.println("《金色梦乡》"); System.out.println("小说类型的书就是比散文类型的书好看"); System.out.println("通俗易懂"); System.out.println("这周能看完");“面对遭受迫害的人,有人选择拯救,有人…

stream流把list转为map

1.对象中的属性转map 通过Collectors.toMap list.stream().collect(Collectors.toMap(Person::getId,Person::getName)); 2.收集对象本身 list.stream().collect(Collectors.toMap(Person::getId,list->list)

广搜(练习4题)

几道例题还比较简单,练习就卡了比较长的时间了(。_。) 所以我会写一下解题思路了(๑ŐдŐ) 还有博客抽风所以代码里会有一些奇奇怪怪的东西,无视就好了qwq。 这几道题我就按各人认为的难易程度来排序吧QAQ。 第一题. 题意:输入一个迷宫&…

谈一下我们是怎么做数据库单元测试(Database Unit Test)的

背景介绍 最近在团队在做release之前的regression,把各个feature分支merge回master之后发现DB的单元测试出现了20多个失败的test cases。之前没怎么做过DB的单元测试,正好借这个机会熟悉一下写DB单元测试的流程。 这篇博文中首先介绍一下在我们的特定项目场景中是…

JavaFX官方教程(十)之转换类型和示例

翻译自 Transformation Types and Examples 本文档描述了特定的转换并提供了代码示例。 转换 平移变换沿着相对于其初始位置的一个轴将节点从一个位置移动到另一个位置。木琴条的初始位置由x,y和z坐标定义。在实施例2-1中,初始位置值由指定的xStart&a…

ssl2293-暗黑游戏【dp练习题】

题目: 暗黑游戏中,装备直接决定玩家人物的能力。可以使用Pg和Rune购买需要的物品。暗黑市场中的装备,每件有不同的价格(Pg和Rune)、能力值、最大可购买件数。Kid作为暗黑战网的一个玩家,当然希望使用尽可能…

java知识点整理

1.char类型可以整型类型的值 2.变量的命名规则: (1)由字母、、$ 开头的 (2)后面部分可以拾字母、数字、下划线、$ (3)不能是java的关键词 (4)变量名要有意义 3.0是偶数 4.数据类型转换规则: int(源类型) a 1.0(目标类型); (1)源类型大于目标类型&#…

比特(bit)和字节(byte)(1byte=8bit)

一个0或者一个1存储为一个比特(bit),是计算机中最小的存储单位。 计算机中是最基本的存储单元是字节(byte) 。每个字节由8个比特构成。

定位

绝对定位 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title><style>.div1{height: 200px;width: 200px;background-color: gray;/*绝对定位 基于父级标签原点移开以后会自动释放父级标签原点位置*/po…

Web前端知识体系精简

Web前端技术由html、css和javascript三大部分构成&#xff0c;是一个庞大而复杂的技术体系&#xff0c;其复杂程度不低于任何一门后端语言。而我们在学习它的时候往往是先从某一个点切入&#xff0c;然后不断地接触和学习新的知识点&#xff0c;因此对于初学者很难理清楚整个体…

JavaFX官方教程(十一)之动画基础

翻译自 动画基础 动画基础提供基本动画概念&#xff0c;包含以下部分&#xff1a; 转变 时间线动画 插值 JavaFX中的动画可以分为时间轴动画和过渡。本章提供了每种动画类型的示例。 Timeline并且Transition是javafx.animation.Animation该类的子类。有关特定类&#xff…

《金色梦乡》金句摘抄(十一)

System.out.println("《金色梦乡》"); System.out.println("小说类型的书就是比散文类型的书好看"); System.out.println("通俗易懂"); System.out.println("今天准备看完");从一开始他就觉得难以置信&#xff0c;感觉就像是身处迷雾当…

ssl2295-暗黑破坏神【dp练习】

题目&#xff1a; 无聊中的小x玩起了Diablo I... 游戏的主人公有n个魔法 每个魔法分为若干个等级&#xff0c;第i个魔法有p[i]个等级(不包括0) 每个魔法的每个等级都有一个效果值&#xff0c;一个j级的i种魔法的效果值为w[i][j] 魔法升一级需要一本相应的魔法书 购买魔法书…