C#总结(七)动态加载C++动态链接库

C#调用C++ 链接库的方式分为静态调用和动态调用这两种方式。静态调用之前的文章里面都有介绍,使用.net 提供的DllImport 导入相关的C++ 库即可。请看之前的文章,https://www.cnblogs.com/zhangweizhong/p/8119340.html

今天介绍动态调用的方法。很多时候,Dll库的目录可能是变化的,或是有些场景,需要根据具体的情况,来动态加载这些Dll库。这样使用静态调用的方式就很不方便,C#中我们经常通过配置动态的调用托管Dll,那么是不是也可以这样动态调用C++动态链接呢?
只要通过LoadLibrary, GetProcess, FreeLibrary这几个函数是可以动态调用动态链接的(它们包含在kernel32.dll中)。

原理

LoadLibrary ( string lpFileName):载入指定的动态链接库,并将它映射到当前进程使用的地址空间。载入成功后即可访问库内保存的资源 , 除了LoadLibrary 方法,还有一个类似的 LoadLibraryEx 方法。

GetProcAddress (int hModule, string lpProcName):GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。 如果函数调用成功,返回值是DLL中的输出函数地址。 如果函数调用失败,返回值是NULL。调用函数GetLastError ,得到具体的错误信息。

FreeLibrary ( int hModule)  :释放指定的动态链接库,它们早先是用LoadLibrary API函数装载的。

GetLastError() : 获取错误信息

实现

1. 将kernel32中的几个方法封装成本地调用类 DLLWrapper

