【问题标题】:Use Excel VBA to run file in own separate instance of Microsoft Excel使用 Excel VBA 在自己单独的 Microsoft Excel 实例中运行文件
【发布时间】:2019-06-24 07:51:57
【问题描述】:

(最低要求:Excel 2010 和 Windows 7) 我已经设法使用了 MSDN 中的 Bill Manville 的答案,并进行了细微的更改。建议的递归代码基本上使用文件的 Workbook_Open 来创建一个单独的实例,并且该实例将文件打开为可编辑,而不提示只读访问。

Private Sub Workbook_Open()
  Dim oXcl As Excel.Application
  If Workbooks.Count > 1 Then
    ThisWorkbook.Saved = True
    ThisWorkbook.ChangeFileAccess xlReadOnly
    Set oXcl = CreateObject("Excel.Application")
    oXcl.ScreenUpdating = False
    oXcl.Visible = True
    oXcl.Workbooks.Open fileName:=ThisWorkbook.FullName, ReadOnly:=False
    AppActivate oXcl.Caption
    ThisWorkbook.Close SaveChanges:=False
  Else 
    Call Continue_Open
  End If
End Sub

当 Excel 已经在运行时,代码运行良好,因为它创建了一个新的 Excel 实例,如果打开了一个新的 Excel 文件,它会转到另一个 Excel 实例(在它之前运行)。但是,如果带有 Workbook_Open 的文件是启动 Excel 的文件,则通过在该 Excel 实例中双击打开的任何其他 Excel 文件,因为它是最早运行的实例,因此不再是单独的。

我已经能够告诉(Windows)该文件是否通过使用来启动 Excel

Function NumberOfExcelInstances()
  strComputer = "."
  Set objWMI = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
  Set proc = objWMI.ExecQuery("Select * from Win32_Process Where Name = 'Excel.exe'")
  NumberOfExcelInstances = proc.Count
End Function

但我无法找到一种方法来告诉在打开新文件时不要使用该 Excel 实例。任何代码都应与 Worbook_Open 代码捆绑在 Excel 文件中。 我怎么可能在文件中包含 VBA 代码,以便它在单独的 Excel 实例中打开,即使该文件是触发 Excel 的文件?

【问题讨论】:

  • 你确定是 2010 年的吗? MDI 接口在 2013 年被删除,从那时起你就不能做你想做的事,因为你不能有一个没有打开文档的 Excel 实例。对于 2010 年,它应该可以工作,但如果没有,请在启动新 Excel 之前尝试从Workbook_Open 返回(为此,您必须使用Application.OnTime 来安排该代码在您退出Workbook_Open 后运行一秒钟)。
  • 非常感谢您的关注。我不知道 Excel 2013 的这些更改。我已经在 Excel 2010 中测试了该文件,并且它的工作原理,顺便说一下,它的行为与应用程序中提到的一样.OnTime:在 Excel 2010 中,它会在 Excel 已经触发时创建一个新实例,但如果该文件触发 Excel,它会在该实例中打开新的 Excel 文件。我现在可以轻松使用 Application.OnTime 但我不确定我是否理解“尝试从工作簿返回。:打开”你能详细说明一下吗?
  • 我的意思是您需要将 OnTime 设置为这样的时间,以便到那时您将从 Workbook_Open 返回。尝试在Workbook_Open 的最后一行将OnTime 设置为dateadd("s", 1, Now)

标签: excel vba instance


【解决方案1】:

在对应用程序级别的代码进行研究后,找到了一个可行的解决方案。我发布它,以防其他人感兴趣。

当工作簿第一次打开时,它会在应用程序级别(而不是工作簿级别)设置一个工作簿打开事件子例程。

当一个新工作簿打开时,应用程序级别的子程序打开一个新实例,该工作簿通过递归保持分离 - 关闭应用程序实例中检查是否分离的工作簿,从而从应用程序实例中删除事件处理程序并设置该事件处理程序和新创建的应用程序实例上的代码。

所有相关代码都包含在内,并且需要在三个不同的模块中。

1-使用以下代码创建名为 cXlEvents 的 VBA 类模块:

'VBA Class Module named cXlEvents 
Public WithEvents appWithEvents As Application
'Instance variables
Dim sEventSetterPath As String
Dim sEventSetterName As String

Private Sub appWithEvents_WorkbookOpen(ByVal Wb As Workbook)
    Call NewAppInstance(Wb, sEventSetterPath, sEventSetterName)
End Sub

2-ThisWorkbook 模块包括:

'1-ThisWorkbook VBA Module calling events at 
'Workbook level.
'2-At Workbook Open set Application level event 
'handler and then instance code by calling subs 
'held in VBA standard module.  
Private Sub Workbook_Open()
  Call SetEventHandler
  Call NewAppInstance(Me)
End Sub

'Code to call "undo" special settings upon opening 
'when file closes
Private Sub Workbook_BeforeClose(Cancel As Boolean)
  Call UndoSettings
End Sub

3-在工作簿级别创建实例所需的所有代码都将在应用程序级别结束的类的打开事件位于标准 VBA 模块中:

'In a VBA standard Module
Dim oXlEvents As New cXlEvents

Sub SetEventHandler()
  If oXlEvents.appWithEvents Is Nothing Then
    Set oXlEvents.appWithEvents = Application
  End If
End Sub

Sub NewAppInstance(wbWbook As Workbook, Optional sEventSetterPath As String, Optional sEventSetterName As String)

  Dim oXcl As Excel.Application
  Dim wbEventSet As Workbook
  Dim lCaseNum As Long
  Dim sResetMacro As String: sResetMacroName = "UndoSettings"

  'Set instance variables
  sEventSetterPath = ThisWorkbook.FullName
  sEventSetterName = ThisWorkbook.Name

  If wbWbook.ReadOnly And wbWbook.FullName = sEventSetterPath Then
    MsgBox "Already open - please use open file.", , "WARNING"
    wbWbook.Close False
    Exit Sub
  End If

  If Workbooks.Count > 1 Then

    If wbWbook.FullName <> sEventSetterPath Then
      lCaseNum = 1
      Set wbEventSet = Workbooks(1)
      wbEventSet.Save
      Application.Run "'" & sEventSetterName & "'!'" & sResetMacro & "'"
    Else
      lCaseNum = 2
      Set wbEventSet = wbWbook
      wbEventSet.Saved = True
    End If
    wbEventSet.ChangeFileAccess xlReadOnly
    Set oXcl = CreateObject("Excel.Application")
    oXcl.Workbooks.Open Filename:=sEventSetterPath, ReadOnly:=False
    oXcl.Visible = True
    Set oXlEvents.appWithEvents = Nothing
    Select Case lCaseNum
      Case Is = 1
        AppActivate Application.Caption
      Case Is = 2
        AppActivate oXcl.Caption
    End Select
    wbEventSet.Close False
  Else
    Call Continue_Open
  End If
End Sub

Sub Continue_Open()
  'Code with special settings and procedures required for the workbook 
End Sub

Sub UndoSettings()
  'Code to "undo" any special settings when workbook opened   
 End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-23
    • 2019-08-18
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 2016-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多