DLL - Nasıl Yazı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 senkronize edildiğ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).