Makale Özeti

Bu makalemizde Mobil Cihazlar üzerinde, Windows Mobile 5.0 İşletim Sistemi API’ lerini PInvoke yöntemiyle kullanarak bir “Ses Oynatıcısı” geliştireceğiz.

Makale

.Net Compact Framework’ ün gelişimine baktığımızda özellikle 2.0 versiyonu ile standart .Net Framework’ e epeyce yaklaşmış durumdadır. Yavaş yavaş birçok kavram .Net Compact Framework içerisinde de bulunmakta ; mobil cihaz uygulama geliştiricileri tatmin etmeye başlamaktadır.

Windows Mobile 6.0’ ında çıkmasıyla muhtemelen Microsoft yakın zamanda bir eklenti paketi çıkaracak ; yeni işletim sistemi üzerinde gelen API’ lere managed ortamdan managed uygulama geliştiricilerin hizmetine sunacaktır. Olaya bu açıdan baktığımızda her ne kadar yeterli olduğunu düşünsekte, standart .Net Framework ortamında bile managed uygulama geliştiriciler olarak çoğu zaman birçok belirli eylemi gerçekleştirmek için managed sınıflardan yanıt bulamamakta ; çareyi unmanaged kütüphanelerin içerisindeki metotları managed ortamdan çağırarak bulmaktadırlar.

Peki bu sıkıntı .Net Compact Framework üzerinde nasıl çözümlenmektedir ? Evet ; .Net Framework üzerinde olduğu gibi, managed mobil cihaz uygulama geliştiricilerde bu tip durumlarda soruna aşağı yukarı aynı çareyle çözüm bulmakta ; işletim sistemi üzerinde çalıştırılan birçok metodu managed ortamdan çağırarak gerekli eylemleri gerçekleştirmektedirler.

Standart .Net Framework uygulamalarında Platform Invocation Services (PInvoke) adı verilen servisimiz üzerinden managed uygulama geliştiricler, Unmanaged kütüphanelerin içerisinde implement edilmiş bütün fonksiyonları managed ortamdan çağırabilmekte ; platformlar arası tip dönüşümü v.b. gibi tüm karmaşık işlemleri PInvoke servisi gerçekleştirmektedir. Bu sistem, bazı kısıtlamalar ile .Net Compact Framework üzerinde “aynen işlemektedir”.

Makalemizin asıl konusuna geçmeden önce teorik anlamda bu konu ile ilgili bilgilenmek bu noktada daha doğru olacaktır. İlk olarak .Net Compact Framework üzerinde bu sistem sırasıyla nasıl çalışmaktadır ; nelere ihtiyaç duymaktadır bu konular ile ilgili bilgi sahibi olalım.

.Net CF üzerinde Managed ortamdan Unmanaged bir kütüphane içerisindeki bir fonksiyonu çağırmak istediğimizde gerçekleştirilmesi gereken birkaç adım bulunmaktadır. Bu adımlardan sadece ilki ile uygulama geliştirici ilgilenmekte ; diğer adımlar PInvoke servisi üzerinden gerçekleştirilmektedir.

Managed ortamdan Unmanaged bir kütüphane içerisinde bulunan bir fonksiyonu çağırmak gibi bir ihtiyaç olduğunda ilk noktada gerçekleştirilmesi gereken eylem bu fonksiyonun hangi kütüphane içerisinde hangi isimle bulunduğunu belirlemek olacaktır. Az sonra üzerinde çalışacak olduğumuz Attribute’ ün bizden istediği parametrelerin doğru bir şekilde verilebilmesi için bu değerler doğru belirlenmiş olmalı ; kütüphanemiz ise işletim sistemimiz üzerinde fiziksel olarak bulunmak durumdadır.

Fonksiyonun hangi parametreleri istediğini ; hangi kütüphane içerisinde bulunduğu gibi temel bilgileri internet üzerinden araştırdıktan sonra artık gerçekleştirilmesi gereken tek bir adım kalmaktadır ; bu fonksiyonu PInvoke servisinin çalıştıracağı şekilde tanımlamak.

