动态加载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、解析导出函数等步骤。

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

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

动态加载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++编译器的命名改编机制。

动态链接库的加载方式

动态链接库的加载方式

动态链接库的加载方式:1.隐式加载和 2.显示加载一、先做一个隐式加载的例子:1)用MFC向导新建一个Win32 Dynamic-Link Library的工程项目,名字叫做Dll1, 并且新建一个Dll1的C++源文件2)在Dll1.cpp文件中,编写完成加法与减法运算的函数add()和substract()3)编译之后,我们可以在工程目录的Debug文件夹中发现一个Dll1.dll的文件,这就是动态链接库文件。

现在已经有了一个动态链接库,那么怎么让其他程序访问它呢?首先,动态链接库中的文件必须被导出后才能被其它程序访问。

我们可以用VC自带的工具Dumpbin来查看那些动态链接库的函数被导出了。

可在命令行下进入Debug所在目录,输入以下命令dumpbin -exports dll.dll有些时候由于某种安装原因,dumpbin被认为是无效命令,可以到VC的安装目录..\Microsoft Visual Studio\VC98\Bin\下找到VCVARS32.bat并在命令行运行,之后就能执行dumpbin命令了。

输入dumpbin -exports Dll1.dll 就可以查看函数的导出状况了,不过我们没有看到任何导出的函数。

怎样才能让我们自己编写的函数被导出呢?只要在每个函数定义的前面加上_declspec(dllexport)标记就行了,如下所示:_declspec(dllexport)int Add(int x,int y){return x+y;}_declspec(dllexport)int Subtract(int x,int y){return x-y;}加了_declspec(dllexport)以后再编译一下,就会再生一个*.lib引入库文件和一个*.exp文件,里面包含的是导出的函数或者变量的符号名。

而exp文件是一个输出库文件。

这时我们再一次在命令提示符下面输入命令:dumpbin -exports Dll1.dll就会有下面的结果出现然后,新建一个基于对话框的MFC AppWizard 测试工程,在对话框上添加Add与SubTract 按钮,在这两个按钮中,分别调用动态链接库中所写的两个函数。

