Win32 Programlamaya Giriş

Win32 Programlamaya Giriş

NOT : Makale de yer alan kod parçaları sadece konunun anlaşılması için kullanılmıştır, bu nedenle o kod parçalarını kullanarak proje oluşturma gafletinde bulunmayın :) Son kısımda ilgili çalışan kod mevcuttur.Ana sistem parça parça anlatışmıştır, tüm koda bakınca herşey çok daha net olacaktır. Kolay gelsin.

Win32 Api Microsoft tarafından Windows işletim sistemleri için tasarlanmış fonksiyonlar ve yapılar serisidir. Bu fonksiyonlar sayesinde windows işletim sistemleri icinde geliştirdigimiz uygulamaları istediğimiz gibi kontrol edebiliriz. Her türlü ayarını degistirebiliriz ve hatta diger o an çalışan programlara bile atlayıp onlar hakkındada bilgi sahibi olabiliriz :) Kısacası windows işletim sistemleri serisi ortamında program geliştirmek için kullanılan fonksiyonlar ve yapılardır. Peki bunun oyun programlama alakası nedir diyecek olursak cevabımız şu olur ; windows ortamında oyun geliştirmek icin bazı win32 fonksiyonlarını bilmemizde fayda vardır. Herşeyden önce böyle bir fonksiyonlar kümesinin bir sistemi olması lazım dimi, düzenli bir sistem. Peki bu sistem nasıl calısır ? Şu windows ta CTRL + ALT + DELETE yaptıgımızda uygulamalar kısmında bulunan programlar nasıl calısır veyahut işlemler kısmındaki programlar nasıl çalışır? windows programlarının calısma prensibi nedir ? Nasıl bir sistem kurulmustur ?

Bu sistem windows 1.0 çıktığından beridir aynı süre gelen ana bir sistemdir. Tabi eklentiler olmuştur bir çok, fakat bunlara değinmek konu dışı olacagından sadece bir örnek olarak multithread’i verelim. Bir programın işlemciyi daha verimli kullanmasını (paralel gibi çalışır göstermesi) saglayan bir sistem desek yanlıs olmaz sanırım.

Pencere, tam olarak dikdörtgen sekilde olan , kullanıcıdan veri alan ve karsılığında sonuc cikaran veyahut gösteren bir kutucuktan ibarettir. Bilgisayar kullanıcısıysanız bi çok pencere görmüşsünüzdür. Su an okuduğunuz bu yazıdaki programda bi penceredir , yazıyı değiştirdikten sonra cikmaya calıştığınızda size yazıyı kaydediğimmi diye soran sinir kutucukta bi penceredir :) Sadece amaçları farklıdır, o yüzden yabancı sitelerde windows programlama hakkında yazılar okuduğunuzda pencere laflarına dikkat edin ve şaşırmayın J. Çünkü bunlar bir çok kategoride sınıflandırılmışlardır. Mesela en basitinden Mesaj penceresi, ve hatta okuyanları pek zorlayacagını zannetmedigim win32 fonksionuda şöyledir :

C/C++ kodu:
MessageBox (NULL, "Sesler yüklenemedi, Yolu kontrol edin","Hata", NULL) ;

Ve fonksiyonun çıktısı şekildeki gibidir.


Anlaşıldığı üzere fonksiyon 4 parametre almaktadır. Birincisi pencereye ait ID ingilizce handle to window diye gectiginden hwnd yapısındandır. NULL olarak girersek ,o pencereye ait olmaz gerçi şu an pek önemi yok. Önemli olan değerler ikinci ve üçüncü değerlerdir. Ikiside basit string degeri almıstır. Biri pencerenin üst kısmına yani başlık kısmına diğeri ise pencerenin ortasına belirtilmek istenen mesajı oluşturan string lerdir. Vayy be amma basitmiş e peki nerde kullanabilirz bunu sistem demiştiniz nerde sistem, mimari ?
===================================================================
Evet şimdi Window 1.0 dan beri kullanılan sistemden bahsedelim. Herşey mesajlaşmadan ibaret diyebiliriz.Örneğin Farenin imlecinin herhangi pencerenin üstüne geldiginde işletim sistemi o pencereye mesaj atar. Heyy yanlış okumadınız işletim sistemi mesaj atıyor. Mesaj işletim sistemine atılmıyor. Dikkat edilecek hususlardan bir taneside bu. Bize düşen görevde bu mesajları programımızda yakalamak olacak. Işin çok basit açıklaması bu. Basit switch yapısıyla bunu düsünebilirz aslında :

