Anasayfa Eğitseller Programlama Windows Programlamaya Giriş

Windows Programlamaya Giriş PDF Yazdır e-Posta
Kullanıcı Değerlendirmesi: / 7
ZayıfEn iyi 
Eğitseller - Programlama
Cuma, 20 Ekim 2006 19:40
Bir oyun programcısı için windows programlama , içinde  grafiklerimizi  çizdireceğimiz bir pencereyi programlamakla yetinebileceğimiz bir konu.

Pek fazla derine dalmaya gerek yok.Yalnız Windows un temeli olan event-driven(olay-güdümlü) programlamadan biraz bahsetmemiz gerekecek.

Diğer programlama metodlarından farkını anlatmak için  , programlama metodlarından kısaca bahsedeceğim.

İlk yazılan programlar goto deyimini kullanılarak , program içinde çok fazla dallanma yapıyormuş.goto deyimleri program büyüdükçe hangi işin ne

zaman , hangi sırada yapılacağı sorunu, zamanla  programlama dünyasına hediye ediyor!

Bu sorunu çözmek için , C veya Pascal programlama dilinde olduğu gibi , top-down veya structured programlama denilen ,her işin sırayla yapıldığı

programlama metodu kullanılmaya başlanmış.Bu metod yapılacak işi belli bir düzene sokmuş ve karmaşıklığı gidermiş.Zamanla , programların

büyüklüğü arttıkça , değişken sayısı artıyor ve bu değişkenlerin yönetilebilirliği de zorlaşıyor.Demişler ki: bizim için gerekli olan fonksiyonları ve bu

fonksiyonların kullandığı değişkenleri belli bir alana hapsedelim , böylelikle daha kolay yönetilebilen   daha büyük parçalar(nesneler) elde ederiz .Bu

mantık da bize NYP (nesne yönelimli programlama) modelini getirmiş . Her ne kadar nesne yönetimi   önemli bir sorun olsa da   NYP işleri fazlasıyla

kolaylaştırmış .

  Şimdi size bahsedeceğim event-driven programlamada ise  olayları tetikleyen “if-else-while-for…”  un  varlığı veya sırası değil , kullanıcının ulaştığı

arayüzden ,örneğimizde pencereler ,yaptığı isteklerdir.Bu metodun tercih edilmesinin başlıca gayesi programların kullanımını

kolaylaştırmaktır.Event-driven(olay güdümlü ) programlama olmasaydı bugün hala daha DOS ta komut yazıyorduk . Windows event-driven

programlama metodunu  kullandığı için çok meşhur olmuştur..Nesne yönelimli  programlamada structured programlama kullanılabildiği gibi (örneğin

C++)  ; olay güdümlü programlamada her ikisi de ( NYP veya structured ) kullanılabilir.Structured programlamada (örneğin pascal) programın akışını

değiştiren şey , “ if ” ile kontrol edilebilen bir değişken olabilir . Olay güdümlü programlama da ise , programın akışını değiştirebilecek olan bir butona

basma veya mouse tıklama işidir. Olay güdümlü programlamada her yaptığınız fiil(tuşa basma , Mouse a tıklama ) bir olaydır ve program tarafından

işlenmelidir.Bu fiillerin program tarafından doğru şekilde anlaşılabilmesi için kendine has bilgileri barındırmaları gerekir.Bu bilgileri barındıran yapılara

mesaj diyoruz.Kullanılan pencereye ait mesajlar yine o pencereye ait mesaj kuyruğuna eklenir ve işlenmeyi bekler.Her mesajın öncelik sırası vardır ve

bu sıraya göre mesaj döngüsüne girerek işlem görürler.Mesela tarayıcı sayfasında, sayfa yenile tuşuna bastınız ve birden fikrinizi değiştirip aniden

tarayıcınızı kapattınız.Burada kapatma olayının  önceliği yenileme olayından yüksek olduğu için  tarayıcınız kapatılır ve ilk önce istediğiniz yineleme

işlemi yapılmaz.

 

   Aranızda ,“Olay-güdümlü programlamayı anlattın   , windows un  temeli olan multi-programming ve multi-threading de nedir? “ diyenleriniz

olabilir.Kısaca multi-programming, tek işlemcide aynı anda(aslında aynı anda değil) birden fazla programın çalışabilmesi işidir.Programlar ihtiyacı olan

işlemleri çok kısa zaman aralıklarında(time quantum) sırayla işlemciye yaptırırlar ve işlenmiş veriyi saklarlar. Diğer programlar işlemlerini yaptırırken

 sakladıkları işlenmiş veriyi bize sunarlar.Biz de depolanmış veriyi kullanırız , sanırız ki 10 tane program birden çalışıyor halbuki çalışan bir tane

 programdır ve işlenmiş veriyi kullandığımız 9 tane program vardır(Bir bilgisayarda 10 programın birden çalıştığı durumda) .”Multi-threading   hakkında

