Windows для профессионалов

       

Что такое экспорт


В предыдущем разделе я упомянул о модификаторе __declspec(dllexport). Если он указан перед переменной, прототипом функции или С++-классом, компилятор Microsoft С/С++ встраивает в конечный OBJ-файл дополнительную информацию. Она понадобится компоновщику при сборке DLL из OBJ-файлов.

Обнаружив такую информацию, компоновщик создает LIB-файл со списком идентификаторов, экспортируемых из DLL. Этот LIB-файл нужен при сборке любого ЕХЕ-модуля, ссылающегося на такие идентификаторы. Компоновщик также вставляет в конечный DLL-файл таблицу экспортируемых идентификаторов - раздел экспорта, в котором содержится список (в алфавитном порядке) идентификаторов экспортируемых функций, псрсмснных и классов. Туда же помещается относительный виртуальный адрес (relative virtual address, RVA) каждого идентификатора внутри DLL-модуля.

Воспользовавшись утилитой DumpBin.exe (с ключом -exports) из состава Microsoft Visual Studio, мы можем увидеть содержимое раздела экспорта в DLL-модуле. Вот лишь небольшой фрагмент такого раздела для Kernel32.dll:

C:\WINNl\SYSiEM32>DUMPBIN -exports Kemel32.Dll

Microsoft (R) COFF Binary File Dumper Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998 All rights reserved

Dump of file kernel32.dll

File Type DLL

Section contains the following exports for KERNEL32.dll

0 characteristics

36DB3213 time date stamp Mon Mar 01 16 34:27 1999

0 00 version

1 ordinal base 829 number of functions 829 number of names

ordinal hint RVA name



1 0 0001A3C6 AddAtomA

2 1 0001A367 AddAtomW

3 2 0003F7C4 AddConsoleAliasA

4 3 0003F78D AddConsoleAliasW

5 4 0004085C AllocConsole

6 5 0002C91D AllocateUserPhysicalPages

7 6 00005953 AreFileApisANSI

8 7 0003F1AO AssignProcessToJobObject

9 8 00021372 BackupRead

10 9 000215CE BackupSeek

11 A OQ021F21 BackupWrite

...

828 33B 00003200 lstrlenA

829 33C 000040D5 lstrlenW

Summary

3000 .data

4000 .reloc

4DOOO .rsrc

59000 .text

Как видите, идентификаторы расположены по алфавиту; в графе RVA указывается смещение в образе DLL-файла, по которому можно найти экспортируемый идентификатор.
Значения в графе ordinal предназначены для обратной совместимости с исходным кодом, написанным для 16-разрядной Windows, — применять их в современных приложениях не следует. Данные из графы hint используются системой и для нас интереса не представляют.

NOTE:
Многие разработчики — особенно те, у кого большой опыт программирования для 16-разрядной Windows, — привыкли экспортировать функции из DLL, присваивая им порядковые номера. Но Microsoft не публикует такую информацию по системным DLL и требует связывать EXE- или DLL-файлы с Windows-функциями только по именам. Используя порядковый номер, Вы рискуете тем, что Ваша программа не будет работать в других версиях Windows.

Кстати, именно это и случилось со мной. В журнале Microsoft Systems Journal я опубликовал программу, построенную на применении порядковых номеров. В Windows NT 3.1 программа работала прекрасно, но сбоила при запуске в Windows NT 3.5. Чтобы избавиться от сбоев, пришлось заменить порядковые номера именами функций, и все встало на свои места.

Я поинтересовался, почему Microsoft отказывается от порядковых номеров, и получил такой ответ: "Мы (Microsoft) считаем, что РЕ-формат позволяет сочетать преимущества порядковых номеров (быстрый поиск) с гибкостью импорта по именам. Учтите и то, что в любой момент в API могут появиться новые функции. А с порядковыми номерами в большом проекте работать очень трудно — тем более, что такие проекты многократно пересматриваются.

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


Содержание раздела