Pustakam Library

Free Productivity learning guide

Mastering Excel VBA Macros: Intermediate to Advanced

Mastering Excel VBA Macros: Intermediate to Advanced — a free intermediate-level guide covering learn microsoft excel vba macros from scratch. Learn...

97 min read11 chaptersintermediate

What you will learn

  1. The VBA Editor and Macro Architecture
  2. VBA Syntax and Data Types
  3. Control Flow and Logic
  4. Navigating the Excel Object Model
  5. Subroutines, Functions, and Scope
  6. Arrays and Dynamic Data Structures
  7. UserForms and UI Controls
  8. Event-Driven Programming
  9. Error Handling and Debugging
  10. File I/O and External Data Integration
  11. Performance Optimization and Best Practices

1. The VBA Editor and Macro Architecture

You’ve been handed a workbook that tracks regional sales across 50 sheets. Your task: format every sheet identically—bold the headers, apply currency formatting to the revenue columns, and set the print area. Manually, this takes roughly two minutes per sheet. That’s nearly two hours of mindless clicking. You know Excel has a macro recorder, so you click "Record," perform the actions on the first sheet, and stop the recording. When you run it on the next sheet, it works perfectly. But instead of running it 49 more times, you decide to peek under the hood to see what Excel actually did. Opening the Visual Basic Editor reveals a block of text that looks vaguely like English, but heavily abbreviated. You recognize words like "Range" and "Font," but the surrounding syntax is alien. To bridge the gap between blindly recording macros and writing your own automated solutions, you need to understand the environment where VBA lives, how Excel translates your mouse clicks into code, and how the architecture of a workbook dictates where your code should reside. Configuring the Developer Tab and Navigating the VBE Before writing or recording anything, the Excel environment must be configured for development. Out of the box, Excel hides its development tools to keep the ribbon uncluttered for standard users. Enabling the Developer Tab To access macro recording and VBE shortcuts, you must enable the Developer tab: 1. Right-click anywhere on the Excel ribbon and select Customize the Ribbon. 2. In the right-hand column under "Main Tabs," check the box next to Developer. 3. Click OK. The Developer tab houses the Code group, which contains your primary entry points: Visual Basic (opens the VBE), Macros (manages existing macros), and Record Macro. The Visual Basic Editor (VBE) Interface Press Alt + F11 to open the VBE. Unlike the standard Excel interface, the VBE has remained largely unchanged for decades. It is a multi-pane, document-centric interface. By default, you will see several key windows: Project Explorer (Ctrl + R): This is your navigation pane. It displays a hierarchical tree of every open workbook and add-in. Each workbook is a VBAProject, containing folders for Excel Objects (the workbook itself and its worksheets), Forms, Modules, and References. Properties Window (F4): Context-sensitive window that displays the properties of whatever object is currently selected in the Project Explorer. If you select a worksheet, you can change its programmatic (Name) here. Code Window: The main canvas where you write and inspect code. Double-clicking any object in the Project Explorer opens its dedicated Code Window. Immediate Window (Ctrl + G): A versatile console used for debugging, testing single lines of code, and querying object states on the fly. If any of these windows are …

2. VBA Syntax and Data Types

The Anatomy of a VBA Statement In the previous chapter, you recorded a macro and peeked behind the curtain to see the generated code in the Code Window. That recorded macro was a literal translation of your physical actions—selecting cells, applying Format Cells, and choosing Currency. But recorded macros are rigid. They execute the exact same steps on the exact same cell ranges every time. To transition from a macro recorder to a VBA programmer, you need to write code that makes decisions, adapts to different data sizes, and processes information dynamically. This requires a firm grasp of VBA syntax—the rules that govern how you write instructions the compiler can understand. At its core, a VBA macro is a sequence of statements. A statement is a single, complete instruction. When you press F5 to run a macro, VBA executes these statements sequentially, line by line. Consider this fundamental statement: This is an assignment statement. It instructs VBA to take the value on the right side of the equals sign (100) and assign it to the property on the left side (Range("A1").Value). Notice the syntax rules at play: - The object (Range) is followed by parentheses containing the argument "A1". - The property (.Value) is appended to the object using a dot operator. - The equals sign (=) acts as the assignment operator, not a statement of mathematical equality. - The line ends without a semicolon or terminator. In VBA, the end of a line signifies the end of a statement. If you need to write a very long statement, you can break it across multiple lines using the line continuation character, an underscore (), preceded by a space: While recording macros taught you how to manipulate the Excel interface, writing assignment statements requires you to manipulate data. And to manipulate data efficiently, you must store it in variables. Explicit vs. Implicit Variable Declaration A variable is a named storage location in your computer’s memory that holds data while your macro runs. You can think of it as a container. In VBA, you can create a variable implicitly simply by assigning a value to a name: VBA will happily create EmployeeName on the fly. However, this practice—known as implicit declaration—is a notorious source of bugs. If you later misspell the variable name as EmployeName, VBA will create a brand-new, empty variable instead of throwing an error, and your macro will silently fail. To prevent this, you should enforce explicit declaration by placing Option Explicit at the very top of your Standard Module. With Option Explicit enabled, VBA requires you to declare every variable using the Dim (Dimension) statement before you can use it. If you misspell EmployeeName, the compiler will catch …

