此文章是針對憐香的系列專題教程"從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...)
不管了,沒犯路線錯誤就行...(馬馬乎乎,也敢貼出來$%$#%$%%&%&^%,"砰",怎麼有磚打到腦袋上?¥#¥%¥%……%)