;--------------------------------------------------------------------------------------
.data
End DllEntry
;
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
.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
;-------------------------------------------------------------------------------------
;
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 LIBRARY
DLLSkeleton
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.
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.
.data
.data?
.code
Donc vous pouvez voir que l'utilisation de LoadLibrary est un peu plus compliquée mais elle est aussi plus flexible.
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.
Exemple: Si vous connaissez la DLL Kernel32.DLL vous savez bien qu'elle possède plusieurs fonctions ou modules à l'intérieurs d'elle, dont GetCommandeLineA et ExitProcess.
reason
peut être une des quatre valeurs :
Renvoyez TRUE dans eax si vous souhaitez que la DLL continue son exécution. Si vous renvoyez FALSE, la DLL ne sera pas chargée. Par exemple, si votre code d'initialisation doit réserver de la mémoire et qu'il ne peut pas faire ça avec succès, la fonction d'entrypoint doit renvoyer FALSE pour indiquer que la DLL ne peut pas être lancée.
Vous pouvez placer vos fonctions dans la DLL après la fonction Entrypoint ou même avant çà. Mais si vous voulez qu'elles soient CALLables par d'autres programmes, vous devez mettre leurs noms dans la liste d'exportation du fichier de définition de module (.def).
Une DLL a besoin d'un fichier de définition de module dans son process liée à son développement. Nous y jetons un coup d'œil maintenant.
EXPORTS
TestFunction
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 :
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
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
hLib dd ?
; l' handle de la librairie (l' handle de la DLL)
TestHelloAddr dd ?
; l'adresse de la function TestHello
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 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 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