动态链接库知识点总结之三(如何以显示的方式加载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#程序设计有所帮助。

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调⽤的。

c#动态加载dll并调用dll中类的方法

c#动态加载dll并调用dll中类的方法

c#动态加载dll并调⽤dll中类的⽅法当然,这⾥指的是托管的dll与托管的⽅法,实际上⽤到的东西⼤部分是在反射(reflecting)命名空间⾥头的。

⽤途或许⼴泛吧,我不是很确信,但这个是在运⾏期绑定的,那么就不会有编译期绑定那么僵硬……但也没有编译期绑定那么简单。

可以⽤于做插件之类的。

先是⼀个接⼝,实现了这个接⼝的类被认为是合法的,可以被载⼊的……namespace gp{public delegate void DoWhat();public interface IInterface{string GetName();DoWhat dowhat { get; set; }}}很简单的接⼝,⼀个是⽤于判断做什么的函数,另外⼀个,则是⼀个⽅法的委托,做什么。

然后,我们新建⼀个项⽬,弄个类实现这个接⼝:namespace gp{public delegate void DoWhat();public interface IInterface{string GetName();DoWhat dowhat { get; set; }}}在构造函数⾥头将委托加了⼀个项,当执⾏那个委托的时候就会执⾏这个函数。

现在是重要的⼀个部分,代码难度不⼤~~新建⼀个windows application,然后在窗体上头拖⼀个panel,这个是为了动态加载后将操作按钮放上去的。

不过可能会重叠,建议考虑⽤flowlayoutpanel,这个会⾃动重排以满⾜个数,anyway,⽆所谓,反正是为了阐述概念。

private void Form1_Load(object sender, EventArgs e){var plugindir = System.IO.Directory.GetParent(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName).CreateSubdirectory("startup");foreach (var filesInPlugin in plugindir.GetFiles()){if (filesInPlugin.Extension.ToLower() == ".dll"){Assembly dllFromPlugin = Assembly.LoadFile(filesInPlugin.FullName);foreach (var dllModule in dllFromPlugin.GetLoadedModules()){foreach (var typeDefinedInModule in dllModule.GetTypes()){if (typeDefinedInModule.GetInterfaces().Contains(typeof(gp.IInterface))){if (typeDefinedInModule.IsClass){var itemGet = System.Activator.CreateInstance(typeDefinedInModule) as gp.IInterface;LinkLabel ll_now = new LinkLabel();ll_now.Text = itemGet.GetName();ll_now.Click += (a, b) => { if (itemGet.dowhat != null)itemGet.dowhat(); };panel1.Controls.Add(ll_now);}}}}}}}⼀个不难看懂的代码,先是指定插件⽂件夹的位置,要是没有就创建⼀个。

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所需要的三个函数详解(LoadLibrary,GetProcAddress,FreeLibrary)动态载入 DLL动态载入方式是指在编译之前并不知道将会调用哪些 DLL 函数,完全是在运行过程中根据需要决定应调用哪些函数。

方法是:用 LoadLibrary 函数加载动态链接库到内存,用 GetProcAddress函数动态获得DLL 函数的入口地址。

当一个 DLL 文件用 LoadLibrary 显式加载后,在任何时刻均可以通过调用 FreeLibrary 函数显式地从内存中把它给卸载。

动态调用使用的 Windows API 函数主要有 3 个,分别是 LoadLibrary、 GetProcAddress 和FreeLibrary。

我们分别详细介绍这三个函数的功能,因为无论学习编程还是逆向这是三个函数都是非常常用滴。

(1)LoadLibrary 函数注:Delphi 中还提供了 SafeLoadLibrary 函数,它封装了 Loadlibrary 函数,可以装载由 Filename 参数指定的 WindowsDLL或 Linux 共享对象。

它简化了DLL的装载并且使装载更加安全。

[格式]:1.function LoadLibrary(LibFileName : PChar): Thandle;复制代码[功能]:加载由参数 LibFileName 指定的 DLL 文件。

[说明]:参数 LibFileName 指定了要装载的 DLL 文件名,如果 LibFileName 没有包含一个路径,系统将按照:当前目录、Windows 目录、Windows 系统目录、包含当前任务可执行文件的目录、列在 PATH 环境变量中的目录等顺序查找文件。

如果函数操作成功,将返回装载 DLL 库模块的实例句柄,否则,将返回一个错误代码,错误代码的定义如下表所示。

假如在应用程序中用 LoadLibrary 函数装入某一个 DLL 前,其他应用程序已把该 DLL 装入内存中了,则系统将不再装入该 DLL 的另一个实例,而是使该 DLL 的“引用计数”加 1 。

动态链接库dll的静态加载与动态加载

动态链接库dll的静态加载与动态加载

动态链接库dll的静态加载与动态加载动态链接是指在⽣成可执⾏⽂件时不将所有程序⽤到的函数链接到⼀个⽂件,因为有许多函数在操作系统带的dll⽂件中,当程序运⾏时直接从操作系统中找。

⽽静态链接就是把所有⽤到的函数全部链接到exe⽂件中。

动态链接是只建⽴⼀个引⽤的接⼝,⽽真正的代码和数据存放在另外的可执⾏模块中,在运⾏时再装⼊;⽽静态链接是把所有的代码和数据都复制到本模块中,运⾏时就不再需要库了。

1.⽣成静态链接库 newdll) win32项⽬ -> dll添加.h⽂件betabinlib.h[cpp]1. #ifndef BETABINLIB_H2. #define BETABINLIB_H3.4. #ifdef NEWDLL_EXPORTS //⾃动添加的宏右键⼯程-属性-配置属性-预处理器-..定义5. #define MYDLL_API extern "C" __declspec(dllexport)6. #else7. #define MYDLL_API extern "C" __declspec(dllimport)8. #endif9.10. MYDLL_API int add(int x, int y); // 必须加前缀11. #endif#ifndef BETABINLIB_H#define BETABINLIB_H#ifdef NEWDLL_EXPORTS //⾃动添加的宏右键⼯程-属性-配置属性-预处理器-..定义#define MYDLL_API extern "C" __declspec(dllexport)#else#define MYDLL_API extern "C" __declspec(dllimport)#endifMYDLL_API int add(int x, int y); // 必须加前缀#endif添加.cpp⽂件 betabinlib.cpp[cpp]1. #include "stdafx.h"2. #include "betabinlib.h"3.4. int add(int x, int y)5. {6. return x + y;7. }#include "stdafx.h"#include "betabinlib.h"int add(int x, int y){return x + y;}编译⽣成 .dll 和 .(1)dll的静态加载--将整个dll⽂件加载到 .exe⽂件中特点:程序较⼤,占⽤内存较⼤,但速度较快(免去调⽤函数LOAD1. #include <stdio.h>2. #include "betabinlib.h"3. #include <Windows.h>4. #pragma comment(lib, "newdll.lib")5.6. int main()7. {8. printf("2 + 3 = %d \n", add(2, 3));9. return 0;10. }#include <stdio.h>#include "betabinlib.h"#include <Windows.h>#pragma comment(lib, "newdll.lib")int main(){printf("2 + 3 = %d \n", add(2, 3));return 0;}1. #include <stdio.h>2. #include <Windows.h>3.4. int main()5. {6. HINSTANCE h=LoadLibraryA("newdll.dll");7. typedef int (* FunPtr)(int a,int b);//定义函数指针8.9. if(h == NULL)10. {11. FreeLibrary(h);12. printf("load lib error\n");13. }14. else15. {16. FunPtr funPtr = (FunPtr)GetProcAddress(h,"add");17. if(funPtr != NULL)18. {19. int result = funPtr(3, 3);20. printf("3 + 3 = %d \n", result);21. }22. else23. {24. printf("get process error\n");25. printf("%d",GetLastError());26. }27. FreeLibrary(h);28. }29.30. return 0;31. }。