çok çeşitli şeyler var  , şimdi anlatıp kafanızı karıştırmak istemiyorum” demeyi isterdim çünkü ben de bir şey bilmiyorum J

 

  Şu ana kadar size olay güdümlü programlamadan bahsettim.Belki fark etmişsinizdir , olay güdümlü programlamada üç ana yapı vardır.Olayın

gerçekleşeceği  görsel bir birim , olayı bildirecek bir mesaj ve mesajı işleyecek başka bir fonksiyon.Bunlar olay-güdümlü programlamada mutlaka

olmalıdır.Windows ta bu yapılara karşılık gelenler : pencere ,mesaj ve mesaj işleme fonksiyonudur.  

İlk yapıyı , windows’ta penceremizi , üretebilmemiz için WinMain() isimli  ana bir fonksiyona ihtiyacımız var.Bu fonksiyon C deki main()fonksiyonunun

karşılığıdır , çalışacak her programın mutlaka bir ana fonksiyona ihtiyacı vardır.WinMain() içinde penceremizi üretip yine bu

pencereden mesaj beklemeye başlayacağız.Sonrasında bu mesajları işleyecek WndProc() isimli fonksiyonu yazacağız.Bu fonksiyonun başında

CALLBACK isimli bir niteleyici vardır ki   bu fonksiyonun , bizim çağırmamızdan ziyade ,  ihtiyaç duyulduğu zaman işletim sistemi tarafından

çağrılacağını belirtir.Bu da işletim sistemi tarafından olayların algılanması ve cevaplanması için gerekli olan bir durumdur. 

Şimdi sırasıyla ihtiyacımız olan fonksiyonları yazalım.Birincisi  pencereyi üretecek ve  mesaj döngüsünü başlatacak WinMain fonksiyonudur ;

ikincisi üretilen mesajları işleyecek WndProc fonksiyonudur.Mesaj döngüsünü başlatmamız pencereyi çalıştırmakla eşdeğerdir. WinMain

fonksiyonu   programın girişidir   ve her programda bir tane olur  , diğer fonksiyon çağrımları bu ana fonksiyondan yapılır.

Herhangi bir program birden fazla pencereye ihtiyaç duyabilir. Bu pencerelerin her birinin ayrı ayrı tiplerinin belirlenmesi, bu tiplerin işletim

sistemine bildirilmesi ve en sonunda bu tiplerden pencere üretilmesi gerekir. Bütün bu dediklerimi WinMain fonksiyonu yapar. Aşağıda WinMain

fonksiyonunun görevleri gösterilmiştir.


WinMain()

1-Pencere tipini belirle

2-Bu pencere tipini işletim sistemine kaydet

3-İşletim sistemi tarafından tipi bilinen pencereyi üret

4-Üretilen pencereyi göster

5-Bu pencereden mesaj almaya başla(pencereyi başlat, mesaj döngüsüne gir.)

            Bu dediklerimin hepsini sırayla yapacağız yalnız size kod göstermeden önce windows’ ta tanımlı bazı veri tiplerinden bahsetmek istiyorum, yazı

boyunca göreceğiniz diğer değişkenleri yeri gelince açıklayacağım. Bu tipler Windows.h dosyasında tanımlıdır.Bu tanımlı değerleri her windows

programımıza ,yazdığımız programın   ilk satırına  #include <windows.h> yazarak katarız.İlk windows programınızı yazarken çok fazla tanımadığınız

kelime ile karşılaşacaksınız , bu tanımlı tipler aslında C – C++ programlama dillerinden bildiğiniz tiplerin hemen hemen karşılığıdır ama windowsa

uyarlanmış oldukları için ilk başta  biraz karmaşık gelebilir.

HANDLE   : 32 bitlik bir integer veriye karşılık gelir .Programımızda integer yerine  kullanabiliriz.

 HWND     : Handle window diye okunabilir , 8 bit değerindedir.Mesaj gönderdiğimiz pencereyi sistemdeki diğer pencerelerden ayırt eden bir

değerdir.Handle değeri aslında bir pointer pointeri dir ve pencere bilgisini tutan hafızadaki adresi gösterir.Böylesine iki katmanlı bir yapının(pointer

pointeri) kullanılmasının sebebi windowsun hafıza yönetimiyle alakalıdır.Windows kendi içinde yaptığı yer değişimlerini bizim kullanımımızdan soyutlamak

için böylesine iki katmanlı  bir yolu tercih eder.Ben HWND ile tanımlanmış pencereleri tanımlayan değişkenlere , kulp kelimesinin kısaltılmışı olan ‘k’

önekini koyacağım. Handle kelimesinin yerine kulp kelimesi Türkçe’de aynı anlama gelir.Ayrıca ilerde göreceğiniz gibi nesnelerin kulpundan tutup işlem

yapacağız veya parametre olarak yollayacağız.

BYTE : 8 bitlik değerdir.

WORD :16 bitlik unsigned integer değerdir.

DWORD : Double word diye okunabilir.32 bitlik unsigned integer değerindedir.

LONG : 32 bit long değerindedir.

BOOL : Integer değerdedir.False veya true değerini alabilir.

