Bu Blogda Ara

27 Nisan 2010 Salı

Dynamic-Link Library (DLL) / Giriş

DLL dosyaları Microsoft'un Windows ve OS/2 işletim sistemleri için gerçeklediği kütüphane paylaşım konsepti olarak tanımlanabilir. Bu kütüphaneler genellikle DLL, OCX ya da DRV uzuntasındadır.

DLL dosyaları aynen EXE dosyaları gibi kod, veri ve kaynak bölümlerine (ve bunların herhangi bir kombinasyonunda) olabilir.

Windows işletim sisteminin ilk sürümlerinde tüm programlar tek bir bellek bölgesinde koşturuluyordu. İşletim sistemi düzeyindeki tüm işlemler MS-DOS tarafından gerçekleştirilirken yüksek seviyeli hizmetler Windows DLL leri tarafından sağlanıyordu. Çizim API'leri yani GDI.EXE, kullanıcı arayüzü işlemleri USER32.EXE adlı kütüphane dosyasında gerçeklenmiştir.


Günümüzde daha farklı bir yaklaşım kullanılmaktadır. Sistem tarafından sunulan kütüphaneler uygulamalara ayrı ayrı yüklenmektedir. Korumalı modda olduğu için bir program başka bir programın hafıza alanına doğrudan bir müdehalede bulunamıyor.

Assembly dilinde basit bir mesaj gösteren DLL uygulaması şu şekilde olabilir:


.386 ; intel x86 architecture
.model flat,stdcall ; use flat memory management
option casemap:none ; ignore letter case

include \masm32\include\windows.inc
include \masm32\include\user32.inc ; for MessageBox func.
include \masm32\include\kernel32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
message db "Test message...",0 ; content of our simple message

.code
DllEntry proc hInstance:HINSTANCE, reason:WORD, reserved1:WORD ; DLL entry point function
mov eax,TRUE
ret
DllEntry Endp

SimpleMessage proc
invoke MessageBox,NULL,addr message,NULL,MB_OK ; win32 MessageBox func.
ret
SimpleMessage Endp

End DllEntry




Bu programı derlemek için birde def dosyası oluşturmalıyız. Bu dosyada 2 satır bilgi gerekiyor. Birinci satırda kütüphanenin ismini ikinci satırda ise kütüphaneden dışarı aktarılacak yani diğer programların hizmetine sunuculacak olan fonksiyonların isimleri.

örnek olarak

LIBRARY Simple
EXPORTS SimpleMessage


Projemizi derlemek için komut satırına bazı komutlar girmemiz gerekecek. Bu işlemin otomasyonu için şöyle bir batch dosya oluşturabiliriz.


c:\masm32\bin\ml.exe /c /coff /Cp "%CD%\Simple.asm"
c:\masm32\bin\link.exe /DLL /DEF:"%CD%\Simple.def" /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm32\lib "%CD%\Simple.obj"


Not: Bu uygulamayı derleyebilmeniz için sisteminizde Masm32 derleyicisi yüklü durumda olmalıdır. http://www.masm32.com/

Şimdi oluşturduğumuz bu DLL dosyasını başka bir programdan çağıralım. Bunun için çağırı yapacak programımızı derlerken DLL dosyamızın yapısını bildirmek üzere bir .lib dosyası vereceğiz. Bu dosya DLL projemizi derlerken derleyici tarafından otomatik olarak oluşturulmaktadır.

Kısa basit bir örnek:

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib Simple.lib ; lib file of Simple.dll to inform linker
includelib \masm32\lib\kernel32.lib

SimpleMessage PROTO ; name of the function in DLL

.code
start:
invoke SimpleMessage ; invoke the function in DLL
invoke ExitProcess,NULL ; terminate process
end start




Şimdi benzer bir çağırı programını C++ dilinde dinamik çağırma yöntemiyle yapalım.


#include <stdio.h>
#include <windows.h>

typedef void (WINAPI *SimpleMessage)(); // type defination to call dll function.

