Office Forum
www.Office-Loesung.de
Access :: Excel :: Outlook :: PowerPoint :: Word :: Office :: Wieder Online ---> provisorisches Office Forum <-
Delegates in VBA? Delegates in VBA!
zurück: RibbonX-Workshop Zusammenstellung weiter: FlxControls - Teil 3 (Das Projekt) Unbeantwortete Beiträge anzeigen
Neues Thema eröffnen   Neue Antwort erstellen     Status: Tutorial Facebook-Likes Diese Seite Freunden empfehlen
Zu Browser-Favoriten hinzufügen

Konntest du mit dem Thema und der Erklärung etwas anfangen?
Super, wusste gar nicht, dass das geht.
0%
 0%  [ 0 ]
Nicht unbedingt, das meiste kannte ich schon.
50%
 50%  [ 1 ]
Ist vielleicht ganz interessant, aber nichts für mich...
50%
 50%  [ 1 ]
Stimmen insgesamt : 2

Autor Nachricht
KeepCoolMan
VBA-NonExpert ;) Office 2010


Verfasst am:
13. Feb 2012, 14:28
Rufname: Thomas
Wohnort: Celle


Delegates in VBA? Delegates in VBA! - Delegates in VBA? Delegates in VBA!

Nach oben
       Version: (keine Angabe möglich)

Ein Hinweis vorweg: Diese kleine Einführung erhebt absolut keinen Anspruch auf Vollständigkeit und Richtigkeit. Über Fehler-Hinweise und auch Feedback bin ich wie immer dankbar!
Alle Beispiele sind unter Windows XP mit Office XP und unter Windows 7 mit Office 2010 getestet!


Viele .NET-Programmierer, die sich mehr oder weniger zwangsläufig mit VBA beschäftigen, vermissen natürlich die ein oder andere Funktionalität.
Da ist zum Beispiel die Möglichkeit, nicht nur Werte, Variablen oder Objekte als Argumente an Funktionen zu übergeben, sondern ganze Funktionen bzw. deren Aufrufe. Die Rede ist von

Delegates
VBA selbst stellt augenscheinlich keine Delegates bereit. Wenn wir uns aber vor Augen halten, dass das gesamte Windows fast ausschließlich auf Ereignissen basiert und Ereignisse nur über Delegates realisiert werden können (wie sonst wüsste ein Programm, wenn Button A gedrückt wird, dass die Ereignisroutine von Button A ausgelöst werden soll und führt nicht die Routine von Button B aus? Es sind doch beide nur Abkömmlinge von der Klasse Button und es wird ja nicht für jeden Button ein eigenes Ereignis definiert, sondern jeder Button bekommt „nur“ für DAS Ereignis seine Ereignis-Routine [EventHandler]), dann muss es doch auch eine Möglichkeit geben, eigene Delegates zu realisieren.

