You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过第一个Excel实例的宏刷新第二个实例中的数据?

解决跨Excel实例刷新工作簿的问题

要遍历所有独立运行的Excel实例,你需要借助Windows API枚举所有Excel窗口,再通过GetObject获取对应的Application对象。以下是完整的实现代码:

步骤1:添加Windows API声明

在VBA模块的顶部添加以下API声明(需放在所有过程之外):

Option Explicit

' Windows API声明:枚举窗口、获取窗口类名、获取窗口所属进程ID
Private Declare PtrSafe Function EnumWindows Lib "user32" (ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Boolean
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Integer) As Integer
Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As LongPtr, lpdwProcessId As Long) As Long
Private Declare PtrSafe Function AccessibleObjectFromWindow Lib "oleacc" (ByVal hwnd As LongPtr, ByVal dwId As Long, riid As Any, ppvObject As Object) As Long

' 用于获取Excel实例的GUID
Private Const IID_IDispatch As String = "{00020400-0000-0000-C000-000000000046}"
Private Const OBJID_NATIVEOM As Long = &HFFFFFFF0

步骤2:编写收集所有Excel实例的函数

Private Function GetAllExcelInstances() As Collection
    Dim colInstances As New Collection
    Dim hwnd As LongPtr
    
    ' 枚举所有顶级窗口,回调函数处理每个窗口
    EnumWindows AddressOf EnumWindowsProc, VarPtr(colInstances)
    
    Set GetAllExcelInstances = colInstances
End Function

Private Function EnumWindowsProc(ByVal hwnd As LongPtr, ByVal lParam As LongPtr) As Boolean
    Dim className As String * 256
    Dim excelApp As Object
    Dim colInstances As Collection
    
    Set colInstances = GetCollectionFromPtr(lParam)
    
    ' 获取窗口类名,判断是否为Excel窗口
    GetClassName hwnd, className, 256
    If Left$(className, 7) = "XLMAIN" Then ' Excel主窗口类名是XLMAIN
        ' 通过AccessibleObjectFromWindow获取对应的Excel Application实例
        If AccessibleObjectFromWindow(hwnd, OBJID_NATIVEOM, GuidFromString(IID_IDispatch), excelApp) = 0 Then
            ' 避免重复添加同一个实例
            Dim existing As Object
            Dim isDuplicate As Boolean
            isDuplicate = False
            For Each existing In colInstances
                If existing Is excelApp Then
                    isDuplicate = True
                    Exit For
                End If
            Next
            If Not isDuplicate Then
                colInstances.Add excelApp
            End If
        End If
    End If
    
    EnumWindowsProc = True ' 继续枚举下一个窗口
End Function

Private Function GuidFromString(ByVal guid As String) As GUID
    Dim guidObj As GUID
    With guidObj
        .Data1 = Val("&H" & Mid$(guid, 2, 8))
        .Data2 = Val("&H" & Mid$(guid, 11, 4))
        .Data3 = Val("&H" & Mid$(guid, 16, 4))
        .Data4(0) = Val("&H" & Mid$(guid, 21, 2))
        .Data4(1) = Val("&H" & Mid$(guid, 23, 2))
        Dim i As Integer
        For i = 2 To 7
            .Data4(i) = Val("&H" & Mid$(guid, 25 + (i - 2) * 2, 2))
        Next i
    End With
    Set GuidFromString = guidObj
End Function

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

Private Function GetCollectionFromPtr(ByVal ptr As LongPtr) As Collection
    Dim col As Collection
    CopyMemory col, ptr, LenB(ptr)
    Set GetCollectionFromPtr = col
    CopyMemory col, 0&, LenB(ptr) ' 清空指针,避免内存泄漏
End Function

Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (dest As Any, source As Any, ByVal bytes As LongPtr)

步骤3:编写主刷新过程

替换你原来的代码,用以下过程实现跨实例刷新:

Sub RefreshAllWorkbooksAcrossInstances()
    Dim excelInstances As Collection
    Dim excelApp As Object
    Dim wb As Workbook
    Dim mainWBName As String
    
    mainWBName = "Main.xlsb" ' 你的主工作簿名称
    
    Set excelInstances = GetAllExcelInstances()
    
    ' 遍历每个Excel实例
    For Each excelApp In excelInstances
        On Error Resume Next ' 处理可能的权限或实例访问问题
        ' 遍历当前实例下的所有工作簿
        For Each wb In excelApp.Workbooks
            ' 跳过主工作簿
            If wb.Name <> mainWBName Then
                ' 刷新所有数据连接
                wb.RefreshAll
                ' 等待异步查询完成
                excelApp.CalculateUntilAsyncQueriesDone
                ' 等待计算完成
                Do Until excelApp.CalculationState = xlDone
                    DoEvents ' 释放CPU资源,避免假死
                Loop
            End If
        Next wb
        On Error GoTo 0
    Next excelApp
    
    MsgBox "所有工作簿已完成刷新!", vbInformation
End Sub

关键说明

  • 代码通过枚举所有XLMAIN类的窗口(Excel主窗口),获取每个窗口对应的Excel Application实例,确保覆盖所有独立打开的Excel进程(包括SharePoint打开的实例)。
  • 添加了DoEvents避免等待计算时Excel假死。
  • 加入了重复实例判断,防止同一个实例被多次处理。
  • 错误处理部分避免因权限问题导致整个过程中断。

内容的提问来源于stack exchange,提问作者TBoulz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 01:52:12