web-dev-qa-db-fra.com

Caractéristiques cachées de VBA

Quelles fonctionnalités du langage VBA sont soit mal documentées, soit simplement peu utilisées?

29
guillermooo

Cette astuce ne fonctionne que dans Access VBA, Excel et d'autres ne le permettront pas. Cependant, vous pouvez masquer un module standard à l'explorateur d'objets en préfixant son nom par un trait de soulignement. Le module ne sera alors visible que si vous modifiez le navigateur d'objets pour afficher les objets cachés. 

Cette astuce fonctionne avec Enums dans toutes les versions de VBA basées sur vb6. Vous pouvez créer un membre caché d'un Enum en mettant son nom entre parenthèses, puis en le préfixant d'un trait de soulignement. Exemple:

Public Enum MyEnum
    meDefault = 0
    meThing1 = 1
    meThing2 = 2
    meThing3 = 3
    [_Min] = meDefault 
    [_Max] = meThing3 
End Enum

Public Function IsValidOption(ByVal myOption As MyEnum) As Boolean
    If myOption >= MyEnum.[_Min] Then IsValidOption myOption <= MyEnum.[_Max]
End Function

Dans Excel-VBA, vous pouvez référencer des cellules en les mettant entre crochets. Ces crochets fonctionnent également comme une commande evaluer vous permettant d’évaluer la syntaxe de la formule:

Public Sub Example()
    [A1] = "Foo"
    MsgBox [VLOOKUP(A1,A1,1,0)]
End Sub

Vous pouvez également transmettre des données brutes sans utiliser MemCopy (RtlMoveMemory) en combinant LSet avec des types définis par l'utilisateur de même taille:

Public Sub Example()
    Dim b() As Byte
    b = LongToByteArray(8675309)
    MsgBox b(1)
End Sub

Private Function LongToByteArray(ByVal value As Long) As Byte()
    Dim tl As TypedLong
    Dim bl As ByteLong
    tl.value = value
    LSet bl = tl
    LongToByteArray = bl.value
End Function

Les littéraux octaux et hexadécimaux sont en fait des types non signés. Ils produiront tous les deux -32768:

Public Sub Example()
    Debug.Print &H8000
    Debug.Print &O100000
End Sub

Comme mentionné précédemment, le fait de passer une variable entre parenthèses le fait passer à ByVal:

Sub PredictTheOutput()
    Dim i&, j&, k&
    i = 10: j = i: k = i
    MySub (i)
    MySub j
    MySub k + 20
    MsgBox Join(Array(i, j, k), vbNewLine), vbQuestion, "Did You Get It Right?"
End Sub

Public Sub MySub(ByRef foo As Long)
    foo = 5
End Sub

Vous pouvez affecter une chaîne directement dans un tableau d'octets et inversement:

Public Sub Example()
    Dim myString As String
    Dim myBytArr() As Byte
    myBytArr = "I am a string."
    myString = myBytArr
    MsgBox myString
End Sub

"Mid" est aussi un opérateur. En l’utilisant, vous écrasez des portions spécifiques de chaînes sans la concaténation de chaînes notoirement lente de VBA: 

Public Sub Example1()
    ''// This takes about 47% of time Example2 does:
    Dim myString As String
    myString = "I liek pie."
    Mid(myString, 5, 2) = "ke"
    Mid(myString, 11, 1) = "!"
    MsgBox myString
End Sub

Public Sub Example2()
    Dim myString As String
    myString = "I liek pie."
    myString = "I li" & "ke" & " pie" & "!"
    MsgBox myString
End Sub
32
Oorang

Il existe une caractéristique importante, mais presque toujours oubliée, de la déclaration Mid (). C'est là que Mid () apparaît à gauche d'une affectation, par opposition à la fonction Mid () qui apparaît à droite ou dans une expression.

La règle est la suivante: si la chaîne cible n'est pas un littéral et qu'il s'agit de la seule référence à la chaîne cible et que la longueur du segment inséré correspond à la longueur du segment remplacé, la chaîne sera traitée comme mutable pour l'opération. 

Qu'est-ce que ça veut dire? Cela signifie que si vous construisez un rapport volumineux ou une longue liste de chaînes en une seule valeur de chaîne, son exploitation accélérera le traitement de votre chaîne.

Voici un cours simple qui en profite. Cela donne à votre VBA la même capacité que StringBuilder que celle de .Net.

' Class: StringBuilder

Option Explicit

Private Const initialLength As Long = 32

Private totalLength As Long  ' Length of the buffer
Private curLength As Long    ' Length of the string value within the buffer
Private buffer As String     ' The buffer

