Showing posts with label excel. Show all posts
Showing posts with label excel. Show all posts

Thursday, June 5, 2008

AddIns - Creating menu options

Well, I just realized I posted my FoundRange function as part of an earlier post (maybe my Burst function). That isn't exactly fair to you now is it. So here is what I put in my ThisWorkbook object for any add-in I write (non-office2007) to create menus/submenus. The comments in the code should be enough for you, but if you have any questions about it please post a comment!

Option Explicit
'I use this as a basis for the code in ThisWorkbook of most add-ins that I make
' -MenuCaption is the menu in the worksheet menu bar to add to. Feel free to create
' your own menu, or use an existing menu (using the & symbol for the alt-key shortcut)
' For example, to add your new option(s) to the 'Tools' menu, use &Tools
' -MenuOption1 and MenuOption1MacroName are used for the individual menu options
' For additional options, follow the same guideline as MenuOption1, and make sure to
' reference your new Const'ants in the Workbook_Open and RemoveMenuOption subroutines
Private Const MenuCaption As String = "&New Menu"
Private Const MenuOption1 As String = "&Menu Option"
Private Const MenuOption1MacroName As String = "MacroName"

Private Sub Workbook_Open()
Dim CmdBar As Object, NewMenu As Object, NewSubMenu As Object

RemoveMenuOption
On Error Resume Next
Set CmdBar = Application.CommandBars("Worksheet Menu Bar")
Set NewMenu = AddMenu(CmdBar, MenuCaption)

''Use syntax like this for a sub-menu
' Set NewSubMenu = AddMenu(NewMenu, MenuName1)
' AddControl NewSubMenu, MenuOption1_1, MenuOption1_1MacroName
' AddControl NewSubMenu, MenuOption1_2, MenuOption1_2MacroName

'Otherwise use this syntax
AddControl NewMenu, MenuOption1, MenuOption1MacroName
End Sub

Private Function AddMenu(ByRef ParentMenu As Object, ByVal NewMenuName As String) As Object
Dim vNewMenu As Object
On Error Resume Next
Set vNewMenu = ParentMenu.Control(Replace(NewMenuName, "&", ""))
If vNewMenu Is Nothing Then
Set vNewMenu = ParentMenu.Controls.Add(Type:=10, Before:=ParentMenu.Controls.Count + 1 _
, Temporary:=True) '10=msoControlPopup
vNewMenu.Caption = NewMenuName
End If
Set AddMenu = vNewMenu
End Function

Private Function AddControl(ByRef NewMenu As Object, ByVal vOption As String, _
ByVal vOptionMacro As String, Optional ByVal vBeginGroup As Boolean = False) As Boolean
With NewMenu.Controls.Add
.Caption = vOption
.BeginGroup = vBeginGroup
.OnAction = "'" & ThisWorkbook.Name & "'!" & vOptionMacro
.Tag = Replace(vOption, "&", "")
End With
End Function

Private Sub Workbook_AddinUninstall()
RemoveMenuOption
If Not ThisWorkbook.Saved Then ThisWorkbook.Save
End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Not ThisWorkbook.Saved Then ThisWorkbook.Save
End Sub

Private Sub RemoveMenuOption()
Dim cBc2 As Object, cBc As Object
On Error Resume Next
For Each cBc In Application.CommandBars("Worksheet Menu Bar").Controls
If Replace(cBc.Caption, "&", "") = Replace(MenuCaption, "&", "") Then
For Each cBc2 In cBc.Controls
Select Case LCase(Replace(cBc2.Caption, "&", ""))
Case LCase(Replace(MenuOption1, "&", "")): cBc2.Delete
'add more additional Case statements here as you add more MenuOptions
End Select
Next
If cBc.Controls.Count = 0 Then cBc.Delete
Exit For
End If
Next cBc
End Sub

Miss me?

Sorry I've been away so long. As you probably know, I'm losing my job at the end of June. My department is being moved to our corporate office in Stamford, CT, and the group taking our work has been a little slow on learning how to do things (we were first told in September about our impending job loss). Now that the time is getting closer and closer, that group is realizing they have a lot more to learn than they thought (i think they thought we did nothing) and on top of me still doing my job I am now showing them how to do it as well.

Plus, with me leaving in 3 1/2 weeks, some people here in my Rochester office are trying to suck me dry of all sorts of excel and automation info. I enjoy that, but I wish I had more time in the day. But it has been fun, giving people some excel classes, both to groups as a group level (usually basic) as well as a one-on-one level. I have given a few classes here and there for people within my building before, but I am really starting to enjoy it. I wish I could do it full time! Maybe I'll play the lottery and hope to strike it big, so I can teach people for free for the rest of my life.

