VBA 关闭的工作簿未关闭引用的 IsAddin 工作簿
Workbook Closed by VBA Doesn't Close Referenced, IsAddin Workbook
版本
Excel 2016 桌面
上下文
VBA 项目(“客户端”.xlsb)引用了另一个工作簿(“工具”菜单 >“引用”)。参考书 不是 插件,它是一个普通的 .xlsb 文件。
如果客户书仍然打开,则引用的书无法关闭:
"This workbook is currently referenced by another workbook and cannot be closed."
我渴望那种行为。
问题
如果客户端书籍被 VBA 使用 ThisWorkbook.Close
关闭,那么引用的书籍将保留在内存中——它不会像手动关闭客户端时那样自动关闭.
如何让引用的书自动关闭,当客户端的书用VBA关闭时?理想情况下,即使其他工作簿处于打开状态,该解决方案也会关闭引用的书籍。
我无法使用需要以编程方式从客户端删除引用的解决方案,因为我无法保证用户在宏安全性中对 VBA 具有可信访问权限。
假设不止一本打开的书可能引用引用的书,因此在最后一个客户端关闭之前不应关闭引用。
尝试的解决方案
AfterClose 事件: 当没有其他客户端打开时,让引用的书自行关闭。这里的挑战是在所有客户端关闭之前无法关闭引用的文件。这意味着,我们必须等待 Workbook_AfterClose 事件——不幸的是,不存在这样的 Workbook_AfterClose 事件。我试图通过拦截 Application_WorkbookDeactivate 和 Application_WorkbookActivate 事件(客户端外部)来滚动我自己的 Workbook_AfterClose 事件。到目前为止运气不好。
OnTime: 在最后一个客户端关闭 5 秒后用 OnTime 事件模拟 AfterClose 事件。但是,如果在由 VBA 和 ClientWorkbook.Close.
发起的 Workbook_Close 事件中注册,似乎不会触发 OnTime 事件。
模拟鼠标: 在客户图书的 Workbook_Close 事件中,模拟鼠标点击客户图书的前端关闭按钮。但是操纵鼠标通常不是一个好主意。此外,如果其他不相关的书籍打开,这不会关闭引用的书籍。
删除引用: 在关闭客户端之前以编程方式删除引用。但这需要对 VBA 的可信访问权限,而我没有。
这就是你所面对的
这是你正在尝试的吗?
Option Explicit
'~~> This is the name of the VBA project from the referenced workbook
Private Const ReferenceWbModule As String = "MyVBAProject"
Private Const ReferenceWb As String = "Test.xlsb"
Sub Sample()
'~~> Save the workbook (IMPORTANT)
ThisWorkbook.Save
'~~> Remove the reference
Dim RefName As String: RefName = ReferenceWbModule
Dim oRefS As Object, oRef As Object
Set oRefS = ThisWorkbook.VBProject.References
For Each oRef In oRefS
If oRef.Name = RefName Then
oRefS.Remove oRef
Exit For
End If
Next
'~~> Close the workbook
Dim wb As Workbook
Set wb = Workbooks(ReferenceWb)
wb.Close (False)
'~~> Close without saving so that next time the reference is still there
ThisWorkbook.Close (False)
End Sub
这就是现在发生的事情
注意
你必须给Programmatic access to Office VBA project
否则,当您 运行 代码时,您将收到以下错误。
感谢 ,我了解了如何在编程工作簿关闭事件中执行 OnTime。我改进了那个方法,把不干净的细节放到外部书里。
此解决方案要求客户预订调用自定义 CloseBook
过程,而不是 ThisWorkbook.Close
但这并不可怕。
客户簿
模块 1
Sub Test()
CloseBook ThisWorkbook
End Sub
备注
- 参考: 如果事件侦听器加载到参考中,那么您可以使用上面的语法——调用
CloseBook
就好像它是客户手册的内部一样。
- 插件: 如果事件侦听器是一个插件,或者只是另一个工作簿,那么您需要使用 运行 语法:
Application.Run "CloseBook", ThisWorkbook
事件监听器书籍
模块 1
Sub CloseBook(oBk As Workbook)
' This is the secret sauce.
' The OnTime procedure won't execute until this sub finishes,
' which won't happen until oBk.Close finishes.
' That's what makes this an AfterClose event.
Application.OnTime Now, "Workbook_AfterClose"
oBk.Close
End Sub
Sub Workbook_AfterClose()
' This is the AfterClose event. Put anything you want here.
If NoClients Then ThisWorkbook.Close
End Sub
(注意,NoClients
过程不在本题的讨论范围内)
版本
Excel 2016 桌面
上下文
VBA 项目(“客户端”.xlsb)引用了另一个工作簿(“工具”菜单 >“引用”)。参考书 不是 插件,它是一个普通的 .xlsb 文件。
如果客户书仍然打开,则引用的书无法关闭:
"This workbook is currently referenced by another workbook and cannot be closed."
我渴望那种行为。
问题
如果客户端书籍被 VBA 使用 ThisWorkbook.Close
关闭,那么引用的书籍将保留在内存中——它不会像手动关闭客户端时那样自动关闭.
如何让引用的书自动关闭,当客户端的书用VBA关闭时?理想情况下,即使其他工作簿处于打开状态,该解决方案也会关闭引用的书籍。
我无法使用需要以编程方式从客户端删除引用的解决方案,因为我无法保证用户在宏安全性中对 VBA 具有可信访问权限。
假设不止一本打开的书可能引用引用的书,因此在最后一个客户端关闭之前不应关闭引用。
尝试的解决方案
AfterClose 事件: 当没有其他客户端打开时,让引用的书自行关闭。这里的挑战是在所有客户端关闭之前无法关闭引用的文件。这意味着,我们必须等待 Workbook_AfterClose 事件——不幸的是,不存在这样的 Workbook_AfterClose 事件。我试图通过拦截 Application_WorkbookDeactivate 和 Application_WorkbookActivate 事件(客户端外部)来滚动我自己的 Workbook_AfterClose 事件。到目前为止运气不好。
OnTime: 在最后一个客户端关闭 5 秒后用 OnTime 事件模拟 AfterClose 事件。但是,如果在由 VBA 和 ClientWorkbook.Close.
发起的 Workbook_Close 事件中注册,似乎不会触发 OnTime 事件。模拟鼠标: 在客户图书的 Workbook_Close 事件中,模拟鼠标点击客户图书的前端关闭按钮。但是操纵鼠标通常不是一个好主意。此外,如果其他不相关的书籍打开,这不会关闭引用的书籍。
删除引用: 在关闭客户端之前以编程方式删除引用。但这需要对 VBA 的可信访问权限,而我没有。
这就是你所面对的
这是你正在尝试的吗?
Option Explicit
'~~> This is the name of the VBA project from the referenced workbook
Private Const ReferenceWbModule As String = "MyVBAProject"
Private Const ReferenceWb As String = "Test.xlsb"
Sub Sample()
'~~> Save the workbook (IMPORTANT)
ThisWorkbook.Save
'~~> Remove the reference
Dim RefName As String: RefName = ReferenceWbModule
Dim oRefS As Object, oRef As Object
Set oRefS = ThisWorkbook.VBProject.References
For Each oRef In oRefS
If oRef.Name = RefName Then
oRefS.Remove oRef
Exit For
End If
Next
'~~> Close the workbook
Dim wb As Workbook
Set wb = Workbooks(ReferenceWb)
wb.Close (False)
'~~> Close without saving so that next time the reference is still there
ThisWorkbook.Close (False)
End Sub
这就是现在发生的事情
注意
你必须给Programmatic access to Office VBA project
否则,当您 运行 代码时,您将收到以下错误。
感谢
此解决方案要求客户预订调用自定义 CloseBook
过程,而不是 ThisWorkbook.Close
但这并不可怕。
客户簿
模块 1
Sub Test()
CloseBook ThisWorkbook
End Sub
备注
- 参考: 如果事件侦听器加载到参考中,那么您可以使用上面的语法——调用
CloseBook
就好像它是客户手册的内部一样。 - 插件: 如果事件侦听器是一个插件,或者只是另一个工作簿,那么您需要使用 运行 语法:
Application.Run "CloseBook", ThisWorkbook
事件监听器书籍
模块 1
Sub CloseBook(oBk As Workbook)
' This is the secret sauce.
' The OnTime procedure won't execute until this sub finishes,
' which won't happen until oBk.Close finishes.
' That's what makes this an AfterClose event.
Application.OnTime Now, "Workbook_AfterClose"
oBk.Close
End Sub
Sub Workbook_AfterClose()
' This is the AfterClose event. Put anything you want here.
If NoClients Then ThisWorkbook.Close
End Sub
(注意,NoClients
过程不在本题的讨论范围内)