Info zu Window-Prozeduren

Jedes Fenster ist ein Element einer bestimmten Fensterklasse. Die Fensterklasse bestimmt die standardmäßige Window-Prozedur, die ein einzelnes Fenster zum Verarbeiten seiner Nachrichten verwendet. Alle Fenster, die derselben Klasse angehören, verwenden dieselbe standardmäßige Window-Prozedur. Beispielsweise definiert das System eine Window-Prozedur für die Kombinationsfeldklasse (COMBOBOX); alle Kombinationsfelder verwenden dann diese Window-Prozedur.

Eine Anwendung registriert in der Regel mindestens eine neue Fensterklasse und die zugehörige Window-Prozedur. Nach dem Registrieren einer Klasse kann die Anwendung viele Fenster dieser Klasse erstellen, von denen alle die gleiche Window-Prozedur verwenden. Da dies bedeutet, dass mehrere Quellen gleichzeitig den gleichen Codeabschnitt aufrufen können, müssen Sie beim Ändern freigegebener Ressourcen aus einer Window-Prozedur vorsichtig vorgehen. Weitere Informationen finden Sie unter Fensterklassen.

Window-Prozeduren für Dialogfelder (als Dialogfeldprozeduren bezeichnet) weisen eine ähnliche Struktur und Funktion wie normale Window-Prozeduren auf. Alle Punkte, die auf Window-Prozeduren in diesem Abschnitt verweisen, gelten auch für Dialogfeldprozeduren. Weitere Informationen finden Sie unter Dialogfelder.

In diesem Abschnitt werden die folgenden Themen erläutert.

Struktur einer Window-Prozedur

Eine Window-Prozedur ist eine Funktion mit vier Parametern, die einen signierten Wert zurückgibt. Die Parameter bestehen aus einem Fensterhandle, einem UINT-Nachrichtenbezeichner und zwei Nachrichtenparametern, die mit den Datentypen WPARAM und LPARAM deklariert wurden. Weitere Informationen finden Sie unter WinProc.

Nachrichtenparameter enthalten häufig Informationen in ihren Wörtern sowohl mit niedriger als auch mit hoher Reihenfolge. Es gibt mehrere Makros, mit denen eine Anwendung Informationen aus den Nachrichtenparametern extrahieren kann. Das LOWORD-Makro extrahiert z. B. das Wort mit niedriger Reihenfolge (Bits 0 bis 15) aus einem Nachrichtenparameter. Weitere Makros sind das HIWORD-, LOBYTE- und HIBYTE-Makro.

Die Interpretation des Rückgabewerts hängt von der jeweiligen Nachricht ab. Lesen Sie die Beschreibung jeder Nachricht, um den entsprechenden Rückgabewert zu ermitteln.

Da es möglich ist, eine Window-Prozedur rekursiv aufzurufen, ist es wichtig, die Anzahl der von ihr verwendeten lokalen Variablen zu minimieren. Bei der Verarbeitung einzelner Nachrichten sollte eine Anwendung Funktionen außerhalb der Window-Prozedur aufrufen, um übermäßige Verwendung lokaler Variablen zu vermeiden, was dazu führen kann, dass der Stapel während der tiefen Rekursion überläuft.

Standardmäßige Window-Prozedur

Die standardmäßige Window-Prozedurfunktion DefWindowProc definiert bestimmte grundlegende Verhaltensweisen, die von allen Fenstern gemeinsam verwendet werden. Die standardmäßige Window-Prozedur stellt die minimale Funktionalität für ein Fenster bereit. Eine anwendungsdefinierte Window-Prozedur sollte alle Meldungen übergeben, die sie nicht für die Standardverarbeitung an die DefWindowProc-Funktion verarbeitet.

Erstellen von Unterklassen für Window-Prozeduren

Wenn eine Anwendung ein Fenster erstellt, weist das System einen Speicherblock zum Speichern spezifischer Informationen für das Fenster zu, einschließlich der Adresse der Window-Prozedur, die Nachrichten für das Fenster verarbeitet. Wenn das System eine Nachricht an das Fenster übergeben muss, durchsucht es die fensterspezifischen Informationen nach der Adresse der Window-Prozedur und übergibt die Nachricht an diese Prozedur.

