BilgiTeknoloji.net    
b i l g i   t e k n o l o j i   y a z ı l ı m

Ana Sayfa

Marjinal XML Access Pratik Uygulamalar Projeler Ekonometri Dilimiz Editörden Çetrefil İletişim
 

Windows'un Pencereleri - III
Pencerelere Ulaşmak

• Pencereleri Bulmak
• Pencere İşlevleri
• Pencerelere Mesaj Göndermek
• Stiller ve Gelişmiş Stiller
• GetWindowLong, SetWindowLong
• Listelere Ulaşmak
• ListeMatik

Windows'un pencerelerine ulaşmak ve pencere bilgilerini elde etmek çok çeşitli yollarla mümkündür. Belirli özellikteki pencerelere doğrudan ulaşılabilmesi dışında sınıf ve başlık bilgilerine göre arama yapılabilir, pencerelere göreceli olarak ulaşılabilir veyahut tüm pencerelerin listesi bir kerede elde edilebilir.

Windows'un Pencereleri'nin üçüncü ve son bölümündeki PencereBul ve ListeMatik örnek uygulamaları ile pencereler farklı özelliklere göre aranabiliyor, pencereler üzerinde çeşitli işlemler yapılabiliyor. PencereBul'da ek olarak Windows'taki not metin (memo) kutularının içerikleri elde edilebiliyor. Geçen ay bahsettiğimiz ListeMatik'in kodları bu ay CD'mizde yer alıyor.

PENCERELERİ BULMAK

Windows'taki pencerelere ulaşmak bazı hallerde çok gerekli olabilir. Genellikle çalışan diğer uygulamalardan birine ulaşmak ihtiyacı duyulmaktadır.

Elde özel hiçbir bilginin olmadığı durumlarda pencereleri bulmanın en kolay yollarından biri FindWindow işlevini kullanmaktır.

FindWindow'u kullanmak için hedef pencerenin sınıf türünü ve pencere başlığını biliyor olmak gerekir. (Sınıf türleri -yani class- her pencereye göre ve hatta pencerenin geliştirildiği uygulamaya göre değişebilir. Örneğin Delphi'de oluşturulan düğmeler TButton sınıfında olurken, VB düğmeleri genellikle ThunderRT6CommandButton gibi bir sınıf türünde olurlar.)


[Delphi]

FindWindow( Pchar('Notepad'), Pchar('Untitled - Notepad') );


[VB]

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

MsgBox FindWindow("Notepad", "Untitled - Notepad")


FindWindow yalnızca masaüstündeki pencereleri bulmaktadır. Özelleştirilmiş olarak daha önce bahsettiğimiz GetDesktopWindow masaüstünün, GetForegroundWindow ekranda üstte aktif olan pencerenin HWND değerlerini verir. Bunun dışında GetWindow ise HWND değeri bilinen bir pencerenin yakınındaki pencereleri bulmamızı sağlar.

H:=GetWindow(12345, GW_HWNDNEXT); //Sonraki komşu
H:=GetWindow(12345, GW_HWNDPREV); //Önceki komşu
H:=GetWindow(12345, GW_HWNDNFIRST); //Komşuların ilki
H:=GetWindow(12345, GW_HWNDLAST); //Komşuların sonuncusu
H:=GetWindow(12345, GW_CHILD); //Alt pencerelerin ilki
H:=GetWindow(12345, GW_OWNER); //Üst pencere

Bir pencerenin içindeki tüm alt pencereleri listelemek için daha önce yaptığımız gibi, GetWindow'u döngü ile kullanmak yerine sayısallaştırıcı EnumChildWindows işlevini kullanmayı deneyelim.

procedure AltPencereler(var h:hwnd; l:lParam);
begin
  AnaForm.Liste.Items.add(inttostr(h));
end;

procedure TAnaForm.Button1Click(Sender: TObject);
begin
  Liste.Items.Clear;
  EnumChildWindows(12345,@AltPencereler,0);
end;

EnumChildWindows 12345 HWND değerine sahip pencerenin alt pencerelerini listelemek için, her alt pencere için yeniden olacak şekilde AltPencereler genel yordamını sırayla çağırıyor. EnumChildWindows AltPencereler işlevinin h geçiş değişkenine alt pencerenin HWND değerini gönderiyor.

Pencere bulmak için kullanılan işlevlerin önemli bir diğeri de WindowFormPoint'tir. Doğrusu pencerenin kullanıcı tarafından bulunmasının istendiği durumlarda bu işlev etkindir.

WindowFromPoint ekranda belirli bir noktada görüntülenen pencerenin HWND değerini verir. Örnekte fare işaretçisinin bulunduğu noktadaki pencere getiriliyor.

var
  nokta:TPoint;
  H: HWND;
begin
  GetCursorPos(nokta);
  H:= WindowFromPoint(nokta);


PENCERE İŞLEVLERİ

Windows hemen tüm pencereler üzerinde neredeyse sınırsız sayıda işlem yapılmasına olanak vermektedir. HWND değerini bildiğiniz herhangi bir pencerenin, kendi uygulamanızdaymış gibi özelliklerini değiştirmeniz mümkündür.

Ekteki PencereBul'da genel pencere işlevlerinin bir kısmı yer alıyor. Doğrusu pencereler üzerinde işlem yapmak için işlevlerin yanında Windows mesajları da kullanılmaktadır. Örneğin GetWindowText işlevi ile WM_GETTEXT mesajı benzer iş yapar.

WM_GETTEXT pencere başlıklarını alabilmekle birlikte Windows'taki metin kutularının içeriğini getirebilir. Aşağıdaki kodda h penceresinin başlığının ilk 1000 karakteri s'ye aktarılıyor. Pencere bir not metin kutusu (memo) olduğunda kutunun içeriğini getirir.

SendMessage( h, WM_GETTEXT, 1000, s );

Metin kutularının içeriğini tam olarak almak için öncelikle WM_GETTEXTLENGTH ile kutudaki metnin boyunu öğrenmek gerekir.

uzunluk:=SendMessage( h, WM_GETTEXTLENGTH, 0, 0 );
SetLength( s, uzunluk+1 );
SendMessage( h, WM_GETTEXT, 1000, s );

Windows'taki standart metin kutuları bu komutları aynı şekilde destekler.

Windows'taki genel not metin kutularında hemen her türlü işlem mesaj gönderme yoluyla yapılabilir. Basitçe bir not kutusunun sonuna metin eklemek için, aşağıdaki NotSatiriEkle işlevi kullanılabilir.


procedure NotSatiriEkle(NotAdres:HWND; M:string);
//Uygulama içindeki ya da Windows'taki, handle değeri
//bilinen bir not (memo) kutusuna yeni bir satır ekler.
var
  SatirAdedi, SatirSira, SatirUzunluk:integer;
  metin:string;
begin

  metin:= M + #13#10;

  SatirAdedi:= SendMessage(NotAdres,EM_GETLINECOUNT,0,0);
  SatirSira:= SendMessage(NotAdres,EM_LINEINDEX,SatirAdedi-1,0);
  SatirUzunluk:= SendMessage(NotAdres,EM_LINELENGTH,SatirSira,0);
  if SatirUzunluk>0 then
  begin
    metin:=#13#10 + metin;
    inc(SatirSira,SatirUzunluk);
  end;

  SendMessage(NotAdres,EM_SETSEL,SatirSira,SatirSira);

  SendMessage(NotAdres,EM_REPLACESEL,0,integer(PCHAR(metin)));

end;

...
NotSatiriEkle(12345,'(Yeni eklenen metin)');

Spymon++ ya da Spy++ ile geçerli bir not metin kutusu bulduktan sonra yukarıdaki kodu çalıştırmayı deneyin.


PencereBul uygulamasında kullandığımız bazı işlevler aşağıda yer alıyor.

BringWindowToTop ile bir pencere en üste getiriliyor:
BringWindowToTop(12345);

CascadeWindows pencere altındaki çocuk pencereleri ekrana döşüyor:
CascadeWindows(GetDesktopWindow,0,pointer(0),0,pointer(nil));

CloseWindow pencereleri simge durumuna (minimize) getiriyor. Formlar dışında düğme ve metin kutusu gibi pencereler de simge durumuna getirilebilir:
CloseWindow(12345);

WM_CLOSE mesajı ise pencereyi kapatıyor:
SendMessage(12345, WM_CLOSE,0,0);

Bunun dışında MoveWindow pencereleri taşıyıp, ShowWindow da pencereleri büyütür ve küçültür.

MoveWindow(12345, sol, üst, genişlik, yükseklik, True);

ShowWindow(12345, SW_MINIMIZE);
ShowWindow(12345, SW_MAXIMIZE);


STİLLER

Her pencere, görüntüsüyle ilgili bilgileri stil özelliklerinde depolar. Pencerelerin normal ve gelişmiş stil özellikleri vardır.

Normal stillere GetWindowLong işlevine GWL_STYLE değeri gönderilerek ulaşılır. Gelişmiş stiller için ise GWL_EXSTYLE kullanılır.

Stilleri kullanarak pencerenin görüntüsünde birçok değişiklik yapılabilir. Örneğin bir Windows formunun sağ üst köşesindeki küçültme, büyütme, kapatma düğmeleri, pencerelerin kenarlıkları, başlık çubukları, hareket yetenekleri stillerle ayarlanır.

Resimdeki pencere Windows Gezgini'nin biraz değiştirilmiş hali. Pencerenin stil bilgilerine ulaşarak başlık çubuğunu, sistem menüsünü, üst düğmeleri kaldırdık ve pencereye yatay ve düşey kaydırma çubukları ekledik.

PencereBul'daki Stiller sayfasında bu tür değişiklikler yapılabilir.

Stil bilgileri GetWindowLong ile aşağıdakine benzer şekilde alınır.

var
  stil:integer;
begin
  stil:=GetWindowLong(strtoint(pencere.text),GWL_STYLE);