DLL动态加载

DLL动态加载

DLL动态加载DLL是windows平台下的⽂件,调⽤⽅式为了动态加载和静态链接(有的地⽅⼜称显⽰调⽤和隐式调⽤),静态链接⽅式可参见相关⽂章,本⽂章主要记录动态加载的⽅法。

动态加载需要.dll⽂件,以及dll内导出函数的说明若是普通函数,数据结构都是通⽤结构,则只需要dll,和调⽤函数的说明;若有⾃定义的类型,则需要和dll中的该类型相同的声明定义,简单的说,有头⽂件最好。

使⽤平台API或者库API加载dll其中的函数,然后再使⽤,本⽂主要介绍使⽤Qt库函数的⽅法,该⽅法⽀持跨平台。

所谓动态加载就是在程序运⾏时进⾏加载,能否调⽤dll中的⽅法,只有在程序运⾏的时候才能知道。

使⽤dll中的函数Qt提供QLibrary类提供动态加载。

⽰例://导出的函数int DllAdd(int num, int num_2);//动态加载typedef int (*AddFunction)(int, int); //定义函数指针,参数和返回值必须和导出的函数⼀致QLibrary library("DllName.dll");if(library.load()) //加载dll{AddFunction Add = (AddFunction)library.resolve("DllAdd"); //提取指定函数if(Add) //导出成功{qDebug()<<Add(1, 2); //使⽤函数}else{qWarning()<<library.errorString();}}else //加载失败{qWarning()<<library.errorString();}使⽤dll中类由上例可见,平台和库API只能加载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的加载静态链接库在链接时,编译器会将 .obj 文件和 .LIB 文件组织成一个 .exe 文件,程序运行时,将全部数据加载到内存。