I know some of you think I'm crazy for that. Why not try and get paid for it? Well, for one, I just love to help people. It's why I love the forums. Beyond that, I live in a smaller market (200,000 people in the city of Rochester, 1-1.5mil in the metro area) and I don't think there is much interest. Then again, I'm probably wrong, so I'll have to look into that. Then again, if I move out of the area (looking at the DC area) I'd probably have many more opportunities. Of course an area like that probably has job openings for people like me, not for training but for automation/etc.

Either way, just wanted to give a reason why I've been gone. I did realize one nice thing about teaching people things: you learn stuff yourself. Someone showed me an XP keyboard shortcut (I'm a total keyboard guy), I believe it was alt-up-up or alt-down-down, I don't remember at the moment as I'm on a win2k machine. It wasn't anything earth shattering by any means, but always good to learn new stuff :) Another one I found was Alt-Home to go to the home page in a browser. Makes perfect sense, but oddly I never knew it existed; I use it all the time now.

I'll try and post some more tonight, I've been exhausted in the evenings but I should start trying to do more.

And for a treat for you, I'm gonna post a subroutine I wrote a while ago that I still love. It is very simple, it just returns a list of all "found" cells in a specified range as a range object. Very useful :)

Function FoundRange(ByVal vRG As Range, ByVal vVal) As Range
Dim FND As Range, FND1 As Range
Set FND = vRG.Find(vVal, LookIn:=xlValues, LookAt:=xlWhole)
If Not FND Is Nothing Then
Set FoundRange = FND
Set FND1 = FND
Set FND = vRG.FindNext(FND)
Do Until FND.Address = FND1.Address
Set FoundRange = Union(FoundRange, FND)
Set FND = vRG.FindNext(FND)
Loop
End If
End Function


Unrelated to VBA, I wanted to give an update for mario kart wii. I got it when it first came out, and played the hell out of it for a week. So much so that my wrists started hurting :( So I have only played it I think twice since then, and both times were less than a half hour. Maybe I'll buy a gamecube controller to play it during my upcoming mini-retirement (aka: severance) to avoid further damage.

Friday, May 16, 2008

Minimize userform to system tray

During the course of any VBA developer's life, the desire to want to be able to make a form seem independent of Excel will appear. One nice way to do this is to hide the excel application, so only a userform appears, but it doesnt usually seem the same. One nice thing that can be done to improve the looks (and possible functionality) is to minimize a userform to the system tray. An actual need to do this rarely comes up, but is usually impressive anyways depending on the end user.

I would like to say for the record that I did not create this code. I found some snippets that others had written in the past, and adapted it for my example. As usual, I researched exactly what it is doing so that I can write something similar from scratch as well as help others with any problems they have doing the same. I really don't remember who wrote the initial code that I adapted this from though. If you know, please let me know so I can give them proper credit.

Anyways, this is a pretty simple concept. Create a userform (called UserForm1), and add 2 commandbuttons to it. Keep them at their default name as well. Inside the codepane for the userform, paste the following:

'******************************************************'
'**************** START USERFORM1 CODE ****************'
'******************************************************'
Option Explicit
Private Sub CommandButton1_Click()
Dim Me_hWnd As Long, Me_Icon As Long, Me_Icon_Handle As Long, IconPath As String
Me_hWnd = FindWindowd("ThunderDFrame", UserForm1.Caption)
IconPath = Application.Path & Application.PathSeparator & "excel.exe"
Me_Icon_Handle = ExtractIcond(0, IconPath, 0)
Hook Me_hWnd
AddIconToTray Me_hWnd, 0, Me_Icon_Handle, "Double Click to re-open userform"
Me.Hide
End Sub

Private Sub CommandButton2_Click()
Application.Visible = True
Unload Me
End Sub

Private Sub UserForm_Activate()
RemoveIconFromTray
Unhook
End Sub

Private Sub UserForm_Initialize()
CommandButton1.Caption = "Minimize to tray"
CommandButton2.Caption = "Close this form"
Application.Visible = False
End Sub
'******************************************************'
'***************** END USERFORM1 CODE *****************'
'******************************************************'


Then insert a new module in the same project, and paste in the following:
'******************************************************'
'***************** START MODULE CODE ******************'
'******************************************************'
Option Explicit
Declare Function SetForegroundWindow Lib "User32" (ByVal hwnd As Long) As Long
Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" ( _
ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
Declare Function CallWindowProc Lib "User32" Alias "CallWindowProcA" (ByVal _
lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam _
As Long, ByVal lParam As Long) As Long
Declare Function SetWindowLong Lib "User32" Alias "SetWindowLongA" (ByVal hwnd _
As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName _
As String, ByVal lpWindowName As String) As Long
Declare Function ExtractIcon Lib "shell32.dll" Alias "ExtractIconA" (ByVal hInst _
As Long, ByVal lpszExeFileName As String, ByVal nIconIndex As Long) As Long

Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_LBUTTONDBL = &H203
Public Const WM_RBUTTONDOWN = &H204
Public Const WM_RBUTTONUP = &H205
Public Const WM_ACTIVATEAPP = &H1C
Public Const NIF_ICON = &H2
Public Const NIF_MESSAGE = &H1
Public Const NIF_TIP = &H4
Public Const NIM_ADD = &H0
Public Const NIM_DELETE = &H2
Public Const MAX_TOOLTIP As Integer = 64
Public Const GWL_WNDPROC = (-4)

Type NOTIFYICONDATA
cbSize As Long
hwnd As Long
uID As Long
uFlags As Long
uCallbackMessage As Long
hIcon As Long
szTip As String * MAX_TOOLTIP
End Type

Public nfIconData As NOTIFYICONDATA

Private FHandle As Long
Private WndProc As Long
Private Hooking As Boolean

Public Sub Hook(Lwnd As Long)
If Hooking = False Then
FHandle = Lwnd
WndProc = SetWindowLong(Lwnd, GWL_WNDPROC, AddressOf WindowProc)
Hooking = True
End If
End Sub

Public Sub Unhook()
If Hooking = True Then
SetWindowLong FHandle, GWL_WNDPROC, WndProc
Hooking = False
End If
End Sub

Public Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam _
As Long, ByVal lParam As Long) As Long
If Hooking Then
If lParam = WM_LBUTTONDBL Then
UserForm1.Show 1
WindowProc = True
' Unhook
Exit Function
End If
WindowProc = CallWindowProc(WndProc, hw, uMsg, wParam, lParam)
End If
End Function