Stil bilgilerinin tamamı Integer tipinde bir tamsayıda tutulmaktadır. Bu, bit sayısı kadar özelliğin GWL_STYLE türündeki stilde depolanabileceği anlamına gelir. Nitekim en fazla 32 olabilse de GWL_STYLE ile halihazırda 27 civarında özellik depolanıyor:

WS_BORDER, WS_CAPTION, WS_CHILD, WS_CHILDWINDOW, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_DISABLED, WS_DLGFRAME, WS_GROUP, WS_HSCROLL, WS_ICONIC, WS_MAXIMIZE, WS_MAXIMIZEBOX, WS_MINIMIZE, WS_MINIMIZEBOX, WS_OVERLAPPED, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_POPUPWINDOW, WS_SIZEBOX, WS_SYSMENU, WS_TABSTOP, WS_THICKFRAME, WS_TILED, WS_TILEDWINDOW, WS_VISIBLE, WS_VSCROLL

Bu özelliklerin herbiri stil içinde var veya yok kabul edilir. Bir özelliğin stil içinde olup olmadığına bakmak için değerleri AND ile karşılaştırmak yeterlidir.

if (stil and özellik) = özellik then ..

koşulu gerçekleştiğinde özelliğin stil içinde olduğunu söyleyebiliriz. Tersi ise aşağıdaki gibi.

if (stil and özellik) <> özellik then ..

PencereBul'daki Stiller sayfasında Getir düğmesi bu şekilde çalışıyor. Uygula düğmesi ise stilde değişiklikler yapıp bu stili pencereye geri yüklüyor.

Stil yüklemek SetWindowLong ile yapılır ve GW_STYLE ile birlikte yeni stil bilgisini de geçiş değeri olarak alır.

SetWindowLong( 12345, GWL_STYLE, stil );

Genel sayfasındaki Ters Çevir düğmesi pencerenin yatayda yönünü değiştirmek için GW_STYLE yerine GW_EXSTYLE ve WS_EX_LAYOUTRTL özelliklerine başvurur. Stilde değişiklik yapmak için ilgili özelliği sayısal olarak stile eklemek ya da stilden çıkarmak gerekir. Örnekte bu, inc ve dec ile yapılıyor.

procedure TAnaForm.btnTersCevirClick(Sender: TObject);
var
  stil: integer;
  h:hwnd;
begin

  h:=12345;

  stil:= GetWindowLong(h, GWL_EXSTYLE);

  //WS_EX_LAYOUTRTL var ise çıkar, yok ise ekle.
  if (stil and WS_EX_LAYOUTRTL) = WS_EX_LAYOUTRTL then
    dec(stil, WS_EX_LAYOUTRTL)
  else
    inc(stil, WS_EX_LAYOUTRTL);

  SetWindowLong(h, GWL_EXSTYLE, stil);

end;

Gerçekte WS_EX_LAYOUTRTL Arap alfabesi için sağdan-sola (Right-To-Left) çevirme yapmaktadır.


LİSTELERE ULAŞMAK

Windows, geliştirme araçlarında kullanılması için bazı ortak bileşenler sunmaktadır. Zengin metin kutuları, düz listeler, ağaç listeleri gibi bileşenler bunlardan birkaçıdır. Örneğin Delphi'de Win32 sayfasındaki kontroller aslında Windows'un ortak bileşenlerindendir.

Ortak bileşenler her uygulamada aynı temel özelliklere sahiptir. Bunların karakteristiği VB'de ya da Delphi'de ayrı kullanıldıklarında değişmez. Bu bileşenler Windows'ta çok sık kullanılır.

Delphi'deki TreeView ve ListView ile Windows Gezgini'ndeki ağaç dizin ve dosya listeleri aynı özelliktedir. Bu durumda başka uygulamalardaki listelere ait bilgileri elde etmek, hatta onlarda değişiklik yapmak olanaklıdır.

Ekteki ListeMatik, Windows'taki listelerden bilgi alabiliyor ve düz listelerde çeşitli değişiklikler yapabiliyor.

Listelerde, salt mesaj gönderme yoluyla değişiklik yapılabilmektedir. Aşağıdaki iki satır ile, HWND değeri bilinen bir düz listeye yeni bir değer ekleniyor ve eklenen yeni satır seçiliyor.

SendMessage( hwnd, LB_INSERTSTRING, sıra, Integer(PChar('Yeni Eklenen Değer')));
SendMessage( hwnd, LB_SETCURSEL, sıra, 0);

ListeMatik'in ekteki kodlarında listelere mesaj göndermekle ilgili daha ayrıntılı örnekler bulacaksınız.


Windows'un Pencereleri'ni daha çok aralamak mümkün. Şimdilik sonlandırdığımız bu konu sonraki yazılarımızda devam edebilir.

İyi seneler.

DOSYALAR:
listematik.exe
(zip, 250 kb.)
listematik_kod.zip
pencerebul.exe
(zip, 234 kb.)
pencerebul_kod.zip
spyfinder.zip


Serkan ŞAHİNOĞLU
(Chip Dergisi, Ocak 2003)


http://BilgiTeknoloji.net