友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

VC语言6.0程序设计从入门到精通-第72章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!






               。。。。。。。  



          case DLL_PROCESS_DETACH:  



               。。。。。。。  



          }  



          return TRUE;  



     }  



     注意:函数名 DllMain 是区分大小写的。许多编程人员有时调用的函数是 DLLMain 。这是一个非 



            常容易犯的错误,因为  DLL              这个词常常使用大写来表示。如果调用的进入点函数不是 



            DllMain ,而是别的函数,代码将能够编译和链接,但是其进入点函数永远不会被调用, 



            DLL 永远不会被初始化。  



     参数 hinstDll 包含了 DLL  的实例句柄。与(w)WinMain 函数的 hinstExe 参数一样,这个 

值用于标识 DLL 的文件映像被映射到进程的地址空间中的虚拟内存地址。通常将这个参数保 



                                                                                               ·253 ·  


…………………………………………………………Page 265……………………………………………………………

Visual C++ 6。0 程序设计从入门到精通  



存在一个全局变量中,这样就可以在调用加载资源函数(如 DialogBox  和 LoadString )时使 

用它。最后一个参数是 fImpLoad,如果 DLL 是隐含加载的,那么该参数将是个非 0 值,如 

果 DLL 是显式加载的,那么它的值是 0 。  

   参 数   fdwReason 用 于 指 明 系 统 为 什 么 调 用 该 函 数 。 该 参 数 可 以 使 用 

DLL_PROCESS_ATTACH  ( 进 程 被 调 用 )、DLL_THREAD_ATTACH  ( 线 程 被 调 用 )、 

DLL_PROCESS_DETACH  (进程被停止)、DLL_THREAD_DETACH  (线程被停止)4 个值的 

其中之一,lpReserved 为保留参数。下面就具体介绍这 4 个值的意义。  



    1.DLL_PROCESS_ATTACH 通知  



    当 DLL 被初次映射到进程的地址空间中时,系统将调用该 DLL 的 DllMain() 函数,给它 

传递参数 fdwReason 的值 DLL_PROCESS_ATTACH 。只有当 DLL 的文件映像初次被映射时, 

才 会 出现 这种 情 况。 如果 线 程在 后来 为 已经 映射 到 进程 的地 址 空间 中的          DLL 调用 

LoadLibrary(Ex) 函 数 , 那 么 操 作 系 统 只 是 递 增 DLL 的 使 用 计 数 , 它 不 会 再 次 用 

DLL_PROCESS_ATTACH 的值来调用 DLL 的 DllMain() 函数。  

    当处理 DLL_PROCESS_ATTACH 时,DLL 应该执行 DLL 中的函数要求的任何与进程相 

关的初始化。例如,DLL 可能包含需要使用它们自己的堆栈(在进程的地址空间中创建 )的 

函数。通过在处理DLL_PROCESS_ATTACH 通知时调用 HeapCreate() 函数,该DLL 的DllMain() 

函数就能够创建这个堆栈。已经创建的堆栈的句柄可以保存在 DLL 函数有权访问的一个全局 

变量中。  

    当 DllMain()函数处理一个 DLL_PROCESS_ATTACH 通知时,DllMain() 的返回值能够指 

明 DLL 的初始化是否已经取得成功。如果对 HeapCreate() 函数的调用取得了成功,DllMain() 

应该返回 TRUE 。如果堆栈不能创建,它应该返回 FALSE 。如果 fdwReason 使用的是其他的 

值,即 DLL_PROCESS_DETACH 、DLL_HREAD_ATTACH 和 DLL_THREAD_DETACH ,那 

么系统将忽略 DllMain()返回的值。  

    当然,系统中的有些线程必须负责执行 DllMain() 函数中的代码。当一个新线程创建时, 

系统将分配进程的地址空间,将 EXE 文件映像和所有需要的 DLL 文件映像映射到进程的地 

址空间中。然后开始创建进程的主线程,并使用该线程调用每个 DLL  的带有 DLL_PROCES  

S_ATTACH 值的 DllMain() 函数。当已经映射的所有 DLL 都对通知信息作出响应后,系统将 

使进程的主线程开始执行可执行模块的 C/C++运行期启动代码,然后执行可执行模块的进入 

点函数(main、wmain 、WinMain 或  wWinMain) 。如果 DLL 的任何一个 DllMain() 函数返回 

FALSE ,则表明初始化没有取得成功,系统便终止整个进程的运行,从它的地址空间中删除 

所有文件映像,给用户显示一个消息框,说明进程无法启动运行。  



   2 .DLL_PROCESS_DETACH 通知  



    当DLL 从进程的地址空间中被卸载时,系统将调用DLL 的DllMain() 函数,给它传递fdwR  

eason 的值 DLL_PROCESS_DETACH 。当 DLL 处理这个值时,它可以执行任何与进程相关的 

清除操作。例如,DLL 可以调用 HeapDestroy() 函数来撤消它在 DLL_PROCESS_DETACH 通 

知期间创建的堆栈。需要注意的是,如果 DllMain() 函数接收到 DLL_PROCESS_DETACH 通 

知时返回 FALSE ,那么 DllMain()就不是用 DLL_PROCESS_DETACH 通知调用的。如果因为 

进程终止运行而使 DLL 被卸载,那么调用 ExitProcess()函数的线程将负责执行 DllMain() 函数 



 ·254 ·  