Das Erstellen von Unterklassen ist eine Technik, mit der eine Anwendung Nachrichten abfangen und verarbeiten kann, die an ein bestimmtes Fenster gesendet oder gepostet wurden, bevor das Fenster die Möglichkeit hat, sie zu verarbeiten. Durch das Erstellen von Unterklassen eines Fensters kann eine Anwendung das Verhalten des Fensters erweitern, ändern oder überwachen. Eine Anwendung kann Unterklassen für ein Fenster erstellen, die zu einer globalen Systemklasse gehören, z. B. ein Bearbeitungssteuerelement oder ein Listenfeld. Beispielsweise könnte eine Anwendung eine Unterklasse für ein Bearbeitungssteuerelement erstellen, um zu verhindern, dass das Steuerelement bestimmte Zeichen akzeptiert. Sie können jedoch keine Unterklassen für ein Fenster oder eine Klasse erstellen, die zu einer anderen Anwendung gehört. Alle Unterklassen müssen innerhalb desselben Prozesses ausgeführt werden.

Eine Anwendung erstellt eine Unterklasse für ein Fenster, indem die Adresse der ursprünglichen Window-Prozedur des Fensters durch die Adresse einer neuen Window-Prozedur ersetzt wird, die als Unterklassenprozedur bezeichnet wird. Danach empfängt die Unterklassenprozedur alle Nachrichten, die an das Fenster gesendet oder gepostet werden.

Die Unterklassenprozedur kann beim Empfangen einer Nachricht drei Aktionen ausführen: Sie kann die Nachricht an die ursprüngliche Window-Prozedur übergeben, die Nachricht ändern und an die ursprüngliche Window-Prozedur übergeben oder die Nachricht verarbeiten und nicht an die ursprüngliche Window-Prozedur übergeben. Wenn die Unterklassenprozedur eine Nachricht verarbeitet, kann dies vor, nach oder sowohl vor als auch nach dem Übergeben der Nachricht an die ursprüngliche Window-Prozedur erfolgen.

Das System bietet zwei Arten für das Erstellen von Unterklassen: Instanz und global. Beim Erstellen von Unterklassen für Instanzen ersetzt eine Anwendung die Adresse der Window-Prozedur einer einzelnen Instanz eines Fensters. Eine Anwendung muss das Erstellen von Unterklassen für Instanzen verwenden, um eine Unterklasse für ein vorhandenes Fenster zu erstellen. Beim Erstellen globaler Unterklassen ersetzt eine Anwendung die Adresse der Fensterprozedur in der WNDCLASSEX-Struktur einer Fensterklasse. Alle nachfolgenden Fenster, die mit der Klasse erstellt werden, weisen die Adresse der Unterklassenprozedur auf, vorhandene Fenster der Klasse sind jedoch nicht betroffen.

Erstellen von Unterklassen für Instanzen

Eine Anwendung erstellt eine Unterklasse für eine Instanz eines Fensters mithilfe der SetWindowLongPtr-Funktion. Die Anwendung übergibt das GWL_WNDPROC-Flag, das Handle an das Fenster, für das eine Unterklasse erstellt werden woll, und die Adresse der Unterklassenprozedur an SetWindowLongPtr. Die Unterklassenprozedur kann sich entweder in der ausführbaren Datei der Anwendung oder in einer DLL befinden.

Nach Übergabe des GWL_WNDPROC-Flags gibt SetWindowLongPtr die Adresse der ursprünglichen Window-Prozedur des Fensters zurück. Die Anwendung muss diese Adresse speichern, indem sie sie in nachfolgenden Aufrufen der CallWindowProc-Funktion verwendet, um abgefangene Nachrichten an die ursprüngliche Fensterprozedur zu übergeben. Die Anwendung muss auch über die Adresse der ursprünglichen Window-Prozedur verfügen, um die Unterklasse aus dem Fenster zu entfernen. Um die Unterklasse zu entfernen, ruft die Anwendung SetWindowLongPtr erneut auf und übergibt die Adresse der ursprünglichen Fensterprozedur mit dem GWL_WNDPROC-Flag und dem Handle an das Fenster.