Public Sub RemoveIconFromTray()
Shell_NotifyIcon NIM_DELETE, nfIconData
End Sub

Public Sub AddIconToTray(MeHwnd As Long, MeIcon As Long, MeIconHandle As Long, _
Tip As String)
With nfIconData
.hwnd = MeHwnd
.uID = MeIcon
.uFlags = NIF_ICON Or NIF_MESSAGE Or NIF_TIP
.uCallbackMessage = WM_RBUTTONUP
.hIcon = MeIconHandle
.szTip = Tip & Chr$(0)
.cbSize = Len(nfIconData)
End With
Shell_NotifyIcon NIM_ADD, nfIconData
End Sub

Function FindWindowd(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
FindWindowd = FindWindow(lpClassName, lpWindowName)
End Function

Function ExtractIcond(ByVal hInst As Long, ByVal lpszExeFileName As String, ByVal _
nIconIndex As Long) As Long
ExtractIcond = ExtractIcon(hInst, lpszExeFileName, nIconIndex)
End Function

Sub ShowUserForm()
Application.Visible = False
UserForm1.Show 1
End Sub
'******************************************************'
'****************** END MODULE CODE *******************'
'******************************************************'

To try this out, simply run the ShowUserForm subroutine. Pretty cool, huh? Of course this can be quickly ported to run in other office programs as well as vb6, but since I love Excel I see no reason to generalize it for the sake of this post :)

Heroes Happen Here

So yesterday, my fair city got a visit from Microsoft during their "HEROES happen {here}" campaign. They are celebrating/marketing the recent release (and upcoming release, in SQL Server's case) of 3 new versions of their products: Visual Studio 2008, Windows Server 2008, and MS SQL Server 2008. Back in February I received an email from my MVP Lead at MS saying that the HHH tour was going around the country, and if we wanted to attend any of them to sign up and let him know so he could notify the peeps running HHH. After a quick look at the list of cities, I realized Rochester was actually included, so how could I not go? I expected to be unemployed by this point (fyi, as of now, I'm on through June 30th), but knew that I wanted to go no matter what. So I signed up, and a week later received an email confirming my registration.