LPSTR : Pointer to string .String bir değişkeni işaret eder.LP long pointer dan gelir , long pointer nitelemesi 16 bit programlama döneminden kalmıştır.

LPCSTR : Const pointer to string .String bir değişkeni işaret eden sabit bir pointer dir.

UINT : 32 bit  unsigned integer değerindedir.

 

Şimdi oyunlarda kullanacağımız pencereyi üretecek programımızı yazalım.Programda sıklıkla :: ve sonrasında windows ta tanımlı fonksiyonları kullandım ,

aslında bu iki tane :: üst üste noktalar kullanılmasa da olur . İki nokta ‘ :: ‘kullanılan fonksiyonların windowsun kendi ad uzayında (namespace) tanımlı

olduklarını belirtmek için kullanılmıştır.

 

#include<windows.h> // her windows programında olmalıdır.

// Pencerenin tipinin belirlenmesi ,tanıtılması ve üretilmesini yapacak fonksiyon , Winmain //içinden çağrılacak.Doğru şekilde üretmişse true değerini

döndürecek.

bool PencereUret( HINSTANCE kProgram , int Goster) ;

 

// Ana penceremizi sistemdeki diğer pencerelerden ayıran kulpumuz

HWND kAnaPencere = 0 ; //Ana pencere kulpu,tutucusu : ilk değer olarak 0 atanır.

// Penceremizi mesaj dongusune sokarak çalıştıracak, WinMain içinden çağrılacak

int PencereCalistir();

// Mesajlarımızı işleyecek fonksiyon , işletim sistemi(Windows) tarafından çağrılır.

//Gönderdiğimiz 4 parametreyi ilerde açıklayacağım

LRESULT CALLBACK WndProc( HWND kPen , UINT msg ,WPARAM wParam, LPARAM lParam  );

// Programın başladığı ana fonksiyonumuz

int  WINAPI WinMain(HINSTANCE kProgram , HINSTANCE kOncekiProgram ,LPSTR lpEmirSatiri ,int nGosterEmri )

{

            // Penceremiz üretilebiliyor mu?

            if(!PencereUret(kProgram , nGosterEmri ))

{

            // message box  ile ilgili açıklama aşağıda

            ::MessageBox(0,”pencere üretilemedi”,”Hata”,MB_OK);

            Return 0 ;

}

//Üretildiyse mesaj döngüsüne gir

return PencereCalistir();

// WM_QUIT dönerse  ana program düzgün şekilde kapatılmış demektir , şayet hata  //oluşmuşsa  0 ile biter ki pencere mesaj döngüsüne

girememiştir demektir.

}

bool  PencereUret( HINSTANCE kProgram , int goster)

{

// 1-Ilk aşama olarak pencere tipimizi belirleyelim , window class “ c++ class “ıyla alakalı  değildir, //pencere tipi anlamında kullanılır

            WNDCLASS penSinifi ; // pencere sinifi anlamında

            penSinifi.style = CS_VREDRAW | CS_HREDRAW ; //ClassStyle vertical or //horizontal redraw anlamına geliyor , penceremiz yatay veya dikey

olarak  //şekillendirildiğinde  penceremizin içi yeniden çizilecek

            penSinifi.lpfnWndProc = WndProc ; // long pointer function Window procedure, //penceremizin mesajlarını işleyecek fonksiyonun belirtilmesi lazım.

            penSinifi.cbClsExtra = 0 ;//count byte class Extra anlamında ,class ın  extradan veri //depolamasına gerek yok çünkü fazladan iş yapmayacak

            penSinifi.cbWndExtra = 0 ;// count byte window Extra anlamında ,pencerenin //extradan   veri depolamasına gerek yok

            penSinifi.hInstance = kProgram ; // Handle instance , çalışan programı sistemde diğer // programlardan ayıran Handle değeri belirtilmelidir.

            penSinifi.hIcon = ::LoadIcon(0 , IDI_APPLICATION );// Handle ıcon ,Pencerenin en //üst  soldaki imgesini yükle

            penSinifi.hCursor = ::LoadCursor(0 , IDI_ARROW );// metni gireceğiniz zaman //ekranda yazı yazılacak yerde beliren şekili yükle

            penSinifi.hbrBackground =(HBRUSH)::GetStockObject(WHITE_BRUSH) ;

            penSinifi.lpszMenuName = 0 ; // long pointer string zero , Penceremizin menüsü //olmayacak, sol üst köşede  görünen , dosya ,

düzen ,görünüm vs.vs.

            penSinifi.lpszClassName = “SinifIsmi”;// sonu 0 ile sonlandırılmış bir string , //penceremizin ismi veriliyor.

 

// 2-Penceremizin tipini belirledik , şimdi işletim sistemine bu pencere tipini kaydedelim

if(!::RegisterClass(&penSinifi))

{

 ::MessageBox(0,“pencere işletim sistemine kaydedilemedi”,”Hata”,MB_OK);

return false ;

}

//3- Penceremizi üretelim , global olarak tanımlı kAnaPencere değişkenine üretilen pencerenin  // kulpunu atar

kAnaPencere = ::CreateWindow(

“SinifIsmi”, //Sınıf ismi

“PencIsmi” , // pencere ismi

WS_OVERLAPPEDWINDOW ,// statndart bir pencere //stiline sahip olsun

CW_USEDEFAULT ,// açıklama aşağıda

CW_USEDEFAULT ,

CW_USEDEFAULT ,

CW_USEDEFAULT ,

0,

0,

kProgram ,

0

) ;

if( kAnaPencere == 0  )

{

            ::MessageBox(0,“Pencere üretilemedi ”,”Hata”,MB_OK);

            return false ;

}

//aşağıdaki fonksiyonda goster değeri pencerenin ilk defa nasıl gösterileceğini belirler ,

// bazı atamalar :SW_MINIMIZE , SW_MAXIMIZE ,show window minimize gibi.Bizim //göndereceğimiz SW_SHOW olacak ve bu fonksiyon pencereyi

göstermekle yetinecek.

::ShowWindow(kAnaPencere , goster ) ;

::UpdateWindow(kAnaPencere);

return true ; // herşey düzgün çalıştı ise true değerini döndürecek

 

 

 

}

