7.4. Динамические библиотеки

Кроме обычных приложений в Windows появился специальный тип файла -динамические библиотеки (DLL). DLL - это файл, содержащий процедуры и дан­ные, которые доступны программам, обращающимся к нему. Например, все сис­темные функции Windows, которыми мы пользовались, на самом деле были про­цедурами, входящими в состав таких библиотек, - kernel32.dll, user32.dll, comdlg32.dll и т. д. Динамические библиотеки позволяют уменьшить использова­ние памяти и размер исполняемых файлов в тех случаях, когда несколько про­грамм (или даже копий одной программы) используют одну и ту же процедуру.

Можно считать, что DLL - это аналог пассивной резидентной программы, с тем

лишь отличием, что его нет в памяти, если ни одна программа, работающая с ним, не загружена.

С точки зрения программирования на ассемблере DLL - это самый обычный исполняемый файл формата РЕ, отличающийся только тем, что при входе в него

в стеке передается три параметра (идентификатор DLL-модуля, причина вызова процедуры и зарезервированный параметр), которые надо удалить, например ко­мандой ret 12. Помимо этой процедуры в DLL входят и другие, часть которых можно вызывать из разных программ. Список экспортируемых процедур должен быть задан во время компиляции DLL, и поэтому команды для создания нашего следующего примера будут отличаться от обычных.

Компиляция MASM:

ml /с /coff /Ср /D_MASM_ dllrus. asm

link dllrus.obj ©dllrus.Ink Содержимое файла dllrus.lnk:

/DLL

/entry:start /subsystem:windows /export:koi2win_asm /export:koi2win /export:koi2wins_asm /export:koi2wlns Компиляция TASM: tasm /га /х /ml /D_TASM_ dllrus.asm

tlink32 -Tpd -c dllrus.obj_dllrus.def

Содержимое файла dllrus.def: EXPORTS koi2win_asm koi2win koi2wins koi2wins_asm Компиляция WASM: wasm   dllrus.asm wlink ©dllrus.dir

Содержимое dllrus.dir:

file      dllrus.obj form      windows nt DLL

exp       koi2win_asm,koi2win,koi2wins_asm,koi2wins

; dllrus.asm

; DLL для Win32 - перекодировщик из koi8 в ср1251.

.386

.model flat

; Функции,  определяемые в DLL-файле.

ifdef _MASM_

public _koi2win_asm@0    ; koi2win_asm - перекодирует символ в AL. public _koi2win@4 ;  CHAR WINAPI koi2win(CHAR symbol),

public _koi2wins_asm@0 ; koi2wins_asm - перекодирует строку в [ЕАХ]. public _koi2wins@4 ; VOID WINAPI koi2win(CHAR* string).

else

public koi2win_asm ;  Те же функции для TASM и WASM.

public koi2win public koi2wins_asm

public koi2wins

endif

const

Таблица для перевода символа из кодировки К018-Г (RFC1489) в кодировку Windows (ср1251),  таблица толвко для символов 80h - FFh (то еств надо будет вычеств 80h из символа,  преобразоватв его командой xlat ;  и снова добавитв 80h).

k2w_tbl db        16 dup(O) ; Символы, не существующие в ср!251,

db

16 dup(O)

 

;

Символы, не существу

db

16 dup(O)

 

;

перекодируются

в 80h.

db

OOh,

OOh,

OOh,

38h,

OOh,

OOh,

OOh,

OOh

db

OOh,

OOh,

OOh,

OOh,

OOh,

OOh,

OOh,

OOh

db

OOh,

OOh,

OOh,

28h,

OOh,

OOh,

OOh,

OOh

db

OOh,

OOh,

OOh,

OOh,

OOh,

OOh,

OOh,

OOh

db

7Eh,

60h,

61h,

76h,

64h,

65h,

74h,

63h

db

75h,

68h,

69h,

6Ah,

6Bh,

6Ch,

6Dh,

6Eh

db

6Fh,

7Fh,

70h,

71h,

72h,

73h,

66h,

62h

db

7Ch,

7Bh,

67h,

78h,

7Dh,

79h,

77h,

7Ah

db

5Eh,

40h,

41h,

56h,

44h,

45h,

54h,

43h

db

55h,

48h,

49h,

4Ah,

4Bh,

4Ch,

4Dh,

4Eh

db

4Fh,

5Fh,

50h,

51h,

52h,

53h,

46h,

42h

db

5Ch,

5Bh,

47h,

58h,

5Dh,

59h,

57h,

5Ah

.code

; Процедура Получает три параметра - идентификатор, причину вызова

; и зарезервированный параметр. Нам не нужен ни один из них.

_start@12:

mov      al,1      ;  Надо вернуть ненулевое число в ЕАХ.

ret 12

; Процедура BYTE ШАРІ koi2win (BYTE symbol) ifdef MASM точка входа для вызова из С.

_koi2win@4

else koi2win endif

pop pop

proc

proc

ecx eax

ecx

push

; Здесь нет команды RET

ifdef MASM_ koi2win@4 endp

else

koi2win endp

endif ;  Обратный адрес в ЕСХ. ;   Параметр в ЕСХ (теперв стек очищен ;  от параметров!).

;  Обратный адрес вернуть в стек для RET. ■ управление передается следующей процедуре.

Процедура koi2win_asm:

Точка входа для вызова из ассемблерных'программ:

ввод:     - код символа в KOI,

вывод: AL -ifdef _MASM_ koi2win_asm@0 else koi2win_asm

endif код этого же символа в WIN.

proc

proc

(старший бит 0),

test

., al,80h

 

Если символ менвше 80ґі

jz

dont_decode

 

не перекодироватв,

push

ebx

 

иначе -

mov

ebx, offset

k2w_tbl

 

sub

al,80h

 

