如果 Excel 或 Word 已打开,ThisWorkbook Workbook_Open 无法显示用户窗体

Bad*_*ing 3 excel vba userform office365

我用的是Office365。我有一个名为 Test.xlsm 的 Excel 文件,其中包含一个名为 frmMain 的用户窗体。
在 ThisWorkbook 对象和 Workbook_Open 事件中,我有以下代码:

    Private Sub Workbook_Open()
       Worksheets("Main").Activate
       frmMain.Show
    End Sub
Run Code Online (Sandbox Code Playgroud)

它旨在每次打开 Test.xlsm 文件时启动(显示)frmMain 用户窗体。
但是,如果另一个 Excel 或 Word 文件已打开,则 frmMain 用户窗体无法启动/显示。
有没有办法让 Excel 或 Word 文件已打开,并且仍然能够启动和使用 Test.xlsm 文件及其用户窗体 frmMain ?这是Office365的问题吗?

更新:

还尝试将应用程序安全性设置为低,以防默认为 msoAutomationSecurityByUI:

Private Sub Workbook_Open()

dim frm As frmMain
Dim secAutomation As MsoAutomationSecurity

set frm = New frmMain
secAutomation = Application.AutomationSecurity

Application.AutomationSecurity = msoAutomationSecurityLow
Worksheets("Main").Activate
frmMain.Show

End Sub
Run Code Online (Sandbox Code Playgroud)

更新:

还尝试将其放在独立模块上(不在 ThisWorkbook 中):

Private Sub runForm()
   frmMain.Show
End Sub
Run Code Online (Sandbox Code Playgroud)

然后从 ThisWorkbook > Workbook_Open 事件中这样调用它:

Private Sub Workbook_Open()
   Application.OnTime VBA.Now, "name of file '!runForm.runForm"
End Sub
Run Code Online (Sandbox Code Playgroud)

在关闭所有其他 Excel 的情况下,这也会打开 Test.xlsm 和用户窗体,但是当 .xlsx 已经打开时,会出现同样的问题 - 打开文件但没有打开用户窗体。

Cri*_*use 5

打开另一个工作簿时,新打开的工作簿无法正确触发 Workbook_Open 事件。这是一个错误。

解决此问题的一种方法是利用自定义 RibbonUI 对象,以便在打开工作簿时触发事件。

设置起来并不简单,但您只需要做一次。需要3个步骤:

1)在ThisWorkbook对象中设置Friend方法在ThisWorkbook
模块 中编写以下代码:

Option Explicit

Private m_openAlreadyRan As Boolean

Friend Sub FireOpenEventIfNeeded(Optional dummyVarToMakeProcHidden As Boolean)
    If Not m_openAlreadyRan Then Workbook_Open
End Sub

Private Sub Workbook_Open()
End Sub
Run Code Online (Sandbox Code Playgroud)

请注意以下几点:
a) 需要虚拟参数来隐藏宏框中的方法( Alt+F8)
b) 该方法被声明为Friend,因此只能由该项目访问
c) 需要一个布尔变量 (m_openAlreadyRan) )。这将在稍后的第 3 阶段使用

2) 将 CustomRibbon 嵌入到您的工作簿中
首先,我们需要一些代码来调用在步骤 1 中创建的方法。
在您的工作簿中创建一个标准模块并将其命名为CustomUI。将以下代码添加到CustomUI模块中:

Option Explicit

Public Sub InitRibbon(ribbon As IRibbonUI)
    ThisWorkbook.FireOpenEventIfNeeded
End Sub
Run Code Online (Sandbox Code Playgroud)

Ribbon初始化时需要调用该方法。换句话说,这个方法是Ribbon使用的回调方法。

这是棘手的部分。这可以通过多种方式完成,您可以在网上找到一些工具。不过,我将向您展示如何手动执行此操作:
a) 关闭并保存工作簿

b) 如果您不使用存档程序,请下载该程序。我使用免费的7-Zip

c) 打开存档器并浏览到您的工作簿文件夹

