Домой! Изучаем DLL. Часть 2. Явное подключение



Самое забавное в этом проекте - согласно книге [6] он (как и предыдущий) НЕ ДОЛЖЕН РАБОТАТЬ (но работает. Возможно, я что-нибудь не дочитал :-(). Подробнее об этом см в конце предыдущей страницы

Так как проект самой библиотеки POISKLIB остается без изменений, обсудим только приложение Poisk, импортирующее подпрограмы RandomData и CalcMax, экспортируемые этой библиотекой.

В связи с тем, что способ подключения изменился, модуль UnPoiskIntface стал почти не нужен (используется только описание типов TPointFloat и TCoord). Описания TPointFloat и TCoord перенес в интерфейсную часть модуля unPokaz, а модуль UnPoiskIntface удаляю из проекта (меню Делфи | Project | Remove from Project). Затем файл можно удалить из папки. Явное подключение библиотеки производится с использованием функций WinAPI LoadLibrary (загрузить библиотеку), GetProcAddress (получить адрес процедуры) и FreeLibrary (отключить библиотеку). Описан и используется класс исключений ELoadDLL - для реагирование на ошибку (библиотека не подключается - например, не найден файл POISKLIB.DLL)

Запуск каждой подпрограммы состоит из таких элементов:

Рассмотрим текст приложения:
unit unMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Menus, unPokaz;

type
  TfrmMain = class(TForm)
    MainMenu1: TMainMenu;
    Vvod: TMenuItem;
    Random: TMenuItem;
    Solve: TMenuItem;
    Quit: TMenuItem;
    Pokaz: TMenuItem;
    Label1: TLabel;
    edCount: TEdit;
    Label2: TLabel;
    edminX: TEdit;
    Label3: TLabel;
    edmaxX: TEdit;
    Label4: TLabel;
    edminY: TEdit;
    Label5: TLabel;
    edmaxY: TEdit;
    btnNew: TMenuItem;
    procedure RandomClick(Sender: TObject);
    procedure QuitClick(Sender: TObject);
    procedure PokazClick(Sender: TObject);
    procedure SolveClick(Sender: TObject);
    procedure btnNewClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TRandomData = procedure(NumPoints: integer; MinX,MaxX,MinY,MaxY: double;
   var Coord: TCoord); StdCall; //Создаем тип процедуры
  TCalcMax = function (NumPoints: integer; MinX,MaxX,MinY,MaxY: double;
  var Coord: TCoord; var N1,N2: integer {номера заданных точек}):word;  StdCall;

  ELoadDLL = class (Exception);

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

var
  NPoints, NN1, NN2: integer;
  MinX1,MaxX1,MinY1,MaxY1: double;
  Coord1: TCoord;
  Buf: word;

procedure TfrmMain.RandomClick(Sender: TObject);
var LibHnd: THandle;
    RandomData: TRandomData;
begin
  NPoints:= StrToInt(edCount.Text);
  MinX1:= StrToFloat(edminX.Text);
  MaxX1:= StrToFloat(edmaxX.Text);
  MinY1:= StrToFloat(edminY.Text);
  MaxY1:= StrToFloat(edmaxY.Text);
  
if MaxX1 <= MinX1 then
  begin
    showmessage('MaxX > MinX !');
    exit;
  end;

if MaxY1 <= MinY1 then
  begin
    showmessage('MaxY > MinY !');
    exit;
  end;

  SetLength(Coord1, NPoints);
  Randomize;

 { *********** подключение процедуры RandomData из POISKLIB.DLL ************ }
  LibHnd:= LoadLibrary('POISKLIB.DLL');
  try
  if LibHnd = 0 then
    raise ELoadDLL.Create('Не удалось загрузить POISKLIB.DLL');
    @RandomData:= GetProcAddress(LibHnd,'RandomData');
    if not (@RandomData = nil) then
      begin
        RandomData(NPoints,MinX1,MaxX1,MinY1,MaxY1,Coord1);
        Solve.Enabled:= true;
        edCount.Enabled:= false;
        edminX.Enabled:= false;
        edmaxX.Enabled:= false;
        edminY.Enabled:= false;
        edmaxY.Enabled:= false;
      end
      else RaiseLastWin32Error;
  finally
    FreeLibrary(LibHnd);
  end;
 { ************                      ************************* }
end;

procedure TfrmMain.QuitClick(Sender: TObject);
begin
  Application.Terminate;
end;

procedure TfrmMain.PokazClick(Sender: TObject);
begin
 ShowGraphPoints(NPoints,MinX1,MaxX1,MinY1,MaxY1,Coord1,0,0);
end;

procedure TfrmMain.SolveClick(Sender: TObject);
var LibHnd: THandle;
    CalcMax: TCalcMax;
begin
 { *********** подключение функции CalcMax из POISKLIB.DLL ************ }
  LibHnd:= LoadLibrary('POISKLIB.DLL');
  try
  if LibHnd = 0 then
    raise ELoadDLL.Create('Не удалось загрузить POISKLIB.DLL');
    @CalcMax:= GetProcAddress(LibHnd,'CalcMax');
    if not (@CalcMax = nil) then
        begin Buf:= CalcMax(NPoints,MinX1,MaxX1,MinY1,MaxY1,Coord1,NN1,NN2);
            ShowGraphPoints(NPoints,MinX1,MaxX1,MinY1,MaxY1,Coord1,NN1,NN2);
        end
      else RaiseLastWin32Error;
  finally
    FreeLibrary(LibHnd);
  end;
end;

procedure TfrmMain.btnNewClick(Sender: TObject);
begin
  edCount.Enabled:= true;
  edminX.Enabled:= true;
  edmaxX.Enabled:= true;
  edminY.Enabled:= true;
  edmaxY.Enabled:= true;
  Coord1:= nil; 
end;

end.

 ----------------------- 

unit unPokaz;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TfrmPokaz = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TPointFloat = record
    X,Y: single;
    end;
  TCoord = array of TPointFloat;

var
  frmPokaz: TfrmPokaz;

procedure ShowGraphPoints(NumPoints: integer; MinX,MaxX,MinY,MaxY: double;
 var Coord: TCoord; N1,N2: integer);

implementation

{$R *.dfm}

procedure ShowGraphPoints(NumPoints: integer; MinX,MaxX,MinY,MaxY: double;
var Coord: TCoord; N1,N2: integer);
var ii,XX,YY: integer;
  ax,bx,ay,by: double;
  { коэффициенты линейного преобразования реальных координат
    в экранные: Хэкр := ax*Хреал + bx; такие, что
    Хэкр(Xmin) = 0; Хэкр(Xmax) = ширина формы.
    Yэкр := ay*Yреал + by;
    Yэкр(Ymin) = высота формы; Yэкр(Ymax) = 0.
    a,b - определяются из решения СЛАУ, записанных выше 
  }
begin
//  showmessage('Показ точек - график');
 ax:= frmPokaz.ClientWidth/(MaxX-MinX);
 bx:= ax*MinX;
 ay:= frmPokaz.ClientHeight/(MinY - MaxY);
 by:= -ay*MaxY;

 with frmPOkaz do
   begin
     Canvas.Pen.Width:=2;
     Canvas.Pen.Color:= clGreen;
     Color:= clBlack;
     Canvas.FillRect(ClientRect);
     Show;
     for ii:= 0 to NumPoints - 1 do
       begin
       XX:= Round(ax*Coord[ii].X + bx);
       YY:= Round(ay*Coord[ii].Y + by);

       Canvas.Pixels[XX,YY ]:= RGB(200,200,200);
       Canvas.Pixels[XX+1,YY ]:= RGB(200,200,0);
       Canvas.Pixels[XX+1,YY+1 ]:= RGB(0,200,200);
       Canvas.Pixels[XX,YY+1 ]:= RGB(200,0,200);
       end;
      if N1<>N2 then
        begin
          XX:= Round(ax*Coord[N1].X + bx);
          YY:= Round(ay*Coord[N1].Y + by);
          Canvas.Ellipse(XX-5,YY-5,XX+5,YY+5);
          XX:= Round(ax*Coord[N2].X + bx);
          YY:= Round(ay*Coord[N2].Y + by);
          Canvas.Ellipse(XX-5,YY-5,XX+5,YY+5);
        end;
   end;
end;

end.
Скачать RAR-архив исходника + .exe(0.23 Mб)
Rambler's Top100
Hosted by uCoz