AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Tutorials Delphi Handles
Tutorial durchsuchen
Ansicht
Themen-Optionen

Handles

Ein Tutorial von Luckie · begonnen am 9. Jun 2002 · letzter Beitrag vom 9. Jun 2002
 
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#1

Handles

  Alt 9. Jun 2002, 16:52
Alles was sie schon immer über Handles wissen wollte, aber nie zu fragen wagten (frei nach Woody Allen)

In diesm Tutorial soll es also um das Schreckgespenst Handles gehen. Aber wie wir sehr bald sehen werden ist das Schreckgespenst ein recht armloser, alter Hausgeist, der uns bei Zeiten recht nützlich werden kann.

"Wo simmer denn dran? Aha, heute kriejen mer de Handles. Also, wat is en Handle? Da stelle wir uns janz dumm. Und da sage mer so: En Handle, dat is ene Zahl, die hat nen Datentyp und ne Funktion. Der Datenty ist vom Typ DWORD und de Funktion bekommen wer später." (So mehr können wir erst mal nicht aus Heinrich Spoerls "Feuerzangenbowle" raus holen, für den Rest müßte man Bill Gates bemühen .)

Gut, ich denke, es ist klar geworden um was es hie rgehen soll: Handles und was man mit ihnen anstellen kann. Ich werde hier erst mal etwas Theorie machen und dann die Theorie in die Praxis umsetzten, damit man auch ein Ergebnis auf der Hand hat.

1. Theorie
Um mit Handles um gehen zu können, muß man erst mal verstehen, wie Windows grundsätzlich funktioniert. Windows ist ein multitasking System, dass heißt, der Benutzer kann mehrere Programme gleichzeitig gestartet haben und mit ihnen arbeiten, zum Beispiel kann er wärend ein Grafikprogramm eine große Grafik bearbeitet mit einem Textverarbeitungsprogramm seinen ersten Roman fertigstellen. Dies Stellt gewisse Anforderungen an das System, zum einen was die Speicherverwaltung betrifft (darum wollen wir uns aber hier nicht kümmer) und zum anderen was die Kommunikation mit den Programmen angeht und das ist schon eher Gegenstand diese Tutorials.

Kann in einem System immer nur ein Programm in den Speicher geladen werden, bedeutet das für die Kommunikation kein großes Problem. Nehem wir ein Textverarbeitungsprogramm unter DOS: Stellt es eine Anfrage, um eine Datei zu öffnen, leitet es die Anfrage an das System, welches die Anfrage verarbeitet und die gewünschten / benötigten Informationen zurückliefert. Da es nur ein aktives Programm gibt, hat das System kein Problem damit, von welchen Programm die Anfrage kommt bzw. an welches es die Informationen liefern muß.

Unter einem multitasking System funktioniert das nun nicht mehr, da muß man sich was anderes einfallen lassen und das haben auch die Entwickler getan. Windows-Programme kommunizieren mit dem Betriebssystem und gegebenenfalls auch mit anderen Programmen über Nachrichten (Messages). Und der Rest funktioniert auch wie im wirklichen Leben mit der Post: Wenn ich einen Brief verschicke muß ich zu mindest dem Empfänger angeben und dieser sollte nach Möglichkeit eindeutig sein und nichts anderes ist ein Handle, ein eindeutiger Bezeichner für ein Fenster. Hier müssen wir uns von der Vorstellung lösen, dass nur es sich nur um das Hauptfenster um ein Fenster handelt. Windows versteht unter Fenster eigentlich alles, was sich auf unserem Programmfenster befindet, also Schaltflächen (Buttons), Texteingabefelder (Edits), Bezeichner (Lables) und alles andere, also auch ein Listview, Treeview oder eine Listbox usw. Und bei jedem Start eine Programmes vergibt Windows an alle Fenster des Programmes eindeutige Bezeichner und unter Windows nennt man diese Bezeichner - ihr dürft raten - genau, Handles.

Windows verwaltet diese Handles in einer Tabelle und kann daher zu jedem Zeitpunkt ein Objekt in einem Programm genau identifizieren.

Beispiel:
Code:
SendMessage(hEdit, WM_GETTEXT, sizeof(buffer), Integer(@buffer));
Ich will jetzt diese Win32-API Funktion nicht zerlegen. Nur so viel, sie schreibt den Inhalt eines Textfeldes in eine Variable mit den Namen buffer. Damit Windows jetzt weiß, von welchem Textfeld es den Text holen soll, muß als erster Parameter der Handle des Fensters angegeben werden. In unserem Fall handelt es sich um die Variable hEdit. Dieses Handle muß man sich vorher holen - wie auch immer - bzw. man kennt es schon von vorherigen Aktionen, beispielsweise, wenn man das Edit mit der Win32-API-Funktion CreateWindow erstellt hat liefert es den Handle zurück. Klevere Programmierer merken sich dieses Handle gleich in einer globalen Variable zu späteren Verwendungszwecken.

Ich denke, dies sollte genug Theorie sein und für das Grundverständnis reichen. Zusammen fassend kann man sich merken:
Ein Handle ist ein eindeutiger Bezeichner für ein Fenster.
Hat man erst mal dieses Handle kann man alles Windows mögliche damit, besser mit dem Fenster machen.


