Vba 检测打开工作簿的其他实例
我正在尝试让用户选择Excel的实例或打开工作簿。其思想是有一个窗口来显示所有打开的Excel实例,然后显示这些实例中的工作簿。我做了一些自我调查,我在下面发现了Vba 检测打开工作簿的其他实例,vba,excel,Vba,Excel,我正在尝试让用户选择Excel的实例或打开工作簿。其思想是有一个窗口来显示所有打开的Excel实例,然后显示这些实例中的工作簿。我做了一些自我调查,我在下面发现了 Public Declare Function GetDesktopWindow Lib "user32" () As Long Public Declare Function FindWindowEx Lib "user32" Alias _ "FindWindowExA" (ByVal hWnd1 As Long, ByVal
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function FindWindowEx Lib "user32" Alias _
"FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Function ExcelInstances() As Long
Dim hWndDesk As Long
Dim hWndXL As Long
'Get a handle to the desktop
hWndDesk = GetDesktopWindow
Do
'Get the next Excel window
hWndXL = FindWindowEx(GetDesktopWindow, hWndXL, _
"XLMAIN", vbNullString)
'If we got one, increment the count
If hWndXL > 0 Then
ExcelInstances = ExcelInstances + 1
End If
'Loop until we've found them all
Loop Until hWndXL = 0
End Function
问题:
运行代码时,我收到错误消息:
编译错误:
只有注释可以出现在End Sub、End Function或End Property之后
它突出显示了代码中的第一行,我相信这与“user32”
字符串有关
问题:
这段代码只会告诉我当前打开了多少个Excel实例。是否有方法返回实例的名称,然后返回另一个子例程,该子例程也将返回实例中的工作簿?我看到了一个使用VB.Net的解决方案;但是,我希望避免这种情况,以便我可以尝试将所有内容合并到一个Excel电子表格中(如果可能)。以下代码将回答您的第二个问题
Option Explicit
Private Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" ( _
ByVal hwnd As Long, _
ByVal lpClassName As String, _
ByVal nMaxCount As Long) As Long
Private Declare Function EnumWindows Lib "user32.dll" ( _
ByVal lpEnumFunc As Long, _
ByVal lParam As Long) As Boolean
Private Declare Function EnumChildWindows Lib "user32.dll" ( _
ByVal hWndParent As Long, _
ByVal lpEnumFunc As Long, _
ByVal lParam As Long) As Long
Private Declare Sub IIDFromString Lib "ole32.dll" ( _
ByVal lpsz As String, _
ByRef lpiid As GUID)
Private Declare Sub AccessibleObjectFromWindow Lib "oleacc.dll" ( _
ByVal hwnd As Long, _
ByVal dwId As Long, _
ByRef riid As GUID, _
ByRef ppvObject As Any)
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Private Const GC_CLASSNAMEEXCEL = "XLMAIN"
Private Const GC_CLASSNAMEEXCEL7 = "EXCEL7"
Private Const IID_EXCELWINDOW = "{00020893-0000-0000-C000-000000000046}"
Private Const OBJID_NATIVEOM = &HFFFFFFF0
Private lalngChildHwnd() As Long, lialngChildCount As Long
Private lalngMainHwnd() As Long, lialngMainCount As Long
Private Function GetApplications() As Application()
Dim ialngIndex As Long, ialngCount As Long
Dim udtGuid As GUID
Dim objWindow As Window
Dim aobjTempApplications() As Application
'Alle lokalen Variablen zuruecksetzen
Erase lalngChildHwnd
lialngChildCount = 0
Erase lalngMainHwnd
lialngMainCount = 0
'Konvertiere die IID des Excel-Window-Objektes in die GUID-Struktur
Call IIDFromString(StrConv(IID_EXCELWINDOW, vbUnicode), udtGuid)
'Callback Aufruf um alle Fenster zu klassifizieren
Call EnumWindows(AddressOf EnumWindowsProc, ByVal 0&)
'Schleife ueber alle gefundenen Parent-Excelfenster
For ialngIndex = LBound(lalngMainHwnd) To UBound(lalngMainHwnd)
'Callback Aufruf um alle Child-Fenster der
'entsprechenden Parent-Fenster zu durchlaufen
Call EnumChildWindows(lalngMainHwnd(ialngIndex), _
AddressOf EnumChildWindowsProc, ByVal 0&)
Next
'Schleife ueber die jeweils ersten gefundenen Window-Fenster
For ialngIndex = LBound(lalngChildHwnd) To UBound(lalngChildHwnd)
'Hole ueber die Zugriffsnummer das entsprechende Window-Objekt
Call AccessibleObjectFromWindow(lalngChildHwnd(ialngIndex), _
OBJID_NATIVEOM, udtGuid, objWindow)
'Wenn das Objekt gefunden wurde setze einen Verweis
'auf dessen Application-Objekt in das Array
If Not objWindow Is Nothing Then
ReDim Preserve aobjTempApplications(ialngCount)
Set aobjTempApplications(ialngCount) = objWindow.Application
ialngCount = ialngCount + 1
End If
Next
'Array an die Funktionsvariable uebergeben
GetApplications = aobjTempApplications
End Function
Private Function EnumWindowsProc( _
ByVal pvlngHwnd As Long, _
ByVal pvlnglParam As Long) As Long
'Callback Funktion um alle Fenster zu durchlaufen
'Wenn ein Excelfenster gefunden wurde schreibe dessen Handle in das Array
If ClassName(pvlngHwnd) = GC_CLASSNAMEEXCEL Then
ReDim Preserve lalngMainHwnd(lialngMainCount)
lalngMainHwnd(lialngMainCount) = pvlngHwnd
lialngMainCount = lialngMainCount + 1
End If
EnumWindowsProc = 1
End Function
Private Function EnumChildWindowsProc( _
ByVal pvlngHwnd As Long, _
ByVal pvlnglParam As Long) As Long
'Callback Funktion um alle Child-Fenster zu durchlaufen
'Wenn ein Window-Fenster im Excel-Fenster gefunden wurde schreibe
'dessen Handle in das Array und verlasse die Callback-Prozedur
If ClassName(pvlngHwnd) = GC_CLASSNAMEEXCEL7 Then
ReDim Preserve lalngChildHwnd(lialngChildCount)
lalngChildHwnd(lialngChildCount) = pvlngHwnd
lialngChildCount = lialngChildCount + 1
EnumChildWindowsProc = 0
Else
EnumChildWindowsProc = 1
End If
End Function
Private Function ClassName( _
ByVal pvlngHwnd As Long) As String
'Funktion zum Ermitteln des Klassennames
Dim strClassName As String * 256
Dim lngReturn As Long
'Lese den Klassenname des Handles
lngReturn = GetClassName(pvlngHwnd, strClassName, Len(strClassName))
'Klassenname an die Funktionsvariable uebergeben
ClassName = Left$(strClassName, lngReturn)
End Function
函数GetApplications将为您提供Excel的所有实例。
Public
声明应位于模块顶部。@BigBen Perfect,这样就解决了我的第一个问题。。。感谢您捕捉到:)除非您采取了特定的措施,否则您有一个Excel实例和多个文档,它们都可以通过Application.Workbooks
相互查看。如果您已经采取了措施(或),并且您确实有多个Excel实例,那么可能是您没有看到其他实例的预期行为。