Skip forward 3 months to 3 nights ago, when I realized what the date was and that I had forgotten all about it. I had no expectations of what it was going to entail, but if I could help them out in any way, it would be a good experience. I secured the day off with my supervisor, and woke up early to make it at 7am for the registration (per my confirmation).

So I get to the convention center, see a couple registration desks and also see an MS employee just inside so I asked her what I should do. I then registered/signed in, and went off to find Gail who was running it to see what was in store for me. I eventually found her (it was still early, and she looked to be getting some fine touches done), so I introduced myself and asked what I could do to help. She walks me over to a table in the "ask an expert" area with a small sign on it saying Microsoft MVP. She said she planned on having me sit there, and answering any questions people may have. I was taken a little back, as I was just an Excel MVP and have only some experience with vs2008, certainly not enough to be an expert with it. I explained that I would do whatever she thought was best, but that I didn't really feel that I would be the best person for that job. She said she had wondered about it as well, but seemed happy nonetheless to have a real mvp there. Sure, I could tell my own "hero" story of how I went from lowly office worker to the local excel guru, and eventually an MVP. But in dealing with people who either develop full time, or work in the development field of some sort, why would a VBA programmer be anything special? So I asked her what else I could do.

At first, I was brought over to relieve one of the other people running the event who was helping out with registration. After a quick explanation of how registration works, I was there for a few hours. Once that became a little less hectic I was moved to a couple other areas there, such as a Speak Your Mind video booth where attendees could record their thoughts for Microsoft to see, as well as a few tasks here and there to make things run smoothly. I had a great time, got to meet many local people in the field as well as some more people from Microsoft (based out of the Boston area). I even stepped into a session on using vs2008 with MS Office, but quickly realized the presenter wasn't showing me anything new. Most of the people in there seemed genuinely interested in what he was doing and he certainly had a good vibe with the crowd, seemed like a big hit (which did give me a little hope that my skills could be used once my current job is over).

Overall, I had a good time and I'm happy I attended. I found it interesting (at least it felt so to me) that most of the MS employees had never come across an MVP before and seemed genuinely interested in my story and the whole MVP program. They all seemed to know about it, and had a good impression of it despite not knowing much of it. It had crossed my mind (both before, as well as after, that wonderful Summit in April) that only some groups (product teams, PR, marketing) had any interest in the MVP program and that other employees either knew nothing about it or didn't think that highly of it. I would have to say that after yesterday, I was wrong. None of them seemed to ever deal with an MVP before but all showed immediate respect for me. Perhaps that contributed to my enjoyment of the day, but I think if I had just signed up to attend and didn't help out at all (which I did for about 8 hours) I would have still thoroughly enjoyed myself. If you get a chance to attend one of these, by all means do! Good learning experience (so I heard from some attendees of the sessions I did not see), good networking opportunity, and of course good swag (pens, lunch coolers, normal attendees even got free copies of the software being introduced!)

If you get the chance to see this, or any software roll-out conference, by all means do. You won't regret it!

Loop through all files within a directory

Another thing I see a lot is where someone wants to loop through a directory (and/or subfolders). There are a number of ways to do this, such as VB's Dir() method, FileSystemObject, FindFirstFile/FindNextFile APIs, even Application.FileSearch (up through excel 2003, I believe). I have done a few speed tests for various threads, and usually find Dir() to be the quickest (usually true for local disks; network shares seem to vary). Dir is also the one I go with the most, as it doesn't require and early/late binding for FSO, and needs no API declare statements.

Note that if you're working in VBScript, you will have to use FileSystemObject, as Dir() doesn't exist in VBS and APIs are more trouble than they're worth if you want to use them (you'd have to create a container class in vb to use them in vbs).

Here is an example of looping through all the files within a specific directory; my calling subroutine just sends a message box with the number of files contained, but it can obviously do much more. I'm also including a simple routine called DesktopAddress, should anyone ever want to know the desktop's location via code (I use this is many of my distributed projects at work, actually). Run the LoopThroughAllFilesInDirectory to return a filecount of files on your desktop, and change as needed!

Sub LoopThroughAllFilesInDirectory()
Dim vFiles() As String, i As Long
ReDim vFiles(1, 0)
GetFilesWithDir DesktopAddress, vFiles 'all files desktop + below
MsgBox "You have " & CStr(UBound(vFiles, 2) + 1) & " files on your desktop"
End Sub
Function DesktopAddress() As String
Dim vShell As Object, vDesktop As String
Set vShell = CreateObject("WScript.Shell")
vDesktop = vShell.SpecialFolders("Desktop")
If Right(vDesktop, 1) <> "\" Then vDesktop = vDesktop & "\"
DesktopAddress = vDesktop
Set vShell = Nothing
End Function

