Kaynaklar
Kaynaklar, Windows uygulamaları için olmazsa olmazlardan biri değilse de eğer uygulamanızın güzel bir kullanıcı arabirimine sahip olmasını istiyorsanız, ve her bir pencerenin yaratım ve mesajları için satırlarca kod yazacak zamanınız yoksa kesinlikle başvurmak isteyeceğiniz yardımcı elemanlardır. Bu bölümümüzde kaynak dosyalarını, Win32 uygulamalarında kullanılan başlıca kaynak çeşitlerini, bu kaynakların kullanım alanlarını ve bazı kaynak fonksiyonlarını inceleyerek kaynaklar konusuna bir giriş yapacağız.
Nedir? Nasıl yapılır?
Kaynak kelimesi, uygulamanızı derlediğiniz zaman oluşan EXE dosyasının içine gömülecek olan ikilik veriyi temsil eder. Uygulamanız çalışırken bazı WinAPI fonksiyonlarını kullanarak bu veriye ya da verilere kolayca erişebilir. Uygulamanıza kaynak eklemek için genellikle kodlama aşamasında geliştirme ortamınızın kaynak düzenleyicisini (resource editor) kullanırsınız. Diğer bir yol ise kaynakların tanımlandığı betik benzeri dilin notasyonunu öğrenmektir, ama günümüzde çoğu programcı kaynak düzenleyicilerin sunduğu RAD benzeri kullanıcı arabirimlerini kullanıyor (Visual Basic bir RAD örneğidir). Tabii ki bu kaynak düzenleyicileriyle yarattığınız formları pat diye EXE haline getiremezsiniz, Windows giriş kodunu yazmanız ve pencereyi göstermeniz hala gerekiyor. "Madem o kadar şeyi yapacağız, neden kaynak kullanıyoruz da Makale 2'de yaptıklarımızı yapmıyoruz?" diye düşünebilirsiniz. Boş bir pencere için bu doğru olabilir. Ama o pencerenin üzerine kontroller (butonlar, liste kutuları gibi) ekleyince kaynaklar epey bir kod tasarrufu sağlayacak bize. Görsel olarak tasarlayabilmeniz de cabası.
Nasıl çalışır?
Temel düzeyde şöyle...kaynak düzenleyicinizle yarattığınız her kaynağa bir ID numarası verilir (genellikle 1001,1002 diye giden numaralar), bu ID numaraları resource.h adlı başlık dosyasında sizin tanımladığınız isimlere atanırlar, böylece "benim liste kutusunun ID numarası neydi?" diye düşünmeniz gerekmez. Mesela adına IDC_LISTE dediğimiz bir liste kutumuz olsun. resource.h dosyası içinde #define IDC_LISTE 1002 gibi bir ifade, bu başlık dosyasını eklettiğiniz kaynak kodunuzda 1002 yerine IDC_LISTE yazabileceğiniz anlamına gelir (IDC_LISTE'nin bir string ifade olmadığına dikkat edin).
Kaynakların çalışmasıyla ilgili bilmeniz gereken temel kural buydu, ama eğer EXE içine nasıl gömülüyor gibi derin ve felsefik sorularınız varsa onu da kısa olarak açıklayacağım. Kaynak düzenleyicisinin yaptığı şey yaptığınız görsel düzenlemeyi kaynak betiği formatında bir dosyaya kaydetmektir. Daha sonra derleme aşamasında kaynak derleyicisi (resource compiler) dediğimiz ve derleyici paketine dahil olan bir uygulama, bu kaynak betiğini derleyerek özel bir ikilik formata dönüştürür ve EXE dosyası oluşturulurken .res veya .rsrc bölümüne (resource flag taşıyan bölüm, adı farklı da olabilir) bir ağaç hiyeraşisi içinde yazar. Daha fazla detay istiyorsanız, Win32 Core SDK'ya başvurabilir veya bu konuda kapsamlı bir araştırma yapabilirsiniz.
Ne işe yarar?
İşte en can alıcı noktaya geldik. Şimdiye kadar kaynaktan hep veri olarak bahsettik, birçoğumuzun aklına "veri ama nasıl veri? ikilik veri mi olacak illa?" şeklinde sorular gelmiş olabilir. Windows, kaynakları önce standart kaynaklar ve uygulama-tanımlı kaynaklar olarak ikiye ayırıyor. Uygulama-tanımlı kaynaklar, adı üstünde, uygulamaya özgü ve "özel" nitelikli kaynaklar. Bizim bu makalede inceleyeceğimiz, şekil ve şemalleri önceden tanımlı olan standart kaynaklar. Bu standart kaynakların da 11 çeşidi var:
İkonlar
Fare işaretçileri
Menüler
Diyalog Kutuları
Bit Eşlemler
Zenginleştirilmiş metaveri dosyaları (enhanced metafile)
Fontlar
Hızlandırıcı tabloları
Mesaj tablosu girişleri
Metin tablosu girişleri
Sürüm bilgisi
Makalede bahsedeceklerimiz ikonlar, fare işaretçileri, bit eşlem dosyaları, metin tablosu girişleri ve sürüm bilgisi. Menüler ve diyalog kutularına bir sonraki makalede değineceğiz, çünkü onlar başlı başına birer dünya. Diğer kaynak tipleri ya çok az kullanılıyor ya da kullanılmıyor, bu kaynak tipleri için de Win32 Core SDK'ya başvurabilirsiniz.
Şimdi bu kaynak tiplerini incelemeye başlayalım.
İkonlar
İkonlar, veya simgeler, bildiğiniz gibi Windows altında uygulamalar veya belirli görevlerle özdeşleşmiş, 16x16 veya 32x32 gibi standart boyutları ve renk derinliği olan küçük resim dosyalarıdır. Normal resim dosyalarından başlıca farkları bir transparan renk içermeleri. İkonların başlıca kullanım alanları form veya uygulama simgeleri de olsa da ikonlar için başka kullanım alanları da bulunmakta. Uygulamanıza eklediğiniz ikonlar dışında Windows'un programcılara sunduğu bazı standart ikonlar da var. Bu ikonları kullanmak için LoadIcon fonksiyonunu kullanacağız:
HICON LoadIcon(HINSTANCE hInstance,LPCTSTR lpIconName);
hInstance - ikonu hangi uygulamadan yüklemek istiyorsanız o uygulamanın instance handle değeri. Eğer kendi uygulamanıza eklediğiniz bir kaynağı kullanmak istiyorsanız buraya GetModuleHandle(NULL) parametresini geçebilirsiniz. Eğer standart Windows ikonlarından birini yükleyecekseniz bu parametreye NULL geçin. Bu ifadeler bütün kaynak türleri için geçerlidir.
lpIconName - ikonun tanımlayıcısı (ID değeri). Dikkat ettiyseniz bizim kaynak tanımlayıcılarımız sayısal değerler alıyordu, bu ise bir string parametre. Bu yüzden bu parametreyi yaratmak için MAKEINTRESOURCE makrosunu kullanacağız - mesela IDI_IKONUM yerine MAKEINTRESOURCE(IDI_IKONUM). Şimdi de Windows'un bize sağladığı ikonlara bir bakalım: IDI_APPLICATION (standart uygulama ikonu), IDI_ASTERISK (asterisk), IDI_EXCLAMATION (ünlem), IDI_HAND (el), IDI_QUESTION (soru işareti), IDI_WINLOGO (Windows logosu).
Fare İşaretçileri
Fare işaretçileri, fare, ışık kalemi (hala kullanan var mı?) veya bir notebook için trackball'ı hareket ettirdiğiniz zaman ekranınızda aynı hareketi yapan ve size işaretleme cihazınızın (biz en iyisi fare diyelim) geçerli konumunun nerede olduğunu belirtir. Bu işaretçi resimleri hareketli (ANI) veya hareketsiz (CUR) olabilir. ANI veya CUR dosyalarını entegre kaynak olmadan LoadCursorFromFile fonksiyonuyla da yükleyebilirsiniz, ama biz entegre CUR kaynaklarını yükleyen LoadCursor fonksiyonunu kullanacağız:
HCURSOR LoadCursor(HINSTANCE hInstance,LPCTSTR lpCursorName);
Gördüğünüz gibi LoadIcon'a son derece benziyor. Benzemekle kalmıyor, neredeyse aynısı. Sadece buradaki lpCursorName parametresine ikon tipinde değil de fare işaretçisi tipinde bir ID parametresi vermemiz gerekiyor (yine MAKEINTRESOURCE kullanarak). Windows'un bize sunduğu fare işaretçiler de mevcut elbet: IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_IBEAM, IDC_ICON, IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE, IDC_UPARROw, IDC_WAIT. Biraz İngilizceniz ve Windows tecrübeniz varsa nasıl şeyler olduklarını ilk bakışta anlarsınız. Eğer merak ettikleriniz olursa, deneyin :).
Fare İşaretçileri Tasarlarken: Tıklama işlemini gerçekleştirdiğiniz zaman standart ok ikonunun ucuyla, artı ikonunun ise ortasıyla gerçekleştirirsiniz. Kendi fare işaretçinizi tasarlarken bunu unutmayın. İşaretçinin "aktif" olan bu kısmına "hot spot" deniyor.
Bit Eşlemler
Bit Eşlemler ikonlar ve fare işaretçileri gibi resim dosyaları, ama farklı olarak daha büyük boyutlarda ve renk derinliklerinde olabiliyorlar. Bit eşlem kaynaklarını bildiğimiz BMP dosyalarından yaratabilir veya kaynak düzenleyicinizi kullanarak kendiniz oluşturabilirsiniz. Bit eşlem kaynaklarının da hayalgücünüzle sınırlı kullanım alanları var. Yüklemek için kullanacağımız fonksiyon LoadBitmap ama bit eşlemleri yükledikten sonra ekranın bir yerlerine çizdirmek için başka fonksiyonlar gerekiyor (device context dediğimiz yapılarla ilgili GDI fonksiyonları). Bu fonksiyonlar ise tamamen ayrı bir mesele, o yüzden onlar bu makalede olmayacaklar (daha ileride GDI makalesinde yer alacaklar). LoadBitmap fonksiyonunun tanımı şöyle:
HBITMAP LoadBitmap(HINSTANCE hInstance,LPCTSTR lpBitmapName);
Windows'un bize sunduğu bir bitmap koleksiyonu var, onu da GDI makalesinde inceleyeceğiz inşallah. Coming soon :).
Metin Tablosu Girişleri
Metin tablosu girişleri adından da anlaşılacağı gibi metin verisinden oluşan bir tabloyu oluşturan girişler. Metin tabloları (string table) özellikle birden fazla dili destekleyen programlarda çok işe yarıyor. Metin tablolarındaki her giriş kendisine ait bir ID ile temsil ediliyor. Bu ID ile temsil edilen tablo girişinin içinde de tahmin ettiğiniz gibi bir metin verisi var. Bu metin tablosu girişlerinden metini almak için LoadString fonksiyonunu kullanacağız. Bu fonksiyon diğer kaynak yükleyici fonksiyonlardan biraz farklı:
int LoadString(HINSTANCE hInstance,UINT uID,LPTSTR lpBuffer,int nBufferMax);
hInstance - diğer kaynak yükleme fonksiyonlarımızla aynı.
uID - yüklemek istediğimiz metin tablosu girişinin ID'si. Bir integer parametre, yani MAKEINTRESOURCE makrosunu kullanmaya gerek yok.
lpBuffer - metin verisini alacak olan tampon bölgeye string işaretçisi.
nBufferMax - lpBuffer'de belirttiğiniz tamponun fazla dolup GPF hatalarına yol açmaması için içine kopyalanacak maximum karakter sayısı.
Sürüm Bilgisi
Adından da anlaşılabileceği gibi bu kaynaklar, uygulamanızla ilgili sürüm bilgisini içeriyor ve kullanıcı derlenmiş EXE dosyasına sağ tıklayıp Özellikler->Sürüm sekmesini seçtiği zaman gösterilecek olan sürüm bilgisini içeriyor. Uygulama başına sadece bir adet sürüm bilgisi ekleyebilirsiniz.
Kaynaklar konusunun bu kısmı bundan ibaret. Değil, olamaz tabii ki, yoksa Microsoft Windows Core SDK dökümanları bu kadar büyük olmazdı :). Buradakiler birer özet niteliğinde, gerisini getirmek size kalmış. Makalenin örnek kodlarını (ve kaynaklarını - sanat eseri olmasalar da) buradan indirebilirsiniz.