У меня запущено несколько экземпляров Excel, может быть до 4 экземпляров. Один из них (назовем в примере A) обычно не имеет открытой рабочей книги. Он используется одним из других экземпляров (назовем его экземпляром B), чтобы открыть книгу в экземпляре A, добавить, изменить данные, затем сохранить и закрыть эту книгу, таким образом, возвращается экземпляр, где эти изменения вносятся (экземпляр A) в состояние, когда нет открытых рабочих книг. Я делаю это так, потому что это намного быстрее, чем когда рабочая книга с кодом (экземпляр B) открывает рабочую книгу, выполняет эти задачи и затем закрывает рабочую книгу.
Моя проблема заключается в следующем: время от времени, в основном для целей отладки желательно сделать экземпляр A видимым, но я обнаружил, что экземпляр без открытой рабочей книги нельзя сделать видимым, или, по крайней мере, на этом я и заключаю. Я использую Excel 2016, 64 бит. Мой код для этого:
Private Sub cmdMakeSelectionVisible_Click()
Dim strng As String
Dim lCol As Long, lRow As Long
Dim oXLApp As Excel.Application
Dim bFoundInstance As Boolean
Dim wb_Actress As Workbook
With Me.lstXL '<--| refer to your listbox: change "ListBox1" with your actual listbox name
For lRow = 0 To .ListCount - 1 '<--| loop through listbox rows
If .Selected(lRow) Then '<--| if current row selected
For lCol = 0 To .ColumnCount - 1 '<--| loop through listbox columns
strng = strng & .List(lRow, lCol) & " | " '<--| build your output string
If lCol = 1 Then
MsgBox .List(lRow, lCol)
bFoundInstance = GetReferenceToXLApp(.List(lRow, lCol), oXLApp)
MsgBox oXLApp.Caption
Set wb_Actress = oXLApp.Workbooks.Open("T:\-1996\Dummy Performer's Book.xlsm")
oXLApp.Visible = True
wb_Actress.Close
End If
Next lCol
MsgBox "you selected" & vbCrLf & Left(strng, (Len(strng) - 1)) '<--| show output string (after removing its last character ("|"))
Exit For '<-_| exit loop
End If
Next lRow
End With
End Sub
Внутри циклов For есть оператор If и в этом операторе If, если рассматриваемый экземпляр открывает рабочую книгу, то код работает. Если экземпляр не открывает рабочую книгу и не содержит дочерних элементов, он не работает. Если в этот момент я проверяю, имеет ли значение oXApp.Visible значение true, это правда, но экземпляр остается скрытым.
Вопрос в том, можно ли обойти это без открытия книги, сделать экземпляр видимым а потом закрывать книгу? Я все еще считаю себя новичком, когда дело доходит до VBA. Может быть совершенно другой подход, кроме использования дескриптора для нужного экземпляра.
Спасибо за внимание и помощь.
Редактировать:
Код для GetReferenceToXLApp:
Public Function GetReferenceToXLApp(hWndXL As Long, oXLApp As Object) As Boolean
Dim hWinDesk As Long
Dim hWin7 As Long
Dim obj As Object
Dim iID As GUID
'// Rather than explaining, go read
'// http://msdn.microsoft.com/en-us/library/windows/desktop/ms687262(v=vs.85).aspx
Call IIDFromString(StrPtr(IID_IDispatch), iID)
'// We have the XL App (Class name XLMAIN)
'// This window has a child called 'XLDESK' (which I presume to mean 'XL desktop')
'// XLDesk is the container for all XL child windows....
hWinDesk = FindWindowEx(hWndXL, 0&, "XLDESK", vbNullString)
'// EXCEL7 is the class name for a Workbook window (and probably others, as well)
'// This is used to check there is actually a workbook open in this instance.
hWin7 = FindWindowEx(hWinDesk, 0&, "EXCEL7", vbNullString)
'// Deep API... read up on it if interested.
'// http://msdn.microsoft.com/en-us/library/windows/desktop/dd317978(v=vs.85).aspx
If AccessibleObjectFromWindow(hWin7, OBJID_NATIVEOM, iID, obj) = RETURN_OK Then
Set oXLApp = obj.Application
GetReferenceToXLApp = True
End If
End Function
А
Private Declare PtrSafe Function IIDFromString Lib "ole32" _
(ByVal lpsz As LongPtr, ByRef lpiid As GUID) As Long
А
Private Declare PtrSafe Function FindWindowEx Lib "User32" Alias "FindWindowExA" _
(ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, _
ByVal lpsz2 As String) As Long