Windows API

Mesaj İşlemleri

Şimdiye kadar bir programı çalıştırmak ve sona erdirmek dışında herhangi bir işlem yapmadık. Program ana penceresi de dahil olmak üzere, program içinde yer alan bütün kontrollar (buton, edit, listbox, vb) bir pencere olarak oluşturulur ve hepsinin kendisine ait bir mesaj işlem fonksiyonu olabilir. Program çalıştıktan sonra, artık kullanıcının fareyi hareket ettirmek, tıklamak, klavyeden giriş yapmak ve pencere boyutlarını değiştirmek gibi herhangi bir giriş işlemi yapmasını beklemektedir. Event adı verilen bu işlemlerden herhangi biri yapıldığında sistem tarafından bu işlemi gösteren bir mesaj oluşturulur ve programa gönderilir. Oluşturulan pencereler birbiri ile Windows mesaj sistemi ile haberleşir. Mesajlar sistem ve uygulamalar tarafından oluşturulabilir. Yapılan bu işlem program içinde yer alan hangi pencere ile ilgili ise, o pencerenin mesaj işlem fonksiyonu gelen mesaja işlem yapar.

DispatchMessage() fonksiyonu ile MSG yapı parametresi kullanılarak gönderilen mesaj ile pencere mesaj işlem fonksiyonuna bir pencere Handle değeri, bir mesaj tanımlayıcısı ve iki mesaj parametresi gönderilir. Pencere Handle değeri mesajın gönderileceği pencereyi belirlemek için kullanılır. Mesaj tanımlayıcısı, başlık dosyalarında tanımlanmış tamsayı değerleri içeren ve mesaj amacını belirleyen makrolardır. Mesaj parametreleri ise, mesaj tanımlayıcısına bağlı olarak bir tamsayı, flag değerleri veya yapı değeri içerebilir. Mesaj, mesaj parametrelerini kullanmadığında ise NULL değerler atanır.

typedef struct tagMSG {
	HWND hwnd;      /* Pencere Handle değeri */   
	UINT message;   /* Mesaj tanımlayıcısı (32 bit - 0-4294967295) */
	WPARAM wParam;  /* Mesaj parametresi */
	LPARAM lParam;  /* Mesaj parametresi */
	DWORD time;     
	POINT pt;       
} MSG;

LRESULT CALLBACK WindowProcedure (HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)

Bu bölümde, kullanıcı tarafından yapılan 5 farklı giriş işlemine (event) WindowProcedure() fonksiyonu içinde işlem yapacağız. WindowProcedure() fonksiyonu her mesaj için çağrılır. Eğer belirli bir mesaj için switch() kalıbı içinde bir seçenek tanımlayarak bir işlem yapabiliriz. Fonksiyona gönderilen mesaja herhangi bir işlem yapılmadığında ise default seçeneği için tanımlanan DefWindowProc() fonksiyonu çağrılır. 5 farklı giriş işlemi için üretilen mesajlara işlem yapmak üzere düzenlenmiş WindowProcedure() fonksiyonu aşağıda yer almaktadır:

