Meist unbeachtet: das Fenster "ThunderRT?Main"
Vielleicht haben Sie es noch gar nicht bemerkt: Zu jedem VB-Programm gehört neben den von Ihnen angelegten Formen und Modulen immer ein (unsichtbares) Fenster der Klasse "ThunderRT?Main", wobei das Fragezeichen für die Versionsnummer von VB steht und das "RT" die Runtime-Ausführung (kompilierte Exe-Datei) verkörpert. Die Beschriftung des Fensters entspricht dem Projektnamen.
Wenn sie es noch nicht bemerkt haben, ist das kein Beinbruch, denn normalerweise haben Sie mit diesem Fenster auch überhaupt nichts zu tun: Es ist für das normale Programmieren ohne jegliche Bedeutung, kann aber dennoch recht nützlich sein. Stellen Sie sich vor, Sie hätten ein Programm geschrieben, das keine Form enthält, sondern nur Module, das aber aufgrund seiner Struktur trotzdem über längere Zeit am Leben ist, und Sie möchten an dieses Programm per SendMessage eine Meldung schicken. Meldungen kann man aber nur an Fenster schicken, und Fenster werden in VB durch Formen oder Steuerelemente verkörpert - und die haben wir in diesem Fall schließlich nicht. In einem solchen Fall können wir das bewußte Fenster verwenden, denn es verfügt wie jedes "normale" Fenster über eine Fensterprozedur, die wir subclassen können. Und schon läßt sich das Problem lösen.
Oder ein anderes Beispiel: Sie haben ein Modul geschrieben, das universell einsetzbar ist und einen Empfänger für Messages benötigt. Dieser Empfänger muß ein Fenster sein. Wenn Sie das Modul in verschiedenen Programmen einsetzen, müßten Sie irgendeine Form des jeweiligen Programms als "Empfänger" deklarieren und den Code entsprechend schreiben. Das kann natürlich nicht Sinn der Sache sein - einfacher ist es, das ohnehin überall vorhandene Fenster "ThunderRT?Main" als Empfänger zu benutzen - so läßt sich der Code vereinheitlichen.
Im folgenden möchte ich eine kurze Codesequenz vorstellen, die bei Aufruf der Prozedur WaitForMessage das besagte Fenster subclasst, auf den Eingang einer definierten Meldung wartet (im konkreten Fall auf die Message WM_APP und eine in lParam der Message übergebene Fensterhandle der aufrufenden Anwendung) und danach das Subclassing wieder aufhebt:
Private Const GWL_WNDPROC& = (-4)
Private Const WM_APP& = &H8000&
Private Declare Function SetWindowLong& Lib "user32" Alias "SetWindowLongA" _
(ByVal hwnd&, ByVal nIndex&, ByVal dwNewLong&)
Private Declare Function CallWindowProc& Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc&, ByVal hwnd&, ByVal msg&, ByVal wParam&, ByVal lParam&)
Private Declare Function FindWindow& Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName$, ByVal lpWindowName$)
Private Declare Function IsWindow& Lib "user32" (ByVal hwnd&)
Dim OldProc&, hMain&, Handle&
Sub WaitForMessage()
hMain = FindWindow("thunderrt5main", App.Title)
If IsWindow(hMain) Then
SubClass hMain, True
End If
End Sub
Private Sub SubClass(ByVal hwnd&, ByVal YesNo As Boolean)
Select Case YesNo
Case True
OldProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf myWndProc)
Case False
Call SetWindowLong(hwnd, GWL_WNDPROC, OldProc)
End Select
End Sub
Public Function myWndProc&(ByVal hwnd&, ByVal wMsg&, ByVal wParam&, ByVal _
lParam&)
If wMsg = WM_APP Then
Handle = lParam
SubClass hMain, False
myWndProc = 0
Exit Function
End If
myWndProc = CallWindowProc(OldProc, hwnd, wMsg, wParam, lParam)
End Function Anmerkung: Bei mehreren Instanzen ist die Ermittlung von hMain über die API-Funktion FindWindow nicht sicher, denn diese liefert die Handle des ersten Fensters, das mit den Vorgaben übereinstimmt (und das muß nicht unbedingt das der aktuellen Anwendung sein). Verwenden Sie stattdessen besser die Funktion GetHandle in der DSHANDLE.DLL, bei der Sie noch die Thread-ID vorgeben können. |