| ||
Listing 16.4 provides the code of a DLL and a program calling a procedure from this library. In this program, there isn't anything especially difficult. The main goal of this example is to demonstrate that the primary process and the DLL share the same address space. The process passes addresses of strings located in the data block of the primary process. The procedure, in turn , returns to the primary process the address of the string that resides in the DLLs block of data.
; DLL2.ASM .586P ; Flat memory model IFDEF MASM .MODEL FLAT, stdcall ELSE .MODEL FLAT ENDIF PUBLIC DLLP1 ; Constants ; Messages that 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 TEXT DB "String in a DLL", 0 _DATA ENDS ; Code segment __TEXT SEGMENT ; [EBP+10H] ; Reserved parameter ; [EBP+0CH] ; Cause of the call ; [EBP+8] ; DLL module identifier DLLENTRY: MOV FAX, DWORD PTR [EBP+0CH] CMP FAX, 0 JNE DL ; Close the library JMP _EXIT D1: CMP FAX, 1 JNE _EXIT ; Open the library _EXIT: MOV FAX, 1 RET 12 ;------------------ ; Parameter addesses ; [EBP+8] ; [EBP+0CH] DLLP1 PROC EXPORT PUSH EBP MOV EBP, ESP PUSH 0 PUSH DWORD PTR [EBP+0CH] PUSH DWORD PTR [EBP+8] PUSH 0 CALL MessageBoxA@16 POP EBP LEA EAX, TEXT RET 8 DLLP1 ENDP _TEXT ENDS END DLLENTRY ; Main module DLLEX2.ASM that calls ; a procedure from the DLL .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 c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE ; TASM includelib c:\tasm32\lib\import32.lib EXTERN GetProcAddress:NEAR EXTERN LoadLibraryA:NEAR EXTERN FreeLibrary:NEAR EXTERN ExitProcess:NEAR EXTERN MessageBoxA:NEAR 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 'DLL2.DLL', 0 HLIB DD ? MS1 DB 'Message from the library', 0 TEXT DB 'The string is contained in the main module', 0 IFDEF MASM NAMEPROC DB ' DLLP1@0', 0 ELSE NAMEPROC DB 'DLLP1', 0 ENDIF _DATA ENDS ; Code segment _TEXT SEGMENT ; [EBP+10H] ; Reserved parameter ; [EBP+0CH] ; Cause of the call ; [EBP+8] ; DLL module identifier START: ; Load the library PUSH OFFSET LIBR CALL LoadLibraryA@4 CMP EAX, 0 JE _ERR MOV HLIB, EAX ; Get the 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 OFFSET MS1 PUSH OFFSET TEXT CALL EAX PUSH 0 PUSH OFFSET MS PUSH EAX PUSH 0 CALL MessageBoxA@16 ; Close the library PUSH HLIB CALL FreeLibrary@4 ; The library is automatically closed ; when exiting the program ; Exit _EXIT: PUSH 0 CALL ExitProcess@4 _TEXT ENDS END START
To translate this program, issue the following commands for MASM32:
ml /c /coff /DMASM dllex2.asm link /subsystem:windows dllex2.obj
Issue the following commands for TASM32:
tasm32 /ml dllex2.asm tlink32 -aa -Tpd dllex2.obj
Next, consider an interesting example (Listing 16.5). The primary process uses the resources of the DLL that it has loaded. I have already mentioned that font files are DLLs. It's convenient , isn't it? The resources can be placed into a DLL, separate from the code, and then can be loaded as needed. The program in Listing 16.5 first loads an icon from the DLL resources and sets it as the window icon. If you right-click the mouse somewhere in the window area, a procedure from the DLL will be called. This procedure will alternately set different icons to the window.
// The DLL3.RC file // Identifiers #define IDI_ICON1 3 #define IDI ICON2 10 // Define icons IDI_ICON1 ICON "icol.ico" IDI_ICON2 ICON "ico2.ico" ; The DLL3.ASM file .586P PUBLIC SETIC ; Flat memory model IFDEF MASM .MODEL FLAT, stdcall ELSE .MODEL FLAT ENDIF ; Constants WM_SETICON equ 80h IFDEF MASM ; MASM ; Prototypes of external procedures EXTERN LoadIconA@8:NEAR EXTERN PostMessageA@16:NEAR ; INCLUDELIB directives for the linker includelib c:\masm32\lib\user32.lib includelib c: \masm32\lib\kernel32.lib ELSE ; TASM ; Prototypes of external procedures EXTERN LoadIconA:NEAR EXTERN PostMessageA:NEAR ; INCLUDELIB directives for the linker includelib c:\tasm32\lib\import32.lib LoadIconA@8 = LoadIconA PostMessageA@16 = PostMessageA ENDIF ;--------------------------------------------- ; Data segment _DATA SEGMENT PRIZ DB 0 _DATA ENDS ; Code segment _TEXT SEGMENT DLLENTRY: MOV EAX, 1 RET 12 ; [EBP+8] ; [EBP+0CH] SETIC PROC EXPORT PUSH EBP MOV EBP, ESP ; Choose the icon to set CMP PRIZ, 0 JZ IC_1 MOV PRIZ, 0 PUSH 3 JMP CONT IC_1 : MOV PRIZ, 1 PUSH 10 CONT: ; Load the icon from the DLL resources PUSH DWORD PTR [EBP+0CH] ; Identifier ; of the DLL CALL LoadIconA@8 ; Set the window icon PUSH EAX PUSH 0 PUSH WM_SETICON PUSH DWORD PTR [EBP+08H] ; Window descriptor CALL PostMessageA@16 POP EBP RET 8 SETIC ENDP _TEXT ENDS END DLLENTRY // The DLLEX3.RC file // Constant definitions #define WS_SYSMENU 0x00080000L #define WS_MINIMIZEBOX 0x00020000L #define WS_MAXIMIZEBOX 0x00010000L #define DS_3DLOOK 0x0004L // Dialog box definition DIAL1 DIALOG 0, 0, 340, 120 STYLE WS_SYSMENU WS_MINIMIZEBOX WS_MAXIMIZEBOX DS_3DLOOK CAPTION "Dialog with an icon from DLL resources" FONT 8, "Arial" { } ; Main module DLLEX3.ASM, calling ; the procedure from the DLL . 586P ; Flat memory model IFDEF MASM .MODEL FLAT, stdcall ELSE .MODEL FLAT ENDIF ; Constants ; This message arrives when the window is closed WM_CLOSE equ 10h WM_INITDIALOG equ 110h WM_SETICON equ 80h WM_LBUTTONDOWN equ 201h ; Prototypes of external procedures IFDEF MASM ; MASM EXTERN PostMessageA@16:NEAR EXTERN GetProcAddress@8:NEAR EXTERN LoadLibraryA@4:NEAR EXTERN FreeLibrary@4:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetModuleHandleA@4:NEAR EXTERN DialogBoxParamA@20:NEAR EXTERN EndDialog@8:NEAR EXTERN LoadIconA@8:NEAR ; INCLUDELIB directives for the linker includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE ; INCLUDELIB directives for the linker includelib c:\tasm32\lib\import32.lib EXTERN PostMessageA:NEAR EXTERN GetProcAddress:NEAR EXTERN LoadLibraryA:NEAR EXTERN FreeLibrary:NEAR EXTERN ExitProcess:NEAR EXTERN GetModuleHandleA:NEAR EXTERN DialogBoxParamA:NEAR EXTERN EndDialog:NEAR EXTERN LoadIconA:NEAR PostMessageA@16 = PostMessageA LoadIconA@8 = LoadIconA EndDialog@8 = EndDialog GetModuleHandleA@4 = GetModuleHandleA DialogBoxParamA@20 = DialogBoxParamA GetProcAddress@8 = GetProcAddress LoadLibraryA@4 = LoadLibraryA FreeLibrary@4 = FreeLibrary ExitProcess@4 = ExitProcess ENDIF ;--------------------------------------------- ; Data segment _DATA SEGMENT LIBR DB 'DLL3.DLL', 0 HLIB DD ? HINST DD ? PA DB "DIAL1", 0 IFDEF MASM NAMEPROC DB "_SETIC@0", 0 ELSE NAMEPROC DB "SETIC", 0 ENDIF _DATA ENDS ; Code segment _TEXT SEGMENT START: ; Get the application descriptor PUSH 0 CALL GetModuleHandleA@4 ; Create a dialog MOV [HINST], EAX PUSH 0 PUSH OFFSET WNDPROC PUSH 0 PUSH OFFSET PA PUSH [HINST] CALL DialogBoxParamA@20 ; Exit _EXIT: PUSH 0 CALL ExitProcess@4 ; Window procedure ; Position of parameters in the stack ; [BP+014H] ; LPARAM ; [BP+10H] ; WAPARAM ; [BP+0CH] ; MES ; [BP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP, ESP PUSH EBX PUSH ESI PUSH EDI ;-------------- CMP DWORD PTR [EBP+0CH], WM_CLOSE JNE L1 ; Close the library ; The library is closed automatically ; when exiting the program PUSH HLIB CALL FreeLibrary@4 PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog@8 JMP FINISH L1: CMP DWORD PTR [EBP+0CH], WM_INITDIALOG JNE L2 ; Load the library PUSH OFFSET LIBR CALL LoadLibraryA@4 MOV HLIB, EAX ; Load the icon PUSH 3 ; Program identifier PUSH [HLIB] ; Process identifier CALL LoadIconA@8 ; Set the icon PUSH EAX PUSH 0 ; Icon type (small) PUSH WM_SETICON PUSH DWORD PTR [EBP+08H] CALL PostMessageA@16 JMP FINISH L2: CMP DWORD PTR [EBP+0CH], WM_LBUTTONDOWN JNE FINISH ; Get the address of the DLL procedure PUSH OFFSET NAMEPROC PUSH HLIB CALL GetProcAddress@8 ; Call the procedure with two parameters PUSH [HLIB] PUSH DWORD PTR [EBP+08H] CALL EAX FINISH: POP EDI POP ESI POP EBX POP EBP MOV EAX, 0 RET 16 WNDPROC ENDP _TEXT ENDS END START
To translate the program from Listing 16.5, issue the following commands for MASM32:
ml /c /coff /DMASM dllex3.asm rc dllex3.rc link /subsystem:windows dllex3.obj dllex3.res ml /c /coff /DMASM dll3.asm rc dll3.rc link /subsystem:windows /DLL /ENTRY:DLLENTRY dll3.obj dll3.res
Issue the following commands for TASM32:
tasm32 /ml dllex3.asm brcc32 dllex3.rc tlink32 -aa -Tpd dllex3.obj,,,,,dllex3.res tasm32 /ml dll3.asm brcc32 dll3.rc tlink32 -aa -Tpd dll3.obj,,,,dll3.def,dll3.res
The contents of the DLL3.DEF file are as follows :
EXPORTS SETIC
As you have already noticed, the DLL becomes a part of your program and, with the primary process, can use all its capabilities. Thus, for example, using the GetMessage and PeekMessage functions, it can receive the messages intended for the process. If you need to create a window in the DLL, use the identifier of the program that has called it.
| ||