На этом шаге мы рассмотрим алгоритмы вызова функций из DLL.
Теперь, когда вы знаете, как пишутся DLL, вы можете захотеть узнать, как вызвать ее из другой программы. Сначала, перед компиляцией программы, вы должны указать компоновщику имена функций, которые ваша программа импортирует из DLL. Если вы забудете это сделать, компоновщик сгенерирует для каждой импортированной функции ошибку типа "неопределенный символ" (Undefined Symbol). Есть три способа информирования компоновщика об импортированных функциях.
Вы добавляете раздел IMPORTS к файлу определения программы (файл с расширением *.def):
EXETYPE WINDOWS CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE MULTIPLE HEAPSIZE 4096 STACKSIZE 5120 IMPORTS SHAPELIB.Fred SHAPELIB.Triangle SHAPELIB.Squiggle
Этот способ является подходящим для программ, которые импортируют всего лишь несколько функций. Однако перечисление всех этих функций, импортированных из большой DLL, может быть долгим и скучным процессом.
Способ, обратный предыдущему, состоит в присвоении порядковых значений каждой из функций, которую экспортирует ваша DLL. Это осуществляется добавлением раздела EXPORTS к файлу определения DLL (файл с расширением *.def):
EXPORTS Fred @1 Triangle @2 Squiggle @3
Эти порядковые значения, перед которыми стоит символ "@", могут быть любыми уникальными целыми положительными числами. Теперь в разделе IMPORTS файла определения вашей программы вы можете присвоить этим порядковым значениям имена соответствующих функций:
IMPORTS Fred = SHAPELIB.1 Triangle = SHAPELIB.2 Squiggle = SHAPELIB.3
Путем запоминания порядкового значения вместо имени функций объем выполняемого файла вашей программы станет несколько меньше. Однако, опять-таки, перечисление всех функций, включенных в большую DLL, может быть утомительным процессом.
Создание библиотеки импорта является более простым способом информирования компоновщика об импортированных DLL-функциях. После создания вашей DLL запуск программы IMPLIB.EXE в Borland создает файл библиотеки импорта за вас. При правильной установке вашего проекта Borland IDE автоматически запускает программу IMPLIB.EXE для DLL-файла.
Когда создается файл библиотеки импорта, он имеет расширение LIB. Если вы компилируете программу, которая не содержит в проекте выходной объект DLL, вы должны ввести этот новый библиотечный файл в список файлов в проекте вашей программы, а затем компилировать программу. И это все. Вам не надо отыскивать все функции вручную; библиотека импорта все это сделает за вас.
При написании вашей программы вы теперь можете вызвать DLL-функции, как если бы они являлись частью вашей программы, что вы и увидите, когда изучите класс главного окна нашей программы, начиная с определения класса:
class TWndw: public TFrameWindow { public: TWndw (TWindow *parent, const char far *title); protected: void EvLButtonDown (UINT, TPoint &point); void EvRButtonDown (UINT, TPoint &point); void EvMButtonDown (UINT, TPoint &point); DECLARE_RESPONSE_TABLE (TWndw); }; DEFINE_RESPONSE_TABLE1 (TWndw, TFrameWindow) EV_WM_LBUTTONDOWN, EV_WM_RBUTTONDOWN, EV_WM_MBUTTONDOWN, END_RESPONSE_TABLE;
В этом примере главное окно является производным из класса TFrameWindow. Функциями главного окна, кроме конструктора, являются лишь функции отклика на сообщения для всех трех кнопок мыши. Когда пользователь нажимает на кнопку мыши, вызывается функция, которая рисует в окне требуемую фигуру, например, функция EvLButtonDown() рисует "Фреда":
void TWndw::EvLButtonDown (UINT, TPoint &point) { // Получить контекст устройства для рабочей области окна. TClientDC DC(HWindow); // Вызвать функцию DLL. Fred(HDC(DC), point.x, point.y); }
В данном примере эта функция получает контекст устройства окна и вызывает функцию Fred(), рисующую фигуру. Хотя Fred() и находится в DLL, функция EvLButtonDown() вызывает ее точно так же, как и любую другую функцию в программе. Функции EvRButtonDown() и EvMButtonDown() работают аналогично.
На следующем шаге мы рассмотрим особенности применения DLL.