Skip to content

VB_Attribute Annotations

Mathieu Guindon edited this page Sep 14, 2019 · 6 revisions

VBA and VB6 modules can contain module and member attributes, but adding and editing a lot of these attributes is, at least in VBA (VB6 does provide a UI for this), rather painful: module must be removed/exported, then edited manually outside the editor, saved, and re-imported. And then... they are hidden.

Rubberduck supports a number of special annotations that can be used to surface these hidden attributes in the editor, and inspections that identify missing attributes or annotations, and quickfixes to synchronize them.

Because document modules can't be exported/imported, these annotations will not work in e.g. a Worksheet module.

Module and member descriptions appear in the bottom panel of the Code Explorer, as well as in the Rubberduck toolbar when an identifier that has a description is selected.

Module Annotations

Both standard and class modules can have a VB_Description attribute. To control the value of this attribute, use the '@ModuleDescription annotation:

'@ModuleDescription("Description of the module's purpose")

When synchronizing attributes, this will add or update the module's VB_Description hidden attribute:

Attribute VB_Description = "Description of the module's purpose"

Class modules have more attributes that control their visibility and usage:

  • VB_PredeclaredId is normally False (True for UserForm modules). Use the '@PredeclaredId annotation to make it True. Classes with a predeclared ID have a global-scope instance that's named after the class. While we do not recommend using this default instance for global state, this is extremely useful for creating and exposing factory methods and pure functions, among other things.
  • VB_Exposed is normally False. Use the '@Exposed annotation to make it True. Exposed classes can be accessed/consumed from other VBA projects. This attribute is also modifiable by editing the Instancing property of the class.

Fields can have a description too:

  • VB_VarDescription attributes control the description string of module fields. Use the '@VariableDescription annotation on the line immediately above a field's declaration, to specify a description string for that variable.

     '@VariableDescription("It's a thing")
     Private thing As Something
    

Member Annotations

Members can also have attributes. For Property procedures, the attribute is typically added to the Get member. Member attributes use a similar syntax as module attributes, but the member name needs to qualify the attribute. For example:

Public Sub DoSomething()
Attribute DoSomething.VB_Description = "Does something"
End Sub

Rubberduck annotations handles the following member attributes in standard modules:

  • VB_Description controls the description string of the procedure; use the @Description annotation to determine its value;

     '@Description("Does something")
     Public Sub DoSomething()
     End Sub
    
  • VB_ProcData.VB_Invoke_Func is used in Excel to assign hotkeys; use the @ExcelHotkey annotation to specify a hotkey to invoke a macro:

     '@ExcelHotkey("D")
     Public Sub DoSomething()
     End Sub
    

    The annotation argument is expected to be a 1-character string; given a lowercase "d", the hotkey is Ctrl+D; given an uppercase "D", the hotkey is Ctrl+Shift+D

Class module members can have more attributes:

  • VB_UserMemId with a value of 0, makes a member the class' default member. Use the '@DefaultMember annotation to control this specific attribute value - note that only one member of the class can be the default member. For collection classes, by convention this member is an indexed Property Get procedure named Item. The default member of an object can be invoked implicitly - use judiciously, since this is very much double-edged.
  • VB_UserMemId with a value of -4, marks a member as the enum provider function for a collection class that can be iterated with a For Each loop. This member is typically a Function or Property Get procedure named NewEnum, that returns an IUnknown, wrapping an internal collection's own hidden [_NewEnum] member. Use the '@Enumerator annotation to identify that member in code.
Clone this wiki locally