C#动态加载第三方非托管DLL,LoadLibraryEx,LoadLibrary

本文主要是介绍C#动态加载第三方非托管DLL,LoadLibraryEx,LoadLibrary,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C#动态加载第三方DLL

当我们需要加载第三方非托管DLL时,通常会直接使用DllImport的方式,代码如下:

  1. [DllImport("GetFile.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]

  2. static extern string GetFileData(string fileName);

上图的调用方式,默认GetFile.dll文件位于与调用程序(.exe文件)相同的目录中(这里不考虑System32目录、环境变量目录,因为通常情况下,不会将第三方DLL放到这些目录中)。

如果不想将DLL放到exe所在目录,那也可以手动指定DLL文件路径,代码如下:

  1. [DllImport("C:\\Customer\\GetFile.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]

  2. static extern string GetFileData(string fileName);

更进一步,如果此时我们想动态指定DLL文件路径,则以上方式将无法应对,原因是DllImport中的DLL文件路径必须是常量。

为了动态调用DLL,我们需要通过其它方式,具体代码如下。这里我们定义了一个DllInvoke类,其中用到了LoadLibrary()函数,通过该函数导入DLL(如上文中的GetFile.dll)文件,然后再通过GetProcAddress()函数获取DLL中欲使用的API(上文中为GetFileData())的指针,最终通过Marshal.GetDelegateForFunctionPointer()函数返回API对应的委托。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;class DllInvoke
{[DllImport("kernel32.dll", SetLastError = true)]private static extern IntPtr LoadLibrary(string lpFileName);[DllImport("kernel32.dll")]private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);[DllImport("kernel32.dll")]private extern static bool FreeLibrary(IntPtr lib);private IntPtr hLib;public DllInvoke(String DllName){hLib = LoadLibrary(DllName);if (hLib == IntPtr.Zero){var err = Marshal.GetLastWin32Error(); //只有SetLastError = true时,才能获取到Error Code}}~DllInvoke(){FreeLibrary(hLib);}//将要执行的函数转换为委托public Delegate Invoke(String ApiName, Type t){IntPtr api = GetProcAddress(hLib, ApiName);return (Delegate)Marshal.GetDelegateForFunctionPointer(api, t);}
}

另外,有个问题需要注意。当被调用的DLL,它自身也在调用其它DLL时,此时使用上文中的LoadLibrary()函数时,会有值为126的Error Code(通过Marshal.GetLastWin32Error()函数获取Error Code,126表示找不到指定的模块)。之所以会有此报错,是因为对于被调用DLL自身调用的“其它DLL”,会按照和DllImport同样的顺序(即exe所在目录、System32目录、环境变量目录)去寻找它们,而这些“其它DLL”你可能放在了和被调用DLL同样的目录中,而没有放在exe所在目录、System32目录、环境变量目录中,所以显然是找不到的。

如果我就是想把所有的DLL(不论是被调用的DLL,还是被调用DLL自身调用的其它DLL)都放在一个我自己指定的目录中呢?此时我们可以使用LoadLibraryEx()函数,通过该函数导入的DLL,如果它本身也调用了其它DLL的话,会强制先在被调用DLL所在的目录中查找它调用的“其它DLL”。使用LoadLibraryEx()函数的完整代码如下,新的DllInvoke类中,定义了一个LoadLibraryFlags枚举变量,其中的LOAD_WITH_ALTERED_SEARCH_PATH值会被传入LoadLibraryEx()函数中,从而强制在DLL所在目录中查找。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;class DllInvoke
{/// <summary>/// LoadLibraryFlags/// </summary>public enum LoadLibraryFlags : uint{DONT_RESOLVE_DLL_REFERENCES = 0x00000001,LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,LOAD_LIBRARY_AS_DATAFILE = 0x00000002,LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008}[DllImport("kernel32.dll", SetLastError = true)]private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);[DllImport("kernel32.dll")]private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);[DllImport("kernel32.dll")]private extern static bool FreeLibrary(IntPtr lib);private IntPtr hLib;public DllInvoke(String DllName){hLib = LoadLibraryEx(DllName, IntPtr.Zero, LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH);if (hLib == IntPtr.Zero){var err = Marshal.GetLastWin32Error(); //只有SetLastError = true时,才能获取到Error Code}}~DllInvoke(){FreeLibrary(hLib);}//将要执行的函数转换为委托public Delegate Invoke(String ApiName, Type t){IntPtr api = GetProcAddress(hLib, ApiName);return (Delegate)Marshal.GetDelegateForFunctionPointer(api, t);}
}

如何使用以上定义的DllInvoke类呢?具体代码如下,首先定义一个委托CustomerAPI(该委托的形参列表需要和待调用的DLL中的API一致),然后即可用类似下图Example()函数中的代码,进行API的调用。

public delegate int CustomerAPI(string fileName);
private void Example()
{string dllName = "C:\\Customer\\GetFile.dll";DllInvoke customerDll = new DllInvoke(dllName);CustomerAPI GetFileData = (CustomerAPI)customerDll.Invoke("GetFileData", typeof(CustomerAPI));string fileName = "C:\\Customer\\ExampleFile.txt";int data = GetFileData(fileName);MessageBox.Show("The data got from file is: " + data.ToString());
}

这篇关于C#动态加载第三方非托管DLL,LoadLibraryEx,LoadLibrary的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/515851

相关文章

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

C#中读取XML文件的四种常用方法

《C#中读取XML文件的四种常用方法》Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具,下面我们就来看看C#中读取XML文件的方法都有哪些吧... 目录XML简介格式C#读取XML文件方法使用XmlDocument使用XmlTextReader/XmlTextWr

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

TP-Link PDDNS服将于务6月30日正式停运:用户需转向第三方DDNS服务

《TP-LinkPDDNS服将于务6月30日正式停运:用户需转向第三方DDNS服务》近期,路由器制造巨头普联(TP-Link)在用户群体中引发了一系列重要变动,上个月,公司发出了一则通知,明确要求所... 路由器厂商普联(TP-Link)上个月发布公告要求所有用户必须完成实名认证后才能继续使用普联提供的 D

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

Java使用POI-TL和JFreeChart动态生成Word报告

《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码... 目录前言一、需求背景二、方案分析三、 POI-TL + JFreeChart 实现3.1 Maven

C#比较两个List集合内容是否相同的几种方法

《C#比较两个List集合内容是否相同的几种方法》本文详细介绍了在C#中比较两个List集合内容是否相同的方法,包括非自定义类和自定义类的元素比较,对于非自定义类,可以使用SequenceEqual、... 目录 一、非自定义类的元素比较1. 使用 SequenceEqual 方法(顺序和内容都相等)2.

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

Java导出Excel动态表头的示例详解

《Java导出Excel动态表头的示例详解》这篇文章主要为大家详细介绍了Java导出Excel动态表头的相关知识,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录前言一、效果展示二、代码实现1.固定头实体类2.动态头实现3.导出动态头前言本文只记录大致思路以及做法,代码不进

C#从XmlDocument提取完整字符串的方法

《C#从XmlDocument提取完整字符串的方法》文章介绍了两种生成格式化XML字符串的方法,方法一使用`XmlDocument`的`OuterXml`属性,但输出的XML字符串不带格式,可读性差,... 方法1:通过XMLDocument的OuterXml属性,见XmlDocument类该方法获得的xm