d) 右键单击​​工作簿并选择在内部打开
在此输入图像描述

e) 创建一个名为customUI 的文件夹。您会注意到工作簿文件实际上是文件的存档
在此输入图像描述

f) 打开记事本或任何文本编辑器并使用以下 xml 创建一个新文件:

Option Explicit

Private m_openAlreadyRan As Boolean

Friend Sub FireOpenEventIfNeeded(Optional dummyVarToMakeProcHidden As Boolean)
    If Not m_openAlreadyRan Then Workbook_Open
End Sub

Private Sub Workbook_Open()
End Sub
Run Code Online (Sandbox Code Playgroud)

请注意, onLoad回调的名称与 VBA 中创建的方法(即InitRibbon )相匹配

g)将文本文件(任何地方)保存为customUI.xml(确保没有双重扩展名(例如.xml.txt)

h) 将 .xml 文件拖放到存档器内的 customUI 文件夹中
在此输入图像描述

i) 返回上一级并打开_rels文件夹。您应该看到一个.rels文件在此输入图像描述

j) 编辑.rels文件(右键单击然后编辑应打开记事本)

k) 添加 xml:

Option Explicit

Public Sub InitRibbon(ribbon As IRibbonUI)
    ThisWorkbook.FireOpenEventIfNeeded
End Sub
Run Code Online (Sandbox Code Playgroud)

这需要位于结束标记之前</Relationships>。不是之后。我使用了 rId10,但您可以查看文件中的所有其他 rId 编号并选择下一个可用的编号。确保不重复现有的 rId

l) 保存对文件的编辑并退出存档,同时确保也保存存档编辑(如果您使用带有“确定”/取消框的 7-Zip,系统会提示您)

m) 关闭存档器。你已经完成了

3) 设置 Workbook_Open 事件
我们需要考虑在步骤 1 中创建的布尔值(这样我们就不会运行相同的代码两次)和窗口视图的受保护状态。
将步骤 1 中的代码(在本工作簿中)替换为:

Option Explicit

Private m_openAlreadyRan As Boolean
Private m_isOpenDelayed As Boolean

Friend Sub FireOpenEventIfNeeded(Optional dummyVarToMakeProcHidden As Boolean)
    If Not m_openAlreadyRan Then Workbook_Open
End Sub

Private Sub Workbook_Activate()
    If m_isOpenDelayed Then
        m_isOpenDelayed = False
        InitWorkbook
    End If
End Sub

Private Sub Workbook_Open()
    m_openAlreadyRan = True
    Dim objProtectedViewWindow As ProtectedViewWindow
    '
    On Error Resume Next
    Set objProtectedViewWindow = Application.ProtectedViewWindows(Me.Name)
    On Error GoTo 0
    '
    m_isOpenDelayed = Not (objProtectedViewWindow Is Nothing)
    If Not m_isOpenDelayed Then InitWorkbook
End Sub

Private Sub InitWorkbook()
    If VBA.Val(Application.Version) < 12 Then
        MsgBox "This Workbook requires Excel 2007 or later!", vbCritical, "Closing"
        Me.Close False
        Exit Sub
    End If
    '
    With New frmMain
        .Show
        'Other code
        '
        '
        '
    End With
End Sub
Run Code Online (Sandbox Code Playgroud)

请注意以下事项:
a)如果窗口视图受到保护,_Open事件代码将延迟到_Activate
事件 b) _Open_Activate都指向InitWorkbook方法。您可以在此处添加工作簿打开时需要运行的代码
c )m_openAlreadyRan在_Open事件中设置为 True ,以便FireOpenEventIfNeeded方法不会不必要地调用_Open(即,当错误没有发生,因为没有其他书籍打开时)
d)我使用了frmMainNew实例,与@完全相同弓箭鸟提到过。通过调用来使用表单的全局实例被认为是不好的做法。另外,您也可以创建一个变量:frmMain.ShowWith New frmMain

Dim f As New frmMain
f.Show
Run Code Online (Sandbox Code Playgroud)