Das System besitzt die globalen Systemklassen, und Aspekte der Steuerelemente können sich von einer Version des Systems zum nächsten ändern. Wenn die Anwendung eine Unterklasse für ein Fenster erstellen muss, das zu einer globalen Systemklasse gehört, muss der Entwickler die Anwendung möglicherweise aktualisieren, wenn eine neue Version des Systems veröffentlicht wird.

Da das Erstellen von Unterklassen für Instanzen nach dem Erstellen eines Fensters stattfindet, können Sie dem Fenster keine zusätzlichen Bytes hinzufügen. Anwendungen, die eine Unterklasse für ein Fenster erstellen, sollten die Eigenschaftenliste des Fensters verwenden, um alle Daten zu speichern, die für eine Instanz des Unterklassenfensters erforderlich sind. Weitere Informationen finden Sie unter Fenstereigenschaften.

Wenn eine Anwendung eine Unterklasse für eine Unterklasse eines Fensters erstellt, muss sie die Unterklassen in der umgekehrten Reihenfolge entfernen, in der sie ausgeführt wurden. Wenn die Entfernungsreihenfolge nicht umgekehrt wird, kann ein nicht behebbarer Systemfehler auftreten.

Erstellen von globalen Unterklassen

Um eine globale Unterklasse für eine Fensterklasse zu erstellen, muss die Anwendung über ein Handle für ein Fenster der Klasse verfügen. Die Anwendung benötigt das Handle außerdem, um die Unterklasse zu entfernen. Zum Abrufen des Handles erstellt eine Anwendung in der Regel ein ausgeblendetes Fenster der Klasse, für das eine Unterklasse erstellt werden soll. Nach dem Abrufen des Handles ruft die Anwendung die SetClassLongPtr-Funktion auf, wobei das Handle, das GCL_WNDPROC-Flag und die Adresse der Unterklassenprozedur angegeben werden. SetClassLongPtr gibt die Adresse der ursprünglichen Fensterprozedur für die Klasse zurück.

Die Adresse der ursprünglichen Window-Prozedur wird beim Erstellen globaler Unterklassen auf die gleiche Weise verwendet wie beim Erstellen von Unterklassen für Instanzen. Die Unterklassenprozedur übergibt Nachrichten an die ursprüngliche Window-Prozedur, indem CallWindowProc aufgerufen wird. Die Anwendung entfernt die Unterklasse aus der Fensterklasse, indem SetClassLongPtr erneut aufgerufen wird, wobei die Adresse der ursprünglichen Fensterprozedur, das GCL_WNDPROC-Flag und das Handle für ein Fenster der Klasse angegeben wird, für das eine Unterklasse erstellt wird. Eine Anwendung, die global eine Unterklasse für eine Steuerelementklasse erstellt, muss die Unterklasse entfernen, wenn die Anwendung beendet wird. Andernfalls kann ein nicht behebbarer Systemfehler auftreten.

Das Erstellen globaler Unterklassen weist die gleichen Einschränkungen wie das Erstellen von Unterklassen für Instanzen sowie einige zusätzliche Einschränkungen auf. Eine Anwendung sollte die zusätzlichen Bytes nicht für die Klasse oder die Fensterinstanz verwenden, ohne genau zu wissen, wie die ursprüngliche Window-Prozedur sie verwendet. Wenn die Anwendung einem Fenster Daten zuordnen muss, sollte sie Fenstereigenschaften verwenden.

Erstellen von Unterklassen für Window-Prozeduren

Das Erstellen von Unterklassen ist eine Technik, die es einer Anwendung ermöglicht, eine neue Fensterklasse mit der grundlegenden Funktionalität der vorhandenen Klasse zu erstellen, sowie Verbesserungen, die von der Anwendung bereitgestellt werden. Eine Superklasse basiert auf einer vorhandenen Fensterklasse, die als Basisklasse bezeichnet wird. Häufig ist die Basisklasse eine globale Systemfensterklasse, z. B. ein Bearbeitungssteuerelement, kann jedoch eine beliebige Fensterklasse sein.