// Bu fonksiyon ile alakalı açıklamalar aşağıda

int PencereCalistir()

{

            MSG mesaj ;

            ::ZeroMemory(&mesaj , sizeof(MSG));

            while( ::GetMessage(&mesaj , 0 , 0 , 0 ) )

{

            ::TranslateMessage( &mesaj );

            ::DispatchMessage( &mesaj );

}

return mesaj.wParam ;

 

}

LRESULT  CALLBACK  WndProc( HWND penKulpu ,

UINT msj ,

WPARAM wParam ,

LPARAM lParam

)

{

            switch(msj)

{

case WM_LBUTTONDOWN :

::MessageBox(0,”farenin sol tarafına bastınız ”,”Uyarı”,MB_OK);

return 0 ;

case WM_KEYDOWN :

if(wParam == VK_ESCAPE )

            ::DestroyWindow(kAnaPencere);

            return 0 ;

case WM_DESTROY :

::PostQuitMessage(0);

return 0 ;

}

return DefWindowProc( penKulpu,msj,wParam ,lParam);

 

 

}

Yukarıdaki programı word ile yazdım , kendisi otomatikman bazı düzenlemeler yaptı ,kopyala-yapıştır yaparsanız  kod çalışmayabilir , o yüzden

ekteki kodu kullanın .

           

            Şimdi kodu açıklayalım. Programımızda tam 4 tane fonksiyon var.Bunlardan iki tanesini yardımcı fonksiyon olarak kullandım. Bunlar pencerenin

üretilmesi ve çalıştırılması işlerini toplu olarak yapan PencereUret ve PencereCalistir  fonksiyonlarıdır. Bu fonksiyonların yaptıkları işler WinMain içine

de yazılabilirdi , yapılan işleri daha iyi anlayabilmeniz için böyle bütün halinde yazdım.Zaten bu fonksiyonlar WinMain içinden çağrıldığı için yaptıkları

işler WinMain fonksiyonu sınırları içinde kalıyor.

           

            #include<windows.h> dosyası windows programlamada kullanılan veri tiplerinin ve fonksiyonların çoğunun tanımlı olduğu dosyadır.Her windows

programının başında mutlaka olmalıdır.

            Bundan sonraki kısım, WinMain fonksiyonuna kadar, programda kullanılacak fonksiyon prototiplerini tanımlıyor.

Birincisi pencerenin tipinin belirlenmesi, tanıtılması ve üretilmesini yapacak, Winmain içinden çağrılacak  olan PencereUret

fonksiyonudur.Pencere  doğru şekilde üretmişse true değerini döndürür .Bu fonksiyona parametre olarak programımızı sistemdeki diğer

programlardan ayıran kProgram(program kulpu) değeri atanır.Ayrıca goster isimli parametre üretilen fonksiyonun ilk olarak nasıl

gösterileceğini belirler.

İkincisi ,penceremizi mesaj dongusune sokarak çalıştıracak, WinMain içinden çağrılacak olan PencereCalistir fonksiyonudur.

Üçüncüsü , WndProc fonksiyonudur.Çalışması için pencerenin mesaj alması(Mouse tıklaması , tuşa basılması) gerekir.Mesaj aldığı zaman

windows tarafından otomatik olarak çağrılır , bunu fonksiyonu tanımlayan CALLBACK nitelendiricisinden anlıyoruz.Başındaki LRESULT

değeri ise fonksiyonun döneceği değeri gösterir ki C programlarındaki long değerindedir(4 byte uzunluğunda ).Bu LRESULT değeri bu

fonksiyonun doğru olarak çalışıp çalışmadığını Windows a döndürür.Fonksiyonun parametre olarak aldığı değerler :

1-HWND tipinde   kPen(Pencere Kulpu) değeridir.WndProc hangi pencerenin mesajlarını işleyeceğini bilmelidir.

2-MSG tipinde msj değeridir.  Windows’ta tanımlı mesaj “MSG “ yapısı ,alınan her mesaj için işletim sistemi tarafından doldurulur ve

