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 ...
随机推荐
- css----7渐变
linear-gradient(90deg,red 10%,yellow 20%,green 30%) <!DOCTYPE html> <html> <head> ...
- odoo 分组视图下显示同一批次记录的总数
修改前: 修改后: xml文件: <?xml version="1.0" encoding="utf-8"?> <!-- vim:fdn=3: ...
- E: Sub-process /usr/bin/dpkg returned an error code (1)解决办法
解决方法: 先将info文件夹更名 sudo mv /var/lib/dpkg/info /var/lib/dpkg/info.bk 新建一个新的info文件夹 sudo mkdir /var/lib ...
- [ZJOI 2018]历史
题意:给定一棵树和点的\(Access\)次数,求切换链的最大值. 考虑修改时实边与虚边的贡献,用\(LCT\)维护此树. // luogu-judger-enable-o2 #include< ...
- c# 中xml序列化时相同节点存入不同类型值
先上需要序列话的类定义: [System.Xml.Serialization.XmlIncludeAttribute(typeof(DescriptionType))] [System.CodeDom ...
- 线程池_ThreadPool
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; ...
- 集中式日志分析平台 - ELK Stack - 安全解决方案 X-Pack
大数据之心 关注 0.6 2017.02.22 15:36* 字数 2158 阅读 16457评论 7喜欢 9 简介 X-Pack 已经作为 Elastic 公司单独的产品线,前身是 Shield, ...
- git push到多个不同的远程仓库
1.若现在本地有一个已经和github远程仓库关联好的本地仓库,平时都会将本地仓库push到github上. 2.有一天突然发现"码云"这个远程仓库网站,咦!这个还可以创建priv ...
- JS时间比较大小
目录 1. 时间比较 2. 时间戳比较 3. 日期比较方法 4. 参考 1. 时间比较 var curTime = new Date(); //把字符串格式转化为日期类 var starttime = ...
- 「题解」:[BZOJ4358]permu
问题: permu 时间限制: 30 Sec 内存限制: 512 MB 题面 题目描述 给出一个长度为n的排列P(P1,P2,...Pn),以及m个询问.每次询问某个区间[l,r]中,最长的值域 连 ...