Eine Superklasse hat eine eigene Window-Prozedur, die als Superklassenprozedur bezeichnet wird. Die Superklassenprozedur kann beim Empfangen einer Nachricht drei Aktionen ausführen: Sie kann die Nachricht an die ursprüngliche Window-Prozedur übergeben, die Nachricht ändern und an die ursprüngliche Window-Prozedur übergeben oder die Nachricht verarbeiten und nicht an die ursprüngliche Window-Prozedur übergeben. Wenn die Superklassenprozedur eine Nachricht verarbeitet, kann dies vor, nach oder sowohl vor als auch nach dem Übergeben der Nachricht an die ursprüngliche Window-Prozedur erfolgen.

Im Gegensatz zu einer Unterklassenprozedur kann eine Superklassenprozedur Fenstererstellungsmeldungen verarbeiten (WM_NCCREATE, WM_CREATE usw.), aber sie muss sie auch an die ursprüngliche Basisklassen-Window-Prozedur übergeben, damit die Prozedur ihre Initialisierungsprozedur für die Basisklassenfenster ausführen kann.

Um Superklassen für eine Fensterklasse zu erstellen, ruft eine Anwendung zuerst die GetClassInfoEx-Funktion auf, um Informationen über die Basisklasse abzurufen. GetClassInfoEx füllt eine WNDCLASSEX-Struktur mit den Werten aus der WNDCLASSEX-Struktur der Basisklasse. Als Nächstes kopiert die Anwendung ein eigenes Instanzhandle in das hInstance-Element der WNDCLASSEX-Struktur und kopiert den Namen der Superklasse in das lpszClassName-Element. Wenn die Basisklasse über ein Menü verfügt, muss die Anwendung ein neues Menü mit denselben Menübezeichnern bereitstellen und den Menünamen in das lpszMenuName-Element kopieren. Wenn die Superklassenprozedur die WM_COMMAND-Nachricht verarbeitet und nicht an die Window-Prozedur der Basisklasse übergibt, benötigt das Menü keine entsprechenden Bezeichner. GetClassInfoEx gibt nicht das Element lpszMenuName, lpszClassName oder hInstance der WNDCLASSEX-Struktur zurück.

Eine Anwendung muss auch das lpfnWndProc-Element der WNDCLASSEX-Struktur festlegen. Die GetClassInfoEx-Funktion füllt dieses Element mit der Adresse der ursprünglichen Window-Prozedur für die Klasse aus. Die Anwendung muss diese Adresse speichern, um Nachrichten an die ursprüngliche Window-Prozedur zu übergeben, und dann die Adresse der Superklassenprozedur in das lpfnWndProc-Element kopieren. Die Anwendung kann ggf. andere Elemente der WNDCLASSEX-Struktur ändern. Nachdem sie die WNDCLASSEX-Struktur ausgefüllt hat, registriert die Anwendung die Superklasse, indem die Adresse der Struktur an die RegisterClassEx-Funktion übergeben wird. Die Superklasse kann dann zum Erstellen von Fenstern verwendet werden.

Da beim Erstellen von Superklassen eine neue Fensterklasse registriert wird, kann eine Anwendung sowohl die zusätzlichen Klassenbytes als auch die zusätzlichen Fensterbytes hinzufügen. Die Superklasse darf die ursprünglichen zusätzlichen Bytes für die Basisklasse oder das Fenster aus denselben Gründen nicht verwenden wie eine Instanzunterklasse oder eine globale Unterklasse. Wenn die Anwendung zusätzliche Bytes für die Verwendung der Klasse oder der Fensterinstanz hinzufügt, muss sie auch auf die zusätzlichen Bytes relativ zur Anzahl zusätzlicher Bytes verweisen, die von der ursprünglichen Basisklasse verwendet werden. Da die Anzahl der von der Basisklasse verwendeten Bytes von einer Version der Basisklasse zur nächsten variieren kann, kann der Anfangsoffset für die zusätzlichen Bytes der Superklasse ebenfalls von einer Version der Basisklasse zur nächsten variieren.