【问题标题】:Closing a workbook from an other one without stopping code从另一个工作簿关闭而不停止代码
【发布时间】:2017-03-15 00:37:06
【问题描述】:

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

这个问题已经在一些帖子中暴露了,但似乎没有解决方案。

我想要做什么:

  1. 我在工作簿 WB1.xlsm 中有一个名为“Code1”的代码,它通过以下方式打开 WB2 Workbooks.Open("WB2.xlsm").RunAutoMacros(xlAutoOpen)

  2. Auto_Open 代码表单 WB2 现在正在运行,我在 WB2 中执行我的操作(复制数据),然后目标是将这些数据粘贴到 WB3 中并关闭 WB1,因此我在 Auto_Open 代码末尾执行以下操作在跳入 WB3 之前从 WB2:

    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 后停止(在上面您可以看到关闭它的不同尝试,但它们都失败了......)

问题:实际上是否可以从另一个工作簿关闭工作簿而不会看到代码被停止?

【问题讨论】:

  • 如果我没记错的话,您正在关闭运行代码的工作簿?
  • 你有 code (A) 正在运行 code (B),所以当你说“整个代码”时,你是指 A 还是乙?那个代码在WB1中吗? wbk.Close 位于循环中,该循环迭代 ApplicationWorkbooks 集合中的所有工作簿,其中包括包含当前正在执行该循环的代码的工作簿(即 ThisWorkbook) - 关闭包含执行代码的文件将停止该代码,就是这样。所以请edit 澄清你的意思,我们没有看你的屏幕,也无法读心。
  • 这是正常行为。因为 WB2 的自动运行是在 WB1 中打开 WB2 的子程序的上下文中。如果您在 WB2 的自动运行中关闭 WB1,您会立即终止该上下文,从而立即停止运行。 VBA 不能多线程!
  • FWIW 一个关闭其他工作簿的 Auto_Open 宏是一个非常非常糟糕的主意。
  • 你应该重新考虑你的设计。如果我曾经打开一个 Excel 文件并关闭了我正在处理的所有其他文件,我会删除它并且不再使用它。那是恶意软件 - 不是宏。

标签: vba excel


【解决方案1】:

我在工作簿 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 的自动宏打开WB3 - 因此WB2 也应该负责关闭WB3,因为它负责打开它 - 在WB2.xlsm 中,您将拥有一个Workbook_BeforeClose 处理程序确保 WB3 与 WB2 一起关闭。或者其他什么 - 完全不清楚为什么需要自动宏来执行此操作,或者为什么 WB1 不能只打开 WB2 和 WB3。

记住您的执行上下文/调用堆栈(调用源自 WB1,因此在执行返回到 WB1 之前,您有待处理的内容),并记住 VBA 代码存在于宿主文档中 -如果您关闭该文档,代码将不复存在。

【讨论】:

  • Okeeeyyy !更有意义!不敢相信我直到现在才知道这条规则而幸存下来!谢谢你们的帮助!
  • 请注意,With 块仅捕获对象引用(并在End With 上正确丢弃它)-它仍然假定文件已成功打开。
  • 感谢您让我开心:)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-01
      • 1970-01-01
      • 2014-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-09
      相关资源
      最近更新 更多