DLL - Hızlı Kılavuz

Dinamik bağlama, uygulamaları çalışma zamanında kitaplıklara bağlayan bir mekanizmadır. Kitaplıklar kendi dosyalarında kalır ve uygulamaların çalıştırılabilir dosyalarına kopyalanmaz. DLL'ler, uygulama oluşturulduğunda değil çalıştırıldığında bir uygulamaya bağlanır. DLL'ler, diğer DLL'lere bağlantılar içerebilir.

Çoğu zaman DLL'ler, .exe, .DRV veya .DLL gibi farklı uzantılara sahip dosyalara yerleştirilir.

DLL'nin Avantajları

Aşağıda, DLL dosyalarına sahip olmanın birkaç avantajı verilmiştir.

Daha az kaynak kullanır

DLL dosyaları, ana programla birlikte RAM'e yüklenmez; gerekmedikçe yer kaplamazlar. Bir DLL dosyası gerektiğinde, yüklenir ve çalıştırılır. Örneğin, bir Microsoft Word kullanıcısı bir belgeyi düzenlediği sürece, RAM'de yazıcı DLL dosyası gerekli değildir. Kullanıcı belgeyi yazdırmaya karar verirse, Word uygulaması yazıcı DLL dosyasının yüklenmesine ve çalıştırılmasına neden olur.

Modüler mimariyi destekler

Bir DLL, modüler programların geliştirilmesine yardımcı olur. Birden çok dil sürümü gerektiren büyük programlar veya modüler mimari gerektiren bir program geliştirmenize yardımcı olur. Modüler bir programa bir örnek, çalışma zamanında dinamik olarak yüklenebilen birçok modüle sahip bir muhasebe programıdır.

Kolay dağıtım ve kurulum için yardım

DLL içindeki bir işlev bir güncellemeye veya düzeltmeye ihtiyaç duyduğunda, DLL'nin dağıtımı ve yüklenmesi, programın DLL ile yeniden bağlanmasını gerektirmez. Ek olarak, birden fazla program aynı DLL'yi kullanıyorsa, tümü güncellemeden veya düzeltmeden yararlanır. Bu sorun, düzenli olarak güncellenen veya düzeltilen bir üçüncü taraf DLL kullandığınızda daha sık ortaya çıkabilir.

Derlemenin bir parçası olarak modül tanımlama dosyasının IMPORTS bölümünde DLL bağlantısı belirtilmişse, uygulamalar ve DLL'ler diğer DLL'lere otomatik olarak bağlanabilir. Aksi takdirde, bunları Windows LoadLibrary işlevini kullanarak açıkça yükleyebilirsiniz.

Önemli DLL Dosyaları

  • COMDLG32.DLL - İletişim kutularını kontrol eder.

  • GDI32.DLL - Grafik çizmek, metni görüntülemek ve yazı tiplerini yönetmek için çok sayıda işlev içerir.

  • KERNEL32.DLL - Hafızanın yönetimi ve çeşitli süreçler için yüzlerce işlev içerir.

  • USER32.DLL- Çok sayıda kullanıcı arabirimi işlevi içerir. Program pencerelerinin oluşturulmasına ve birbirleriyle etkileşimlerine katılır.

İlk olarak, kendi DLL'lerinizi geliştirirken göz önünde bulundurmanız gereken sorunları ve gereksinimleri tartışacağız.

DLL türleri

Bir uygulamaya bir DLL yüklediğinizde, iki bağlama yöntemi dışa aktarılan DLL işlevlerini çağırmanıza izin verir. İki bağlama yöntemi şunlardır:

  • yükleme süresi dinamik bağlama ve
  • çalışma zamanı dinamik bağlama.

Yükleme zamanı dinamik bağlama

