WinAPI Fonksiyonlarının C#’ta Kullanımı

c-ders-148C# ve dotNET ile birlikte yazılım geliÅŸtirmeye yeni bir soluk gelmiÅŸ olsada C# ile eskiden yazılmış COM komponentlerine eriÅŸebilmek mümkündür. Daha önceki iki makalede .NET ve COM iliÅŸkisini detaylı bir ÅŸekilde incelemiÅŸtik. Bu makalede .NET’in Win 32 API ile nasıl entegre edildiÄŸi anlatılacaktır. .NET ve C#’ın yeni imkanlarının yanısıra eski bir teknoloji olan COM ve yönetilmeyen(unmanaged) kodlarla uyumlu bir ÅŸekilde çalışması belkide C# ve .NET’i diÄŸer yazılım geliÅŸtirme platformlarından ayıran en önemli özelliktir.

BildiÄŸiniz gibi C#’ta gösterici kullanımı tamamen serbesttir. Bu yüzden eskiden(.NET öncesi) yazılmış ve parametre olarak gösterici alan COM komponentleri ve Windows API fonksiyonları C# ile sorunsuz bir ÅŸekilde çalıştırılabilmektedir. Bu yazıda Win API fonksiyonlarının .NET ortamında ne ÅŸekilde ele alındığı incelenecektir.

Win32 sistem fonksiyonları kullanıldığında, kod CLR tarafından yönetilmekten çıkar. .NET ortamında geliÅŸtirilen bir uygulamada yönetilmeyen kod segmenti ile kaşılaşılırsa ilgi kod segmenti CLR tarafından yönetilmekten çıkar. Dolayısıyla “garbage collection” mekanizması ve .NET’e özgü diÄŸer servisler kullanım dışı olur.

CLR tarafından yönetilmeyen kodlara eriÅŸebilmek için C#’ta System.Runtime.InteropServices isim alanında bulunan ve DllImprtAttribute sınıfını temsil eden DllImport niteliÄŸi kullanılmaktadır. DllImport niteliÄŸi ile harici bir kaynakta bulunan metoda referans vermek için external anahtar sözcüğü kullanılır. Bir sınıf bildiriminin en başında external anahtar sözcüğü ve DllImport niteliÄŸi kullanılarak CLR tarafından yönetilmeyen bir metot bildirimi yapılır. Tabi metodun gövdesi harici bir kaynakta zaten var olduÄŸu için bizim metodun gövdesini yazmamızın bir anlamı yoktur. Ardından bu metot sınıfın istenildiÄŸi yerinde kullanılabilir. İsterseniz basit bir örnekle DllImport niteliÄŸinin kullanımını gösterelim.

Win API windows sistemlerinin programlanabilir arayüzünü içermektedir. Windows uygulamarının tamamı bu arayüzdeki fonksiyonları ve diğer yapıları kullanmaktadır. Aşağıdaki programda Win32 sistemlerinde bulunan MessageBox() fonksiyonunun kullanımına bir örnek verilmiştir.

Not : Bu yazıda C#’ta niteliklerin(Attributes) nasıl kullanıldığını bildiÄŸiniz varsayılmıştır.

using System;
using System.Runtime.InteropServices;

class Class1
{
    [DllImport("user32.dll")]
    
public static extern int MessageBox(int tip,string mesaj,string baslik,int secenek);

    static void Main()
    {
        MessageBox(0,”Mesaj”,”Win API MessageBox”,2);
    }
}

DllImportAttribute sınıfının bir tane yapıcı metodu bulunmaktadır. Bu metot parametre olarak harici kaynağın adı belirtmektedir. Yukarıdaki kaynak kodda MessageBox fonksiyonunun bulunduÄŸu “user32.dll” isimli dosya DllImport niteliÄŸine parametre olarak verilmiÅŸtir. Bu örnekte dikkat edilmesi gereken diÄŸer nokta ise extern anahtar sözcüğünün kullanımıdır. Bu anahtar sözcük ile bildirimi yapılan metodun harici bir dosyada olduÄŸu belirtilmektedir. Dolayısıyla C# derleyicisi metodun gövdesini kaynak kodda aramayacaktır.

Programın çalışma şeklini açıklamadan önce ekran çıktısına bakalım :

c-winapi-1

Yukurıdaki çıktıdan ve kaynak koddan da görüldüğü üzere Win API deki bir fonksiyonun çağrımı klasik metot çağrımından farklı değildir. Değişen tek şey metodun bildirim şeklidir.

Not : Gösterilen mesaj kutusunun farklı formlarını görmek için MessageBox metodunun parametreleri ile oynayın.