int main(int argc, char **argv)
{
HINSTANCE hDLL = LoadLibrary(L"simple.dll"); // loads our DLL into application memory section.
SimpleMessage sm = (SimpleMessage)GetProcAddress(hDLL,"SimpleMessage"); // gets address of our function in the dll.
if (!sm) // function address validation.
{
printf("Couldn't load library!\n");
}
else
{
sm(); // simple call.
}
return 0;
}



C# tarafında işler çok daha kolay:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace SimpleCall
{
class Program
{
[DllImport("simple.dll")]
static extern void SimpleMessage();

static void Main(string[] args)
{
SimpleMessage();
}
}
}


Java tarafında direk bir erişim şekli mevcut değil. Bunun yerine bazı 3. parti kütüphaneleri kullabiliriz. Bunlar JNI (Java Native Interface) tabanlı kütüphaneler. Biz bu örnekte JNA (Java Native Access) kullanacağız.

Bu kütüphanenin açıklamasını daha önceki bir yazımda (Bkz: http://rbellek.blogspot.com/2010/04/java-native-access-basit-ornek.html) bahsettiğim için burada yüzeysel geçiyorum.

Örnek uygulama:


//Main.java
package simple;

import com.sun.jna.Native;

public class Main {

public static void main(String[] args)
{
Simple simpleDLL = (Simple)Native.loadLibrary("e:\\Simple.dll", Simple.class);
simpleDLL.SimpleMessage();
}
}



//Simple.java
package simple;

import com.sun.jna.Library;

public interface Simple extends Library {
void SimpleMessage();
}



DLL dosyasının aynı EXE dosyaları gibi bir giriş noktları mevcuttur. Bu noktanın adı DllEntry adlı bir fonksiyondur. Ve giriş parametreleri olarak şu 4 değerden birini almaktadır.

DLL_PROCESS_ATTACH
DLL_PROCESS_DETACH
DLL_THREAD_ATTACH
DLL_THREAD_DETACH

Basit bir toplama kütüphanesi:


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
AppName db "Simple 2",0
HelloMsg db "Hello, you're calling a function in this DLL",0
LoadMsg db "The DLL is loaded",0
UnloadMsg db "The DLL is unloaded",0
ThreadCreated db "A thread is created in this process",0
ThreadDestroyed db "A thread is destroyed in this process",0

.code
DllEntry proc hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD
.if reason==DLL_PROCESS_ATTACH
invoke MessageBox,NULL,addr LoadMsg,addr AppName,MB_OK
.elseif reason==DLL_PROCESS_DETACH
invoke MessageBox,NULL,addr UnloadMsg,addr AppName,MB_OK
.elseif reason==DLL_THREAD_ATTACH
invoke MessageBox,NULL,addr ThreadCreated,addr AppName,MB_OK
.else ; DLL_THREAD_DETACH
invoke MessageBox,NULL,addr ThreadDestroyed,addr AppName,MB_OK
.endif
mov eax,TRUE
ret
DllEntry Endp

Addition proc param1:DWORD, param2:DWORD
mov ebx,param1
mov eax,param2
add eax,ebx
ret
Addition endp
End DllEntry




Bu toplama fonksiyonunu (parametreli) çağıran C++ uygulaması:


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

typedef int (WINAPI* Addition)(int,int); // two DWORD (32-bit integer) in parameters
// WINAPI same as __stdcall
// __stdcall gives order of parameters in stack
int main(int argc, char **argv)
{
HINSTANCE hDLL = LoadLibrary(L"calculator.dll");
Addition addition = (Addition)GetProcAddress(hDLL,"Addition");
if (!addition)
{
printf("Couldn't load library!");
}
else
{
printf("5 + 9 = %i",addition(5,9)); // simple two parameter call
}
return EXIT_SUCCESS;
}



Şimdilik basit bir girişle yetiniyorum. Umarım devamında detaylandırabilirim...

Hiç yorum yok: