动态加载DLL的方法与注意的问题

合集下载

dll加载原理

dll加载原理

dll加载原理DLL加载原理概述•DLL(动态链接库)是一种可执行文件格式,用于存储和共享程序代码和数据。

•DLL加载是将DLL文件加载到内存并解析其导出函数的过程。

DLL的分类•内核模式DLL:运行在操作系统内核空间中,提供给操作系统使用。

•用户模式DLL:运行在应用程序进程的用户空间中,为应用程序提供功能支持。

DLL的加载方式1.隐式加载:在应用程序启动时由操作系统自动加载所需的DLL文件。

–应用程序代码中使用函数,操作系统自动在加载应用程序的同时加载其依赖的DLL。

–应用程序代码需要将DLL的路径告知操作系统,操作系统根据路径找到DLL并加载。

2.显式加载:在应用程序运行时手动加载所需的DLL文件。

–应用程序通过调用加载函数(如LoadLibrary函数)手动加载DLL。

–调用GetProcAdress函数获取DLL中函数的入口地址,从而调用DLL中的函数。

DLL的加载过程1.读取DLL文件:–操作系统通过文件系统读取DLL文件的内容。

2.根据DLL文件的导入表(Import Table)解析DLL的依赖:–导入表记录了DLL所依赖的其他DLL,以及导出函数的名称和地址。

3.加载DLL依赖的其他DLL:–递归地加载DLL所依赖的其他DLL文件。

4.解析DLL导出函数:–根据导入表中记录的函数名称,找到导出函数的入口地址。

5.将DLL文件映射到进程空间:–将DLL文件映射到进程的虚拟内存空间中,以便能够访问DLL中的代码和数据。

6.更新进程的导入表:–更新进程的导入表,将DLL中导出函数的地址填入相应的入口地址。

DLL的卸载•当不再需要某个DLL时,可以将其从内存中卸载。

•DLL卸载的条件通常是没有其他模块依赖该DLL,或者由操作系统决定。

总结•DLL加载是将DLL文件加载到内存并解析导出函数的过程。

•DLL可以通过隐式加载或显式加载的方式加载。

•DLL的加载过程包括读取DLL文件、解析依赖、加载其他DLL、解析导出函数等步骤。

动态链接库的使用方法

动态链接库的使用方法

动态链接库的使用方法动态链接库(Dynamic Link Library,DLL)是Windows系统中一种常见的文件类型,用于存储可被程序在运行时动态加载的函数和数据。

它可以提供代码和资源的共享,使得程序的安装包更小,节省了系统资源。

使用动态链接库有以下几个优点:1.模块化:将程序代码和资源划分为独立的模块,便于开发和维护。

2.共享性:多个程序可以共享同一个动态链接库,减少重复的代码和数据的存储。

3.动态加载:可以在程序运行时动态地加载和卸载动态链接库,提高了程序的灵活性和可扩展性。

1.创建动态链接库:使用C/C++编程语言可以创建动态链接库。

首先,在开发环境中创建新的DLL项目,并选择动态链接库的类型。

在项目中添加需要的代码和资源,并编写相应的函数和数据接口。

将这些接口封装在一个头文件中,并在源文件中实现具体的功能。

最后,编译项目生成动态链接库文件(.dll 文件)。

2.导出函数和数据:在动态链接库中,明确指定哪些函数和数据需要被其他程序调用。

在函数和数据的声明前加上__declspec(dllexport)关键字即可。

例如:```C++__declspec(dllexport) int Add(int a, int b);```3.调用动态链接库:在其他程序中调用动态链接库中的函数和数据,需要先导入相应的函数和数据。

使用C/C++编程语言可以创建一个头文件,其中包含要导入的函数和数据的声明。

例如:```C++__declspec(dllimport) int Add(int a, int b);__declspec(dllimport) extern double PI;```然后,在使用这些函数和数据的源文件中包含这个头文件即可。

4.加载和卸载动态链接库:在程序运行时,需要动态地加载动态链接库,并在使用完之后卸载。

可以使用LoadLibrary函数来加载动态链接库,使用FreeLibrary函数来卸载动态链接库。

加载DLL文件失败的解决办法

加载DLL文件失败的解决办法

开机提示找不到 *.dll 解决小结。

最近这个问题很多,把这个也总结一下吧,欢迎大家提出其它意见供大家参考:首先查一下是哪个.dll无法加载,试着手动regsvr32 *.dll加载试试1、开始-运行,输入msconfig,在“启动”中把相关自启动的选项都去掉。

2、关闭系统还原。

(我的电脑-属性-系统还原,选择“在所有的驱动器上关闭系统还原”)3、把C:\Documents and Settings\用户名\Local Settings\Temp和C:\Documents and Settings\用户名\Local Settings\Temporary Internet Files文件夹下的所有文件都删除。

(如果看不到此文件夹,工具-文件夹选项,在“查看”中有一项是“隐藏文件和文件夹”,选择“显示所有文件和文件夹”)4、把C:\WINDOWS\Prefetch文件夹下的所有文件都删除。

5、控制面板-服务,把你认为不需要的服务都改为“手动”并停用。

6、关闭各种视觉效果(我的电脑-属性,弹出的窗口里选择“高级”标签,性能的设置,选择最佳性能,或者只保留倒数第二项、倒数第三项和在窗口和按钮上保持视觉样式。

)7、关闭远程协助(我的电脑-属性,弹出的窗口里选择“远程”标签,然后取消下面两个选项的选择。

)8、安装优化软件(二者选一即可) TuneUp Utilities 或者 Windows 优化大师或者其它的......可能是这个dll因为某些原因(最大的可能是因为它是个病毒或流氓软件的dll 文件,被杀软删除了)丢失了,但其相关的注册信息却还在,导致系统开机时还加载它,却又找不到它的文件,所以报错。

如果你点击“确定”后,系统没有什么不正常,并且可以正常运行的话,你可以用这个软件清理掉这个开机加载项,以后开机就不会出现这个信息了。

Autoruns:开机启动项管理DLL文件即动态链接库文件,是一种可执行文件,它允许程序共享执行特殊任务所必需的代码和其他资源。

WORD打开时出现加载DLL错误解决方法

WORD打开时出现加载DLL错误解决方法

WORD打开时出现加载DLL错误解决方法WORD打开时出现加载DLL错误解决方法
1、接下来看看解决办法,按组合键WIN + R或者按开始---运行,打开运行窗口,
2、在运行对话框中输入或者复制粘贴
“%USERPROFILE%\AppData\Roaming\Microsoft\T emplate s”(注意双引号就不要输入咧),输入完成后,点击确定按钮。

3、然后的打开的窗口中将“Normal.dotm”文件删除,
4、到这里已经把问题完美解决啦,其实还有一种方法捏,仍然是打开开始---运行(或者按WIN + R快捷键),输入“regedit”(双引号不要输入)打开注册表。

5、进入注册表编辑器后,分别找到(定位)“HKEY_CURRENT_USER”和“HKEY_LOCAL_MACHINE”两个选项,
6、点击左侧的小箭头展开注册表选项,分别找到
“HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\W ord”和“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\Word\A ddi ns”
7、然后分别在找到的两个选项上点击右键---删除就OK咧。

动态链接库知识点总结之三(如何以显示的方式加载DLL)

