;--------------------------------------------------------------------------------------
;
DLLSkeleton.asm
;--------------------------------------------------------------------------------------
.386
.model
flat,stdcall
option
casemap:none
include
\masm32\include\windows.inc
include
\masm32\include\user32.inc
include
\masm32\include\kernel32.inc
includelib
\masm32\lib\user32.lib
includelib
\masm32\lib\kernel32.lib
.data
.code
DllEntry
proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
mov eax,TRUE
ret
DllEntry
Endp
;---------------------------------------------------------------------------------------------------
;
C'est une fonction factice
;
Ça ne fait rien. Je l'ai mise ici pour montrer où vous pouvez insérer des fonctions à l'intérieur d'une DLL.
;----------------------------------------------------------------------------------------------------
TestFunction
proc
ret
TestFunction
endp
End DllEntry
;-------------------------------------------------------------------------------------
;
DLLSkeleton.def
;-------------------------------------------------------------------------------------
LIBRARY
DLLSkeleton
EXPORTS
TestFunction
Ce tout petit programme ci-dessus est le squelette de la DLL. Chaque DLL doit avoir une fonction d'entrypoint. Windows appellera la fonction d'entrypoint chaque fois que :
Vous pouvez nommer la fonction d'entrypoint comme vous le souhaitez tant que vous avez une FIN correspondante à 'END
hInstDLL
est l'handle du module(de la fonction) de la DLL. Ce n'est pas le même que l'instance handle du process. Vous devez garder cette valeur si vous avez besoin de l'employer plus tard. Vous ne pourrez pas l'obtenir de nouveau aussi facilement.
reason
peut être une des quatre valeurs :
LIBRARY
DLLSkeleton
EXPORTS
TestFunction
Normalement vous devez avoir la première ligne. La déclaration LIBRARY définit le nom du module interne (la fonction souhaitée) de la DLL. Vous devez correspondre avec ce module grâce au nom du fichier de la DLL.
La déclaration EXPORTS dit au linker quelles fonctions sont en train de tourner dans la DLL, c'est-à-dire quelles fonctions sont déjà utilisées par d'autres programmes. Dans l'exemple, nous voulons que d'autres modules soient capables d'appeler TestFunction, donc nous mettons son nom dans la déclaration EXPORTS.
Un autre changement c'est le commutateur du linker. Vous devez mettre le commutateut /DLL et /DEF:<votre nom de fichier def>
dans votre linker de commutation comme cela :
link /DLL /SUBSYSTEM:WINDOWS /DEF:DLLSkeleton.def /LIBPATH:c:\masm32\lib DLLSkeleton.obj
Les commutateurs d'assembleur sont les mêmes, à savoir /c /coff /Cp. Ainsi après que vous ayez lié le fichier objet, vous obtiendrez *.DLL et *.lib. Le *.lib est la bibliothèque d'importation que vous pouvez employer pour vous lier avec d'autres programmes qui emploient les fonctions de votre DLL.
Ensuite je vous montrerai comment employer LoadLibrary pour charger une DLL.
;---------------------------------------------------------------------------------------------
;
UseDLL.asm
;----------------------------------------------------------------------------------------------
.386
.model
flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
.data
LibName db "DLLSkeleton.dll",0
FunctionName db "TestHello",0
DllNotFound db "Cannot load library",0
AppName db "Load Library",0
FunctionNotFound db "TestHello function not found",0
.data?
hLib dd ?
; l' handle de la librairie (l' handle de la DLL)
TestHelloAddr dd ?
; l'adresse de la function TestHello
.code
start:
invoke LoadLibrary,addr LibName
;---------------------------------------------------------------------------------------------------------
;
Appelle LoadLibrary avec le nom de la DLL désirée. Si l'appel est couronné de succès
;
Il renverra l'handle de la bibliothèque (DLL). Sinon, il renverra le NULL.
;
Vous pouvez passer l'handle de la bibliothèque à GetProcAddress ou n'importe quelle fonction qui en a besoin
;
de l'handle d'une DLL comme paramètre.
;------------------------------------------------------------------------------------------------------------
.if eax==NULL
invoke MessageBox,NULL,addr DllNotFound,addr AppName,MB_OK
.else
mov hLib,eax
invoke GetProcAddress,hLib,addr FunctionName
;-------------------------------------------------------------------------------------------------------------
;
Quand vous obtenez l'handle de la bibliothèque, vous le passez à GetProcAddress avec l'adresse
;
du nom de la fonction de la DLL que vous souhaitez appeler. Ceci renvoie l'adresse
;
de la fonction si tout s'est passé avec succès. Autrement, il renvoie le NULL.
;
Les adresses des fonctions ne changent pas à moins que vous ne déchargiez puis rechargiez la bibliothèque.
;
Donc vous pouvez les placer dans des variables globales pour de futures utilisations.
;-------------------------------------------------------------------------------------------------------------
.if eax==NULL
invoke MessageBox,NULL,addr FunctionNotFound,addr AppName,MB_OK
.else
mov TestHelloAddr,eax
call [TestHelloAddr]
;-------------------------------------------------------------------------------------------------------------
;
Ensuite, vous pouvez appeler la fonction avec un appel simple avec la variable contenant
;
l'adresse de la fonction comme l'opérande.
;-------------------------------------------------------------------------------------------------------------
.endif
invoke FreeLibrary,hLib
;-------------------------------------------------------------------------------------------------------------
;
Quand vous n'avez plus besoin de la bibliothèque, vous la déchargez avec FreeLibrary.
;-------------------------------------------------------------------------------------------------------------
.endif
invoke ExitProcess,NULL
end
start
Donc vous pouvez voir que l'utilisation de LoadLibrary est un peu plus impliquée mais c'est aussi plus flexible.