如果程序体积较大,功能较为复杂,那么加载到内存中的时间就会比较长,最直接的一个例子就是双击打开一个软件,要很久才能看到界面。

这是静态链接库的一个弊端。

动态链接库有两种加载方式:隐式加载和显示加载。

•隐式加载又叫载入时加载,指在主程序载入内存时搜索DLL,并将DLL载入内存。

隐式加载也会有静态链接库的问题,如果程序稍大,加载时间就会过长,用户不能接受。

•显式加载又叫运行时加载,指主程序在运行过程中需要DLL中的函数时再加载。

显式加载是将较大的程序分开加载的,程序运行时只需要将主程序载入内存,软件打开速度快,用户体验好。

隐式加载首先创建一个工程,命名为cDemo,添加源文件main.c,内容如下:1.#include2.3.extern int add(int, int); // 也可以是_declspec(dllimport) intadd(int, int);4.extern int sub(int, int); // 也可以是_declspec(dllimport) intsub(int, int);5.6.int main(){7.int a=10, b=5;8.printf('a+b=%d\n', add(a, b));9.printf('a-b=%d\n', sub(a, b));10.return 0;11.}#includeextern int add(int, int); // 也可以是_declspec(dllimport) intadd(int, int);extern int sub(int, int); // 也可以是 _declspec(dllimport) intsub(int, int);int main(){ int a=10, b=5; printf('a+b=%d\n', add(a, b)); printf('a-b=%d\n', sub(a, b)); return 0;}找到上节创建的 dllDemo 工程,将 debug 目录下的dllDemo.lib 和dllDemo.dll 复制到当前工程目录下。

C#,动态加载DLL,反射,参数,自定义,子窗体

C#,动态加载DLL,反射,参数,自定义,子窗体

C#,动态加载DLL,反射,参数,自定义,子窗体
C#,动态加载DLL,反射,参数,自定义,子窗体
2009-07-28 12:46:38| 分类: .NET |字号订阅
DOTNET中有时候需要,调用自定义的DLL,带窗口的或者不带的都有.用途还比较广泛..
看到网上很多资料都没说明白怎么回事情,特记录整理如下
例子:
在父窗体里动态加载DLL中的窗体:
父窗体代码:
首先确定DLL文件的存在,当然如果不存在,还可以到服务器取回来,代码略.
Assembly MyAssembly = Assembly.LoadFrom("ClassLibrary2.dll"); //找到DLL文件,最好放在同1目录下
Form fom = (Form)MyAssembly.CreateInstance("ClassLibrary2.Form1"); //DLL 文件中的空间名.类名(窗体名)
fom.GetType().GetProperty("Field").SetValue(fom, "参数", null); //设置参数,Field为DLL自定义参数名
fom.MdiParent = this;//设置父窗体
fom.Show();
DLL中子窗体:
private string field;
public string Field
{
get
{
return this.field;
}
set
{
this.field = value;
}
}
当然你还可以增加N个参数.。

