How can VBA keep track of which workbooks are open?
I am writing a data mining macro that takes information from a variable number of workbooks. The user may choose what workbooks will be parsed via a userform. However, workbooks can be opened and closed while the userform is running.
So, how can my userform keep track of which workbooks are open, so that it can display them accurately.
Right now, I’m using a recursive function that calls itself with “Application.OnTime”. I don’t really like this solution for because it involves extra checks to see if the userform is still open, as well as having a delay because of whatever period the function is called at.
Final: Combined solution from answers and comments
userform code, requires a ListBox called WorkbookList, and a Textbox called FileTextBox
Private WithEvents App As Application Public Sub WorkbookList_UpdateList() WorkbookList.Clear For Each Wb In Application.Workbooks WorkbookList.AddItem Wb.name Next Wb End Sub Private Sub WorkbookList_Change() If WorkbookList.ListIndex = -1 Then Exit Sub key = WorkbookList.List(WorkbookList.ListIndex) For Each Wb In Application.Workbooks IsWorkBookOpen Wb.path If Wb.name = key Then FileTextbox.text = Wb.path Next Wb End Sub Private Sub App_WorkbookOpen(ByVal Wb As Workbook) WorkbookList_UpdateList End Sub Private Sub App_NewWorkbook(ByVal Wb As Workbook) WorkbookList_UpdateList End Sub Private Sub App_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean) Application.OnTime Now + TimeValue("00:00:01"), "WorkbookClosed" End Sub Private Sub UserForm_Initialize() Set App = Application WorkbookList_UpdateList UpdatePeriodicly End Sub
module code (put this in a vba module):
'Code From: http://www.ozgrid.com/forum/showthread.php?t=152892 Function IsUserFormLoaded(ByVal UFName As String) As Boolean Dim UForm As Object IsUserFormLoaded = False For Each UForm In VBA.UserForms If UForm.name = UFName Then IsUserFormLoaded = True Exit For End If Next End Function Public Sub WorkbookClosed() If IsUserFormLoaded("InputForm") = False Then Exit Sub InputForm.WorkbookList_UpdateList End Sub
You can use Application Events fgor this.
E.g. see cpearson.com/excel/appevent.aspx
Private WithEvents app As Excel.Application Sub Init() Set app = Application 'start capturing events End Sub Private Sub app_NewWorkbook(ByVal Wb As Workbook) Debug.Print "New" End Sub Private Sub app_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean) Debug.Print "Before close: " & Wb.Name End Sub Private Sub app_WorkbookOpen(ByVal Wb As Workbook) Debug.Print "Open: " & Wb.Name End Sub
So I think that this is an interesting script and something that might be useful for the problem your trying to solve.
Public Function IsWorkBookOpen(FileName As String) Dim ff As Long, ErrNo As Long On Error Resume Next ff = FreeFile() Open FileName For Input Lock Read As #ff Close ff ErrNo = Err On Error GoTo 0 Select Case ErrNo Case 0: IsWorkBookOpen = False 'Workbook IS NOT Case 70: IsWorkBookOpen = True 'Workbook IS open Case Else: Error ErrNo End Select End Function
You can call this by doing something like this
Ret = IsWorkBookOpen("C:\test.xlsm") If Ret = True Then 'YOUR CODE HERE