Yükleme zamanı dinamik bağlamada bir uygulama, yerel işlevler gibi dışa aktarılan DLL işlevlerine açık çağrılar yapar. Yükleme zamanı dinamik bağlamayı kullanmak için, uygulamayı derleyip bağladığınızda bir başlık (.h) dosyası ve bir içe aktarma kitaplığı (.lib) dosyası sağlayın. Bunu yaptığınızda, bağlayıcı, sisteme DLL'yi yüklemek ve dışa aktarılan DLL işlevi konumlarını yükleme anında çözmek için gereken bilgileri sağlayacaktır.

Çalışma zamanı dinamik bağlama

Çalışma zamanı dinamik bağlamada, bir uygulama DLL'yi çalışma zamanında yüklemek için LoadLibrary işlevini veya LoadLibraryEx işlevini çağırır. DLL başarıyla yüklendikten sonra, aramak istediğiniz dışa aktarılan DLL işlevinin adresini almak için GetProcAddress işlevini kullanırsınız. Çalışma zamanı dinamik bağlantısını kullandığınızda, bir içe aktarma kitaplık dosyasına ihtiyacınız yoktur.

Aşağıdaki liste, yükleme zamanı dinamik bağlama ve çalışma zamanı dinamik bağlama arasında seçim yapmak için uygulama kriterlerini açıklar:

  • Startup performance : Uygulamanın başlangıçtaki performansı önemliyse, çalışma zamanı dinamik bağlamayı kullanmalısınız.

  • Ease of use: Yükleme zamanı dinamik bağlamada, dışa aktarılan DLL işlevleri yerel işlevler gibidir. Bu işlevleri kolayca çağırmanıza yardımcı olur.

  • Application logic: Çalışma zamanı dinamik bağlamada, bir uygulama gerektiğinde farklı modülleri yüklemek için dallara ayrılabilir. Bu, çoklu dil sürümleri geliştirirken önemlidir.

DLL Giriş Noktası

Bir DLL oluşturduğunuzda, isteğe bağlı olarak bir giriş noktası işlevi belirtebilirsiniz. İşlemler veya iş parçacıkları kendilerini DLL'ye eklediklerinde veya kendilerini DLL'den ayırdıklarında giriş noktası işlevi çağrılır. Veri yapılarını DLL'nin gerektirdiği şekilde başlatmak veya yok etmek için giriş noktası işlevini kullanabilirsiniz.

Ek olarak, uygulama çok iş parçacıklıysa, giriş noktası işlevindeki her iş parçacığına özel bellek ayırmak için iş parçacığı yerel depolamasını (TLS) kullanabilirsiniz. Aşağıdaki kod, DLL giriş noktası işlevinin bir örneğidir.