动态加载类(动态加载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方法
{
if(assembly == null)
return false;
Type tp = assembly.GetType(fullClassName);
if (tp == null)
return false;
MethodInfo method = tp.GetMethod(methodName);
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Reflection;
namespace UnloadDll
{
class Program
{
static void Main(string[] args)
C#中动态加载和卸载DLL方法以及注意事项
2010-09-22 14:45:00 我来说两句 收藏 我要投稿
在C 中加载和卸载DLL是一件很容易的事,LoadLibrary和FreeLibrary让你能够轻易的在程序中加载DLL,然后在任何地方卸载。在C#中我们也能使用 Assembly.LoadFile实现动态加载DLL,但是当你试图卸载时,你会很惊讶的发现Assembly没有提供任何卸载的方法。这是由于托管代码的自动垃圾回收机制会做这件事情,所以C#不提供释放资源的函数,一切由垃圾回收来做。
AppDomain.Unload(ad);
obj = null;
Console.ReadLine();
}
}
class ProxyObject : MarshalByRefObject
{

visual studio loadlibrary用法

visual studio loadlibrary用法

visual studio loadlibrary用法Visual Studio是一款广泛应用于软件开发的集成开发环境(IDE)。

其中一个重要的功能是LoadLibrary,它是一个用于在程序运行时动态加载DLL(动态链接库)的函数。

1. 什么是LoadLibrary函数?LoadLibrary是Windows操作系统提供的一个函数,其目的是在程序运行时动态加载DLL文件并返回DLL的句柄(Handle)。

通过LoadLibrary函数,开发者可以在程序运行时选择性地加载DLL,以增强程序的功能和灵活性。

2. LoadLibrary函数的语法LoadLibrary函数的语法如下:HMODULE LoadLibrary(LPCWSTR lpLibFileName);其中,lpLibFileName参数是指向DLL文件路径的指针,函数返回一个HMODULE类型的句柄,表示已加载的DLL。

3. 使用LoadLibrary函数加载DLL使用Visual Studio的LoadLibrary函数加载DLL文件非常简单。

首先,将目标DLL文件放置在项目文件夹中(或者指定其他绝对路径)。

然后,在需要加载DLL的地方调用LoadLibrary函数,并传入DLL文件的路径作为参数。

下面是一个示例代码:```c++#include <iostream>#include <Windows.h>int main() {HMODULE hDll = LoadLibrary(L"example.dll");if (hDll != nullptr) {std::cout << "DLL加载成功!" << std::endl;// 使用加载的DLL执行其他操作// ...// 使用完毕后,记得释放DLLFreeLibrary(hDll);} else {std::cout << "DLL加载失败!" << std::endl;}return 0;}```在上述示例中,通过LoadLibrary函数加载了一个名为"example.dll"的DLL文件。

C#动态加载dll扩展系统功能的方法

C#动态加载dll扩展系统功能的方法

C#动态加载dll扩展系统功能的⽅法本⽂实例讲述了C#动态加载dll扩展系统功能的⽅法。

分享给⼤家供⼤家参考。

具体分析如下:动态加载dll,主要是为了扩展功能,增强灵活性⽽实现的。

主要通过xml配置,来获取所有要动态加载的dll,然后通过反射机制来调⽤dll中的类及其⽅法。

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Reflection;using System.Text;using System.Threading.Tasks;namespace DynamicLoadDLL{/// <summary>/// 动态加载dll/// </summary>public class LoadDLL{private Assembly ass = null;/// <summary>/// 加载dll/// </summary>/// <param name="dllPath">dll⽂件路径</param>public LoadDLL(string dllPath){this.ass = Assembly.LoadFrom(dllPath);//利⽤dll的路径加载(fullname)}/// <summary>/// 返回反射的dll/// </summary>/// <returns></returns>public Assembly GetAssembly(){return this.ass;}/// <summary>/// 获取所有类名/// </summary>/// <returns></returns>public Type[] GetClass(){return ass.GetTypes();}/// <summary>/// 获取程序集下的所有⽂件名/// </summary>/// <returns></returns>public Module[] GetModules(){return ass.GetModules();}/// <summary>/// 获取程序集清单⽂件表中的⽂件/// </summary>/// <returns></returns>public FileStream[] GetFiles(){return ass.GetFiles();}}}这个是加载dll的,然后返回⼀个Assembly类型的⼀个反射值,如果该dll中有多个命名空间和类的话,就只⽤⼀个Assembly类型的⼀个反射值即可以完成调⽤,否则每次⽣成⼀个类,都需要反射⼀次。

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

动态加载不需要再在程序中用生成dll的.h文件如:#include "linkdll.h"而是通过用句柄取地址的方式读取dll中的内容在测试程序中,动态加载dll的方法如下:(粉色标注的是三个大步骤)1.写头文件#include<stdio.h>#include<windows.h>2.宏定义函数指针类型typedef函数类型(*函数指针名)(参数类型参数名);typedef int(*pMax)(int a,int b);//定义了一个int型的函数指针,并指明这个函数指针的参数及参数类型typedef char*(*pStringcat)(char*pstr1,char*pstr2);//这里可能不对3.声明一个句柄Win32处理语句句柄名;HINSTANCE hDll;//HINSTANCE是win32的关键字hDll是句柄的名字4用函数指针类型声明一个函数名字(写在函数体内)void main(void){函数指针类型测试程序中用的函数名字;pMax DMax;//用函数指针类型定义一个函数pMax相当于一个类型,DMax是在下面程序中将要用到的自己定义的函数的名字5.通过句柄hDll加载linkdll.dllhDll=LoadLibrary("linkdll.dll");6.判断句柄是否指向不能用的内存,如果不是则通过句柄取函数地址if(hDll!=NULL)(不要忘记判断){DMax=(pMax)GetProcAddress(hDll,"Max");//dMax是一个PMax的一个变量pMax是一个函数指针类型(pMax)相当于类型强制转换取hDLL加载出来的Linkdll.dll的函数中定义的Max()地址给DMax,这样DMax就和Max()有了一样的功能}7.开始写测试程序//最大数if(DMax!=NULL){int a,b;int max;printf("从键盘输入两个数\n");printf("第一个数:\n");scanf("%d",&a);printf("第二个数:\n");scanf("%d",&b);max=DMax(a,b);printf("最大数为:%d\n",max);}8.释放句柄FreeLibrary(hDll);}示例程序1:Dll程序:#include<stdio.h>#include<string.h>#include"linkdll.h"int Max(int x,int y){int z;z=x>y?x:y;return z;}int Add(int x,int y){int z;z=x+y;return z;}char*Stringcat(char*pstr1,char*pstr2) {pstr1=strcat(pstr1,pstr2);return(pstr1);}动态加载dll的测试程序#include<stdio.h>#include<windows.h>#include"linkdll.h"typedef int(*pMax)(int a,int b);//宏定义函数指针类型typedef int(*pAdd)(int a,int b);typedef char*(*pStringcat)(char*pstr1,char*pstr2);void main(void){HINSTANCE hDll;//句柄pMax DMax;//用函数指针类型定义一个函数pAdd DAdd;pStringcat DStringcat;hDll=LoadLibrary("linkdll.dll");if(hDll!=NULL){DMax=(pMax)GetProcAddress(hDll,"Max");//dMax是一个PMax的一个变量pMax是一个函数指针类型(pMax)相当于类型强制转换//取hDLL加载出来的Linkdll.dll的函数中定义的Max()地址给DMax,这样DMax就和Max()有了一样的功能DAdd=(pAdd)GetProcAddress(hDll,"Add");DStringcat=(pStringcat)GetProcAddress(hDll, "*Stringcat");}//最大数if(DMax!=NULL&&DAdd!=NULL){int a,b;int max;printf("从键盘输入两个数\n");printf("第一个数:\n");scanf("%d",&a);printf("第二个数:\n");scanf("%d",&b);max=DMax(a,b);printf("最大数为:%d\n",max); //相加int sum;sum=DAdd(a,b);printf("两数和为:%d\n",sum);}//分配内存if(DStringcat!=NULL){char*pstr1=(char*)malloc(200);char*pstr2=(char*)malloc(100);if((pstr1==NULL)||(pstr2==NULL)){printf("分配内存失败!\n");return;}else{memset(pstr1,0,200);memset(pstr2,0,100);}//char str[100]={0};//拼接字符串printf("输入两个字符串:");scanf("%s%s",pstr1,pstr2);printf("%s\n",DStringcat(pstr1,pstr2)); //释放内存if(pstr1!=NULL&&pstr2!=NULL) {free(pstr1);pstr1=NULL;free(pstr2);pstr2=NULL;}}FreeLibrary(hDll);}示例程序2:给定ReadAndWriteKey.dll文件及说明文档编写测试程序北京市规划委员会Dll接口说明1.DWORD GetCardCount()函数功能:获取智能卡设备数量(只支持飞天3K智能卡).参数:空返回值:成功返回智能卡设备数量,失败返回111,错误码通过调用GetTheLastError()函数获得。

//8bit=1byte。

2个字节就是1个Word(1个字,16位),DWORD (Double Word)就是双字的意思,两个字(32位)。

2.BOOL OpenCardByIndex(DWORD dwIndex)函数功能:打开指定索引号的智能卡(智能卡索引号从0开始)。

参数:[in]dwIndex:要打开的智能卡索引号//头文件中OpenCardByIndex(DWORD dwIndex);返回值:成功返回TRUE,失败返回FALSE.错误码通过调用GetTheLastError()函数获得。

备注:此函数一般先调用GetCardCount()获取智能卡数量后,再打开指定索引号的智能卡。

在这里也支持直接调用,打开存在索引号的智能卡。

3.BOOLGetkeySeriealNumber(UCHAR*pSeriealNumber,ULONG*pSeriealNum berLen)函数功能:获取打开的智能卡的硬件介质序列号参数:[out]pSeriealNumber:获取的硬件介质序列号[out]pSeriealNumberLen:获取的硬件介质序列号长度返回值:成功返回TRUE,失败返回FALSE.错误码通过调用GetTheLastError()函数获得备注:此函数是在打开某个智能卡之后,故在此之前要保证调用了OpenCardByIndex函数打开了要操作的智能卡。

通过获取智能卡序列号可以来区分要操作的智能卡。

4.BOOL WriteGWFileContent(UCHAR*pWriteData,ULONG ulWriteDataLen)参数功能:向打开的智能卡中写入数据参数:[in]pWriteData:待写入智能卡的数据[in]ulWriteDataLen:待写入智能卡的数据长度返回值:成功返回TRUE,失败返回FALSE.错误码通过调用GetTheLastError()函数获得备注:1)数据长度不能超过1000字节2)此函数是在打开某个智能卡之后,故在此之前也要保证调用了OpenCardByIndex函数打开了要操作的智能卡5.BOOL ReadGWFileContent(UCHAR*pReadData,ULONG *pReadDataLen)函数功能:读取打开的智能卡中曾经写入的数据参数:[out]pReadData:读取出的数据[out]pReadDataLen:读取出的数据长度返回值:成功返回TRUE,失败返回FALSE.错误码通过调用GetTheLastError()函数获得备注:此函数是在打开某个智能卡之后,故在此之前也要保证调用了OpenCardByIndex函数打开了要操作的智能卡6.BOOL CloseCard()函数功能:关闭打开的智能卡参数:空返回值:成功返回TRUE,失败返回FALSE.错误码通过调用GetTheLastError()函数获得7.int GetTheLastError()函数功能:获取错误码参数:空返回值:错误码测试程序:#include<stdio.h>#include<string.h>#include<malloc.h>#include<windows.h>typedef int(*pGetCardCount)(void);//宏定义函数指针类型typedef BOOL(*pOpenCardByIndex)(DWORD dwIndex);typedef BOOL(*pGetkeySeriealNumber)(UCHAR *pSeriealNumber,ULONG*pSeriealNumberLen);typedef BOOL(*pWriteGWFileContent)(UCHAR*pWriteData,ULONG ulWriteDataLen);typedef BOOL(*pReadGWFileContent)(UCHAR*pReadData,ULONG *pReadDataLen);typedef BOOL(*pCloseCard)(void);typedef int(*pGetTheLastError)(void);void main(){HINSTANCE hDll;//句柄pGetCardCount GetCardCount;//用函数指针类型定义一个函数pOpenCardByIndex OpenCardByIndex;pGetkeySeriealNumber GetkeySeriealNumber;pWriteGWFileContent WriteGWFileContent;pReadGWFileContent ReadGWFileContent;pCloseCard CloseCard;pGetTheLastError GetTheLastError;hDll=LoadLibrary("ReadAndWriteKey.dll");if(hDll!=NULL){GetCardCount=(pGetCardCount)GetProcAddress(hDll, "GetCardCount");OpenCardByIndex=(pOpenCardByIndex)GetProcAddress(hDll, "OpenCardByIndex");GetkeySeriealNumber= (pGetkeySeriealNumber)GetProcAddress(hDll,"GetkeySeriealNumber");WriteGWFileContent= (pWriteGWFileContent)GetProcAddress(hDll, "WriteGWFileContent");ReadGWFileContent= (pReadGWFileContent)GetProcAddress(hDll, "ReadGWFileContent");CloseCard=(pCloseCard)GetProcAddress(hDll, "CloseCard");GetTheLastError=(pGetTheLastError)GetProcAddress(hDll, "GetTheLastError");}//输出USBKEY数量int usbcount=GetCardCount();if(usbcount==111){printf("获取数量失败,错误码:%d",GetTheLastError());return;}else{printf("智能卡数量:%d",usbcount);printf("\n");}//打开指定索引号的智能卡unsigned long dwIndex=0;printf("输入USBKey的索引号,索引号从0开始:");scanf("%u",&dwIndex);BOOL res1=OpenCardByIndex(dwIndex);if(!res1){printf("失败,错误码:%d",GetTheLastError());return;}else{printf("打开成功\n");}//分配内存unsigned char*pSeriealNumber=(unsigned char*)malloc(32);unsigned long SeriealNumberLen=0;if(pSeriealNumber==NULL){printf("分配内存失败!\n");return;}else{memset(pSeriealNumber,0,32);}//获取打开的智能卡的硬件介质序列号BOOL res2 =GetkeySeriealNumber(pSeriealNumber,&SeriealNumberLen);if(!res2)//pSeriealNumber指针直接就是序列号?{printf("获取硬件介质序列号失败:%d\n",GetTheLastError());return;}else{printf("智能卡序列号为:%s\n",pSeriealNumber);printf("智能卡序列号长度为:%d\n",SeriealNumberLen);}//释放内存if(pSeriealNumber!=NULL){free(pSeriealNumber);pSeriealNumber=NULL;}//向智能卡中写入数据unsigned char WriteData[100]={0};unsigned long ulWriteDataLen=0;printf("请向智能卡中输入数据:");scanf("%s",WriteData);printf("输入数据的长度为:");scanf("%d",&ulWriteDataLen);BOOL res3=WriteGWFileContent(WriteData,ulWriteDataLen);if(!res3){printf("数据写入失败!%d\n",GetTheLastError());return;}else{printf("数据写入成功!\n");}/*自动计算字符串长度unsigned char writedata[100]={0};unsigned long writedatalen=0;printf("please input string writedata:");scanf("%s",writedata);printf("please input writedatalen:");if(WriteGWFileContent(writedata,strlen((char *)writedata))==0){printf("数据写入失败!%d\n",GetTheLastError());return;}else{printf("数据写入成功!\n");}*///分配内存unsigned char*pReadData=(unsigned char*)malloc(1000*sizeof(unsigned char));;unsigned long pReadDataLen=0;if(pReadData==NULL){printf("分配内存失败!\n");return;}else{memset(pReadData,0,1000*sizeof(unsigned char));}//读出智能卡中数据BOOL res4=ReadGWFileContent(pReadData, &pReadDataLen);if(!res4){printf("数据读取失败,失败码:%d\n",GetTheLastError());return;}else{printf("读出的数据为:%s\n",pReadData);printf("读出的数据长度为:%d\n",pReadDataLen);}//释放内存if(pReadData!=NULL){free(pReadData);pReadData=NULL;}//关闭智能卡if(CloseCard()==0){printf("关闭智能卡失败!%d\n",GetTheLastError());return;}else{printf("成功关闭智能卡!\n");}FreeLibrary(hDll);}。

相关文档
最新文档