вычеств 80Г1,

xlat

 

 

перекодироватв

add

al,80h

 

и прибавитв 80И.

pop

ebx

 

 

dont_decode:

 

 

 

ret

 

Выйти.

ifdef _MASM_

 

 

 

_koi2win_asm@0

endp

 

 

else

 

 

 

koi2win asm

endp

 

 

endif

 

 

 

; VOID koi2wins(BYTE*koistring) -

 

;  точка входа

для вызова из

С.

 

ifdef _MASM_

 

 

 

_koi2wins@4

proc

 

 

else

 

 

 

koi2wins

proc

 

 

endif

 

 

 

pop

ecx

 

Адрес возврата из стека.

pop

eax

 

Параметр в ЕАХ.

push

ecx

\

Адрес возврата в стек.

ifdef _MASM_

 

 

 

_koi2wins@4

endp

 

 

else

 

 

 

koi2wins

endp

 

 

endif

 

 

 

; Точка входа

для вызова из

ассемблера:

:  ввод:  ЕАХ -

адрес строки,

которую

надо преобразоватв из КС

ifdef _MASM_ .

 

 

 

proc

 

 

else

 

 

 

koi2wins asm

proc

 

 

endif

 

 

 

push

esi

 

Сохранитв регистры, кото нелвзя изменятв.

push

edi

 

 

push

ebx

 

 

mov

esi,eax

!

Приемник строк

mov

edi.eax

]

и источник совпадают.

mov

ebx,offset

k2w_tbl

 

decode_string:

 

 

 

lodsb

 

 

Прочитатв байт,

test

al,80h

l

если старший бит О,

в WIN.библиотеки

 

dont_decode2 ;

не перекодировать,

sub

al,80h ;

иначе' - вычесть 80п,

xlat

 

перекодировать

add

al,80h

и добавитв 80п.

dont_decode2:

 

 

stosb

 

Вернуть байт на место,

test

al.al ;

если байт - не ноль,

jnz

decode_string ;

продолжить.

pop

ebx

 

pop

edi

 

pop

esi ■

 

ret

 

 

ifdef _MASM_

 

 

_koi2wins_asm@0

endp

 

else

 

 

koi2wins_asm

endp '

 

endif

end _start@12

 

Как видно из примера, нам пришлось назвать все процедуры по-разному для различных ассемблеров. В случае MASM понятно, что все функции должны иметь имена Tnna_start@12, а иначе программам, использующим их, придется обращать­ся к функциям с именами типа_imp_start, то есть такой DLL-файл нельзя будет

загружать из программы, написанной на Microsoft С. В случае TASM и WASM процедуры могут иметь неискаженные имена (и более того, wlink.exe не позволяет экспортировать имя переменной, содержащее символ @), так как их компиляторы берут имена процедур не из библиотечного файла, а прямо из DLL посредством соответствующей программы - implib или wlib.

Итак, чтобы воспользоваться полученным DLL-файлом, напишем простую программу, которая перекодирует одну строку из в Windows

; dlldemo.asm

;  Графическое приложение для Win32, демонстрирующее работу с dllrus.dll,

; выводит строку в KOI8 и затем в ср1251,  перекодированную функцией koi2wins.

; Компиляция:

; MASM

;   ml /с /coff /Cp /D_MASM_ dlldemo.asm ;    link dlldemo.obj /subsystem:windows

;   (должен присутствоватв файл dllrus.lib,  созданный ори компиляции dllrus.dll) ; TASM

tasm /m /ml /D_TASM_ dlldemo.asm implib dllrus.lib dllrus.dll tlink32 /Tpe /aa /x /c dlldemo.obj

WASM

wasm dlldemo.asm

HMf№   Программирование для Windows 95/NT

wlib dllrus.lib dllrus.dll

file form windows nt

include def32.inc include user32.inc' include kernel32.inc

includelib dllrus.lib

ifnde'f _MASM_

extrn

extrn extrn

extrn

koi2win_asm;near

koi2win:near koi2wins_asm:near

koi2wins:near

Определения для функций ; из DLL для

TASM и WASM (хотя для WASM было бы ;эффективнее

использовать_imp_koi2win,

выделив else

koi2win_asm koi2win koi2wins_asm koi2wins gndif

extrn extrn extrn extrn

equ

-equ_

equ equ

_imp_koi2win_asm(9)0: dwo rd imp_koi2win@4:dword imp_koi2wins_asm@0: dword

_imp_koi2wins@4:dword

_imp_koi2win_asm@0 imp_koi2win@4

_imp_koi2wins_asm@0

_imp_lkoi2wins@4

его в условный блок). ; А это для MASM.

.386

 

 

.model

flat

 

.const

 

 

title stringl

db

"ko'i2win demo:  string in K0I8",0

title_string2

db

"koi2win demo:   string in cp1251",0

. data

 

 

koi_string

db

0F3h, 0D4h, 0D2h, OCFh, OCBh, 0C1h, 20h, OCEh, 0C1h

 

db

20h,0EBh,0EFh,0E9h,2Dh,28h,O

_start:

.code

push push push push call

mov

push call

push push push push

call

MB_OK

offset title_string1 offset koi_string 0

MessageBox

eax, offset koi_string eax

koi2wins MB_0K

offset title_string2 offset koi_string 0

MessageBox

;   Заголовок окна MessageBox.

;   Строка на KOI.шшшшш

push      0 ;   Код выхода,

call       ExitProcess ;   Конец программы,

end _start

Этот небольшой DLL-файл может оказаться очень полезным для расшифров­ки текстов, взятых из Internet или других систем, где применяется кодировка KOI8. Воспользовавшись таблицами из приложения 1, вы можете расширить на­бор функций dllrus.dll, вплоть до перекодировки в какой угодно вариант.