Subclassing mit Access

Zwischenhändler

Natürlich brauchen Sie auch noch die Funktion, deren Adresse Sie mit dem Parameter wNewLong der SetWindowLong festlegen. Sie hat die gleiche Syntax wie CallWindowProc mit Ausnahme von lpPrevWndFunc. Wenn Sie die Funktion fctHookAccessWindow nennen möchten, sieht ihr Prozedurrumpf so aus:

Public Function fctHookAccessWindow(ByVal hwnd As
Long, ByVal msg As Long, ByVal wParam As Long, ByVal
lParam As Long) As Long
End Function

In diese Funktion müssen Sie nun nur noch den Code einfügen, der die Nachricht auswertet, die gewünschten Schritte durchführt und die Nachricht – im Original oder geändert – an den eigentlichen Empfänger weitergibt. Bevor Sie dies tun, werfen Sie einen Blick auf das Zwischenergebnis (Listing 1).

Option Compare Database
Option Explicit
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
Private Declare Function SetWindowLongA Lib "user32" (ByVal hwnd As Long, ByVal
nIndex As Long, ByVal wNewWord As Long) As Long
Private Const GWL_WNDPROC As Long = (-4)
Private lngProc As Long
Private lngHwnd As Long
Private boolCancel As Boolean
Public Function fctHookAccessWindow(ByVal hwnd As Long, ByVal msg As Long, ByVal
wParam As Long, ByVal lParam As Long) As Long
fctHookAccessWindow = CallWindowProcA(lngProc, hwnd, msg, wParam, lParam)
End Function
Public Function Subclass() As Long
lngHwnd = Application.hWndAccessApp
lngProc = SetWindowLong(lngHwnd, GWL_WNDPROC, AddressOf fctHookAccessWindow)
End Function
Public Function UnSubclass()
SetWindowLong lngHwnd, GWL_WNDPROC, lngProc
lngProc = 0
End Function

Der Grund, warum Sie nun noch nicht einfach loslegen sollen, ist folgender: Subclassing verträgt sich nicht mit dem geöffneten VBA-Editor; zumindest dann nicht, wenn das Subclassing in Access- Modulen realisiert ist. Wenn Sie dafür eine VB-DLL erstellen und von Access aus referenzieren, können Sie wie gewohnt mit dem VBA-Editor arbeiten, aber ansonsten gilt: Speichern Sie jedes Mal, bevor Sie die Subclassing-Routinen verwenden, alle Objekte ab, denn sobald Sie das Subclassing gestartet haben und zum VBA-Editor wechseln, stürzt Access ab – hier hilft dann nur noch der Task-Manager. Das gilt übrigens auch für den Fall, dass Sie den VBA-Editor einmal geöffnet und wieder geschlossen haben: Der VBA-Editor bleibt im Hintergrund geöffnet, und ein eventuell folgendes Subclassing führt zum Absturz.

Das bedeutet, dass die Debugging-Möglichkeiten stark eingeschränkt sind – immerhin können Sie nicht mal eben einen Haltepunkt setzen oder Werte in das Direktfenster schreiben lassen. Zumindest für Letzteres gibt es Auswege: Sie können Variablenwerte oder Meldungen über ein Meldungsfenster ausgeben oder in eine Textdatei oder Tabelle schreiben lassen. Das mit dem Meldungsfenster kann allerdings schnell nervig werden, denn etwa das Verschieben des Access- Hauptfensters erzeugt so viele Nachrichten und damit Aufrufe der Subclassing-Routinen, dass das andauernde Bestätigen der Meldungsfenster schnell nervt.

Wenn Sie also zuerst schauen wollen, was etwa beim Verschieben des Access-Hauptfensters an Nachrichten gesendet wird, legen Sie eine kleine Tabelle wie in Bild 1 an und ergänzen die Routine fctHookAccessWindow wie in Listing 2.

Bild 1: Tabelle zum Speichern von Nachrichten.
Bild 1: Tabelle zum Speichern von Nachrichten.

Public Function fctHookAccessWindow(ByVal hwnd As Long, ByVal msg As Long, ByVal
wParam As Long, ByVal lParam As Long) As Long
CurrentDb.Execute "INSERT INTO tblMessages(Message, wParam, lParam) VALUES(" &
msg & ", " & wParam & ", " & lParam & ")"
fctHookAccessWindow = CallWindowProcA(lngProc, hwnd, msg, wParam, lParam)
End Function