Function GetFilesWithDir(ByVal vPath As String, ByRef vsArray() _
As String, Optional IncludeSubfolders As Boolean = True) As Boolean
'You must send this a string array, ReDim'med to (1,0)
' (0,x) = path of file
' (1,x) = file name
Dim TempStr As String, vDirs() As String, Cnt As Long, dirCnt As Long
dirCnt = 0
If Len(vsArray(0, 0)) = 0 Then
Cnt = 0
Else
Cnt = UBound(vsArray, 2) + 1
End If
If Right(vPath, 1) <> "\" Then vPath = vPath & "\"

If IncludeSubfolders Then
On Error GoTo BadDir
TempStr = Dir(vPath, 31)
Do Until Len(TempStr) = 0
If Asc(TempStr) <> 46 Then
If GetAttr(vPath & TempStr) And vbDirectory Then
ReDim Preserve vDirs(dirCnt)
vDirs(dirCnt) = TempStr
dirCnt = dirCnt + 1
End If
BadDirGo:
End If
TempStr = Dir
SkipDir:
Loop
End If

On Error GoTo BadFile
TempStr = Dir(vPath, 15)
Do Until Len(TempStr) = 0
ReDim Preserve vsArray(1, Cnt)
vsArray(0, Cnt) = vPath
vsArray(1, Cnt) = TempStr
Cnt = Cnt + 1
TempStr = Dir
Loop
BadFileGo:
On Error GoTo 0
If dirCnt > 0 Then
For dirCnt = 0 To UBound(vDirs)
If Len(Dir(vPath & vDirs(dirCnt))) = 0 Then
GetFilesWithDir vPath & vDirs(dirCnt), vsArray
End If
Next
End If
Exit Function
BadDir:
If TempStr = "pagefile.sys" Or TempStr = "???" Then
Debug.Print "DIR: Skipping: " & vPath & TempStr
Resume BadDirGo
ElseIf Err.Number = 52 Then
Debug.Print "No read dir rights: " & vPath & TempStr
Resume SkipDir
End If
Debug.Print "Error with DIR Dir: " & Err.Number & " - " & Err.Description
Exit Function
BadFile:
If Err.Number = 52 Then
Debug.Print "No read file rights: " & vPath & TempStr
Else
Debug.Print "Error with DIR File: " & Err.Number & " - " & Err.Description
End If
Resume BadFileGo
End Function

Wednesday, May 14, 2008

Splitting a worksheet based on a column's value

One question I come across a lot is when someone has a lot of data on a single worksheet, and wants to split it out to multiple worksheets based on the value of a column. For example, if someone had the following birthday data on a worksheet, and wanted to have a sheet for each month. Assume this sample data:

SHEET NAME: Birthdays
Name Month Day
Emmy August 27
Bill July 3
Andy November 24
Bob July 27
Dana June 24


And after running a macro:
SHEET NAME: August
Name Month Day
Emmy August 27

SHEET NAME: July
Name Month Day
Bill July 3
Bob July 27

SHEET NAME: November
Name Month Day
Andy November 24

SHEET NAME: June
Name Month Day
Dana June 24


That is a simplistic example, but I see something like that frequently. The following code will do that for you, just set the column to use for the splitting-data and run.

Option Explicit
Sub SplitIntoMultipleSheetsBasedOnColumn()
Dim TheColumn As Range, ValRG As Range
Dim UniqVals() As Variant, AllVals() As Variant
Dim FirstDataRow As Long, i As Long, Cnt As Long

'Unique values in the column specified by TheColumn are given their own worksheet,
' and their entire row is copied to that worksheet
Set TheColumn = Columns("G") 'must be a single column
FirstDataRow = 2 'so that the header row(s) aren't turned into a sheet

Set ValRG = Intersect(TheColumn, TheColumn.Worksheet.UsedRange, _
TheColumn.Worksheet.Rows(FirstDataRow & ":" & TheColumn.Worksheet.Rows.Count))
If ValRG Is Nothing Then
MsgBox "No data found. Exiting."
Exit Sub
End If
ReDim UniqVals(0)
Cnt = 0
AllVals = ValRG.Value
For i = 1 To UBound(AllVals, 1)
If Not InArray(UniqVals, AllVals(i, 1)) Then
ReDim Preserve UniqVals(Cnt)
UniqVals(Cnt) = AllVals(i, 1)
Cnt = Cnt + 1
End If
Next 'i

