Nov.

Une fonction qui utilise l'argument ParamArray permet de transmettre à cette fonction un nombre d'arguments variables tout en standardisant sa signature.
Ex:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
Function Multiply ( ParamArray args() as Variant
    dim x as Long, Ret as long
 
    if ubound(args)>=0 then
        ret=1
        For x=lbound(args) to ubound(args)
            ret=ret*args(x)
        next
    endif
 
    Multiply=ret
End Function
Cette fonction qui utilise l'argument paramArray pourra alors être appelée indifféremment par
i=Multiply(2,7)
ou par
i=Multiply(2,7,11,14)

=> L'argument ParamArray convertit la liste des paramètres transmis en un tableau d'arguments à une dimension.


Problématique du passage d'arguments
Quid de l'appel imbriqué de 2 fonctions utilisant l'argument ParamArray ?


La 1ère idée qui vient à l'esprit serait de transmettre tel quel le tableau récupéré à la seconde fonction -
par exemple
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
i=ComplexeFunct(2,3,4)
'avec
Function ComplexFunct(ParamArray args())
    ComplexFunct=Multiply(args)
End Function
ce qui induit évidemment une erreur puisque l'argument récupéré ne sera plus un tableau à 1 dimension de n arguments
... mais un tableau à 1 seul élément contenant un tableau de n arguments unique de la forme args(0)().
En cas d'imbriquements plus complexes le tableau sera sera du type args(0)(0)(0)()...


Solution pour gérer la propagation des arguments

La solution consiste à utiliser la fonction CallByName
en l'appelant par le biais d'un artifice (InvokeHookArray) délivré par le librairie TLI (TypeLibInfo) .
CallByName impose toutefois deux contraintes :
- la fonction appelée doit appartenir à un module object,
- elle doit être publique.


Exemple de propagation d'un argument paramArray
L'exemple suivant est inspiré de l'exemple extrait de l'adresse suivante http://www.devx.com/tips/Tip/15422.
'Soit 1 Form - Autoredraw:true

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 
Option Explicit
 
Private Sub Form_Activate()
    Dim i As Long, a As Long, b As Long, c As Long
 
    a = 2: b = 4: c = 5
    Me.Print "Multiply : " & a & " x " & b & " x " & c & " = " & ComplexFunct(1, a, b, c)
    Me.Print "Divise   : " & a & " / " & b & " / " & c & " = " & ComplexFunct(2, a, b, c)
End Sub
 
 
Private Function ComplexFunct(oper As Long, ParamArray args() As Variant)
    Dim v As Variant
 
    v = args
    Select Case oper
        Case 1
            ComplexFunct = CallByNameEx(Me, "Multiply", VbMethod, v)
 
        Case Else
            ComplexFunct = CallByNameEx(Me, "Divise", VbMethod, v)
    End Select
End Function
 
        Public Function Multiply(ParamArray args() As Variant)
            Dim x As Long, Ret As Long
 
            If UBound(args) >= 0 Then
                Ret = 1
                For x = LBound(args) To UBound(args)
                    Ret = Ret * args(x)
                Next
            End If
 
            Multiply = Ret
        End Function
        Public Function Divise(ParamArray args() As Variant)
            Dim x As Long, Ret As Double
 
            If UBound(args) >= 0 Then
                Ret = args(LBound(args))
                For x = LBound(args) + 1 To UBound(args)
                    Ret = Ret / args(x)
                Next
            End If
 
            Divise = Ret
        End Function
 
        '   INVOKE CALLBYNAME                       '
        '==========================================='
        Private Function CallByNameEx(Obj As Object, ProcName As String, CallType As VbCallType, Optional vArgsArray As Variant)
            Dim oTLI As Object
            Dim ProcID As Long, numArgs As Long, i As Long
            Dim v()
 
            Set oTLI = CreateObject("TLI.TLIApplication")
 
            ' Récupérer l'adresse de la fonction                                                '
            ProcID = oTLI.InvokeID(Obj, ProcName)
 
            ' Aucun paramètre transmis                                                          '
            If IsMissing(vArgsArray) Then
                CallByNameEx = oTLI.InvokeHook(Obj, ProcID, CallType)
 
            Else
 
                ' Inverser les paramètres du tableau                                            '
                If IsArray(vArgsArray) Then
                    numArgs = UBound(vArgsArray)
                    ReDim v(numArgs)
                    For i = 0 To numArgs
                        v(i) = vArgsArray(numArgs - i)
                    Next i
                    CallByNameEx = oTLI.InvokeHookArray(Obj, ProcID, CallType, v)
 
                Else
                ' Conserver la compatibilité dans le cas d'un appel direct à un seul argument   '
                    CallByNameEx = oTLI.InvokeHook(Obj, ProcID, CallType, vArgsArray)
                End If
 
            End If
            Set oTLI = Nothing
 
        End Function