excel vba notes for professionals - media.codenza.app › books_pdfs ›...

of 128/128
Excel VBA Notes for Professionals Excel ® VBA Notes for Professionals GoalKicker.com Free Programming Books Disclaimer This is an unocial free book created for educational purposes and is not aliated with ocial Excel® VBA group(s) or company(s). All trademarks and registered trademarks are the property of their respective owners 100+ pages of professional hints and tricks

Post on 04-Feb-2021

15 views

Category:

Documents

4 download

Embed Size (px)

TRANSCRIPT

  • Excel VBANotes for ProfessionalsExcel® VBA

    Notes for Professionals

    GoalKicker.comFree Programming Books

    DisclaimerThis is an unocial free book created for educational purposes and is

    not aliated with ocial Excel® VBA group(s) or company(s).All trademarks and registered trademarks are

    the property of their respective owners

    100+ pagesof professional hints and tricks

    https://goalkicker.comhttps://goalkicker.com

  • ContentsAbout 1 ................................................................................................................................................................................... Chapter 1: Getting started with Excel VBA 2 .......................................................................................................

    Section 1.1: Opening the Visual Basic Editor (VBE) 3 ..................................................................................................... Section 1.2: Declaring Variables 5 ................................................................................................................................... Section 1.3: Adding a new Object Library Reference 6 ................................................................................................. Section 1.4: Hello World 10 .............................................................................................................................................. Section 1.5: Getting Started with the Excel Object Model 12 ........................................................................................

    Chapter 2: Debugging and Troubleshooting 16 ................................................................................................ Section 2.1: Immediate Window 16 ................................................................................................................................. Section 2.2: Use Timer to Find Bottlenecks in Performance 17 .................................................................................. Section 2.3: Debugger Locals Window 17 ...................................................................................................................... Section 2.4: Debug.Print 18 .............................................................................................................................................. Section 2.5: Stop 19 .......................................................................................................................................................... Section 2.6: Adding a Breakpoint to your code 19 .......................................................................................................

    Chapter 3: Methods for Finding the Last Used Row or Column in a Worksheet 20 ........................ Section 3.1: Find the Last Non-Empty Cell in a Column 20 ........................................................................................... Section 3.2: Find the Last Non-Empty Row in Worksheet 20 ....................................................................................... Section 3.3: Find the Last Non-Empty Column in Worksheet 21 ................................................................................. Section 3.4: Find the Last Non-Empty Cell in a Row 22 ................................................................................................ Section 3.5: Get the row of the last cell in a range 22 .................................................................................................. Section 3.6: Find Last Row Using Named Range 22 ..................................................................................................... Section 3.7: Last cell in Range.CurrentRegion 23 .......................................................................................................... Section 3.8: Find the Last Non-Empty Cell in Worksheet - Performance (Array) 23 ................................................

    Chapter 4: User Defined Functions (UDFs) 26 ................................................................................................... Section 4.1: Allow full column references without penalty 26 ...................................................................................... Section 4.2: Count Unique values in Range 27 .............................................................................................................. Section 4.3: UDF - Hello World 27 ...................................................................................................................................

    Chapter 5: VBA Best Practices 30 ............................................................................................................................. Section 5.1: ALWAYS Use "Option Explicit" 30 ................................................................................................................ Section 5.2: Work with Arrays, Not With Ranges 32 ..................................................................................................... Section 5.3: Switch o properties during macro execution 33 .................................................................................... Section 5.4: Use VB constants when available 34 ......................................................................................................... Section 5.5: Avoid using SELECT or ACTIVATE 35 ......................................................................................................... Section 5.6: Always define and set references to all Workbooks and Sheets 37 ...................................................... Section 5.7: Use descriptive variable naming 37 ........................................................................................................... Section 5.8: Document Your Work 38 ............................................................................................................................. Section 5.9: Error Handling 39 ......................................................................................................................................... Section 5.10: Never Assume The Worksheet 41 ............................................................................................................ Section 5.11: Avoid re-purposing the names of Properties or Methods as your variables 41 .................................. Section 5.12: Avoid using ActiveCell or ActiveSheet in Excel 42 ................................................................................... Section 5.13: WorksheetFunction object executes faster than a UDF equivalent 43 ................................................

    Chapter 6: Loop through all Sheets in Active Workbook 45 ....................................................................... Section 6.1: Retrieve all Worksheets Names in Active Workbook 45 .......................................................................... Section 6.2: Loop Through all Sheets in all Files in a Folder 45 ...................................................................................

    Chapter 7: Ranges and Cells 47 ................................................................................................................................. Section 7.1: Ways to refer to a single cell 47 .................................................................................................................

  • Section 7.2: Creating a Range 47 ................................................................................................................................... Section 7.3: Oset Property 49 ....................................................................................................................................... Section 7.4: Saving a reference to a cell in a variable 49 ............................................................................................ Section 7.5: How to Transpose Ranges (Horizontal to Vertical & vice versa) 49 ......................................................

    Chapter 8: Common Mistakes 51 .............................................................................................................................. Section 8.1: Qualifying References 51 ............................................................................................................................ Section 8.2: Deleting rows or columns in a loop 52 ...................................................................................................... Section 8.3: ActiveWorkbook vs. ThisWorkbook 52 ...................................................................................................... Section 8.4: Single Document Interface Versus Multiple Document Interfaces 53 ...................................................

    Chapter 9: Arrays 55 ....................................................................................................................................................... Section 9.1: Dynamic Arrays (Array Resizing and Dynamic Handling) 55 ................................................................. Section 9.2: Populating arrays (adding values) 55 ....................................................................................................... Section 9.3: Jagged Arrays (Arrays of Arrays) 56 ........................................................................................................ Section 9.4: Check if Array is Initialized (If it contains elements or not) 56 ................................................................ Section 9.5: Dynamic Arrays [Array Declaration, Resizing] 56 ...................................................................................

    Chapter 10: Excel VBA Tips and Tricks 58 ............................................................................................................. Section 10.1: Using xlVeryHidden Sheets 58 ................................................................................................................... Section 10.2: Using Strings with Delimiters in Place of Dynamic Arrays 59 ............................................................... Section 10.3: Worksheet .Name, .Index or .CodeName 59 ............................................................................................ Section 10.4: Double Click Event for Excel Shapes 61 ................................................................................................... Section 10.5: Open File Dialog - Multiple Files 62 ..........................................................................................................

    Chapter 11: PowerPoint Integration Through VBA 63 ..................................................................................... Section 11.1: The Basics: Launching PowerPoint from VBA 63 ......................................................................................

    Chapter 12: Workbooks 64 ............................................................................................................................................ Section 12.1: When To Use ActiveWorkbook and ThisWorkbook 64 ........................................................................... Section 12.2: Changing The Default Number of Worksheets In A New Workbook 64 .............................................. Section 12.3: Application Workbooks 64 ......................................................................................................................... Section 12.4: Opening A (New) Workbook, Even If It's Already Open 65 .................................................................... Section 12.5: Saving A Workbook Without Asking The User 66 ...................................................................................

    Chapter 13: Pivot Tables 67 .......................................................................................................................................... Section 13.1: Adding Fields to a Pivot Table 67 .............................................................................................................. Section 13.2: Creating a Pivot Table 67 .......................................................................................................................... Section 13.3: Pivot Table Ranges 70 ............................................................................................................................... Section 13.4: Formatting the Pivot Table Data 70 .........................................................................................................

    Chapter 14: Binding 71 ................................................................................................................................................... Section 14.1: Early Binding vs Late Binding 71 ...............................................................................................................

    Chapter 15: Charts and Charting 73 ........................................................................................................................ Section 15.1: Creating a Chart with Ranges and a Fixed Name 73 .............................................................................. Section 15.2: Creating an empty Chart 74 ..................................................................................................................... Section 15.3: Create a Chart by Modifying the SERIES formula 75 ............................................................................. Section 15.4: Arranging Charts into a Grid 77 ................................................................................................................

    Chapter 16: Application object 81 ............................................................................................................................. Section 16.1: Simple Application Object example: Display Excel and VBE Version 81 ............................................... Section 16.2: Simple Application Object example: Minimize the Excel window 81 .....................................................

    Chapter 17: Merged Cells / Ranges 82 ................................................................................................................... Section 17.1: Think twice before using Merged Cells/Ranges 82 .................................................................................

    Chapter 18: VBA Security 83 ........................................................................................................................................ Section 18.1: Password Protect your VBA 83 ..................................................................................................................

  • Chapter 19: How to record a Macro 84 .................................................................................................................. Section 19.1: How to record a Macro 84 .........................................................................................................................

    Chapter 20: Locating duplicate values in a range 86 .................................................................................... Section 20.1: Find duplicates in a range 86 ....................................................................................................................

    Chapter 21: Named Ranges 88 ................................................................................................................................... Section 21.1: Define A Named Range 88 ......................................................................................................................... Section 21.2: Using Named Ranges in VBA 88 .............................................................................................................. Section 21.3: Manage Named Range(s) using Name Manager 89 ............................................................................. Section 21.4: Named Range Arrays 91 ...........................................................................................................................

    Chapter 22: autofilter ; Uses and best practices 92 ....................................................................................... Section 22.1: Smartfilter! 92 ..............................................................................................................................................

    Chapter 23: Creating a drop-down menu in the Active Worksheet with a Combo Box 96 .......... Section 23.1: Example 2: Options Not Included 96 ......................................................................................................... Section 23.2: Jimi Hendrix Menu 97 ................................................................................................................................

    Chapter 24: Conditional statements 99 ................................................................................................................ Section 24.1: The If statement 99 ....................................................................................................................................

    Chapter 25: Working with Excel Tables in VBA 101 .......................................................................................... Section 25.1: Instantiating a ListObject 101 ................................................................................................................... Section 25.2: Working with ListRows / ListColumns 101 .............................................................................................. Section 25.3: Converting an Excel Table to a normal range 101 ................................................................................

    Chapter 26: Excel-VBA Optimization 102 ............................................................................................................... Section 26.1: Optimizing Error Search by Extended Debugging 102 .......................................................................... Section 26.2: Disabling Worksheet Updating 103 ......................................................................................................... Section 26.3: Row Deletion - Performance 103 ............................................................................................................. Section 26.4: Disabling All Excel Functionality Before executing large macros 104 ................................................. Section 26.5: Checking time of execution 105 ............................................................................................................... Section 26.6: Using With blocks 106 ...............................................................................................................................

    Chapter 27: Conditional formatting using VBA 108 ......................................................................................... Section 27.1: FormatConditions.Add 108 ........................................................................................................................ Section 27.2: Remove conditional format 109 .............................................................................................................. Section 27.3: FormatConditions.AddUniqueValues 109 ................................................................................................ Section 27.4: FormatConditions.AddTop10 110 ............................................................................................................. Section 27.5: FormatConditions.AddAboveAverage 110 .............................................................................................. Section 27.6: FormatConditions.AddIconSetCondition 110 ..........................................................................................

    Chapter 28: File System Object 113 ......................................................................................................................... Section 28.1: File, folder, drive exists 113 ........................................................................................................................ Section 28.2: Basic file operations 113 ........................................................................................................................... Section 28.3: Basic folder operations 114 ...................................................................................................................... Section 28.4: Other operations 114 ................................................................................................................................

    Chapter 29: SQL in Excel VBA - Best Practices 116 .......................................................................................... Section 29.1: How to use ADODB.Connection in VBA? 116 ..........................................................................................

    Chapter 30: Use Worksheet object and not Sheet object 118 ................................................................... Section 30.1: Print the name of the first object 118 .......................................................................................................

    Chapter 31: CustomDocumentProperties in practice 119 ............................................................................. Section 31.1: Organizing new invoice numbers 119 .......................................................................................................

    Credits 122 ............................................................................................................................................................................ You may also like 124 ......................................................................................................................................................

  • GoalKicker.com – Excel® VBA Notes for Professionals 1

    About

    Please feel free to share this PDF with anyone for free,latest version of this book can be downloaded from:

    https://goalkicker.com/ExcelVBABook

    This Excel® VBA Notes for Professionals book is compiled from Stack OverflowDocumentation, the content is written by the beautiful people at Stack Overflow.Text content is released under Creative Commons BY-SA, see credits at the end

    of this book whom contributed to the various chapters. Images may be copyrightof their respective owners unless otherwise specified

    This is an unofficial free book created for educational purposes and is notaffiliated with official Excel® VBA group(s) or company(s) nor Stack Overflow. All

    trademarks and registered trademarks are the property of their respectivecompany owners

    The information presented in this book is not guaranteed to be correct noraccurate, use at your own risk

    Please send feedback and corrections to [email protected]

    https://goalkicker.com/ExcelVBABookhttps://archive.org/details/documentation-dump.7zhttps://archive.org/details/documentation-dump.7zmailto:[email protected]://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 2

    Chapter 1: Getting started with Excel VBAMicrosoft Excel includes a comprehensive macro programming language called VBA. This programming languageprovides you with at least three additional resources:

    Automatically drive Excel from code using Macros. For the most part, anything that the user can do by1.manipulating Excel from the user interface can be done by writing code in Excel VBA.Create new, custom worksheet functions.2.Interact Excel with other applications such as Microsoft Word, PowerPoint, Internet Explorer, Notepad, etc.3.

    VBA stands for Visual Basic for Applications. It is a custom version of the venerable Visual Basic programminglanguage that has powered Microsoft Excel's macros since the mid-1990s.

    IMPORTANTPlease ensure any examples or topics created within the excel-vba tag are specific and relevant to the use of VBAwith Microsoft Excel. Any suggested topics or examples provided that are generic to the VBA language should bedeclined in order to prevent duplication of efforts.

    on-topic examples:

    ✓ Creating and interacting with worksheet objects✓ The WorksheetFunction class and respective methods✓ Using the xlDirection enumeration to navigate a range

    off-topic examples:

    ✗ How to create a 'for each' loop✗ MsgBox class and how to display a message✗ Using WinAPI in VBA

    VBVersion Release Date

    VB6 1998-10-01

    VB7 2001-06-06

    WIN32 1998-10-01

    WIN64 2001-06-06

    MAC 1998-10-01

    ExcelVersion Release Date

    16 2016-01-01

    15 2013-01-01

    14 2010-01-01

    12 2007-01-01

    11 2003-01-01

    10 2001-01-01

    9 1999-01-01

    https://en.wikipedia.org/wiki/Microsoft_Excelhttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 3

    8 1997-01-01

    7 1995-01-01

    5 1993-01-01

    2 1987-01-01

    Section 1.1: Opening the Visual Basic Editor (VBE)Step 1: Open a Workbook

    Step 2 Option A: Press Alt + F11

    This is the standard shortcut to open the VBE.

    Step 2 Option B: Developer Tab --> View Code

    First, the Developer Tab must be added to the ribbon. Go to File -> Options -> Customize Ribbon, then check thebox for developer.

    https://i.stack.imgur.com/MHMA9.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 4

    Then, go to the developer tab and click "View Code" or "Visual Basic"

    Step 2 Option C: View tab > Macros > Click Edit button to open an Existing Macro

    All three of these options will open the Visual Basic Editor (VBE):

    https://i.stack.imgur.com/8WoiR.pnghttps://i.stack.imgur.com/388eU.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 5

    Section 1.2: Declaring VariablesTo explicitly declare variables in VBA, use the Dim statement, followed by the variable name and type. If a variable isused without being declared, or if no type is specified, it will be assigned the type Variant.

    Use the Option Explicit statement on first line of a module to force all variables to be declared before usage (seeALWAYS Use "Option Explicit" ).

    Always using Option Explicit is highly recommended because it helps prevent typo/spelling errors and ensuresvariables/objects will stay their intended type.

    Option Explicit

    Sub Example() Dim a As Integer a = 2 Debug.Print a 'Outputs: 2

    Dim b As Long b = a + 2 Debug.Print b 'Outputs: 4

    Dim c As String c = "Hello, world!" Debug.Print c 'Outputs: Hello, world!End Sub

    Multiple variables can be declared on a single line using commas as delimiters, but each type must be declaredindividually, or they will default to the Variant type.

    Dim Str As String, IntOne, IntTwo As Integer, Lng As Long

    https://i.stack.imgur.com/azT5a.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 6

    Debug.Print TypeName(Str) 'Output: StringDebug.Print TypeName(IntOne) 'Output: Variant

  • GoalKicker.com – Excel® VBA Notes for Professionals 7

    Step 1: Select Menu Tools --> References…

    Step 2: Select the Reference you want to add. This example we scroll down to find “Microsoft PowerPoint 14.0Object Library”, and then press “OK”.

    http://i.stack.imgur.com/0IwJy.jpghttp://i.stack.imgur.com/yfb7J.jpghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 8

    Note: PowerPoint 14.0 means that Office 2010 version is installed on the PC.

    Step 3: in the VB Editor, once you press Ctrl+Space together, you get the autocomplete option of PowerPoint.

    After selecting PowerPoint and pressing ., another menu appears with all objects options related to the PowerPointObject Library. This example shows how to select the PowerPoint's object Application.

    http://i.stack.imgur.com/vsKbO.jpghttp://i.stack.imgur.com/6DoDc.jpghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 9

    Step 4: Now the user can declare more variables using the PowerPoint object library.

    Declare a variable that is referencing the Presentation object of the PowerPoint object library.

    Declare another variable that is referencing the Slide object of the PowerPoint object library.

    http://i.stack.imgur.com/Av3V7.jpghttp://i.stack.imgur.com/dzCOc.jpghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 10

    Now the variables declaration section looks like in the screen-shot below, and the user can start using thesevariables in his code.

    Code version of this tutorial:

    Option Explicit

    Sub Export_toPPT()

    Dim ppApp As PowerPoint.ApplicationDim ppPres As PowerPoint.PresentationDim ppSlide As PowerPoint.Slide

    ' here write down everything you want to do with the PowerPoint Class and objects

    End Sub

    Section 1.4: Hello WorldOpen the Visual Basic Editor ( see Opening the Visual Basic Editor )1.Click Insert --> Module to add a new Module :2.

    http://i.stack.imgur.com/QARnI.jpghttp://i.stack.imgur.com/bfQff.jpghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 11

    Copy and Paste the following code in the new module :3.

    Sub hello() MsgBox "Hello World !" End Sub

    To obtain :

    Click on the green “play” arrow (or press F5) in the Visual Basic toolbar to run the program:4.

    Select the new created sub "hello" and click Run :5.

    http://i.stack.imgur.com/0KhKM.pnghttp://i.stack.imgur.com/wv7kE.pnghttp://i.stack.imgur.com/aFU8E.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 12

    Done, your should see the following window:6.

    Section 1.5: Getting Started with the Excel Object Model

    This example intend to be a gentle introduction to the Excel Object Model for beginners.

    Open the Visual Basic Editor (VBE)1.Click View --> Immediate Window to open the Immediate Window (or ctrl + G ):2.

    You should see the following Immediate Window at the bottom on VBE:3.

    http://i.stack.imgur.com/Mcj1X.pnghttp://i.stack.imgur.com/j88GC.pnghttps://i.stack.imgur.com/I57Nk.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 13

    This window allow you to directly test some VBA code. So let's start, type in this console :

    ?Worksheets.

    VBE has intellisense and then it should open a tooltip as in the following figure :

    Select .Count in the list or directly type .Cout to obtain :

    ?Worksheets.Count

    Then press Enter. The expression is evaluated and it should returns 1. This indicates the number of4.Worksheet currently present in the workbook. The question mark (?) is an alias for Debug.Print.

    Worksheets is an Object and Count is a Method. Excel has several Object (Workbook, Worksheet, Range, Chart ..)and each of one contains specific methods and properties. You can find the complete list of Object in the Excel VBAreference. Worksheets Object is presented here .

    This Excel VBA reference should become your primary source of information regarding the Excel ObjectModel.

    Now let's try another expression, type (without the ? character):5.

    Worksheets.Add().Name = "StackOveflow"

    Press Enter. This should create a new worksheet called StackOverflow.:6.

    To understand this expression you need to read the Add function in the aforementioned Excel reference. You willfind the following:

    Add: Creates a new worksheet, chart, or macro sheet.The new worksheet becomes the active sheet.Return Value: An Object value that represents the new worksheet, chart,

    https://i.stack.imgur.com/msMIR.pnghttps://i.stack.imgur.com/f1i7c.pnghttps://msdn.microsoft.com/en-us/library/ff194068.aspxhttps://msdn.microsoft.com/en-us/library/ff194068.aspxhttps://msdn.microsoft.com/en-us/library/ff821537.aspxhttps://i.stack.imgur.com/7YbHr.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 14

    or macro sheet.

    So the Worksheets.Add() create a new worksheet and return it. Worksheet(without s) is itself a Object that can befound in the documentation and Name is one of its property (see here). It is defined as :

    Worksheet.Name Property: Returns or sets a String value that represents the object name.

    So, by investigating the different objects definitions we are able to understand this code Worksheets.Add().Name ="StackOveflow".

    Add() creates and add a new worksheet and return a reference to it, then we set its Name property to"StackOverflow"

    Now let's be more formal, Excel contains several Objects. These Objects may be composed of one or severalcollection(s) of Excel objects of the same class. It is the case for WorkSheets which is a collection of Worksheetobject. Each Object has some properties and methods that the programmer can interact with.

    The Excel Object model refers to the Excel object hierarchy

    At the top of all objects is the Application object, it represents the Excel instance itself. Programming in VBArequires a good understanding of this hierarchy because we always need a reference to an object to be able to calla Method or to Set/Get a property.

    The (very simplified) Excel Object Model can be represented as,

    Application Workbooks Workbook Worksheets Worksheet Range

    A more detail version for the Worksheet Object (as it is in Excel 2007) is shown below,

    https://msdn.microsoft.com/en-us/library/ff194464.aspxhttps://msdn.microsoft.com/en-us/library/ff194464.aspxhttps://msdn.microsoft.com/en-us/library/ff841127.aspxhttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 15

    The full Excel Object Model can be found here.

    Finally some objects may have events (ex: Workbook.WindowActivate) that are also part of the Excel Object Model.

    https://i.stack.imgur.com/3yhD8.pnghttps://msdn.microsoft.com/en-us/library/ff194068(v=office.15).aspxhttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 16

    Chapter 2: Debugging andTroubleshootingSection 2.1: Immediate WindowIf you would like to test a line of macro code without needing to run an entire sub, you can type commands directlyinto the Immediate Window and hit ENTER to run the line.

    For testing the output of a line, you can precede it with a question mark ? to print directly to the ImmediateWindow. Alternatively, you can also use the print command to have the output printed.

    While in the Visual Basic Editor, press CTRL + G to open the Immediate Window. To rename your currently selectedsheet to "ExampleSheet", type the following in the Immediate Window and hit ENTER

    ActiveSheet.Name = "ExampleSheet"

    To print the currently selected sheet's name directly in the Immediate Window

    ? ActiveSheet.NameExampleSheet

    This method can be very useful to test the functionality of built in or user defined functions before implementingthem in code. The example below demonstrates how the Immediate Window can be used to test the output of afunction or series of functions to confirm an expected.

    'In this example, the Immediate Window was used to confirm that a series of Left and Right'string methods would return the desired string

    'expected output: "value"print Left(Right("1111value1111",9),5) '

  • GoalKicker.com – Excel® VBA Notes for Professionals 17

    Section 2.2: Use Timer to Find Bottlenecks in PerformanceThe first step in optimizing for speed is finding the slowest sections of code. The Timer VBA function returns thenumber of seconds elapsed since midnight with a precision of 1/256th of a second (3.90625 milliseconds) onWindows based PCs. The VBA functions Now and Time are only accurate to a second.

    Dim start As Double ' Timer returns Single, but converting to Double to avoidstart = Timer ' scientific notation like 3.90625E-03 in the Immediate window' ... part of the codeDebug.Print Timer - start; "seconds in part 1"

    start = Timer' ... another part of the codeDebug.Print Timer - start; "seconds in part 2"

    Section 2.3: Debugger Locals WindowThe Locals window provides easy access to the current value of variables and objects within the scope of thefunction or subroutine you are running. It is an essential tool to debugging your code and stepping throughchanges in order to find issues. It also allows you to explore properties you might not have known existed.

    Take the following example,

    Option ExplicitSub LocalsWindowExample() Dim findMeInLocals As Integer Dim findMEInLocals2 As Range findMeInLocals = 1 Set findMEInLocals2 = ActiveWorkbook.Sheets(1).Range("A1")End Sub

    In the VBA Editor, click View --> Locals Window

    Then by stepping through the code using F8 after clicking inside the subroutine, we have stopped before getting toassigning findMeinLocals. Below you can see the value is 0 --- and this is what would be used if you never assignedit a value. The range object is 'Nothing'.

    http://i.stack.imgur.com/rT6Wf.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 18

    If we stop right before the subroutine ends, we can see the final values of the variables.

    We can see findMeInLocals with a value of 1 and type of Integer, and FindMeInLocals2 with a type of Range/Range.If we click the + sign we can expand the object and see its properties, such as count or column.

    Section 2.4: Debug.PrintTo print a listing of the Error Code descriptions to the Immediate Window, pass it to the Debug.Print function:

    Private Sub ListErrCodes() Debug.Print "List Error Code Descriptions" For i = 0 To 65535 e = Error(i) If e "Application-defined or object-defined error" Then Debug.Print i & ": " & e Next iEnd Sub

    http://i.stack.imgur.com/B8vZt.pnghttp://i.stack.imgur.com/8smT0.pnghttp://i.stack.imgur.com/VE12u.pnghttp://i.stack.imgur.com/m7Rdu.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 19

    You can show the Immediate Window by:

    Selecting View | Immediate Window from the menu barUsing the keyboard shortcut Ctrl-G

    Section 2.5: StopThe Stop command will pause the execution when called. From there, the process can be resumed or be executedstep by step.

    Sub Test() Dim TestVar as String TestVar = "Hello World" Stop 'Sub will be executed to this point and then wait for the user MsgBox TestVarEnd Sub

    Section 2.6: Adding a Breakpoint to your codeYou can easily add a breakpoint to your code by clicking on the grey column to the left of the line of your VBA codewhere you want execution to stop. A red dot appears in the column and the breakpoint code is also highlighted inred.

    You can add multiple breakpoints throughout your code and resuming execution is achieved by pressing the "play"icon in your menu bar. Not all code can be a breakpoint as variable definition lines, the first or last line of aprocedure and comment lines cannot be selected as a breakpoint.

    http://i.stack.imgur.com/AJUpD.jpghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 20

    Chapter 3: Methods for Finding the LastUsed Row or Column in a WorksheetSection 3.1: Find the Last Non-Empty Cell in a ColumnIn this example, we will look at a method for returning the last non-empty row in a column for a data set.

    This method will work regardless of empty regions within the data set.

    However caution should be used if merged cells are involved, as the End method will be "stopped" against a mergedregion, returning the first cell of the merged region.

    In addition non-empty cells in hidden rows will not be taken into account.

    Sub FindingLastRow() Dim wS As Worksheet, LastRow As Long Set wS = ThisWorkbook.Worksheets("Sheet1") 'Here we look in Column A LastRow = wS.Cells(wS.Rows.Count, "A").End(xlUp).Row Debug.Print LastRowEnd Sub

    To address the limitations indicated above, the line:LastRow = wS.Cells(wS.Rows.Count, "A").End(xlUp).Row

    may be replaced with:

    for last used row of "Sheet1":1.LastRow = wS.UsedRange.Row - 1 + wS.UsedRange.Rows.Count.

    for last non-empty cell of Column "A" in "Sheet1":2.

    Dim i As Long For i = LastRow To 1 Step -1 If Not (IsEmpty(Cells(i, 1))) Then Exit For Next i LastRow = i

    Section 3.2: Find the Last Non-Empty Row in WorksheetPrivate Sub Get_Last_Used_Row_Index() Dim wS As Worksheet Set wS = ThisWorkbook.Sheets("Sheet1") Debug.Print LastRow_1(wS) Debug.Print LastRow_0(wS)End Sub

    You can choose between 2 options, regarding if you want to know if there is no data in the worksheet :

    NO : Use LastRow_1 : You can use it directly within wS.Cells(LastRow_1(wS),...)YES : Use LastRow_0 : You need to test if the result you get from the function is 0 or not before using it

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 21

    Public Function LastRow_1(wS As Worksheet) As Double With wS If Application.WorksheetFunction.CountA(.Cells) 0 Then LastRow_1 = .Cells.Find(What:="*", _ After:=.Range("A1"), _ Lookat:=xlPart, _ LookIn:=xlFormulas, _ SearchOrder:=xlByRows, _ SearchDirection:=xlPrevious, _ MatchCase:=False).Row Else LastRow_1 = 1 End If End WithEnd Function

    Public Function LastRow_0(wS As Worksheet) As Double On Error Resume Next LastRow_0 = wS.Cells.Find(What:="*", _ After:=ws.Range("A1"), _ Lookat:=xlPart, _ LookIn:=xlFormulas, _ SearchOrder:=xlByRows, _ SearchDirection:=xlPrevious, _ MatchCase:=False).RowEnd Function

    Section 3.3: Find the Last Non-Empty Column in WorksheetPrivate Sub Get_Last_Used_Row_Index() Dim wS As Worksheet Set wS = ThisWorkbook.Sheets("Sheet1") Debug.Print LastCol_1(wS) Debug.Print LastCol_0(wS)End Sub

    You can choose between 2 options, regarding if you want to know if there is no data in the worksheet :

    NO : Use LastCol_1 : You can use it directly within wS.Cells(...,LastCol_1(wS))YES : Use LastCol_0 : You need to test if the result you get from the function is 0 or not before using it

    Public Function LastCol_1(wS As Worksheet) As Double With wS If Application.WorksheetFunction.CountA(.Cells) 0 Then LastCol_1 = .Cells.Find(What:="*", _ After:=.Range("A1"), _ Lookat:=xlPart, _ LookIn:=xlFormulas, _ SearchOrder:=xlByColumns, _ SearchDirection:=xlPrevious, _ MatchCase:=False).Column Else LastCol_1 = 1 End If End WithEnd Function

    The Err object's properties are automatically reset to zero upon function exit.

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 22

    Public Function LastCol_0(wS As Worksheet) As Double On Error Resume Next LastCol_0 = wS.Cells.Find(What:="*", _ After:=ws.Range("A1"), _ Lookat:=xlPart, _ LookIn:=xlFormulas, _ SearchOrder:=xlByColumns, _ SearchDirection:=xlPrevious, _ MatchCase:=False).ColumnEnd Function

    Section 3.4: Find the Last Non-Empty Cell in a RowIn this example, we will look at a method for returning the last non-empty column in a row.

    This method will work regardless of empty regions within the data set.

    However caution should be used if merged cells are involved, as the End method will be "stopped" against a mergedregion, returning the first cell of the merged region.

    In addition non-empty cells in hidden columns will not be taken into account.

    Sub FindingLastCol() Dim wS As Worksheet, LastCol As Long Set wS = ThisWorkbook.Worksheets("Sheet1") 'Here we look in Row 1 LastCol = wS.Cells(1, wS.Columns.Count).End(xlToLeft).Column Debug.Print LastColEnd Sub

    Section 3.5: Get the row of the last cell in a range'if only one area (not multiple areas):With Range("A3:D20") Debug.Print .Cells(.Cells.CountLarge).Row Debug.Print .Item(.Cells.CountLarge).Row 'using .item is also possibleEnd With 'Debug prints: 20

    'with multiple areas (also works if only one area):Dim rngArea As Range, LastRow As LongWith Range("A3:D20, E5:I50, H20:R35") For Each rngArea In .Areas If rngArea(rngArea.Cells.CountLarge).Row > LastRow Then LastRow = rngArea(rngArea.Cells.CountLarge).Row End If Next Debug.Print LastRow 'Debug prints: 50End With

    Section 3.6: Find Last Row Using Named RangeIn case you have a Named Range in your Sheet, and you want to dynamically get the last row of that DynamicNamed Range. Also covers cases where the Named Range doesn't start from the first Row.

    Sub FindingLastRow()

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 23

    Dim sht As WorksheetDim LastRow As LongDim FirstRow As Long

    Set sht = ThisWorkbook.Worksheets("form")

    'Using Named Range "MyNameRange"FirstRow = sht.Range("MyNameRange").Row

    ' in case "MyNameRange" doesn't start at Row 1LastRow = sht.Range("MyNameRange").Rows.count + FirstRow - 1

    End Sub

    Update:A potential loophole was pointed out by @Jeeped for a a named range with non-contiguous rows as it generatesunexpected result. To addresses that issue, the code is revised as below.Asumptions: targes sheet = form, named range = MyNameRange

    Sub FindingLastRow() Dim rw As Range, rwMax As Long For Each rw In Sheets("form").Range("MyNameRange").Rows If rw.Row > rwMax Then rwMax = rw.Row Next MsgBox "Last row of 'MyNameRange' under Sheets 'form': " & rwMaxEnd Sub

    Section 3.7: Last cell in Range.CurrentRegionRange.CurrentRegion is a rectangular range area surrounded by empty cells. Blank cells with formulas such as =""or ' are not considered blank (even by the ISBLANK Excel function).

    Dim rng As Range, lastCell As RangeSet rng = Range("C3").CurrentRegion ' or Set rng = Sheet1.UsedRange.CurrentRegionSet lastCell = rng(rng.Rows.Count, rng.Columns.Count)

    Section 3.8: Find the Last Non-Empty Cell in Worksheet -Performance (Array)

    The first function, using an array, is much fasterIf called without the optional parameter, will default to .ThisWorkbook.ActiveSheetIf the range is empty will returns Cell( 1, 1 ) as default, instead of Nothing

    Speed:

    GetMaxCell (Array): Duration: 0.0000790063 secondsGetMaxCell (Find ): Duration: 0.0002903480 seconds

    .Measured with MicroTimer

    Public Function GetLastCell(Optional ByVal ws As Worksheet = Nothing) As Range Dim uRng As Range, uArr As Variant, r As Long, c As Long Dim ubR As Long, ubC As Long, lRow As Long

    https://msdn.microsoft.com/en-us/library/office/ff196678.aspxhttps://msdn.microsoft.com/en-us/library/office/ff196678.aspxhttps://msdn.microsoft.com/en-us/library/office/ff196678.aspxhttps://support.microsoft.com/en-us/kb/823838https://msdn.microsoft.com/en-us/library/office/ff700515(v=office.14).aspx#Anchor_5https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 24

    If ws Is Nothing Then Set ws = Application.ThisWorkbook.ActiveSheet Set uRng = ws.UsedRange uArr = uRng If IsEmpty(uArr) Then Set GetLastCell = ws.Cells(1, 1): Exit Function End If If Not IsArray(uArr) Then Set GetLastCell = ws.Cells(uRng.Row, uRng.Column): Exit Function End If ubR = UBound(uArr, 1): ubC = UBound(uArr, 2) For r = ubR To 1 Step -1 '----------------------------------------------- last row For c = ubC To 1 Step -1 If Not IsError(uArr(r, c)) Then If Len(Trim$(uArr(r, c))) > 0 Then lRow = r: Exit For End If End If Next If lRow > 0 Then Exit For Next If lRow = 0 Then lRow = ubR For c = ubC To 1 Step -1 '----------------------------------------------- last col For r = lRow To 1 Step -1 If Not IsError(uArr(r, c)) Then If Len(Trim$(uArr(r, c))) > 0 Then Set GetLastCell = ws.Cells(lRow + uRng.Row - 1, c + uRng.Column - 1) Exit Function End If End If Next NextEnd Function

    'Returns last cell (max row & max col) using Find

    Public Function GetMaxCell2(Optional ByRef rng As Range = Nothing) As Range 'Using Find

    Const NONEMPTY As String = "*"

    Dim lRow As Range, lCol As Range

    If rng Is Nothing Then Set rng = Application.ThisWorkbook.ActiveSheet.UsedRange

    If WorksheetFunction.CountA(rng) = 0 Then Set GetMaxCell2 = rng.Parent.Cells(1, 1) Else With rng Set lRow = .Cells.Find(What:=NONEMPTY, LookIn:=xlFormulas, _ After:=.Cells(1, 1), _ SearchDirection:=xlPrevious, _ SearchOrder:=xlByRows) If Not lRow Is Nothing Then Set lCol = .Cells.Find(What:=NONEMPTY, LookIn:=xlFormulas, _ After:=.Cells(1, 1), _ SearchDirection:=xlPrevious, _ SearchOrder:=xlByColumns)

    Set GetMaxCell2 = .Parent.Cells(lRow.Row, lCol.Column) End If End With End If

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 25

    End Function

    .

    MicroTimer:

    Private Declare PtrSafe Function getFrequency Lib "Kernel32" Alias "QueryPerformanceFrequency"(cyFrequency As Currency) As LongPrivate Declare PtrSafe Function getTickCount Lib "Kernel32" Alias "QueryPerformanceCounter"(cyTickCount As Currency) As Long

    Function MicroTimer() As Double Dim cyTicks1 As Currency Static cyFrequency As Currency

    MicroTimer = 0 If cyFrequency = 0 Then getFrequency cyFrequency 'Get frequency getTickCount cyTicks1 'Get ticks If cyFrequency Then MicroTimer = cyTicks1 / cyFrequency 'Returns SecondsEnd Function

    https://msdn.microsoft.com/en-us/library/office/ff700515(v=office.14).aspx#Anchor_5https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 26

    Chapter 4: User Defined Functions (UDFs)Section 4.1: Allow full column references without penaltyIt's easier to implement some UDFs on the worksheet if full column references can be passed in as parameters.However, due to the explicit nature of coding, any loop involving these ranges may be processing hundreds ofthousands of cells that are completely empty. This reduces your VBA project (and workbook) to a frozen mess whileunnecessary non-values are processed.

    Looping through a worksheet's cells is one of the slowest methods of accomplishing a task but sometimes it isunavoidable. Cutting the work performed down to what is actually required makes perfect sense.

    The solution is to truncate the full column or full row references to the Worksheet.UsedRange property with theIntersect method. The following sample will loosely replicate a worksheet's native SUMIF function so thecriteria_range will also be resized to suit the sum_range since each value in the sum_range must be accompanied by avalue in the criteria_range.

    The Application.Caller for a UDF used on a worksheet is the cell in which it resides. The cell's .Parent property is theworksheet. This will be used to define the .UsedRange.

    In a Module code sheet:

    Option Explicit

    Function udfMySumIf(rngA As Range, rngB As Range, _ Optional crit As Variant = "yes") Dim c As Long, ttl As Double With Application.Caller.Parent Set rngA = Intersect(rngA, .UsedRange) Set rngB = rngB.Resize(rngA.Rows.Count, rngA.Columns.Count) End With For c = 1 To rngA.Cells.Count If IsNumeric(rngA.Cells(c).Value2) Then If LCase(rngB(c).Value2) = LCase(crit) Then ttl = ttl + rngA.Cells(c).Value2 End If End If Next c udfMySumIf = ttl

    End Function

    Syntax: =udfMySumIf(*sum_range*, *criteria_range*, [*criteria*])

    https://msdn.microsoft.com/en-us/library/office/ff840732.aspxhttps://msdn.microsoft.com/en-us/library/office/aa195772.aspxhttps://msdn.microsoft.com/en-us/library/office/ff193687.aspxhttps://msdn.microsoft.com/en-us/library/office/aa224980.aspxhttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 27

    While this is a fairly simplistic example, it adequately demonstrates passing in two full column references (1,048,576rows each) but only processing 15 rows of data and criteria.

    Linked official MSDN documentation of individual methods and properties courtesy of Microsoft™.

    Section 4.2: Count Unique values in RangeFunction countUnique(r As range) As Long 'Application.Volatile False ' optional Set r = Intersect(r, r.Worksheet.UsedRange) ' optional if you pass entire rows or columns to thefunction Dim c As New Collection, v On Error Resume Next ' to ignore the Run-time error 457: "This key is already associated withan element of this collection". For Each v In r.Value ' remove .Value for ranges with more than one Areas c.Add 0, v & "" Next c.Remove "" ' optional to exclude blank values from the count countUnique = c.CountEnd Function

    Collections

    Section 4.3: UDF - Hello WorldOpen Excel1.Open the Visual Basic Editor ( see Opening the Visual Basic Editor )2.Add a new module by clicking Insert --> Module :3.

    http://i.stack.imgur.com/sgMr4.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 28

    Copy and Paste the following code in the new module :4.

    Public Function Hello() As String'Note: the output of the function is simply the function's nameHello = "Hello, World !"End Function

    To obtain :

    Go back to your workbook and type "=Hello()" into a cell to see the "Hello World".5.

    http://i.stack.imgur.com/0KhKM.pnghttp://i.stack.imgur.com/1r1E7.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 29

    http://i.stack.imgur.com/PFQsX.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 30

    Chapter 5: VBA Best PracticesSection 5.1: ALWAYS Use "Option Explicit"In the VBA Editor window, from the Tools menu select "Options":

    Then in the "Editor" tab, make sure that "Require Variable Declaration" is checked:

    Selecting this option will automatically put Option Explicit at the top of every VBA module.

    Small note: This is true for the modules, class modules, etc. that haven't been opened so far. So if youalready had a look at e.g. the code of Sheet1 before activating the option "Require Variable Declaration",Option Explicit will not be added!

    Option Explicit requires that every variable has to be defined before use, e.g. with a Dim statement. WithoutOption Explicit enabled, any unrecognized word will be assumed by the VBA compiler to be a new variable of theVariant type, causing extremely difficult-to-spot bugs related to typographical errors. With Option Explicitenabled, any unrecognized words will cause a compile error to be thrown, indicating the offending line.

    Example :

    https://i.stack.imgur.com/DBq0L.pnghttps://i.stack.imgur.com/B3Gam.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 31

    If you run the following code :

    Sub Test() my_variable = 12 MsgBox "My Variable is : " & myvariableEnd Sub

    You will get the following message :

    You have made an error by writing myvariable instead of my_variable, then the message box displays an emptyvariable. If you use Option Explicit , this error is not possible because you will get a compile error messageindicating the problem.

    Now if you add the correct declaration :

    Sub Test() Dim my_variable As Integer my_variable = 12 MsgBox "My Variable is : " & myvariableEnd Sub

    You will obtain an error message indicating precisely the error with myvariable :

    https://i.stack.imgur.com/DDpmM.pnghttps://i.stack.imgur.com/0K5UY.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 32

    Note on Option Explicit and Arrays (Declaring a Dynamic Array):

    You can use the ReDim statement to declare an array implicitly within a procedure.

    Be careful not to misspell the name of the array when you use the ReDim statement

    Even if the Option Explicit statement is included in the module, a new array will be created

    Dim arr() as Long

    ReDim ar() 'creates new array "ar" - "ReDim ar()" acts like "Dim ar()"

    Section 5.2: Work with Arrays, Not With RangesOffice Blog - Excel VBA Performance Coding Best Practices

    Often, best performance is achieved by avoiding the use of Range as much as possible. In this example we read inan entire Range object into an array, square each number in the array, and then return the array back to the Range.This accesses Range only twice, whereas a loop would access it 20 times for the read/writes.

    Option ExplicitSub WorkWithArrayExample() Dim DataRange As VariantDim Irow As LongDim Icol As IntegerDataRange = ActiveSheet.Range("A1:A10").Value ' read all the values at once from the Excel grid, putinto an array

    For Irow = LBound(DataRange,1) To UBound(DataRange, 1) ' Get the number of rows. For Icol = LBound(DataRange,2) To UBound(DataRange, 2) ' Get the number of columns. DataRange(Irow, Icol) = DataRange(Irow, Icol) * DataRange(Irow, Icol) ' cell.value^2 Next IcolNext Irow

    https://i.stack.imgur.com/Z55Ln.pnghttps://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/declaring-arrays#declaring-a-dynamic-arrayhttps://blogs.office.com/2009/03/12/excel-vba-performance-coding-best-practices/https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 33

    ActiveSheet.Range("A1:A10").Value = DataRange ' writes all the results back to the range at once End Sub

    More tips and info with timed examples can be found in Charles Williams's Writing efficient VBA UDFs (Part 1) andother articles in the series.

    Section 5.3: Switch o properties during macro executionIt is best practice in any programming language to avoid premature optimization. However, if testing reveals thatyour code is running too slowly, you may gain some speed by switching off some of the application’s propertieswhile it runs. Add this code to a standard module:

    Public Sub SpeedUp( _ SpeedUpOn As Boolean, _ Optional xlCalc as XlCalculation = xlCalculationAutomatic _) With Application If SpeedUpOn Then .ScreenUpdating = False .Calculation = xlCalculationManual .EnableEvents = False .DisplayStatusBar = False 'in case you are not showing any messages ActiveSheet.DisplayPageBreaks = False 'note this is a sheet-level setting Else .ScreenUpdating = True .Calculation = xlCalc .EnableEvents = True .DisplayStatusBar = True ActiveSheet.DisplayPageBreaks = True End If End WithEnd Sub

    More info on Office Blog - Excel VBA Performance Coding Best Practices

    And just call it at beginning and end of macros:

    Public Sub SomeMacro 'store the initial "calculation" state Dim xlCalc As XlCalculation xlCalc = Application.Calculation

    SpeedUp True

    'code here ...

    'by giving the second argument the initial "calculation" state is restored 'otherwise it is set to 'xlCalculationAutomatic' SpeedUp False, xlCalcEnd Sub

    While these can largely be considered "enhancements" for regular Public Sub procedures, disabling eventhandling with Application.EnableEvents = False should be considered mandatory for Worksheet_Change andWorkbook_SheetChange private event macros that change values on one or more worksheets. Failure to disableevent triggers will cause the event macro to recursively run on top of itself when a value changes and can lead to a"frozen" workbook. Remember to turn events back on before leaving the event macro, possibly through a "safeexit" error handler.

    https://fastexcel.wordpress.com/2011/05/25/writing-efficient-vba-udfs-part-1/https://fastexcel.wordpress.com/page/2/?s=writing+efficienthttps://blogs.office.com/2009/03/12/excel-vba-performance-coding-best-practices/https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 34

    Option Explicit

    Private Sub Worksheet_Change(ByVal Target As Range) If Not Intersect(Target, Range("A:A")) Is Nothing Then On Error GoTo bm_Safe_Exit Application.EnableEvents = False 'code that may change a value on the worksheet goes here End Ifbm_Safe_Exit: Application.EnableEvents = TrueEnd Sub

    One caveat: While disabling these settings will improve run time, they may make debugging your application muchmore difficult. If your code is not functioning correctly, comment out the SpeedUp True call until you figure out theproblem.

    This is particularly important if you are writing to cells in a worksheet and then reading back in calculated resultsfrom worksheet functions since the xlCalculationManual prevents the workbook from calculating. To get aroundthis without disabling SpeedUp, you may want to include Application.Calculate to run a calculation at specificpoints.

    NOTE: Since these are properties of the Application itself, you need to ensure that they are enabled again beforeyour macro exits. This makes it particularly important to use error handlers and to avoid multiple exit points (i.e.End or Unload Me).

    With error handling:

    Public Sub SomeMacro() 'store the initial "calculation" state Dim xlCalc As XlCalculation xlCalc = Application.Calculation

    On Error GoTo Handler SpeedUp True 'code here ... i = 1 / 0CleanExit: SpeedUp False, xlCalc Exit SubHandler: 'handle error Resume CleanExitEnd Sub

    Section 5.4: Use VB constants when availableIf MsgBox("Click OK") = vbOK Then

    can be used in place of

    If MsgBox("Click OK") = 1 Then

    in order to improve readability.

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 35

    Use Object Browser to find available VB constants. View → Object Browser or F2 from VB Editor.

    Enter class to search

    View members available

    Section 5.5: Avoid using SELECT or ACTIVATEIt is very rare that you'll ever want to use SELECT or Activate in your code, but some Excel methods do require aworksheet or workbook to be activated before they'll work as expected.

    If you're just starting to learn VBA, you'll often be suggested to record your actions using the macro recorder, thengo look at the code. For example, I recorded actions taken to enter a value in cell D3 on Sheet2, and the macro codelooks like this:

    Option ExplicitSub Macro1()

    https://i.stack.imgur.com/VXZD4.pnghttps://i.stack.imgur.com/tBix3.pnghttps://i.stack.imgur.com/QSQJw.pnghttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 36

    '' Macro1 Macro'

    ' Sheets("Sheet2").Select Range("D3").Select ActiveCell.FormulaR1C1 = "3.1415" '(see **note below) Range("D4").SelectEnd Sub

    Remember though, the macro recorder creates a line of code for EACH of your (user) actions. This includes clickingon the worksheet tab to select Sheet2 (Sheets("Sheet2").Select), clicking on cell D3 before entering the value(Range("D3").Select), and using the Enter key (which is effectively "selecting" the cell below the currently selectedcell: Range("D4").Select).

    There are multiple issues with using .Select here:

    The worksheet is not always specified. This happens if you don't switch worksheets while recording, andmeans that the code will yield different results for different active worksheets..Select() is slow. Even if Application.ScreenUpdating is set to False, this is an unneccessary operation tobe processed..Select() is unruly. If Application.ScreenUpdating is left to True, Excel will actually select the cells, theworksheet, the form... whatever it is you're working with. This is stressful to the eyes and really unpleasant towatch..Select() will trigger listeners. This is a bit advanced already, but unless worked around, functions likeWorksheet_SelectionChange() will be triggered.

    When you're coding in VBA, all of the "typing" actions (i.e. SELECT statements) are no longer necessary. Your codemay be reduced to a single statement to put the value in the cell:

    '--- GOODActiveWorkbook.Sheets("Sheet2").Range("D3").Value = 3.1415

    '--- BETTERDim myWB As WorkbookDim myWS As WorksheetDim myCell As Range

    Set myWB = ThisWorkbook '*** see NOTE2Set myWS = myWB.Sheets("Sheet2")Set myCell = myWS.Range("D3")

    myCell.Value = 3.1415

    (The BETTER example above shows using intermediate variables to separate different parts of the cell reference.The GOOD example will always work just fine, but can be very cumbersome in much longer code modules andmore difficult to debug if one of the references is mistyped.)

    **NOTE: the macro recorder makes many assumptions about the type of data you're entering, in this case enteringa string value as a formula to create the value. Your code doesn't have to do this and can simply assign a numericalvalue directly to the cell as shown above.

    **NOTE2: the recommended practice is to set your local workbook variable to ThisWorkbook instead ofActiveWorkbook (unless you explicitly need it). The reason is your macro will generally need/use resources inwhatever workbook the VBA code originates and will NOT look outside of that workbook -- again, unless you

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 37

    explicitly direct your code to work with another workbook. When you have multiple workbooks open in Excel, theActiveWorkbook is the one with the focus which may be different from the workbook being viewed in your VBA Editor.So you think you're executing in a one workbook when you're really referencing another. ThisWorkbook refers tothe workbook containing the code being executed.

    Section 5.6: Always define and set references to allWorkbooks and SheetsWhen working with multiple open Workbooks, each of which may have multiple Sheets, it’s safest to define and setreference to all Workbooks and Sheets.

    Don't rely on ActiveWorkbook or ActiveSheet as they might be changed by the user.

    The following code example demonstrates how to copy a range from “Raw_Data” sheet in the “Data.xlsx” workbookto “Refined_Data” sheet in the “Results.xlsx” workbook.

    The procedure also demonstrates how to copy and paste without using the SELECT method.

    Option Explicit

    Sub CopyRanges_BetweenShts()

    Dim wbSrc As Workbook Dim wbDest As Workbook Dim shtCopy As Worksheet Dim shtPaste As Worksheet ' set reference to all workbooks by name, don't rely on ActiveWorkbook Set wbSrc = Workbooks("Data.xlsx") Set wbDest = Workbooks("Results.xlsx") ' set reference to all sheets by name, don't rely on ActiveSheet Set shtCopy = wbSrc.Sheet1 '// "Raw_Data" sheet Set shtPaste = wbDest.Sheet2 '// "Refined_Data") sheet ' copy range from "Data" workbook to "Results" workbook without using Select shtCopy.Range("A1:C10").Copy _ Destination:=shtPaste.Range("A1")

    End Sub

    Section 5.7: Use descriptive variable namingDescriptive names and structure in your code help make comments unnecessary

    Dim ductWidth As DoubleDim ductHeight As DoubleDim ductArea As Double

    ductArea = ductWidth * ductHeight

    is better than

    Dim a, w, h

    a = w * h

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 38

    This is especially helpful when you are copying data from one place to another, whether it's a cell, range, worksheet,or workbook. Help yourself by using names such as these:

    Dim myWB As WorkbookDim srcWS As WorksheetDim destWS As WorksheetDim srcData As RangeDim destData As Range

    Set myWB = ActiveWorkbookSet srcWS = myWB.Sheets("Sheet1")Set destWS = myWB.Sheets("Sheet2")Set srcData = srcWS.Range("A1:A10")Set destData = destWS.Range("B11:B20")destData = srcData

    If you declare multiple variables in one line make sure to specify a type for every variable like:

    Dim ductWidth As Double, ductHeight As Double, ductArea As Double

    The following will only declare the last variable and the first ones will remain Variant:

    Dim ductWidth, ductHeight, ductArea As Double

    Section 5.8: Document Your WorkIt's good practice to document your work for later use, especially if you are coding for a dynamic workload. Goodcomments should explain why the code is doing something, not what the code is doing.

    Function Bonus(EmployeeTitle as String) as Double If EmployeeTitle = "Sales" Then Bonus = 0 'Sales representatives receive commission instead of a bonus Else Bonus = .10 End IfEnd Function

    If your code is so obscure that it requires comments to explain what it is doing, consider rewriting it to be moreclear instead of explaining it through comments. For example, instead of:

    Sub CopySalesNumbers Dim IncludeWeekends as Boolean 'Boolean values can be evaluated as an integer, -1 for True, 0 for False. 'This is used here to adjust the range from 5 to 7 rows if including weekends. Range("A1:A" & 5 - (IncludeWeekends * 2)).Copy Range("B1").PasteSpecialEnd Sub

    Clarify the code to be easier to follow, such as:

    Sub CopySalesNumbers Dim IncludeWeekends as Boolean Dim DaysinWeek as Integer If IncludeWeekends Then DaysinWeek = 7

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 39

    Else DaysinWeek = 5 End If Range("A1:A" & DaysinWeek).Copy Range("B1").PasteSpecialEnd Sub

    Section 5.9: Error HandlingGood error handling prevents end users from seeing VBA runtime errors and helps the developer easily diagnoseand correct errors.

    There are three main methods of Error Handling in VBA, two of which should be avoided for distributed programsunless specifically required in the code.

    On Error GoTo 0 'Avoid using

    or

    On Error Resume Next 'Avoid using

    Prefer using:

    On Error GoTo 'Prefer using

    On Error GoTo 0

    If no error handling is set in your code, On Error GoTo 0 is the default error handler. In this mode, any runtimeerrors will launch the typical VBA error message, allowing you to either end the code or enter debug mode,identifying the source. While writing code, this method is the simplest and most useful, but it should always beavoided for code that is distributed to end users, as this method is very unsightly and difficult for end users tounderstand.

    On Error Resume Next

    On Error Resume Next will cause VBA to ignore any errors that are thrown at runtime for all lines following theerror call until the error handler has been changed. In very specific instances, this line can be useful, but it shouldbe avoided outside of these cases. For example, when launching a separate program from an Excel Macro, the OnError Resume Next call can be useful if you are unsure whether or not the program is already open:

    'In this example, we open an instance of Powerpoint using the On Error Resume Next callDim PPApp As PowerPoint.ApplicationDim PPPres As PowerPoint.PresentationDim PPSlide As PowerPoint.Slide

    'Open PPT if not running, otherwise select active instanceOn Error Resume NextSet PPApp = GetObject(, "PowerPoint.Application")On Error GoTo ErrHandlerIf PPApp Is Nothing Then 'Open PowerPoint Set PPApp = CreateObject("PowerPoint.Application") PPApp.Visible = TrueEnd If

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 40

    Had we not used the On Error Resume Next call and the Powerpoint application was not already open, theGetObject method would throw an error. Thus, On Error Resume Next was necessary to avoid creating twoinstances of the application.

    Note: It is also a best practice to immediately reset the error handler as soon as you no longer need the On ErrorResume Next call

    On Error GoTo

    This method of error handling is recommended for all code that is distributed to other users. This allows theprogrammer to control exactly how VBA handles an error by sending the code to the specified line. The tag can befilled with any string (including numeric strings), and will send the code to the corresponding string that is followedby a colon. Multiple error handling blocks can be used by making different calls of On Error GoTo . Thesubroutine below demonstrates the syntax of an On Error GoTo call.

    Note: It is essential that the Exit Sub line is placed above the first error handler and before every subsequent errorhandler to prevent the code from naturally progressing into the block without an error being called. Thus, it is bestpractice for function and readability to place error handlers at the end of a code block.

    Sub YourMethodName() On Error GoTo errorHandler ' Insert code here On Error GoTo secondErrorHandler

    Exit Sub 'The exit sub line is essential, as the code will otherwise 'continue running into the error handling block, likely causing an error

    errorHandler: MsgBox "Error " & Err.Number & ": " & Err.Description & " in " & _ VBE.ActiveCodePane.CodeModule, vbOKOnly, "Error" Exit Sub

    secondErrorHandler: If Err.Number = 424 Then 'Object not found error (purely for illustration) Application.ScreenUpdating = True Application.EnableEvents = True Exit Sub Else MsgBox "Error " & Err.Number & ": " & Err.Desctription Application.ScreenUpdating = True Application.EnableEvents = True Exit Sub End If Exit Sub

    End Sub

    If you exit your method with your error handling code, ensure that you clean up:

    Undo anything that is partially completedClose filesReset screen updatingReset calculation modeReset eventsReset mouse pointerCall unload method on instances of objects, that persist after the End Sub

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 41

    Reset status bar

    Section 5.10: Never Assume The WorksheetEven when all your work is directed at a single worksheet, it's still a very good practice to explicitly specify theworksheet in your code. This habit makes it much easier to expand your code later, or to lift parts (or all) of a Sub orFunction to be re-used someplace else. Many developers establish a habit of (re)using the same local variablename for a worksheet in their code, making re-use of that code even more straightforward.

    As an example, the following code is ambiguous -- but works! -- as long the developer doesn't activate or change toa different worksheet:

    Option ExplicitSub ShowTheTime() '--- displays the current time and date in cell A1 on the worksheet Cells(1, 1).Value = Now() ' don't refer to Cells without a sheet reference!End Sub

    If Sheet1 is active, then cell A1 on Sheet1 will be filled with the current date and time. But if the user changesworksheets for any reason, then the code will update whatever the worksheet is currently active. The destinationworksheet is ambiguous.

    The best practice is to always identify which worksheet to which your code refers:

    Option ExplicitSub ShowTheTime() '--- displays the current time and date in cell A1 on the worksheet Dim myWB As Workbook Set myWB = ThisWorkbook Dim timestampSH As Worksheet Set timestampSH = myWB.Sheets("Sheet1") timestampSH.Cells(1, 1).Value = Now()End Sub

    The code above is clear in identifying both the workbook and the worksheet. While it may seem like overkill,creating a good habit concerning target references will save you from future problems.

    Section 5.11: Avoid re-purposing the names of Properties orMethods as your variablesIt is generally not considered 'best practice' to re-purpose the reserved names of Properties or Methods as thename(s) of your own procedures and variables.

    Bad Form - While the following is (strictly speaking) legal, working code the re-purposing of the Find method as wellas the Row, Column and Address properties can cause problems/conflicts with name ambiguity and is just plainconfusing in general.

    Option Explicit

    Sub find() Dim row As Long, column As Long Dim find As String, address As Range find = "something" With ThisWorkbook.Worksheets("Sheet1").Cells

    https://msdn.microsoft.com/en-us/library/office/ff839746.aspxhttps://msdn.microsoft.com/en-us/library/office/ff196952.aspxhttps://msdn.microsoft.com/en-us/library/office/ff198200.aspxhttps://msdn.microsoft.com/en-us/library/office/ff837625.aspxhttps://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 42

    Set address = .SpecialCells(xlCellTypeLastCell) row = .find(what:=find, after:=address).row '< note .row not capitalized column = .find(what:=find, after:=address).column '< note .column not capitalized Debug.Print "The first 'something' is in " & .Cells(row, column).address(0, 0) End WithEnd Sub

    Good Form - With all of the reserved words renamed into close but unique approximations of the originals, anypotential naming conflicts have been avoided.

    Option Explicit

    Sub myFind() Dim rw As Long, col As Long Dim wht As String, lastCell As Range wht = "something" With ThisWorkbook.Worksheets("Sheet1").Cells Set lastCell = .SpecialCells(xlCellTypeLastCell) rw = .Find(What:=wht, After:=lastCell).Row '◄ note .Find and .Row col = .Find(What:=wht, After:=lastCell).Column '◄ .Find and .Column Debug.Print "The first 'something' is in " & .Cells(rw, col).Address(0, 0) End WithEnd Sub

    While there may come a time when you want to intentionally rewrite a standard method or property to your ownspecifications, those situations are few and far between. For the most part, stay away from reusing reserved namesfor your own constructs.

    Section 5.12: Avoid using ActiveCell or ActiveSheet in ExcelUsing ActiveCell or ActiveSheet can be source of mistakes if (for any reason) the code is executed in the wrongplace.

    ActiveCell.Value = "Hello"'will place "Hello" in the cell that is currently selectedCells(1, 1).Value = "Hello"'will always place "Hello" in A1 of the currently selected sheet

    ActiveSheet.Cells(1, 1).Value = "Hello"'will place "Hello" in A1 of the currently selected sheetSheets("MySheetName").Cells(1, 1).Value = "Hello"'will always place "Hello" in A1 of the sheet named "MySheetName"

    The use of Active* can create problems in long running macros if your user gets bored and clicks on anotherworksheet or opens another workbook.It can create problems if your code opens or creates another workbook.It can create problems if your code uses Sheets("MyOtherSheet").Select and you've forgotten which sheetyou were on before you start reading from or writing to it.

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 43

    Section 5.13: WorksheetFunction object executes faster than aUDF equivalentVBA is compiled in run-time, which has a huge negative impact on it's performance, everything built-in will be faster,try to use them.

    As an example I'm comparing SUM and COUNTIF functions, but you can use if for anything you can solve withWorkSheetFunctions.

    A first attempt for those would be to loop through the range and process it cell by cell (using a range):

    Sub UseRange() Dim rng as Range Dim Total As Double Dim CountLessThan01 As Long Total = 0 CountLessThan01 = 0 For Each rng in Sheets(1).Range("A1:A100") Total = Total + rng.Value2 If rng.Value < 0.1 Then CountLessThan01 = CountLessThan01 + 1 End If Next rng Debug.Print Total & ", " & CountLessThan01End Sub

    One improvement can be to store the range values in an array and process that:

    Sub UseArray() Dim DataToSummarize As Variant Dim i As Long Dim Total As Double Dim CountLessThan01 As Long DataToSummarize = Sheets(1).Range("A1:A100").Value2 'faster than .Value Total = 0 CountLessThan01 = 0 For i = 1 To 100 Total = Total + DataToSummarize(i, 1) If DataToSummarize(i, 1) < 0.1 Then CountLessThan01 = CountLessThan01 + 1 End If Next i Debug.Print Total & ", " & CountLessThan01End Sub

    But instead of writing any loop you can use Application.Worksheetfunction which is very handy for executingsimple formulas:

    Sub UseWorksheetFunction() Dim Total As Double Dim CountLessThan01 As Long With Application.WorksheetFunction Total = .Sum(Sheets(1).Range("A1:A100")) CountLessThan01 = .CountIf(Sheets(1).Range("A1:A100"), "

  • GoalKicker.com – Excel® VBA Notes for Professionals 44

    Debug.Print Total & ", " & CountLessThan01End Sub

    Or, for more complex calculations you can even use Application.Evaluate:

    Sub UseEvaluate() Dim Total As Double Dim CountLessThan01 As Long With Application Total = .Evaluate("SUM(" & Sheet1.Range("A1:A100").Address( _ external:=True) & ")") CountLessThan01 = .Evaluate("COUNTIF('Sheet1'!A1:A100,""

  • GoalKicker.com – Excel® VBA Notes for Professionals 45

    Chapter 6: Loop through all Sheets inActive WorkbookSection 6.1: Retrieve all Worksheets Names in ActiveWorkbookOption Explicit

    Sub LoopAllSheets()

    Dim sht As Excel.Worksheet' declare an array of type String without committing to maximum number of membersDim sht_Name() As StringDim i As Integer

    ' get the number of worksheets in Active Workbook , and put it as the maximum number of members inthe arrayReDim sht_Name(1 To ActiveWorkbook.Worksheets.count)

    i = 1

    ' loop through all worksheets in Active WorkbookFor Each sht In ActiveWorkbook.Worksheets sht_Name(i) = sht.Name ' get the name of each worksheet and save it in the array i = i + 1Next sht

    End Sub

    Section 6.2: Loop Through all Sheets in all Files in a Folder Sub Theloopofloops()

    Dim wbk As Workbook Dim Filename As String Dim path As String Dim rCell As Range Dim rRng As Range Dim wsO As Worksheet Dim sheet As Worksheet

    path = "pathtofile(s)" & "\" Filename = Dir(path & "*.xl??") Set wsO = ThisWorkbook.Sheets("Sheet1") 'included in case you need to differentiate_ between workbooks i.e currently opened workbook vs workbook containing code

    Do While Len(Filename) > 0 DoEvents Set wbk = Workbooks.Open(path & Filename, True, True) For Each sheet In ActiveWorkbook.Worksheets 'this needs to be adjusted for specifiyingsheets. Repeat loop for each sheet so thats on a per sheet basis Set rRng = sheet.Range("a1:a1000") 'OBV needs to be changed For Each rCell In rRng.Cells If rCell "" And rCell.Value vbNullString And rCell.Value 0 Then

    'code that does stuff

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 46

    End If Next rCell Next sheet wbk.Close False Filename = Dir Loop End Sub

    https://goalkicker.com/https://goalkicker.com/https://goalkicker.com/

  • GoalKicker.com – Excel® VBA Notes for Professionals 47

    Chapter 7: Ranges and CellsSection 7.1: Ways to refer to a single cellThe simplest way to refer to a single cell on the current Excel worksheet is simply to enclose the A1 form of itsreference in square brackets:

    [a3] = "Hello!"

    Note that square brackets are just convenient syntactic sugar for the Evaluate method of the Application object,so technically, this is identical to the following code:

    Application.Evaluate("a3") = "Hello!"

    You could also call the Cells method which takes a row and a column and returns a cell reference.

    Cells(3, 1).Formula = "=A1+A2"

    Remember that whenever you pass a row and a column to Excel from VBA, the row is always first, followed by thecolumn, which is confusing because it is the opposite of the common A1 notation where the column appears first.

    In both of these examples, we did not specify a worksheet, so Excel will use the active sheet (the sheet that is infront in the user interface). You can specify the active sheet explicitly:

    ActiveSheet.Cells(3, 1).Formula = "=SUM(A1:A2)"

    Or you can provide the name of a particular sheet:

    Sheets("Sheet2").Cells(3, 1).Formula = "=SUM(A1:A2