Application.ScreenUpdating = False
For i = LBound(UniqVals) To UBound(UniqVals)
Set ValRG = FoundRange(TheColumn, UniqVals(i))
With Sheets.Add(After:=Sheets(Sheets.Count))
On Error Resume Next
.Name = ValidSheetName(UniqVals(i))
On Error GoTo 0
If FirstDataRow > 1 Then TheColumn.Worksheet.Range(TheColumn.Cells(1), _
TheColumn.Cells(FirstDataRow - 1)).EntireRow.Copy .Range("A1")
ValRG.EntireRow.Copy .Range("A" & FirstDataRow)
End With
Next 'i
Application.ScreenUpdating = True
End Sub
Private Function ValidSheetName(ByVal DesiredSheetName As String) As String
On Error Resume Next
ValidSheetName = Left(Replace(Replace(Replace(Replace(Replace(Replace(Replace( _
DesiredSheetName, ":", ""), "\", ""), "/", ""), "?", ""), "*", ""), "[", ""), _
"]", ""), 31)
End Function
Public Function InArray(ByRef vArray(), ByVal vValue) As Boolean
Dim i As Long
For i = LBound(vArray) To UBound(vArray)
If vArray(i) = vValue Then
InArray = True
Exit Function
End If
Next 'i
InArray = False
End Function
Function FoundRange(ByVal vRG As Range, ByVal vVal) As Range
Dim FND As Range, FND1 As Range
Set FND = vRG.Find(vVal, LookIn:=xlValues, LookAt:=xlWhole)
If Not FND Is Nothing Then
Set FoundRange = FND
Set FND1 = FND
Set FND = vRG.FindNext(FND)
Do Until FND.Address = FND1.Address
Set FoundRange = Union(FoundRange, FND)
Set FND = vRG.FindNext(FND)
Loop
End If
End Function


Note that you don't need to sort your sheet first, though it will make things run a bit smoother. I originally had the code go through an array containing the sheet data, but a lot of the format was being lost. This way takes slightly longer but everything stays to the new sheets. I use this for my job, and I'm sure other people can use it for theirs as well.

Tuesday, May 13, 2008

Wootoffs

Do you ever Woot? I do. If you do too, then you probably know what a Wootoff is. Ever wish you could easily know what item is up and how much is left (and be more ready when their bags of crap are available, since you have literally only seconds to buy one). Well why not use our favorite tool (Excel)! I made this for a wootoff last week Heres how you can do it:

  1. Download wootie.xla, and save it to your addins directory, usually:
    C:\Documents and Settings\your-username\Application Data\Microsoft\AddIns\
  2. Open Excel, and with a workbook open go to Tools then AddIns. If you do not see Wootie listed, then click Browse and select wootie.xla
  3. After your "Help" menu there will now be a Wootie menu. Assuming there is a wootoff, go to Start Wootoff, and you should be all set!
  • As with all my add-ins, I kept it unlocked and the source code is fully viewable/editable.
It helped me out this past wootoff, hopefully it'll help you out as well. Beware though, if you plan on actually using Excel during this time, you may want to open a new instance of Excel for Wootie so it doesn't interfere. I coded it to hide the excel application while the IE statusbar window is up, but don't worry if you forgot and think your open files are gone; they'll be back when the IE window closes. I went with IE instead of a userform so that I could easily open a new window when a bag of crap comes up (less load time if it is already open). And for the more advanced users, you can always code yourself a BOC-sniping subroutine for when they're available (the other benefit of IE--easy automation from vba)

VBA will be back for Mac Office!

Ok, those of you that know me know that I'm not a huge Mac/Apple fan. I'm not really much against them, though I don't like the 'anti-pc' tone of their commercials versus a traditional 'pro-mac' commercial. Regardless, being a huge Excel and VBA fan, I felt bad for the many mac users that bought Office 2008 only to find out VBA was gone. Now I know the reasons behind it, so I'm not going to whinge about it, but it still sucked. That move alone would have prompted me to leave my mac in the dust (if I had one), despite it being a decision on Microsoft's part rather than Apple's.

So I was very happy to read today that VBA will be back in the next version of Mac Office! The press release is really about the release of SP1, but said MS will be bringing VBA back at a yet-unspecified future date. Score one for the good guys!

Go VBA!