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

 

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


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

 

原理

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

函数

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

 

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

 

GetLastError() : 获取错误信息.net

 

实现

 

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

using System; using System.IO; using System.Runtime.InteropServices; namespace Irisking.Basic.Util { /// <summary>
    /// DLLWrapper /// </summary>
    internal class DLLWrapper { [DllImport("kernel32.dll")] private static extern uint GetLastError(); /// <summary>
        /// API LoadLibraryEx /// </summary>
        /// <param name="lpFileName"></param>
        /// <param name="hReservedNull"></param>
        /// <param name="dwFlags"></param>
        /// <returns></returns>
        [DllImport("kernel32.dll", EntryPoint = "LoadLibraryEx", SetLastError = true)] private static extern int LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags); /// <summary>
        /// API GetProcAddress /// </summary>
        /// <param name="handle"></param>
        /// <param name="funcname"></param>
        /// <returns></returns>
        [DllImport("Kernel32", EntryPoint = "GetProcAddress", SetLastError = true)] public static extern int GetProcAddress(int handle, string funcname); /// <summary>
        /// API FreeLibrary /// </summary>
        /// <param name="handle"></param>
        /// <returns></returns>
        [DllImport("Kernel32", EntryPoint = "FreeLibrary", SetLastError = true)] private static extern int FreeLibrary(int handle); ///<summary>
        /// 经过非托管函数名转换为对应的委托 , by jingzhongrong ///</summary>
        ///<param name="dllModule"> 经过 LoadLibrary 得到的 DLL 句柄 </param>
        ///<param name="functionName"> 非托管函数名 </param>
        ///<param name="t"> 对应的委托类型 </param>
        ///<returns> 委托实例,可强制转换为适当的委托类型 </returns>
        public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t) { int address = GetProcAddress(dllModule, functionName); if (address == 0) return null; else
                return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t); } ///<summary>
        /// 将表示函数地址的 intPtr 实例转换成对应的委托 ///</summary>
        public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t) { if (address == IntPtr.Zero) return null; else
                return Marshal.GetDelegateForFunctionPointer(address, t); } ///<summary>
        /// 将表示函数地址的 int 转换成对应的委托 ///</summary>
        public static Delegate GetDelegateFromIntPtr(int address, Type t) { if (address == 0) return null; else
                return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t); } /// <summary>
        /// 加载sdk /// </summary>
        /// <param name="lpFileName"></param>
        /// <returns></returns>
        public static int LoadSDK(string lpFileName) { if (File.Exists(lpFileName)) { var hReservedNull = IntPtr.Zero; var dwFlags = LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH; var result = LoadLibraryEx(lpFileName, hReservedNull, dwFlags); var errCode = GetLastError(); LogHelper.Info($"LoadSDK Result:{result}, ErrorCode: {errCode}"); return result; } return 0; } /// <summary>
        /// 释放sdk /// </summary>
        /// <param name="handle"></param>
        /// <returns></returns>
        public static int ReleaseSDK(int handle) { try { if (handle > 0) { LogHelper.Info($"FreeLibrary handle:{handle}"); var result = FreeLibrary(handle); var errCode = GetLastError(); LogHelper.Info($"FreeLibrary Result:{result}, ErrorCode: {errCode}"); return 0; } return -1; } catch (Exception ex) { LogHelper.Error(ex); return -1; } } } /// <summary>
    /// LoadLibraryFlags /// </summary>
    public enum LoadLibraryFlags : uint { /// <summary>
        /// DONT_RESOLVE_DLL_REFERENCES /// </summary>
        DONT_RESOLVE_DLL_REFERENCES = 0x00000001, /// <summary>
        /// LOAD_IGNORE_CODE_AUTHZ_LEVEL /// </summary>
        LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, /// <summary>
        /// LOAD_LIBRARY_AS_DATAFILE /// </summary>
        LOAD_LIBRARY_AS_DATAFILE = 0x00000002, /// <summary>
        /// LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE /// </summary>
        LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, /// <summary>
        /// LOAD_LIBRARY_AS_IMAGE_RESOURCE /// </summary>
        LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, /// <summary>
        /// LOAD_LIBRARY_SEARCH_APPLICATION_DIR /// </summary>
        LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200, /// <summary>
        /// LOAD_LIBRARY_SEARCH_DEFAULT_DIRS /// </summary>
        LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000, /// <summary>
        /// LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR /// </summary>
        LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100, /// <summary>
        /// LOAD_LIBRARY_SEARCH_SYSTEM32 /// </summary>
        LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800, /// <summary>
        /// LOAD_LIBRARY_SEARCH_USER_DIRS /// </summary>
        LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400, /// <summary>
        /// LOAD_WITH_ALTERED_SEARCH_PATH /// </summary>
        LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 } }

 

2. 使用DLLWrapper类动态读取C++Dll,得到函数指针,而且将指针封装成C#中的委托。缘由很简单,C#中已经不能使用指针了,以下: code

定义委托htm

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

 

 

3. 调用函数blog

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

 

 

最后

经过如上例子,咱们能够在C#中动态或者静态的调用C++写的代码了。

 

原文出处:https://www.cnblogs.com/zhangweizhong/p/10594422.html

相关文章
相关标签/搜索