zoukankan      html  css  js  c++  java
  • win32汇编-动态链接库(六)

    DLL函数头

        
    DllEntry        proc hInstDLL,dwReason,dwReserved
    
     
    
                    mov     eax,dwReason
    
                    .if     eax ==  DLL_PROCESS_ATTACH
    
                            ;保存hInstDll
    
                            ;初始化库需要的各种资源
    
                            .if     初始化成功
    
                                mov     eax,TRUE
    
                            .else
    
                                mov eax,FALSE
    
                            .endif
    
                    .elseif eax ==  DLL_THREAD_ATTACH
    
                        ;释放库使用的资源
    
                    .elseif eax ==  DLL_THREAD_DETACH
    
                        ;为新的线程分配资源
    
                    .elseif eax ==  DLL_PROCESS_DETACH
    
                        ;为线程释放资源
    
                    .endif
    
                    ret
    
     
    
    DllEntry        Endp 
    View Code

    Windows会传给入口函数3个参数,dwReason参数的值表示本次调用的原因,它可能是下面四种情况。

    dwReason的值是DLL_PROCESS_ATTACH  表示动态链接库刚被映射到某个进程的地址空间,程序可以在这里进行一些初始化的工作,并返回TRUE表示初始化成功,返回FALSE表示初始化出错,这样库的装入就会失败。报"初始化错误" 这给了动态链接库一个机会来阻止自己被装入。

    当dwReason的值是DLL_PROCESS_DETACH 表示动态链接库将被卸载,库程序可以在这里进行一些资源的释放工作,如将初始化时申请的内存释放,将打开的文件关闭等。 以DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH值进行的调用在库的生命周期中只可能出现一次。

    当dwReason的值是DLL_THREAD_ATTACH 表示应用程序创建了一个新的线程。当某个线程正常终止的时候,dwReason的值是DLL_PROCESS_DETACH。如果应用程序不是以多线程方式工作的话,就不会有这两种原因的调用;反之,如果应用程序频繁地创建和结束线程,那么入口函数将不断被调用。

    hInstDll是动态链接库的模块实例句柄。当使用这个句柄来装入资源的时候,表示资源是定义在库文件中的,对于动态链接库来说,获取这个句柄的惟一途径就是保留入口函数的这个参数,如果在DLL_PROCESS_ATTACH时不将这个句柄保存下来的话,运行时可能就没有其他方法可以获取了。dwReserved参数是系统保留的参数,可以不必理会。

    动态链接库有一种很“极端”的应用:纯资源库,这些库仅包含资源而没有任何的功能函数,如字体文件等,对于这些库来说,库中的全部代码仅是入口函数中用来返回TRUE的那几句,这是库能被正常装入所必须的代码。

    2. 导出函数

    与写普通的可执行文件相比,动态链接库的设计流程中多了一个文件,那就是定义文件 *.def,示例源代码目录中还包括一个Counter.def文件,它的内容是:

    EXPORTS _IncCount

            _DecCount

    调用未导出函数声明将报"在xx.dll未找到xx函数的错误"

     

    如果dll文件是当做最终应用程序发布的,可以仅发布dll文件;如果是当做插件供其他人做二次开发用的,那么就要为其他程序员同时提供dll文件和lib文件,并且根据情况提供不同语言使用的头文件(最后,还要为每个导出函数写一个说明,包括参数的个数、类型和定义等)。目录中还有一个Counter.inc文件,它的内容如下:

     

    _IncCount   proto   :dword,:dword

     

    _DecCount   proto   :dword,:dword

    使用动态链接库

     

    1. 方法一:常规方法

    头文件中导入xx.inc和xx.lib 后当作一般函数调用 需保证xx.dll文件始终存在不然将报"找不到xx.dll"错误

     

    2. 方法二:动态装入

     

    方法一的优点就是使用方便,应用程序可以像使用自己内部的函数一样使用DLL中的函数,缺点也显而易见,如果装入DLL的过程中有任何错误,应用程序没有任何机会完成应变的措施,因为它根本没有被装入执行。

    使用情况:1 程序需要使用系统中的保留函数。

                2 同版本Windows中的函数集不同 根据函数是否存在做不同的处理。

                3 使用某些并不重要库(如仅用来显示程序版本的库),丢失后,程序也能继续运行

     

    不再需要Counter.lib文件和Counter.inc文件

    LoadLibrary函数的使用方法是:

     invoke  LoadLibrary,lpDllFileName //需要装载的库文件名(仅文件名)
    
       .if     eax
    
               mov     hDllInstance,eax
    
       .endif

     

    如果装载动态链接库成功,下一步就是使用GetProcAddress函数来获取库中函数的地址。GetProcAddress函数的使用方法是:

     invoke  GetProcAddress,hDllInstance,lpProcName
    
       .if     eax
    
               mov     lpProc,eax
    
       .endif

    hDllInstance参数就是LoadLibrary函数返回的动态链接库的实例句柄,lpProcName指向要获取的函数名称,函数名也是用以NULL结尾的字符串来定义。有些系统DLL中的函数名称并不是字符串,而是使用数值编号,对于这种情况,lpProcName参数可以指定为函数的编号数值。

    如果执行成功,返回值是要获取的函数的入口地址,程序可以保存它并在以后调用。如果执行失败,比如因为版本变化等原因导致需要获取的函数不存在,这时函数返回NULL。

    在不再需要动态链接库的时候,为了释放库所占用的系统资源,需要使用FreeLibrary函数释放它。FreeLibrary函数的用法是:

       invoke  FreeLibrary,hDllInstance

    输入参数是LoadLibrary函数返回的实例句柄,函数导致系统以DLL_PROCESS_DETACH代码调用库的入口函数,这样库文件可以自己释放占用的一些资源,然后,整个库的代码和数据被从应用程序的地址空间中清除。

    方法二和方法一的最后一个不同点是调用函数的方法,在使用GetProcAddress函数获取了库中导出函数的入口点以后,程序在调用的时候一般使用将参数手工入栈的方法,如对_IncCount函数的调用可以写为:

       push        IDC_COUNTER

       push        hWnd

       call        lpIncCount      lpIncCount保存有GetProcAddress获取的地址

    这样写法的缺点是无法使用invoke伪指令来进行参数检验,容易引发错误。实际上还有一个变通的方法,可以将一个变量定义为子程序入口指针,并为它定义参数个数,方法是两次使用typedef伪操作

    _PROCVAR2       typedef proto :dword,:dword

    PROCVAR2            typedef ptr _PROCVAR2

    如上面的第一句将_PROCVAR2类型定义为使用两个参数的函数类型,第二句将PROCVAR类型定义为_PROCVAR2类型的指针,这样,在数据段中就可以将保存函数入口地址的变量使用PROCVAR2类型来定义了,得到的好处就是可以用invoke语句来调用这个变量中的指针:

                       .data?

    lpIncCount      PROCVAR2    ?

    lpDecCount      PROCVAR2    ?

    动态链接库中的数据共享

     

    未初始化数据段 .data?的节区名称为 .bbs,加上/section:.bss,S链接选项就可以将这个段的属性改为共享,这样,当DLL被不同应用程序装载的时候,不但映射到不同进程地址空间中的代码段来自同一段物理内存,.data?段的映射也来自同一段物理内存。

     

     

     

     

     

  • 相关阅读:
    request和request.form和request.querystring的区别
    PL/SQL Developer连接64位Oracle
    C# Winform控件对透明图片重叠时导致图片不透明的解决方法
    C++11多线程编程-两个进程轮流打印1~100
    使用 C++11 并发编程入门
    STL vector动态扩容
    GDB入门教程
    统计整数中1的个数
    gulp的使用
    nvm安装教程
  • 原文地址:https://www.cnblogs.com/xuankuwa/p/3660517.html
Copyright © 2011-2022 走看看