VBA

Topics related to VBA:

Getting started with VBA

This section provides an overview of what vba is, and why a developer might want to use it.

It should also mention any large subjects within vba, and link out to the related topics. Since the Documentation for vba is new, you may need to create initial versions of those related topics.

Declaring Variables

Scripting.FileSystemObject

Procedure Calls

The first two syntaxes are for calling Sub procedures; notice the first syntax involves no parentheses.

See This is confusing. Why not just always use parentheses? for a thorough explanation of the differences between the first two syntaxes.

The third syntax is for calling Function and Property Get procedures; when there are parameters, the parentheses are always mandatory. The Let keyword is optional when assigning a value, but the Set keyword is required when assigning a reference.

Fourth syntax is for calling Property Let and Property Set procedures; the expression on the right-hand side of the assignment is passed to the property's value parameter.

Naming Conventions

Creating a procedure

Flow control structures

Comments

Comment Blocks

If you need to comment or uncomment several lines at once, you can use the IDE's Edit Toolbar buttons:

Comment Block - Adds a single apostrophe to the start of all selected lines

Comment Block

Uncomment Block - Removes the first apostrophe from the start of all selected lines

Uncomment Block

Multi-line Comments Many other languages support multi-line block comments, but VBA only allows single-line comments.

Arrays

Error Handling

Recursion

Recursion allows for repeated, self-referencing calls of a procedure.

Conditional Compilation

Data Types and Limits

String Literals - Escaping, non-printable characters and line-continuations

The assignment of string-literals in VBA is confined by the limitations of the IDE and the codepage of the current user's language settings. The examples above demonstrate the special-cases of escaped strings, special, non-printable strings and long string-literals.

When assigning string-literals that contain characters that are specific to a certain codepage, you may need to consider internationalization concerns by assigning a string from a separate unicode resource file.

Declaring and assigning strings

Strings are a Reference type and are central to most programming tasks. Strings are assigned text, even if the text happens to be numeric. Strings can be zero-length, or any length up to 2GB. Modern versions of VBA store Strings internally using a Byte array of Multi-Byte Character Set bytes (an alternative to Unicode).

Converting other types to strings

VBA will implicitly convert some types to string as necessary and without any extra work on the part of the programmer, but VBA also provides a number of explicit string conversion functions, and you can also write your own.

Three of the most frequently used functions are CStr, Format and StrConv.

Searching within strings for the presence of substrings

When you need to check for the presence or position of a substring within a string, VBA offers the InStr and InStrRev functions that return the character position of the substring in the string, if it is present.

Substrings

VBA has built-in functions for extracting specific parts of strings, including:

  • Left/Left$
  • Right/Right$
  • Mid/Mid$
  • Trim/Trim$

To avoid implicit type conversion onverhead (and therefore for better performance), use the $-suffixed version of the function when a string variable is passed to the function, and/or if the result of the function is assigned to a string variable.

Passing a Null parameter value to a $-suffixed function will raise a runtime error ("invalid use of null") - this is especially relevant for code involving a database.

Measuring the length of strings

A string's length can be measured in two ways: The most frequently used measure of length is the number of characters using the Len functions, but VBA can also reveal the number of bytes using LenB functions. A double-byte or Unicode character is more than one byte long.

Working with ADO

The examples shown in this topic use early binding for clarity, and require a reference to the Microsoft ActiveX Data Object x.x Library. They can be converted to late binding by replacing the strongly typed references with Object and replacing object creation using New with CreateObject where appropriate.

Concatenating strings

Strings can be concatenated, or joined together, using one or more concatenation operator &.

String arrays can also be concatenated using the Join function and providing a string (which can be zero-length) to be used between each array element.

Assigning strings with repeated characters

There are times you need to assign a string variable with a specific character repeated a specific number of times. VBA provides two main functions for this purpose:

  • String/String$
  • Space/Space$.

Scripting.Dictionary object

You must add Microsoft Scripting Runtime to the VBA project through the VBE's Tools → References command in order to implement early binding of the Scripting Dictionary object. This library reference is carried with the project; it does not have to be re-referenced when the VBA project is distributed and run on another computer.

VBA Option Keyword

It is much easier to control the boundaries of arrays by declaring the boundaries explicitly rather than letting the compiler fall back on an Option Base {0|1} declaration. This can be done like so:

