版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Windows核心编程和运行程序动态链接库它们扩展了应用程序的特性。它们可以用许多种编程语言来编写。它们简化了软件项目的管理。它们有助于节省内存。它们有助于资源的共享。它们有助于应用程序的本地化。它们有助于解决平台差异。它们可以用于一些特殊的目的。创建创建D L L常常比创建应用程序更容易,因为D L L往往包含一组应用程序可以使用的自主函数。在D L L中通常没有用来处理消息循环或创建窗口的支持代码。D L L只是一组源代码模块,每个模块包含了应用程序(可执行文件)或另一个D L L将要调用的一组函数。当所有源代码文件编译后,它们就像应用程序的可执行文件那样被链接程序所链接。但是,对于一个D
2、 L L来说,你必须设定该连链程序的/ D L L开关。这个开关使得链接程序能够向产生的D L L文件映像发出稍有不同的信息,这样,操作系统加载程序就能将该文件映像视为一个D L L而不是应用程序。内存管理内存管理创建若要创建D L L模块,必须执行下列操作步骤:1) 首先必须创建一个头文件,它包含你想要从D L L输出的函数原型、结构和符号。D L L的所有源代码模块均包含该头文件,以帮助创建D L L。后面将会看到,当创建需要使用D L L中包含的函数和变量的可执行模块(或多个模块)时,也需要这个头文件。2) 要创建一个C / C + +源代码模块(或多个模块),用于实现你想要在D L L
3、模块中实现的函数和变量。由于这些源代码模块在创建可执行模块时是不必要的,因此创建D L L的公司能够保护公司的秘密创建3) 创建D L L模块,将使编译器对每个源代码模块进行处理,产生一个. o b j模块(每个源代码模块有一个. o b j模块)。4) 当所有的. o b j模块创建完成后,链接程序将所有. o b j模块的内容组合在一起,产生一个D L L映象文件。该映像文件(即模块)包含了用于D L L的所有二进制代码和全局/静态数据变量。为了执行这个可执行模块,该文件是必不可少的。5) 如果链接程序发现D L L的源代码模块至少输出了一个函数或变量,那么链接程序也生成一个. l i b
4、文件。这个. l i b文件很小,因为它不包含任何函数或变量。它只是列出所有已输出函数和变量的符号名。为了创建可执行模块,该文件是必不可少的。一旦创建了D L L模块,就可以创建可执行模块。其创建步骤是:6) 在引用函数、变量、数据、结构或符号的所有源代码模块中,必须包含D L L开发人员创建的头文件。7) 要创建一个C / C + +源代码模块(或多个模块),用于实现你想要在可执行模块中实现的函数和变量。当然该代码可以引用D L L头文件中定义的函数和变量。创建8) 创建可执行模块,将使编译器对每个源代码模块进行处理,生成一个. o b j模块(每个源代码模块有一个. o b j模块)。9)
5、 当所有. o b j模块创建完成后,链接程序便将所有的. o b j模块的内容组合起来,生成一个可执行的映像文件。该映像文件(或模块)包含了可执行文件的所有二进制代码和全局/静态变量。该可执行模块还包含一个输入节,列出可执行文件需要的所有D L L模块名(关于各个节的详细说明,参见第1 7章)。此外,对于列出的每个D L L名字,该节指明了可执行模块的二进制代码引用了哪些函数和变量符号。下面你会看到操作系统的加载程序将对该输入节进行分析。一旦D L L和可执行模块创建完成,一个进程就可以执行。当试图运行可执行模块时,操作系统的加载程序将执行下面的操作步骤:10) 加载程序为新进程创建一个虚拟
6、地址空间。可执行模块被映射到新进程的地址空间。加载程序对可执行模块的输入节进行分析。对于该节中列出的每个D L L名字,加载程序要找出用户系统上的D L L模块,再将该D L L映射到进程的地址空间。注意,由于D L L模块可以从另一个D L L模块输入函数和变量,因此D L L模块可以拥有它自己的输入节。若要对进程进行全面的初始化,加载程序要分析每个模块的输入节,并将所有需要的D L L模块映射到进程的地址空间。导出文件当创建D L L模块时,首先应该建立一个头文件,该文件包含了你想要输出的变量(类型和名字)和函数(原型和名字)。输入当输入一个符号时,不必使用关键字- -d e c l s
7、p e c ( d l l i m p o r t ),只要使用标准的C关键字e x t e r n即可。但是,如果编译器预先知道你引用的符号将从一个D L L的. l i b文件输入,那么编译器就能够生成运行效率稍高的代码。因此建议你尽量将- - d e c l s p e c ( d l l i m p o r t )关键字用于输入函数和数据符号。当你调用标准Wi n d o w s函数中的任何一个时,M i c r o s o f t将为你进行这项设置。运行可执行模块当一个可执行文件被启动时,操作系统加载程序将为该进程创建虚拟地址空间。然后,加载程序将可执行模块映射到进程的地址空间中。加
8、载程序查看可执行模块的输入节,并设法找出任何需要的D L L,并将它们映射到进程的地址空间中。由于该输入节只包含一个D L L名而没有它的路径名。因此加载程序必须搜索用户的磁盘驱动器,找出D L L。下面是加载程序的搜索顺序:1) 包含可执行映像文件的目录。2) 进程的当前目录。3) Wi n d o w s系统目录。4) Wi n d o w s目录。5) PAT H环境变量中列出的各个目录。缺少DLL出错提示创建DLL创建DLL:1) 建立带有输出原型/结构/符号的头文件。2) 建立实现输出函数/变量的C/C+源文件。3) 编译器为每个C/C+源文件生成.obj模块。4) 链接程序将生成D
9、LL的.obj模块链接起来。5) 如果至少输出一个函数/变量,那么链接程序也生成.lib 文件。创建EXE创建EXE:6) 建立带有输入原型/结构/符号的头文件(视情况而定)。7) 建立不引用输入函数/变量的C/C+源文件。8) 编译器为每个C/C+源文件生成.obj源文件。9) 链接程序将各个.obj模块链接起来,生成.exe文件。注: DLL的lib文件是不需要的,因为并不直接引用输出符号。.exe 文件不包含输入表。运行应用程序运行应用程序:10) 加载程序为.exe 创建模块地址空进程的主线程开始执行;应用程序启动运行。显式加载DLL:11) 一个线程调用LoadLibrary (Ex
10、)函数,将DLL加载到进程的地址空间这时线程可以调用GetProcAddress以便间接引用DLL的输出符号。DLL模块的显式加载和符号链接如果线程需要调用D L L模块中的函数,那么D L L的文件映像必须映射到调用线程的进程地址。可以用两种方法进行这项操作。第一种方法是让应用程序的源代码只引用D L L中包含的符号。这样,当应用程序启动运行时,加载程序就能够隐含加载(和链接)需要的D L L。第二种方法是在应用程序运行时让应用程序显式加载需要的D L L并且显式链接到需要的输出符号。显式加载D L L模块HMODULE LoadLibrary( LPCTSTR lpFileName );
11、HMODULE LoadLibraryEx( LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags ); 显式卸载D L L模块BOOL FreeLibrary( HMODULE hModule ); void FreeLibraryAndExitThread( HMODULE hModule, DWORD dwExitCode ); 显式链接到一个输出符号FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName ); DLL的进入点函数通知DLL_PROCESS_AT TA C H通知DLL
12、_PROCESS_DETA C H通知DLL_THREAD_AT TA C H通知DLL_THREAD_DETA C H通知延迟加载D L L如果你的应用程序使用若干个D L L,那么它的初始化时间就比较长,因为加载程序要将所有需要的D L L映射到进程的地址空间中。解决这个问题的方法之一是在进程运行的时候分开加载各个D L L。延迟加载的D L L能够更容易地完成这样的加载。 如果调用代码中的一个新函数,然后试图在老版本的系统上运行你的应用程序,而该系统中没有该函数,那么加载程序就会报告一个错误,并且不允许该应用程序运行。你需要一种方法让你的应用程序运行,然后,如果(在运行时)发现该应用程序
13、在老的系统上运行,那么你将不调用遗漏的函数。例如,一个应用程序在Windows 2000上运行时想要使用P S A P I函数,而在Windows 98上运行想要使用To o l H e l p函数(比如P r o c e s s 3 2 N e x t)。当该应用程序初始化时,它调用G e t Ve r s i o n E x函数来确定主操作系统,并正确地调用相应的其他函数。如果试图在Windows 98上运行该应用程序,就会导致加载程序显示一条错误消息,因为Windows 98上并不存在P S A P I . d l l模块。同样,延迟加载的D L L能够使你非常容易地解决这个问题。延迟加
14、载D L L 从可执行模块的输入节中删除M y D l l . d l l,这样,当进程被初始化时,操作系统的加载程序就不会显式加载D L L。 将新的Delay Import(延迟输入)节(称为. d i d a t a)嵌入可执行模块,以指明哪些函数正在从M y D l l . d l l输入。 通过转移到对- - d e l a y L o a d H e l p e r函数的调用,转换到对延迟加载函数的调用。函数转发器函数转发器是D L L的输出节中的一个项目,用于将对一个函数的调用转至另一个D L L中的另一个函数。函数转发器如果调用下面的函数,G e t P r o c A d d
15、 r e s s就会查看K e r n e l 3 2的输出节,发现H e a p A l l o c是个转发函数,然后按递归方式调用G e t P r o c A d d r e s s函数,查找N T D L L . d l l的输出节中的R t l A l -l o c a t e H e a p。已知的D L L操作系统提供的某些D L L得到了特殊的处理。这些D L L称为已知的D L L。它们与其他D L L基本相同,但是操作系统总是在同一个目录中查找它们,以便对它们进行加载操作。已知的D L L关键字包含一组值的名字,这些名字是某些D L L的名字。每个值名字都有一个数据值,该值
16、恰好与带有. d l l文件扩展名的值名字相同(不过,情况并非完全如此,我将在下面的例子中加以说明)。当L o a d L i b r a r y或L o a d L i b r a r y E x被调用时,这些函数首先查看是否传递了包含. d l l扩展名的D L L名字。如果没有传递,那么它们将使用通常的搜索规则来搜索D L L。如果确实设定了. d l l扩展名,那么这些函数将删除扩展名,然后搜索注册表关键字K n o w n D L L,以便确定它是否包含匹配的值名字。如果没有找到匹配的名字,便使用通常的搜索规则。但是,如果找到了匹配的值名字,系统将查找相关的值数据,并设法使用值数据来
17、加载D L L。系统也开始在注册表中的D l l D i r e c t o r y值数据指明的目录中搜索D L L。按照默认设置,Windows 2000上的D l l D i r e c t o r y值的数据是% S y s t e m R o o t % S y s t e m 3 2。例子DLL转移因此Wi n d o w s在设计时总是尽可能多地安排资源的共享,以节省宝贵的存储器资源。为了达到这个目的, M i c r o s o f t建议,多个应用程序共享的任何模块,如C / C + +运行期库和M i c r o s o f t基础类(M F C)D L L等,应该放入Wi
18、n d o w s的系统目录中。这样,系统就能够方便地找到共享文件。M i c r o s o f t给Windows 2000增加了一个D L L转移特性。这个特性能够强制操作系统的加载程序首先从你的应用程序目录中加载文件模块。只有当加载程序无法在应用程序目录中找到该文件时,它才搜索其他目录。为了强制加载程序总是首先查找应用程序的目录,要做的工作就是在应用程序的目录中放入一个文件。该文件的内容可以忽略,但是该文件必须称为A p p N a m e . l o c a l。改变模块的位置每个可执行模块和D L L模块都有一个首选的基地址,用于标识模块应该映射到的进程地址空间中的理想内存地址。当
19、创建一个可执行模块时,链接程序将该模块的首选基地址设置为0 x 0 0 4 0 0 0 0 0。如果是D L L模块,链接程序设置的首选基地址是0 x 1 0 0 0 0 0 0 0。MOV 0 x10014540 5MOV 0 x20014540 5插入D L L:一个例子当你想要为另一个进程创建的窗口建立子类时。当你需要调试帮助时(例如,当你需要确定另一个进程正在使用哪个D L L时)。当你想要挂接其他进程时。使用注册表来插入D L L使用注册表来插入D L L由于系统在初始化时要读取这个关键字的值,因此在修改这个值后必须重新启动你的计算机即使退出后再登录,也不行。当然,如果从这个关键字的
20、值中删除D L L,那么在计算机重新启动之前,系统不会停止对库的映射操作。 你的D L L只会映射到使用U s e r 3 2 . d l l的进程中。所有基于G U I的应用程序均使用U s e r 3 2 . d l ,不过大多数基于C U I的应用程序并不使用它。因此,如果需要将D L L插入编译器或链接程序,这种方法将不起作用。 你的D L L将被映射到每个基于G U I的应用程序中,但是必须将你的库插入一个或几个进程中。你的D L L映射到的进程越多,“容器”进程崩溃的可能性就越大。毕竟在这些进程中运行的线程是在执行你的代码。如果你的代码进入一个无限循环,或者访问的内存不正确,就会影
21、响代码运行时所在进程的行为特性和健壮性。因此,最好将你的库插入尽可能少的进程中。 你的D L L将被映射到每个基于G U I的应用程序中。这与上面的问题相类似。在理想的情况下,你的D L L只应该映射到需要的进程中,同时,它应该以尽可能少的时间映射到这些进程中。假设在用户调用你的应用程序时你想要建立Wo r d P a d的主窗口的子类。在用户调用你的应用程序之前,你的D L L不必映射到Wo r d P a d的地址空间中。如果用户后来决定终止你的应用程序的运行,那么你必须撤消Wo r d P a d的主窗口。在这种情况下,你的D L L将不再需要被插入Wo r d P a d的地址空间。最
22、好是仅在必要时保持D L L的插入状态。使用Wi n d o w s挂钩来插入D L L1) 进程B中的一个线程准备将一条消息发送到一个窗口。2) 系统查看该线程上是否已经安装了W H _ G E T M E S S A G E挂钩。3) 系统查看包含G e t M s g P r o c函数的D L L是否被映射到进程B的地址空间中。4) 如果该D L L尚未被映射,系统将强制该D L L映射到进程B的地址空间,并且将进程B中的D L L映像的自动跟踪计数递增1。使用Wi n d o w s挂钩来插入D L L5) 当D L L的h i n s t D l l用于进程B时,系统查看该函数,并
23、检查该D L L的h i n s t D l l是否与它用于进程A时所处的位置相同。6) 系统将进程B中的D L L映像的自动跟踪计数递增1。7) 系统调用进程B的地址空间中的G e t M s g P r o c函数。8) 当G e t M s g P r o c函数返回时,系统将进程B中的D L L映像的自动跟踪计数递减1。使用远程线程来插入D L LHANDLE CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_
24、ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); 使用远程线程来插入D L L使用远程线程来插入D L L使用远程线程来插入D L L1) 使用Vi r t u a l A l l o c E x函数,分配远程进程的地址空间中的内存。2) 使用Wr i t e P r o c e s s M e m o r y函数,将D L L的路径名拷贝到第一个步骤中已经分配的内存中。3) 使用G e t P r o c A d d r e s s函数,获取L o a d L i b r a r y A或L o a d L i b r a t y W函数的实地址(在K e r n e l 3 2 . d l l中)。4) 使用C r e a t e R e m o t e T h r e a d函数,在远程进程中创建一个线程,它调用正确的L o a d L i b r a r y函数,为它传递第一个步骤中分配的内存的地址。使用远程线程来插入D L L5) 使用Vi r t u a l F r e e E x函数,释放第一个步骤中分配的内存。6) 使用G e t P
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 48230.8-2026混凝土和混凝土结构的环境管理第8部分:环境标志和声明
- 机电一体化综合设计实训教程 课件 第4章-PLC组网与通信
- 饲草种子繁育工技术基础模拟考核试卷含答案
- 单漂流送工岗中技术理论考核试卷含答案
- 炭素成型工岗位安全规程考核试卷含答案
- 2025年工业视觉算法优化技巧
- 2025年职业病防治考试试题附与答案
- 2025年职业资格考试初级养老护理员试题(附答案)
- 2025年中药处方点评试题及答案
- 2025年注册城乡规划师考试(城乡规划实务)题库及答案(广东省)
- 2026年《中国下肢深静脉血栓诊疗临床指南(2026版)》
- 《人类简史》荐书主题演讲课件
- 《机械现代设计方法》课件
- 2024-2025学年广东省深圳市高二上学期11月期中考试数学检测试题(附解析)
- 《标准工时培训资料》课件
- 《管理学》课程思政教学案例
- 《教育学原理》马工程教材第三章-教育与人的发展
- 矿山地质学课件
- 湖州南浔圣船混凝土有限公司年产50万立方米生态混凝土项目环境影响报告
- 团体心理游戏256例
- 专项维修资金使用培训
评论
0/150
提交评论