DllImport 自动选择x64或x86 dll
来源:互联网 发布:淘宝金酷娃玩具拖车 编辑:程序博客网 时间:2024/05/17 16:46
前言
标题不知道怎么确切地命名,在.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跨平台或扫描二维码关注
- DllImport 自动选择x64或x86 dll
- C#调用本地动态链接库时,根据x86或x64自动选择相应的动态链接库dll文件
- x86或x64
- C#中调用C++动态链接库DLL两者目标平台X64或X86必须保持一致
- 專案參考X86跟X64的dll
- 请注意选择x86还是x64版本
- 编译anycpu 引用X86或X64问题
- SQLite自动切换32位64位dll兼容32位和64位问题 X86 X64
- x86 X64
- x86, x64
- x86,x64
- x86 x64
- x86 x64
- 检测一个DLL文件是x64还是x86
- 如何查看dll或者exe是X86还是X64架构
- Windows x86/ x64 Ring3层注入Dll总结
- Windows x86/ x64 Ring3层注入Dll总结
- x86,x64,Debug,release在VS中的编译如何选择
- Web前端知识体系精简
- 谈一下我们是怎么做数据库单元测试(Database Unit Test)的
- Ubuntu设置IP
- .Net Core 图片文件上传下载
- 数据结构导论第一章导图
- DllImport 自动选择x64或x86 dll
- 来腾讯云开发者实验室 学习.NET
- 不请自来 | Redis 未授权访问漏洞深度利用
- WebAssembly,开发者赢了
- JS中的事件冒泡
- Unity 游戏用XLua的HotFix实现热更原理揭秘
- Work Time Manager【开源项目】- 创建自己日志组件 2.0重构
- 详解CockroachDB事务处理系统
- SLAM关于旋转矩阵 欧拉角 四元数