BOOL APIENTRY DllMain(
HANDLE hModule,	// Handle to DLL module DWORD ul_reason_for_call, LPVOID lpReserved )  // Reserved
{
   switch ( ul_reason_for_call )
   {
      case DLL_PROCESS_ATTACHED:
      // A process is loading the DLL.
      break;
      case DLL_THREAD_ATTACHED:
      // A process is creating a new thread.
      break;
      case DLL_THREAD_DETACH:
      // A thread exits normally.
      break;
      case DLL_PROCESS_DETACH:
      // A process unloads the DLL.
      break;
   }
   return TRUE;
}

Giriş noktası işlevi FALSE bir değer döndürdüğünde, yükleme süresi dinamik bağlama kullanıyorsanız uygulama başlamaz. Çalışma zamanı dinamik bağlama kullanıyorsanız, yalnızca tek tek DLL yüklenmez.

Giriş noktası işlevi yalnızca basit başlatma görevlerini gerçekleştirmeli ve başka herhangi bir DLL yükleme veya sonlandırma işlevini çağırmamalıdır. Örneğin, giriş noktası işlevinde, doğrudan veya dolaylı olarak çağrı yapmamalısınız.LoadLibrary function veya the LoadLibraryExişlevi. Ek olarak, aramamalısınızFreeLibrary İşlem sona erdiğinde işlev görür.

WARNING: Çok iş parçacıklı uygulamalarda, olası veri bozulmasını önlemek için DLL genel verilerine erişimin eşitlendiğinden (iş parçacığı güvenli) emin olun. Bunu yapmak için, her iş parçacığı için benzersiz veriler sağlamak üzere TLS'yi kullanın.

DLL İşlevlerini Dışa Aktarma

DLL işlevlerini dışa aktarmak için, dışa aktarılan DLL işlevlerine bir işlev anahtar sözcüğü ekleyebilir veya dışa aktarılan DLL işlevlerini listeleyen bir modül tanımı (.def) dosyası oluşturabilirsiniz.

Bir function anahtar sözcüğü kullanmak için, dışa aktarmak istediğiniz her işlevi aşağıdaki anahtar sözcükle bildirmelisiniz:

__declspec(dllexport)

Uygulamada dışa aktarılan DLL işlevlerini kullanmak için, içe aktarmak istediğiniz her işlevi aşağıdaki anahtar sözcükle bildirmelisiniz:

__declspec(dllimport)

Genellikle, bir başlık dosyası kullanırsınız. define ifade ve bir ifdef ihracat bildirimini ve ithalat bildirimini ayırmak için açıklama.

Dışa aktarılan DLL işlevlerini bildirmek için bir modül tanımlama dosyası da kullanabilirsiniz. Bir modül tanımlama dosyası kullandığınızda, function anahtar sözcüğünü dışa aktarılan DLL işlevlerine eklemeniz gerekmez. Modül tanımlama dosyasında,LIBRARY ifade ve EXPORTSDLL için ifade. Aşağıdaki kod, bir tanım dosyası örneğidir.

// SampleDLL.def
//
LIBRARY "sampleDLL"

EXPORTS
   HelloWorld

Örnek bir DLL yazın

Microsoft Visual C ++ 6.0'da, aşağıdakilerden birini seçerek bir DLL oluşturabilirsiniz. Win32 Dynamic-Link Library proje türü veya MFC AppWizard (dll) Proje tipi.

Aşağıdaki kod, Win32 Dinamik Bağlantı Kitaplığı proje türü kullanılarak Visual C ++ 'da oluşturulan bir DLL örneğidir.

// SampleDLL.cpp

#include "stdafx.h"
#define EXPORTING_DLL
#include "sampleDLL.h"

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved )
{
   return TRUE;
}

void HelloWorld()
{
   MessageBox( NULL, TEXT("Hello World"), 
   TEXT("In a DLL"), MB_OK);
}
// File: SampleDLL.h
//
#ifndef INDLL_H
#define INDLL_H

#ifdef EXPORTING_DLL
extern __declspec(dllexport) void HelloWorld() ;
#else
extern __declspec(dllimport) void HelloWorld() ;
#endif

#endif

Örnek DLL Çağırma

Aşağıdaki kod, SampleDLL DLL'de dışa aktarılan DLL işlevini çağıran bir Win32 Uygulama projesinin bir örneğidir.

// SampleApp.cpp 

#include "stdafx.h"
#include "sampleDLL.h"

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine,  int       nCmdShow)
{ 	
   HelloWorld();
   return 0;
}

NOTE : Yükleme zamanı dinamik bağlamada, SampleDLL projesini oluşturduğunuzda oluşturulan SampleDLL.lib içe aktarma kitaplığını bağlamanız gerekir.

Çalışma zamanı dinamik bağlamada, SampleDLL.dll dışa aktarılan DLL işlevini çağırmak için aşağıdaki koda benzer bir kod kullanırsınız.

...
typedef VOID (*DLLPROC) (LPTSTR);
...
HINSTANCE hinstDLL;
DLLPROC HelloWorld;
BOOL fFreeDLL;

hinstDLL = LoadLibrary("sampleDLL.dll");
if (hinstDLL != NULL)
{
   HelloWorld = (DLLPROC) GetProcAddress(hinstDLL, "HelloWorld");
	
   if (HelloWorld != NULL)
   (HelloWorld);

   fFreeDLL = FreeLibrary(hinstDLL);
}
...