Bir sonraki adımda ise gerekli parametreleri tanımlı olan bu unmanaged fonksiyona göndermek olacaktır. Gerekli platformlar arası dönüşümler, kontroller PInvoke servisi tarafından gerçekleştirilecek ; bize eğer geliyor ise fonksiyon sonucu CLR tipinde geri dönüş değeri olarak gelecektir. İşte bu kadar basit !

Peki az önce üzerinde konuştuğumuz ; metodumuzun PInvoke servisi tarafından alıgalanacak şekilde tanımlanması işlemini .Net Compact Framework üzerinde nasıl gerçekleştireceğiz ?

İşte bu noktada karşımıza sadece bu iş için oluşturulmuş bir Attribute ; System.Runtime.InteropServices namespace’ i altında bulunan DllImport attribute’ u karşımıza çıkmaktadır.

DllImport ; adından da anlaşılabileceği üzere unmanaged bir kütüphaneyi managed ortam üzerine taşımakla yükümlü bir attribute’ tur. Bu attribute doğru noktada doğru parametreler ile kullanılabilir ise PInvoke metot çağırısını başarılı bir şekilde alabilecek ve bu şekilde iki farklı platform arası haberleşme gerçekleştirilmiş olacaktır.

.Net Compact Framework üzerinde PInvoke Servisleri ile ilgili temel kısıtlamalar DllImport attribute’ u ile karşımıza çıkmaktadır. Bu noktada standart .Net Framework üzerinde onlarca değer alabilirken ; .Net Compact Framework üzerinde bu attribute sadece 3 adet parametre değeri almaktadır.

EntryPoint, CharSet, CallingConvention ve SetLastError şeklinde 4 adet sıralanabilecek bu parametre değerleri DllImport’ un PInvoke servisleri ile iletişim kurulacağı noktada sistemin çalışabilmesi için gerekli değerleri sağlamaktadır.

Bu parametre değerlerini göz önünde bulundurduğumuzda hayati derecede önem taşıyabilecek en önemli parametre EntryPoint parametre değeri olacaktır. Çünkü bu parametre değeri içerisinde hangi kütüphane’ nin hangi fonksiyonu çağırılacak ; bu bilginin değeri belirlenmektedir.

Lafı fazla uzatmadan hızlı bir şekilde makalemizin temel konusuna odaklanalım. Amacımız standart .Net Compact Framework 2.0 sınıfları ile gerçekleştiremeyeceğimiz bir eylemi ; uygulamamız üzerinden ses çaldırma işini PInvoke yardımıyla az sonra üzerinde konuşacağımız kütüphane içerisindeki bir fonksiyonu ; PlaySound fonksiyonunu kullanarak gerçekleştirmek olacaktır.

Ayrıntıları proje esnasında geliştireceğimizden hiç vakit kaybetmeden bir C# Smart Device uygulaması açarak işe başlayalım.

Amacımız adresi verilen bir wave dosyasını form üzerine yerleştirilen button’ u kullanarak çaldırmak olacaktır.  Bu noktada şekildeki form’ u tasarlamış olmak uygulamamız için yeterli olacaktır.

Şimdi geldik asıl ve zor olan bölüme. Bu noktada öncelikle gerçekleştirmemiz gereken en önemli adım PlaySound fonksiyonunun hangi kütüphane içerisinde bulunduğunu bulmak ; akabinde çalışabilmek için hangi parametre değerlerini istediğini bulmak olacaktır. Belirli bir araştırma sonucunda bu fonksiyonun işletim sisteminin kullandığı temel kütüphane ; CodeDll.DLL içerisinde bulunduğunu ; ve çalışabilmek için 3 adet parametre istediği sonucuna ulaşmaktayız.

http://msdn2.microsoft.com/en-us/library/aa909766.aspx

Parametreler sırasıyla ;

Çalınacak Dosyanın Adı, boş bir handle değeri ve az sonra üzerinde çalışacak olduğumuz bazı enum değerleri olmaktadır.

Yapmamız gereken ilk ve en önemli adımdan sonra sıra geldi ikinci noktaya. Bu noktada DllImport attribute’ u yardımı ile bu unmanaged fonksiyonu doğru parametre değerlerini kullanarak çalışma zamanında tanıtmış olmamız gerekmektedir. Şekildeki kod ile uygulamamıza devam ediyoruz :