动态链接库知识点总结之三(如何以显示的方式加载DLL)

动态链接库知识点总结之三(如何以显⽰的⽅式加载DLL)总结⼀下如何显⽰加载⽅式加载DLL,⾸先,我们新建⼀个win32项⽬,选择dll,空项⽬,再添加⼀个源⽂件,⼀个模块定义⽂件(.def),具体如下图。

(详细⽅法已经在前两篇⽂章中讲述,如有不懂,打开链接查看)(1) 新建项⽬,名称为:dll,添加⼀个源⽂件(.cpp),编代码,编译⽂件。

(2) 为项⽬添加⼀个模块定义⽂件(上⼀篇⽂章中详细介绍)(先新建⼀个⽂本,再改属性名),编辑代码,如下图(3) 新建⼀个DLL测试应⽤程序(基于对话框的),项⽬名字:TestDLL,添加⼀个按钮,属性如下,先编译⼀下。

(4) 为按钮添加⼀个响应函数,编写如下代码(具体代码含义在最后介绍)(5) 把已经编译好的DLL,选择.dll⽂件将拷贝到应⽤程序⽬录下(dll放在与该测试⽂件的.exe⽂件夹下(具体做法已在前两篇介绍过),如图(7) 点击,运⾏,成功运⾏,以显⽰的⽅式加载DLL成功现在介绍下,按钮消息响应函数中的代码含义。

函数LoadLibrary()作⽤是将可执⾏模块映射到进程的地址空间,通俗点来说,就是可以⽤来加载DLL的,这个函数是显⽰加载DLL的重要函数。

参数是DLL的名称,这个函数在MSDN上有详细的解释,⼤家可以通过以下链接查看。

该函数返回的是所加载的DLL的句柄。

()有了DLL的句柄,我们需要再获得导出函数的地址即可,获得地址,⽤此函数:GetProcAddress(),参数1是:DLL句柄,参数2:⼀个指针,指向导出函数的名字。

该函数返回值如果为NULL,则获取地址失败。

成功,则返回导出函数的导出地址。

有了地址,我们如何操纵函数,我们还需要⼀个函数指针,使⽤函数指针来调⽤导出函数。

在此我们总结⼀下:动态加载DLL时,客户端程序不再需要包含引⼊库⽂件,只需要.dll⽂件即可。

静态加载和动态加载各有各的优缺点,⾸先,静态加载DLL⽐较简单,但是如果需要加载的DLL过多的话会造成启动程序过慢,所以还是选择动态加载⽐较好。

c#实现动态加载Dll

c#实现动态加载Dll

c#实现动态加载Dll原理如下:1、利用反射进行动态加载和调用.Assembly ass=Assembly.LoadFrom(DllPath); //利用dll的路径加载,同时将此程序集所依赖的程序集加载进来,需后辍名.dllAssembly.LoadFile 只加载指定文件,并不会自动加载依赖程序集.Assmbly.Load无需后辍名2、加载dll后,需要使用dll中某类.Type type=ass.GetType(“TypeName”);//用类型的命名空间和名称获得类型3、需要实例化类型,才可以使用,参数可以人为的指定,也可以无参数,静态实例可以省略Object obj = Activator.CreateInstance(type,params[]);//利用指定的参数实例话类型4、调用类型中的某个方法:需要首先得到此方法MethodInfo mi=type.GetMethod(“MehtodName”);//通过方法名称获得方法5、然后对方法进行调用,多态性利用参数进行控制mi.Invoke(obj,params[]);//根据参数直线方法,返回值就是原方法的返回值#region 声明动态载入DLL的参数object obj=null;byte[] filesByte;Assembly assembly;Type type;MethodInfo timerInitial;MethodInfo timerDispose;#endregionprivate void LoadDll()//加载DLL{try{filesByte = File.ReadAllBytes(Path.GetDirectoryName(Application.ExecutablePath) + "\\loadDll.dll");assembly = Assembly.Load(filesByte);type = assembly.GetType("test.loadDll");obj = System.Activator.CreateInstance(type);timerStart = tp.GetMethod("TimerStart");timerStop = tp.GetMethod("TimerStop");if (timerStart != null){timerStart.Invoke(obj, null);}}catch(Exception){}}以下摘自MSDNpublic class A{public virtual int method () {return 0;}}public class B{public virtual int method () {return 1;}}class Mymethodinfo{public static int Main(){Console.WriteLine ("\nReflection.MethodInfo");A MyA = new A();B MyB = new B();// Get the Type and MethodInfo.Type MyTypea = Type.GetType("A");MethodInfo Mymethodinfoa = MyTypea.GetMethod("method");Type MyTypeb = Type.GetType("B");MethodInfo Mymethodinfob = MyTypeb.GetMethod("method");// Get and display the Invoke method.Console.Write("\nFirst method - " + MyTypea.FullName +" returns " + Mymethodinfoa.Invoke(MyA, null));Console.Write("\nSecond method - " + MyTypeb.FullName + " returns " + Mymethodinfob.Invoke(MyB, null));return 0;}}。

C#实现动态加载dll的方法

C#实现动态加载dll的方法

C#实现动态加载dll的⽅法本⽂实例讲述了C#实现动态加载dll的⽅法。

分享给⼤家供⼤家参考。

具体实现⽅法如下:复制代码代码如下:using System;using System.Collections.Generic;using System.Text;using System.Reflection;using System.IO;namespace monAPI.DynamicLoadAssembly{public class AssemblyDynamicLoader<T>{private AppDomain appDomain;private DynamicRemoteLoadAssembly<T> remoteLoader;public T InvokeMethod(string assemblyName, string assemblyPath, string assemblyConfigFilePath, string fullClassName, string methodName, params object[] args){AppDomainSetup setup = new AppDomainSetup();setup.ApplicationName = "ApplicationLoader";setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory + @"bin\";//setup.PrivateBinPath = bine(AppDomain.CurrentDomain.BaseDirectory, "private");setup.CachePath = setup.ApplicationBase;setup.ShadowCopyFiles = "true";if (assemblyConfigFilePath != string.Empty){setup.ConfigurationFile = AppDomain.CurrentDomain.BaseDirectory + assemblyConfigFilePath;}setup.ShadowCopyDirectories = setup.ApplicationBase;setup.LoaderOptimization = LoaderOptimization.SingleDomain;this.appDomain = AppDomain.CreateDomain("ApplicationLoaderDomain", null, setup);String name = Assembly.GetExecutingAssembly().GetName().FullName;this.remoteLoader = (DynamicRemoteLoadAssembly<T>)this.appDomain.CreateInstanceAndUnwrap(name, typeof(DynamicRemoteLoadAssembly<T>).FullName);assemblyName = AppDomain.CurrentDomain.BaseDirectory + assemblyPath + assemblyName;return this.remoteLoader.InvokeMethod(assemblyName, fullClassName, methodName, args);}/// <summary>////// </summary>public void Unload(){try{AppDomain.Unload(this.appDomain);this.appDomain = null;}catch (CannotUnloadAppDomainException ex){}}}}复制代码代码如下:using System;using System.Collections.Generic;using System.Text;using System.Reflection;using System.Globalization;namespace monAPI.DynamicLoadAssembly{public class DynamicRemoteLoadAssembly<T> : MarshalByRefObject{private Assembly assembly = null;public T InvokeMethod(string assemblyPath, string fullClassName, string methodName, params object[] args){this.assembly = null;T result = default(T);try{this.assembly = Assembly.LoadFile(assemblyPath);Type pgmType = null;if (this.assembly != null){pgmType = this.assembly.GetType(fullClassName, true, true);}else{pgmType = Type.GetType(fullClassName, true, true);}BindingFlags defaultBinding = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Static;CultureInfo cultureInfo = new CultureInfo("es-ES", false);try{MethodInfo methisInfo = assembly.GetType(fullClassName, true, true).GetMethod(methodName);if (methisInfo == null){new Exception("EMethod does not exist!");}if (methisInfo.IsStatic){if (methisInfo.GetParameters().Length == 0){if (methisInfo.ReturnType == typeof(void)){pgmType.InvokeMember(methodName, defaultBinding, null, null, null, cultureInfo);}else{result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, null, null, cultureInfo);}}else{if (methisInfo.ReturnType == typeof(void)){pgmType.InvokeMember(methodName, defaultBinding, null, null, args, cultureInfo);}else{result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, null, args, cultureInfo);}}}else{if (methisInfo.GetParameters().Length == 0){object pgmClass = Activator.CreateInstance(pgmType);if (methisInfo.ReturnType == typeof(void)){pgmType.InvokeMember(methodName, defaultBinding, null, pgmClass, null, cultureInfo);}else{result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, pgmClass, null, cultureInfo); }}else{object pgmClass = Activator.CreateInstance(pgmType);if (methisInfo.ReturnType == typeof(void)){pgmType.InvokeMember(methodName, defaultBinding, null, pgmClass, args, cultureInfo);}else{result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, pgmClass, args, cultureInfo); }}}}catch (Exception e){result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, null, null, cultureInfo);}return result;}catch (Exception ee){return result;}}}}希望本⽂所述对⼤家的C#程序设计有所帮助。

C#动态载入DLL,并调用成员方法(提供非接口及接口调用两种方式)

C#动态载入DLL,并调用成员方法(提供非接口及接口调用两种方式)
lic class TestB : ItestF {
public int Max(int a, int b) {
return a > b ? a : b; } public int Min(int a, int b) {
return a < b ? a : b; } }
}
Form 源代码
private void button1_Click(object sender, EventArgs e)
return a > b ? a : b; }
} }
Form 源码,添加 TextBox 和 Button 控件
private void button1_Click(object sender, EventArgs e)
{
try
{
Assembly ass = Assembly.LoadFrom("TestDll.dll"); Type t = ass.GetType("TestDll.TestA"); object obj = Activator.CreateInstance(t); MethodInfo method = t.GetMethod("Max"); textBox1.Text += "Max(10, 20): " + method.Invoke(obj, new object[] { 10, 20 }).ToString();
} public TestC(int a, int b) {
A = a; B = b; } public int Max() { return a > b ? a : b; } public int Min() { return a < b ? a : b; }}

