Простой пример
Итак, попробуем рассказать в простоте. Вот есть у вас класс - примитивный калькулятор:
MyCalc=class fx,fy:integer; public: procedure SetOperands(x,y:integer) function Sum:integer; function Diff:integer; end; procedure MyCalc.SetOperands(x,y:integer) begin fx:=x; fy:=y; end; function MyCalc.Sum:integer; begin result:=fx+fy; end; function MyCalc.Diff:integer; begin result:=fx-fy; end;
Все элементарно. Теперь если у вас есть объект этого класса, то вам не составит труда им воспользоваться.
Но представим следующую ситуацию: у вас есть один модуль, где объявлется объект этого класса. Допустим:
unit MyCalc type MyCalc=class <описание выше> var Calc:MyCalc;
и теперь вы хотите использовать в другом модуле. Хорошо, скажите Вы, мы его просто подключим, и используем. Но, допустим, вы хотите, чтобы и другие могли пользоваться вашим объектом, даже используея другой компилятор. То есть нужно сделать так, чтобы ваш модуль можно было бы использовать без перекомпиляции. Как это сделать?
Ясно, что без каких-то стандартов не обойтись. Скорее всего, самый простой вариант выглядел бы так:
unit MyCalc type MyCalc=class <описание выше> var Calc:MyCalc; procedure SetOperands(x,y:integer) begin Calc.SetOperands(x,y); end; function Sum:integer; begin result:= Calc.Sum; end; function Diff:integer; begin result:= Calс.Diff; end; procedure CreateObject; begin Calc:=MyCalc.Create; end; procedure ReleaseObject; begin Calc.Free; end;
откомпилировать этот юнит, посмотреть, по какому адресу находятся функции SetOperands, Sum, Diff, CreateObject и ReleaseObject и приложить документацию где эти адреса будут указанны. Теперь каждый сможет загрузить ваш модуль в память и по адресу указанном в вашей документации вызвать нужную функцию.
Понятно, чем такой подход чреват. Это крайне не удобно. Но, эта проблема была поставленна давно, и теперь у нас есть стандартизированное соглашение об экспорте функций. То есть вместо того, чтобы писать для каждого модуля документацию с адресами функций при компиляции в заголовке модуля создается специальная стандартная таблица где указанны имена этих функций и их адреса (также указывается числовой индефикатор, который может быть использован вместо имени). Теперь уже лучше. Для того чтобы вызвать ваши функции, достаточно загрузить ваш модуль в память прочитать таблицу экспорта, и можно по именам в ней нати адреса функций и их вызвать. Так устроены DLL. Сейчас все это поддерживается компиляторами, и Windows API. То есть вам самому ничего этого делать не надо, а достаточно вызвать LoadLibrary, чтобы загрузить ваш модуль в память, и GetProcAddress чтобы получить адрес функции по имени.