|
DLL
Nedir?
DLL (Dynamic Link Library) yani dinamik link kütüphaneleri olarak isimlendirilen
dosyalar Windows'un en önemli parçalarından birisidir. Bir DLL dosyası .exe gibi
çalıştırılabilir bir programın icrası anında çağırabileceği fonksiyonları
barındırmaktadır.
Yani diğer bir değişle dll, programların dinamik olarak bağlantı kurabileceği
fonksiyonların bir kütüphanesidir.
Bağlantılar statik ve dinamik olmak üzere ikiye
ayrılmaktadır:
1-) Statik bağlantılar icra sırasında değişmezler ve programınızın icrası
sırasında kütüphane içindeki
fonksiyonlara erişim için gerekli tüm adres bilgileri icra edilebilir dosya
derlendiği sırada
belirlenmiştir ve sabittir.
2-) Dinamik bağlantılar ise sadece gerektiği zaman kurulurlar. Eğer programınız
ihtiyaç duyduğu bir
fonksiyonu kendi içinde bulamazsa o zaman Windows gerekli dll'i yükler ve
içindeki fonksiyonları
programınızın emrine verir. Bu sırada Windows dll içindeki tüm
fonksiyonların adreslerini çözümler
ve dinamik olarak programınız arasında bağlantı kurulmasını sağlar.
Örneğin Visual Basic içinde kullanılan tüm özel kontroller birer dll'dir. Tek
farkı sadece Visual Basic tarafından işlenen mesajların kendine özgü işlem
gerektirmesidir.
Neden DLL kullanılır?
Dll neden kullanmamız gerektiğini 4 ana başlık altında toplayabiliriz.
- C İcra anı (Run-Time) fonksiyonlarına erişim:
C İcra anı kütüphanesi Visual Basic programcılarına bahşedilmeyen bir çok
yararlı fonksiyonları barındırır. Örneğin _dos_getdiskfree fonksiyonu diskteki
mevcut boş alanı hesaplamak için kullanılmaktadır.
- Windows API'ye (Uygulama Programlama Arayüzü) Erişim:
Bazı Windows API fonksiyonları "Callback" özelliğine sahiptir. Yani bunu
açıklamak gerekirse API çağrısının işlenmesi sırasında Windows'un o fonksiyonu
rekürsif olarak yani tekrarlı olarak çağırması diyebiliriz. Buna örnek olarak "EnumTaskWindows"
fonksiyonunu verebiliriz. Bu fonksiyon o anda icra edilen görevlerin
sahiplendiği pencerelerin "handle" yani bir çeşit tanımlayıcısını geri
döndürmede kullanılır diyebiliriz.
- Hız:
C, 0 ve 1 gibi doğal makine diline en yakın programlama dillerinden biridir. Bu
programlarınızın eğer doğru olarak kodlanmış ise c dilinde en hızlı olarak
çalışacağı anlamına gelmektedir.
- Kullanılacağı zaman yüklenme:
Bir dll içindeki kod veya veri sadece gerektiği zaman belleğe alınır. Bu
programların ihtiyaç duyduğu bellek miktarının düşük olmasını sağlamakla beraber
yüklenme süresini azaltırlar.
Bir Dll'in Anatomisi
Her dll, çalıştırılabilir dosyalar tarafından kullanılabilmesi için
içinde mutlaka bir LibMain fonksiyonu ve Windows Çıkış Prosedürü(WEP)
bulundurması gerektirmektedir.
- LibMain:
Bir DLL yukarıda da belirtildiği gibi mutlaka LibMain fonksiyonu barındırması
gerekir. LibMain fonksiyonu DLL'in yüklenmesini isteyen ilk program tarafından
çağırılır ve aşağıdaki açıklanan parametreler bu fonksiyona aktarılır:
- HANDLE : DLL örneğinin handle değerini belirtir.
- WORD : Kütüphane'nin veri segmentini belirtir.
- WORD : Yığın boyutu
- LPSTR : Komut satırı parametreleri
-WEP:
WEP(Windows Çıkış Prosedürü) bir dll'in bellekte artık görevi bittiğinde
temizlenmesi işlemini gerçekleştirir. Windows işletim sistemlerinde her dll
içinde bir tane WEP fonksiyonu gereklidir. Windows 3.1 için bu seçimliktir. Bir
WEP fonksiyonu Visual C'de modül tanımlama dosyasında (.DEF) aşağıdaki gibi
bulunmalıdır.
EXPORTS
WEP
- İhraç edilmiş Fonksiyonlar:
Bu fonksiyonlar sizin DLL içinden çağırmak istediğiniz fonksiyonlardır. Bunlar
geriye doğru uyumluluk sağlamak için _export._export ile gösterilir. Ayrıca
çağırmak istediğiniz tüm fonksiyonlar dll'inizin (.DEF) dosyası içinde
listelenmiş olması gerekmektedir.
DLL Bellek Yönetimi Konuları
Geniş bellek modelinde C, statik veya global tüm değişkenleri (Bir fonksiyon
dışında tanımlanmış) programın yığın boşluğunda saklar. Diğer değişkenleri de
yığın(Stack) da saklar.
Küçük ve orta bellek modelinde ise tüm işaretçiler(Pointers) geçerli olarak near
özelliğindedir. Bu veri segmenti (DS) kayıtçısına veya yığın segmenti (SS)
kayıtçısına 16-bit ofset değerleriyle ulaşılacağını belirtir. Ne yazık ki
derleyiciye bunun DS' ten mi yoksa SS' ten gelen bir ofset mi olduğunu anlatmak
için bir yol yoktur. Birçok programda DS ve SS aynı segmenti işaret ettiği için
bu bir problem olmaz. Bununla birlikte dll özel bir durumdur.
Bir DLL kendi veri segmentine sahiptir fakat yığınını çağıran program ile
birlikte ortaklaşa kullanır. Bu DS ve SS'in aynı konuma işaret etmeyeceğini
anlamına gelmektedir. Bu problemi çözmenin en kolay yolu DLL'i tüm değişkenlerin
32-bit değerleriyle referans verildiği geniş bellek modelini kullanmaktır.
Neden Bellek Dinamik olarak Tahsis edilir?
Belleği dinamik olarak tahsis etmek Windows'a özgü bir yöntemdir. Büyük
boyutta veriyi bir dizi içinde deklare etmek hem programınızın 64k'lik yığınını
hem de program veri segmentinin dolmasına neden olur ve bununla birlikte disk ve
bellek boşluğu boşuna doldurulmuş olur. En iyisi ihtiyaç olduğu zaman belleği
doldurmak ve işimiz bittiğinde de belleği boşaltmaktır.
Bellek Tahsisi
Windows'ta dinamik olarak lokal ve global olmak üzere iki şekilde bellek
tahsis edebilirsiniz. Lokal bellek 64k ile sınırlandırılmıştır ve DLL' de lokal
bellek dll'i çağıran program ile birlikte paylaştırılır. Global bellek Windows
yüklendikten sonra geriye kalan mevcut bellektir.
Lokal bellek, LocalAlloc, LocalLock, LocalUnlock
ve LocalFree
fonksiyonları tarafından tahsis edilir ve yönetilir. Örneğin;
char* pzsBuffer;
....
pzsBuffer = (char*) LocalAlloc (LPTR, 20);
....
LocalFree (pzsBuffer);
Lokal belleği tahsis etmek global belleği tahsis etmekten daha hızlıdır. Fakat
lokal yığından bellek tahsisi 64k ile sınırlandırılmıştır ve DLL'i çağıran tüm
programlar arasında paylaştırılmıştır. Lokal belleği küçük miktarda bellek
blokları ihtiyaç olduğunda kullanmak en iyisidir.
Global bellek, GlobalAlloc, GlobalLock,
GlobalUnlock ve GlobalFree fonksiyonları
tarafından tahsis edilir ve yönetilir. Örneğin;
HGLOBAL hglb;
char* pszBuffer;
hglb = GlobalAlloc (GHND, 2048);
// GHND belleği taşınabilir ve 2048 birim büyüklüğünde tahsis eder.
pszBuffer = GlobalLock (hglb);
....
GlobalUnlock (hglb);
GlobalFree (hglb);
GlobalAlloc fonksiyonu belleği 4K'nın katları şeklinde tahsis eder. Eğer DLL ile
diğer programlar arasında tahsis edilmiş belleği paylaştırmak isterseniz o zaman
GMEM_SHARED bayrağını, eğer DDE üzerinden belleği paylaştırmak isterseniz GMEM_DDESHARE
bayrağını kullanarak tahsis etmeniz gerekir.
Statik değişkenlerde veri saklarken dikkatli olunması gereklidir. Eğer bir DLL
içinde global veya statik değişkenlerde veri saklayacaksanız bu değişkenlerin
DLL'i bir sonraki çağırışınızda değişmiş olabileceğini göz önünde
bulundurmalısınız. Çünkü bu şekilde veri saklanması DLL'i kullanan tüm
uygulamalara bu değişkenlerin açık olmasını sağlamaktadır. Bir DLL'i kaç
uygulamanın kullandığı önemli değildir her zaman DLL'in bir örneği vardır.
Dosya Tanımlayıcı(Handle) Değerleri:
Uygulamalar ve DLL'ler arasında dosya handle değerlerini paylaştırmak mümkün
değildir. Yani her uygulama bir dosyayı bir dll kullanarak okumak isterse kendi
dosya-handle tablosunu kullanmalı ve dosyayı özel olarak açmaları gerekmektedir.
Visual Basic içinden DLL çağırma:
Visual Basic'de DLL içindekiler de dahil olmak üzere çağırmak istediğiniz
tüm fonksiyonlar önce deklare edilmesi gerekmektedir. Fonksiyonları bir formun
veya modülün içinde deklare edebilirsiniz. Eğer bir fonksiyonu veya DLL
prosedürünü form içinde tanımlarsanız bunlar sadece o Form içinden
çağırılabilir. Bunların her yerden kullanılabilmesi yani 'Public' yapabilmek
için herhangi bir modül içinde tanımlamanız gerekir. Örnek bir deklarasyon
satırı aşağıda verilmiştir:
Declare Sub getdiskinfo Lib "c:\somepath\diskinfo.dll" (Byval mydrive As String,
Byval myvolume As String, free As Long)
Yukarıda iki satır olarak görülen örneği Visual Basic içinde tek satır olarak
yazmanız gerekmektedir. Fonksiyonu bir kez tanımladığınızda bu fonksiyonu normal
Visual Basic fonksiyonu gibi kullanabilirsiniz.
DLL parametreleri:
DLL genel olarak C dilinde yazıldığı için DLL'ler Visual Basic dili
tarafından desteklenmeyen bir çok parametreden birini alabilir. Bu yüzden DLL
fonksiyonuna parametreleri aktarırken ona uygun veri yapısını bilmek
gerekmektedir.
Argümanları Değerleri veya Referanslarıyla
Aktarma:
Visual basic aksi belirtilmedikçe tüm argümanları 32 bitlik adres referansı ile
aktarır. Bununla birlikte birçok DLL argümanları değerleri ile almak ister. Bunu
argüman tanımının başında Byval kelimesini kullanarak gerçekleştirebilirsiniz.
Aşağıdaki bölüm parametreleri Visual Basic'e göre nasıl dönüştüreceğinizi
göstermektedir.
8-16 bit Nümerik Parametreleri (int, short, unsigned int, unsigned short, BOOL
ve word) Integer olarak
32 bit Nümerik Parametreleri (long, unsigned long ve DWORD) Long olarak
çevirebilirsiniz.
Nesne
Handle değerleri:
Tüm handle değerleri ilişkili olduğu pencere ile tekil ve 16bit' dir. Ayrıca
değeri ile aktarılırlar. Bu yüzden bu parametreleri Integer olarak aktarmanız
gerekmektedir.
String'ler:
LPSTR ve LPBYTE veri yapılarına sahip stringleri parametre olarak aktarırken
Byval parametre_adi As String olarak aktarın. DLL fonksiyonları Visual Basic
stringlerini geri döndürememektedir. Ama bazen API fonksiyonlarını kullanıp
LPSTR olarak Visual Basic String'ine aktarılabilir. Visual Basic stringlerini
direkt olarak aktarmak için (param As String) kullanabilirsiniz.
Not: Visual Basic string'lerinin yapısı farklı olduğu için DLL için gerçekten
gerekli olduğundan emin olmadıkça stringleri direkt olarak aktarmayın.
Structure'lar:
Eğer Visual Basic kullanıcı tanımlı yapı, DLL tarafından beklenen şekilde ise
yapı, referansı ile aktarılabilir.
Not: Structure'lar değerleri ile aktarılamaz.
Null Pointer'lar:
Eğer DLL bir Null pointer bekliyorsa o zaman onu (Byval
parametre_adi As Any) olarak aktarabilirsiniz. Parametre değeri yerine &0 veya
&0h kullanabilirsiniz.
DLL kullanırken karşılaşılan bazı problemler:
Sistem Kaynaklarının DLL Çağırdıktan Sonra
Azalması:
Eğer DLL GDI nesnelerini kullanıyor ise DLL'in kullanımından sonra serbest
bırakılması gerekmektedir. Örneğin Windows SDK (Software development Kit)
kullanırken bir GDI nesnesi oluşturursanız (mesela CreateBrushIndirect) daha
sonra kullanımı bitince DeleteObject kullanarak silmeniz gerekmektedir.
Bad DLL Calling Convention Hatası:
Bu hata genellikle Deklare satırında ByVal kelimesini hatalı şekilde kullanma
veya hiç kullanmamak yüzünden meydana gelmektedir. Bu hata ayrıca yanlış
parametreler aktarıldığında da meydana gelmektedir.
DLL
yüklenmesi sırasındaki hata:
Bu hata bir dinamik link kütüphane prosedürü çağırdığınızda prosedürün
tanımlandığı satırdaki dosyanın yüklenememesi yüzünden meydana gelmektedir.
Microsoft Windows API fonksiyonlarından LoadLibrary fonksiyonunu kullanarak
DLL'in neden yüklenmediği konusunda ayrıntılı bilgi elde edebilirsiniz.
Programlar:
DLLView for Windows 9x: Bu programla o anda hafızada çalışan veya yüklenmiş
olan DLL'lerin listesini görebilirsiniz.
|