Home » excel » excel – Closing different workbook ends code execution of current workbook

excel – Closing different workbook ends code execution of current workbook

Posted by: admin May 14, 2020 Leave a comment

Questions:

I am trying to run foo in Book1.xlsm that runs another sub, bar, in Book2.xlsm. Following is the code for both:

In Book1:

Sub foo()
    Dim oldBook As Workbook: Set oldBook = ActiveWorkbook
    Dim newBook As Workbook: Set newBook = Workbooks("Book2.xlsm")

    Application.Run "'Book2.xlsm'!Module1.bar", oldBook
End Sub

In Book2:

Sub bar(book As Workbook)
    book.Close False
    Debug.Print "Closed Workbook!"
    MsgBox "Closed workbook!"
End Sub

The execution of foo runs perfectly fine and the control is passed onto bar in Book2.xlsm. The line book.Close false runs perfectly fine (closes Book1.xlsm), but code execution stops immediately without any warning (no messages in console or popup). Shouldn’t both lines be executed in Book2.xlsm since the control was passed to bar?

I tried this by calling bar workbooks(1) (workbooks(1) = Book1.xlsm) and the entirety of the code runs perfectly fine, as expected. Shouldn’t the same happen

How do I preserve code execution in the first scenario, i.e. foo runs bar, change workbooks, close Book1.xlsm and continue execution of bar?

How to&Answers:

Reconsider who’s responsible for what. It’s not normal that a workbook is just given any random Workbook object and proceeds to Close it.

Sure you can hack around the fact that you’re essentially closing the owner of the call stack, but the root of the problem is, when you have WorkbookA responsible for doing something, and that something involves opening or creating WorkbookB, then it’s WorkbookA‘s responsibility to close WorkbookB when it’s done.

Book2 has no business closing anything. Assuming the real macro actually does something more than just closing it, then it should do its thing and then let the caller decide whether to close the workbook or leave it open; Book2!Bar is given a resource that it doesn’t own: it’s beyond its responsibility to close that resource.

Maybe this can serve as a simple illustration:

Public Sub DoSomething()
    Set t = New Thing
    UseTheThing t
    t.SomeMethod ' error 91: object reference is gone!
End Sub

Private Sub UseTheThing(ByRef t As Thing)
    t.Foobar 42
    Set t = Nothing ' not your job!
End Sub

Working around the natural order of things (caller -> callee -> back to caller) is neither recommended nor useful. Something is broken in the bigger picture – take a step back and fix the higher level instead of fighting the entire paradigm.

Answer:

You can use Application.OnTime to accomplish this task.

Book2.xlsm

Public wb As Workbook

Public Sub bar(book As Workbook)
'set the variable for the workbook we want to close - We do this because we cannot pass a workbook object
Set wb = book
'set it to call 1 second from now
Application.OnTime DateTime.DateAdd("s", 1, DateTime.Now), "CloseIt"
End Sub


Sub CloseIt()
    wb.Close False
    Debug.Print "Closed Workbook!"
    MsgBox "Closed workbook!"
End Sub