C/C++ kodu:
switch (message) 
{
 
    case WM_CREATE:
    MessageBox (NULL, "Pencere Yaratıldı!","Uyarı", NULL) ;
    break;
 
    case WM_DESTROY:
    MessageBox (NULL, "Pencere Kapatılıyor..."," Uyarı", NULL) ;
    break;
}

Anladığınız üzere Windowsta pencere yaratıldığı zaman işletim sistemi ilgili pencereye WM_CREATE mesajı gönderiyor.( WM açılım : window message ). Pencere kapatıldıgı zaman ise WM_DESTROY mesajı gönderiyor.Böyle birçok mesajlar var.WM_MOUSEMOVE mesela farenin imleci ile ilgili verilere ulaşmak için. Pozisyon Hover time vs gibi. Bunların genişletilmiş örneğini microsoft un MSDN (Microsoft Developer’s Network) sitesinde bulabilirsiniz. Mesaj listesine yani. Bi kere mimariyi anladınızmı gerisi sadece arayıp bakmanıza kalır.
===================================================================
Peki bu mesajları nasıl alırız ? hangi fonksiyon ? Aşağıdaki kod parçası sanırım bu işin nasıl çalıştığını göstermeye yeter. Merak etmeyin makalenin sonunda hazır kod mevcut olacak ve siz bunları yazmak zorunda kalmayacaksınız :) Sadece ne işe yaradıklarını anlayın ve değiştireceğiniz yeri bilin yeter. :)

C/C++ kodu:
MSG msg;

while (GetMessage(&msg, NULL, 0, 0))
{
    if (msg.message != WM_QUIT)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

Oyunun Ana Döngüsü WM_QUIT mesajı gelene kadar çalışacaktır. WM_QUIT mesajı gelince sona erecektir. PeekMessage komutuyla MSG adlı yapıdan olusturdugumuz msg adlı değişkeni gelen mesaj bilgisiyle dolduruyoruz. Böylece msg.message şeklinde esas önemli olan şeye yani mesaja ulaşabiliyoruz. Eğer WM_QUIT dısında bir mesaj geldiyse o zaman DispatchMessage fonksiyonu ile gelen mesajı pencere prosedürüne yollar. Bu pencere prosedüründe de mesaj işlenir. Nasıl işlenir peki prosedürmü o ne ? Window prosedürü ise Callback bir fonksiyondur. Bütün mesajlar bu fonksiyonda işlenir . Bir önceki kod örneği aslında bu fonksiyonun içinde olur.

C/C++ kodu:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        MessageBox(NULL, "Pencere Yaratıldı!", "Uyarı", NULL);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

Deminki mesaj kodundan farklı olarak WM_DESTROY kısmında PostQuitMessage olmasıdır. WM_DESTROY mesajı window kapatılınca deil tam kapatılınırken yollanan bir mesajdır. Bu yüzden ayrı bir api ile pencereye WM_QUIT mesajı yollamak gerekir. Oda PostQuitMessage ile gerçekleştirilir. Eğer yakalamak istemediğimiz bir mesaj gelmişsede onun içinde default pencere prosedürü çalıştırılır. Bu Callback fonksionu işletim sistemi tarafından doldurulur yani pencerenin handle i, mesajı, wParam, lParam degişkenleri. (WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)). Bu degerleride biz yakalayarak istedigimizi yaptırırız pencereye. Burayı okuduktan sonra yukardaki koda tekrar bakarsanız daha rahat anlaşılacaktır.

===================================================================
Peki pencereyi veya pencereleri nasıl yaratacağız ?

C/C++ kodu:
HWND hStatic1 ;
 