3. Control Flow and Logic

You recorded a macro to format a financial report. It applies a currency format, bolds the headers, and sets the column widths. It works perfectly—until the finance team sends a report where the totals are already bolded, or the data contains text instead of numbers. The macro blindly executes its literal translations, overwriting data and formatting things that shouldn’t be touched. The issue isn't the macro recorder; it’s the absence of decision-making. Macros recorded via the Developer tab are purely linear—they execute step 1, then step 2, regardless of context. To build macros that adapt to the data they process, you need control flow: the ability to evaluate conditions, branch execution, and repeat actions dynamically. Conditional Logic: Branching Execution In VBA Syntax and Data Types, we explored how variables hold information. Control flow allows your code to inspect those variables and change its behavior based on their values. The two primary structures for this are If...Then...Else and Select Case. If...Then...Else Structures The If statement is the backbone of VBA decision-making. It evaluates a Boolean expression and executes code only if that expression is True. For quick, single-line checks, you can write an If statement without an End If: However, as an intermediate learner, you should default to the multi-line block structure for readability and maintainability, especially when adding ElseIf and Else branches: VBA evaluates these conditions sequentially. Once it finds a True condition, it executes that block and skips the rest, dropping down to the code following End If. Combining Conditions: You will frequently need to evaluate multiple conditions simultaneously. Use the And and Or operators to build compound logical expressions. Select Case Structures When you need to evaluate the same variable against multiple possible values, a long chain of ElseIf statements becomes visually cluttered. The Select Case structure is cleaner and often easier to read. Instead of repeatedly evaluating salesTotal, Select Case evaluates it once and compares it against a list of criteria. Notice the flexibility of the Case statements: Case Is =: Used for relational comparisons (greater than, less than). To: Used to define a range of values. Comma-separated lists: Allows you to match any of the specified values (e.g., Case 1000, 2000, 3000). Case Else: The catch-all for anything not explicitly tested above. Looping Structures: Executing Repetitive Tasks Conditional logic allows your code to make a decision once. Loops allow your code to make that same decision across thousands of rows of data. Instead of writing 500 lines of code to format 500 rows, you write the logic once and loop it 500 times. For...Next Loops Use a For...Next loop when you know exactly how many times the code should execute. The loop uses a counter variable …

4. Navigating the Excel Object Model

