Простой пример
Простой пример
Итак, попробуем рассказать в простоте. Вот есть у вас класс - примитивный калькулятор:
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 чтобы получить адрес функции по имени.