Java动态加载DLL方法

Java动态加载DLL方法

Java动态加载DLL⽅法⼀、JAVA中所需要做的⼯作 在JAVA程序中,⾸先需要在类中声明所调⽤的库名称,如下:static {System.loadLibrary(“goodluck”);} 在这⾥,库的扩展名字可以不⽤写出来,究竟是DLL还是SO,由系统⾃⼰判定。

还需对将要调⽤的⽅法做本地声明,要害字为native。

且只需要声明,⽽不需要具体实现。

如下:public native static void set(int i);public native static int get(); 然后编译该JAVA程序⽂件,⽣成CLASS,再⽤JAVAH命令,JNI就会⽣成C/C 的头⽂件。

例如程序testdll.java,内容为:public class testdll{static{System.loadLibrary("goodluck");}public native static int get();public native static void set(int i);public static void main(String[] args){testdll test = new testdll();test.set(10);System.out.println(test.get());}} ⽤javac testdll.java编译它,会⽣成testdll.class。

再⽤javah testdll,则会在当前⽬录下⽣成testdll.h⽂件,这个⽂件需要被C/C 程序调⽤来⽣成所需的库⽂件。

⼆、C/C 中所需要做的⼯作 对于已⽣成的.h头⽂件,C/C 所需要做的,就是把它的各个⽅法具体的实现。

然后编译连接成库⽂件即可。

再把库⽂件拷贝到JAVA程序的路径下⾯,就可以⽤JAVA调⽤C/C 所实现的功能了。

接上例⼦。

我们先看⼀下testdll.h⽂件的内容:/* DO NOT EDIT THIS FILE - it is machine generated */#include/* Header for class testdll */#ifndef _Included_testdll#define _Included_testdll#ifdef __cplusplusextern "C" {#endif/** Class: testdll* Method: get* Signature: ()I*/JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);/** Class: testdll* Method: set* Signature: (I)V*/JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);#ifdef __cplusplus}#endif#endif 在具体实现的时候,我们只关⼼两个函数原型 JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); 和 JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint); 这⾥JNIEXPORT和JNICALL都是JNI的要害字,表⽰此函数是要被JNI调⽤的。

dll加载原理

dll加载原理

dll加载原理DLL加载原理是指动态链接库(DLL,Dynamic Link Library)在程序运行过程中被加载并使用的过程。

下面将介绍DLL加载的基本原理。

1. 搜寻和定位DLL文件:在程序运行时,系统会按照一定的规则搜索并定位需要加载的DLL文件。

这个规则包括在程序所在目录、系统目录、Windows目录和用户自定义路径等位置搜索。

2. 加载DLL文件:一旦DLL文件被定位,系统会根据指定的路径加载DLL文件。

加载过程包括将DLL文件的引用数据加载到内存中,以及执行相应的初始化代码。

3. 解析DLL文件的导入项:DLL文件通常会依赖其他DLL文件,这些依赖关系通过导入项列表进行声明。

加载DLL文件时,系统会解析并加载所依赖的DLL文件,以满足程序的需要。

4. 分配并初始化内存空间:DLL文件在加载后会被映射到进程的内存空间中。

系统会为DLL文件分配相应的内存空间,并在内存中创建相关的数据结构。

5. 调用DLL中的函数和变量:一旦DLL文件加载成功,程序就可以通过函数指针或通过函数名字符串调用DLL中的函数和变量。

调用过程中,系统会通过符号解析找到函数的入口点,并执行相应的操作。

6. 释放DLL文件:在程序运行结束或不再需要DLL文件时,系统会负责卸载并释放DLL文件。

卸载过程包括释放内存空间、解除函数绑定关系以及执行必要的资源清理操作。

总结:DLL加载原理涉及了搜寻定位、加载、解析导入项、分配初始化空间、调用函数/变量和释放等过程。

通过这些步骤,程序能够有效地利用并调用DLL文件中的功能,实现模块化和动态性的设计。

(动态链接库)DLL编写与使用方法

(动态链接库)DLL编写与使用方法

DLL的创建与调用1、DLL的概念DLL(Dynamic Linkable Library),动态链接库,可以向程序提供一些函数、变量或类。

这些可以直接拿来使用。

静态链接库与动态链接库的区别:(1)静态链接库与动态链接库都是共享代码的方式。

静态链接库把最后的指令都包含在最终生成的EXE 文件中了;动态链接库不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。