LRESULT CALLBACK WindowProcedure (HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
  char cdizi [100];
  
  switch (message)
  {     
    case WM_MOVE:
         sprintf (cdizi, "Pencere hareket etti. Sol üst kenar koordinatı x:%d y:%d", 
                         (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
         SetWindowText(hwnd, cdizi);
         break;
		 
    case WM_SIZE:
         sprintf (cdizi, "Pencere boyutu değişti. Genişliği:%d Yüksekliği:%d", 
                         (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
         SetWindowText(hwnd, cdizi);	 
         break;
		 
    case WM_MOUSEMOVE:
         sprintf (cdizi, "Fare koordinatları x:%d y:%d",
                         (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
         SetWindowText(hwnd, cdizi);
         break;
		 
    case WM_LBUTTONDOWN:
         sprintf (cdizi, "Fare sol tuşuna basıldı: Koordinatlar x:%d y:%d",
                         (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
         SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) cdizi);
         break;

   case WM_KEYDOWN:
         if (wParam>64 && wParam<91) {
             sprintf (cdizi, "%c harfine basıldı", (int)(short) wParam);
             SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)cdizi);
         }	 
         break;
		 
    case WM_DESTROY:
         PostQuitMessage (0);
         break;
    default:                 
         return DefWindowProc (hwnd, message, wParam, lParam);
  }

  return 0;
}

WindowProcedure() fonksiyonu içinde renkli olarak gösterilen yeni kodların açıklamaları aşağıdadır:

WM_MOVE : 3 sayı değerine karşılık gelen mesaj kullanıcı ana pencereyi hareket ettiğinde oluşturulur. wParam parametresi kullanılmaz. lParam parametresinin düşük word değeri pencere sol üst köşe x koordinatını ve yüksek word değeri pencere sol üst köşe y koordinatını gösterir.

WM_SIZE : 5 sayı değerine karşılık gelen mesaj kullanıcı ana pencerenin boyutunu değiştirdiğinizde oluşturulur. wParam parametresi pencere durumunu SIZE_MAXHIDE, SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED, SIZE_RESTORED) gösterir. lParam parametresinin düşük word değeri pencere genişliğini ve yüksek word değeri pencere yüksekliğini gösterir.

WM_MOUSEMOVE : 512 sayı değerine karşılık gelen mesaj kullanıcı fareyi hareket ettirdiğinde oluşturulur. wParam parametresi SHIFT ve CTRL tuşları ile fare tuşlarının basılı olup olmadığını gösterir ve bu değerlerin birleşiminden oluşabilir. lParam parametresinin düşük word değeri pencere kullanım alanının sol üst köşesine göre x koordinatını ve yüksek word değeri y koordinatını gösterir.

WM_LBUTTONDOWN : 513 sayı değerine karşılık gelen mesaj kullanıcı pencere kullanım alanında fare sol tuşuna bastığında oluşturulur. wParam parametresi SHIFT ve CTRL tuşları ile fare tuşlarının basılı olup olmadığını gösterir ve bu değerlerin birleşiminden oluşabilir. lParam parametresinin düşük word değeri pencere kullanım alanının sol üst köşesine göre farenin x koordinatını ve yüksek word değeri y koordinatını gösterir.

WM_KEYDOWN : 256 sayı değerine karşılık gelen mesaj kullanıcı klavyeden sistem tuşu olmayan (ALT tuşu basılı değilken basılan tuş) bir tuşa bastığında oluşturulur. wParam parametresi sistem tuşu olmayan bir tuşun sanal tuş kodunu gösterir. lParam parametresi tekrar sayısını, scan code vb. değerleri gösterir.

Fonksiyon içinde ayrıca stdio.h başlık dosyasında yer alan sprintf() fonksiyonu kullanılmaktadır:

int sprintf (char *cdizi, const char *format, ... );

sprintf() fonksiyonu cdizi ile gösterilen char diziye format ile gösterilen parametredeki sisteme göre verilen değişken değerlerini atar.

windef.h başlık dosyasında tanımlı LOWORD makrosu 32 bit'lik DWORD bir değerin sağ tarafta yer alan WORD (16 bit) değeri, HIWORD makrosu ise 32 bit'lik DWORD bir değerin sol tarafta yer alan WORD (16 bit) değeri elde etmek için kullanılan Windows makrolarıdır.

Aşağıdaki her iki komut bir pencerenin başlık yazısını değiştirmek için kullanılır. İkinci seçenek ile bir pencereye, herhangi bir kullanıcı giriş işlemi beklemeksizin, SendMessage() fonksiyonu ile direk olarak WM_SETTEXT mesajı gönderilir.

SetWindowText(hwnd, cdizi);		 
SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) cdizi);

Programda, mesajların ilk üçünde ilk seçeneği, diğerlerinde ise ikinci seçeneği kullandık.

Program çalıştığında:

  • Program penceresini hareket ettirirseniz, pencere sol üst kenar koordinatları pencere başlık bilgisi yerine yazılır.
  • Program penceresinin boyutunu değiştirdiğinizde, pencere kullanım alanı genişliği ve yüksekliği pencere başlık bilgisi yerine yazılır.
  • Fareyi program penceresi üzerinde hareket ettirdiğinizde, pencere kullanım alanının sol üst köşesine göre x ve y koordinatları pencere başlık bilgisi yerine yazılır.
  • Program penceresi üzerinde fare sağ tuşuna bastığınızda, pencere kullanım alanının sol üst köşesine göre fare x ve y koordinatları pencere başlık bilgisi yerine yazılır.
  • Program penceresi üzerinde A-Z harfleri arasında yer alan bir ASCII karaktere bastığınızda, karakter değeri pencere başlık bilgisi yerine yazılır.

Programın çalışan en son hali aşağıdadır:

#include <windows.h>
#include <stdio.h>

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

char szClassName[ ] = "WinAPIWindowsApp";
HINSTANCE ghInst;

int WINAPI WinMain (HINSTANCE hThisInstance, 
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)
{
  HWND hwndMain;         
  MSG messages;      
  WNDCLASSEX wincl;

  ghInst = hThisInstance;

  wincl.hInstance = hThisInstance;
  wincl.lpszClassName = szClassName;
  wincl.lpfnWndProc = WindowProcedure;
  wincl.style = CS_DBLCLKS;           
  wincl.cbSize = sizeof (WNDCLASSEX);

  wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
  wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
  wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
  wincl.lpszMenuName = NULL; 
  wincl.cbClsExtra = 0; 
  wincl.cbWndExtra = 0; 
  wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

  if (!RegisterClassEx (&wincl)) return 0;

  hwndMain = CreateWindowEx (0, szClassName, "WinAPI Temel Program", 
                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, 
                   HWND_DESKTOP, NULL, hThisInstance, NULL);

  if (!hwndMain) return 0;

  ShowWindow (hwndMain, nCmdShow);
  UpdateWindow(hwndMain);

  while (GetMessage (&messages, NULL, 0, 0) > 0) {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
  }	
	
  return messages.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
  char cdizi [100];
  
  switch (message)
  { 
    case WM_MOVE:
         sprintf (cdizi, "Pencere hareket etti. Sol üst kenar koordinatı x:%d y:%d", 
                         (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
         SetWindowText(hwnd, cdizi);		 
         break;
		 
    case WM_SIZE:
         sprintf (cdizi, "Pencere boyutu değişti. Genişliği:%d Yüksekliği:%d", 
                         (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
         SetWindowText(hwnd, cdizi); 
         break;
		 
    case WM_MOUSEMOVE:
         sprintf (cdizi, "Fare koordinatları x:%d y:%d",
                         (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
         SetWindowText(hwnd, cdizi);
         break;
		 
    case WM_LBUTTONDOWN:
         sprintf (cdizi, "Fare sol tuşuna basıldı: Koordinatlar x:%d y:%d",
                         (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
         SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) cdizi);
         break;

   case WM_KEYDOWN:
         if (wParam>64 && wParam<91) {
             sprintf (cdizi, "%c harfine basıldı", (int)(short) wParam);
             SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)cdizi);
         }	 
         break;
		 
    case WM_DESTROY:
         PostQuitMessage (0);
         break;
    default:                 
         return DefWindowProc (hwnd, message, wParam, lParam);
  }

  return 0;
}