首页 > 解决方案 > VBA 中 Microsoft Office 实例之间的通信

问题描述

我正在尝试在实例 A 上创建一个 VBA 脚本,用于在 Word 的实例 B 上复制由具有临时且不可预测名称的层程序生成的基本内容,因此我无法使用 GetObject(Path,) 来使用 Path 获取此实例,因为我没有它。

我的临时解决方案是 PowerShell 从实例 A 运行此命令以获取标题中带有“Word”的所有 Windows 的名称......并将其存储在 VBA 变量中以检测名称是否来自实例 A 以外的其他实例:

Get-Process |Where-Object {$_.mainWindowTitle -like "*Word*"} |format-table mainwindowtitle 

它有效,但我无法相信即使路径未知,也无法直接从 VBA 检测所有正在运行的应用程序实例。

我在 VBA 中尝试过这样丑陋的东西来跨越不同的实例但没有成功:

Sub GetAllInstance()
Dim WordApp As Word.Application, wordInstance As Object
Set WordApp = GetObject(, "Word.Application")

For Each wordInstance In WordApp
    MsgBox (wordInstance)
Next wordInstance

End Sub

并且即时命令告诉我,GetObject 只有关于我的实例 A 的信息,即使在单独的实例上打开了 3 个文档,也只会产生 1 个文档:

?WordApp.Documents.Count
1

编辑 20/02:

在 Cindy 的好建议下,我改变了尝试使用进程的方法,我使用以下代码成功检测到正在运行的实例的不同 PID:

Sub IsProcessRunning()
    Dim process As String
    Dim objList As Object
    Dim xprocess As Variant
    Dim wdApp As Word.Application

    process = "Word.exe"

    Set objList = GetObject("winmgmts:") _
        .ExecQuery("select ProcessID from win32_process where name='" & process & "'")


For Each xprocess In objList
    Debug.Print xprocess.ProcessID
    AppActivate (xprocess.ProcessID)
    Set wdApp = GetObject(, "Word.Application")
    Debug.Print wdApp.Workbooks(1).Name
Next xprocess

End Sub

不幸的是,激活应用程序并没有清除 ROT,我现在正试图找到一种方法来清除它并刷新它以在 ROT 中注册新激活的应用程序并将 GetObject 与好的实例一起使用。

标签: excelvbams-word

解决方案


终于找到解决办法了!使用下面的代码,因为我知道我的第三个软件在哪里使用新实例生成临时文件,所以我使用 HWND 和来自 user32 lib 的 GetWindowText 搜索文件的名称。它允许我使用完整路径分配 GetObject 并在来自两个单独实例的两个文档之间进行交互。感谢 Cindy 和 Mathieu 的帮助:

' API declaration
Const GW_HWNDNEXT = 2
Private Declare PtrSafe Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Private Sub CommandButton1_Click()

    Dim openDoc As Document, sourceDoc As Document, targetDoc As Object
    Dim hWndThis As Long
    Dim sTitle As String
    Dim xTable As Table

    ''' INITIALIZATION '''

    'Assign the source Document
    Set sourceDoc = ActiveDocument

    'Detect each instance by Window Name, then assign it to different object
    hWndThis = FindWindow(vbNullString, vbNullString)
        While hWndThis
            sTitle = Space$(255)
            sTitle = Left$(sTitle, GetWindowText(hWndThis, sTitle, Len(sTitle)))

                If sTitle Like "*tmp*.DOC*" Then
                    FileToOpen = Left(sTitle, Len(sTitle) - 8)
                    Set targetDoc = GetObject("C:\Users\xxxxx\AppData\Local\Temp" & "\" & FileToOpen)
                    GoTo EndLoop:
                End If
            hWndThis = GetWindow(hWndThis, GW_HWNDNEXT)
        Wend
    EndLoop:
End Sub

推荐阅读