在不停止代码的情况下从另一个工作簿关闭工作簿

时间:2017-03-14 16:01:12

标签: excel vba excel-vba

问题:我遇到的问题是,如果我尝试从另一个工作簿中关闭工作簿,代码就会停止运行。

此问题已在几个帖子中公开,但似乎没有解决方案。

我要做的是:

  1. 我在工作簿WB1.xlsm中有一个名为" Code1"以下列方式Workbooks.Open("WB2.xlsm").RunAutoMacros(xlAutoOpen)

  2. 打开WB2
  3. Auto_Open代码格式WB2现在正在运行,我在WB2中执行我的操作(复制数据),然后目标是将这些数据粘贴到WB3中并关闭WB1,因此我按照以下步骤结束在跳转到WB3之前,WB2的Auto_Open代码:

    For Each wbk In Workbooks
      If wbk.Name = "WB1.xlsm" Then
        'wbk.Activate
        'DoEvents
        'ActiveWorkbook.Close False
         wbk.Close False
        'Application.OnTime Now + TimeValue("00:00:01"), "wbk.Close"
      End If
    Next
    Workbooks.Open(PathTo_WB3).RunAutoMacros (xlAutoOpen)
    

    问题是代码在关闭WB1后停止(上面你可以看到关闭它的不同尝试,但它们都失败了......)

  4. 问题:实际上是否可以在不看到代码停止的情况下从另一个工作簿中关闭工作簿?

3 个答案:

答案 0 :(得分:6)

  

我在工作簿WB1.xlsm中有一个名为" Code1"打开WB2

所以WB1是WB2的来电者。这是一条黄金法则:

打开文件的人应该负责关闭它。

这条黄金法则适用于编程中的许多事情,如果你从中衍生出来,那么你将会遇到许多问题。

  • 创造一个物体的人应该负责摧毁它。
  • 分配资源的人应负责解除分配资源。
  • ...

因此,您有一个名为WB1.xlsm的文件,其中包含正在运行的代码 - 就执行上下文而言,WB1为ThisWorkbook

所以ThisWorkbook这样做:

Workbooks.Open("WB2.xlsm").RunAutoMacros xlAutoOpen

假设文件成功打开,并丢弃了您真正需要的珍贵对象引用......非常糟糕。将其更改为:

With Workbooks.Open("WB2.xlsm")
    .RunAutoMacros xlAutoOpen
    .Close False
End With

现在WB2中的自动搜索可以做任何他们喜欢的事情,除了尝试关闭WB1

因此WB2的automacro会打开WB3 - 因此WB2也应该负责关闭WB3,因为它负责打开WB2.xlsm - 在Workbook_BeforeClose中,您将拥有一个List<String> names = Arrays.asList( "Success 100 - Operation worked John", "Success 100 - It also worked for Harry", "ERROR 4514 for Sally. It's always Sally."); Predicate<String> IS_ERROR = name -> name.startsWith("ERROR"); 处理程序,以确保WB3与WB2一起关闭。或者其他什么 - 它根本不清楚为什么你需要一个自动化程序来做这个,或者为什么WB1不能打开WB2和WB3。

记住你的执行上下文/ 调用堆栈(来自WB1的调用,所以直到执行返回到WB1你有待处理的东西),并记住VBA代码存在于宿主文档中 - 如果你关闭该文件,代码就不复存在了。

答案 1 :(得分:1)

这是正常行为。因为WB2的自动运行是在打开WB2的WB1中的子的上下文内。如果在WB2的自动运行中关闭WB1,则会立即终止该上下文,从而立即停止运行。

解决方法可能是隐藏WB1而不是关闭(例如将其最小化)。并运行WB1关闭作为WB2中自动运行的最后一个动作。这仍然会中止WB2的自动运行,但这并不重要,因为它是最后一次动作。

答案 2 :(得分:-1)

确保使用OnTime方法调用WB2中的代码。假设您要启动的WB2中的例程称为ContinueOpen:

Sub OpenWB2AndDoStuff()
    Workbooks.Open("WB2.xlsm")
    Application.Ontime Now, "'" & ActiveWorkbook.FullName & "'!ContinueOpen"
End Sub