…………………………………………………………Page 266……………………………………………………………

                                                         第 10 章    动态链接库  



的代码。在正常情况下,这是应用程序的主线程。当进入点函数返回到 C/C++运行期库的启 

动代码时,该启动代码将显式调用 ExitProcess()函数,终止进程的运行。  

    如果因为进程中的线程调用 FreeLibrary()或 FreeLibraryAndExitThread() 函数而将 DLL 卸 

载,那么调用函数的线程将负责执行 DllMain()函数的代码。如果使用 FreeLibrary ,那么要等 

到  DllMain() 函数完成对   DLL_PROCESS_DETACH   通知的执行后,该线程才可以从对 

FreeLibrary 函数的调用中返回。  



    3 .DLL_THREAD_ATTACH 通知  



    当在一个进程中创建线程时,系统查看当前映射到该进程的地址空间中的所有 DLL 文件 

映像,并调用每个带有 DLL_THREAD_ATTACH  值的 DllMain() 函数文件映像。这样,DLL 

就可以执行每个线程的初始化操作。新创建的线程负责执行 DLL  的所有 DllMain()函数中的 

代码。只有当所有的 DLL 都有机会处理该通知时,系统才允许新线程开始执行它的线程函数。  

    当一个新 DLL 被映射到进程的地址空间时,如果该进程内已经有若干个线程正在运行, 

那么系统将不为现有的线程调用带有 DLL_THREAD_ATTACH 值的 DDL 的 DllMain()函数。 

只 有 当 新 线 程 创 建 时 , DLL   被 映 射 到 进 程 的 地 址 空 间 中 , 它 才 可 以 调 用 带 有 

DLL_THREAD_ATTACH 值的 DLL 的 DllMain() 函数。  

    另外要注意,系统并不为进程的主线程调用带有 DLL_THREAD_ATTACH 值的任何 DllMain() 

函数。进程初次启动时映射到进程的地址空间中的任何 DLL 均接收 DLL_PROCESS_ATTACH 通 

知,而不是 DLL_THREAD_ATTACH 通知。  



    4 .DLL_THREAD_DETACH 通知  



    让线程终止运行的首选方法是使它的线程函数返回。这使得系统可以调用  ExitThread() 

函数来撤消该线程。如果 ExitThread() 函数要终止运行该线程,系统不会立即将它撤消,而是 

取 出 这 个 即 将 被 撤 消 的 线 程 , 并 让 它 调 用 已 经 映 射 的          DLL  中 所 有 带 有 

DLL_THREAD_DETACH 值的 DllMain() 函数。这个通知告诉所有的 DLL 执行每个线程的清 

除操作。例如,DLL 版本的 C/C++运行期库能够释放它用于管理多线程应用程序的数据块。  



    注意:DLL 能够防止线程终止运行。例如,当 DllMain() 函数接收到 DLL_THREAD_DETACH 通 



        知时,它就能够进入一个无限循环。只有当每个 DLL  已经完成对 DLL_THREAD_DETACH 



        通知的处理时,操作系统才会终止线程的运行。  



    如 果 当  DLL 被 撤 消 时 仍 然 有 线 程 在 运 行 , 那 么 就 不 会 有 任 何 线 程 调 用 带 有 

DLL_THREAD_DETACH 值的 DllMain() 函数。可以在进行 DLL_THREAD_DETACH 的处理 

时查看这个情况,这样就能够执行必要的清除操作。  



10。2。2    DLL 的导出函数  



    当 Microsoft 的 C/C++编译器看到变量、函数原型或 C++类之前的这个修改符的时候,它 

就将某些附加信息嵌入产生的。obj 文件中。当链接 DLL 的所有。obj 文件时,链接程序将对这 

些信息进行分析。  

      



                                                                  ·255 ·  


…………………………………………………………Page 267……………………………………………………………

Visual C++ 6。0 程序设计从入门到精通  



     当 DLL  被链接时,链接程序要查找关于输出变量、函数或  C++类的信息,并自动生成 

一个。lib 文件。该。lib 文件包含一个 DLL 输出的符号列表。当然,如果要链接引用该 DLL 的 

输出符号的任何可执行模块,该。lib 文件是必不可少的 。除了创建。lib 文件外,链接程序还要 

将一个输出符号表嵌入产生的 DLL 文件。这个输出节包含输出变量、函数和类符号的列表(按 

字母顺序排列)。该链接程序还将能够找到每个符号的相对虚拟地址(RVA ),并在该地址中 

放入 DLL 模块。  

    使用 Microsoft 的 Visual Studio 的 DumpBin。exe 实用程序(带有…exports 开关),能够看到 

DLL 的输出节是个什么样子。Kernel32。dll 的输出结果如图 10…1 所示。  



                                                                       



                         图 10…1    dumpbin 输出动态链接库的导出函数  



    通过 Visual  Studio 所提供的 Dependency  Walker 的可视化工具也可以查看动态链接库的 

导出函数信息,如图 10…2 所示。  



                                                                         



                     图 10…2    利用 Dependency Walker 工具查看导出函数信息  



 ·256 ·  


…………………………………………………………Page 268……………………………………………………………

                                                                  第 10 章    动态链接库  



10。3    两种链接 DLL 的方式  



    如果线程需要调用 DLL 模块中的函数,那么 DLL 文件映像必须映射到调用线程的进程 

地址空间中。可以用两种方法进行这项操
返回目录 上一页 下一页 回到顶部 0 1
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!