2019-8-30-C#-如何在项目引用x86-x64的非托管代码
| title | author | date | CreateTime | categories |
|---|---|---|---|---|
|
C# 如何在项目引用x86 x64的非托管代码
|
lindexi
|
2019-08-30 08:53:52 +0800
|
2018-03-03 20:43:34 +0800
|
C#
|
因为现在的项目使用的是 AnyCpu 在 x86 的设备使用的是x86,在x64使用的是x64,但是对于非托管代码,必须要在x64使用x64的dll,在x86使用x86的dll。在C++没有和C#一样的 AnyCpu 所以需要在项目运行在x86的时候加载x86的dll。
本文告诉大家如何在代码引用不同的dll。
使用宏
最简单的方法是编译两个版本,编译多个版本可以点击配置管理器,然后创建x86和x64,然后版本添加宏,这样就可以判断宏来使用不同的dll
点击活动解决方案平台,然后点击新建
选择项目属性,点击生成,就可以添加不同的宏
于是在后台代码可以这样写
#if x86
public const string DLL_FILE_NAME = "SvkiqauhKvdhrureh32.dll";
#else
public const string DLL_FILE_NAME = "SvkiqauhKvdhrureh64.dll";
#endif [DllImport(DLL_FILE_NAME, EntryPoint = "HfwzsnHzhpbbzbn", CallingConvention = CallingConvention.Cdecl)]
private static extern int HfwzsnHzhpbbzbn(int var1, int var2);
可以看到这个方法如果有很多个 dll 那么需要写很多路径
多个函数
实际上如果已经有两个dll ,那么可以使用两个不同函数
[DllImport("SvkiqauhKvdhrureh32.dll", EntryPoint = "HfwzsnHzhpbbzbn",
CallingConvention = CallingConvention.Cdecl)]
private static extern int HfwzsnHzhpbbzbn32(int txcuiwKjvwu, int hhmzfadnHexkmr);
[DllImport("SvkiqauhKvdhrureh64.dll", EntryPoint = "HfwzsnHzhpbbzbn",
CallingConvention = CallingConvention.Cdecl)]
private static extern int HfwzsnHzhpbbzbn64(int txcuiwKjvwu, int hhmzfadnHexkmr);
然后再写一个函数
public int HfwzsnHzhpbbzbn(int txcuiwKjvwu, int hhmzfadnHexkmr)
{
if (Environment.Is64BitProcess)
{
return HfwzsnHzhpbbzbn64(txcuiwKjvwu, hhmzfadnHexkmr);
} return HfwzsnHzhpbbzbn32(txcuiwKjvwu, hhmzfadnHexkmr);
}
这样就不需要在使用的时候判断当前使用的是哪个,但是如果dll多了,一个dll都需要写三次,看起来代码还是很烂
设置查找的文件
实际上好多人都觉得,应用程序首先是从运行的目录开始查找dll,如果找不到,就去GAC查找,如果还是找不到,就去System查找。实际上这句话是不对的,在没有设置默认查找的文件的时候就是这样,但是软件是可以设置查找文件。
设置的方法使用使用这个dll,请看下面
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
需要先把 x86 的 dll 放在程序的 x86文件夹,当然对于x64的大家也知道放哪里。
然后在程序运行的时候使用下面的代码
var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
path = Path.Combine(path, Environment.Is64BitProcess ? "x64" : "x86");
SetDllDirectory(path);
这样就可以直接写一个函数,最后的方法是我推荐的。
但是存在一些特殊的文件,他不能放在x86文件夹,所以就需要使用下面的代码特别加载
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllToLoad);
LoadLibrary("../SdarTfqzok.dll");
如果使用了 LoadLibrary 相对是比较复杂的做法,因为需要手动创建委托的方式。但是用 LoadLibrary 的好处是可以进行释放。
先创建一个类用来存在辅助的方法,请看代码
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool FreeLibrary(IntPtr hModule);
首先通过 LoadLibrary 加载 dll 请看下面代码
var ptr = LoadLibrary("../SdarTfqzok.dll");
这样就可以拿到 dll 的指针,通过 GetProcAddress 可以拿到方法的指针
// 这里 C++ 的方法是 int HfwzsnHzhpbbzbn(int txcuiwKjvwu, int hhmzfadnHexkmr)
// 方法名就是 HfwzsnHzhpbbzbn 通过方法名找到地址
IntPtr pAddressOfFunctionToCall = GetProcAddress(pDll, "HfwzsnHzhpbbzbn32");
只是拿到了以为方法的指针是比较难调用的,所以就需要将方法指针转换
需要创建一个委托,签名和 dll 里的方法一样
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int HfwzsnHzhpbbzbn(int txcuiwKjvwu, int hhmzfadnHexkmr);
注意这个委托需要标记UnmanagedFunctionPointer才可以调用
通过 Marshal.GetDelegateForFunctionPointer 可以转函数指针为对应的类
HfwzsnHzhpbbzbn hfwzsnHzhpbbzbn = (HfwzsnHzhpbbzbn)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(HfwzsnHzhpbbzbn));
这样就可以直接调用 C++ 的方法了,使用下面的代码调用
var n = hfwzsnHzhpbbzbn(1, 2);
遇过遇到了 LoadLibrary 返回的 ptr 是 0 那么需要调用下面代码
var ptr = LoadLibrary("../SdarTfqzok.dll");
if(ptr == IntPtr.Zero )
{
var foo = Marshal.GetLastWin32Error().ToString();
}
通过 foo 的值在 System Error Codes (0-499) 就可以找到原因
需要注意,使用 GetLastWin32Error 必须设置 DllImport("xx.dll", SetLastError = true, CharSet = CharSet.Unicode) 才可以,当然最后的CharSet = CharSet.Unicode不是一定需要
查看了项目的代码才看到,实际上还有一个方法,就是在运行的时候,如果当前运行的是x86的,就从x86文件夹复制dll出来,这个方法是速度最慢的。
2019-8-30-C#-如何在项目引用x86-x64的非托管代码的更多相关文章
- C# 如何在项目引用x86 x64的非托管代码
因为现在的项目使用的是 AnyCpu 在 x86 的设备使用的是x86,在x64使用的是x64,但是对于非托管代码,必须要在x64使用x64的dll,在x86使用x86的dll.在C++没有和C#一样 ...
- 【Maven jar】打包单个或多个文件,有依赖jar包的将架包一起打包成一个jar包供别的项目引用
之前有一片文章,是打包单个java文件的.这次想要将http://www.cnblogs.com/sxdcgaq8080/p/8398780.html 打包成jar包,发现这个java文件中引用了多 ...
- 在 Target 中获取项目引用的所有依赖(dll/NuGet/Project)的路径
原文:在 Target 中获取项目引用的所有依赖(dll/NuGet/Project)的路径 在项目编译成 dll 之前,如何分析项目的所有依赖呢?可以在在项目的 Target 中去收集项目的依赖. ...
- Alpha冲刺(7/10)——2019.4.30
所属课程 软件工程1916|W(福州大学) 作业要求 Alpha冲刺(7/10)--2019.4.30 团队名称 待就业六人组 1.团队信息 团队名称:待就业六人组 团队描述:同舟共济扬帆起,乘风破浪 ...
- 这台计算机上缺少此项目引用的 NuGet 程序包-缺少的文件是 ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props
异常处理汇总-开发工具 http://www.cnblogs.com/dunitian/p/4522988.html 协助开发里面总有几个是极简爱好者,但是呢删了不该删的就会影响项目开发,下面看下完 ...
- chrome调试本地项目, 引用本地javascript文件
chrome调试本地项目, 引用本地javascript文件 本地文件可以访问本地文件 修改快捷方式属性 C:\Users\xxx\AppData\Local\Google\Chrome\Applic ...
- 您的项目引用了最新实体框架;但是,找不到数据链接所需的与版本兼容的实体框架数据库 EF6使用Mysql的技巧
转载至: http://www.cnblogs.com/Imaigne/p/4153397.html 您的项目引用了最新实体框架:但是,找不到数据链接所需的与版本兼容的实体框架数据库 EF6使用Mys ...
- GZFramwork数据库层《前言》DLL项目引用
新建项目: 1. 项目引入GZFramwork.dll NuGet地址:Install-Package GZFramwork 每个项目都引用 2.BLL层 设置数据库连接维护类:继承于:GZFramw ...
- Java web项目引用java项目,类型找不到
Java web项目引用java项目,类型找不到 错误信息: java.lang.ClassNotFoundException: org.codehaus.jackson.map.ObjectMapp ...
随机推荐
- Redis问题整理
Redis问题总结 1.单点登录的两个项目cookie不一致 由于在配置自定义Cookie的时候 @Bean("shiroCookie") public SimpleCookie ...
- offset系列属性
offset系列:获取元素的相关的样式属性的值 offsetwidth:获取元素的宽 offsetheight:获取元素的高 offsetleft:获取元素距离左边位置的值 offsettop;获取元 ...
- CSIC_716_20191114【生成器、匿名函数、内置函数、三元表达式、列表生成式、生成器表达式】
生成器: 函数与yield连用,凡是函数中有yield的,调用该函数的时候均不会立即执行,而是会返回一个生成器. 生成器本质上是一个迭代器,需要通过 [生成器.__next__()]或者[nex ...
- 校园商铺-2项目设计和框架搭建-8升级mysql驱动相关的配置以支持mysql8
1.如何升级驱动 1.1步骤: a 确保当前程序能正常访问数据库 b 更新mysql驱动重新运行程序进行校验 maven依赖https://mvnrepository.com/artifact/mys ...
- thinkphp 模块化设计
一个完整的ThinkPHP应用基于模块/控制器/操作设计,并且,如果有需要的话,可以支持多入口文件和多级控制器. ThinkPHP3.2采用模块化的架构设计思想,对目录结构规范做了调整,可以支持多模块 ...
- python 毫秒时间戳转日期
import time import datetime timestamp = 1570774556514 # 转换成localtime time_local = time.localtime(tim ...
- js 过滤非法字符
demo = 'zhang#@$san'; reg=/[`~!@#$%^&*()_+<>?:"{},.\/;'[\]]/im; if(reg.test(demo)){ t ...
- Android Matrix理论与应用详解
转:http://zensheno.blog.51cto.com/2712776/513652 Matrix学习——基础知识 以前在线性代数中学习了矩阵,对矩阵的基本运算有一些了解,前段时间在使用GD ...
- VS2010-MFC(MFC常用类:定时器Timer)
转自:http://www.jizhuomi.com/software/232.html 前面一节讲了CTime类和CTimeSpan类的使用,本节继续讲与时间有关的定时器.定时器并不是一个类,主要考 ...
- Vue-Grid-Layout分享一款好用的可拖拽组件
在使用Grafana的过程中,发现Grafana关于视图页面中每一个面板都可拖拽,可随意放大放小,体验非常棒,F12看了Grafana的代码,看打包后的代码很像react,进一步css,看到有grid ...