![]() |
DLL dengan Delphi | Nov 13, ’09 10:18 AM for everyone |
Baru belajar DLL niy ceritanya.. Udah tua begini belajar DLL. Mungkin buat teman-teman yang sudah berkesempatan belajar dan bertahun-tahun bermain-main dengannya hanya tersenyum simpul melihat saya baru belajar DLL. Hare gene??
Tapi tidak mengapa. Islam mengajari bahwa hidup adalah belajar. Minal madi, ilal lahdi. Dari buaian hingga liang kubur. Selama belum ada bendera kuning, kita mesti terus belajar, dan lebih baik lagi, berbagi dengan sesama. Toh kita bisa belajar karena ada orang lain yang mendahului kita belajar dan berbagi ilmu kan? Kita tahu karena ada orang yang berbagi kepada kita. Itulah yang coba saya lakukan. Karena saya tidak ingin menunggu bertahun-tahun sebelum membagikannya, saya mencoba menuliskannya sekarang. Jika ada teman-teman yang ingin mengoreksi atau menambahkan, saya dengan senang hati akan menerimanya sebagai tambahan proses belajar itu sendiri.
Buat teman-teman yang tidak tertarik dengan dunia pemrograman, tidak perlu meneruskan untuk membaca tulisan ini, silakan ke http://wishknew.multiply.com/tag/movies untuk membaca tulisan saya tentang hobi saya yang lain, menonton film.
Ok, DLL adalah sebuah file yang biasa terdapat di platform sistem operasi berbasis Windows dari Microsoft, merupakan singkatan dari Dynamic Link Library. Sejarah lengkap DLL bisa dibaca di http://en.wikipedia.org/wiki/.dll. Intinya DLL menyediakan mekanisme bagi programmer untuk berbagi kode program, resource, maupun data atau kombinasinya untuk program lain yang membutuhkan hal yang sama. Dalam kasus saya kali ini, saya mempunyai sebuah kelas di Delphi yang algoritmanya bertumbuh. Jika suatu ketika nanti saya ingin menyempurnakan algoritmanya tanpa mengubah antarmukanya, saya ingin hanya memperbaharui sebagian kecil program saya, tidak seluruhnya. Nah hal ini dimungkinkan apabila kelas yang saya buat itu disimpan di sebuah DLL. Jika lain kali saya ingin memperbaharui implementasinya atau melakukan perbaikan kesalahan (bugs), maka saya tidak perlu mendistribusikan aplikasi executablenya selurunhya sekaligus. Saya bisa memperbaharui hanya DLLnya saja.
Itu idenya. Ok, sekarang bagaimana membuatnya? Seperti biasa, duduk manis di depan laptop, bertanya kepada Mbah Google. Mbah memberi banyak sekali petunjuk. Salah satu di antaranya ada di delphi.about .com yaitu http://delphi.about.com/od/windowsshellapi/a/dll_basics.htm dan juga ada di http://delphi.about.com/library/weekly/aa010901a.htm yang membandingkannya dengan BPL (Borland Package Library). BPL disebut lebih cocok jika memang kita selalu menggunakan Delphi. Nah jadinya bingung deh mau memilih DLL atau BPL. Akhirnya bertanya lagi ke stackoverflow di http://stackoverflow.com/questions/1700366/loading-a-delphi-object-run-time-using-bpl
Wah dari sebagian besar mereka justru tidak menganjurkan menggunakan BPL karena tergantung versi Delphinya. Lebih banyak mudharat daripada manfaat kata mereka. Ya sudah. Kita ikuti kata mereka-mereka, dan sekarang tambah yakin mau mencoba menggunakan DLL.
Dari petunjuk mereka, kuncinya adalah membuat sebuah fungsi yang mengembalikan instance dari sebuah interface. Nah itulah yang dicoba. Dan alhamdulillah berhasil, thanx to Riza yang dah nemenin mencoba-coba membuatnya.
library TestDLL;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library’s USES clause AND your project’s (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL–even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
ShareMem,
SysUtils,
Classes;
{$R *.res}
type
THelloWorld = class(TObject)
public
class function SayHelloWorld: TStringBuilder; stdcall;
end;
{ THelloWorld }
function HelloWorld: TStringBuilder; stdcall;
begin
Result := THelloWorld.SayHelloWorld;
end;
class function THelloWorld.SayHelloWorld: TStringBuilder;
begin
Result := TStringBuilder.Create;
Result.Append(‘Hello World’);
Result.Append(#13#10 + ‘Hurray…’);
end;
exports HelloWorld;
begin
end.
·Kode di atas merupakan program untuk membentuk DLL. Strukturnya mirip file Delphi Project yang biasa kita dapatkan ketika membuat project baru. Bedanya kalau project diawali dengan kata kunci Program sedangkan DLL diawali dengan Library
·Pastikan semua fungsi yang akan dibuat publik di DLL memiliki tambahan kata kunci stdcal dan nanti pas akan dipanggil juga harus sama. Kalau kelupaan, bisa gak jalan!
Contoh:
function HelloWorld: TStringBuilder; stdcall; //awas case sensitive
·Di bagian bawah program sebutkan semua fungsi yang akan diexport, contoh:
exports HelloWorld;
Ok sekarang kita buat contoh di mana kita menggunakan interface, karena di kelas yang akan menggunakan object DLL, kita tidak punya skeleton dari definisi kelasnya. Karenanya kita perlu bantuan interface, sebangsa kelas abstract yang merupakan kontrak mati bagi semua kelas yang mengimplementasikannya untuk mengimplementasikan semua fungsi dalam interface tersebut.
Kelas DLL kita akan berupa:
library DLLNoHell;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library’s USES clause AND your project’s (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL–even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
SysUtils,
Classes,
unitInterface,
Dialogs;
type
B = class(TInterfacedObject, IB)
public
procedure HelloB;
end;
A = class(TInterfacedObject, IA)
public
procedure HelloA;
function GetB: IB;
end;
{$R *.res}
{ B }
procedure B.HelloB;
begin
showMessage(‘I am B’);
end;
{ A }
function A.GetB: IB;
begin
Result := B.Create;
end;
procedure A.HelloA;
begin
ShowMessage(‘I am A’);
end;
function GetInstanceOfA: IA; stdcall;
begin
Result := A.Create;
end;
exports GetInstanceOfA;
begin
end.
Unit interface kita berupa:
unit unitInterface;
interface
uses Classes;
type
IB = interface
procedure HelloB;
end;
IA = interface
procedure HelloA;
function GetB: IB;
end;
implementation
end.
Dan kelas tester yang kita miliki:
unit unitTester;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, unitInterface, StdCtrls;
type
TForm4 = class(TForm)
Label1: TLabel;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
function GetInstanceOfA: IA stdcall; external ‘DLLNoHell.dll’;
implementation
{$R *.dfm}
procedure TForm4.FormCreate(Sender: TObject);
var
instanceA: IA;
instanceB: IB;
begin
instanceA := GetInstanceOfA;
instanceA.HelloA;
instanceB := instanceA.GetB;
instanceB.HelloB;
end;
end.
Perhatikan kata kunci stdcall harus sama persis dengan yang ada di DLL. Melupakan stdcall akan menyebabkan kegagalan mencari fungsi yang dimaksud. Ok.. semoga cukup jelas.
Kalau ada yang ingin menambahkan atau bertanya please feel free to do so.