excel - 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 与好的实例一起使用。
解决方案
终于找到解决办法了!使用下面的代码,因为我知道我的第三个软件在哪里使用新实例生成临时文件,所以我使用 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
推荐阅读
- c++ - 为什么 std::reduce 需要可交换性?
- c++ - 控制台输出在 Qt5 中无法正确显示
- api - UserStoreConfigAdminService 问题
- html - 如何构建类似于 Facebook 提要侧边栏的粘性滚动侧边栏行为
- c - 尝试移动到在上述程序集的 C 代码中定义的变量时出现未定义符号错误
- sql - 返回计数值为 0 的 table_name 和 partition_name
- asp.net-core - 在 C# 中启动 2 个网络服务器
- python - 从 SmartSheet API 创建 Pandas DataFrame(嵌套、笨拙、JSON)
- ios - “可滚动内容大小与“ScrollView”不明确
- apache-kafka - 我们可以为生产者配置“delivery.timeout.ms”设置自定义值吗?