Macros
NOTE: This page is no longer updated. Most of the topics here are now covered on other pages, or have pages of their own. However, I will leave this page intact and available. See the Topics page for a complete list of topics covered on my web site.
These Excel macros and functions were written in VBA version 5, for Microsoft Excel 97. They may or may not work properly, if at all, in previous versions of Excel.
A frequent question people have is "Can I run a macro
from a cell function? Something like
=IF(A1>10,Macro1)." The answer is no, you
cannot. However, you can use the worksheet's Change event to do something like this.
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Not Application.Intersect(Target, Range("A1")) Is Nothing Then
If Target.Value > 10 Then
MsgBox "Put Your Code Here"
End If
End If
End Sub
Clipboard
The Clipboard page describes the VBA procedures for working
with the Windows Clipboard.
This macro will close all of the workbooks open in Excel. It requires the SaveAll macro, listed later on this page.
Public Sub CloseAll()
Dim Wb As Workbook
SaveAll
For Each Wb In Workbooks
If Wb.Name <> ThisWorkbook.Name Then
Wb.Close savechanges:=True
End If
Next Wb
ThisWorkbook.Close savechanges:=True
End Sub
Closing All Inactive Workbooks
This macro will close all of the workbooks, except the active workbook, which will
remain open
active.
Public Sub CloseAllInactive()
Dim Wb As Workbook
Dim AWb As String
AWb = ActiveWorkbook.Name
SaveAll
For Each Wb In Workbooks
If Wb.Name <> AWb Then
Wb.Close savechanges:=True
End If
Next Wb
Application.StatusBar = "All Workbooks Closed."
End Sub
Date Functions In VBA
A variety of Date and Time macros and functions are listed on the Date And Time Page.
Other Date Related Procedures are described on the following pages.
For macros for deleting blank rows or duplicate rows in an range of cells, click here.
This macro will reverse the order of a range of data. You may flip data in a single row or in a single column of data (i.e., an N by 1 array or an 1 by N array). You may not select and entire row or an entire column.
Public Sub FlipSelection()
Dim Arr() As Variant
Dim Rng As Range
Dim C As Range
Dim Rw As Long
Dim Cl As Long
On Error GoTo EndMacro
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Set Rng = Selection
Rw = Selection.Rows.Count
Cl = Selection.Columns.Count
If Rw > 1 And Cl > 1 Then
MsgBox "Selection May Include Only 1 Row or 1 Column", _
vbExclamation, "Flip Selection"
Exit Sub
End If
If Rng.Cells.Count = ActiveCell.EntireRow.Cells.Count Then
MsgBox "You May Not Select An Entire Row", vbExclamation, _
"Flip Selection"
Exit Sub
End If
If Rng.Cells.Count = ActiveCell.EntireColumn.Cells.Count Then
MsgBox "You May Not Select An Entire Column", vbExclamation,
_
"Flip Selection"
Exit Sub
End If
If Rw > 1 Then
ReDim Arr(Rw)
Else
ReDim Arr(Cl)
End If
Rw = 0
For Each C In Rng
Arr(Rw) = C.Formula
Rw = Rw + 1
Next C
Rw = Rw - 1
For Each C In Rng
C.Formula = Arr(Rw)
Rw = Rw - 1
Next C
EndMacro:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
End Sub
Getting A Built-In Or Custom Document Property
See the Document Properties page for much more detail.
This macro will return the value of a custom or built-in document property. If the property does not exist, and empty string is returned.
Public Function GetProperty(p As String)
Dim S As Variant
On Error Resume Next
S = ActiveWorkbook.CustomDocumentProperties(p)
If S <> "" Then
GetProperty = S
Exit Function
End If
On Error GoTo EndMacro
GetProperty = ActiveWorkbook.BuiltinDocumentProperties(p)
Exit Function
EndMacro:
GetProperty = ""
End Function
From the Page Setup dialog, you can set up some basic headers and footers, but you're somewhat limited. With VBA, however, you can create your own custom headers and footers:
Activesheet.Pagesetup.Leftfooter = "Some Text"
In addition to Leftfooter, you can use CenterFooter, RightFooter, LeftHeader, CenterHeader,or RightHeader.
To include one of the built-in document properties in a footer (or header), use
Activesheet.Pagesetup.Leftfooter = ActiveWorkbook.Builtinproperties("Manager")
Of course, change "Manager" to the name of the property you want to include.
If you want to make the active cell appear in a special color, use the following code in the Workbook_SheetSelectionChange event of the workbook.
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object,
ByVal Target As Excel.Range)
Static OldRange As Range
On Error Resume Next
Target.Interior.ColorIndex = 6 ' yellow - change as needed
OldRange.Interior.ColorIndex = xlColorIndexNone
Set OldRange = Target
End Sub
This will change the background color of the ActiveCell to yellow anytime you select a new
cell, either with the mouse or with the arrow keys.
Download a workbook illustrating this method.
NOTE: This technique has been greatly enhanced in my RowLiner add-in. I strongly suggest you use RowLiner instead.
Playing WAV Files From VBA
This section has been replaced by the PlaySound page.
It is very simple to have your macro code play a WAV file. First, add a Windows95
API declaration at the top of your code module:
Declare Function sndPlaySound32 Lib "winmm.dll" Alias _
"sndPlaySoundA" (ByVal lpszSoundName As String, _
ByVal uFlags As Long) As Long
Then, call the function, passing it the name of the WAV file you want to play:
Call sndPlaySound32("c:\test\MySound.WAV", 0)
This macro will print all of the cell comments to Microsoft Word. The Word
application will remain
open and active. You may then save or print the cell comment document.
Make sure that
you have enabled references to Word objects, from the Tools->References menu.
Public Sub PrintCellComments()
Dim Cmt As String
Dim C As Range
Dim I As Integer
Dim WordObj As Object
Dim ws As Worksheet
Dim PrintValue As Boolean
Dim res As Integer
On Error Resume Next
Err.Number = 0
res = MsgBox("Do want to print cell values with comments?", _
vbYesNoCancel + vbQuestion, "Print Cell Comments")
Select Case res
Case vbCancel
Exit Sub
Case vbYes
PrintValue = True
Case Else
PrintValue = False
End Select
Set WordObj = GetObject(, "Word.Application")
If Err.Number = 429 Then
Set WordObj = CreateObject("Word.Application")
Err.Number = 0
End If
WordObj.Visible = True
WordObj.Documents.Add
With WordObj.Selection
.TypeText Text:="Cell Comments In Workbook: " + ActiveWorkbook.Name
.TypeParagraph
.TypeText Text:="Date: " + Format(Now(), "dd-mmm-yy hh:mm")
.TypeParagraph
.TypeParagraph
End With
For Each ws In Worksheets
For I = 1 To ws.Comments.Count
Set C = ws.Comments(I).Parent
Cmt = ws.Comments(I).Text
With WordObj.Selection
.TypeText Text:="Comment In Cell: " +
_
C.Address(False, False,
xlA1) + " on sheet: " + ws.Name
If PrintValue = True Then
.TypeText Text:="
Cell Value: " + Format(C.Value)
End If
.TypeParagraph
.TypeText Text:=Cmt
.TypeParagraph
.TypeParagraph
End With
Next I
Next ws
Set WordObj = Nothing
MsgBox "Finished Printing Comments To Word", vbInformation, _
"PrintCellComments"
End Sub
This macro will print all of the cell values and formulas to Microsoft Word. The
Word application will
remain open and active. You may then save or print the document. Make sure
that
you have enabled references to Word objects, from the Tools->References
menu.
Public Sub PrintFormulasToWord()
Dim Cnt As String
Dim C As Range
Dim WordObj As word.Application
Dim HasArr As Boolean
On Error Resume Next
Err.Number = 0
Set WordObj = GetObject(, "Word.Application")
If Err.Number = 429 Then
Set WordObj = CreateObject("Word.Application")
Err.Number = 0
End If
WordObj.Visible = True
WordObj.Documents.Add
With WordObj.Selection
.Font.Name = "Courier New"
.TypeText "Formulas In Worksheet: " + ActiveSheet.Name
.TypeParagraph
.TypeText "Cells: " +
Selection.Cells(1,1).Address(False,False,xlA1) _
& " to "
& Selection.Cells(Selection.Rows.Count, _
Selection.Columns.Count).Address(False, False, xlA1)
.TypeParagraph
.TypeParagraph
End With
For Each C In Selection
HasArr = C.HasArray
Cnt = C.Formula
If HasArr Then
Cnt = "{" + Cnt + "}"
End If
If Cnt <> "" Then
With WordObj.Selection
.Font.Bold = True
.TypeText
C.Address(False, False, xlA1) & ": "
.Font.Bold = False
.TypeText Cnt
.TypeParagraph
.TypeParagraph
End With
End If
Next C
MsgBox "Done printing formulas to Word. ", , "Print Formulas To Word"
End Sub
Returning Arrays From Functions
You can write VBA functions that return an array of values back to Excel. Click here for details.
Saving And Returning To A Location
These three macros are used to save a location and then return to that location later.
It is
useful when you need to change the Selection range during the execution of a macro, and
then
return to the original Selection range when your macro is complete.
Public Sub SaveLocation(ReturnToLoc As Boolean)
Static WB As Workbook
Static WS As Worksheet
Static R As Range
If ReturnToLoc = False Then
Set WB = ActiveWorkbook
Set WS = ActiveSheet
Set R = Selection
Else
WB.Activate
WS.Activate
R.Select
End If
End Sub
To save the current location, call SetSaveLoc.
Public Sub SetSaveLoc()
SaveLocation (False)
End Sub
To return to the saved location, call GetSaveLoc.
Public Sub GetSaveLoc()
SaveLocation (True)
End Sub
This macro will save all of the workbooks open in Excel.
Public Sub SaveAll()
Dim WB As Workbook
For Each WB In Workbooks
WB.Save
Next WB
Application.StatusBar = "All Workbooks Saved."
End Sub
If the ActiveCell is part of an array, this macro will select the entire array.
Public Sub SelectArray()
Dim Msg As String
On Error GoTo EndOfMacro
Msg = "Cell is not part of an array."
ActiveCell.CurrentArray.Select
Msg = "Array Selected."
EndOfMacro:
Application.StatusBar = Msg
End Sub
Selecting The Current Named Range
If the ActiveCell is part of a named range, this macro will select the entire named
range.
This macro requires the CellInNamedRange function, shown
first.
CellInNamedRange
Public Function CellInNamedRange(Rng As Range) As String
Dim N As Name
Dim C As Range
Dim TestRng As Range
On Error Resume Next
For Each N In ActiveWorkbook.Names
Set C = Nothing
Set TestRng = N.RefersToRange
Set C = Application.Intersect(TestRng, Rng)
If Not C Is Nothing Then
CellInNamedRange = N.Name
Exit Function
End If
Next N
CellInNamedRange = ""
End Function
SelectRange
Public Sub SelectRange()
Dim RngName As String
Dim R As Range
Set R = ActiveCell
Dim Msg As String
Msg = "Active Cell Is Not In A Named Range."
RngName = CellInNamedRange(R)
If RngName <> "" Then
Range(RngName).Select
Msg = "Range: " + RngName + " Selected."
End If
Application.StatusBar = Msg
End Sub
It is very simple to retrieve sheet names in VBA. They are stored in two collection objects in the ActiveWorkbook object: the Sheets collection and the Worksheets collection. The Sheets collection contains both worksheets and chart sheets. The Worksheets collection contains only worksheets.
To retrieve the name of the first sheet in the workbook, use
Public Function FirstSheetName()
FirstSheetName = Sheets(1).Name
End Function
To retrieve the name of the last sheet in the workbook, use
Public Function LastSheetName()
LastSheetName = Sheets(Sheets.Count).Name
End Function
You can return an array of all the sheet names with the following
Public Function AllSheetNames()
Dim Arr() As String
Dim I as Integer
Redim Arr(Sheets.Count-1)
For I = 0 To Sheets.Count - 1
Arr(i) = Sheets(I+1).Name
Next I
AllSheetNames = Arr ' return a row array
OR
AllSheetNames = Application.Worksheetfunction.Transpose(Arr)
' return a column array
End Function
See Sorting Worksheets In A Workbook for VBA code to sort worksheets by name.