SampleDLL uygulamasını derleyip bağladığınızda, Windows işletim sistemi SampleDLL DLL'yi aşağıdaki konumlarda bu sırayla arar:

  • Uygulama klasörü

  • Mevcut klasör

  • Windows sistem klasörü (The GetSystemDirectory işlevi Windows sistem klasörünün yolunu döndürür).

  • Windows klasörü (The GetWindowsDirectory işlevi Windows klasörünün yolunu döndürür).

Bir DLL kullanmak için, Kayıt Defterine uygun referanslar girilerek kaydedilmesi gerekir. Bazen bir Kayıt Defteri başvurusu bozulur ve DLL'nin işlevleri artık kullanılamaz. DLL, Başlat-Çalıştır'ı açıp aşağıdaki komut girilerek yeniden kaydedilebilir:

regsvr32 somefile.dll

Bu komut, somefile.dll dosyasının PATH'deki bir dizin veya klasörde olduğunu varsayar. Aksi takdirde, DLL'nin tam yolu kullanılmalıdır. Bir DLL dosyasının kaydı, aşağıda gösterildiği gibi "/ u" anahtarı kullanılarak da kaldırılabilir.

regsvr32 /u somefile.dll

Bu, bir hizmeti açıp kapatmak için kullanılabilir.

DLL sorunlarını gidermenize yardımcı olacak çeşitli araçlar mevcuttur. Bazıları aşağıda tartışılmaktadır.

Bağımlılık Walker

Bağımlılık Gezgini aracı (depends.exe) bir program tarafından kullanılan tüm bağımlı DLL'leri özyinelemeli olarak tarayabilir. Dependency Walker'da bir program açtığınızda, Dependency Walker aşağıdaki kontrolleri gerçekleştirir:

  • Eksik DLL'leri denetler.
  • Geçerli olmayan program dosyalarını veya DLL'leri denetler.
  • İçe aktarma işlevlerinin ve dışa aktarma işlevlerinin eşleşip eşleşmediğini kontrol eder.
  • Döngüsel bağımlılık hatalarını denetler.
  • Modüller farklı bir işletim sistemi için olduğu için geçerli olmayan modülleri denetler.

Dependency Walker'ı kullanarak, bir programın kullandığı tüm DLL'leri belgeleyebilirsiniz. Gelecekte oluşabilecek DLL sorunlarının önlenmesine ve düzeltilmesine yardımcı olabilir. Dependency Walker, Microsoft Visual Studio 6.0'ı yüklediğinizde aşağıdaki dizinde bulunur:

drive\Program Files\Microsoft Visual Studio\Common\Tools

DLL Evrensel Sorun Çözücü

DLL Evrensel Sorun Çözücü (DUPS) aracı, DLL bilgilerini denetlemek, karşılaştırmak, belgelemek ve görüntülemek için kullanılır. Aşağıdaki liste, DUPS aracını oluşturan yardımcı programları açıklamaktadır:

  • Dlister.exe - Bu yardımcı program bilgisayardaki tüm DLL'leri numaralandırır ve bilgileri bir metin dosyasına veya bir veritabanı dosyasına kaydeder.

  • Dcomp.exe - Bu yardımcı program, iki metin dosyasında listelenen DLL'leri karşılaştırır ve farklılıkları içeren üçüncü bir metin dosyası oluşturur.

  • Dtxt2DB.exe - Bu yardımcı program, Dlister.exe yardımcı programı ve Dcomp.exe yardımcı programı kullanılarak oluşturulan metin dosyalarını dllHell veritabanına yükler.

  • DlgDtxt2DB.exe - Bu yardımcı program, Dtxt2DB.exe yardımcı programının bir grafik kullanıcı arabirimi (GUI) sürümünü sağlar.

