如何在 Excel 的另一个实例中连接到 OPEN 工作簿
How to connect to OPEN workbook in another instance of Excel
目前我可以 运行 2 Excel VBA 在一台 PC 上的 2 个独立 Excel 实例中同时处理。
我的目标是每分钟将数据从 Excel 实例 2 导入到 Excel 实例 1。
遗憾的是,无法从我在 Excel 实例 1 中的工作簿连接到 Excel 实例 2 中打开的工作簿。
由于我可以连接到已保存的工作簿,解决方案可能是每分钟在实例 2 中保存工作簿并从已保存的工作簿中检索新数据。
虽然这是一个比较重的方法。在 Excel 的另一个实例中连接到另一个打开的工作簿是否有更好的解决方案?
(在同一个实例中打开工作簿不是解决方案,因为在那种情况下我无法再同时 运行 2 VBA 个进程。)
简短版
Option Explicit
Public Sub GetDataFromExternalXLInstance()
Dim instanceFile As Object, ur As Variant, lr As Long
'if not already open, GetObject() will open it in a new instance
Set instanceFile = GetObject("C:\Tmp\TestData2.xlsx") '(code running from TestData1)
ur = instanceFile.Worksheets(2).UsedRange 'get used range from 2nd Worksheet
With ActiveSheet
lr = .Cells(.Rows.Count, "A").End(xlUp).Row + 1 'last row on active sheet
.Range(.Cells(lr, "A"), .Cells(UBound(ur) + lr - 1, UBound(ur, 2))) = ur
End With
'instanceFile.Close
'Set instanceFile = Nothing
End Sub
使用 API 个调用的长版本(来自 Excel GetObject()
的帮助文件)
Option Explicit
#If VBA7 Then 'or: #If Win64 Then 'Win64=true, Win32=true, Win16= false
Private Declare PtrSafe Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function SendMessage Lib "User32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
#Else
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName as String, ByVal lpWindowName As Long) As Long
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd as Long,ByVal wMsg as Long, ByVal wParam as Long, ByVal lParam As Long) As Long
#End If
Public Sub GetDataFromExternalXLInstanceAPI()
Dim xlApp As Object
Dim xlNotRunning As Boolean 'Flag for final reference release
On Error Resume Next 'Check if Excel is already running; defer error trapping
Set xlApp = GetObject(, "Excel.Application") 'If it's not running an error occurs
xlNotRunning = (Err.Number <> 0)
Err.Clear 'Clear Err object in case of error
On Error GoTo 0 'Reset error trapping
DetectExcel 'If Excel is running enter it into the Running Object table
Set xlApp = GetObject("C:\Tmp\TestData2.xlsx") 'Set object reference to the file
'Show Excel through its Application property
xlApp.Application.Visible = True
'Show the actual window of the file using the Windows collection of the xlApp object ref
xlApp.Parent.Windows(1).Visible = True
'... Process file
'If Excel was not running when this started, close it using the App's Quit method
If xlNotRunning = True Then xlApp.Application.Quit
Set xlApp = Nothing 'Release reference to the application and spreadsheet
End Sub
Public Sub DetectExcel() 'This procedure detects a running Excel app and registers it
Const WM_USER = 1024
Dim hwnd As Long
hwnd = FindWindow("XLMAIN", 0) 'If Excel is running this API call returns its handle
If hwnd = 0 Then Exit Sub '0 means Excel not running
'Else Excel is running so use the SendMessage API function
'to enter it in the Running Object Table
SendMessage hwnd, WM_USER + 18, 0, 0
End Sub
目前我可以 运行 2 Excel VBA 在一台 PC 上的 2 个独立 Excel 实例中同时处理。
我的目标是每分钟将数据从 Excel 实例 2 导入到 Excel 实例 1。
遗憾的是,无法从我在 Excel 实例 1 中的工作簿连接到 Excel 实例 2 中打开的工作簿。
由于我可以连接到已保存的工作簿,解决方案可能是每分钟在实例 2 中保存工作簿并从已保存的工作簿中检索新数据。
虽然这是一个比较重的方法。在 Excel 的另一个实例中连接到另一个打开的工作簿是否有更好的解决方案?
(在同一个实例中打开工作簿不是解决方案,因为在那种情况下我无法再同时 运行 2 VBA 个进程。)
简短版
Option Explicit
Public Sub GetDataFromExternalXLInstance()
Dim instanceFile As Object, ur As Variant, lr As Long
'if not already open, GetObject() will open it in a new instance
Set instanceFile = GetObject("C:\Tmp\TestData2.xlsx") '(code running from TestData1)
ur = instanceFile.Worksheets(2).UsedRange 'get used range from 2nd Worksheet
With ActiveSheet
lr = .Cells(.Rows.Count, "A").End(xlUp).Row + 1 'last row on active sheet
.Range(.Cells(lr, "A"), .Cells(UBound(ur) + lr - 1, UBound(ur, 2))) = ur
End With
'instanceFile.Close
'Set instanceFile = Nothing
End Sub
使用 API 个调用的长版本(来自 Excel GetObject()
的帮助文件)
Option Explicit
#If VBA7 Then 'or: #If Win64 Then 'Win64=true, Win32=true, Win16= false
Private Declare PtrSafe Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function SendMessage Lib "User32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
#Else
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName as String, ByVal lpWindowName As Long) As Long
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd as Long,ByVal wMsg as Long, ByVal wParam as Long, ByVal lParam As Long) As Long
#End If
Public Sub GetDataFromExternalXLInstanceAPI()
Dim xlApp As Object
Dim xlNotRunning As Boolean 'Flag for final reference release
On Error Resume Next 'Check if Excel is already running; defer error trapping
Set xlApp = GetObject(, "Excel.Application") 'If it's not running an error occurs
xlNotRunning = (Err.Number <> 0)
Err.Clear 'Clear Err object in case of error
On Error GoTo 0 'Reset error trapping
DetectExcel 'If Excel is running enter it into the Running Object table
Set xlApp = GetObject("C:\Tmp\TestData2.xlsx") 'Set object reference to the file
'Show Excel through its Application property
xlApp.Application.Visible = True
'Show the actual window of the file using the Windows collection of the xlApp object ref
xlApp.Parent.Windows(1).Visible = True
'... Process file
'If Excel was not running when this started, close it using the App's Quit method
If xlNotRunning = True Then xlApp.Application.Quit
Set xlApp = Nothing 'Release reference to the application and spreadsheet
End Sub
Public Sub DetectExcel() 'This procedure detects a running Excel app and registers it
Const WM_USER = 1024
Dim hwnd As Long
hwnd = FindWindow("XLMAIN", 0) 'If Excel is running this API call returns its handle
If hwnd = 0 Then Exit Sub '0 means Excel not running
'Else Excel is running so use the SendMessage API function
'to enter it in the Running Object Table
SendMessage hwnd, WM_USER + 18, 0, 0
End Sub