Private Sub Class_Initialize()
  ' We set the buffer up to it's initial size and the string value ""
  totalLength = initialLength
  buffer = Space(totalLength)
  curLength = 0
End Sub

Public Sub Append(Text As String)

  Dim incLen As Long ' The length that the value will be increased by
  Dim newLen As Long ' The length of the value after being appended
  incLen = Len(Text)
  newLen = curLength + incLen

  ' Will the new value fit in the remaining free space within the current buffer
  If newLen <= totalLength Then
    ' Buffer has room so just insert the new value
    Mid(buffer, curLength + 1, incLen) = Text
  Else
    ' Buffer does not have enough room so
    ' first calculate the new buffer size by doubling until its big enough
    ' then build the new buffer
    While totalLength < newLen
      totalLength = totalLength + totalLength
    Wend
    buffer = Left(buffer, curLength) & Text & Space(totalLength - newLen)
  End If
  curLength = newLen
End Sub

Public Property Get Length() As Integer
  Length = curLength
End Property

Public Property Get Text() As String
  Text = Left(buffer, curLength)
End Property

Public Sub Clear()
  totalLength = initialLength
  buffer = Space(totalLength)
  curLength = 0
End Sub

Et voici un exemple d'utilisation:

  Dim i As Long
  Dim sb As StringBuilder
  Dim result As String
  Set sb = New StringBuilder
  For i = 1 to 100000
    sb.Append CStr( i)
  Next i
  result = sb.Text
18
Swanny

VBA lui-même semble être une fonctionnalité cachée. Les personnes que je connais et qui utilisent des produits Office depuis des années n’ignorent même pas que cela fait même partie de la suite.

J'ai posté ceci sur plusieurs questions ici, mais le navigateur d'objets est mon arme secrète. Si j'ai besoin de code ninja quelque chose de très rapide, mais ne suis pas familier avec les dll, Object Browser me sauve la vie. Il est beaucoup plus facile d’apprendre les structures de classe que MSDN.

La fenêtre Locals est également idéale pour le débogage. Mettez une pause dans votre code et il vous montrera toutes les variables, leurs noms, ainsi que leurs valeurs et types actuels dans l’espace de noms actuel.

Et qui pourrait oublier notre bon ami Immediate Window? Non seulement c'est bon pour la sortie standard Debug.Print, mais vous pouvez aussi y entrer des commandes. Besoin de savoir ce qu'est VariableX?

?VariableX

Besoin de savoir de quelle couleur est cette cellule?

?Application.ActiveCell.Interior.Color

En fait, toutes ces fenêtres sont d'excellents outils pour être productif avec VBA.

15
mandroid

Ce n'est pas une fonctionnalité, mais une chose que j'ai souvent vue de travers dans VBA (et VB6): une parenthèse a été ajoutée aux appels de méthodes, ce qui changerait la sémantique

Sub Foo()

    Dim str As String

    str = "Hello"

    Bar (str)
    Debug.Print str 'prints "Hello" because str is evaluated and a copy is passed

    Bar str 'or Call Bar(str)
    Debug.Print str 'prints "Hello World"

End Sub

Sub Bar(ByRef param As String)

    param = param + " World"

End Sub
13
Dirk Vollmar

Caractéristiques cachées

  1. Bien que ce soit "Basic", vous pouvez utiliser OOP - classes et objets
  2. Vous pouvez faire des appels d'API
7
Raj More

Les fonctionnalités les moins documentées de VBA sont probablement celles que vous ne pouvez exposer qu'en sélectionnant "Afficher les membres cachés" dans le navigateur d'objets VBA. Les membres cachés sont les fonctions de VBA, mais non prises en charge. Vous pouvez les utiliser, mais Microsoft peut les éliminer à tout moment. Aucun d'entre eux n'a de documentation fournie, mais vous pouvez en trouver sur le Web. Peut-être le plus parlé de ces fonctionnalités cachées fournit un accès aux pointeurs dans VBA. Pour une rédaction décente, consultez; Pas si léger - Shlwapi.dll

Documenté, mais peut-être plus obscur (dans Excel de toute façon), utilisez ExecuteExcel4Macro pour accéder à un espace de nom global masqué qui appartient à l'ensemble de l'instance d'application Excel, par opposition à un classeur spécifique.

7
DaveParillo

Vous pouvez implémenter des interfaces avec le mot clé Implements.

6
guillermooo

Dictionnaires. VBA ne vaut pratiquement rien sans eux!

Référencez Microsoft Scripting Runtime, utilisez Scripting.Dictionary pour toute tâche suffisamment compliquée et vivez heureux pour toujours.

Le Scripting Runtime vous fournit également le FileSystemObject, qui est également hautement recommandé.

Commencez ici, puis creusez un peu ...

http://msdn.Microsoft.com/en-us/library/aa164509%28office.10%29.aspx

6
eksortso

Taper VBA. affichera une liste intellisense de toutes les fonctions et constantes intégrées.

5
CtrlDot

Avec un peu de travail, vous pouvez parcourir des collections personnalisées comme ceci:

' Write some text in Word first.'
Sub test()
    Dim c As New clsMyCollection
        c.AddItems ActiveDocument.Characters(1), _
            ActiveDocument.Characters(2), _
            ActiveDocument.Characters(3), _
            ActiveDocument.Characters(4)

    Dim el As Range
    For Each el In c
        Debug.Print el.Text
    Next
    Set c = Nothing
End Sub

Votre code de collection personnalisé (dans une classe appelée clsMyCollection):

Option Explicit

Dim m_myCollection As Collection

Public Property Get NewEnum() As IUnknown
    ' This property allows you to enumerate
    ' this collection with the For...Each syntax
    ' Put the following line in the exported module
    ' file (.cls)!'
    'Attribute NewEnum.VB_UserMemId = -4
    Set NewEnum = m_myCollection.[_NewEnum]
End Property

Public Sub AddItems(ParamArray items() As Variant)

    Dim i As Variant

    On Error Resume Next
    For Each i In items
        m_myCollection.Add i
    Next
    On Error GoTo 0
End Sub

Private Sub Class_Initialize()
    Set m_myCollection = New Collection
End Sub
4
guillermooo
  • Enregistrez 4 frappes de touches complètes en tapant debug.? xxx au lieu de debug.print xxx.
  • Crash-le en ajoutant: enum foo: me=0: end enum en haut d'un module contenant un autre code.
4
Alex K.

Prise en charge des versions localisées, qui (du moins au siècle précédent) prenaient en charge les expressions utilisant des valeurs localisées. Comme Pravda pour True et Fałszywy (pas très sûr, mais au moins, il avait le drôle L) pour False en polonais ... En fait, la version anglaise pourrait lire des macros dans n'importe quelle langue et convertir à la volée. Les autres versions localisées ne gèreraient pas cela. 

ÉCHOUER.

3
Arjan

IsDate("13.50") renvoie True mais IsDate("12.25.2010") renvoie False

En effet, IsDate pourrait être nommé plus précisément IsDateTime. Et parce que la période (.) est traitée comme un séparateur d'heure et non comme un séparateur de date. Voir ici pour une explication complète

2
mwolfe02

Le modèle objet VBE (Visual Basic Extensibility) est une fonctionnalité moins connue et/ou sous-utilisée. Il vous permet d’écrire du code VBA pour manipuler du code, des modules et des projets VBA. J'ai déjà écrit un projet Excel qui assemblerait d'autres projets Excel à partir d'un groupe de fichiers de module. 

Le modèle objet fonctionne également à partir de VBScript et de HTA. J'ai écrit un HTA à un moment donné pour m'aider à suivre un grand nombre de projets Word, Excel et Access. De nombreux projets utilisaient des modules de code communs, et il était facile pour les modules de "se développer" sur un système et de devoir ensuite migrer vers d'autres systèmes. Mon HTA me permettait d'exporter tous les modules d'un projet, de les comparer aux versions d'un dossier commun, de fusionner les routines mises à jour (avec BeyondCompare), puis de réimporter les modules mis à jour.

Le modèle d'objet VBE fonctionne légèrement différemment entre Word, Excel et Access. Malheureusement, il ne fonctionne pas du tout avec Outlook, mais offre néanmoins une excellente capacité de gestion du code.

2
Todd

VBA prend en charge les opérateurs au niveau des bits pour comparer les chiffres binaires (bits) de deux valeurs. Par exemple, l'expression 4 And 7 évalue les valeurs de bits de 4 (0100) et 7 (0111) et renvoie 4 (le bit activé dans les deux chiffres). ) et 8 (1000) et renvoie 12 (1100), c’est-à-dire les bits où l’un ou l’autre est vrai.

Malheureusement, les opérateurs de bits ont les mêmes noms dans les opérateurs de comparaison logique: And, Eqv, Imp, Not, Or et Xor. Cela peut conduire à des ambiguïtés, voire à des résultats contradictoires.

Par exemple, ouvrez la fenêtre Immédiate (Ctrl + G) et entrez: ? (2 And 4) Cela renvoie zéro, car il n'y a pas de bits en commun entre 2 (0010) et 4 (0100).

1
ph mrnt

Déclarations de type

Cette fonctionnalité existe probablement pour assurer la compatibilité ascendante. Ou pour écrire du code spaghetti désespérément obfusqué. Votre choix.

0
mwolfe02