动态加载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中所有标志为_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,⾸先,我们新建⼀个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原理如下: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的⽅法。
分享给⼤家供⼤家参考。
具体实现⽅法如下:复制代码代码如下: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中所需要做的⼯作 在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中类的⽅法当然,这⾥指的是托管的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);}}}}}}}⼀个不难看懂的代码,先是指定插件⽂件夹的位置,要是没有就创建⼀个。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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);}。