Åžimdi kısaca yukarıdaki programın çalışma zamanındaki durumunu inceleyelim. Program çalıştırıldığında, CLR tarafından yönetilmeyen bir metot çaÄŸrımı yapıldığında ilgili kaynaktan metot belleÄŸe yüklenir ve belleÄŸe yüklenen metodun baÅŸlangıç adresi saklanır. Ardından bizim parametre olarak geçtiÄŸimiz deÄŸiÅŸkenler DLL’ deki fonksiyona uyumlu hale getirilir ve parametre olarak geçirilir. EÄŸer bir geri dönüş deÄŸeri bekleniyorsa yönetilmeyen kod bölümünden gelen deÄŸer uygun .NET türüne dönüştürülerek iÅŸlemlere devam edilir. Bu iÅŸlemler tamamen .NET’in alt yapısını ilgilendirmektedir. Dolayısıyla programcının yapacağı iÅŸ sadece metodun bildirimini doÄŸru bir ÅŸekilde gerçekleÅŸtirmektir.

DllImportAttribute sınıfının bir kaç önemli özelliği daha vardır. Bunlardan en önemlisi harici kaynaktaki bir fonksiyona takma isim verebilmemizi sağlayan string türünde olan EntryPoint özelliğidir. EntryPoint özelliğini kullanarak MessagBox fonksiyonuna takma isim verebiliriz. Fonksiyon çağrımı bu takma isim ile gerçekleştirilebilmektedir. Örneğin MessageBox fonksiyonuna TebrikMesajiVer şeklinde bir takma isim vermek için aşağıdaki gibi bir bildirim yapılmalıdır.

using System;
using System.Runtime.InteropServices;

class Class1
{
    [DllImport("user32.dll",EntryPoint = "MessageBox")]
    
public static extern int TebrikMesajiVer(int tip,string mesaj,string baslik,int secenek);

    static void Main()
    {
        TebrikMesajiVer(0,”Tebrikler”,”Takma İsim Verme”,0);
    }
}


Şimdi de DllImport niteliği ile ilgili diğer özelliklere ve önemli noktalara bakalım.

1 – DllImport niteliÄŸi yalnızca metotlara uygulanabilir.

2 – DllImport niteliÄŸi ile iÅŸaretlenmiÅŸ metotlar mutlaka extern anahtar sözcüğü ile bildirilmelidir.

3 – DllImport niteliÄŸinin EntryPoint’in haricinde 4 tane isimli parametresi(named parameter) daha vardır. Bunlar : CallingConvention, CharSet, ExactSpelling, PreserveSig ve SetLastError parametreleridir. Bu parametrelerden önemli olanlar aÅŸağıda açıklanmıştır.

4CallingConvention : Bu paramtre CallingConvention numaralandırması türündendir. Bu parametre ile harici metodun ne ÅŸekilde çaÄŸrılacağı ile ilgili bilgi verilir. CallingConvention numaralandırması 5 tane sembol içerir. Varsayılan olarak bu sembol Winapi olacak ÅŸekilde ayarlanmıştır. Yani CallingConvention parametresini DllImport ile kullanmıyorsak varsayılan olarak bu Winapi’dir. DiÄŸer semboller ise Cdecl, FastCall, ThisCall, StdCall ÅŸeklindedir. En çok Winapi sembolu kullanıldığı için diÄŸer sembollerin ne anlama geldiÄŸi anlatılmayacaktır. DiÄŸer sembollerin ne anlama geldiklerini MSDN kütüphanesinden detaylı bir ÅŸekilde öğrenebilirsiniz.

5 - CharSet : Harici fonksiyonun çağrımında kullanılacak karekter setini belirler. Bu parametre CharSet numaralandırması ile belirtilir. Varsayılan olarak CharSet.Auto şeklindedir. CharSet numaralandırmasının diğer sembolleri Ansi, Unicode ve None şeklindedir.

6 - ExactSpelling : EntryPoint ile belirtilen ismin ilgili fonksiyon ismine yazım biçimi bakımından tam uyumlu olup olmayacağını belirtir. Bu özellik bool türündendir ve varsayılan olarak false değerdir.


DllImport metodunun varsayılan çağrım biçimi olan Winapi sadece Windows sistemlerine özgün olduğu için sistemler arası taşınabilirliğin yüksek olması gereken projelerde bu niteliğin kullanımından kaçınmak gerekir. Bu yüzden DllImport özelliğini kullanmadan önce ilgili fonksiyonun .NET Framework içinde olup olmadığını kontrol etmek gerekir. Örneğin MessageBox fonksiyonu zaten System.Windows.Forms isim alanında bulunduğu için API kullanarak bu fonksiyondan yararlanmak mantıklı değildir. Zira ileride programınızın Linux ortamında yada diğer farklı ortamlarda da çalışmasını istiyorsanız programınızı değiştirip yeniden derlemeniz gerekecektir. Oysa .NET Framework içinde bulunan standart sınıfları ve onların metotlarını kullanırsanız böyle bir derdiniz olmayacaktır.

Kategoriler: C# Programlama, Yazılım

Tags: , , , ,

Yorumlar

Yorum Yok

Yorumunuzu Ekleyin

Yorum eklemek için giris yapmalısınız.