| ||
Now, it's time to consider some examples that illustrate DLL creation. Listing 16.1 provides an example of the simplest DLL. This DLL isn't doing anything useful. It is just loaded and then unloaded. Its entry procedure DLLP1 is called, and a normal Windows message will be generated. Pay attention to the processes of loading and unloading this library. Also note that the entry procedure must return a nonzero value. The DLLP1 procedure also processes one parameter traditionally passed through the stack.
.586P ; Flat memory model IFDEF MASM .MODEL FLAT, stdcall ELSE .MODEL FLAT ENDIF PUBLIC DLLP1 ; Constants ; These messages arrive ; when the DLL is opened DLL_PROCESS_DETACH equ 0 DLL_PROCESS_ATTACH equ 1 DLL_THREAD_ATTACH equ 2 DLL_THREAD_DETACH equ 3 IFDEF MASM ; MASM ; Prototypes of external procedures EXTERN MessageBoxA@16:NEAR ; INCLUDELIB directives for the linker includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE ; TASM EXTERN MessageBoxA:NEAR MessageBoxA@16 = MessageBoxA includelib c:\tasm32\lib\import32.lib ENDIF ;----------------------- ; Data segment _DATA SEGMENT TEXT1 DB 'Library's entry point', 0 TEXT2 DB 'Library's exit point', 0 MS DB 'Message from the library', 0 TEXT DB 'Calling a procedure from a DLL', 0 _DATA ENDS ; Code segment _TEXT SEGMENT ; [EBP+10H] ; Reserved parameter ; [EBP+0CH] ; Cause of the call ; [EBP+8] ; Identifier of the DLL module DLLENTRY: MOV EAX, DWORD PTR [EBP+0CH] CMP EAX, 0 JNE D1 ; Closing the library PUSH 0 PUSH OFFSET MS PUSH OFFSET TEXT2 PUSH 0 CALL MessageBoxA@16 JMP _EXIT D1: CMP EAX, 1 JNE _EXIT ; Opening the library PUSH 0 PUSH OFFSET MS PUSH OFFSET TEXT1 PUSH 0 CALL MessageBoxA@16 _EXIT: MOV EAX, 1 RET 12 ;------------------- ; [EBP+8] ; Procedure parameter DLLP1 PROC EXPORT PUSH EBP MOV EBP, ESP CMP DWORD PTR [EBP+8], 1 JNE _EX PUSH 0 PUSH OFFSET MS PUSH OFFSET TEXT PUSH 0 CALL MessageBoxA@l6 _EX: POP EBP RET 4 DLLP1 ENDP _TEXT ENDS END DLLENTRY
The program presented in Listing 16.1 can be translated using both MASM32 and TASM32. This point deserves more careful consideration. First, note that after the name of a procedure called from another module, the EXPORT keyword was inserted. This keyword is required for correct translation using MASM. For TASM, this keyword isn't required, but, fortunately, this translator doesn't notice the presence of any keywords after PROC . However, TASM requires the DLLP1 procedure to be defined as PUBLIC . Furthermore, for correct translation using TASM, it is necessary to create a DEF file and specify it in the command line for TLINK32. To create DLLs, the link linker requires the /DLL key to be specified in the link command line, and the LINK32 command line requires the -Tpd key (the -Tpe key is used by default). The /ENTRY:DLLENTRY key in the link command line can be omitted because the entry point is defined from the END DLLENTRY directive.
To translate the DLL from Listing 16.1, issue the following commands for MASM32:
ml /c /coff /DMASM d1l1.asm link /subsystem:windows /DLL /ENTRY:DLLENTRY dll1.obj
Issue the following commands for TASM32:
tasm32 /ml dll1.asm tlink32 -aa -Tpd dlll.obj,,,,dlll.def
The contents of the DLL1 .DEF file are as follows :
EXPORTS DLLP1
Listing 16.2 is the program that loads the DLL shown in Listing 16.1. This is an example of the late linking. First, it is necessary to load the library using the LoadLibrary function. Then, it is necessary to determine the procedure address using the GetProcAddress function, after which it is possible to call the library. As expected, MASM places _DLLP1@0 instead of DLLP1 into the library name. TASM, on the contrary, doesn't change the name. You must take this into account in the program. Also, it is necessary to account for the possibility of errors when calling the LoadLibrary and GetProcAddress functions. In this respect, consider the following sequence in which the LoadLibrary function searches for the library:
Search the directory from which the program was started.
Search the current directory.
Search the system directory (determined using the GetsystemDirectory function).
Search the Windows directory (determined using the GetwindowsDirectory function).
Search the directories specified by the PATH environment variable.
In the end of the program, the DLL is unloaded from the memory. By the way, this is not necessary because this procedure is carried out automatically when exiting the program.
.586P ; Flat memory model .MODEL FLAT, stdcall ; Constants ; Prototypes of external procedures IFDEF MASM ; MASM EXTERN GetProcAddress@8:NEAR EXTERN LoadLibraryA@4:NEAR EXTERN FreeLibrary@4:NEAR EXTERN ExitProcess@4:NEAR EXTERN MessageBoxA@16:NEAR ; INCLUDELIB directives for the linker includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE ; TASM EXTERN GetProcAddress:NEAR EXTERN LoadLibraryA:NEAR EXTERN FreeLibrary:NEAR EXTERN ExitProcess:NEAR EXTERN MessageBoxA:NEAR ; INCLUDELIB directives for the linker includelib c:\tasm32\lib\import32.lib GetProcAddress@8 = GetProcAddress LoadLibraryA@4 = LoadLibraryA FreeLibrary@4 = FreeLibrary ExitProcess@4 = ExitProcess MessageBoxA@16 = MessageBoxA ENDIF ;---------------------------------------- ; Data segment _DATA SEGMENT TXT DB 'DLL error', 0 MS DB 'Message', 0 LIBR DB 'DLL1.DLL', 0 HLIB DD ? IFDEF MASM NAMEPROC DB '_DLLP1@O', 0 ELSE NAMEPROC DB 'DLLP1', 0 ENDIF _DATA ENDS ; Code segment _TEXT SEGMENT START: ; Load the library PUSH OFFSET LIBR CALL LoadLibraryA@4 CMP EAX, 0 JE _ERR MOV HLIB, EAX ; Get the procedure address PUSH OFFSET NAMEPROC PUSH HLIB CALL GetProcAddress@8 CMP EAX, 0 JNE YES_NAME ; Error message _ERR: PUSH 0 PUSH OFFSET MS PUSH OFFSET TXT PUSH 0 CALL MessageBoxA@16 JMP _EXIT YES_NAME: PUSH 1 ; Parameter CALL EAX ; Close the library PUSH HLIB CALL FreeLibrary@4 ; The library will be closed automatically ; when exiting the program ; Exit _EXIT: PUSH 0 CALL ExitProcess@4 _TEXT ENDS END START
The program presented in Listing 16.2 is translated like any other normal program. For MASM32, use the following:
ml /c /coff /DMASM dllex.asm link /subsystem:windows dllex.obj
For TASM32, use the following:
tasm32 /ml dllex.asm tlink32 -aa dllex.obj
| ||