2. Praxis
Eine beliebte Frage ist immer wieder: Wie kann ich ein bestimmtes Fenster minimieren oder schließen? Wer wissen will, wie beliebt diese Frage ist braucht nur mal die Suchfunktion des Forums zu bemühen und wird feststellen, dass regelmäßig alle 14 Tage diese Frage auftaucht. Dies ist auch ein gutes Beispiel, um mal zu demonstrieren, wie man mit Handles umgeht und was man mit ihnen machen kann. Weitaus besser eigent sich hierzu natürlich die nonVCl oder direkte Win32-Api Programmierung, da man da ohne Handles nicht sehr weit kommt, aber das will ich euch nicht auch noch zu muten, deswegen ein Beispiel mit VCL.

Also was wollen wir machen: Wir wollen ein anderes Fenster schließen. (Wichtig: Wir wollen keinen Prozess beenden, denn ein Prozess kann mehrere Fenster haben und wir würden nur den Prozess beenden, wenn wir zufälligerweise das Hauptfenster erwischen.) Ein Fenster schließen wir mit der Windows-Nachricht WM_CLOSE. Diese müssen wir an das Fenster senden. Senden tuen wir eine Nachricht mit SendMessage(). SendMessage erwartet als ersten Paramter den Empfänger der Nachricht, also um es mal fachmännisch auszudrücken und wer alles bisher gelesen und verstanden hat, sollte dazu in der Lage sein, den Handle. Wenn wir den Handle haben, können wir unsere Nachricht an dan betreffend Fenster schicken und das stellt sich dann wie folgt dar:
Code:
SendMessage(hWnd, WM_CLOSE, 0, 0);
hWnd ist in diesem Fall das gewünschte Handle.
So jetzt wollen wir mal sehen, wie sich das programmtechnisch um setzen läßt. Dazu ein kleines Beispiel-Programm von mir:

Wir benötigen einen Listview mit zwei Spalten: 1. Spalte: "Handle", 2. Spalte: "Fenstertext" und zwei Buttons Button1: "Handles holen", Button2: "Fenster schließen". Das war schon alles. Ich habe die Komponenten nicht umbenannt und stelle hier nur den für uns interessante Programmteil dar, nämlich die Prozeduren für die Buttons.

Code:
procedure TForm1.Button1Click(Sender: TObject);
var
  buffer: array[0..255] of Char;
  ListItem: TListItem;
  hWnd: DWORD;
begin
  { Inhalt des Listviews löschen }
  Listview1.Clear;
  { mit diesem Handle starten wir }
  hWnd := Application.Handle;
  { Listitem hinzufügen }
  ListItem := Listview1.Items.Add;
  { Listviewitem mit Handle beschriften }
  ListItem.Caption := IntToStr(hWnd);
  { Fenstertext in das Subitem schreiben }
  ListItem.SubItems.Add(Form1.Caption);
 
  { alle Fenster durchgehen }
  while hWnd > 0 do begin
    { das Handle des nächsten Fensters in der Z-Order holen, unseres ist das }
    { oberste, da aktiv }
    hWnd := GetNextWindow(hWnd, GW_HWNDNEXT);
    { buffer leeren }
    ZeroMemory(@buffer, sizeof(buffer));
    { Fenstertext holen, hier brauchen wir das Handle }
    GetWindowText(hWnd, buffer, sizeof(buffer));
    { uns interessieren nur die Fenster mit Text und die sichtbar sind }
    if (buffer <> '') AND (IsWindowVisible(hWnd) = TRUE) then
    begin
      { Listitem hinzufügen }
      ListItem := Listview1.Items.Add;
      { mit Handle beschriften }
      ListItem.Caption := IntToStr(hWnd);
      { Und den Fenstertext in das Subitem schreiben }
      ListItem.SubItems.Add(buffer);
    end;
  end;
end;


procedure TForm1.Button2Click(Sender: TObject);
var
  hWnd: DWORD;
begin
  { Handle auslesen }
  hWnd := StrToInt(Listview1.Selected.Caption);
  { Nachricht schicken }
  SendMessage(hWnd, WM_CLOSE, 0, 0);
  { Listview aktualisieren }
  Form1.Button1Click(Form1);
end;
So das war eigentlich schon alles. Ich denke, ich muß dazu nicht mehr sagen, die Kommentare sollten für sich sprechen.

Ich hoffe, ich konnte hier ein paar Unklarheiten beseitigen und euch die Angst vor diese doch so geheimnisvollen Handles nehmen. Nur weil es sich um ziemlich systeminterne Dinge handelt braucht man keine Angst davor zu haben. Man sollte allerdings genau wissen, was man tut. Aber alles in allem, kann man wohl sagen, dass alles nur halb so wild ist. Auch Windows kocht nur mit Wasser, um mal meinen alten Fußballtrainer zu zitiern.

Also Jungs und Mädels viel Spaß beim Programmieren, Ball flach halten und immer dran denken: "Und immer eine Hand voll Handles." (<- stammt glaube ich von unserem NIcoDE)

Das Tutorial dürfte fürs erste von meiner Seite als abgeschlossen betrachtet werden. Wer Ergänzungen hat oder meint ich hätte hier den totalen Schrott erzählt, kann ja posten.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
 


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:30 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz