




已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
windows sdk编程系列文章 - 动态链接库2008-04-15 23:10本课中,我们将学习DLLs,它们到底是什么和如何创建它们。理论:如果您编程的时间非常长,就会发现很多的程序之间其实有相当多的重复代码。每编一个程序就重写一遍这些代码既没必要又浪费时间。在DOS时代,一般的做法是把这些重复的代码写成一个个的函数,然后把它们按类别放到不同的库文件中去。当要使用这些函数时,只要把您的目标文件(.obj)文件和先前存放在库文件中的函数进行链接,链接时链接器会从库文件中抽取相关的信息并把它们插入到可执行文件中去。这个过程叫做静态链接。C运行时库就是一个好例子。这样的库的缺点是您在每一个调用库函数的程序中都必须嵌入同一函数的拷贝,这显然很浪费磁盘。在DOS时代毕竟每一时刻仅有一个程序在运行,所以浪费的还只是磁盘而已,在多任务的WINDOWS时代就不仅浪费磁盘,还要浪费宝贵的内存了。在WINDOWS中,由于有多个程序同时运行,如果您的程序非常大的话,那将消耗相当多的内存。WINDOWS的解决办法是:使用动态链接库。动态链接库从表面上看也是一大堆的通用函数,不过即使有多个程序调用了它,在内存中也仅仅只有动态链接库的唯一一份拷贝。WINDOWS是通过分页机制来作到这一点的。当然,库的代码只有一份,但是每一个应用程序要有自己单独的数据段,要么就会乱掉。不象旧时的静态链接库,它并不会把这些函数的可执行代码放入到应用程序中去,而是当程序已经在内存中运行时,如果需要调用该函数时才调入内存也即链接。这也就是为什么把它叫做“动态”的原因所在。另外您还可以动态地卸载动态链接库,当然要求这时没有其它的应用程序在使用它,否则就要一直等到最后一个使用它的函数也不再使用该动态链接库时才能去卸载它。为了正确的调用库和给库函数分配内存空间,在编译和链接应用程序时,必须把重定位等一些消息插入到执行代码中去,以便载入正确的库,并给库函数分配正确的地址。那么这些信息从哪里得到呢?引入库。引入库包含足够的信息,链接器从中抽取足够的信息(注意区别:静态链接库放入的是可执行代码)把它们放入到可执行文件中去。当WINDOWS的加载器装入应用程序查看到有DLL时,它会查找该库文件,如果没有查到,就报错退出,否则就把它映射进进程的地址空间,并修正函数调用语句的地址。 如果没有引入库呢?当然我们也可以调用动态链接库中的任意函数。只不过您必须知道调用的函数是否在库中而且是否在库的引出名字表中,另外还需要知道该函数的参数个数和参数的类型。说到这里,让我想起了一件很有名的事。一书的作者Angel Schudleman 曾经利用此方法来跟踪微软Win3x系统动态链接库中未公开的函数,因为在微软给程序员提供的系统动态链接库的引入库中没有提供这些函数的原型,所以您无法在链接时把这些函数的信息链接到可执行文件中去,而为了某种目的您又要使用这些函数,您就可以在执行时加载动态链接库并得到这些函数的地址,从而和调用其它的库函数一样使用这些未公开的函数。由于这本书的巨大影响,当时许多程序员纷纷在它们的程序中调用未公开函数,甚至在写商业程序时也这么做。这种走偏峰的做法引起了微软的反感,后来微软在它Win3x的改进版中不再把那些未公开函数列入系统动态链接库的引出名字表,这样也就无法再利用这种方法来调用未公开的函数了。 当您让系统的加载器为您加载动态库时,如果不能找到库文件,它就会提示一条“A required .DLL file, xxxxx.dll is missing”,这样您的应用程序就无法运行,即使该库对您的应用程序来说并不重要。 如果您选择在程序运行时自己加载该库,就没有这种问题了。 如果您知道足够的信息,就可以调用系统未公开的函数。 如果您调用LoadLibrary函数加载库,就必须再调用GetProcAddress函数来得到每一个您想调用的函数的地址,GetProcAddress会在动态链接库中查找函数的入口地址。由于多余的步骤,这样您的程序执行起来会慢一点,但是并不明显。 明白了LoadLibrary函数的优缺点,下面我们就来看看如何产生一个动态链接库。下面的代码是一个动态链接库的框架: 例子:见光盘FirstWindow15中的skeleton#include windows.h#include tchar.hTCHAR AppName = _T(DLL Skeleton);TCHAR HelloMsg = _T(Hello, youre calling a function in this DLL);TCHAR LoadMsg = _T(The DLL is loaded);TCHAR UnloadMsg = _T(The DLL is unloaded);TCHAR ThreadCreated = _T(A thread is created in this process);TCHAR ThreadDestroyed = _T(A thread is destroyed in this process);void TestHello() MessageBox(NULL,HelloMsg,AppName,MB_OK);BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) switch(fdwReason) case DLL_PROCESS_ATTACH: MessageBox(NULL,LoadMsg,AppName,MB_OK); break; case DLL_PROCESS_DETACH: MessageBox(NULL,UnloadMsg,AppName,MB_OK); break; case DLL_THREAD_ATTACH: MessageBox(NULL,ThreadCreated,AppName,MB_OK); break; case DLL_THREAD_DETACH: MessageBox(NULL,ThreadDestroyed,AppName,MB_OK); break; return TRUE;- ; skeleton.def;- LIBRARY skeletonEXPORTS TestHello分析:上面是一个动态链接库的框架,每一个DLL必须有一个入口点函数,WINDOWS每一次在做下面的动作时会调用该入口点函数: 当动态链接库被加载时 当动态链接库卸载时 同一进程的线程生成时 同一进程的线程退出时 BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) switch(fdwReason) case DLL_PROCESS_ATTACH: MessageBox(NULL,LoadMsg,AppName,MB_OK); break; case DLL_PROCESS_DETACH: MessageBox(NULL,UnloadMsg,AppName,MB_OK); break; case DLL_THREAD_ATTACH: MessageBox(NULL,ThreadCreated,AppName,MB_OK); break; case DLL_THREAD_DETACH: MessageBox(NULL,ThreadDestroyed,AppName,MB_OK); break; return TRUE;hInstDLL是该动态链接库模块的句柄。它和进程的实例句柄不一样。如果您以后要用,可以保存它,因为以后再要获得它不容易。根据不同的时机,reason传入的值可能是下面的四个值中的一个: DLL_PROCESS_ATTACH 动态链接库第一次插入进程的地址空间时。当传入的参数是该值时,您可以做一些初始化的工作。 DLL_PROCESS_DETACH 动态链接库从进程的地址空间卸出时。您可以在此做一些清理的工作。譬如:释放内存等。 DLL_THREAD_ATTACH 新线程生成。 DLL_THREAD_DETACH 线程销毁。 如果想要库中的代码继续执行,返回TRUE,否则返回FALSE,那样动态链接库就不会加载了。譬如:您想分配一块内存,如果不成功的话就退出,这时您就可以返回FALSE。那样动态链接库就不会加载了。您可以加入的函数,它们的位置并不重要,把它们放在入口点函数的前面或后面都可以。只是如果您想要它们能被其它的程序调用的话,就必须把它们的名字放到模块定义文件(.def)中去。动态链接库在它们自己的编译过程就需要,而不只是提供给其它要引用它的程序参考。他们如下:LIBRARY Skeleton EXPORTS TestHello第一行是必须的。LIBRARY 定义了DLL的模块名称。它必须和动态链接库的名称相同。EXPORTS关键字告诉链接器该DLL的引出函数,也就是其它程序可以调用的函数。举个例子:其它的程序想要调用函数TestHello ,我们就把它放到EXPORTS中。在vc中我们把skeleton.def添加到skeleton工程中,在您编译链接好后,链接器会生成.lib 和.dll文件。前者是引入库,当其它的程序要调用您的动态链接库中的函数时就需要该引入库,以便把必要的信息加入到其可执行文件中去。例如:见光盘usedll1#include windows.hextern void TestHello();#pragma comment(lib,skeleton.lib)int _stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) TestHello(); return 0;接下来我们来看看如何使用LoadLibrary函数来加载一个DLL。例如:见光盘usedll2#include windows.h#include tchar.hTCHAR LibName = _T(skeleton.dll);TCHAR FunctionName = _T(TestHello);TCHAR DllNotFound = _T(Cannot load library);TCHAR AppName = _T(Load Library);TCHAR FunctionNotFound = _T(TestHello function not found);HINSTANCE hLib;typedef void (*pTestHello)();pTestHello TestHelloAddr;int _stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) hLib = LoadLibrary(LibName); if(hLib = NULL) MessageBox(NULL,DllNotFound,AppName,MB_OK); else TestHelloAddr = (pTestHello)GetPr
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025下半年机械行业设备更新科技赋能智能无人装备崛起
- 历史期末专题复习知识点整L2024~2025学年统编版七年级历史下册
- 金融科技企业估值与投资策略在2025年金融科技机器人技术应用报告
- 低碳城市建设的规划与实践:山东案例分析报告2025
- 2025年工业机器人在柔性制造系统中的应用与机器人视觉技术结合报告
- 民办教育机构2025年合规运营与品牌建设创新路径探索报告
- 2025年零售行业私域流量运营的顾客体验提升计划报告
- 新零售环境下便利店智能化库存管理与物流优化报告
- 新能源微电网稳定性控制与优化运行在智能家居中的应用报告
- 海洋生态修复项目可行性分析与2025年政策支持报告
- 污水处理工培训课件
- 2023年职中实习班班主任考核办法
- 生物信息学知到章节答案智慧树2023年华东理工大学
- 特别的人歌词
- 赛龙酒店管理系统操作手册
- 监理规划实施细则审批表
- 2023-2024学年江苏省扬州市小学语文五年级期末评估试卷
- 风场前期相关windpro2中文版帮助文件
- 2023-2024学年江苏省姜堰市小学数学一年级下册期末评估测试题
- YY/T 0316-2003医疗器械 风险管理对医疗器械的应用
- 第四届编校大赛试题及答案(含编辑、校对)
评论
0/150
提交评论