Kod üzerinden dikkat edilebileceği üzere System.Runtime.InteropServices namespace’ i altında bulunan DllImport Attribute’ üne ilk parametresinde PlaySound isimli fonksiyonumuzun hangi kütüphane içerisinde bulunduğunu belirtmekteyiz. İkinci parametrede ise memory içerisine yüklenen kütüphane’ nin hangi fonksiyonunu araması gerektiğini belirtiyoruz –ki bu noktada yazıma dikkat etmiş olmalıyız. Aksi takdirde fonksiyon bulunamayacaktır. Son parametremizde ise bir hata oluştuğunda bunu PInvoke servisleri üzerinden managed ortama taşıyacağı bilgisini vererek string, IntPtr ve int alacak şekilde 3 parametreli bir fonksiyon deklare ediyoruz. Dikkat edilecek olursa sistem .Net Framework üzerindeki yapıyla birebir aynı çalışmaktadır.

Bir sonraki adımda ; fonksiyonun 3. Parametresinde kullanıcıdan istenen ; hali hazırda bazı statik değerlerden bahsetmek konunun tam olarak anlaşılabilmesi açısından daha doğru olacaktır.

Uygulama geliştiriciler bu fonksiyonu çağıracakları zaman sistem üzerinde bu “sadece” fonksiyonun tanıdığı bazı özel numerik değerleri 3. parametre değeri olarak göndermeleri gerekmektedir. Bu hazır numerik değerlerin daha rahat kullanılabilmesi açısında bit flag tanımlamak bu noktada daha rahat olacaktır. Şekildeki kod bloğu üzerinden uygulamamamıza devam ediyoruz :

Statik olarak daha önceden belirlenmiş olan bu değerlere internet üzerinden rahatlıkla ulaşılabilmektedir. Sistemin düzgün çalışabilmesi açısından bu değerler Hexadecimal formatta belirlenmiştir. Ayrıca dikkat edilecek olursa tanımlanan her enum değerinin karşısına az önce bahsedilen “statik” değerler eşitlenmektedir. Bu şekilde fonksiyona tamamen bizden istediği ve kendisinin kabul ettiği değerler gönderilmektedirler.

Hangi numerik değerin ne işe yaradığı yanında yorum olarak yazmaktadır.Bilindiği üzere bu tip parametri durumlarda araya OR ( | ) işareti konularak birden fazla enum değeri gönderilebilmekte ; tek taşla birden fazla kuş vurabilmekteyiz. Biz makalemizde sadece tek bir enum değerini ; SND_FILENAME değerini fonksiyona göndereceğiz. Böylece sistem fiziksel bir dosyadan okuma yapacağını anlayacaktır.

Sıra geldi uygulamamızın son adımına ; şekildeki kod bloğu üzerinden uygulamamıza devam ediyoruz :

 

Dikkat edilecek olursak ; button’ a tıkladığımızda MuzikCaldir metodu cagirilmakta ; parametre değeri olarakta dosya ismi txtPATIKA isimli metin kutusunun Text özelliğinden alınmakta ; ikinci parametreye boş bir IntPtr değeri gönderilmekte ve son flag parametre değerine ise gönderilen patikanın bir “dosya patikası” olduğunu ifade eden SND_FILENAME enum değeri gönderilemektedir.

Bu değerler üzerinden uygulamımızı çalıştırıyoruz ve şekildeki patikayı yazıp Button’ a basıyoruz :

Ve sonuç mükemmel ! Uygulamayı emülatör yada fiziksel cihaz üzerinde denediğinizde sesin çalındığını sizde rahatlıkla duyabilirsiniz.

Bu makalemizde PInvoke kullanarak Unmanaged bir kütüphane içerisindeki bir fonksiyonu .Net Compact Framework üzerinden çağırarak basit bir Ses Oynatıcısı geliştirdik.

Bir başka makalede daha görüşmek üzere.


Ekin ÖZÇİÇEKÇİLER
Microsoft Certified Trainer
ekin.ozcicekciler@bilgeadam.com
MCP, MCAD.NET, MCSD.NET, MCSD.NET, MCTS, MCPD Ent.