(2)静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。

动态链接库的分类:Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。

非MFC动态库不采用MFC 类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。

2、创建一个DLL2.1 非MFC的DLL2.1.1声明导出函数:extern “C” __declspec(dllexport) int add(int a, int b);其中extern “C”为声明为C编译。

由于C++编译器在编译的时候会造成其函数名的该变,在其他应用程序中导致函数不可调用,而C编译器则不会在编译后改变其函数名。

这样如果用C编译的程序来调用该dll中的函数时,可能会造成找不到该函数。

__declspec(dllexport)表示该函数为DLL输出函数,即其他应用程序可以调用该函数从dll中声明输出函数有两种方式:(1)另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。

如何从资源中加载DLL动态库

如何从资源中加载DLL动态库

如何从资源中加载DLL动态库就是自己使用Brcc32命令制作一个包含DLL动态库的资源文件,然后我如何从程序中加载该动态库呢!比如有一个动态库 Test.dll,然后我在制作资源文件如下:MyDll DLL Test.dll 保存为T est.rc然后使用 Brcc32 test.rc命令生成 Brcc32.res然后在程序中{$R Test.res}将该资源文件作为应用程序的一个资源编译到EXE文件中去我就想问一下,当EXE文件在运行的过程中,我如何从它的资源文件中加载我编译进去的DLL动态库,然后调用其中的函数从磁盘加载用LoadLibrary就可以了,但是,此时动态库在程序的资源文件中,也就是说他在内存中。

此时该如何加载呢?期待高手解答。