The Object Model Hierarchy You recorded a macro to format a report. It works perfectly—until you run it on a different worksheet, and suddenly it overwrites data on your summary sheet because the macro hardcoded Sheets("Sheet1"). This is the classic trap of the macro recorder. It records what you clicked, not what you meant. To transition from recording macros to writing professional VBA, you must understand the Excel Object Model: a structured hierarchy that represents every piece of Excel, from the application itself down to a single cell on a specific worksheet. Think of the Object Model as a set of Russian nesting dolls. To interact with the innermost doll (a cell), you must open the outer dolls first. At the highest level is the Application object—Excel itself. Beneath that are Workbooks (the open files), which contain Worksheets, which contain Ranges (cells). To manipulate a cell, VBA needs a path down this hierarchy. You can write this path out explicitly: This tells VBA exactly where to go. However, writing fully qualified paths for every line of code is exhausting and unnecessary. VBA allows you to omit the Application object entirely (it is always implied). Furthermore, if you don't specify a workbook or worksheet, VBA defaults to the ActiveWorkbook and ActiveSheet. Relying on the active sheet is exactly how macros accidentally overwrite data. As a rule of thumb, explicitly reference the workbook and worksheet, but omit the Application object. Referencing Cells: Range, Cells, Offset, and End The Range object is the most frequently used object in Excel VBA. It represents one or more cells, and how you reference it depends on the task at hand. The Range Property Use the Range property when you want to reference cells using standard A1 notation. It is perfect for hardcoded addresses. The Cells Property While Range uses letters, the Cells property uses row and column numbers: Cells(Row, Column). This is invaluable when you are looping through rows or columns using numeric variables (covered in Chapter 3: Control Flow and Logic). You can also combine Range and Cells to dynamically define the corners of a range: The Offset Property Rarely do you know the exact address of the cell you need. More often, you know a starting point and need to navigate relative to it. The Offset property moves a specified number of rows and columns away from a base range: Offset(RowOffset, ColumnOffset). Offset is zero-indexed relative to itself. Offset(0, 0) is the base range. Offset(1, 0) moves down one row; Offset(-1, 0) moves up one row. This is heavily used when iterating through data sets to pull adjacent values. The End Property When working with dynamic data, you frequently need to find the last …

5. Subroutines, Functions, and Scope

Sub Procedures vs. Function Procedures Up to this point, the macros you’ve written have been Sub procedures (subroutines). When you use the Developer tab’s Record Macro button, VBA generates a Sub. A Sub is an action-oriented block of code. You run it, it executes a series of statements—formatting cells, navigating the Excel Object Model, or looping through data—and then it finishes. It does not return a value. A Function procedure, on the other hand, is calculation-oriented. It accepts inputs, processes them, and returns a single resulting value. You have already interacted with built-in VBA functions like MsgBox() (which returns a user's button click) and Excel worksheet functions like SUM() or VLOOKUP(). The distinction comes down to architecture: - Subs do things. They are the verbs of your macro (e.g., FormatReport, ClearData). - Functions compute things. They are the formulas of your macro (e.g., CalculateTax, GetEmployeeName). Because functions return values, you must declare a return data type when creating them, and you assign the result back to the function's own name within the code block. Notice the line CalculateBonus = Number 0.15. To return a value from a Function, you assign the value to the function’s name. VBA handles passing that value back to whatever called the function. Passing Arguments: ByVal and ByRef To make procedures reusable, you pass them arguments—the variables or literal values they need to do their job. In VBA, you can pass arguments in two ways: By Value (ByVal) and By Reference (ByRef). Understanding the difference is critical for preventing bugs where variables mysteriously change values. Passing By Value (ByVal) When you pass an argument ByVal, VBA creates a copy of the variable and hands that copy to the procedure. If the procedure modifies the argument, it is only modifying the copy. The original variable in the calling procedure remains untouched. Passing By Reference (ByRef) When you pass an argument ByRef, VBA passes the actual memory address of the variable. If the procedure modifies the argument, it alters the original variable directly. ByRef is the default in VBA if you don't explicitly specify a passing method, which can lead to unexpected side effects if you aren't careful. A Concrete Scenario: The Payroll Bug Imagine you are writing a payroll macro. You have a base salary, and you need to calculate the salary after a one-time deduction. You pass the salary to a function to calculate the deduction. If you run ProcessPayroll, the message box will report that BaseSalary is now 4500, even though we never explicitly told ProcessPayroll to change it. The CalculatePenalty function reached back into ProcessPayroll and altered the original variable. To fix this, pass the argument ByVal: Now, BaseSalary remains 5000. When to use …

6. Arrays and Dynamic Data Structures

The Problem with Cell-by-Cell Processing Imagine you have a worksheet with 100,000 rows of sales data. Your task is to loop through every row, calculate a commission based on the sale amount, and write the result in the next column. If you use a macro that reads a cell, calculates the value, and writes it back—moving row by row—Excel will happily oblige, but it will take an agonizingly long time. The screen will flicker, the status bar will crawl, and your users will think Excel has frozen. The bottleneck isn't the math. It's the communication overhead between VBA and the Excel object model. Every time you interact with a worksheet range (like Range("A1").Value), VBA has to cross a bridge to talk to Excel, ask it for the data, wait for the response, and cross back. Doing this 100,000 times is like making 100,000 trips to the grocery store for a single ingredient each time. Arrays solve this problem by allowing you to load all the data into VBA's memory at once. You do your calculations in memory—which is nearly instantaneous—and then write the results back to the worksheet in a single trip. Fixed-Size and Multi-Dimensional Arrays An array is simply a variable that can hold multiple values, accessed using an index number. You were introduced to standard variables and data types in Chapter 2; think of an array as a row of those variables sharing a single name. Declaring Fixed-Size Arrays When you know exactly how many items your array needs to hold, you declare a fixed-size array. You use the Dim statement, but add parentheses to specify the upper and lower bounds. This creates an array that can hold exactly 12 Currency values. The index starts at 1 and ends at 12. By default, if you only provide one number, VBA assumes the array starts at index 0 (unless Option Base 1 is declared at the top of your module). Therefore, Dim Months(11) As String creates an array with 12 slots, indexed from 0 to 11. Explicitly defining the bounds (e.g., 1 To 12) is highly recommended as it makes your code self-documenting and prevents off-by-one errors. Multi-Dimensional Arrays Single-dimensional arrays are great for lists, but Excel data is inherently two-dimensional (rows and columns). VBA handles this effortlessly with multi-dimensional arrays. This creates a 2D array capable of holding 100 rows and 5 columns of data. You access a specific value by providing both indices: SalesData(10, 3) retrieves the value in the 10th row and 3rd column. VBA supports up to 60 dimensions, but in practice, you will rarely need more than two or three. A third dimension might be useful for tracking data across multiple sheets or time …

7. UserForms and UI Controls

The Limitations of InputBox Imagine building a data-entry tool for a sales team. You need to collect a customer name, a product category, a quantity, and a discount percentage. Using the InputBox function requires four sequential pop-ups, offers no drop-down lists for standardized categories, allows users to type text where numbers are required, and provides no way to prevent a 150% discount. The solution is a custom UserForm. A UserForm acts as a custom dialog box or graphical interface within Excel, allowing you to combine text boxes, drop-down lists, and buttons into a single, cohesive user experience. By building a UserForm, you control exactly what the user sees, how they navigate the inputs, and how the data is validated before a single cell on your worksheet is touched. Designing and Initializing a UserForm Creating a UserForm shifts your focus from writing code in a standard Module to designing a visual interface and writing code behind that interface. To begin, open the Visual Basic editor from the Developer tab. In the Project Explorer (Ctrl + R), right-click your VBAProject and select Insert UserForm. A blank gray canvas appears, along with the Toolbox. If the Toolbox doesn't automatically appear, select View Toolbox. The canvas is your design surface. Alongside it, the Properties Window (F4) is your primary tool for configuring the form and its controls. Configuring the Form's Properties Before adding controls, configure the form itself. In the Properties Window, adjust these key properties: - (Name): Change this to something meaningful, like frmSalesEntry. This is how you will refer to the form in your standard modules. - Caption: Change this to "Sales Entry Form". This is the text displayed in the title bar of the dialog box. Adding and Configuring Standard Controls Using the Toolbox, drag and drop controls onto your canvas. For our sales entry scenario, we will use four standard controls: Labels, Text Boxes, a Combo Box, and a Command Button. 1. Labels: Add labels next to where your inputs will go (e.g., "Customer Name:", "Quantity:", "Discount %:"). 2. Text Boxes (TextBox): Draw text boxes next to the Name, Quantity, and Discount labels. In the Properties Window, name them txtCustomer, txtQuantity, and txtDiscount. 3. Combo Box (ComboBox): Draw a combo box next to a "Category:" label. Name it cboCategory. 4. Command Button (CommandButton): Draw a button at the bottom. Name it cmdSubmit and set its Caption to "Submit". You can align these controls precisely by selecting multiple controls (hold Ctrl while clicking) and using the Format menu in the VBA editor to align tops, centers, or distribute spacing evenly. Initializing the UserForm Unlike standard macros that run top-to-bottom from a module, a UserForm requires setup code that runs the moment …

8. Event-Driven Programming

The Anatomy of an Event Handler Imagine a user opens a shared budget workbook, and before they even touch the keyboard, a macro automatically hides all the administrative sheets, locks the input cells, and navigates them directly to the summary dashboard. They type a value into the "Travel Expenses" column, and instantly, the cell turns red and a warning message appears because the value exceeds the departmental limit. This is the power of event-driven programming. Unlike the standard macros we've written in standard Modules, which require a user to click a button or run a macro from the Macros dialog, event handlers listen for specific actions performed by the user or the system and execute code in response. Where Do Events Live? In the Project Explorer, you've likely noticed that every Microsoft Excel Object in your VBAProject (usually listed as Sheet1, Sheet2, and ThisWorkbook) has its own dedicated Code Window. Events are strictly tied to these specific objects. You cannot place a worksheet event handler inside Module1; it will simply sit there and do nothing. To write code that responds to a worksheet, you must double-click that specific sheet in the Project Explorer. To write code that responds to the workbook itself, you must double-click This Workbook. The Event Procedure Signature When you open the code window for a worksheet or ThisWorkbook, you can manually type the event signature, but VBA provides a faster, error-free way. At the top of the Code Window are two dropdowns. 1. Select (General) from the left dropdown and change it to Worksheet (or Workbook). 2. VBA automatically inserts the default event procedure. For a Worksheet, this is WorksheetSelectionChange. For a Workbook, it's WorkbookOpen. Every event handler has a strict signature—a predefined name and a specific set of parameters. Notice the ByVal Target As Range parameter. VBA passes this argument to your code automatically when the event fires. Target represents the exact cell or range of cells that the user just modified. Understanding how to leverage these parameters is the core of writing effective event handlers. Worksheet-Level Events Worksheet events are the most commonly used triggers. They allow you to respond to user interactions on a specific sheet. To access them, double-click the sheet in the Project Explorer, select Worksheet from the left dropdown, and browse the available events in the right dropdown. The WorksheetChange Event The WorksheetChange event fires whenever a cell's value is altered by the user or an external link. It does not fire when a formula recalculates and updates a cell's displayed value. Let's look at a practical scenario. You have a data entry sheet where users must enter a status of "Pending", "Approved", or "Denied" in column D. You want …

9. Error Handling and Debugging

The Anatomy of a Crash You have a macro that processes 500 rows of data. It loops through an array, writes values to a worksheet, and formats the output. It works perfectly on your machine. You hand the workbook to a colleague, they click the button, and they are immediately staring at a dialog box: "Run-time error '9': Subscript out of range." Up to this point in your VBA journey, your primary strategy for fixing errors has likely been clicking "Debug" when the code crashes, reading the highlighted line, and figuring out what went wrong. This is fine for a developer actively writing code, but it is entirely unacceptable for a production macro running on a user's machine. When a macro crashes on a user's desktop, they don't see the VBA Editor; they see a cryptic error dialog and a broken spreadsheet. To build robust, professional-grade macros, you must transition from reactive debugging to proactive error handling. This means anticipating where code might fail, gracefully intercepting those failures, and logging the details so you can actually fix the root cause. Stepping Through Time: Debugging Fundamentals Before we can handle errors programmatically, we need to know how to track them down during development. When your code behaves unexpectedly but doesn't crash, logical errors are to blame. The VBA Editor provides three powerful tools for real-time inspection: Breakpoints, the Immediate Window, the Locals Window, and the Watch Window. Setting Breakpoints and Stepping A breakpoint tells VBA to pause execution immediately before executing a specific line of code. You can toggle a breakpoint by clicking in the left margin of the Code Window next to the line, or by pressing F9. When execution pauses, the line is highlighted in yellow. Once paused, you can control execution flow using stepping commands: F8 (Step Into): Executes the current line and moves to the next. If the line calls another Subroutine or Function, it steps into that procedure. Shift + F8 (Step Over): Executes the current line, but if it calls another procedure, it runs that entire procedure without pausing inside it. Ctrl + Shift + F8 (Step Out): Runs the remainder of the current procedure and pauses at the line immediately following the one that called it. F5 (Run): Resumes normal execution until the next breakpoint or the end of the macro. The Immediate Window You were briefly introduced to the Immediate Window (Ctrl + G) in earlier chapters. During a debug session, it becomes a live command prompt for your paused code. You can query variables, test object states, or execute single lines of code on the fly. To evaluate an expression, prefix it with a question mark (?). For example, if your code …

10. File I/O and External Data Integration

The Limit of the Spreadsheet Imagine receiving 50 separate Excel files every Friday afternoon, each containing a regional sales summary. Your job is to open each one, copy the data, paste it into a master workbook, and send the consolidated report to management. Doing this manually takes hours and is ripe for the kind of copy-paste errors we discussed in Error Handling and Debugging. Excel is a phenomenal tool for analyzing data, but it is fundamentally a single-document application. To break out of the single-workbook constraint and interact with the file system at large, VBA provides two primary mechanisms: the traditional VBA File I/O commands and the FileSystemObject (FSO). Manipulating Files and Folders with the FileSystemObject While VBA has legacy commands for file handling, the FileSystemObject (FSO) provides a modern, object-oriented way to interact with the computer's file system. Because FSO is part of the Windows Scripting Host library rather than the core Excel object model, it gives you a unified way to create, delete, move, and query folders and files. To use FSO, you must first enable the Microsoft Scripting Runtime library. Go to Tools References in the VBA Editor, scroll down, and check Microsoft Scripting Runtime. Once enabled, you can instantiate the FSO using the New keyword: Alternatively, if you prefer late binding (which avoids the need to set references but loses IntelliSense), you can use CreateObject: Navigating the FSO Object Hierarchy FSO operates through a clear hierarchy of objects: Drive Folder File. When working with directories, the Folder and File objects are your primary tools. Here is a practical scenario: checking if a target folder exists, and if not, creating it before you attempt to save files into it. Iterating Through Folders One of the most powerful applications of FSO is looping through a directory to process multiple files. Using the Files collection of a Folder object, you can dynamically discover files without hardcoding their names. Because we covered Arrays and Dynamic Data Structures in a previous chapter, you could easily modify the loop above to push those file paths into a dynamic array for batch processing later in the macro. Reading and Writing Sequential Text Files and CSVs While FSO is excellent for managing files from the outside, you still need a way to reach inside a file to read or write its contents. VBA provides traditional sequential file access for this purpose using three core modes: Input (read), Output (write/overwrite), and Append (write to end). The Mechanics of Sequential File I/O Sequential file access requires a file number. VBA uses the FreeFile function to grab the next available file number, ensuring you don't accidentally conflict with another open file in memory. Writing to a text …

11. Performance Optimization and Best Practices

A financial analyst writes a macro to loop through 100,000 rows of transactional data, apply currency formatting, and summarize the results. They click Run, wait three minutes, and watch Excel freeze. They force-close the application, lose their work, and assume VBA is simply too slow for large datasets. The reality is that VBA is exceptionally fast—but Excel is not. Every time a macro reads from or writes to a worksheet, it forces Excel to update its interface, recalculate formulas, and redraw the screen. A macro that interacts with the worksheet 100,000 times will crawl, regardless of how efficient the underlying VBA logic is. Performance optimization in VBA is largely about minimizing the communication between your code and the Excel application. This chapter covers how to toggle application-level settings for maximum speed, manage memory effectively, write code that scales over time, and secure your work for distribution. Application-Level Toggles for Speed When you run a macro, Excel assumes it needs to keep you visually informed of what is happening. It updates the screen, recalculates dependent formulas, and tracks page breaks. For macros that process large amounts of data, these visual updates consume massive amounts of system resources. You can temporarily disable these features using the Application object. Screen Updating The Application.ScreenUpdating property is the single most impactful setting for macro performance. When set to False, Excel stops redrawing the screen while your code executes. Without this line, every time your code writes a value to a cell, Excel visually jumps to that cell. With it, the operations happen silently in the background, often reducing execution time by orders of magnitude. Automatic Calculation If your workbook contains complex formulas, Excel will try to recalculate them every time a cell value changes. If your macro writes data across 10,000 rows, Excel might attempt 10,000 full recalculations. To prevent this, switch calculation to manual during execution. This is especially critical when integrating external data, as covered in File I/O and External Data Integration. Once your macro finishes writing all data, you can restore automatic calculation and force a single, final calculation: Status Bar Updates When ScreenUpdating is False, the user cannot see what the macro is doing, which can make long processes feel unresponsive. You can use the Excel status bar to provide custom progress updates without triggering a screen redraw. Because updating the status bar does carry a minor performance cost, avoid putting this line inside a tight loop if the progress increment is too small (e.g., updating it for every single row out of a million). The Execution Wrapper As you learned in Error Handling and Debugging, if your macro crashes before it can restore application settings, Excel remains in a disabled …

Continue learning