第一周报告:初识DLL及API函数
目录
1.对DLL的了解... 2
2.对API的了解... 2
3.选择语言... 3
4.用C#调用API函数... 3
1)用C#调用DLL的一般方法... 4
2) C#动态调用DLL. 4
5.关于调用非系统中的DLL是的路径的小总结... 4
6.查看API函数的方法及其声明原型的方法:... 5
1)DOS下查看... 5
2)利用VC6.0中的工具DEPENDS.EXE查看... 5
3)利用Visual Studio 2005中的MSDN.. 5
7.实践的小项目... 6
总结:... 6
通过一周查资料学习,对DLL和API有了初步的了解。下面以报告的形式做总结回顾(引用的话用蓝色标注)。
关键词:DLL(动态链接库)、API(应用程序编程接口)
DLL(Dynamic Link Library)动态链接库,它不能直接运行,只是一个独立文件,里面含有能被其他程序调用的函数。系统盘的WINDOWS文件夹下有很多系统自带的DLL。“Windows就是将一些主要的系统功能以DLL模块的形式实现”。另外DLL也可作为产品,由开发人员自己编写。比如我们如果使用照相机拍流动的细胞,要通过USB接口控制相机,那么就要调用与该相机配套的DLL文件中的函数。大多数的DLL都是用C或C++,编写的,通过查资料发现也可以用C#编写。
下面列出了当程序使用 DLL 时提供的一些优点:
1) 使用较少的资源
当多个程序使用同一个函数库时,DLL 可以减少在磁盘和物理内存中加载的代码的重复量。这不仅可以大大影响在前台运行的程序,而且可以大大影响其他在 Windows 操作系统上运行的程序。
2) 推广模块式体系结构
DLL 有助于促进模块式程序的开发。这可以帮助您开发要求提供多个语言版本的大型程序或要求具有模块式体系结构的程序。模块式程序的一个示例是具有多个可以在运行时动态加载的模块的计帐程序。
3) 简化部署和安装
当 DLL 中的函数需要更新或修复时,部署和安装 DLL 不要求重新建立程序与该 DLL 的链接。此外,如果多个程序使用同一个 DLL,那么多个程序都将从该更新或修复中获益。当您使用定期更新或修复的第三方 DLL 时,此问题可能会更频繁地出现。
”
API(Application Programming Interface)应用程序编程接口,这个
是通过程序调用DLL中的API函数实现对底层的控制。API函数主要在“kernel32.dll”、“user32.dll”、“GDI32.dll”这三个DLL文件中,它们在C:\WINDOWS\system32目录下。
张老师用的是VB语言,C和C++也可以。我之前大学用的最多的.NET下的C#,通过查资料知道C#语言也可以用调用API函数。
上网查了一下有什么区别:
“(SDK)软件开发包通常是一系列API函数,而MFC 是由微软公司提供的对API封装后的类库,因此从这个意义上可以说MFC是SDK的封装。另外,mfc中封装了一套消息处理流程,将sdk中API全部做了封装,使得开发起来速度加快,而sdk是最底层的函数库,mfc对它进行了封装。 ”
“SDK是基于C语言的,而MFC是基于C++的,这是最根本的区别。”
而.NET具有的是CLR(公共语言运行库),它的P/Invoke(互操作平台)可以完成调用函数的调用。给出的原理图如下:
这里非托管的概念就是用非.NET语言编写的代码,如C和C++等为非托管代码,利用.NET中的C#语言调用C或C++编写的非托管的DLL就要用到互操作平台调用技术。
“一般来说,在NET 平台下,使用Vi sual Basic .NET 和C#描写生成的代码都是托管代码, 而使用Visual C++ .NET 描写代码时,则可以根据自己的需要使用托管代码或非托管代码. 另外, 使用Vi sual Basic 6 或Visual C++ 6 等创建的代码、Win 32DLL 且由C/C++创建的DLL都属于非托管代码的范畴。”
目前,我了解到的是两种常用方式,还有别的方式还需要在日后继续深入学习
引入命名空间System.Runtime.Interop
[DlllImport(“DLL文件”)]
修饰符 extern 返回变量类型 方法名称 (参数列表)
就是首先新建一个动态链接DLL的类,如命名为dld.cs(dynamic link dll)
在这里面利用[DllImport(“DLL文件”)]来导入kernel32.dll,以调用它下面的LoadLibrary、GetProcAddress、FreeLibrary。查MSDN了解了三个函数的原型为:
HMODULE LoadLibrary(LPCTSTR lpFileName);
FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
BOOL FreeLibrary(HMODULE hModule);
LoadLibrary需要的参数为要调用的DLL文件的名字,而它的返回值为这个DLL文件的句柄;
GetProcAddress需要的参数一个为要调用的DLL的句柄,这个值
由LoadLibrary的返回值提供,另一个参数为要调用该DLL文件中函数的名字。它的返回值为函数的指针;
FreeLibrary需要的参数为调用的函数DLL文件的句柄,返回值为布尔型。
当我调用常用的kernel32.dll、user32.dll时不用考虑路径问题,而当我要调用外部的一个dll时候,却不知道怎么找到。通过上网,了解了程序运行过程中的顺序,得到了调用系统dll的几种方法,并做了小结。
“DllImport会按照顺序自动去寻找的地方: 1、exe所在目录 2、System32目录 3、环境变量目录”
总结的解决办法为:
a.将该DLL文件放到Visual Studio项目的bin\debug文件夹下面
b.将其放在C:\WINDOWS\SYSTEM32下面
c.使用其绝对路径[DllImport(@"F:\newStart\theDLL\Debug\theDLL.dll")]
PS:我觉得第一种方法最好,因为方法简便,而且,程序也是从这里首先开始查找的。
首先,运行Visual Studio 2005\Visual Studio Tools\Visual Studio 2005命令提示符
然后,运行dumpbin.exe/exports dllName 命令即可看到此DLL所导出函数的信息.
例如. user32.dll
dumpbin . exe/exports user32.dll
PS:由于此DLL 包含的函数众多, 在控制台上查看并不是太方便,因此可以将结果输出到文件中,以方便查看.
dumpbin.exe/exports user32.dll > d : uer32dllFunctionList.txt
若查看某个文件夹下的DLL 如:
dumpbin.exe/exports F:\newStart\theDLL\Debug\theDLL.dll
该执行文件的位置在:
C++安装软件包\C++\VS6\COMMON\TOOLS\DEPENDS.EXE
使用方法:执行文件->打开要查看的dll即可看到该DLL文件中函数的名字(Function)、入口(Entry Point)及其他一些信息
API函数的具体介绍放在的路径为:根目录->Win32和COM开发->Development Guides->Windows API->Windows API Reference下,可以按照功能类别或函数首字母方式进行查询。
1) 完全按照网上的代码编写了一个获取Windows及系统路径、系统时间、内存信息、CPU信息。
小结:代码不是很懂,但是基本了解了C#如何调用DLL函数
2) .NET Framework自己封装了部分常用的API函数,尝试用C#自己方法替换了一个之前调用的一个API函数。得到相同的效果。
小结:明白有些方法,不用非得调用API函数,网上也有很多人不建议在有相应封装好的函数的情况下调用API函数,这样开发工具的封装就没意义了,而且直接调用API函数不安全,对我们的开发效率也有影响。
3) 按照网上的步骤先用C++编写了一个里面只含有一个实现加法功能的函数的DLL文件,然后又用C#调用这个DLL下的函数完成一个控制台应用程序。
小结:熟悉调用DLL中函数的同时,对DLL文件的产生有了一些了解。
4) 按照网上的步骤,编写一个每调用一次就加一的函数的DLL文件。用C#语言采用一般调用法和动态调用法调用该DLL。实现每点击一次按钮窗口提示点击次数。
小结:一般调用法中,用一个按钮,每次点击按钮都会加一,除非关闭程序重新运行才重新开始计数。说明这个函数是全局的、静态的。
采用动态调用的方式,有三个按钮,分别调用了LoadLibrary、GetProcAddress、FreeLibrary三个API函数对自己编写的DLL文件进行加载、获得函数指针以及释放。这样,只要释放后再重新加载这个DLL就可以重新计数,而不用关闭程序。
这是工作的第一周,感觉特别充实,每天都会有进步,但是感觉自己的进步还是很慢。感觉这周对知识的掌握上是宽度的,因为很多概念都是很陌生的,需要查很多旁的知识,也算打基础吧,根基稳固了以后才不会费劲。这周没有自己独立完成一个程序代码的编写,主要都是根据网上的指导操作的,下周希望自己能够通过查MSDN练习编写一些程序。这周主要是接受新事物,自己的思考还很少,以后要多多思考。上面自己的认识,不一定准确,希望老师们帮忙指正。还有谢谢老师们的鼓励与指导和师兄的帮助。自己很幸运。加油!