hStatic1 = CreateWindow("static","Isminizi Girin:",
            WS_CHILD | WS_VISIBLE,
            0,0,105,20,hWnd,(HMENU)203,
            (hInstance,NULL);

CreateWindow fonksiyonu ile her türlü pencere yaratabiliriz. Bunlara örnek butonlar, textbox lar, scroll barları örnek verebiliriz. Bunların hepsi birer penceredir. Yukardaki örnekte bir staticbox veyahut label penceresi yaratilmistir. 1. aldıgı değişken bir string degerinde class ın ismini vermektedir yani static ile belirtilmek istenen static bir pencere genelde içinde yazı bulunduran pencere yani. ‘. Aldığı değer ise başka bi string olup bu pencerede görünecek olan yazı olacaktır. Her bir pencerenin kendine ait özelliği mevcuttur. Statik pencerelere kullanıcı giriş yapamaz sadece etiket görevi yaparlar. Aşşağıdaki ekran görüntüsünden ne demek istediğimi daha rahat anlayabilirsiniz. WS_CHILD ve WS_VISIBLE ise pencerenin özellikleridir. Her pencerenin özelliği farklı, bir veyahut birden fazla olabilir. Eğer birden fazla özelliği olmasını istiyorsanız ‘|’ işareti ile örnekteki gibi özellikleri ayırarak belirtebilirsiniz. Örnekteki özellikler derki : bu yaratılan pencere ana pencerenin alt bir penceresidir WS_CHILD. Diger özellik ise pencere yaratıldığı anda kullanıcı tarafından görülebilir olacak. Bu özellik sonradanda ShowWindow fonksiyonu ilede aktif olabilir ve aynı fonksiyon ile görünmez yani invisible olabilir.Sonra gelen 4 tane int türündeki değerler ise tamamen pozisyon ve boyut bilgisidir. Ilk ikisi yani 0 ve 0, statik pencerenin ana pencerenin görünen kısmındaki X ve Y koordinatlarıdır. 105 ise statik pencerenin X uzunluğu, 20 ise statik pencerenin Y uzunluğunu belirtir. Bir sonraki parametre hWnd bu alt pencerenin ana penceresinin sahip olduğu handledır. Yani hWnd. Bu durumda anlaşılırki başka bir createwindow dan bir hWnd değişkeni elde etmişizdir. Bir sonraki hInstance değişkeni ise programa işletim sistemi tarafından verilen bir handle dır. Bir programa bir handle olarak düşünülebilir. Bu pecereye ait hInstance i belirtiyoruz sadece ve penceremiz hazır.


Başka bir pencere daha ekliyelim :

C/C++ kodu:
hEdit1 = CreateWindow("edit"," ",
            WS_CHILD | WS_VISIBLE | WS_BORDER,
            0,30,200,20,hWnd,(HMENU)100,
            (hInstance,NULL);

Gene aynı şeyler bu pencere için geçerli. 1. parametre olarak static yerine edit stringi gelmiş. Böylece ullanıcı input değer girebilicek. 2. parametre boş string, 3. parametrede ek olarak WS_BORDER var buda demek oluyorki edit penceremiz daha rahat görülebilmesi için etrafına bir border çekilecek.


===================================================================
Bundan başka son olarak ana penceremizin register olması yani sisteme kayıt olması gerekiyor.
C/C++ kodu:
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SILSONRA);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = (LPCTSTR)IDC_SILSONRA;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

return RegisterClassEx(&wcex);

Burdaki wcex, dolduracagımız ve sonra register yani kayıt edeceğimiz bir yapıdır. Style yapısı 2 değer almıştır, CS_HREDRAW ile eger pencerenin X ekseninde boyutu degisirse pencerenin tekrar tazelenmesi için, CS_VREDRAW ise Y ekseni için geçerli. Her tazelenmede WM_PAINT mesajı yollanacaktır yani bzim her tazelenmede yapmak istediğimiz şeyleri bu mesajla yakalayabiliriz.

Şu ana kadar anlattığım yapılar fonksiyonlar yani sistem otomatik olarak Visual studio .net 2002, 2003 ve 2005 in win32 projesi oluşturularak basitçe program tarafından hazırlanmaktadır. Bize düşen anlattığım kodları baştan yazmak değil nerde neyin olduğunu anlamaktır. Böylece belli değişiklerle Pencereye istediğimizi yaptırabiliriz. Okuyana tavsiyem kodu açıp ordan kod parçalarının nerelerde kullanıldığını bakmanız ve ne işe yaradığını tekrar göz gezdirmeniz olacaktır. Anlattığım yapılar bütün win32 api leri için ana yapılardır. Bazı yabancı sitelerde OpenGL ve win32 nin iyi bi şekilde entegre edilmiş halini göreceksiniz. Bunlarıda incelemenizi tavsiye ederim ve genel yapının aynı olacağını farkedeceksiniz.

Kaynak Kodlar:
http://www.mediafire.com/download/mexo1admfq7840u/Win32_programlamaya_giris.rar


Kodu Visual Studio 2003 IDE si ile açmanızı tavsiye ederim.

Levent A. Sevgili

Yorumlar

Bu blogdaki popüler yayınlar

Doxygen Kullanımı

SDL Nedir?

Winamp'a Plugin Yazmak