Visual Basic - Technik, FAQ, Tricks, Beispiele

Home / Workshops / SubClassing / Technik

Technik - Wie gehts mit VB?

Wie kann man nun unter VB SubClassing realisieren? Es ist klar, daß es sich um eine sehr System-nahe Angelegenheit handelt, also wird man um die Verwendung von API-Funktionen nicht herumkommen. Das API ist übrigens eine vom Betriebssystem zur Verfügung gestellte Schnittstelle, die das Aufrufen von vielen Standardaufgaben ermöglicht (z.B. "Zeichne eine Linie!", "Gib mir den Namen des aktuellen Users!", etc. pp.).

Prinzipiell werden wir VB folgendermaßen "überlisten": Zuerst wird eine VB-Funktion erstellt, die wie ein Nachrichten-Empfänger und -Sender aussieht. Dann wird dem "abzuhörenden" Windows-Objekt mitgeteilt, daß es sowohl seine Nachrichten an diese Funktion schicken als auch auf Nachrichten aus dieser Funktion reagieren soll.

Zur Umlenkung der Nachrichten eines Windows-Objekts wird folgende API-Funktion SetWindowLongA benötigt:
Private Declare Function SetWindowLongA Lib "user32" ( _
    ByVal hWnd As Long, _
    ByVal nIndex As Long, _
    ByVal dwNewLong As Long) As Long
Die Paramter sind folgendermaßen zu lesen: hWnd enthält das sogenannte Windows-Handle des auszuspionierenden Windows-Objekts (eine Windows-interne "Hausnummer"). nIndex wird in unserem Fall immer GWL_WNDPROC (was -4 entspricht) sein, was bedeutet, daß wir die Adresse der sogenannten Windows-Prozedur (sprich: "Nachrichtenleitung") setzen wollen. dwNewLong schließlich wird die Adresse unserer VB-Funktion enthalten. Als Rückgabewert liefert die API-Funktion übrigens die Adresse des bisherigen Nachrichten-Empfängers, was sehr wichtig ist, um die nicht zu modifizierenden Nachrichten an den ursprünglichen Empfänger weiterleiten zu können. Ansonsten darf man sich mal wieder über die eine oder andere "Allgemeine Schutzverletzung" freuen.

Soll in unserer VB-Funktion eine Nachricht an den ursprünglichen Emfänger weitergereicht werden (was fast immer zutreffen wird), so wird folgende API-Funktion CallWindowProcA benötigt:
Private Declare Function CallWindowProcA Lib "user32" ( _
    ByVal lpPrevWndFunc As Long, _
    ByVal hWnd As Long, _
    ByVal Msg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) As Long
Die Parameter sind hier folgendermaßen zu lesen: lpPrevWndFunc bestimmt die Adresse des ursprünglichen Empfängers. hWnd enthält wieder das Windows-Handle. Msg bestimmt den Messagetyp (also WM_MOVE, WM_SIZING, etc. pp.). wParam und lParam enthalten - je nach Messagetyp - eventuell noch Parameter (z.B. die Koordinaten, wo sich gerade die Maus befindet, o.ä.).

Da unsere VB-Funktion als Nachrichten-Empfänger agieren soll, muß sie die gleiche Schnittstelle (sprich: Parameter) besitzen, wie die gerade gezeigte API-Funktion "CallWindowProcA". Hier ein Beispiel:
Public Function TestWndProc( _
    ByVal hWnd As Long, _
    ByVal uMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) As Long

  'Nachricht "analysieren":
  If uMsg = WM_SIZING Then Beep
  '...

  'Nachricht weiterleiten:
  TestWndProc = CallWindowProcA(VorigeAddr, hWnd, _
      uMsg, wParam, lParam)
End Function
Man beachte die letzte Anweisung in der Funktion: Hier wird die Nachricht an den ursprünglichen Empfänger delegiert.

Ein kleines Detail fehlt uns noch: Wie bestimmt man die Adresse einer VB-Funktion? Seit VB5 gibt es (endlich!) den Operator AddressOf, mit der man gerade dies machen kann. Leider funktioniert dies jedoch nur bei Funktionen, welche in einem BAS-Modul definiert worden sind. Außerdem kann dieser Operator nur als Parameter innerhalb eines Funktionsaufrufs benutzt werden. Also funktioniert keine der folgende Anweisungen:
Var = AddressOf TestWndProc
Var = AddressOf(TestWndProc)
Man muß stattdessen eine Dummy-Funktion benutzen, um die Adresse einer VB-Funktion in einer Variablen anlegen zu können:
Private Function Addr2Long(ByVal Addr As Long) As Long
  Addr2Long = Addr
End Function

'Aufruf:
Var = Addr2Long(AddressOf TestWndProc)
Und schon können wir jederzeit auf die Adresse unserer VB-Funktion zugreifen!
...>>

© Jost Schwider, 29.04.2000-30.04.2000 - http://vb-tec.de/subclas2.htm