|
|
|||||||||||||
|
|
Windows'un Pencereleri - II • Windows mesajları
Bu yazıda mesajların nasıl gönderildiği ile birlikte uygulama içindeki pencerelere gelen mesajların nasıl yakalandığı, çalışma anında taşıma ve boyutlandırma işlemlerinin mesaj gönderme yoluyla nasıl yapıldığı anlatılıyor.
Her Windows mesajı, en az dört özniteliğe sahiptir. Mesajın türünü belirten mesaj kodu (Msg), ilk parametre (wparam), ikinci parametre (lparam) ve sonuç değeri (result). Bu özniteliklerin dördü de 4-bayt (32-bit) tamsayıdır. Bir mesajı göndermek SendMessage, PostMessage ve daha birkaç API işlevi ile mümkündür. Bazı işlemler için özelleştirilmiş işlevler mevcut olsa da bu yazıda SendMessage işlevini kullanacağız. Tabii SendMessage ile PostMessage arasındaki farkı söyleyelim. Her ikisi de aynı şekilde mesaj gönderir, fakat SendMessage sonucu bekleyebilirken, PostMessage mesajı iletip beklemeksizin hemen geri döner. Mesajların pencerelere gönderildiğinden geçen yazımızda bahsetmiştik. Mesajları işleyen bir kapalı döngünün uygulama başlangıcından bitimine kadar sürekli çalıştığını da hatırlatalım. Bir mesajın gönderilmesi için en az iki bilgi gerekiyor. Mesajın gönderileceği pencerenin adresi (belirteci - HWND), ve mesajın kodu. Bunun dışında yukarıda belirttiğimiz iki geçiş değeri de (wparam, lparam) tercihe ve mesaj türüne bağlı olarak kullanılabilmektedir. Windows, sınırsız mesaj gönderilmesine izin verse de pencerenin mesaj kuyruğunda biriktirilecek mesaj adedinin bir sınırı vardır. Windows 2000 ve üzeri işletim sistemlerinde geçerli olarak, bir mesaj kuruğunda en fazla 10000 mesaj bulunabilir. Tabii ki, normal şartlarda bu sayıya çıkmak çok zordur. Gerektiği hallerde kayıt defterinin aşağıda belirtilen yolunda bu değer değiştirilebilir. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\USERProcessHandleQuota
Mesaj göndermek için yukarıda belirttiğimiz gibi SendMessage ile birkaç API işlevini kullanabilirsiniz. Bu yazıda ise sadece SendMessage kullanılmaktadır. Bir pencere sol fare tuşu ile tıklatılıp bırakıldığında pencereye en az iki mesaj gönderilir. Birisi farenin basıldığını (WM_LBUTTONDOWN), diğeri de bırakıldığını (WM_LBUTTONUP) işaret eder. Fare kullanmadan, doğrudan mesaj göndermek yoluyla da aynı iş yapılabilir. Spy++ ya da Spymon++ ile Başlat düğmesinin HWND değerini bulduktan sonra aşağıdaki Delphi ve VB kodlarını 12345 yerine bulduğunuz değeri yazarak çalıştırmayı deneyin.
SendMessage(12345, WM_LBUTTONDOWN,0,0);
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Const WM_LBUTTONUP = &H202 Private Sub Command1_Click()
Çalışma anında basit bir taşıma işlemi Windows mesajları kullanılarak çok kolay yapılır. Bir pencerenin MouseDown (fare basıldığında) eylemini aşağıdaki gibi yapmak bunun için yeterlidir.
procedure TForm1.Button1MouseDown(Sender: TObject; Button:
TMouseButton;
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long Private Const WM_SYSCOMMAND = &H112 Private Declare Function ReleaseCapture Lib "user32" () As Long Private Sub Command1_MouseDown(Button As Integer, Shift
As Integer, X As Single, Y As Single)
Fare ile ilgili bazı işlemlerde ReleaseCapture kullanmak gerekiyor. Bu, hareketin SendMessage satırında algılanması içindir.
Çalışma anında boyutlandırma işlemi, taşımaya benzer şekilde yapılır. Bunun için SC_SIZE sabiti 1-9 arası değer alır ve herbir değer pencerenin farklı kenarından ya da köşesinden boyutlandırma yapılacağını ifade eder. 9 ise pencerenin sürüklenip taşınmasını sağlar. Önce MouseDown yordamında SC_SIZE+8 kullararak düğmeyi taşımayı deneyin. ReleaseCapture
4 3 5 Her yön için aynı zamanda fare işaretçisini belirtmek size kalmıştır. Taşımayı ve her yöndeki boyutlandırmayı uygun şekilde sağlamak için aşağıdaki gibi MouseDown ve MouseMove olay yordamlarını kullanmak yeterli. MouseDown'da SC_SIZE ile hareket kodu kullanılırken MouseMove'de farenin konumuna göre işaretçinin (cursor) değiştirildiğine dikkat edin.
var procedure TForm1.Button1MouseDown(Sender: TObject; Button:
TMouseButton; procedure TForm1.Button1MouseMove(Sender: TObject; Shift:
TShiftState; X, case Hareket of end;
Private Declare Function SendMessage Lib "user32"
Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal
wParam As Long, lParam As Any) As Long Dim Hareket As Byte Private Sub Command1_MouseDown(Button As Integer, Shift
As Integer, X As Single, Y As Single) Private Sub Command1_MouseMove(Button As Integer, Shift
As Integer, X As Single, Y As Single) Select Case Hareket End Sub
İçine yerleştirilen her bileşene taşıma ve boyutlandırma özelliği katan bir Delphi nesnesi CD'mizde yer alıyor. Kaynak kodu da verilen TTasarimPanel'in geliştirilmesine, okuyucularımızdan istek geldiği takdirde devam edeceğiz. İsteyenler bunu alıp değiştirebilir, yazar bilgilerini silmeden kendi isimlerini ekleyip, yapılan değişiklikleri de belirterek ve ücretsiz olmak kaydıyla dağıtabilirler. Açık kodlu geliştirmeye katılmak isteyen Delphi programcılarının hazırladıkları TTasarimPanel sürümlerini ya da türevlerini, bize gönderdikleri takdirde yayınlayacağız.
Windows mesajlarının yakalanması zor bir işlem değildir. Fakat Visual Studio araçlarındaki Spy++'da olduğu gibi başka uygulamalardaki pencerelere giden mesajların yakalanması yeterince zor ve masraflıdır. Uygulama içindeki mesajları yakalamak ise Delphi'de zor değil, VB 6'da uğraştırıcıdır. Yine de her ikisi, buna aşina olmayanlar tarafından genellikle kafa karıştırıcı olarak görülür. Bu başlık altında sadece geçen ay verdiğimiz Boyut uygulamasının VB kodlarını kısaca inceleyeceğiz. Uygulamanın çalışma yöntemine bağlı olarak, pencerelerin kendilerine ait, mesajları işleyen kapalı bir döngünün bulunduğu genel yordamları vardır. Uygulamanın kendi içinden bu yordamların adresi değiştirildiğinde tüm mesajlar artık yeni yordama gönderilmeye başlanır. Bir pencerenin ana çalışma yordamını bulmak GetWindowLong ile mümkündür. Yordam_Adresi:=GetWindowLong(Hwnd, GWL_WNDPROC); Bu yordamın adresini değiştirip başka bir yordamın adresini vermek, mesajlara müdahale edebileceğimiz anlamına gelir. Bunu SetWindowLong ile yapmadan önce yeni yordamın uygun şekilde hazırlandığından emin olmak lazımdır. [Delphi] function Yeni_Yordam(..); Eski_Yordam:= SetWindowLong(Hwnd, GWL_WNDPROC,integer(@Yeni_Yordam));
Public Function Yeni_Yordam (..) Eski_Yordam_Adresi = SetWindowLong(Hwnd, GWL_WNDPROC, AddressOf Yeni_Yordam)
Yeni yordamı genel (public) bir yordam olarak tanımlamak gerekir. VB'de bunu genel bir modülün içinde Public ile belirtmek yeterlidir. SetWindowLong ile ayarlandıktan sonra artık pencere ile ilgili tüm mesajlar bu yordama, geçiş değişkenleri aracılığıyla gönderilecektir. Bu durumda ilgilendiğimiz mesajlar için gerekli işlemleri yapıp diğer mesajları çöpe atmaktansa, eski pencere yordamını ilgili mesajları belirterek CallWindowProc ile çalıştırmak gerekir. Zira bizim ilgilenmediğimiz mesajlar aslında pencerenin ilk yordamı için değerli olabilir. CallWindowProc(Eski_Yordam_Adresi, HWND, Mesaj, wParam, lParam) Yeni yordamı aşağıdakine benzer şekilde düzenlemek gerekiyor: Public Function Yeni_Yordam(ByVal hwnd As Long, ByVal uMsg
As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Select Case uMsg SetWindowLong ile pencere yordamının adresi değiştirilmişse uygulama kapatılmadan önce mutlaka eski yordamı bağlamak gerekir. SetWindowLong HWND, GWL_WNDPROC, Eski_Yordamın_Adresi
Boyut uygulamasının VB kodu CD'mizde bulunuyor. Bu uygulamada yakalanan mesajlara ait bilgilerin liste kutusuna SendMessage ile eklendiğine dikkat edin. 'Listeye metin ekle 'Satırı seç 'Satıra değer ver
Gelecek ayki uygulamalarımızdan biri mesaj gönderme yoluyla Windows'taki listelere ait bilgilere ulaşılması ve listelerde değişiklik yapılması ile ilgili olacak. O zamana kadar ekteki Liste Matik'i inceleyebilirsiniz. Liste Matik'i düz listelerde ve Windows Gezgini'ndeki gibi ağaç listelerde kullanmayı deneyin.
Düzeltme: Önceki yazıda geçen "4-bit tamsayı ile ifade edilen HWND'nin
sayısal değeri .." ifadesinin doğrusu "4-bayt (32-bit) tamsayı ile
ifade edilen HWND'nin sayısal değeri .." şeklindedir. DOSYALAR: |