Dim myStringsA(0 To 5) As String '// This has 6 elements (0 - 5)
Dim myStringsB(1 To 5) As String '// This has 5 elements (1 - 5)
Dim myStringsC(6 To 9) As String '// This has 3 elements (6 - 9)

Date Time Manipulation

Creating a Custom Class

This article will show how to create a complete custom class in VBA. It uses the example of a DateRange object, because a starting and ending date are often passed together to functions.

Events

  • An event can only be Public. The modifier is optional because class module members (including events) are implicitly Public by default.

  • A WithEvents variable can be Private or Public, but not Friend. The modifier is mandatory because WithEvents isn't a keyword that declares a variable, but a modifier keyword part of the variable declaration syntax. Hence the Dim keyword must be used if an access modifier isn't present.

Attributes

User Forms

Object-Oriented VBA

Working With Files and Directories Without Using FileSystemObject

The Scripting.FileSystemObject is much more robust that the legacy methods in this topic. It should be preferred in almost all cases.

Operators

Operators are evaluated in the following order:

  • Mathematical operators
  • Bitwise operators
  • Concatenation operators
  • Comparison operators
  • Logical operators

Operators with matching precedence are evaluated from left to right. The default order can be overridden by using parentheses ( and ) to group expressions.

Collections

A Collection is a container object that is included in the VBA runtime. No additional references are required in order to use it. A Collection can be used to store items of any data type and allows retrieval by either the ordinal index of the item or by using an optional unique key.


Feature Comparison with Arrays and Dictionaries

CollectionArrayDictionary
Can be resizedYesSometimes1Yes
Items are orderedYesYesYes2
Items are strongly typedNoYesNo
Items can be retrieved by ordinalYesYesNo
New items can be inserted at ordinalYesNoNo
How to determine if an item existsIterate all itemsIterate all itemsIterate all items
Items can be retrieved by keyYesNoYes
Keys are case-sensitiveNoN/AOptional3
How to determine if a key existsError handlerN/A.Exists function
Remove all itemsIterate and .RemoveErase, ReDim.RemoveAll function

1 Only dynamic arrays can be resized, and only the last dimension of multi-dimensional arrays.

2 The underlying .Keys and .Items are ordered.

3 Determined by the .CompareMode property.

Passing Arguments ByRef or ByVal

Passing arrays

Arrays must be passed by reference. This code compiles, but raises run-time error 424 "Object Required":

Public Sub Test()
    DoSomething Array(1, 2, 3)
End Sub

Private Sub DoSomething(ByVal foo As Variant)
    foo.Add 42
End Sub

This code does not compile:

Private Sub DoSomething(ByVal foo() As Variant) 'ByVal is illegal for arrays
    foo.Add 42
End Sub

CreateObject vs. GetObject

At its simplest, CreateObject creates an instance of an object whereas GetObject gets an existing instance of an object. Determining whether an object can be created or gotten will depend on it's Instancing property. Some objects are SingleUse (eg, WMI) and cannot be created if they already exist. Other objects (eg, Excel) are MultiUse and allow multiple instances to run at once. If an instance of an object does not already exist and you attempt GetObject, you will receive the following trappable message: Run-time error '429': ActiveX component can't create object.

GetObject requires at least one of these two optional parameters to be present:

  1. Pathname - Variant (String): The full path, including filename, of the file containing the object. This parameter is optional, but Class is required if Pathname is omitted.
  2. Class - Variant (String): A string representing the formal definition (Application and ObjectType) of the object. Class is required if Pathname is omitted.

CreateObject has one required parameter and one optional parameter:

  1. Class - Variant (String): A string representing the formal definition (Application and ObjectType) of the object. Class is a required parameter.
  2. Servername - Variant (String): The name of the remote computer on which the object will be created. If omitted, the object will be created on the local machine.

Class is always comprised of two parts in the form of Application.ObjectType:

  1. Application - The name of the application which the object is part of. |
  2. Object Type - The type of object being created. |

Some example classes are:

  1. Word.Application
  2. Excel.Sheet
  3. Scripting.FileSystemObject

Macro security and signing of VBA-projects/-modules

Data Structures

Interfaces

Reading 2GB+ files in binary in VBA and File Hashes

METHODS FOR THE CLASS BY MICROSOFT

Method NameDescription
IsOpenReturns a boolean to indicate whether the file is open.
OpenFile(sFileName As String)Opens the file specified by the sFileName argument.
CloseFileCloses the currently open file.
ReadBytes(ByteCount As Long)Reads ByteCount bytes and returns them in a Variant byte array and moves the pointer.
WriteBytes(DataBytes() As Byte)Writes the contents of the byte array to the current position in the file and moves the pointer.
FlushForces Windows to flush the write cache.
SeekAbsolute(HighPos As Long, LowPos As Long)Moves the file pointer to the designated position from the beginning of the file. Though VBA treats the DWORDS as signed values, the API treats them as unsigned. Make the high-order argument non-zero to exceed 4GB. The low-order DWORD will be negative for values between 2GB and 4GB.
SeekRelative(Offset As Long)Moves the file pointer up to +/- 2GB from the current location. You can rewrite this method to allow for offsets greater than 2GB by converting a 64-bit signed offset into two 32-bit values.

PROPERTIES OF THE CLASS BY MICROSOFT

PropertyDescription
FileHandleThe file handle for the currently open file. This is not compatible with VBA file handles.
FileNameThe name of the currently open file.
AutoFlushSets/indicates whether WriteBytes will automatically call the Flush method.

NORMAL MODULE

FunctionNotes
GetFileHash(sFile As String, uBlockSize As Double, sHashType As String)Simply throw in the full path to be hashed, Blocksize to use (number of bytes), and the type of Hash to use - one of the private constants: HashTypeMD5, HashTypeSHA1, HashTypeSHA256, HashTypeSHA384, HashTypeSHA512. This was designed to be as generic as possible.

You should un/comment the uFileSize As Double accordingly. I have tested MD5 and SHA1.

Sorting

Frequently used string manipulation

Automation or Using other applications Libraries

When an application supports Automation, the objects the application exposes can be accessed by Visual Basic. Use Visual Basic to manipulate these objects by invoking methods on the object or by getting and setting the object's properties.

If you use the objects in other applications as part of your Visual Basic application, you may want to establish a reference to the object libraries of those applications. Before you can do that, you must first be sure that the application provides an object library.

Allows you to select another application's objects that you want available in your code by setting a reference to that application's object library.

Creates an Automation object of the specified class. If the application is already running, CreateObject will create a new instance.

VBA Run-Time Errors

Copying, returning and passing arrays

Non-Latin Characters

API Calls

Common operating environment library files (DLL's):

Dynamic Link LibraryDescription
Advapi32.dllAdvanced services library for APIs including many security and Registry calls
Comdlg32.dllCommon dialog API library
Gdi32.dllGraphics Device Interface API library
Kernel32.dllCore Windows 32-bit base API support
Lz32.dll32-bit compression routines
Mpr.dllMultiple Provider Router library
Netapi32.dll32-bit Network API library
Shell32.dll32-bit Shell API library
User32.dllLibrary for user interface routines
Version.dllVersion library
Winmm.dllWindows multimedia library
Winspool.drvPrint spooler interface that contains the print spooler API calls

New arguments used for the 64 system:

TypeItemDescription
QualifierPtrSafeIndicates that the Declare statement is compatible with 64-bits. This attribute is mandatory on 64-bit systems
Data TypeLongPtrA variable data type which is a 4-bytes data type on 32-bit versions and an 8-byte data type on 64-bit versions of Office 2010. This is the recommended way of declaring a pointer or a handle for new code but also for legacy code if it has to run in the 64-bit version of Office 2010. It is only supported in the VBA 7 runtime on 32-bit and 64-bit. Note that you can assign numeric values to it but not numeric types
Data TypeLongLongThis is an 8-byte data type which is available only in 64-bit versions of Office 2010. You can assign numeric values but not numeric types (to avoid truncation)
ConversionOperatorCLngPtr Converts a simple expression to a LongPtr data type
ConversionOperatorCLngLng Converts a simple expression to a LongLong data type
FunctionVarPtrVariant converter. Returns a LongPtr on 64-bit versions, and a Long on 32-bit (4 bytes)
FunctionObjPtrObject converter. Returns a LongPtr on 64-bit versions, and a Long on 32-bit (4 bytes)
FunctionStrPtrString converter. Returns a LongPtr on 64-bit versions, and a Long on 32-bit (4 bytes)

Full reference of call signatures: