【问题标题】:Excel's VBA ActiveWorkbook is "Nothing" when "Enable Editing" from ProtectedView从受保护的视图中“启用编辑”时,Excel VBA ActiveWorkbook 为“无”
【发布时间】:2013-10-13 13:05:42
【问题描述】:

我有一个从电子表格函数(用户定义函数,UDF)调用的 VBA 宏。当从互联网下载电子表格并且用户已相应地设置“信任中心”设置时,电子表格将在所谓的“受保护视图”中打开。该函数将不会被调用。显示“启用编辑”按钮。 如果按下按钮,则电子表格是“受信任的”并正常重新打开,开始计算,并因此调用用户定义的函数。

但是,在该 VBA 函数中,Application.ActiveWorkbook 的值是 Nothing。这可以在调试器中验证。

由于我只需要读取电子表格的一些属性(如路径名),我可以选择检查 Application.ActiveProtectedViewWindow 的可用性,它应该引用工作簿的受保护版本。在调试器中,可以检查此对象。但是,在发行版中运行(没有调试)Application.ActiveProtectedViewWindow 的值也是Nothing

这两种行为——尤其是第一种——似乎是 Excel 2010 和 2013 中存在的错误(另请参阅 a post at the MSDN forum)。

问题:有没有办法在启用编辑后获取活动工作簿的属性?

PS:作为对 Siddharth Rout 的精彩观察的后续,“ThisWorkbook”可能会起作用:在我的情况下,宏不是打开的 Workbook 的一部分。 UDF 在 XLA 中定义。因此,ThisWorkbook 将引用 XLA。我确实需要获取 ActiveWorkbook(= 调用 UDF 的工作簿)而不是 ThisWorkbook(= 运行 UDF 的工作簿)。

重要要求:

  1. 我的函数被称为用户定义函数,即执行顺序由 Excel 更新单元格决定。

  2. 该函数不是正在打开的工作簿的一部分。它是 XLA 的一部分。

  3. 我无法向打开的工作簿添加任何代码。

【问题讨论】:

  • 工作簿是在浏览器中还是从 Excel 应用程序中打开的?我只有在浏览器中打开时才遇到这种情况。试试这个实验。在 Excel 中打开 URL。
  • 工作簿是 ZIP 文件的一部分。 zip 文件下载到 Window 7 主机。 zip 文件被解压到一个目录中。然后,Windows 7 会将文件“标记”为从 Internet 源获取,Excel 2013 将在“受保护的视图”中打开 XLS 文件。这是 Windows 7/Excel 默认行为。大多数“用户”都会以这种方式下载并打开它……(不是我,是我的用户打开文件)。

标签: excel vba


【解决方案1】:

我今天遇到了同样的问题,我在此页面上或通过搜索 Google-verse 找到的已接受答案或任何其他答案都对我不起作用。我在 Office 365 中使用 Excel 版本,我认为这是问题的根源。

在找到Microsoft Excel 2010 resource 并在旧的尝试失败周期中运行了几个小时后,我最终找到了解决方案。这是我得到的:

Option Explicit
Public WithEvents oApp As Application
Private bDeferredOpen As Boolean
Private Sub Workbook_Open()
    Set oApp = Application
End Sub
Private Sub oApp_WorkbookActivate(ByVal Wb As Workbook)
    If bDeferredOpen Then
        bDeferredOpen = False
        Call WorkbookOpenHandler(Wb)
    End If
End Sub
Private Sub oApp_WorkbookOpen(ByVal Wb As Workbook)
    Dim oProtectedViewWindow As ProtectedViewWindow
    On Error Resume Next
    'The below line will throw an error (Subscript out of range) if the workbook is not opened in protected view.
    Set oProtectedViewWindow = oApp.ProtectedViewWindows.Item(Wb.Name)
    On Error GoTo 0
    'Reset error handling
    If oProtectedViewWindow Is Nothing Then
        bDeferredOpen = False
        Call WorkbookOpenHandler(Wb)
    Else
        'Delay open actions till the workbook gets activated.
        bDeferredOpen = True
    End If
End Sub
Private Sub WorkbookOpenHandler(ByVal Wb As Workbook)
    'The actual workbook open event handler code goes here...
End Sub

2010 解决方案和我的解决方案之间的区别在于,我必须调用 Workbook_Open 并在那里显式设置 oApp 变量,因为没有该分配,当我打开文件时,oApp_WorkbookActivate 和 oApp_WorkbookOpen 函数都不会触发。

认为其他人可能会从中受益,所以我发布了它,尽管该线程的最新更新比 2 岁要好。

最好的。

【讨论】:

    【解决方案2】:

    总结: 问题可以重现,并且有一些可能的解决方法。最有希望的方法(来自聊天)是使用ActiveWindow.Parent 而不是ActiveWorkbook


    我能够复制问题。

    我试过了

    Private Sub Workbook_Open()
        MsgBox "Application.ActiveWorkbook Is Nothing = " & _
        CStr(Application.ActiveWorkbook Is Nothing)
    End Sub
    

    我得到了True

    但是,然后我尝试了这个,它给了我False

    Private Sub Workbook_Open()
        MsgBox "Application.ActiveWorkbook Is Nothing = " & _
        CStr(Application.ThisWorkbook Is Nothing)
    End Sub
    

    现在回答您的问题...

    问题:有没有办法在启用编辑后获取工作簿的属性?

    是的。使用ThisWorkbook 而不是ActiveWorkbook

    评论跟进

    退出Protected Mode 后工作簿完全加载后,您将能够访问ActiveWorkbook 对象。要对此进行测试,请将此代码放入受保护的文件中。

    Private Sub Workbook_Activate()
        MsgBox "Application.ActiveWorkbook Is Nothing = " & _
        CStr(Application.ActiveWorkbook Is Nothing)
    End Sub
    

    你会注意到你得到了一个False

    因此,一旦您的工作簿加载完毕,您的外接程序就可以使用 ActiveWorkbook 与打开的文件进行交互。

    这是另一个测试

    Private Sub Workbook_Activate()
        MsgBox ActiveWorkbook.Path
    End Sub
    

    这就是我得到的时刻,我退出Protected Mode

    聊天跟进

    使用ActiveWindow.Parent.Path 代替ActiveWorkbook.Path 可以解决问题。

    【讨论】:

    • 有趣。但是,这不是我的问题的解决方案:宏不在工作簿本身中。它在 XLA 中。 ThisWorkbook 给出了宏所在的工作簿。我确实想要活动工作簿。
    • 但是一旦打开工作簿,您应该能够从 XLA 访问工作簿。我将上面的代码CStr(Application.ActiveWorkbook Is Nothing) 放在Private Sub Workbook_Activate() 中,它给了我False :)
    • 这也很有趣。我做对了吗:您建议将 Workbook_Activate 放在 XLA(宏所在的位置)中?不是说这对于 XLA 只会被调用一次,即当它被激活时。但不是再次,当(另一个)受保护的工作表进行“启用编辑”时? (请注意,启用的工作簿根本不包含任何宏 - 因此此工作表中的 Workbook_Activate 不是选项。
    • 不,我并不是说您必须在工作簿或加载项中插入 Workbook_Activate`。我试图用Workbook_Activate 演示的是,一旦工作簿完成加载,您就可以使用ActiveWorkbook。因此,您的加载项在使用 ActiveWorkbook 时应该不会有任何困难。但是,您的 XLA 到底在做什么?如果你能给我更多的见解,那么我可以给你一个直接的答案,即如果我知道的话。
    【解决方案3】:

    尝试使用 Application.Caller.Parent.Parent 而不是 Application.Activeworkbook

    【讨论】:

    【解决方案4】:

    这不是原始问题的完整答案,而是与此相关的问题的(肮脏)解决方法。

    我需要 ActiveWorkbook 来推断工作簿路径,即 ActiveWorkbook.Path。

    使用 ActiveWorkbook.Path 的替代方法是检查Application.RecentFiles(1).Path,它是最近打开的文件的路径。在许多情况下,这将是用户刚刚“启用编辑”的工作簿。但是,当然,这种方法可能会失败:如果使用打开了另一个工作表,则启用之前打开的工作表。

    (注意:ActiveWorkbook.Path 给出了文件夹的路径,而 Application.RecentFiles(1).Path 给出了文件的完整路径,所以必须进行一些后期处理)。

    【讨论】:

    • 我不确定您为什么要采用此解决方法。查看我更新的帖子。
    【解决方案5】:

    我知道这是旧线程,但我遇到了同样的问题,我找到了解决方案;)

    绕过它的唯一方法是使用变量类型Workbook

    Dim wbk as Workbook
    Set wbk = Application.ProtectedViewWindows(index).Workbook
    

    警告:
    ActiveSheet 在活动窗口也受到保护时返回 Nothing

    Dim wsh As Worksheet
    Set wsh = wbk.Worksheets(index)
    

    【讨论】:

    • 您好,我只在 Excel 2016 中遇到此问题,您能告诉我“索引”的用途,我们是否定义?
    • @raphuket,是的,您必须传递一个数字 (index),它对应于集合中工作簿的顺序或名称,它对应于工作簿名称。看看MSDN documentation
    • 啊,那行得通。使用您给我的链接:这是有效的代码: Dim WbProtected As Workbook If Application.ProtectedViewWindows.Count > 0 Then Set WbProtected = Application.ProtectedViewWindows(2).Workbook WbProtected.Sheet2.Activate Else: Sheet2.Activate End If
    • 我很高兴能帮上忙 ;)
    【解决方案6】:

    试试这段代码吧。

    If (UCase(ActiveWorkbook.Name) = ucase("<YOUR XLA NAME WITH EXTENSION>")) Then 
        End
    End If
    Set wbObj = ActiveWorkbook
    

    第一次运行宏时,它只是结束,没有做任何事情。第二次拾取正确的文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-07
      • 2013-01-13
      相关资源
      最近更新 更多