Bir DLL yazarken aşağıdaki ipuçlarını aklınızda bulundurun:

  • Uygun arama kuralını kullanın (C veya stdcall).

  • İşleve iletilen argümanların doğru sırasına dikkat edin.

  • Doğrudan bir işleve iletilen bağımsız değişkenleri kullanarak dizileri ASLA yeniden boyutlandırmayın veya dizeleri birleştirmeyin. Unutmayın, ilettiğiniz parametreler LabVIEW verileridir. Dizi veya dizi boyutlarının değiştirilmesi, LabVIEW belleğinde depolanan diğer verilerin üzerine yazılması nedeniyle bir çökmeye neden olabilir. Bir LabVIEW Dizi Tanıtıcısı veya LabVIEW Dize Tutamacını iletirseniz ve DLL dosyanızı derlemek için Visual C ++ derleyicisini veya Symantec derleyicisini kullanıyorsanız, dizileri yeniden boyutlandırabilir veya dizeleri birleştirebilirsiniz.

  • Dizeleri bir işleve geçirirken, geçirilecek doğru dize türünü seçin. C veya Pascal veya LabVIEW dize Tutacağı.

  • Pascal dizelerinin uzunluğu 255 karakterle sınırlıdır.

  • C dizgileri NULL ile sonlandırılır. DLL işleviniz ikili dize biçiminde sayısal veriler döndürürse (örneğin, GPIB veya seri bağlantı noktası aracılığıyla), veri dizesinin bir parçası olarak NULL değerleri döndürebilir. Bu tür durumlarda, kısa (8 bit) tam sayı dizilerini geçirmek en güvenilir olanıdır.

  • Dizilerle veya veri dizileriyle çalışıyorsanız, bunları LabVIEW tutamaçları olarak iletmediğiniz sürece, işlev tarafından arabelleğe yerleştirilen sonuçları tutacak kadar büyük bir arabellek veya dizi geçirin; bu durumda bunları CIN kullanarak yeniden boyutlandırabilirsiniz. Visual C ++ veya Symantec derleyicisi altındaki işlevler.

  • _Stdcall kullanıyorsanız modül tanımlama dosyasının EXPORTS bölümünde DLL işlevlerini listeleyin.

  • Diğer uygulamaların modül tanımlama dosyası EXPORTS bölümünde çağırdığı DLL işlevlerini veya işlev bildirimine _declspec (dllexport) anahtar sözcüğünü içerecek şekilde listeleyin.

  • Bir C ++ derleyici kullanıyorsanız, adların karışmasını önlemek için üstbilgi dosyanızda extern .C. {} İfadesiyle işlevleri dışa aktarın.

  • Kendi DLL dosyanızı yazıyorsanız, DLL başka bir uygulama tarafından belleğe yüklenirken bir DLL dosyasını yeniden derlememelisiniz. Bir DLL'yi yeniden derlemeden önce, söz konusu DLL'yi kullanan tüm uygulamaların bellekten kaldırıldığından emin olun. DLL'nin kendisinin belleğe yüklenmemesini sağlar. Bunu unutursanız ve derleyiciniz sizi uyarmazsa, doğru şekilde yeniden inşa edemeyebilirsiniz.

  • İşlevin (ve DLL'nin) doğru çalıştığından emin olmak için DLL'lerinizi başka bir programla test edin. Derleyicinizin hata ayıklayıcısıyla veya bir DLL'deki bir işlevi çağırabileceğiniz basit bir C programıyla test etmek, DLL veya LabVIEW ile ilgili olası zorlukların doğasında olup olmadığını belirlemenize yardımcı olacaktır.

Bir DLL'nin nasıl yazılacağını ve bir "Merhaba Dünya" programının nasıl oluşturulacağını gördük. Bu örnek size bir DLL oluşturmanın temel konsepti hakkında bir fikir vermiş olmalı.

Burada Delphi, Borland C ++ ve yine VC ++ kullanarak DLL oluşturma hakkında bir açıklama vereceğiz.

Bu örnekleri tek tek ele alalım.

  • Delphi içinde DLL'ler nasıl yazılır ve çağrılır

  • Borland C ++ Builder IDE'den DLL Oluşturma

  • Microsoft Visual C ++ 6.0'da DLL Oluşturma