1using System; 2using System.IO; 3using System.Runtime.InteropServices; 4 5namespace Irisking.Basic.Util 6{ 7 /// <summary> 8 /// DLLWrapper 9 /// </summary> 10 internal class DLLWrapper 11 { 12 [DllImport("kernel32.dll")] 13 private static extern uint GetLastError(); 14 15 16 /// <summary> 17 /// API LoadLibraryEx 18 /// </summary> 19 /// <param name="lpFileName"></param> 20 /// <param name="hReservedNull"></param> 21 /// <param name="dwFlags"></param> 22 /// <returns></returns> 23 [DllImport("kernel32.dll", EntryPoint = "LoadLibraryEx", SetLastError = true)] 24 private static extern int LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags); 25 26 /// <summary> 27 /// API GetProcAddress 28 /// </summary> 29 /// <param name="handle"></param> 30 /// <param name="funcname"></param> 31 /// <returns></returns> 32 [DllImport("Kernel32", EntryPoint = "GetProcAddress", SetLastError = true)] 33 public static extern int GetProcAddress(int handle, string funcname); 34 35 /// <summary> 36 /// API FreeLibrary 37 /// </summary> 38 /// <param name="handle"></param> 39 /// <returns></returns> 40 [DllImport("Kernel32", EntryPoint = "FreeLibrary", SetLastError = true)] 41 private static extern int FreeLibrary(int handle); 42 43 ///<summary> 44 /// 通过非托管函数名转换为对应的委托 , by jingzhongrong 45 ///</summary> 46 ///<param name="dllModule"> 通过 LoadLibrary 获得的 DLL 句柄 </param> 47 ///<param name="functionName"> 非托管函数名 </param> 48 ///<param name="t"> 对应的委托类型 </param> 49 ///<returns> 委托实例,可强制转换为适当的委托类型 </returns> 50 public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t) 51 { 52 int address = GetProcAddress(dllModule, functionName); 53 if (address == 0) 54 return null; 55 else 56 return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t); 57 } 58 59 ///<summary> 60 /// 将表示函数地址的 intPtr 实例转换成对应的委托 61 ///</summary> 62 public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t) 63 { 64 if (address == IntPtr.Zero) 65 return null; 66 else 67 return Marshal.GetDelegateForFunctionPointer(address, t); 68 } 69 70 ///<summary> 71 /// 将表示函数地址的 int 转换成对应的委托 72 ///</summary> 73 public static Delegate GetDelegateFromIntPtr(int address, Type t) 74 { 75 if (address == 0) 76 return null; 77 else 78 return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t); 79 } 80 81 /// <summary> 82 /// 加载sdk 83 /// </summary> 84 /// <param name="lpFileName"></param> 85 /// <returns></returns> 86 public static int LoadSDK(string lpFileName) 87 { 88 if (File.Exists(lpFileName)) 89 { 90 var hReservedNull = IntPtr.Zero; 91 var dwFlags = LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH; 92 93 var result = LoadLibraryEx(lpFileName, hReservedNull, dwFlags); 94 95 var errCode = GetLastError(); 96 LogHelper.Info($"LoadSDK Result:{result}, ErrorCode: {errCode}"); 97 98 return result; 99 } 100 return 0; 101 } 102 103 /// <summary> 104 /// 释放sdk 105 /// </summary> 106 /// <param name="handle"></param> 107 /// <returns></returns> 108 public static int ReleaseSDK(int handle) 109 { 110 try 111 { 112 if (handle > 0) 113 { 114 LogHelper.Info($"FreeLibrary handle:{handle}"); 115 var result = FreeLibrary(handle); 116 var errCode = GetLastError(); 117 LogHelper.Info($"FreeLibrary Result:{result}, ErrorCode: {errCode}"); 118 return 0; 119 } 120 return -1; 121 } 122 catch (Exception ex) 123 { 124 LogHelper.Error(ex); 125 return -1; 126 } 127 } 128 } 129 130 /// <summary> 131 /// LoadLibraryFlags 132 /// </summary> 133 public enum LoadLibraryFlags : uint 134 { 135 /// <summary> 136 /// DONT_RESOLVE_DLL_REFERENCES 137 /// </summary> 138 DONT_RESOLVE_DLL_REFERENCES = 0x00000001, 139 140 /// <summary> 141 /// LOAD_IGNORE_CODE_AUTHZ_LEVEL 142 /// </summary> 143 LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, 144 145 /// <summary> 146 /// LOAD_LIBRARY_AS_DATAFILE 147 /// </summary> 148 LOAD_LIBRARY_AS_DATAFILE = 0x00000002, 149 150 /// <summary> 151 /// LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 152 /// </summary> 153 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, 154 155 /// <summary> 156 /// LOAD_LIBRARY_AS_IMAGE_RESOURCE 157 /// </summary> 158 LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, 159 160 /// <summary> 161 /// LOAD_LIBRARY_SEARCH_APPLICATION_DIR 162 /// </summary> 163 LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200, 164 165 /// <summary> 166 /// LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 167 /// </summary> 168 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000, 169 170 /// <summary> 171 /// LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 172 /// </summary> 173 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100, 174 175 /// <summary> 176 /// LOAD_LIBRARY_SEARCH_SYSTEM32 177 /// </summary> 178 LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800, 179 180 /// <summary> 181 /// LOAD_LIBRARY_SEARCH_USER_DIRS 182 /// </summary> 183 LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400, 184 185 /// <summary> 186 /// LOAD_WITH_ALTERED_SEARCH_PATH 187 /// </summary> 188 LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 189 } 190}

2. 使用DLLWrapper类动态读取C++Dll,获得函数指针,并且将指针封装成C#中的委托。原因很简单,C#中已经不能使用指针了,如下:

定义委托

1UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] 2public delegate int Delegate_IKUSBSDK_GetVersion([In] [Out] [MarshalAs(UnmanagedType.LPArray)] byte[] version);

3. 调用函数

1//1. 加载sdk 2var sdkModule = DLLWrapper.LoadSDK(_route.DeviceA_PATH); 3 4// 2. 通过handle 找到相关的函数 5Delegate_IKUSBSDK_GetVersion getVersion = (Delegate_IKUSBSDK_GetVersion)DLLWrapper.GetFunctionAddress(sdkModule, "IKUSBSDK_GetVersion", typeof(Delegate_IKUSBSDK_GetVersion)); 6 7var result = getVersion(version);

最后

通过如上例子,我们可以在C#中动态或者静态的调用C++写的代码了。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

VC++动态链接库(DLL)编程深入浅出(一)

1.概论  先来阐述一下DLL(DynamicLinkableLibrary)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。  静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直

Nepxion Discovery 5.5.0 发布

!(https://oscimg.oschina.net/oscnet/f81c043194ef4732880459d00c1a720e.png)发布日志功能更新:增加基于Opentracing调用链的支持,目前支持UberJaeger,实现在SpringCloudGateway、Zuul和服务上的灰度

QT开发——动态库(.so文件)的生成与调用

1.qmake方式生成和调用动态库链接:https://blog.csdn.net/lywzgzl/article/details/428059912.cmake方式生成和调用动态库2.1创建共享库项目Cmake新建一个QtCreator项目,在C