Und natürlich gibt es die Möglichkeit, auch wenn VBA – als recht einfache Programmiersprache auch für Einsteiger konzipiert – keinen Datentyp für Delegates bereitstellt (wie z.B. C#). Also muss ein kleiner Umweg gegangen werden.

Machen wir einen kurzen Ausflug in die Objektorientierung und bleiben bei dem Beispiel des Buttons. Wenn ein Button ins Formular eingebaut wird, dann bekommt er seinen eigenen Speicherplatz, in dem seine Eigenschaften festgehalten werden. Der nächste Button bekommt auch wieder seinen Speicherplatz für seine Eigenschaften. Nur so können wir z.B. einen Button rot und den anderen blau darstellen. Aber es sind und bleiben beides Button. Die Funktionen, die uns der Button ermöglicht, werden über Ereignisse realisiert – das bekannteste ist wohl das Click-Ereignis. Wir weisen also dem Click-Ereignis jedes Button eine Prozedur zu, die dann beim Klick ausgeführt wird. Wenn wir den Button klicken, muss das Programm dann an einer bestimmten Stelle im Speicher weitermachen, je nachdem, wo die entsprechende Prozedur gespeichert ist. Im zugeordneten Speicher des Buttons wird nun nicht die ganze Prozedur abgelegt, die beim Klick auf den Button ausgeführt werden soll, denn es ist nicht selten der Fall, dass mehrere Buttons die gleiche Funktion ausführen. Der eine Button soll z.B. die Schrift im Dokument rot darstellen, der andere grün – für diese Funktionalität muss ja nicht jeder Button den gesamten Code implementieren. Vielmehr reicht es, wenn eine Funktion den Text färbt und diese Funktion nur mitgeteilt bekommt, in welcher Farbe. Und deshalb wird im Speicher des Buttons nur die Adresse der zugehörigen Funktion, die beim Klick ausgeführt werden soll, also die Adresse im Speicher, wo der Code fortfahren muss, gespeichert.

Die eigentliche Funktion des Buttons – seine Zuständigkeit – wird also an eine allgemeine Stelle übertragen, delegiert! Und dafür wird die Adresse der Funktion – des Delegaten – benötigt! So einfach ist ein Delegate Smile

Und genauso einfach lassen sich Delegates in der Programmierung für alle möglichen Aufgaben einsetzen. Immer dann, wenn wir z.B. aus verschiedenen Funktionen verschiedene andere Funktionen an eine einzige Funktion weitergeben, sprich delegieren wollen.

Eine Funktion A1 ruft eine Funktion C auf, die ihrerseits aber abhängig vom Ergebnis der Funktion A2 reagieren soll. Und eine Funktion B1 will ebenfalls die Funktion C aufrufen, aber nun soll Funktion C auf das Ergebnis der Funktion B2 reagieren.

Im Sinne der Objektorientierung (und da kommen Delegates her) folgendes Beispiel:

Ein Kind wird zur Schule geschickt. Die Funktion des Kindes lautet also zur Schule. Diese Funktion wird von der Mutter „aufgerufen“: Kind -> zur Schule.

Das Kind hat nun zwei Möglichkeiten, zur Schule zu kommen – mit dem Auto oder mit dem Schulbus. Der „Startwert“ ist der gleiche (-> zur Schule) und das Ergebnis ist das gleiche (-> in Schule ankommen). Aber der Weg dorthin ist unterschiedlich. Entweder ins Auto einsteigen, anschnallen, abschnallen, aussteigen oder in den Schulbus einsteigen, rumgammeln, Busfahrer ärgern, aussteigen. Dem Kind wird von der Mutter nur mitgeteilt, wie es in die Schule fahren soll. Die Fahr-Art wird an das Kind delegiert und es führt es aus, also entweder Kind -> zur Schule -> mit Schulbus oder aber Kind -> zur Schule -> mit Auto. Eine der beiden Varianten wird an die Funktion zur Schule delegiert.

In beiden Fällen wird dem Kind (resp. unserem Programm) mitgeteilt, was es tun soll (Funktion zur Schule) und wie es geschehen soll (mittels Funktion mit Auto oder mit Schulbus). Wir müssen also der Funktion zur Schule die erforderliche „Unterfunktion“ mitgeben. Für die Programmierung bedeutet das, wir müssen einer Funktion die Speicher-Adresse einer weiteren Funktion übergeben, ab der das Programm ausgeführt werden soll, um zum Ergebnis zu gelangen.

Delegate-Workaround
Wie bereits angedeutet, stellt uns VBA keine entsprechende Funktionalität zur Verfügung, um einen solchen „Zeiger“ (Pointer) auf eine Funktion übernehmen und diese Funktion dann ausführen zu können. Deshalb bedienen wir uns einer API-Funktion, mit der wir so etwas realisieren können, nämlich der CallWindowProc-Funktion, die eine Nachricht an ein Fenster bzw. eine Fensterprozedur sendet.
Wir implementieren dafür aus Gründen der Übersichtlichkeit ein neues Modul mit dem Bezeichner Delegates und deklarieren dort diese API-Funktion. Da wir diese Funktion als ausführendes Delegate „missbrauchen“, nennen wir sie doDelegate, der richtige Einsprungspunkt in die DLL-Funktion CallWindowProc wird dabei durch das Alias CallWindowProcA festgelegt.

Modul Delegates
Code:
Option Explicit

' Delegate-Workaround
' hier wird die API CallWindowProc verwendet, die eine "Nachricht"
' weiterreicht.
' Die 4 Parameter hWnd, Msg, wParam und lParam sind optional
' und können für eigene Argumente genutzt werden.
Public Declare Function doDelegate _
                         Lib "user32.dll" Alias "CallWindowProcA" ( _
                         ByVal lpPrevWndFunc As Long, _
                         Optional ByVal hwnd As Long, _
                         Optional ByVal msg As Long, _
                         Optional ByVal wParam As Long, _
                         Optional ByVal lParam As Long) As Long

Jede Funktion, die wir mithilfe dieses Delegates an andere Funktionen übergeben, kann nun alle optionalen Parameter entgegennehmen. Da wir außer dem ersten (obligatorischen) Parameter (die Adresse der „Unterfunktion“) eigentlich keine weiteren benötigen, können (und werden) wir sie für unsere Zwecke nutzen.

Benutzung der Delegates
Um nun einige Beispiele zu zeigen, wie Prozeduren an andere Prozeduren – mit und ohne Parameter – übergeben werden können, bauen wir zuerst eine Klasse, die diverse Funktionen übernehmen und ausführen kann. Diese entspricht unserem Kind von oben. Hinweis: Delegate-Aufrufe müssen natürlich nicht unbedingt in einem Klassenmodul stehen, sondern können auch in jedem Modul verwendet werden.

Schauen wir uns die erste Funktion an, die in unserem Beispiel von oben zur Schule entspricht. Warum schicken wir das Kind denn nicht direkt mit dem Schulbus oder dem Auto in die Schule? Weil es vorher noch ein paar Dinge erledigen muss, um die wir uns beim Losschicken nicht kümmern wollen. Das ist ja Aufgabe einer Klasse, in unserem Fall also des Kindes, sich um die eigenen Dinge zu kümmern. Ich simuliere das hier mal mit einer Ausgabe.

Klassenmodul Kind
Code:
Option Explicit

Sub ZurSchule(procAddr As Long)
    MsgBox "Ich ziehe mich an..."
    doDelegate procAddr
End Sub

Diese Funktion erhält als Parameter eine Prozedur- oder Funktions-Adresse. Da Adressen immer Long sind, wird der Parameter mit diesem Datentyp deklariert. Diese Adresse wird dann als Argument an unsere Delegate-Funktion doDelegate weitergegeben. In diesem Moment wird die Prozedur oder Funktion ausgeführt, deren Adresse wir übergeben haben.

Kleiner Wermutstropfen: Solche Prozeduren/Funktionen, die weitergegeben werden sollen, dürfen nicht in Klassenmodulen stehen. Erstellen wir also ein Modul, in das wir ein paar Prozeduren implementieren, die wir weitergeben wollen. Diese Prozeduren entsprechen mit Auto oder mit Schulbus.

Modul Modul1
Code:
Option Explicit

Sub MitSchulbus()
    MsgBox "Ich fahre mit dem Schulbus..."
End Sub

Sub MitAuto()
    MsgBox "Papa fährt mich hin..."
End Sub

Diese Prozeduren lassen wir jetzt durch die Prozedur ZurSchule ausführen.
Dafür implementieren wir eine Test-Routine in ThisDocument:

Word Objekt ThisDocument
Code:
Option Explicit
 Sub DelegateDemo()
    Dim maria As New Kind
    ' Modul-Prozeduren an eine Klassen-Prozedur übergeben
    maria.ZurSchule AddressOf MitSchulbus   ' aus Modul1
    maria.ZurSchule AddressOf MitAuto
End Sub

Zuerst müssen wir natürlich ein Objekt aus unserer Klasse instanziieren, also unser o.a. Kind zeugen, ich nenne es mal Maria Smile

Dann rufen wir die Prozedur ZurSchule dieser Klasse auf und übergeben – und das ist jetzt wichtig – die Adresse der Prozedur MitSchulbus. Und diese Adresse ermitteln wir mit dem unären Operator AddressOf. Wir können nun also aussuchen, wie wir Maria in die Schule schicken und schicken sie deshalb auch gleich noch mit dem Auto hin.

Dies war jetzt ein einfaches Delegate, aber nichts anderes ist ein Delegate – die Übergabe von Prozedur- oder Funktionsaufrufen an eine andere Prozedur oder Funktion.

Sinn und Zweck eines Delegates
Warum benutzen wir nun Delegates? Weil ggf. vor der eigentlichen Ausführung der Prozedur noch ein paar Dinge erledigt werden müssen, um die wir uns aber beim Aufruf nicht kümmern können/wollen/dürfen. Wir schubsen die Ausführung nur an und wenn es soweit ist, dann wird sie tatsächlich ausgeführt.

Noch ein weiteres Beispiel?
Erstellen wir ein neues Modul und benutzen nun eine Funktion.

Modul Modul2
Code:
Option Explicit

Function LerneMathe() As Integer
    Dim a As Integer, b As Integer
    a = 5
    b = 10
    MsgBox "Ich habe was berechnet...: " & (a * b)
    LerneMathe = a * b
End Function

Weil wir nun auch einen Rückgabewert verarbeiten wollen, sollten wir natürlich auch das Delegate über eine Funktion aufrufen. Also kommt eine entsprechende Funktion in unsere Klasse:

Klassenmodul Kind
Code:
Function Lernen(procAddr As Long)
    Lernen = doDelegate(procAddr)
End Function

Da es sich um einen Funktionsaufruf handelt, müssen nun natürlich die Argumente in Klammern angegeben werden.

Beim Aufruf nehmen wir den Rückgabewert entgegen und lassen ihn anzeigen:

Word Objekt ThisDocument
Code:
    ' Modul-Funktion an eine Klassen-Funktion übergeben
    MsgBox maria.Lernen(AddressOf LerneMathe)   ' aus Modul2


Zusammenfassung
Hier noch mal ein kurze Zusammenfassung des Themas. Im Anschluss folgen dann noch ergänzende Hinweise für den Umgang mit Parametern.

    1. Bereitstellen einer API-Funktion als Workaround für Delegates in einem Modul
    Code:
    Public Declare Function doDelegate _
                             Lib "user32.dll" Alias "CallWindowProcA" ( _
                             ByVal lpPrevWndFunc As Long, _
                             Optional ByVal hwnd As Long, _
                             Optional ByVal msg As Long, _
                             Optional ByVal wParam As Long, _
                             Optional ByVal lParam As Long) As Long

    2. Bereitstellen von Prozeduren/Funktionen, die als Delegate aufgerufen werden sollen, in Modulen
    Code:
    Sub IchMachWas()
        ' …
    End Sub

    Function IchGebeWas() As Integer
        ' …
        IchGebeWas = …
    End Function

    3. Übernahme und Ausführen der Delegates in Klassen oder Modulen
    Code:
    Sub TuWas(procAddr As Long)
        ' …
        doDelegate procAddr
    End Sub

    Function GibWas(procAddr As Long)
        ' …
        GibWas = doDelegate(procAddr)
    End Function

    4. Übergabe der Delegates als Adresse
    Code:
    TuWas AddressOf IchMachWas

    MsgBox GibWas(AddressOf IchGebeWas)


Delegates mit Parameter
Aufmerksame Leser werden festgestellt haben, dass die API-Funktion, die wir hier benutzen, auch alle weiteren Parameter (neben der Prozedur-Adresse) ebenfalls als Long erwartet!

Das bedeutet, wir können die Argumente nicht „einfach so“ übergeben, sondern müssen hier Pointer (Zeiger) benutzen. Auch dafür stellt uns VBA die entsprechenden Funktionen bereit, die allerdings „versteckt“ und nicht dokumentiert sind. Ein Aufruf der Hilfe führt nicht mal unter Office 2010 zum Erfolg Sad Rolling Eyes
Deshalb hier erst mal eine kurze Auflistung der benötigten Pointer-Funktionen:
  • VarPtr() ermittelt die Adresse einer Variablen
  • StrPtr() ermittelt die Adresse eines String-Puffers
  • ObjPtr() ermittelt die Adresse eines Objektes


Hinweise zur Parameterübergabe
(die Auflistung ist sicher nicht vollständig, aber fürs erste wohl ausreichend)

1. Spalte: Datentyp des Arguments
2. Spalte: Verwendung als Argument bei Aufruf
3. Spalte: Verwendung als Parameter bei Übernahme in Proc/Func

Wertetypen: para kann direkt verwendet werden
Code:
Integer     VarPtr(arg)   para As Integer
Double      VarPtr(arg)   para As Double

Strings: para kann direkt verwendet werden, aber bei Nutzung der StrPtr-Funktion muss para ByVal übernommen werden!
Code:
String      VarPtr(arg)   para As String
String      StrPtr(arg)   ByVal para As string

Arrays: para wird als Variant entgegengenommen und kann direkt verwendet werden
Code:
Integer()   VarPtr(arg())   para As Variant
Double()    VarPtr(arg())   para As Variant
String()    VarPtr(arg())   para as Variant

Objekte: para muss ByVal übernommen werden
wird para als richtiger Klassentyp entgegengenommen, kann para direkt verwendet werden
Code:
Object      ObjPtr(arg)   ByVal para As Klasse
Klasse      ObjPtr(arg)   ByVal para As Klasse

wird para als Object entgegengenommen, muss para vor Verwendung konvertiert werden
Code:
Klasse      ObjPtr(arg)   ByVal para As Object
Object      ObjPtr(arg)   ByVal para As Object

Konvertierung:
Code:
Dim cType as Klasse
Set cType = para


Hier noch ein paar Code-Schnipsel mit Beispielen zur Parameterübergabe
Die Modulangaben beziehen sich auf das beigefügte Beispiel-Dokument. Ich habe bei allen Beispielen immer alle 4 Parameter optional entgegen genommen, um wenigstens die Standardwerte der Datentypen an die jeweilige Prozedur übergeben zu können.

Einfache Werte
Code:
    ' verschiedenen Wert-Argumenten übergeben
    Dim i As Integer: i = 100
    Dim d As Double:  d = 1.2345
    Dim s As String:  s = "Hello World!"
    ' Strings können auf 2 Arten entgegengenommen werden...
    maria.MachWasMitValParameter _
        AddressOf IchMachWasMitValParameter, _
        i, d, s, s

Klassenmodul Kind
Code:
' 4 Parameter können sein
Sub MachWasMitValParameter(procAddr As Long, _
                           Optional para1 As Integer, _
                           Optional para2 As Double, _
                           Optional para3 As String, _
                           Optional para4 As String)
    ' die übergebene Prozedur ist IchMachWasMitValParameter
    ' in Modul1:
    ' die beiden Werte-Parameter werden mit der Variablen-Adresse übergeben,
    ' der 1. String wird mit der String-Buffer-Adresse übergeben,
    ' der 2. String wird mit der Variablen-Adresse übergeben
    doDelegate procAddr, VarPtr(para1), _
                         VarPtr(para2), _
                         StrPtr(para3), _
                         VarPtr(para4)
End Sub

Modul Modul1
Code:
' Werte-Typen, die als VarPtr übergeben werden,
' können direkt als entsprechender Typ übernommen werden
' wird ein String als String-Buffer-Adresse übergeben,
' dann muss er byVal übernommen werden! (siehe 3. Parameter)
Sub IchMachWasMitValParameter(i As Integer, _
                              d As Double, _
                              ByVal sAsStrPtr As String, _
                              sAsVarPtr As String)
    ' Um zu prüfen, ob ein VarPtr-Parameter übergeben wurde,
    ' kann vor Verwendung des Parameters
    ' der Parameter auf seinen Standardwert geprüft werden:
    If Not i = 0 Then MsgBox i
    If Not d = 0 Then MsgBox d
    If Not sAsStrPtr = "" Then MsgBox sAsStrPtr
    If Not sAsStrPtr = "" Then MsgBox sAsVarPtr
End Sub



Arrays
Code:
    ' Array-Argumente übergeben
    Dim ta          ' String-Array
    ta = Array("Ich", "heiße", "Thomas")
    Dim ia          ' Integer-Array
    ia = Array(0, 1, 2)
    Dim da(1, 1)    ' Double-Array
    da(0, 0) = 0#
    da(0, 1) = 0.1
    da(1, 0) = 1#
    da(1, 1) = 1.1
    ' Modul1
    maria.MachWasMitArrays AddressOf IchMachWasMitArrays, _
                                     ia, _
                                     da, _
                                     ta
    ' Modul2
    maria.MachWasMitArrays AddressOf IchMachAuchWasMitArrays, _
                                     , , ta, ta

Klassenmodul Kind
Code:
Sub MachWasMitArrays(procAddr As Long, _
                        Optional para1, _
                        Optional para2, _
                        Optional para3, _
                        Optional para4)
    doDelegate procAddr, VarPtr(para1), _
                         VarPtr(para2), _
                         VarPtr(para3), _
                         VarPtr(para4)
End Sub

Modul Modul1
Code:
' Arrays werden als Variant referenziell übernommen
Sub IchMachWasMitArrays(arr1, _
                        arr2, _
                        arr3, _
                        arr4)
    MsgBox arr1(2)
    MsgBox arr2(0, 1)
    MsgBox arr3(1)
End Sub

Modul Modul2
Code:
Sub IchMachAuchWasMitArrays(arr1, _
                            arr2, _
                            arr3, _
                            arr4)
    Dim i As Integer
    Dim s As String
    For i = 0 To UBound(arr3)
        s = s + " " + arr3(i)
    Next
    MsgBox s
    For i = 0 To UBound(arr4)
        s = s + " " + arr4(i)
    Next
    MsgBox s
End Sub



Objekte
Code:
    ' Objekte als Parameter
    Dim o1 As New Klasse2
    o1.Zahl = 555
    maria.MachWasMitObjects AddressOf IchMachWasMitObject, _
                                      o1
    Dim o2 As New Klasse2
    o2.Zahl = 999
    o2.Meldung = "Ich bin auch ein Objekt der Klasse2"
    maria.MachWasMitObjects AddressOf IchMachWasMitObject, _
                                      o2, o2, o2, o2

Klassenmodul Kind
Code:
Sub MachWasMitObjects(procAddr As Long, _
                        Optional para1 As Object, _
                        Optional para2 As Klasse2, _
                        Optional para3 As Klasse2, _
                        Optional para4 As Object)
    doDelegate procAddr, ObjPtr(para1), _
                         ObjPtr(para2), _
                         ObjPtr(para3), _
                         ObjPtr(para4)
End Sub

Modul Modul1
Code:
' Objekte (Klassen) müssen byVal übernommen werden und
' können dabei als entsprechende Klasse
' oder als Object übernommen werden,
' müssen bei letzterem aber konvertiert werden
Sub IchMachWasMitObject( _
               ByVal obj1 As Klasse2, _
               ByVal obj2 As Klasse2, _
               ByVal obj3 As Object, _
               ByVal obj4 As Object)
    MsgBox obj1.Zahl
    ' Um zu prüfen, ob ein ObjPtr-Parameter übergeben wurde,
    ' kann vor Verwendung des Parameters
    ' der Parameter auf Nothing geprüft werden:
    If Not obj2 Is Nothing Then
        MsgBox obj2.Meldung & vbCrLf & "Auch ich bin da...!"
    End If
    ' Klassen-Objekte sollten vor Verwendung
    ' auch in die richtige Klasse konvertiert werden
    Dim cType As Klasse2
    Set cType = obj3
    If Not cType Is Nothing Then _
        MsgBox cType.Meldung & " und habe die Zahl " & cType.Zahl
   
    Set cType = obj4
    If Not obj4 Is Nothing Then _
        MsgBox "Auch ich bin da...!"
End Sub


Und nun viel Spaß mit Delegates Smile

_________________
Gruß Thomas

Ich freue mich über Feedback, Kritik und Verbesserungsvorschläge...
Wer will, findet Möglichkeiten; wer nicht will, findet Gründe! :: Unt wär Rächdshraibfela fint, daaf sie behaltn!



Delegates für Einsteiger und Fortgeschrittene.doc
 Beschreibung:
Die Anleitung als Word-Dokument inkl. aller Makros.
Word 97-2003-Dokument; unter WinXP/OfficeXP und WIn7/Office2010 getestet.

Download
 Dateiname:  Delegates für Einsteiger und Fortgeschrittene.doc
 Dateigröße:  151 KB
 Heruntergeladen:  59 mal

Neues Thema eröffnen   Neue Antwort erstellen Alle Zeiten sind
GMT + 1 Stunde

Diese Seite Freunden empfehlen

Seite 1 von 1
Gehe zu:  
Du kannst Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.
Du kannst Dateien in diesem Forum nicht posten
Du kannst Dateien in diesem Forum herunterladen

Verwandte Themen
Forum / Themen   Antworten   Autor   Aufrufe   Letzter Beitrag 
Keine neuen Beiträge Word Hilfe: *T*AW: Delegates in VBA? Delegates in VBA! 0 GastAfi 143 28. Jun 2012, 11:52
GastAfi *T*AW: Delegates in VBA? Delegates in VBA!
 

----> Diese Seite Freunden empfehlen <------ Impressum - Besuchen Sie auch: Access Tabellen