Динамическая компоновка DLL

   
На этом шаге мы рассмотрим алгоритм динамической компоновки DLL.

   
Приведенный на 67 шаге способ подключения DLL носит название статической компоновки.
В этом случае библиотека подключается к приложению на этапе компоновки. Отсутствие DLL приведет к
неработоспособности приложения. Вы можете в этом убедиться, перенеся DLL в другую папку. В этом случае при запуске
приложения вы получите сообщения такого вида:


Рис.1. Сообщения, получаемые при отсутствии DLL

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

   
Изменим программу, приведенную на 67 шаге, применив динамическую компоновку DLL.

   
Прежде всего, изменим текст SHAPELIB.CPP, чтобы можно было откомпилировать ее для платформы Win32.

#include <windows.h>

// Используйте extern "C", чтобы
// предотвратить искажение имен C++.
extern "C"
{
	void far _export  __stdcall Triangle (HDC hDC, int x, int y);
	void far _export  __stdcall Squiggle (HDC hDC, int x, int y);
	void far _export  __stdcall Fred (HDC hDC, int x, int y);
}
//
// LibMain()
// Эта функция является точкой входа в DLL.
int far PASCAL LibMain (HINSTANCE hInstance, WORD wDataSeg,
	 WORD cbHeapSize, LPSTR lpstrCmdLine)
{
  return 1;
}

// WEP()
// DLL здесь выходит. WEP = Windows Exit Procedure
// (процедура выхода).
int far PASCAL WEP (int nParam)
{
  return TRUE;
}

// Fred()
// Эта функция рисует Фреда.
extern "C" __stdcall void Fred (HDC hDC, int x, int y)
{
  Ellipse (hDC, x, y, x+20, y+30);
  Ellipse (hDC, x+3, y+10, x+8, y+16);
  Ellipse (hDC, x+12, y+10, x+17, y+16);
  Ellipse (hDC, x+7, y+16, x+13, y+20);
  Ellipse (hDC, x+4, y+22, x+16, y+25);
  Ellipse (hDC, x-3, y+10, x, y+18);
  Ellipse (hDC, x+20, y+10, x+23, y+18);
}

// Triangle()
// Эта функция рисует треугольник.
extern "C" __stdcall void Triangle (HDC hDC, int x, int y)
{
  MoveToEx (hDC, x, y, NULL);
  LineTo (hDC, x-10, y+20);
  LineTo (hDC, x+10, y+20);
  LineTo (hDC, x, y);
}

// Squiggle()
// Эта функция рисует "пилу".
extern "C" __stdcall void Squiggle (HDC hDC, int x, int y)
{
  MoveToEx (hDC, x, y, NULL);
  for (int i=1; i<6; ++i)
  {
	 LineTo (hDC, x+(i*10), y-10);
	 LineTo (hDC, x+(i*10), y+10);
  }
}

Текст DLL и все сопуствующие файлы можно взять 67 шага. Однако,
если вы уберете DLL из папки, где находится приложение, то оно запустится, только по щелчку левой, средней
и правой кнопкой мыши будет появляться соотвествующее предупреждающее сообщение.

   
Опишем основные отличия этой программы от аналогичной из 67 шага.

   
Прежде всего обратите внимание на последние две строки контруктора главного окна:

TWndw::TWndw (TWindow *parent, const char far *title) :
			TFrameWindow (parent, title)
{
  // Определить расположение и размеры окна.
  Attr.X = 40;
  Attr.Y = 40;
  Attr.W = GetSystemMetrics (SM_CXSCREEN) / 1.5;
  Attr.H = GetSystemMetrics (SM_CYSCREEN) / 1.5;
  L = LoadLibrary ("shapelib.dll");
  if (!L) MessageBox("Не загрузилась DLL","Ошибка", MB_OK);
}

   
Здесь осуществляется вызов функции API LoadLibrary(), которая загружает DLL с заданным именем. Значением
этой функции является логический номер модуля, который однозначно определяет DLL. Если в процессе загрузки
DLL произошла ошибка, то возвращается NULL.

   
По щелчку левой клавишей мыши вызывается функция EvLButtonDown():

void TWndw::EvLButtonDown (UINT, TPoint &point)
{
  // Получить контекст устройства для рабочей области окна.
  TClientDC DC(HWindow);
  // Вызвать функцию  DLL.
  Func F =(Func)GetProcAddress(L,"Fred");
  if (!F) MessageBox("Не найдена функция Fred","Ошибка", MB_OK);
  else
	 (*F)(HDC(DC), point.x, point.y);
}

   
Здесь используется функция API GetProcAddress() для получения указателя на функцию, находящуюся в DLL, на
которую у нас есть ссылка. Адрес функции, имя которой указано в качестве второго параметра GetProcAddress(),
помещается в переменную F, которая описана как указатель на функцию, имеющую три параметра и возвращающую значение void.
Этот тип определен следующим образом:

  typedef  void far  (*Func)(HDC hDC, int x, int y);

   
Если все прошло успешно, то осуществляется косвенный вызов функции с передачей ей необходимых параметров:

  (*F)(HDC(DC), point.x, point.y);

   
Если определить адрес функции не удалось, то F будет иметь значение NULL, и будет выдано сообщение об ошибке.

   
Осталось выгрузить библиотеку при завершении программы. Это делается в деструкторе:

// TWndw::~TWndw()
// Это деструктор главного окна.
TWndw::~TWndw ()
{
  // Выгрузить библиотеку, если она загружена.
  if (L) FreeLibrary(L);
}

   
Замечание.
Не забудьте установить платформу Win32 для приложения.

   
Со следующего шага мы начнем приводить примеры приложений с использованием изученного материала.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий