Microsoft Excel Programming Recipes
Microsoft Excel is a deep program rich in features and functionality. One of the most powerful features of Excel is the ability to write programs that run "behind" your worksheets to turn Excel into a calculation-oriented development platform for creating special purpose spreadsheets which can function as applications in their own right.
Note to Co-Contributors
I'm starting this Wiki-Book because I have notes squirrelled away in various places where I record Excel-programming recipes as I discover them and figure exposing this to the general Wiki-Book community will:
- Provide free corrections and improvements to these recipes;
- May be helpful for people who are coming up the Excel programming learning curve;
I encourage the structure to be flexible: If someone has an epiphany of how better to organize this page, go for it. However the general concept of a collection of simple atomic recipes for common tasks, I think, is a good one. I suggest every recipe should include at a minimum:
- The version of Excel it is known to work on, and Operating System (if applicable);
- A little introductory text explaining what specifically the recipe aims to accomplish;
- copy-pasteable code (if applicable);
- (anything else?)
Also, I encourage improving the code-samples! These are mostly very sparse and were written mostly for the sake of jogging one's memory on how to do something. Turning these code-snippets into nicely written commented subs and functions would be a great contribution.
When writing code samples it is not necessary to enclose them in <pre>..</pre> tags, just indent them with a couple of spaces (don't forget to indent blank lines as well or there will be breaks in the display). Please also properly indent the code so that it is easily readable.
Notes to versions
A service pack (in short SP) is a collection of updates, fixes or enhancements to a software program delivered in the form of a single installable package.
A service pack can be incremental, which means it only contains the updates that were not present in the previous service packs or, it can be cumulative, which means it includes the contents of all its predecessors. In the case of Microsoft's products, an incremental update was called a service release. For example, Office 2000 must be upgraded to service release 1 (SR-1) before one can install SP2.
Notes to macros
Macro security settings are located in the Trust Center. However, if you work in an organization, your system administrator might have changed the default settings to prevent anyone from changing any settings and execute macros.
VBA Recipes
Macro Recording
A great way of learning about Excel VBA is using its macro recording function. With the function, you tell Excel to start recording, then perform various steps as if you were working without a macro recorder, and finally, tell Excel to stop recording. VBA code corresponding to what you did using Excel GUI has been recorded by Excel. While the code often cannot be meaningfully used without a modification, by starting from it and modifying it you can save a lot of time that would otherwise be spent reading the VBA documentation.
Menu paths:
- Excel 2000, 2003: Tools > Macro > Record New Macro.
- Excel 2007: View (tab) > Macros (group) > down-pointing triangle below Macros button > Record Macro
- Excel 2007: Developer (tab) > Code (group) > Record Macro
Links:
- Use Microsoft Office Excel 2007 macros to speed up work at microsoft.com
- Create a macro (Excel 2003) at microsoft.com
- Record and use Excel macros (Excel 2000) at microsoft.com
Making an XLA
- Works on: Excel 2002 SP-2, Excel 2000 SR-1
An XLA is one way to make a VBA code-library. It's basically just a normal spreadsheet(.xls file) but has its worksheets hidden. Here's how to create a new one:
- New Workbook
- Save-As ...Name it whatever
- Hit Alt-F11
- In the Project-tree, select VBAProject(whatever.xls)/ThisWorkbook
- Hit F4 to get Properties View
- Find Property IsAddin and set to True
- Hit Save
- Close Excel
- Rename whatever.xls to whatever.xla
Alternatively, you can use Save As / Excel AddIn.
Accessing the Registry
- Works on: Microsoft Excel 2002 SP-2
This recipe is for reading/writing keys local to your application -- this is to provide persistent settings for your VBA app. It does not cover arbitrary access to the Registry (i.e. looking at any key).
The VBA sub/functions are SaveSetting and GetSetting. You can type the following into the Immediate window to get a feel for how these work:
SaveSetting "MyApplicationName", "MyConfigSection", "MyKeyName", "Hello World" MsgBox GetSetting("MyApplicationName", "MyConfigSection", "MyKeyName")
If you want to iterate over all keys in a given section you can do so as follows:
Sub ShowAllKeys() Dim mySettings As Variant mySettings = GetAllSettings("MyApplicationName", "MyConfigSection") If Not IsEmpty(MySettings) Then Dim counter As Integer For counter = LBound(mySettings) To UBound(mySettings) Dim keyname As String: keyname = mySettings(counter, 0) Dim keyval As String: keyval = mySettings(counter, 1) MsgBox keyname & "=" & keyval Next End If End Sub
You can also delete a registry key as follows:
DeleteSetting "MyApplicationName", "MyConfigSection", "MyKeyName"
FYI: Excel/VBA sticks this in the following registry location:
MyComputer\HKEY_CURRENT_USER\Software\VB and VBA Program Settings\MyApplicationName\MyConfigSection
...where MyApplication and MyConfigSection are whatever you specified in your SaveSettings call.
They end up in HKEY_CURRENT_USER\Software\VB and VBA Program Settings\MyApplicationName\MyConfigSection.
Prevent Confirmation Popups In Excel
- Works on: Microsoft Excel 2002 SP-2
Make the following call from VBA:
Application.DisplayAlerts = False
Making Cells Read-Only
- Works on: Microsoft Excel 2002 SP-2
Sub ProtectMe() Range("A1:IV65536").Locked = False Range("A1").Locked = True ActiveSheet.Protect Password:="Test" End Sub
Finding Non-Empty Portion of Worksheet
A Worksheet has a maximum size of 65536 rows by 256 columns. However if you want to iterate over all cells you probably don't want to visit all of the empty ones. For this purpose the Worksheet provides the UsedRange property. For example:
ActiveSheet.UsedRange.Rows.Count
tells you how many non-empty rows are in the given worksheet. Empty rows which are inbetween the first and last used row are counted as well. Example: If a given Worksheet has entries in cells A7 and B16, used range is considered to be A7:B16, which counts for a total of 10 rows.
Using Events
- Works on: Microsoft Excel 2002 SP-2
Consider the following class definition -- Assume its a class called CMyClass:
Option Explicit Dim WithEvents mySheet As Worksheet Public Sub Init(aWS as Worksheet) Set MySheet = aWS End Sub Private Sub mySheet_SelectionChange(ByVal Target As Range) Dim MyRange As Range For Each MyRange in Target Debug.Print CStr(MyRange) Next End Sub
The main ideas here are:
- By declaring mySheet WithEvents, you're saying that CMyClass is listening to mySheet's events.
- By declaring the member sub mySheet_SelectionChange you're indicating how an instance of CMyClass should react if mySheet experiences a selection change (i.e. the user selects a new cell or range of cells); The general pattern for events is sub memberVarName_EventName(params).
- You can disconnect the eventing between the given worksheet and CMyClass by setting mySheet = nothing;
- You can create classes that throw events of your design using:
- You would declare at the top of the class: Public Event SomeNiceEventName(YourFavoriteParam1 as WhateverType, etc...),
- You could then raise that event (i.e. firing it to whatever listeners your class has) using RaiseEvent SomeNiceEvent("Some nice event happened.");
- VBA in Excel doesn't like the letters r or c used as variables. Those letters mean 'row' and 'column' elsewhere.
A little more detail is given here: [[1]]
Caveat: Uncaught Exceptions in Event-Handlers Cause VBE to Mysteriously Reset
If you are causing an uncaught exception in an event-handler you probably won't get an error popup. Instead VBE will just reset. For this reason you should make sure you're catching exceptions in all of your event handlers.
Caveat: Online-Help Typos
Some versions of Excel can have typos in the F1-help. Here's an example of a Click handler with the correct parameters:
Private Sub clicksrc_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean) MsgBox "I got a click!" End Sub
Iterating Over MultiSelected Cells
- Works on: Microsoft Excel 2002 SP-2
The following code-snippet writes "YAY!" in each cell selected by the user:
For Each Cell in Selection Cell.Value = "YAY!" Next
Exporting VBA Code
- Works on Microsoft Excel 2002 SP-2
The following code provides a very primitive routine to write serializes the VBA code in your modules to files:
Option Explicit Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) Dim objModule As Object On Error Resume Next For Each objModule In ThisWorkbook.VBProject.VBComponents DoEvents If objModule.CodeModule.CountOfLines > 0 Then objModule.Export objModule.Name & ".bas" End If Next objModule End Sub
Resize a Named Range
- Excel 2003
Note that the Resize property of Range objects does not change the size of the range object. It returns a new anonymous Range object. Easiest way to do this is to set the .Name property of the Resized range:
Sub ResizeRange(ByVal RangeName As String, _ Optional NewRowCount As Long = 0, _ Optional NewColumnCount As Long = 0) Dim oRange As Range Set oRange = Range(RangeName) If NewRowCount = 0 Then NewRowCount = oRange.Rows.Count End If If NewColumnCount = 0 Then NewColumnCount = oRange.Columns.Count End If oRange.Resize(NewRowCount, NewColumnCount).Name = RangeName End Sub
Creating a Named Range
- Excel 2002
Named Ranges allow the user to refer to a cell or range of cells by name instead of by their cell address. This name can be used in other cell formulas as well as in VBA (e.g. using the [SomeName]). There are two sorts of named ranges: Workbook Names and Worksheet Names.
To create a Workbook Name you can select the cell you want to name, pull down Insert-->Name-->Define... This will bring up the "Define Name" dialog. Here you can enter the new name for your cell.
The create a Worksheet Name you follow the same procedure but precede the name with Sheetname!, e.g. Sheet1!InitialValue to create a named-range only visible from within worksheet Sheet1.
When there are two variables with the same name, one local (Worksheet Name) and one global (Workbook Name), the spreadsheet uses the local variable.
There is no way to visualize a named range. The closest thing is to pull down again Insert-->Name-->Define..., but this method does not show if a variable is a local Worksheet Name or a global Workbook Name.
The named range can be a single cell, part of a row, part of a column or a rectangular group of cells. Each one behaves differently:
- A single cell can be referenced anywhere in the worksheet or, if it's defined globally (workbook name), anywhere in any worksheet.
- A group of cells composing part of a row can only be referenced in a parallel row. For example, if the named variable is mass and it spans the cells C5:L5, then a reference to mass' at cell E8 (say, a formula like =mass * (3e8)^2) would take the value at C8, but a reference to mass at cell M9 would return an error
- Similarly, a group of cells composing part of a column can only be referenced in a parallel column. Cells outside the range will return an error
- A group of cells that define a rectangular array of sides greater than one is only useful to be referenced in other worksheets - so, there's no point in defining them locally (worksheet name). For example, if covmatrix are the cells Sheet1!B2:D4, then if cell Sheet2!C3 has the formula =1/sqrt(covmatrix), then it will return 1/sqrt(Sheet1!C3).
Reading a File
Reading a file line by line AKA for each line of a file:
MyFileName = "C:\Users\Joe\Desktop\File.txt" FileNo = FreeFile() Open MyFileName For Input As #FileNo While Not EOF(FileNo) Line Input #FileNo, MyLine MsgBox MyLine Wend Close #FileNo
Links:
- Open at Visual Basic for Applications Reference, msdn.microsoft.com
- Close at Visual Basic for Applications Reference, msdn.microsoft.com
- Line Input at Visual Basic for Applications Reference, msdn.microsoft.com
Writing to a File
Writing to a file:
MyFileName = "C:\Users\Joe\Desktop\File.txt" FileNo = FreeFile() Open MyFileName For Output As #FileNo For I = 1 To 10 Print #FileNo, Str(I); ' The semicolon above prevents printing of a newline Next Close #FileNo
Writing the tab-separated content of the current worksheet to a text file, disregarding some of cell content formatting such as percentages:
MyFileName = "C:\Users\Joe\Desktop\File.txt" FileNo = FreeFile() Open MyFileName For Output As #FileNo RowCount = ActiveSheet.UsedRange.Cells.Rows.Count ColumnCount = ActiveSheet.UsedRange.Cells.Columns.Count For RowNo = 1 To RowCount For ColNo = 1 To ColumnCount Print #FileNo, Cells(RowNo, ColNo); ' The semicolon bars newline printing If ColNo < ColumnCount Then Print #FileNo, vbTab; End If Next If RowNo < RowCount Then Print #FileNo, vbNewline; End If Next Close #FileNo
Links:
- Open at Visual Basic for Applications Reference, msdn.microsoft.com
- Close at Visual Basic for Applications Reference, msdn.microsoft.com
- Print # at Visual Basic for Applications Reference, msdn.microsoft.com
File Existence
Testing whether a file exists:
If Dir(MyFileName) <> "" Then MsgBox "The file exists." End If
Directories
Making a directory:
MkDir "C:\Users\Joe\Desktop\TestFolder"
Removing a directory:
RmDir "C:\Users\Joe\Desktop\TestFolder"
Changing a directory:
ChDir "C:\Users"
Changing the current drive:
ChDrive "C:"
Links:
- ChDir at Visual Basic for Applications Reference, msdn.microsoft.com
- ChDrive at Visual Basic for Applications Reference, msdn.microsoft.com
- MkDir at Visual Basic for Applications Reference, msdn.microsoft.com
- RmDir at Visual Basic for Applications Reference, msdn.microsoft.com
Clipboard
Prerequisites: Accessing the clipboard from an Excel sheet requires that a reference to MSForms (Microsoft Forms Object Library) is set in the sheet. You can set the reference by adding and subsequent removing of a user form, via Insert > UserForm in a pop-up menu. To check the presence of a reference, see Tools > References menu.
Placing text on the clipboard:
Set MyClipboard = New MSForms.DataObject MyClipboard.SetText "My string" MyClipboard.PutInClipboard
Getting text from the clipboard:
Set MyClipboard = New MSForms.DataObject MyClipboard.GetFromClipboard TextContent = MyClipboard.GetText
Links:
- DataObject Class at msdn.microsoft.com; contains a section on Visual Basic, whose applicability to Excel VBA is unclear
Range
A range is a set of cells. The cells in a range do not need to be adjacent. However, the cells in a single range do need to belong to a single worksheet.
Defining a new range:
Set MyRange = Selection 'The current selection, possibly of multiple cells Set MyRange = ActiveCell 'The single active cell Set MyRange = Cells(1, 2) 'Row=1, Column=2 AKA B Set MyRange = Cells(1, 1).Offset(0, 1) '=Cells(1, 2) Set MyRange = Cells(1, 2).Offset(0, -1) '=Cells(1, 1) Set MyRange = Cells(1, 1).Offset(0, -1) 'An error Set MyRange = Range("A1:C2") 'Letters indicate columns; numbers indicate rows Set MyRange = Range("A1:A3,C1:C3") 'A discontinuous range Set MyRange = Range("B2:C2").Cells(1, 1) '=Cells(2, 2) =Range("B2") Set MyRange = Rows(1) 'An entire row Set MyRange = Columns(1) 'An entire column Set MyRange = Cells(2,2).EntireRow Set MyRange = Cells(2,2).EntireColumn Set MyRange = Range("B1:C1").EntireColumn 'Two entire columns Set MyRange = Range("B2:D4").End(xlUp) '=Cells(1, 2) =Range("B1") Set MyRange = Range("B2:D4").End(xlToLeft) '=Cells(2, 1) = Range("A2") Set MyRange = Range("B2:D4").End(xlDown) '=Cells(<last row number>, 2) Set MyRange = Range("B2:D4").End(xlToRight) '=Cells(2, <last column number>)
Iterating a range AKA for each cell in a range:
Set MyRange = Selection For Each Cell in MyRange MsgBox Cell Next
Making an union (a range subsuming both) or intersection (a range covering only cells in common) of two ranges:
Set MyRange = Range("A1:C2") Set MyRange = Union(MyRange, Range("A5:C5")) MyRange.Interior.Color = RGB(230, 230, 0) Set MyRange = Intersect(MyRange, Columns(2)) MyRange.Interior.Color = RGB(230, 100, 0)
Selecting a range:
Set MyRange = Sheets(1).Range("A1:B1,D1:E1") MyRange.Select 'Even a discontinuous range can be selected
Activating a cell:
Range("A1:B2").Select 'Affects Selection, generally of multiple cells Range("A2").Activate 'Affects ActiveCell, the single one
Links:
- Range Collection at Excel 2003 VBA Language Reference at msdn
- Referring to Multiple Ranges at Excel 2003 VBA Language Reference at msdn
- End Property at Excel 2003 VBA Language Reference at msdn
- Intersect Method at Excel 2003 VBA Language Reference at msdn
- Union Method at Excel 2003 VBA Language Reference at msdn
Worksheet
To create, access, or delete worksheets, you can use the methods of Worksheet objects. Examples follow.
Set MyNewWorksheet = Sheets.Add 'Create Set IndexedWorksheet = Sheets(1) 'Access by index Set NamedWorksheet = Sheets("Name") 'Access by name Set NamedWorksheet2 = Worksheets("Name") 'Does the same thing as the line above MyNewWorksheet.Delete Sheets("Name").Cells(1,1) = "New Value" 'Access the cells of the worksheet Sheets("Name").Cells.Clear 'Clear an entire worksheet, including formatting and cell values Sheets("Name").Columns(1).Sort key1:=Sheets("Name").Range("A1") 'Sort the first column Sheets("Name").Columns(1).Sort key1:=Sheets("Name").Range("A1"), _ order1:=xlDescending, header:=xlYes 'Use descending instead of ascending; do not sort ' the first cell, considering it a header
Links:
- Worksheet Object at Excel 2003 VBA Language Reference at mdsn
Searching
You can search for values in a sheet as follows:
Dim SoughtString As String SoughtString = "London" Set ForeignKeySheet = Sheets("CitySize") Set FoundCell = ForeignKeySheet.Columns(1).Find(SoughtString, LookAt:=xlWhole) If Not FoundCell Is Nothing Then 'The value associated with the key is in column 2 CitySize = FoundCell.Offset(0, 1) End If
If you want to have a substring match, drop "LookAt:=xlWhole" or use "LookAt:=xlPart".
Links:
Cell Formatting
You can format cells including text color, background color, font properties and border, but also formatting as a number, percent or text from VBA as follows:
Selection.Characters.Font.Color = RGB(0, 0, 255) 'Foreground color AKA text color Selection.Interior.Color = RGB(230, 230, 230) 'Background color Selection.Font.Name = "Verdana" 'Font face Selection.Font.Size = 8 'Font size Selection.Font.Bold = True Selection.Font.Italic = True Selection.Font.Underline = True 'Selection.Font.Strikethrough = True 'Selection.Borders.LineStyle = xlLineStyleNone or xlDouble or xlDashDotDot or other Selection.Borders.Weight = xlMedium ' xlHairline, xlThin, xlMedium, or xlThick 'Selection.Borders(xlEdgeBottom).Weight = xlThick ' LineStyle and Weight interact in strange ways. Selection.Borders.Color = RGB(127, 127, 0) 'Will be overridden below; applies to all borders Selection.Borders(xlEdgeBottom).Color = RGB(255, 0, 0) Selection.Borders(xlEdgeTop).Color = RGB(0, 255, 0) Selection.Borders(xlEdgeLeft).Color = RGB(0, 0, 255) Selection.Borders(xlEdgeRight).Color = RGB(0, 127, 127) Selection.Borders(xlInsideHorizontal).Color = &H7FFF00 'A hex matching RGB(127, 255, 0) Selection.Borders(xlInsideVertical).Color = RGB(255, 127, 0) Selection.NumberFormat = "General" Selection.NumberFormat = "00" 'As a number with zero decimal places, showing at least two digits Selection.NumberFormat = "0.000" 'As a number, showing three decimal places and no more Selection.NumberFormat = "0.0%" 'As a percent with one decimal place Selection.NumberFormat = "@" 'As text Selection.NumberFormat = "0.00E+00" 'As a number in scientific notation, 'the string before E formatting the significand Selection.NumberFormat = "m/d/yyyy" 'As a date; whether "/" is shown depends on locale Selection.NumberFormat = "d. mmmm yyyy hh:mm:ss" 'As date, showing the month using a word, 'also showing time Selection.ClearFormats 'Remove formatting, keeping cell content. 'Removes also the formatting set using NumberFormat.
Links:
- Font Object (Excel 2003 VBA Language Reference) at msdn
- Borders Collection (Excel 2003 VBA Language Reference) at msdn
- LineStyle Property (Excel 2003 VBA Language Reference) at msdn
- Weight Property (Excel 2003 VBA Language Reference) at msdn
- NumberFormat Property (Excel 2003 VBA Language Reference) at msdn
Color
In Excel VBA, colors are plain numbers rather than objects. Some color examples are listed in #Cell Formatting.
Finding all cells whose text color approaches green:
TargetColor = RGB(0, 255, 0) Tolerance = 200 'Extract the color components. The extraction is unneeded, but if the target 'color came from the color of a selected cell, it would be needed. TmpColor = TargetColor TargetColorRed = TmpColor Mod 256 TmpColor = TmpColor \ 256 TargetColorGreen = TmpColor Mod 256 TmpColor = TmpColor \ 256 TargetColorBlue = TmpColor Mod 256 For Each Cell In ActiveSheet.UsedRange.Cells MyColor = Cell.Characters.Font.Color 'Color is a number 'Extract the RGB components of the color Red = MyColor Mod 256 MyColor = MyColor \ 256 Green = MyColor Mod 256 MyColor = MyColor \ 256 Blue = MyColor Mod 256 'Find the distance from the target color Distance = ((Red - TargetColorRed) ^ 2 + _ (Green - TargetColorGreen) ^ 2 + _ (Blue - TargetColorBlue) ^ 2) ^ 0.5 If Distance < Tolerance Then Cell.Interior.Color = RGB(230, 230, 230) 'Mark the cell using its background color End If Next
Visibility
Hiding a row (hide a row, hide row):
Rows(2).Hidden = True 'Rows(2).Hidden = False 'Show it again
Hiding several rows at once:
Range("A1:A3").EntireRow.Hidden = True 'Hide rows 1, 2, and 3
Hiding the rows of the currently selected cells:
Selection.EntireRow.Hidden = True
Looping over rows that are visible AKA shown AKA not hidden:
For RowNo = 1 To 10 If Not Rows(RowNo).Hidden Then 'Do something on the row End If Next
Toggling the visibility of rows:
For RowNo = 1 To 10 If Not Rows(RowNo).Hidden Then Rows(RowNo).Hidden = True Else Rows(RowNo).Hidden = False End If Next
Hiding a column (hide a column, hide column):
Columns(2).Hidden = True 'Columns(2).Hidden = False 'Show it again
Hiding several columns at once:
Range("A1:C1").EntireColumn.Hidden = True 'Hide columns 1, 2, and 3
Hiding the columns of the currently selected cells:
Selection.EntireColumn.Hidden = True
Other tricks pertaining to visibility of columns work in a direct analogy to the examples for rows above.
Hyperlink
Opening or following a hyperlink (open a hyperlink, follow a hyperlink, open hyperlink, follow hyperlink):
ActiveWorkbook.FollowHyperlink "http://www.microsoft.com"
Opening the Wikipedia article for the article title found in the single active cell by opening a put-together URL:
ActiveWorkbook.FollowHyperlink "http://en.wikipedia.org/wiki/" & ActiveCell
Opening a Wikipedia article per article title in any of the currently selected cells:
For Each Cell In Selection ActiveWorkbook.FollowHyperlink "http://en.wikipedia.org/wiki/" & Cell Next
Opening a local hyperlink, with a possible pop-up asking for confirmation for security reasons:
ActiveWorkbook.FollowHyperlink "file://C:\Users\Joe Hoe\Desktop\Test.txt"
Links:
Temporary file
Getting a temporary file, with unclear robustness of the following method, which uses random numbers and tests for file existence:
Function GetTempFile(Prefix As String, Suffix As String) As String TempFolder = Environ$("tmp") Randomize While True TempFileName = TempFolder & "\" & Prefix & CStr(Int(10000000 * Rnd)) & Suffix If Dir(TempFileName) = "" Then 'Then the file does not exist GetTempFile = TempFileName Exit Function End If Wend End Function
Links:
- How To Use GetTempFileName API to Create a Unique Temporary File at Microsoft.com
Command Output
If you do not mind a popping up console window, here is a way of obtaining output of a command from Excel VBA:
Set MyShell = CreateObject("WScript.Shell") Set ExecObject = MyShell.Exec("tasklist /v") ' AllText = ExecObject.StdOut.ReadAll Do While Not ExecObject.StdOut.AtEndOfStream Line = ExecObject.StdOut.ReadLine() If InStr(Line, "AcroRd32.exe") > 0 Then 'Do something End If Loop
If having a console window popping up is not acceptable and you are okay with creating a temporary file, here is another way of obtaining output of a command from Excel VBA:
'Summary: Run "attrib" on the file in column A (1) of the row 'of the currently selected cell, writing the result into 'column B (2) of the row. 'Get temp file name TempFolder = Environ$("tmp") Randomize TempFileName = "" While TempFileName = "" TempFileNameCand = TempFolder & "\" & "mytmp" & CStr(Int(10000000 * Rnd)) & ".tmp" If Dir(TempFileNameCand) = "" Then 'Then the file does not exist TempFileName = TempFileNameCand End If Wend 'Run the command Set MyShell = CreateObject("WScript.Shell") MyCommand = "cmd /c attrib """ & Cells(Selection.Row, 1) & """ >" & TempFileName MyShell.Run MyCommand, 0, True '0 = show no window 'Although attrib has an exe file, we need to use "cmd" for the 'redirection to work. FileNo = FreeFile() Open TempFileName For Input As #FileNo While Not EOF(FileNo) Line Input #FileNo, MyLine Cells(Selection.Row, 2) = MyLine Wend Close #FileNo Kill TempFileName 'Delete the file to clean up, although not strictly necessary
Links:
- Capture output value from a shell command in VBA? at stackoverflow
Environment Tweaks
Controlling What Add-Ins Excel Opens At Startup
Microsoft Excel 2003
Configure loaded add-ins via Tools -> Add-ins. Their list is mirrored in the following Registry key, but there's no advantage in editing the Registry:
HKCU\Software\Microsoft\Office\11.0\Excel\Init Commands
Microsoft Excel 2002 SP-2
When you start Excel, it may automatically load addins (i.e. those you added from Tools -> Add-Ins). The list of add-ins that get loaded come from the following registry key:
HKCU\Software\Microsoft\Office\10.0\Excel\Options
Under this key you may find a list of string-variables:
- OPEN
- OPEN1
- OPEN2
- etc...
The values of these variables is the name of the add-in. Excel, on start-up, will attempt to load the add-in in string-variable OPEN first, then OPEN1 (if present), onward until it runs out of such string-variables. It seems like Excel will automatically renumber the keys if they are not consecutive (i.e. OPEN1, OPEN3, OPEN4 will become OPEN1, OPEN2, OPEN3).
Note also the list of add-ins presented when you do Tools -> Add-Ons is, in part, populated by the contents of the following key:
HKCU\Software\Microsoft\Office\10.0\Excel\Addin Manager
See also the following MS KB article: How to Remove Entries from Add-Ins Dialog Box.
Nuking Excel's Retained State
- Works on: Microsoft Excel 2002 SP-2
- OS: Windows XP
Excel remembers all sorts of things between runs: What addins to load, what buttons and menus to display, etc. Sometime you'll want to clean all of this stuff up and bring Excel back to its factory state.
Nuking Excel Checklist:
- Make sure the following directories are empty:
- C:\Program Files\Microsoft Office\Office10\xlstart
- C:\apps\xp\application data\Microsoft\xlstart
- Nuke the auto-open keys from the registry(as shown below);
- Nuke all .xlbs – For example check here:
- C:\apps\xp\application data\Microsoft\Excel
External links
- The Mr. Excel Forum: This is a great super-active forum where Excel power-users can often be found.
- Woody's Lounge
- J Rubin's ExcelTip.com
- OzGrid
- Express
- Chip Pearson
- Ron de Bruin
- BygSoftware.com: This site has loads of practical examples showing Excel's potential
- Aspose.Cells for .NET/Java : A component available for .NET and Java that can be used by developers to create and manipulate Excel files without the need for MS Office to be installed on the system.