ByRef et ByVal sont des attributs réservés aux définitions de paramètres des procédures.
C'est une question de lieu de résidence de la donnée transmise, vu de la procédure appelée :
ByRef: externe, ByVal: interne.
Parmi la foule de détails microscopiques contribuant à du code performant, j'ai à cœur d'essayer de programmer en VBA de façon à engendrer un code machine qui ne soit pas trop idiot (comme là où c'est en fond rose des deux cotés dans l'encadré).
Le plus souvent, un paramètre de procédure devrait être défini ByVal. Il ne doit être laissé ByRef (option par défaut) que s'il s'agit d'un tableau, ou si la procédure appelante doit spécifier pour ce paramètre non pas une expression mais une variable, et que la procédure appelée est chargée de la modifier durablement.
Remarque: Pour une variable objet, ce qui consiste à la modifier c'est de l'initialiser par un Set, et non pas de changer des propriétés de l'exemplaire qu'elle désigne. Pour ne faire que ça, ByVal convient parfaitement.
Une variable objet n'est en réalité qu'à un simple pointeur. C’est-à-dire une zone de mémoire contenant une adresse. C'est cette adresse qui en est, techniquement, le contenu, pas ce vers quoi elle pointe.
Ces explications concernent seulement les données de tailles fixes. L'accès au contenu proprement dit, toujours alloué en dehors de la pile, des Variant, String, objets et tableaux est réalisé dans un deuxième temps (voire un troisième, du coup, quand y a des passages ByRef inutiles).
De plus ByVal documente la programmation en indiquant dans l'instruction Sub, Function ou Property qu'il s'agit d'une donnée d'entrée, et que même si la procédure modifiera sa valeur, par simple commodité, ce ne sera pas dans l'intention de modifier le paramètre qui lui aura été transmis. C'est juste une variable de travail interne pourvue par la procédure appelante d'une valeur initiale.