{不支持用ASPACK压缩过的DLL}{DLL Loader by Aphex************************************************function xLoadLibrary(Src: Pointer; Imports: array ofTImportItem): TLibInfo;procedure xFreeLibrary(hModule: TLibInfo);}unit DLLUnit;interfaceusesWindows;typeTImportItem = recordName: string;PProcVar: PPointer;end;TwordArr = array[0..0] of word;PwordArr = ^TwordArr;TdwordArr = array[0..0] of dword;PdwordArr = ^TdwordArr;PImageImportDescriptor = ^TImageImportDescriptor;TImageImportDescriptor = packed recordOriginalFirstThunk: dword;TimeDateStamp: dword;ForwarderChain: dword;Name: dword;FirstThunk: dword;end;PImageBaseRelocation = ^TImageBaseRelocation;TImageBaseRelocation = packed recordVirtualAddress: cardinal;SizeOfBlock: cardinal;end;TDllEntryProc = function(hinstDLL: HMODULE; dwReason: dword; lpvReserved: Pointer): Boolean; stdcall;TStringArray = array of string;TLibInfo = recordImageBase: Pointer;DllProc: TDllEntryProc;LibsUsed: TStringArray;end;PLibInfo = ^TLibInfo;PPointer = ^Pointer;TSections = array[0..100000] of TImageSectionHeader;constIMPORTED_NAME_OFFSET = $00000002;IMAGE_ORDINAL_FLAG32 = $80000000;IMAGE_ORDINAL_MASK32 = $0000FFFF;function xLoadLibrary(Src: Pointer; Imports: array of TImportItem): TLibInfo;function xFreeLibrary(LoadedLib: TLibInfo): boolean;implementationfunction xFreeLibrary(LoadedLib: TLibInfo): boolean;varObjectLoop: integer;beginResult := False;with LoadedLib dobeginif @DllProc <> nil thenbeginDllProc(HModule(LoadedLib.ImageBase),DLL_PROCESS_DETACH, nil);end;for ObjectLoop := 0 to Length(LibsUsed) - 1 dobeginif ObjectLoop >= Length(LibsUsed) thenExit;FreeLibrary(GetModuleHandle(pchar(LibsUsed[ObjectLoop]) ));end;SetLength(LibsUsed, 0);end;VirtualFree(LoadedLib.ImageBase, 0, MEM_RELEASE);Result := True;end;function xLoadLibrary(Src: Pointer; Imports: array ofTImportItem): TLibInfo;var ImageBase: pointer;ImageBaseDelta: integer;ImageNtHeaders: PImageNtHeaders;PSections: ^TSections;SectionLoop: integer;SectionBase: pointer;VirtualSectionSize, RawSectionSize: cardinal;OldProtect: cardinal;NewLibInfo: TLibInfo;function StrT oInt(S: string): integer;beginVal(S, Result, Result);end;procedure Add(Strings: TStringArray; Text: string);beginSetLength(Strings, Length(Strings) + 1); Strings[Length(Strings) - 1] := Text;end;function Find(Strings: array of string; Text: string; var Index: integer): boolean;var StringLoop: integer;beginResult := False;for StringLoop := 0 to Length(Strings) - 1 do beginif lstrcmpi(pchar(Strings[StringLoop]), pchar(T ext)) = 0 then begin Index := StringLoop; Result := True;end;end;end;function GetSectionProtection(ImageScn: cardinal): cardinal;beginResult := 0;if (ImageScn and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then beginResult := Result or PAGE_NOCACHE;end;if (ImageScn and IMAGE_SCN_MEM_EXECUTE) <> 0 then beginif (ImageScn and IMAGE_SCN_MEM_READ) <> 0 then begin if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then begin Result := Result or PAGE_EXECUTE_READWRITEend else beginResult := Result or PAGE_EXECUTE_READend;end else if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then beginResult := Result or PAGE_EXECUTE_WRITECOPYend else beginResult := Result or PAGE_EXECUTEend;end else if (ImageScn and IMAGE_SCN_MEM_READ) <> 0 then beginif (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then begin Result := Result or PAGE_READWRITEend else begin Result := Result or PAGE_READONLY endend else if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then beginResult := Result or PAGE_WRITECOPYend else beginResult := Result or PAGE_NOACCESS;end;end;procedure ProcessExports(PExports: PImageExportDirectory; BlockSize: cardinal);varExportLoop: byte;ImportedFn: cardinal;PFnName: pchar;FnIndex: dword;function IsForwarderString(Data: pchar): boolean;beginResult := Data > PExports;if Result thenResult := cardinal(Data - PExports) < BlockSize;end;function GetForwardedSymbol(ForwarderString: pchar): pointer;varsForwarderString, DllName: string;ForwarderLoop: integer;LibHandle: HModule;beginsForwarderString := ForwarderString;while ForwarderString^ <> '.' do beginInc(ForwarderString);end;DllName := Copy(sForwarderString, 1, pos('.', sForwarderString) - 1);if not Find(NewLibInfo.LibsUsed, DllName, ForwarderLoop) then beginLibHandle := LoadLibrary(pchar(DllName));Add(NewLibInfo.LibsUsed, DllName);end else begin LibHandle := cardinal(NewLibInfo.LibsUsed[ForwarderLoop]);end;if ForwarderString^ = '#' thenForwarderString := pointer(StrToInt((ForwarderString + 1)));Result := GetProcAddress(LibHandle, ForwarderString);end;beginfor ExportLoop := 0 to PExports.NumberOfNames - 1 do beginPFnName := pchar(PdwordArr(cardinal(PExports.AddressOfNames) + cardinal(ImageBase))^[ExportLoop] + cardinal(ImageBase));for ImportedFn := low(Imports) to high(Imports) do begin if Imports[ImportedFn].Name = PFnName then beginFnIndex := PwordArr(cardinal(PExports.AddressOfNameOrdinals) + cardinal(ImageBase))^[ExportLoop];Imports[ImportedFn].PProcVar^ := pointer(PdwordArr(cardinal(PExports.AddressOfFunctions) + cardinal(ImageBase))^[FnIndex] + cardinal(ImageBase));if IsForwarderString(Imports[ImportedFn].PProcVar^) thenbegin Imports[ImportedFn].PProcVar^ := GetForwardedSymbol(Imports[ImportedFn].PProcVar^);end;end;end;end;end;procedure ProcessRelocs(PRelocs: PImageBaseRelocation);varPReloc: PImageBaseRelocation;RelocsSize: cardinal;Reloc: PWord;ModCount: cardinal;RelocLoop: cardinal;beginPReloc := PRelocs;RelocsSize := ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_BASERELOC].Size;while cardinal(PReloc) - cardinal(PRelocs) < RelocsSize do beginModCount := (PReloc.SizeOfBlock - Sizeof(PReloc^)) div 2;Reloc := pointer(cardinal(PReloc) + sizeof(PReloc^));for RelocLoop := 0 to ModCount - 1 dobegin if Reloc^ and $F000 <> 0 thenInc(pdword(cardinal(ImageBase) + PReloc.VirtualAddress + (Reloc^ and $0FFF))^, ImageBaseDelta);Inc(Reloc);end;PReloc := pointer(Reloc);end;end;procedure ProcessImports(PImports: PImageImportDescriptor);varPImport: PImageImportDescriptor;Import: LPDword;PImportedName: pchar;LibHandle: HModule;ProcAddress: pointer;PLibName: pchar; ImportLoop: integer;function IsImportByOrdinal(ImportDescriptor: dword; HLib: THandle): boolean;beginResult := (ImportDescriptor and IMAGE_ORDINAL_FLAG32) <> 0;end;beginPImport := PImports;while <> 0 do beginPLibName := pchar(cardinal() + cardinal(ImageBase));if not Find(NewLibInfo.LibsUsed, PLibName, ImportLoop) thenbegin LibHandle := LoadLibrary(PLibName);Add(NewLibInfo.LibsUsed, PLibName);end else begin LibHandle :=cardinal(NewLibInfo.LibsUsed[ImportLoop]);end; if PImport.TimeDateStamp = 0 then beginImport := LPDword(pImport.FirstThunk + cardinal(ImageBase))end else beginImport := LPDword(pImport.OriginalFirstThunk + cardinal(ImageBase));end;while Import^ <> 0 do beginif IsImportByOrdinal(Import^, LibHandle) then beginProcAddress := GetProcAddress(LibHandle, pchar(Import^ and $FFFF))end else beginPImportedName := pchar(Import^ + cardinal(ImageBase) + IMPORTED_NAME_OFFSET);ProcAddress := GetProcAddress(LibHandle, PImportedName);end;PPointer(Import)^ := ProcAddress;Inc(Import);end;Inc(PImport);end;end;beginImageNtHeaders := pointer(int64(cardinal(Src)) + PImageDosHeader(Src)._lfanew);ImageBase := VirtualAlloc(nil, ImageNtHeaders.OptionalHeader.SizeOfImage, MEM_RESERVE,PAGE_NOACCESS);ImageBaseDelta := cardinal(ImageBase) - ImageNtHeaders.OptionalHeader.ImageBase;SectionBase := VirtualAlloc(ImageBase, ImageNtHeaders.OptionalHeader.SizeOfHeaders,MEM_COMMIT, PAGE_READWRITE);Move(Src^, SectionBase^, ImageNtHeaders.OptionalHeader.SizeOfHeaders);VirtualProtect(SectionBase,ImageNtHeaders.OptionalHeader.SizeOfHeaders,PAGE_READONLY, OldProtect);PSections := pointer(pchar(@(ImageNtHeaders.OptionalHeader)) + ImageNtHeaders.FileHeader.SizeOfOptionalHeader);for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do beginVirtualSectionSize := PSections[SectionLoop].Misc.VirtualSize;RawSectionSize := PSections[SectionLoop].SizeOfRawData;if VirtualSectionSize < RawSectionSize thenbeginVirtualSectionSize := VirtualSectionSize xor RawSectionSize;RawSectionSize := VirtualSectionSize xor RawSectionSize;VirtualSectionSize := VirtualSectionSize xor RawSectionSize;end;SectionBase := VirtualAlloc(PSections[SectionLoop].VirtualAddress + pchar(ImageBase), VirtualSectionSize, MEM_COMMIT, PAGE_READWRITE);FillChar(SectionBase^, VirtualSectionSize, 0);Move((pchar(src) + PSections[SectionLoop].PointerToRawData)^, SectionBase^, RawSectionSize);end;NewLibInfo.DllProc := TDllEntryProc(ImageNtHeaders.OptionalHeader.AddressOfEntry Point + cardinal(ImageBase));NewLibInfo.ImageBase := ImageBase;SetLength(NewLibInfo.LibsUsed, 0);ifImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_BASERELOC].VirtualAddress <> 0 thenProcessRelocs(pointer(ImageNtHeaders.OptionalHeader.Dat aDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddr ess + cardinal(ImageBase)));ifImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_IMPORT].VirtualAddress <> 0 thenProcessImports(pointer(ImageNtHeaders.OptionalHeader.D ataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddres s + cardinal(ImageBase)));for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do beginVirtualProtect(PSections[SectionLoop].VirtualAddress + pchar(ImageBase), PSections[SectionLoop].Misc.VirtualSize, GetSectionProtection(PSections[SectionLoop].Characteristics), OldProtect);end;*********************<>nilthenbeginif not NewLibInfo.DllProc(cardinal(ImageBase), DLL_PROCESS_ATTACH, nil) thenbeginNewLibInfo.DllProc := nil;xFreeLibrary(Result);end;end;ifImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_EXPORT].VirtualAddress <> 0 thenProcessExports(pointer(ImageNtHeaders.OptionalHeader.D ataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddres s + cardinal(ImageBase)), ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_EXPORT].Size);Result := NewLibInfo;end;{//调用示例program test;UsesWindows, DLLUnit;varResourceLocation: HRSRC;ResourceSize: LongWord;ResourceHandle: THandle;ResourcePointer: Pointer;TestFunction: procedure;MyImports: array [0..0] of TImportItem =((Name: 'TestFunction'; PProcVar: @@TestFunction));MyLibrary: TLibInfo;beginResourceLocation := FindResource(HInstance, pchar('a01'), RT_RCDATA);if ResourceLocation <> 0 thenbeginResourceSize := SizeofResource(HInstance, ResourceLocation);if ResourceSize <> 0 thenbeginResourceHandle := LoadResource(HInstance, ResourceLocation);if ResourceHandle <> 0 thenbeginResourcePointer := LockResource(ResourceHandle);if ResourcePointer <> nil thenbeginMyLibrary := xLoadLibrary(ResourcePointer, MyImports);TestFunction;end;end;end;end;xFreeLibrary(MyLibrary);end.//===================================== ========================================= varFLibrary: TLibInfo;test: function(const i : Integer):integer; stdcall;constDllImports: array [0..0] of TImportItem =((Name: 'test'; PProcVar: @@test));procedure LoadLib;varBuf : Pointer;Size : DWORD;ProcessId: Cardinal;ResHandle:Cardinal;beginResHandle := FindResource(hInstance, 'testdll', 'DLL');if ResHandle > 0 thenbeginSize := SizeofResource(hInstance, ResHandle);Buf := LockResource(LoadResource(hInstance, ResHandle));FLibrary := xLoadLibrary(Buf, DllImports);end;end;procedure FreeLib;beginif FLibrary.ImageBase <> nil then beginif xFreeLibrary(FLibrary) then FLibrary.ImageBase := nil; end;end;//}end.。

DLL(动态链接库)详解

DLL(动态链接库)详解

DLL (动态链接库)详解动态链接库英文为DLL,是Dynamic Link Library 的缩写形式,DLL 是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。

动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。

函数的可执行代码位于一个DLL 中,该DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。

DLL 还有助于共享数据和资源。

多个应用程序可同时访问内存中单个DLL 副本的内容。

DLL 是一个包含可由多个程序同时使用的代码和数据的库。

目录定义DLL 的优点DLL文件损坏DLL 依赖项导出DLL 函数DLL错误的危害DLL修复方法定义DLL 的优点DLL文件损坏DLL 依赖项导出DLL 函数DLL错误的危害DLL修复方法展开定义通过使用DLL,程序可以实现模块化,由相对独立的组件组成。

例如,一个计帐程序可以按模块来销售。

可以在运行时将各个模块加载到主程序中(如果安装了相应模块)。

因为模块是彼此独立的,所以程序的加载速度更快,而且模块只在相应的功能被请求时才加载。

此外,可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。

例如,您有一个大型网络游戏,如果把整个数百MB甚至数GB的游戏的代码都放在一个应用程序里,日后的修改工作将会十分费时,而如果把不同功能的代码分别放在数个动态链接库(DLL)中,您无需重新生成或安装整个程序就可以应用更新。

下表说明了Windows 操作系统中的一些作为DLL 实现的文件:•ActiveX 控件(.ocx) 文件ActiveX 控件的一个示例是日历控件,它使您可以从日历中选择日期。

•控制面板(.cpl) 文件.cpl 文件的一个示例是位于控制面板中的项。

每个项都是一个专用DLL。

•设备驱动程序(.drv) 文件设备驱动程序的一个示例是控制打印到打印机的打印机驱动程序。

DLL 的优点1、扩展了应用程序的特性;2、可以用许多种编程语言来编写;3、简化了软件项目的管理;4、有助于节省内存;5、有助于资源共享;6、有助于应用程序的本地化;7、有助于解决平台差异;8、可以用于一些特殊的目的。

Lua5.1中加载dll动态链接库的方法

Lua5.1中加载dll动态链接库的方法

Lua5.1中加载dll动态链接库的⽅法⼀、加载专门为lua写的扩展dll使⽤require或package.loadlib⽅法,在此不做过多解释。

⼆、加载不是专为lua写的扩展dll“不是专为lua写的扩展dll”是指:dll中并没有以lua注册函数的⽅式导出接⼝,⽽是以__declspec(dllexport)形式导出的接⼝。

这样就不能使⽤“package.loadlib”⽅法调⽤,⽽要使⽤lua5.1封装过的“alien.load()”⽅法。

(Lua\5.1\lua\alien.lua)基本⽤法:1、加载alien:复制代码代码如下:require(“alien”)2、加载动态链接库:(此处以”msvcrt.dll”为例)复制代码代码如下:libc = alien.load(“msvcrt.dll”)3、说明参数类型:(第⼀个参数表⽰返回类型,后⾯的参数表⽰传⼊参数类型)复制代码代码如下:libc.puts:types(“void”, “string”)Alien转换 Lua numbers 为C的 numeric 类型, 转换 nil 为 NULL,strings 为 const char* , userdata 为 void* 指针。

⽽函数返回值的转换⼯作正好相反(pointer类型转换为userdata)。

以上三步完成了dll的加载,之后便可调⽤dll中的函数来实现操作,例如:复制代码代码如下:libc.puts(“test”)当传⼊引⽤类型参数时,需要alien在堆栈中分配空间,lua的变量将值传递给函数参数,如:复制代码代码如下:scanf = libc.scanfscanf:types(“int”, “string”, “ref int”, “ref double”)_, x, y = scanf(“%i %lf”, 1, 1) — 后⾯两个参数没有实际意义,只是为了说明参数个数调⽤时输⼊23和24.5,输⼊的这2个参数才是真正需要传递给函数的参数,ref int, ref double是告诉alien需要分配空间,调⽤C 函数从栈中获取它的参数,调⽤结束后将返回结果放到栈中(为了区分返回结果和栈中的其他的值,每个C函数还会返回结果的个数),然后lua函数返回结果值。

C#动态加载DLL(反射学习(二))

C#动态加载DLL(反射学习(二))

window命令大全/*主要说明如何通过反射实现动态加载DLL,* 因为.Net底层有自动回收机制,所以不需要考虑这个问题* ADD by Brian 2008/01/21 参考MSDN*/using System;using System.IO;using System.Threading;using System.Reflection;using System.Reflection.Emit;using System.Runtime.Remoting;namespace DynamicIncreaseDLL{#regionclass DynamicLoadDLL{[STAThread]static void Main(string[] args){string sCallDomainName = Thread.GetDomain().FriendlyName;Console.WriteLine(sCallDomainName);//创建一个动态程序域Console.WriteLine("请输入动态程序域名称");string sAD = Console.ReadLine();AppDomain ad = AppDomain.CreateDomain(sAD);//实例化一个ProxyObject这个类型的对象这个是需要加载DLL的对象 ProxyObject obj =(ProxyObject)ad.CreateInstanceAndUnwrap("DynamicIncreaseDLL", "DynamicIncreaseDLL.ProxyObject");//自己抓一个需要动态加载的DLL的文件名(包含文件路径)string sFileName = Environment.CurrentDirectory + "\\" + "gmrbrian.exe";obj.LoadAssembly(sFileName);obj.Invoke("类名", "构造方法名", "主程序方法参数");AppDomain.Unload(ad);obj = null;Console.ReadLine();}}class ProxyObject : MarshalByRefObject{Assembly asbly = null;//加载包含路径的文件public void LoadAssembly(string AFileName){asbly = Assembly.LoadFile(AFileName);}//实例化该类public bool Invoke(string AFullClassName, string AMethodName, params Object[] args){if (asbly == null)return false;//获取该类的类型Type tp = asbly.GetType(AFullClassName);if (tp == null)return false;//获取该类的构造方法MethodInfo mInfo = tp.GetMethod(AMethodName);if (mInfo == null)return false;//实例化该类Object obj = Activator.CreateInstance(tp);//激活该对象mInfo.Invoke(obj, args);return true;}}#endregion}注意:1. 要想让一个对象能够穿过AppDomain边界,必须要继承MarshalByRefObject类,否则无法被其他AppDomain使用。

动态加载类(动态加载DLL文件)

动态加载类(动态加载DLL文件)

动态加载类(动态加载DLL⽂件)我们在编写程序的时候经常会遇到这样的情况:程序中要⽤到某种计算,⽽且这种计算的计算⽅式很多,我们不得不在编写程序时就要考虑的⼗分全⾯,将各种情况到考虑到。

但是这样做⼜⾮常的费⼒,因为我们⽆法预测到程序编好后,还会出现什么样的计算⽅式。

如果计算⽅式是在交付给客户后,客户新提出的我们就不得不将新的计算⽅式写⼈程序中,然后重新编译,再交给客户。

这样做是相当⿇烦的,⽽且只为了这么⼀⼩段程序,就要重新编译整个⼯程,似乎代价也挺⼤的。

使⽤中System.Reflection中的⼀些⽅法,可以帮助我们很好的解决上⾯的问题。

⾸先,在遇到上⾯提出的问题的时候,我们先要进⾏⼀下分析,这种计算需要⼀些什么参数?在不同的计算⽅式中,它们共同的参数是什么?不同的计算⽅式中特有的参数是否可以通过共有的参数计算出来,或是通过其它⽅法获得?分析完后,提取出可⽤的共同参数。

接下来,我们就可以编写计算⽅法了。

将这种计算的每⼀种⽅式都写成⼀个DLL⼀个类中的⽅法,并将其编译为⼀个DLL⽂件。

中,类的格式要定死,也就是说编写的类的namespace和class要⼀样,类中的⽅法名称也必须是⼀样的。

⽽且,⽅法的参数就是上⾯所说的共同参数。

然后,将编译好的DLL⽂件放在同⼀⽂件夹内,随程序⼀起发布就可以了。

在程序中可以这样处理所要⽤到的不同计算⽅式:给每⼀种计算⽅式起⼀个名字(客户能够明⽩的),然后将这些名字放在下拉列表框的text属性中,并将对应的DLL⽂件名放在下拉列表框的value属性中。

这样,⽤户选择不同的计算⽅式就可以调⽤不同DLL⽂件中的计算⽅法了。

下⾯是⼀个简单的⽰例:我将计算⽅式的名字和DLL⽂件名放在⼀个xml⽂件中,程序加载时将它们读取到下拉列表框中。

⽅法如下:(中)// 在此处放置⽤户代码以初始化页⾯if(Page.IsPostBack==false){//页⾯⾸次加载时读取XML⽂件System.Xml.XmlDocument xmlDoc=new System.Xml.XmlDocument();System.Xml.XmlNode xmlNd;int i;xmlDoc.Load(Server.MapPath("MyConfig.xml"));xmlNd=xmlDoc.SelectSingleNode("//dllfile");//将读出的XML⽂件的有关内容写⼊下拉列表框中for(i=0;i<xmlNd.SelectNodes("field").Count;i++){ListItem it=new ListItem();it.Text=xmlNd.SelectNodes("field").Item(i).Attributes["text"].Value;it.Value=xmlNd.SelectNodes("field").Item(i).Attributes["filename"].Value;this.ddlType.Items.Add(it);}}然后,在输⼊完参数之后,可以使⽤下⾯的代码来完成计算并将结果显⽰出来。

vb动态加载dll的一个类,实现vb动态加载dll并动态调用dll导出的函数的一个方便办法

vb动态加载dll的一个类,实现vb动态加载dll并动态调用dll导出的函数的一个方便办法

vb动态加载dll的一个类,实现vb动态加载dll并动态调用dll导出的函数的一个方便办法自从会vb用调用动态库函数以来,我一直在想:如何动态的调用dll 里的函数?网上有一个用CallWindowProc函数的方法,不过我还是喜欢自己有个办法.今天工夫不负有心人,我终于把我心中一直想的办法给实现了,干脆就往自己的空间上贴吧.错误的地方,希望可以得到有这方面的师傅给以指正,以求进步!对于系统api我没有尝试,如果调用约定相符,应该适用于对系统api的调用.我自己用c写个dll,然后在vb里写了这个类.以下代码只是我简单的实现,主要的是看实现的道理.vc代码:///'我把dll文件名命名为:dll#include <Windows.h>#include <stdlib.h>#include <string.h>#include 'stdafx.h'BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved){return TRUE;}extern 'C' BOOL _declspec(dllexport) add(int a){MessageBoxA(NULL,'运行在dll里!','成功',MB_OK);return 1;}///vb代码:'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''类代码:Private 状态标志 As BooleanPrivate 模块句柄 As LongPrivate 本地函数地址备份(0 To 4) As BytePrivate 被替换函数的地址 As LongPublic Function 替换函数地址(模块名As String, 函数名As String, 本地函数地址 As Long) As BooleanIf 0 = 本地函数地址 Then替换函数地址 = 0Exit FunctionEnd If被替换函数的地址 = 替换函数地址Dim 函数地址 As LongDim a As LongDim 跳转指令(0 To 4) As Byte'加载模块模块句柄 = LoadLibrary(模块名)If 0 <> 模块句柄 Then'状态标志 = 1Else:替换函数地址 = 0Exit Function'检索函数地址函数地址 = GetProcAddress(ByVal 模块句柄, ByVal 函数名)If 0 <> 函数地址 Then'状态标志 = 1Else替换函数地址 = 0Exit FunctionEnd If'计算跳转地址a = 函数地址 - (本地函数地址 + 5)'构造跳转地址跳转指令(0) = 233a = WriteProcessMemory(-1, ByVal VarPtr(跳转指令(1)), ByVal VarPtr(a), 4, 0)If 0 = a Then替换函数地址 = 0Exit FunctionEnd If'先备份本地函数入口指令a = WriteProcessMemory(-1, ByVal VarPtr(本地函数地址备份(0)), ByVal 本地函数地址, 5, 0)If 0 = a Then替换函数地址 = 0Exit FunctionEnd If'写入跳转指令a = WriteProcessMemory(-1, ByVal 本地函数地址, ByVal VarPtr(跳转指令(0)), 5, 0)If 0 = a Then替换函数地址 = 0Exit FunctionElse:状态标志 = 1替换函数地址 = 1End IfEnd FunctionPublic Function 还原函数地址() As BooleanIf 0 = 状态标志 Then还原函数地址 = 0Exit FunctionEnd IfDim a As Longa = WriteProcessMemory(-1, ByVal 被替换函数的地址, ByVal VarPtr(本地函数地址备份(0)), 5, 0)If 0 = a Then还原函数地址 = 0Exit FunctionElse:状态标志 = 0还原函数地址 = 1End IfFreeLibrary 模块句柄End FunctionPublic Function 当前状态() As Boolean当前状态 = 状态标志End Function''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''vb普通模块代码:'读写内存的api函数Public Declare Function WriteProcessMemory Lib 'kernel32' (ByVal hProcess As Long, ByVal _lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long'加载模块的api函数Public Declare Function LoadLibrary Lib 'kernel32' Alias 'LoadLibraryA' (ByVal lpLibFileName As String) As Long '检索模块里函数地址的api函数Public Declare Function GetProcAddress Lib 'kernel32' (ByVal hModule As Long, ByVal lpProcName As String) As Long 'Public Declare Function FreeLibrary Lib 'kernel32' (ByVal hLibModule As Long) As Long'模拟一个函数与dll里,我们想调用函数类型和参数一致, 用类将函数的地址替换Public Function 测试函数(参数 As Long) As Boolean'我们随便给返回0,因为这个指令将不会被程序执行到测试函数 = 0End Function''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''vb窗口模块代码:Private Sub Form_Load()Dim 模块名 As String, 函数名 As String模块名 = App.Path + '/dll.dll''模块名现在可以自己定了,自由了!函数名 = 'add'Dim p As BooleanDim aa As New Class1p = aa.替换函数地址(模块名, 函数名, AddressOf 测试函数) If p Then测试函数 0'将会弹出对话筐:运行在dll里!aa.还原函数地址End IfEnd Sub'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''。

动态链接库(dll)学习资料总结

动态链接库(dll)学习资料总结

1. 什么是lib文件,lib和dll的关系如何(1)lib是编译时需要的,dll是运行时需要的。

如果要完成源代码的编译,有lib就够了。

如果也使动态连接的程序运行起来,有dll就够了。

在开发和调试阶段,当然最好都有。

(2)一般的动态库程序有lib文件和dll文件。

lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。

如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。

如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。

静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。

但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。

(3)在动态库的情况下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,DLL库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行时再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。

从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。

2、严重警告:(1) 用 extern "C" _declspec(dllexport) 只可以导出全局函数,不能导出类的成员函数(2) 使用extern "C" _declspec(dllexport)输出的函数可以被c语言调用,否则则不可(3) 注意标准调用约定的问题,输出与调用的函数约定应该一致,如当dll模块的函数输出采用标准调用约定_stdcall,则调用程序的导入函数说明也要用标准约定(4) 用extern "C" _declspec(dllexport) 和 EXPOTRT导出的函数不改变函数名,可以给c++或c编写的exe调用.假如没有extern "C",导出的函数名将会改变,只能给c++编写的exe调用(5)在动态加载动态链接库函数时注意GetProcAddress(hInst,"add")中第二个参数是否为动态链接库导出的函数名,因为在生成动态库时可能会改变动态库导出函数的函数名,加上修饰符(6)dll初始化全局变量时,全局变量要放在共享数据断,并且初始化每一个变量,在StartHook函数里初始化其值,记得一进函数就初始化(7)调试时,编译器会自动查找其目录下(不含debug和release目录)的dll文件,所以dll文件应该放在主文件目录下,但生成的应用程序则只会在同一个目录下找dll(不需要lib文件),所以单纯的运行exe,不通过编译器,那就要把dll文件放在与exe相同的目录下(8)用#pragma comment(lib,"dllTest.lib")导入lib文件,不需要在设置里修改(9) dll里的指针变量不要用newDLL 调用方式DLL(动态连接库),可以分为动态调用于静态调用。

关于dllimport的使用

关于dllimport的使用

关于dllimport的使⽤最近做⼀个动态加载插件的项⽬,插件中的dll 主要是各⼚商各型号的读卡器的通⽤类库,stdapi.dll,WltRS.dll,有的还有进⼀步封装的dll,主要是为了简化通⽤类库的操作。

这些类库都是⽤C语⾔,或者C++来编写的,我的项⽬是⽤C#语⾔编写,通过Dllimport来调⽤这些⾮托管dll的⽅法。

在做这个项⽬的时候,由于之前的读卡器类库都是通⽤的,所以即时使⽤两款或者更多款读卡器设备,加载的都是同⼀类dll,不会出现问题。

但是在开发与通⽤类库不兼容的插件的时候(都是读卡器插件),问题出现了。

⼀:输⼊⽤户名,密码,登陆系统。

1:该⽤户能使⽤的设备如果都是调⽤通⽤类库的读卡器,那么使⽤起来没有问题;2:该⽤户能使⽤的设备只要有⼀款与其他的不同,那么在切换的时候问题就出现了。

什么问题呢? 假如现在有两个设备,A和B,A属于可以调⽤通⽤类库的设备,B不能调⽤通⽤类库,但是有⾃⼰的⼀套单独的类库。

当我启⽤A设备的时候,第⼀次执⾏DllImport(“sdtapi.dll”)或者DllImport(“WltRS.dll”)后,那么这两个dll就会加载到内存中。

这个时候我把A设备禁⽤,启⽤B设备,B设备也有这样的调⽤语句,DllImport(“sdtapi.dll”)或者DllImport(“WltRS.dll”),但是B设备的这两个dll与A设备的不同, ⼤家猜猜看,这个时候B设备调⽤的是哪⼀个dll?? ⼀开始,我以为B设备调⽤的是⾃⼰⽬录下的dll。

但是经过多次试验,我发现我错了。

只要是同名的dll,如果不指定绝对路径⽅式进⾏加载,那么第⼀次加载之后的所有调⽤语句都是调⽤的第⼀次加载的那个dll中的⽅法。

所以就造成了设备使⽤的紊乱。

但是如果这样 DllImport(“sdtapi.dll”)或者DllImport(“WltRS.dll”),和DllImport(“C:\\sdtapi.dll”)或者DllImport(“C:\\WltRS.dll”), 调⽤的却不是同⼀个dll,操作系统就会分别调⽤。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

动态加载DLL的方法与注意的问题
加载DLL的方法主要有两种:一种是隐式链接,另外一种是动态加载。

隐式链接会把DLL中所有标志为_declspec(dllexport)的函数都加载,如果有多个DLL 加载时,可能会影响到程序执行的效率。

而用动态加载DLL的方式则可以根据需要去加载用到的函数。

动态加载DLL的方法:
1.生成dll过程:把生成的.DLL文件复制到测试工程DLLTest目录下。

这里假设该.DLL 文件为add.dll,主要代码是:
Extern “C” _declspec(dllexport) int add(int x, int y)
{
return x + y;
}
2.使用1生成的dll:在DLLTest工程中添加DllTest.cpp文件.
首先使用LoadLibrary("add.dll")加载add.dll文件:
HMODULE hmod = LoadLibrary("add.dll");
然后定义一个函数指针的类型:
typedef int (*AddAddr)(int x, int y);
注意,这里的参数与返回类型务必与add.dll文件中函数add的声明一样。

接着:
AddAddr Add = (AddAddr)GetProcAddress(hmod, "add");
如果Add值为空,则获取函数的地址失败!
if(!Add)
{
printf("获取函数地址失败!");
return;
}
最后,可以测试一下:
printf("test add(): 1+2=%d", add(1,2));
运行结果一看,会出现“获取函数地址失败!”。

为什么会这样?
打开命令行,用cd命令到add.dll工程目录的debug目录下,然后使用命令:dumpbin -exports add.dll
则会看到add.dll文件中的add函数的名称为“?add@@YAHHH@Z”,而不是函数名add,这是C++编译器的命名改编机制。

修改原来的代码:
AddAddr Add = (AddAddr)GetProcAddress(hmod, "?add@@YAHHH@Z");
这时运行就成功了。

但如果按这样去动态加载DLL,那每次获取函数地址都要使用dumpbin 命令去获取,则会很麻烦。

那怎样可以直接使用add而不是?add@@YAHHH@Z这个长长的字符串呢,修改add.dll 的add函数,在函数前加上extern "C",再编译add.dll文件所在的工程,复制新生成的add.dll覆盖DLLTest工程目录下的add.dll,原来的代码获取函数地址时使用add,结果运行就成功了。

而再使用dumpbin -exports add.dll命令,显示add.dll的中的add函数的名称变成了add.。

相关文档
最新文档