动态库的执行时间
   作者:xlfancy 于2003-9-12上传 

此文章是针对怜香的系列专题教程"从DOS到Win32"中第8篇文章的后续,读此文之前请先阅读怜香的文章.
当程序中引用了动态库后,WINDOWS是先远行程序呢?还是先加载动态库呢?

为了搞清这个问题,我们将MyDLL.ASM和10.ASM稍作修改如下:

;================MyDLL.ASM================
;例:将EDX:EAX中的值转换成十进制输出形式字符串。
;文件名:MyDll.asm,这是动态链接库的源程序
   ;编译模式="DLL"
        .386
        .model flat,stdcall
        option casemap:none

include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib

OutEdxEax PROTO: DWORD

        .DATA
szText0 db "哈哈哈...MyDLL加载",0
szText1 db "MyDLL第一次插入进程的地址空间",0
szText2 db "MyDLL从进程的地址空间卸出",0
szText3 db "同一进程的新线程生成",0
szText4 db "同一进程的线程销毁",0
szText5 db "MyDLL的函数OutEdxEax调用成功",0

        .code

;DllEntry是动态链接库的入口,当动态链接库被加载/卸载时,
;或同一进程的线程生成/退出时,都会调用该入口函数
;当然,函数名不一定非是这个,但要和最后的End DllEntry保持一致。

DllEntry proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
.if reason==DLL_PROCESS_ATTACH      动态链接库第一次插入进程的地址空间
    invoke MessageBox,NULL,addr szText1,addr szText0,MB_OK
    mov    eax,TRUE
    ret
.elseif reason==DLL_PROCESS_DETACH  动态链接库从进程的地址空间卸出
    invoke MessageBox,NULL,addr szText2,addr szText0,MB_OK
    mov    eax,FALSE
    ret
.elseif reason==DLL_THREAD_ATTACH   ;同一进程的新线程生成
    invoke MessageBox,NULL,addr szText3,addr szText0,MB_OK
    mov    reason,TRUE
    ret
.elseif reason==DLL_THREAD_DETACH   ;同一进程的线程销毁
    invoke MessageBox,NULL,addr szText4,addr szText0,MB_OK
    mov    eax,FALSE
    ret
.endif
DllEntry Endp

;将EDX:EAX中的值转换成十进制输出形式字符串,很熟悉吧,前面的例子中有的!
;比如:EDX=0,EAX=01234567H,则转换后的字符串为:
;        -> '19088743',0
OutEdxEax proc uses ebx esi edi,lpString
        mov edi,lpString    指向存放结果的地址
        mov esi,lpString
        mov ecx,10          转换成十进制
        .while eax!=0 || edx!=0
            push eax    
            mov eax,edx
            xor edx,edx
            div ecx
            mov ebx,eax
            pop eax
            div ecx
            add dl,'0'      
            mov [edi],dl    存放结果
            inc edi
            mov edx,ebx
        .endw

        mov BYTE ptr [edi],0;字符串以0为结尾
        dec edi

        .while edi>esi      结果前变后,后变前!
            mov al,[esi]
            xchg al,[edi]
            mov [esi],al
            inc esi
            dec edi
        .endw
    invoke MessageBox,NULL,addr szText5,addr szText0,MB_OK
        ret
OutEdxEax endp
end DllEntry


;================10.ASM================
;例:文件名:10.asm
;调用MyDll.dll,看能否正常工作

        .386
        .model flat,stdcall
        option casemap:none

include windows.inc

include mydll.inc
include masm32.inc
include user32.inc
include kernel32.inc

includelib mydll.lib
includelib masm32.lib
includelib user32.lib
includelib kernel32.lib


        .DATA
szText  db "哈哈哈...10.exe运行",0

        .data?
CharOut db 100 dup(?)

        .code
start:
    invoke MessageBox,NULL,addr szText,addr szText,MB_OK
    mov edx,12345678h
    mov eax,87654321h
    invoke OutEdxEax,addr CharOut   ;用我们自己的程序转换!
    invoke StdOut,addr CharOut
    invoke ExitProcess,NULL  
    end start


好了,将如上修改存盘,编译运行。看到啥啦?似乎也明白了些东东哈!
对啦,我们可以看到:此时WINDOWS先加载动态库,再运行程序。


如果我们把10.ASM再作如下修改,并存盘为10_01.ASM


;================10_01.ASM================
;文件名:10_01.asm
;调用MyDll.dll,看能否正常工作

        .386
        .model flat,stdcall
        option casemap:none

include windows.inc
include masm32.inc
include user32.inc
include kernel32.inc

includelib masm32.lib
includelib user32.lib
includelib kernel32.lib


        .DATA
szText        db "哈哈哈...10_01.exe运行",0
MyDllFileName db "e:\masm32\xlfancy\mydll.dll",0
CallFuncName  db "OutEdxEax",0

        .data?
CharOut       db 100 dup(?)
MyDLLHandle   dd ?
OutEdxEaxAddr dd ?

        .code
start:
    invoke MessageBox, NULL, addr szText, addr szText, MB_OK

    invoke OutEdxEax, addr CharOut   ;用我们自己的程序转换!

    invoke LoadLibrary, offset MyDllFileName
    or     eax, eax
    jz     ExitPro
    mov    MyDLLHandle, eax
    invoke GetProcAddress, eax, offset CallFuncName
    or     eax, eax
    jz     FreeLib
    mov    OutEdxEaxAddr, eax
    lea    eax, CharOut
    push   eax
    mov    edx, 12345678h
    mov    eax, 87654321h
    call   OutEdxEaxAddr

    invoke StdOut,addr CharOut

FreeLib:
    invoke FreeLibrary, MyDLLHandle

ExitPro:
    invoke ExitProcess, NULL  
    end start


编译运行。这时看到啥啦?咦,此时WINDOWS先运行程序,再加载动态库。

以上就是动态库的两种不同的调用方法。经过这两种不同的调用方法,
我们可以粗略地认识和理解WINDOWS加载EXE和DLL的次序和不同。(狗屁!其实我根本就#@$#%#%$%)



以上都在本机编译通过,可就是看不到结果。(折腾了半天,不只所以,JMP...)
不管了,没犯路线错误就行...(马马乎乎,也敢贴出来$%$#%$%%&%&^%,"砰",怎么有砖打到脑袋上?¥#¥%¥%……%)


欢迎访问AoGo汇编小站:http://www.aogosoft.com