MSG Yapısının Elamanları
| işletim |
- HWND hWnd
Her
pencerenin bir mesaj kuyruğu yoktur. Her programın bir mesaj kuyruğu vardır.
Yani bir program 10 tane pencere yaratmış olsa bile bu pencerelerin herhangi
birisinde oluşan girdi işlemi aynı kuyruğa yazılacaktır. Yapının bu elemanı programın
hangi penceresine ilişkin bir mesaj oluştuğunu belirtir.
- UINT message
Bu
eleman mesajın hangi sebepten kuyruğa yazıldığını anlatan bir sayı içerir. Bir
mesaj yüzlerce sebepten dolayı kuyruğa yazılabilir. Ancak mesajın nedenleri
sayısal düzeyde konuşulmaz. Windows.h içerisinde tüm bu sayılar WM_ ile
başlayan sembolik sabitlerle tanımlanmıştır. Yani örneğin 108 numaralı mesaj
yerine WM_XXXXX mesajı biçiminde durum ifade edilir.
- WPARAM wParam
LPARAM
lParam
WPARAM
aslında unsigned int türüdür. Unsigned int türü 16 bit Windows sistemlerinde 2
byte uzunluğundaydı. Ancak 32 bit Windows sistemlerinde 4 byte'lık bir
bilgidir. Burada W ön eki 16 bit Windows sistemleri kullanılırken
isimlendirilmiştir. 32 bit sistemlere geçildiğinde bu isimlendirmenin
kullanılmasına devam edilmiştir. LPARAM unsigned long türüdür ve her iki
sistemde de 4 byte uzunluğundadır. Bu elemanlara mesaja bağlı olan ek bilgiler
yerleştirilir. Örneğin WM_CHAR mesajında wParam basılan tuşun ASCII sıra
numarasını içerirken WM_LBUTTONDOWN mesajında basılan noktanın koordinat
bilgisini içermektedir. Her mesaj için bu elemanlara hangi bilgilerin
yerleştirildiği ayrıca öğrenilmelidir.
- DWORD time
Mesajın
gönderildiği zaman bilgisidir.
- POINT pt
Bu
eleman bazı mesajlarda ekrana ilişkin koordinat bilgisini tutmak amacıyla
kullanılır.
Mesaj Döngüsü
Mesajlar
sistem tarafından kuyruğa yazılır, ancak bu mesajların alınarak işlenmesi
programcı tarafından yapılır. Programcı mesajları alarak önce bu mesajları
anlamlandırır, daha sonra uygun işlemleri yapacak kodları çalıştırır. Programa
ilişkin pencere kapatılıp program sonlandırılacağı zaman bu işlem de Windows
tarafından WM_QUIT mesajı olarak kuyruğa yazılır. Yani bir döngü içerisinde
mesajların sürekli alınarak işlenmesi WM_QUIT mesajı görüldüğünde de döngü
sonlandırılarak programın bitirilmesi gerekir.
GetMessage Fonksiyonu
GetMessage
kuyrukta bulunan ilk mesajı alır ve bu mesajı kuyruktan siler. Fonksiyonun
prototipi:
BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT
wMsgFilterMax
);
Fonksiyonun
birinci paranmertesi MSG türünden bir göstericidir. Bu parametreye MSG türünden
bir yapının adresi geçirilmelidir. GetMessage kuyrukta sırada bulunan mesajı
alarak bu yapının içerisine yerleştirir. İkinci parametre programa ilişkin
hangi pencerenin mesajlarının alınacağını belirtir. Yani GetMessage ile
özellikle bir pencereye ilişkin mesajlar alınabilir. Bu parametre NULL
girilirse bütün pencerelere ilişkin mesajlar alınır. Fonksiyonun üçüncü ve
dördüncü parametreleri hangi aralıktaki mesajların kuyruktan alınacağını
belirtir. Örneğin bu parametrelere 100 ve 120 girilirse yalnızca bu aralıkta
numaralara sahip olan mesajlar alınır. Eğer bu iki parametreye 0 girilirse tüm
mesajların alınacağı anlamına gelir. İskelet programda tüm mesajlar
alınmaktadır. Fonksiyon eğer WM_QUIT mesajını aldıysa 0 değerine, WM_QUIT
dışındaki bir mesajı aldıysa 0 dışı herhangi bir değere geri döner. GetMessage
eğer kuyrukta mesaj yoksa programın çizelgeleme dışı bırakılıp bloke edilmesine
yol açar. Yani programcı bakış açısıyla programın akışı GetMessage içerisinde
beklemektedir. Kuyruktan sürekli olarak mesajı alan WM_QUIT görünce işlemi
sonlandıran bir döngü şöyle kurulabilir:
while (GetMessage(&msg, NULL, 0, 0)) {
...........
..........
.........
}
Mesaj
döngüsünden çıkıldığında WinMain fonksiyonu da biter, bu fonkiyon bitince de
program biter. GetMessage fonksiyonu ile mesaj alındıktan sonra anlamlandırılıp
işlenmelidir, ancak prensip olarak mesajın mümkün olduğu kadar çabuk bir biçimde
işlenmesi istenir. Eğer mesajın işlenmesi uzun sürerse GetMessage bir sonraki
mesajı kuyruktan alamaz. Böylece programda herhangi bir ilerleme söz konusu
olamaz. Ancak yine de mesajın işlenmesini geciktirecek ciddi sebepler olabilir.
O zaman programın akışının devam etmesi nasıl sağlanacaktır? İşte alt işlemli
programlama sistemi(multi-threading) bu tür problemlere çözüm bulmaktadır.
Mesajların İşlenmesi ve Pencere Fonksiyonu
Mesajların
işlenmesi ismine pencere fonksiyonu denilen bir fonksiyon tarafından yapılır.
Kuyruktan mesaj alındığında DispatchMessage API fonksiyonu çağırılır.
DispatchMessage fonksiyonuna parametre olarak kuyruktan alınan mesajın
bulunduğu değişkenin adresi geçirilmektedir. DispatchMessage mesajın hWnd
elamanına bakarak mesajın hangi pencereye ilişkin olduğunu anlar. O pencere
ilişkin pencere fonksiyonunu çağırır. Bir pencere yapısının parametrik yapısı
şöyle olmak zorundadır:
LRESULT CALLBACK WndProc(
HWND hWnd,
UINT message
WPARAM wParam
LPARAM lParam
);
Fonksiyonun
geri dönüş değeri LRESULT yani long olmak zorundadır. Çağırma biçimi __stdcall
olmak zorundadır. Zaten CALLBACK sembolik sabiti __stdcall anlamına
gelmektedir. DispatchMessage fonksiyonu mesajı alıp mesaj içerisindeki hWnd,
message, wParam, lParam elemanlarını ayrıştırarak bu elemanları pencere
fonksiyonunun parametresi yapmak suretiyle pencere fonksiyonunu çağırır. Yani
programın akışı pencere fonksiyonumuzdan çıktığında akış DispatchMessage
içerisinden devam eder.
Mesaj
döngüsünün içerisinde TranslateMessage API fonksiyonu da çağırılmaktadır. Bu
fonksiyonun mesaj işlenme mekanizmasıyla ciddi bir bağlantısı yoktur. ASCII
tuşlarına basıldığında WM_CHAR mesajının oluşumunu sağlar.
Pencere Fonksiyonunun Tasarımı
Bunun
için önce mesajın ne mesajı olduğunun tespit edilmesi gerekir. Bu işlem bir
switch deyimiyle yapılabilir. Daha sonra mesaj parametreleri yorumlanarak case
ifadeleri işlenir.
Windows Programının Sonlandırılması
Bir
Windows programı programın akışı mesaj döngüsünden çıkıp WinMain fonksiyonunun
bitmesiyle sonlanır. Program akışının mesaj döngüsünden çıkması GetMessage
fonksiyonunun 0 ile geri dönmesiyle sağlanır. GetMessage fonksiyonu WM_QUIT
mesajını gördüğünde 0'a geri döner.
DefWindowProc API Fonksiyonu
Bir
programın en basit işlemleri yapacak biçimde sağlıklı çalışabilmesi için bir
takım kritik mesajların işlenmesi gerekir. Oysa bunların işlenmesi ve bu
mesajlara karşılık default bazı işlemleri yapılması uzun bir işlem yükü
gerektirir. İşte DefWindowProc fonksiyonu bir mesaj için default kritik
işlemleri yapabilen bir fonksiyondur. Yani pencere fonksiyonu içerisinde
mesajlar işlenir, işlenmeyen mesajlar bu API fonksiyon çağırılarak işletilir. O
halde en basit bir pencere fonksiyonu şöyle tasarlanabilir:
LRESULT
CALLBACK WindowProc(HWND hWnd, UINT, message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd,
message, wParam, lParam);
} /*Tüm mesajlar default olarak
işlenecektir*/
DefWindowProc
fonksiyonunun gelen mesajlara karşı hangi kritik işlemleri yaptığı bazı tür
işlemlerde programcı tarafından bilinmek zorundadır.
İşlenen
mesajlar için DefWindowProc fonksiyonu çağırılmamalıdır. O halde bu fonksiyon
tipik olarak switch'in default kısmına yerleştirilmelidir.

0 yorum: