Die Community zu .NET und Classic VB.
Menü

VB 5/6-Tipp 0582: Callbacks in Klassenmodule und Formulare

 von 

Beschreibung 

Einige kennen das Problem bereits: Man möchte Controls subclassen und muß deshalb Windows als Callback eine Procedur in einem Modul angeben, da nur dort der AddressOf-Operator funktioniert. Wie bringt man nun aber den Aufruf weiter an eine Form/ein Klassenmodul, ohne daß man dessen Instanz und Namen kennt? Das geht z.B. über eine Interfaceklasse!

Schwierigkeitsgrad:

Schwierigkeitsgrad 2

Verwendete API-Aufrufe:

keine

Download:

Download des Beispielprojektes [3,68 KB]

'Dieser Quellcode stammt von http://www.activevb.de
'und kann frei verwendet werden. Für eventuelle Schäden
'wird nicht gehaftet.

'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
'Ansonsten viel Spaß und Erfolg mit diesem Source!

'------------- Anfang Projektdatei Projekt1.vbp -------------
'--------- Anfang Formular "Form1" alias Form1.frm  ---------
' Steuerelement: Schaltfläche "Command4"
' Steuerelement: Schaltfläche "Command3"
' Steuerelement: Schaltfläche "Command2"
' Steuerelement: Schaltfläche "Command1"

Option Explicit

' Hier werden die Funktionen der Interfaceklasse implementiert

Implements cifInterface

Private Sub Form_Load()
   ' um den Aufruf aus dem Modul wieder zu bekommen,
   ' muß unser Globales Objekt mit dem Verweis auf
   ' das Interface unserer Form gefüttert werden
   Set MyInterface = Me
End Sub

' hier die 4 Buttons, um unsere Funktionen zu testen
Private Sub Command1_Click()
    Test_IFC_Function1
End Sub

Private Sub Command2_Click()
    Test_IFC_Function2
End Sub

Private Sub Command3_Click()
   Test_IFC_Sub1
End Sub

Private Sub Command4_Click()
   Test_IFC_Sub2
End Sub


' Hier folgen nun die Implementierungen unserer
' Schnittstellen-Funktionen aus cifInterface
' diese müssen unbedingt private sein!

Private Sub cifInterface_IFCSub1()
   MsgBox "Callback über Interface Sub 1"
End Sub

Private Sub cifInterface_IFCSub2()
   MsgBox "Callback über Interface Sub 2"
End Sub

Private Function cifInterface_IFCFunction1() As Long
   MsgBox "Callback über Interface Funktion 1"

End Function

Private Function cifInterface_IFCFunction2() As Long
   MsgBox "Callback über Interface Funktion 2"
End Function
'---------- Ende Formular "Form1" alias Form1.frm  ----------
'--------- Anfang Modul "Module1" alias Module1.bas ---------

Option Explicit

' DEMO zu "Callback" in Klassenmodule mittels Interface-Klassen
' so lassen sich z.B. auch gut Aufrufe bei PlugIns Standardisieren
'
' Autor: Stefan Maag
'        für activevb.de
' Datum: 03.02.2003

' Hier wird ein Objekt als Globales Interface definiert
' Diese Routinen werden dann aus der Form aufgerufen
' und der Aufruf wird über die InterfaceKlasse
' cifInterface wieder an die Form zurückgeleitet

Public MyInterface As CifInterface

Public Sub Test_IFC_Function1()
   Dim ret As Long
   ret = MyInterface.IFCFunction1
End Sub

Public Sub Test_IFC_Function2()
   Dim ret As Long
   ret = MyInterface.IFCFunction2
End Sub

Public Sub Test_IFC_Sub1()
    MyInterface.IFCSub1
End Sub

Public Sub Test_IFC_Sub2()
    MyInterface.IFCSub2
End Sub

'---------- Ende Modul "Module1" alias Module1.bas ----------
'------ Anfang Klasse "CifInterface" alias Class1.cls  ------

Option Explicit

' Diese Klasse stellt nur Schnittstellenfunktionen zur
' Verfügung (Interface)
' Jede Klasse oder Formular, das diese Funktionen nutzen
' will, muß diese Interface-Klasse implemtieren
' Implements cifInterface

' ACHTUNG: Diese Funktionen dürfen keinen Code enthalten,
'          nur die Definition der Functionsköpfe
'          in ActiveX-DLL's muss die Eigenschaft einer
'          Interface-Klasse auf "Public, nicht instanzierbar"
'          eingestellt gestellt werden

' zum Test Inteface Funkiton 1
Public Function IFCFunction1() As Long
End Function

' zum Test Inteface Funkiton 2
Public Function IFCFunction2() As Long
End Function

' zum Test Inteface Sub 1
Public Sub IFCSub1()
End Sub

' zum Test Inteface Sub 1
Public Sub IFCSub2()
End Sub
'------- Ende Klasse "CifInterface" alias Class1.cls  -------
'-------------- Ende Projektdatei Projekt1.vbp --------------

Tipp-Kompatibilität:

Windows/VB-VersionWin32sWin95Win98WinMEWinNT4Win2000WinXP
VB4
VB5
VB6

Hat dieser Tipp auf Ihrem Betriebsystem und mit Ihrer VB-Version funktioniert?

Ja, funktioniert!

Nein, funktioniert nicht bei mir!

VB-Version:

Windows-Version:

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 2 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von Götz Reinecke am 20.12.2004 um 12:02

> ... Zwar ist RaiseEvent nicht ganz so flexibel,
> aber es reicht meistens aus und ist einfacher
> zu benutzen.

Es geht hier aber um den Unmstand, daß die Instanz des Empfängers zur Laufzeit unbekannt ist. So etwas läßt sich über RaiseEvent nicht umsetzen.

Beispiel:
Es liegen unterschiedliche Child-Klassen vor deren Objekte zur Laufzeit wiederum unterschiedliche Parents zugewiesen werden können/sollen.
RaiseEvent/WithEvent versagt hier, dies geht nur über ein Interface, daß beiden (Child und Parent) bekannt ist und über die das Child im Parent Ereignisse auslösen kann:

'Interface [INotify]:
Public Sub OnChanged(ByRef SenderID As Long)
End Sub

'Child1 [clsChild1]:
Private m_Parent As INotify

Public Property Set Parent(ByRef NewValue As INotify)
Set m_Parent = NewValue
End Property

Private Sub DoSomething()
'...
m_Parent.OnChanged(MyID)
End Property

'Child2 [clsChild2]:
Private m_Parent As INotify

Public Property Set Parent(ByRef NewValue As INotify)
Set m_Parent = NewValue
End Property

Private Sub DoSomething()
'...
m_Parent.OnChanged(MyID)
End Property

'Parent1 [clsParent1]:
Implements INotify

Private Sub INotify_OnChanged(SenderID As Long)
Call MsgBox("Nachricht von: " & SenderID)
End Sub

'Parent2 [clsParent2]:
Implements INotify

Private Sub INotify_OnChanged(SenderID As Long)
Call MsgBox("Nachricht von: " & SenderID)
End Sub


Childs & Parents sind jeweils andere Typen, können aber über INotify willkürlich getauscht werden. (Polymorphie)

schöne Grüße
Götz

Kommentar von Konrad Rudolph am 15.03.2003 um 11:19

Hmmm.... bliebe nur noch zu erwähnen, daß ähnliches auch sehr viel einfacher über RaiseEvent zu erreichen ist.
Zwar ist RaiseEvent nicht ganz so flexibel, aber es reicht meistens aus und ist einfacher zu benutzen.