pencerenin

ilgili mesaj işleyicisine(WndProc tanımladık) gönderilir. 

typedef struct tagMSG {

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

DWORD time;

POINT pt;

} MSG;

Bu yapıda :

 hwnd : Mesajın ait olduğu pencereyi belirtir.

 message : mesajın tipini belirtir.  Mouse mesajı , veya tuşa basma mesajı gibi.

 wParam : 32 bitlik parametrik bir değerdir.Mesajın özelliklerini tam belirlemek için kullanılır.Mesela bu mesaj tipi tuş basma mesajıysa wParam değeri

hangi tuşa basıldığını gösteren bir değer alır.Mesela wParam = 64 ise A harfine basıldı gibi…

lParam : 32 bitlik parametrik bir değerdir.Mesajın özelliklerini tam belirlemek için wParam ile birlikte kullanılır.

time : 32 bitlik (WORD değerde ) olayın olduğu zamanı tutan veri yapısıdır..

Pt : POINT yapısındadır . x ve y değerine sahip olup olayın olduğu anda mouse un hangi konumda olduğu bilgisini tutar.


Yandaki şekil windowsun x ve y değerlerinin artma yönlerini gösterir.Hesaplarınızda bunu göz önüne alın.

Bir ekranın 640x 480 çözünürlükte olması demek x değerinin en fazla 640 ; y değerinin en fazla 480 olacağı anlamına gelir.

3 ve 4. parametreler yukarında açılandı. WndProc fonksiyonuna gönderilen wParam , lParam ve kPen parametreleri , ilerde açıklayacağımız şekilde

DispatchMessage fonksiyonu tarafından doldurulur.

Gelelim WinMain fonksiyonumuza :

int  WINAPI WinMain(HINSTANCE kProgram ,

 HINSTANCE kOncekiProgram ,

LPSTR lpEmirSatiri ,

int nGosterEmri )

            Başındaki int değeri , WinMain fonksiyonu mesaj döngüsüne girmişse WM_QUIT mesajının wParam değerini alır ki pencerenin doğru şekilde

çalışıp sonlandırıldığını gösterir.Şayet mesaj döngüsüne girmemişse   WinMain fonksiyonu sisteme 0 değerini döndürür.WINAPI ise fonksiyonun sistem

tarafından standart biçimde çağrılacağını gösterir. windows.h dosyasında WINAPI şöyle tanımlıdır:

#define WINAPI _stdcall

Bu konu şu aşamada o kadar önemli değil.

İlk yollanan parametre WinMain fonksiyonun sistemde çalıştırdığı programın tanımlayıcısıdır , bu değer  sistem tarafından(işletim sistemi) verilir.2.

parametre  artık kullanılmamakta(32 bit Windows programlamada ).

WinMain fonksiyonuna yollanan 3. parametre CommandLine (WinMain Dos tan çalıştırılırsa) dan gönderilen değerleri tutar.Tipi LPSTR dir ki “long

pointer to string” anlamına gelir.32 bit windows programlamada *char tipine karşılık gelir.Son parametre ise sistem tarafından varsayılan olarak

SW_SHOW olarak atanır.Ana fonksiyonun(WinMain) çalıştırdığı programda üretilen pencerenin ilk üretildiği zaman nasıl gösterileceğini tanımlar. 

WinMain fonksiyonunun 5 görevi olduğunu söylemiştik.

1-Pencere tipini belirle                                                  \

2-Bu pencere tipini işletim sistemine kaydet                                 \

3-İşletim sistemi tarafından tipi bilinen pencereyi üret      / Bu dördünü PencereUret yapar

4-Üretilen pencereyi göster                                                       /

5-Bu pencereden mesaj almaya başla(pencereyi başlat, mesaj döngüsüne gir.)  || Bunu Pencere Calistir fonksiyonu yapar.

Bu iki fonksiyonu çağırdığımız zaman WinMain fonksiyonun görevleri tamamlanmış oluyor.

if(!PencereUret(kProgram , nGosterEmri ))// if sorgusunun içinde ! var.

{

            ::MessageBox(0,”pencere üretilemedi”,”Hata”,MB_OK);

            return 0 ;

}

PencereUret fonksiyonu çalışamadıysa ,pencere üretememişse, false değeri döndürür , bu durumdan haberdar olmak için , yanlışlığı MessageBox

ile bize  bildiren hata mesajı gösterdik.

MessageBox şöyle tanımlanmıştır:

<span style="font-size: 8pt; font-family: Verdana">int <span style="background: #316ac5 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">MessageBox</span>(      
 
 
 
HWND <em>hWnd</em>,</span>
<span style="font-size: 8pt; font-family: Verdana">    LPCTSTR <em>lpText</em>,</span>
<span style="font-size: 8pt; font-family: Verdana">    LPCTSTR <em>lpCaption</em>,</span>
<span style="font-size: 8pt; font-family: Verdana">    UINT <em>uType</em></span>
<span style="font-size: 8pt; font-family: Verdana">);</span>

İlk parametre hata mesajının hangi pencereye ait olduğunu gösterir , biz 0 yazdık , herhangi bir pencereye ait olmasını istemedik.

2.parametre mesaj kutusunda gösterilecek olan hata yazısını alır.Long pointer to  string tipindedir.

3.parametre mesaj kutusunun tepesinde gösterilecek yazıyı tutar

Son parametre ise mesaj kutusunun davranışını belirler.Biz MB_OK kullandık ki Message Box OK anlamındadır ve OK butonuna sahip bir mesaj

kutusu gösterir.

Gördüğünüz gibi PencereUret fonksiyonu pencere üretememişse pencere üretilemedi mesajını gösteren MessageBox görünecek , sonrasında

WinMain fonksiyonunu bitiren 0 değeri geri döndürülecektir.

WinMain içinden çağrılan PencereCalistir fonksiyonun döneceği değere göre WinMain sonlanır.PencereCalistir fonksiyonu  0 ya da  WM_QUIT

mesajının wParam değerini geri döndürür.

           

PencereUret  fonksiyonunda kullanılan windows ta tanımlı fonksiyonlar ve yapıların açıklamaları :

Bu fonksiyonda yukarıda söylediğimiz 4 görev yapılır:

1-Pencere tipinin tanımlanması.Windows ta pencere tipi aşağıdaki yapı doldurularak tanımlanır.WNDCLASS yapısı aşağıdaki gibidir.

<span style="font-size: 8pt; font-family: Verdana">typedef struct {</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>UINT style; </span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>WNDPROC lpfnWndProc;</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>int cbClsExtra;</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>int cbWndExtra;</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>HINSTANCE hInstance;</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>HICON hIcon;</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>HCURSOR hCursor;</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>HBRUSH hbrBackground;</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>LPCTSTR lpszMenuName;</span>
<span style="font-size: 8pt; font-family: Verdana"><span>    </span>LPCTSTR lpszClassName;</span>

}WNDCLASS, *PWNDCLASS;

 

Yukarıdaki yapı ile ilgili açıklamayı programda yaptım.Yalnızca HBURSH hbrBackground değerini açıklamamıştım.

penSinifi.hbrBackground =(HBRUSH)::GetStockObject(WHITE_BRUSH) ;

burada yaptığımız iş ,tipi tanımlanan pencerenin arka planını boyayacak fırçayı belirlemekten ibaret .Bunu yaparken windows ta tanımlanmış fırça(brush)

nesnelerini kulanıyoruz.İstediğimiz fırça nesnesini üreten ise GetStockObject isimli windows ta tanımlanmış bir fonksiyondur. Bu fonksiyona istediğimiz

türde fırçanın ismini parametre olarak yolluyoruz .O da bize istediğimiz fırçayı üretip geri döndürüyor, üretilen fırça bizim penceremizin arka planını

boyuyor.

 PencereUret fonksiyonunda yaptığımız 2. görev ise tanımladığımız pencere tipini windows a kaydetmektir.Bu işi yine windows ta tanımlanmış olan

RegisterWİndow fonksiyonu yapar parametre olarak WNDCLASS tipinde bir yapı alır.tanımladığımız yapıyı bu fonksiyona yolluyoruz.

İf(!::RegisterClass(&penSinifi))

{

 ::MessageBox(0,“pencere isletim sistemine kaydedilemedi”,”Hata olustu”,MB_OK);

return false ;

}

            Gördüğünüz gibi pencere kaydedilememişse WinMain fonksiyonunu bitiren false(0) değeri  geri döndürülür.Durum message box ile bize bildirilir.

 

PencereUret fonksiyonunun 3. görevi  pencerenin üretilmesidir.

            Bu görev için windowsta tanımlı CreateWindow fonksiyonu kullanılır.Bu fonksiyon başarılı lursa bize üretilen pncereyi sistemde bulunan diğer

pencerelerden ayırmamıza yarayacak WNDHANDLE tipide kAnaPencere değerini döndürür.

kAnaPencere = ::CreateWindow(

“SinifIsmi”, //Sınıf ismi

“PencIsmi” , // pencere ismi

WS_OVERLAPPEDWINDOW ,

//  varsayılan değeri kullan  ,Create Window Use Default ,

CW_USEDEFAULT ,//pencerenin gösterilmeye başlanacağı x değeri.

CW_USEDEFAULT , // pencerenin gösterilmeye başlanacağı y değeri.

CW_USEDEFAULT ,//pencerenin genişliği

CW_USEDEFAULT ,//pencerenin yüksekliği

0,                                 // üretilecek penceremiz herhangi bir pencerenin alt pencersi olmayacak

0,                                 //penceremizin menüsü olmayacak , dosya, düzen , görünüm ….

kProgram ,                   //penceremiz bu programa ailt olacak

0                                  // Kendi tanımladığımız veriyi de burada pencereye ekleyebiliriz ama //bunlara gerenk yok , olmadığı için de zaten 0 yolluyoruz.

) ;

CreateWindow fonksiyonu asağıdaki  parametreleri alır.Yukarıdaki kısa açıklamaları aşağıdaki yapıya bakarak inceleyin.

[code:1]
<span style="font-size: 8pt; font-family: Verdana">HWND <span style="background: #316ac5 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">CreateWindow</span>(      

 
 
    LPCTSTR <em>lpClassName</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    LPCTSTR <em>lpWindowName</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    DWORD <em>dwStyle</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    int <em>x</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    int <em>y</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    int <em>nWidth</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    int <em>nHeight</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    HWND <em>hWndParent</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    HMENU <em>hMenu</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    HINSTANCE <em>hInstance</em>,</span>

<span style="font-size: 8pt; font-family: Verdana">    LPVOID <em>lpParam</em></span>

<span style="font-size: 8pt; font-family: Verdana">);</span>

<span style="font-size: 12pt; color: #231f20; font-family: CourierNew">PencereUret fonksiyonunun 4. görevi<span>  </span>pencerenin gösterilmesidir.</span>

<span style="font-size: 12pt; color: #231f20; font-family: CourierNew">Bu da ShowWindow fonksiyonu ile yapılır.Bu fonksiyonun ilk parametresi gösterilecek pencerenin kulpudur.</span>

<span style="font-size: 12pt; color: #231f20; font-family: CourierNew">2. parametre ise pencerenin ne şekilde gösterileceğidir , mesela SW_MINIMIZE </span>

<span style="font-size: 12pt; color: #231f20; font-family: CourierNew">parametresi yollanırsa pencere kendini gösterir göstermez simge durumuna <span> </span>küçültülür.</span>

<span style="font-size: 12pt; color: #231f20; font-family: CourierNew">Şimdi mesaj döngüsüne gireceğimiz fonksiyonu yazalım.</span>

<span style="font-size: 12pt; color: #231f20; font-family: CourierNew">PencereCalistir fonksiyonu parametre almaz.</span>

Bu fonksiyonda MSG yapısında bir değişken tanımlanır.

MSG msj ;

ZeroMemory(&msj,sizeof(MSG)) ;
[/code:1]

 

Bu mesaj yapısı  yukarıda  inceleyebilirsiniz.Bu değişkeni az sonra kullanacağız yalnız kullanmadan evvel bütün bitlerini sıfırlamak gerekir.ZeroMemory

bunu yapar , msj değişkeninin adresini ve bu adresten itibaren ne kadar bitin sıfırlanacağı sizeof(MSG) ile gönderilir.Bu da MSG yapısı kaç byte ise o kadar

byte temizle demektir.

Flag yapılarında tanımlayıcı bilgiler genellikle bitlerden elde edilir.Örnek olarak yukarıda yaptığımız CS_VREDRAW | CS_HREDRAW ı

gösterebiliriz.Bunlardan CS_VREDRAW  00000001 ile tanımlı olsun diyelim , aslında bu değerler 4Byte uzunluğunda bir flag dir , kolaylık olsun

diye bir byte lık değer aldım.. CS_HREDRAW ise 00000010 ile tanımlı olsun. CS_VREDRAW | CS_HREDRAW yaptığımız zaman bu iki değeri

birleştirmiş ve işimizi gören bir flag elde etmiş oluruz.Bu iki değer birleştiği zaman 00000011 değerini alır. Birleştirme işi or ile yapılır ve

operator olarak | işaretini kulanır. Gördüğünüz gibi bu bit değerlerinden biri temizlenmese programın yanlış çalışmasına sebep olacak.O yüzden bir

fonksiyona flag yollarken mutlaka bütün bitlerini sıfırlayın.

while( ::GetMessage(&mesaj , 0 , 0 , 0 ) ) de GetMessage fonksiyonu mesaj kuyruğundan  bir mesaj alıncaya kadar bekler , gelince de mesaj yapısını

doldurur.Bu fonksiyon WM_QUIT mesajı  gelinceye kadar çalışır , bu mesaj geldiği zaman  0 değerini döndürür ve while döngüsünden çıkar.

 GetMessage fonksiyonunun aldığı  mesaj TranslateMessage fonksiyonu tarafından karakter mesajlarına döndürülür ,bu  virtual key message yapısından

bizim anlayacağımız karakter mesajlarına dönme işidir .Böyle bir şey yapılmasa idi her dile ayrı bir program yazmak gerekirdi.Klavyeyi programdan

soyutlamak için böyle bir yola girilmiş olmalı.TranslateMessage fonksiyonu tarafından çevrilen karakterler en son olarak DispatchMessage fonksiyonu

yoluyla mesajı işleyecek fonksiyona(WndProc) yollanır.

PencereCalistir fonksiyonu en son olarak msj.wParam değerini (tabii ki WM_QUIT mesajını ) döndürür ki bu da WinMain fonksiyonuna yollanır ve

 programı düzgün şekilde bitirir.

 

            Gelelim en son ve en zor fonksiyonumuza  dermişim.

WndProc fonksiyonuyla alakalı bazı açıklamaları(mesela parametrelerini ) yukarıda yaptım.O yüzden doğrudan fonksiyonu anlatıyorum.

LRESULT  CALLBACK  WndProc( HWND penKulpu ,

UINT msj ,

WPARAM wParam ,

LPARAM lParam

)

Bu parametrelerden msj yapısına switch yapıyoruz çünkü mesaja göre işlem yapacağız.

switch(msj)

{

Case WM_LBUTTONDOWN : // Window Message Left Buton Down demek

// Farenin sol tuşuna basıldıysa bu durum aktif olacak ve nssage box ı gösterecek

::MessageBox(0,”farenin sol tarafına bastınız ”,”Uyarı”,MB_OK);

return 0 ;// return 0 yaparak WndProc fonksiyonu mesajı işlemiş olarak sisteme döndü.

}

case WM_KEYDOWN :// Window Message Key Down , tuşa basıldı mı?

if(wParam == VK_ESCAPE )  //Tuşa baıldıysa wParam değeri tuşun değerini tutar

::DestroyWindow(kAnaPencere);  // şayet esc tuşu ise pencereyi

//kapat.DestroyWindow hangi pencereyi kapatacağını gönderilen parametre ile anlar.

            return 0 ;                                    // Mesaj doğru şekilde işlenildi, WndProc bitsin

case WM_DESTROY : // Sağ üstteki x işaretine basıldıysa

::PostQuitMessage(0);  // WM_QUIT mesajını yolla , GetMessage bu mesajı alınca //döngüden çıkar , bu  da  programı bitirir.

return 0 ; // mesaj doğru şekilde işlendi.

 

WndProc fonksiyonun en son yaptığı iş kendisinin işlemediği mesajları sistemde tanımlı genel bir mesaj işleticiye göndermektir.Gördüğünüz gibi

biz pencerede olabilecek bütün mesajları işleyen kodları yazmadık , bazıları varsayılan olarak işlenmesini istedik.Kendimizin işlemeyeceği

mesajları

DefWindowProc( penKulpu,msj,wParam ,lParam);

Fonksiyonu ile işlettiririz.Bu fonksiyon WndProc ile aynı parametreleri alır.Bu fonksiyondan alınan değer return ile geri döndürülerek WndProc

fonksiyonu bitirilir.

 

 

Bu makale burada bitiyor.İnşallah yardımcı olmuşumdur.Bazı yerleri 3 defa anlattığımdan makalenin sayfa sayısı fazla oldu.Tekrarlı anlatımı konuyu daha

iyi anlayabilmeniz için tercih ettim..Makale size başta çok karmaşık gelebilir.Bu kullanılan Api lerin(mesela ShowWindow) ve tanımlanmış değerlerin

 (mesela HWND) çokluğundan kaynaklanıyor.Zamanla alışacak ve bütün bu kodların çoğunun  her windows programında değişmeden kaldığını görüp

şaşıracaksınız.Bu makale ile ilgili kodu ayrı olarak yolluyorum.Kodun nasıl çalıştırılacağını ise  isterseniz ayrıntılı olarak anlatırım.Yazılım geliştirme

ortamı olarak VC6++ kullandım.Boş bir Win32 projesi yaratın ve kodları bu projede yarattığınız bir .cpp uzantılı dosyaya kaydedin.Derleyip çalıştırın.


Çalışan kod yukarıda ki gibi olacak.Alıştırmalar kolay olsa da yapmadan geçmeyin. Kendiniz de bir sürü alıştırma yapabilirsiniz.Yanınızda MSDN bulunması

büyük fayda sağlar.Tanımlı fonksiyonları ve gönderilen parametreleri MSDN den araştırıp inceleyin.

 

 

Alıştırmalar :

Soru 1 :

Pencerenin üstünde farenin sag tarafına basınca program mesaj kutusu ile bize “farenin sag tarafına bastınız “ mesajını versin.İpucu

:WM_RBUTTONDOWN mesajını işleyin.

Soru 2:

Pencere ilk gösterildiği zaman tam ekran olsun.İpucu SW_MAXIMIZE parametresini ilgili fonksiyona yollayın.

Soru 3 :

WS_OVERLAPPEDWINDOW ne anlama geliyor ?Hangi  Windows Style parametrelerin birleşimi olduğunu MSDN ye bakarak öğrenin.

Soru 4 – Pencere boyutlarını ayarlayın , daha küçük bir pencere olsun.

Soru 5 –Pencere istediğimiz yerde gösterilsin ,CreateWindow fonksiyonuna yollanan  x ve y değerleriyle oynayın.

 

Yazan Üye: Alparslan 

Son Güncelleme ( Cuma, 20 Ekim 2006 19:52 )
  Yorum yok.
Yorum ekle. (0 yorum)

 

OyunGelistirici.net - Türk Oyun Yapımcılarının Buluşma Noktası

Bu sitede yazılan tüm yazıların hakları yazarlarına aittir. İzin alınmadan yayınlanamaz.

Bu sitede Firefox kullanmanız önerilir. En az 1024 x 768 masaüstü çözünürlüğü tavsiye edilir.