Skip to content
lokakuu 21, 2006 / Jussi

Modulaarisia ohjelmia Delphillä

Näin lauantaialkuillan iloksi päätin tutustua mieltäni silloin tällöin kutkuttaneeseen ongelmaan: kuinka tehdään modulaarisia, laajennettavia ohjelmia Delphillä? Takoituksena oli siis saada aikaan ohjelma, johon pystyisi lisäämään mitä tahansa toiminnallisuutta myös kolmannen osapuolen toimesta, vähän Mozilla-ohjelmien laajennusten tapaan (tosin ei suinkaan yhtä laajasti).

Päätin ottaa alkuaskeleeksi yksinkertaisen tapauksen: toimenpide, joka suorittaa kahdelle kokonaisluvulle jonkin operaation ja palauttaa yhden kokonaisluvun, esimerkkinä nyt vaikka yhteen- ja kertolasku. Hieman tutkimusta tehtyäni löysinkin lupaavan kuuloisen menetelmän: eksplisiittinen linkitys, joka hyödyntää DLL:iä. Normaalistihan DLL:istä tuotujen funktioiden käyttäminen on jokseenkin automaattista, esittelyn perään pitää vain lisätä direktiivi external DLLn_nimi;. Tämä mahdollistaa kuitenkin vain yhden DLL:n käyttämisen, ja sen nimi täytyy tietää etukäteen.

Eksplisiittisessä dynaamisessa linkityksessä voi määrätä ajonaikaisesti linkitettävän DLL:n nimen, pyytää linkitystä käyttöjärjestelmältä, etsiä tarvittavien funktioiden osoitteen muistista, käyttää funktioita ja lopuksi poistaa DLL:n muistista – mikä kuulosti juuri sopivalta tähän tarkoitukseen. Eksplisiittisestä linkityksestä vastaavat funktiot ovat LoadLibrary(LibName: PChar): THandle, GetProcAddress(LibHandle: THandle; ProcName: PChar): Pointer sekä FreeLibrary(LibHandle: THandle). Pienen näpertelyn jälkeen syntyivät seuraavat ohjelman osat.

Moduletest.pas tuottaa ohjelman, jossa voi valita haluamansa dll:n käytettäväksi sekä antaa parametrit.

unit moduletest;

interface

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

type
  TForm1 = class(TForm)
    Op1: TEdit;
    Op2: TEdit;
    Button: TButton;
    ResultBox: TEdit;
    ModList: TFileListBox;
    procedure ButtonClick(Sender: TObject);
  end;

type TOperationFunc = function(Op1: Integer; Op2: Integer): Integer;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ButtonClick(Sender: TObject);
var
  Handle: THandle;
  Retval: Integer;
  OpFunc: TOperationFunc;
begin
  Handle := LoadLibrary(PChar(ExtractFilePath(Application.ExeName) + '\\' +
      ModList.Items[ModList.ItemIndex]));
  if (Handle  0) then
  begin
    @OpFunc := GetProcAddress(Handle, 'Operate');
    if (@OpFunc <> nil) then
    begin
      Retval := OpFunc(StrToInt(Op1.Text), StrToInt(Op2.Text));
      ResultBox.Text := IntToStr(Retval);
    end;
    FreeLibrary(Handle);
  end;
end;

end.

Addition.pas, joka tuottaa yhteenlaskun suorittavan addition.dll:n

library addition;

uses
  SysUtils,
  Classes;

{$R *.res}

function Operate(Op1: Integer; Op2: Integer): Integer;
begin
  Operate := Op1 + Op2;
end;

exports
Operate;

begin
end.

Viimeiseksi multipl.pas, joka on lähes sama kuin addition, muutoksena vain se, että operaatio on nyt kertolasku

library multipl;

uses
  SysUtils,
  Classes;

{$R *.res}

function Operate(Op1: Integer; Op2: Integer): Integer;
begin
  Operate := Op1 * Op2;
end;

exports
Operate;

begin
end.

Ja tämä toimii juuri niin kuin pitääkin!

Vastaa

Täytä tietosi alle tai klikkaa kuvaketta kirjautuaksesi sisään:

WordPress.com-logo

Olet kommentoimassa WordPress.com -tilin nimissä. Log Out / Muuta )

Twitter-kuva

Olet kommentoimassa Twitter -tilin nimissä. Log Out / Muuta )

Facebook-kuva

Olet kommentoimassa Facebook -tilin nimissä. Log Out / Muuta )

Google+ photo

Olet kommentoimassa Google+ -tilin nimissä. Log Out / Muuta )

Muodostetaan yhteyttä palveluun %s

%d bloggers like this: