excelvba

VBA stops running if user closes VBA created (temp) workbook


What I'm Trying To Do: I would like to (all during the VBA code's runtime) be able to create a temporary workbook, potentially populate it will some data, have the user add/remove/edit the data, close (& save) the workbook to commit their work, and then have the code use this updated data in the rest of the run.

The Issue: I can get the code to create the temp file, and go into a holding pattern that lasts as long as it's open, but as soon as the user closes it the code ceases it's execution.

Code:

Sub Test()   

    ' Set up the filename & path for the temporary workbook.
    Dim Temp_Dir As String, Temp_WB_Name As String, Temp_WB_Path As String

    Temp_Dir = IIf(Environ$("tmp") <> "", Environ$("tmp"), Environ$("temp"))

    Temp_WB_Name = "temp_input_wb.xlsx"
    Temp_WB_Path = Temp_Dir & "\" & Temp_WB_Name   

    ' Create the temporary workbook
    Dim Temp_WB As Workbook

    Set Temp_WB = Workbooks.Add    

    ' Then save it to make it easier to find when the user is done withe it.
    Application.DisplayAlerts = False
    Temp_WB.SaveAs Temp_WB_Path
    Application.DisplayAlerts = True    

    ' Display a message to the user
    MsgBox ("Free to add/remove/edit data via the temp workbook; simply close when done.")

    Dim Counter As Long

    ' Wait until the user closes the workbook.
    ' N.b. The code works up to (and including) this loop; it looks indefinitely whilst the workbook is open, but then once the user closes it the code stops running instead of moving on.

    Do While WorkbookIsOpen(Temp_WB_Name)
        Counter = Counter + 1
        debug.print Counter
        DoEvents

    Loop

 

    Debug.Print "Workbook closed"

   

    ' Open the workbook back up for the code to extract the data from.

    Set Temp_WB = Workbooks.Open(Temp_WB_Path)

   

    

    ' Other code would follow.

   

End Sub

 

 

' A function that just checks if a workbook is currently open with a provided name.

Function WorkbookIsOpen(WB_Name As String) As Boolean

    Dim WB As Variant, WB_Found as Boolean
    For Each WB in Workbooks
        WB_Found = WB_Found Or (WB.Name = WB_Name)
    Next WB
    
    WorkbookIsOpen = WB_Found

End Function

Solution

  • I can get the code to create the temp file, and go into a holding pattern that lasts as long as it's open

    I doubt this: Your WorkbookIsOpen code is wrong.

    WorkbookIsOpen = (WB Is Nothing)
    

    This line will return True when the workbook is closed, and False when it is open — the complete opposite of what you wanted. As such, your code is completely skipping the Do While loop.

    WorkbookIsOpen = Not (WB Is Nothing)
    

    is the code you want. However, more importantly: while the macro is running you can't edit the workbook. Excel is "locked". If you try to close a Workbook, it will interrupt and end the Macro to do so.

    As such, I would recommend splitting your macro into two or more parts, and using Application.OnTime to check periodically. Because this frees up the execution thread until the specified time, it will allow you to edit the workbook.

    Private GlobalWbName AS String 
    
    Sub Test()
        ' Set up the filename & path for the temporary workbook.
        Dim Temp_Dir As String, Temp_WB_Name As String, Temp_WB_Path As String
        Temp_Dir = IIf(Environ$("tmp") <> "", Environ$("tmp"), Environ$("temp"))
        Temp_WB_Name = "temp_input_wb.xlsx"
        Temp_WB_Path = Temp_Dir & "\" & Temp_WB_Name
    
        ' Create the temporary workbook
        Dim Temp_WB As Workbook
        Set Temp_WB = Workbooks.Add
    
        ' Then save it to make it easier to find when the user is done withe it.
        Application.DisplayAlerts = False
        Temp_WB.SaveAs Temp_WB_Path
        Application.DisplayAlerts = True
    
        ' Display a message to the user
        MsgBox ("Free to add/remove/edit data via the temp workbook; simply close when done.", vbInformation)
    
        ' Wait until the user closes the workbook.
        ' N.b. The code works up to (and including) this loop; it looks indefinitely whilst the workbook is open, but then once the user closes it the code stops running instead of moving on.
        'Checks every 5 seconds to see if the workbook is open
        GlobalWbName = Temp_WB.Name
        Debug.Print Format(Now(), "yyyy-mm-dd hh:mm:ss") & " | Workbook opened"
        WaitUntilWorkbookCloses
    End Sub
    
    Public Sub WaitUntilWorkbookCloses()
        If WorkbookIsOpen(GlobalWbName) Then
            'Check every 5 seconds
            Application.OnTime Now()+TimeSerial(0,0,5), "WaitUntilWorkbookCloses"
            Exit Sub
        End If
        
        Debug.Print Format(Now(), "yyyy-mm-dd hh:mm:ss") & " | Workbook closed"
    
        ' Open the workbook back up for the code to extract the data from.
        Set Temp_WB = Workbooks.Open(Temp_WB_Name)
        'Set Temp_WB = Workbooks.Open(GlobalWBName, ReadOnly:=True) 'Open Workbook as "ReadOnly" instead of "Editable"
        GlobalWbName = ""
    
        ' Other code would follow.
    
    End Sub
    
    ' A function that just checks if a workbook is currently open with a provided name.
    Function WorkbookIsOpen(WB_Name As String) As Boolean
    
        Dim WB As Workbook
    
        On Error Resume Next
    
        Set WB = Workbooks(WB_Name)
    
        On Error GoTo 0
        WorkbookIsOpen = Not (WB Is Nothing) 'Fixed
    
    End Function