여러 Excel 인스턴스를 시작했는데, 이 모든 인스턴스에 대한 애플리케이션 개체를 어떻게 얻을 수 있습니까?
▁something다싶니습▁i와 비슷한 것을 하고 싶습니다.GetObject(,"Excel.Application")
내가 만든 응용프로그램을 다시 가져옵니다.
부를게요CreateObject("Excel.Application")
Excel 인스턴스를 만듭니다.나중에 VBA 프로젝트가 재설정되면 디버깅 및 코딩으로 인해 응용 프로그램 개체 변수가 손실되지만 Excel 인스턴스는 백그라운드에서 실행됩니다.일종의 메모리 누수 상황입니다.
다시 사용하거나 닫으려면 다시 연결합니다(기본 방법).
실행 중인 Excel 인스턴스를 나열하는 방법
#If VBA7 Then
Private Declare PtrSafe Function AccessibleObjectFromWindow Lib "oleacc" ( _
ByVal hwnd As LongPtr, ByVal dwId As Long, riid As Any, ppvObject As Object) As Long
Private Declare PtrSafe Function FindWindowExA Lib "user32" ( _
ByVal hwndParent As LongPtr, ByVal hwndChildAfter As LongPtr, _
ByVal lpszClass As String, ByVal lpszWindow As String) As LongPtr
#Else
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" ( _
ByVal hwnd As Long, ByVal dwId As Long, riid As Any, ppvObject As Object) As Long
Private Declare Function FindWindowExA Lib "user32" ( _
ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Long
#End If
Sub Test()
Dim xl As Application
For Each xl In GetExcelInstances()
Debug.Print "Handle: " & xl.ActiveWorkbook.FullName
Next
End Sub
Public Function GetExcelInstances() As Collection
Dim guid&(0 To 3), acc As Object, hwnd, hwnd2, hwnd3
guid(0) = &H20400
guid(1) = &H0
guid(2) = &HC0
guid(3) = &H46000000
Set GetExcelInstances = New Collection
Do
hwnd = FindWindowExA(0, hwnd, "XLMAIN", vbNullString)
If hwnd = 0 Then Exit Do
hwnd2 = FindWindowExA(hwnd, 0, "XLDESK", vbNullString)
hwnd3 = FindWindowExA(hwnd2, 0, "EXCEL7", vbNullString)
If AccessibleObjectFromWindow(hwnd3, &HFFFFFFF0, guid(0), acc) = 0 Then
GetExcelInstances.Add acc.Application
End If
Loop
End Function
플로랑 B.의 매우 유용한 기능 중 하나로 오픈 엑셀 인스턴스 컬렉션을 반환하는 기능에 대한 의견을 제시하는 것이 가장 좋겠지만, 저는 의견을 추가하기에 충분한 평판을 가지고 있지 않습니다.테스트에서 컬렉션에는 동일한 Excel 인스턴스의 "반복"이 포함되어 있었습니다.GetExcelInstances().Count
원래보다 더 컸습니다.이에 대한 해결책은 다음을 사용하는 것입니다.AlreadyThere
아래 버전의 변수입니다.
Private Function GetExcelInstances() As Collection
Dim guid&(0 To 3), acc As Object, hwnd, hwnd2, hwnd3
guid(0) = &H20400
guid(1) = &H0
guid(2) = &HC0
guid(3) = &H46000000
Dim AlreadyThere As Boolean
Dim xl As Application
Set GetExcelInstances = New Collection
Do
hwnd = FindWindowExA(0, hwnd, "XLMAIN", vbNullString)
If hwnd = 0 Then Exit Do
hwnd2 = FindWindowExA(hwnd, 0, "XLDESK", vbNullString)
hwnd3 = FindWindowExA(hwnd2, 0, "EXCEL7", vbNullString)
If AccessibleObjectFromWindow(hwnd3, &HFFFFFFF0, guid(0), acc) = 0 Then
AlreadyThere = False
For Each xl In GetExcelInstances
If xl Is acc.Application Then
AlreadyThere = True
Exit For
End If
Next
If Not AlreadyThere Then
GetExcelInstances.Add acc.Application
End If
End If
Loop
End Function
@PGS62/@Philip Swannell은 컬렉션을 반환하는 정답을 가지고 있습니다. 모든 인스턴스를 반복할 수 있습니다. @M1chael 코멘트처럼 훌륭합니다.
응용 프로그램 개체와 워크북 개체를 혼동하지 마십시오...물론 각 응용프로그램 개체의 워크북 컬렉션에 루프하는 중첩 루프를 작성할 수 있습니다.
이것은 구현되고 완전히 작동하는 중첩 루프입니다.
Sub Test2XL()
Dim xl As Excel.Application
Dim i As Integer
For Each xl In GetExcelInstances()
Debug.Print "Handle: " & xl.Application.hwnd
Debug.Print "# workbooks: " & xl.Application.Workbooks.Count
For i = 1 To xl.Application.Workbooks.Count
Debug.Print "Workbook: " & xl.Application.Workbooks(i).Name
Debug.Print "Workbook path: " & xl.Application.Workbooks(i).path
Next i
Next
Set xl = Nothing
End Sub
Word 인스턴스의 경우 중첩 루프:
Sub Test2Wd()
Dim wd As Word.Application
Dim i As Integer
For Each wd In GetWordInstancesCol()
Debug.Print "Version: " & wd.System.Version
Debug.Print "# Documents: " & wd.Application.Documents.Count
For i = 1 To wd.Application.Documents.Count
Debug.Print "Document: " & wd.Application.Documents(i).Name
Debug.Print "Document path: " & wd.Application.Documents(i).path
Next i
Next
Set wd = Nothing
End Sub
Word의 경우 이 스레드의 끝에 설명된 내용을 사용해야 합니다.
다음을 사용하여 두 인스턴스가 실행 중인지 확인하고 메시지를 표시합니다.다른 인스턴스를 닫도록 변경할 수 있습니다.이게 도움이 될지도...특정 인스턴스를 반환하고 GetObject("Excel")와 유사한 용도로 사용하기 위해 코드가 필요합니다.응용 프로그램")...저는 그것이 가능하다고 생각하지 않습니다.
If checkIfExcelRunningMoreThanOneInstance() Then Exit Function
모듈에서 (일부 선언은 다른 코드에 사용될 수 있음):
Const MaxNumberOfWindows = 10
Const HWND_TOPMOST = -1
Const SWP_NOSIZE = &H1
Const SWP_NOMOVE = &H2
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Public Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Global ret As Integer
Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Public Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Declare Function GetKeyNameText Lib "user32" Alias "GetKeyNameTextA" (ByVal lParam As Long, ByVal lpBuffer As String, ByVal nSize As Long) As Long
Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" _
Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Const VK_CAPITAL = &H14
Private Declare Function GetKeyState Lib "user32" _
(ByVal nVirtKey As Long) As Integer
Private Declare Function OpenProcess Lib "kernel32" ( _
ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long) As Long
Private Declare Function EnumProcesses Lib "PSAPI.DLL" ( _
lpidProcess As Long, ByVal cb As Long, cbNeeded As Long) As Long
Private Declare Function EnumProcessModules Lib "PSAPI.DLL" ( _
ByVal hProcess As Long, lphModule As Long, ByVal cb As Long, lpcbNeeded As Long) As Long
Private Declare Function GetModuleBaseName Lib "PSAPI.DLL" Alias "GetModuleBaseNameA" ( _
ByVal hProcess As Long, ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long
Private Const PROCESS_VM_READ = &H10
Private Const PROCESS_QUERY_INFORMATION = &H400
Global ExcelWindowName$ 'Used to switch back to later
Function checkIfExcelRunningMoreThanOneInstance()
'Check instance it is 1, else ask user to reboot excel, return TRUE to abort
ExcelWindowName = excel.Application.Caption 'Used to switch back to window later
If countProcessRunning("excel.exe") > 1 Then
Dim t$
t = "Two copies of 'Excel.exe' are running, which may stop in cell searching from working!" & vbCrLf & vbCrLf & "Please close all copies of Excel." & vbCrLf & _
" (1 Then press Alt+Ctrl+Del to go to task manager." & vbCrLf & _
" (2 Search the processes running to find 'Excel.exe'" & vbCrLf & _
" (3 Select it and press [End Task] button." & vbCrLf & _
" (4 Then reopen and use PostTrans"
MsgBox t, vbCritical, ApplicationName
End If
End Function
Private Function countProcessRunning(ByVal sProcess As String) As Long
Const MAX_PATH As Long = 260
Dim lProcesses() As Long, lModules() As Long, N As Long, lRet As Long, hProcess As Long
Dim sName As String
countProcessRunning = 0
sProcess = UCase$(sProcess)
ReDim lProcesses(1023) As Long
If EnumProcesses(lProcesses(0), 1024 * 4, lRet) Then
For N = 0 To (lRet \ 4) - 1
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, lProcesses(N))
If hProcess Then
ReDim lModules(1023)
If EnumProcessModules(hProcess, lModules(0), 1024 * 4, lRet) Then
sName = String$(MAX_PATH, vbNullChar)
GetModuleBaseName hProcess, lModules(0), sName, MAX_PATH
sName = Left$(sName, InStr(sName, vbNullChar) - 1)
If Len(sName) = Len(sProcess) Then
If sProcess = UCase$(sName) Then
countProcessRunning = countProcessRunning + 1
End If
End If
End If
End If
CloseHandle hProcess
Next N
End If
End Function
찾은 항목:
Dim xlApp As Excel.Application
Set xlApp = GetObject("ExampleBook.xlsx").Application
Excel 인스턴스에서 현재 활성화된 시트의 이름을 알고 있는 경우 객체를 가져옵니다.이것은 첫 번째 코드를 사용하여 응용 프로그램 제목에서 얻을 수 있을 것 같습니다.내 앱에서 나는 파일 이름을 알고 있습니다.
저는 항상 API 기능을 LAST 수단으로만 사용하는 것을 선호합니다.저는 이 폭로와 형식이 유사한 한 효과가 있을 방법을 고안했습니다.API 명령을 사용하지 않는 전체 솔루션은 다음과 같습니다.
사실 그것은 꽤 간단합니다.각 응용 프로그램 인스턴스 내에서 로드될 것으로 예상되는 워크북 중 하나에서 매우 기본적인 용도로 사용할 공용 서브루틴을 저장해야 합니다.
각 서브루틴은 전체 프로그램 체인의 링크로만 존재합니다.각 "링크"는 "체인"이 완료될 때까지 서브루틴 간에 전달되는 컬렉션 개체에 현재 응용 프로그램의 인스턴스를 추가합니다.
1단계. 프로그래밍 방식으로 새 Excel 인스턴스를 만듭니다.
2단계. 새 앱의 워크북 열기 방법에 워크북 변수를 할당합니다.
3단계. WB 변수.어플."서브루틴", 앱 실행
3단계에서는 앱 모음이 별도의 응용 프로그램 인스턴스에 로드된 워크북에 변수로 전달되는 것을 볼 수 있습니다.일단 "catcher" 서브루틴이 이 컬렉션 오브젝트를 수신하면, 그 서브루틴은 현재 애플리케이션 오브젝트를 컬렉션에 추가할 수 있습니다.2단계와 3단계는 최종 목적지에서 멈출 때까지 미리 결정된 각 "링크"에서 반복할 수 있습니다.
최종 인스턴스는 이론적으로 원래 워크북의 "catcher" 서브루틴으로 보내지거나 선택적 인수를 통해 최종 컬렉션 개체를 원래 서브루틴으로 재귀적으로 보낼 수 있으며, 여기서 포인트 체크는 서브루틴이 이전 포인트를 지나 계속하도록 허용할 수 있습니다.
복잡하게 들릴 수도 있지만, 약간의 독창성만 있으면 API 호출 없이도 이를 달성하기가 매우 쉽습니다.
이것은 당신이 원하는 것을 이룰 수 있습니다.Excel 인스턴스가 열려 있는지 확인합니다.
Dim xlApp As Excel.Application
Set xlApp = GetObject(, "Excel.Application")
중인 인턴스중경다우사음있수다액습을 수 .xlApp
되고 있지 오류가 합니다(처리기가 필요하거나 할 수 ).인스턴스가 실행되고 있지 않으면 런타임 오류가 발생합니다(오류 핸들러가 필요하거나 필요할 수 있음).GetObject
function은 로드된 Excel의 첫 번째 인스턴스를 가져옵니다.당신은 그것으로 당신의 일을 할 수 있고, 다른 사람들에게 접근하기 위해, 당신은 그것을 닫고 시도할 수 있습니다.GetObject
다시 다음 것을 얻기 위해 등.따라서 http://excelribbon.tips.net/T009452_Finding_Other_Instances_of_Excel_in_a_Macro.html) 에서 제공하는 ok-but-second-time 목표를 달성하게 될 것입니다.
당신이 선호하는 목표를 달성하기 위해, 저는 https://stackoverflow.com/a/3303016/2707864 이 당신에게 방법을 보여준다고 생각합니다.
개체 배열을 만들고 새로 만든 Excel을 저장합니다.어레이의 응용 프로그램입니다.그런 식으로 필요할 때 필요한 항목을 참조할 수 있습니다.간단한 예를 들어 보겠습니다.
모듈:
Dim ExcelApp(2) As Object
Sub Test()
Set ExcelApp(1) = CreateObject("Excel.Application")
ExcelApp(1).Visible = True
Set ExcelApp(2) = CreateObject("Excel.Application")
ExcelApp(2).Visible = True
End Sub
Sub AnotherTest()
ExcelApp(1).Quit
ExcelApp(2).Quit
End Sub
테스트() 매크로를 실행하면 두 개의 Excel 응용 프로그램이 팝업됩니다.그런 다음 다른 테스트()를 실행하면 Excel 응용 프로그램이 종료됩니다.완료 후 배열을 없음으로 설정할 수도 있습니다.
http://www.ozgrid.com/forum/showthread.php?t=182853 에 게시된 스크립트를 사용하여 Excel 응용 프로그램을 실행할 수 있습니다.그렇게 하면 당신이 원하는 곳으로 갈 수 있을 겁니다.
이 코드는 Excel 응용 프로그램 개체가 필요할 때마다 사용해야 합니다.이렇게 하면 코드가 하나의 응용 프로그램 개체에서만 작동하거나 기존 개체를 사용할 수 있습니다.사용자가 둘 이상을 시작할 수 있는 유일한 방법은 사용자가 둘 이상을 시작하는 것입니다.이것은 Excel을 열고 원하는 대로 부착하여 재사용할 수 있는 코드입니다.
Public Function GetExcelApplication() As Object
On Error GoTo openExcel
Set GetExcelApplication = GetObject(, "Excel.Application")
Exit Function
openExcel:
If Err.Number = 429 Then
Set GetExcelApplication = CreateObject("Excel.Application")
Else
Debug.Print "Unhandled exception: " & Err.Number & " " & Err.Description
End If
End Function
여러 인스턴스를 닫으려면 호출해야 합니다.GetObject
다음에.Close
오류 429가 발생할 때까지 반복합니다.
자세한 내용은 이 문서에서 확인할 수 있습니다.
언급URL : https://stackoverflow.com/questions/30363748/having-multiple-excel-instances-launched-how-can-i-get-the-application-object-f
'programing' 카테고리의 다른 글
php와 mysql로 워드프레스 컨테이너를 시작하도록 설정된 도커 파일, 대신 mariadb를 시작합니다. (0) | 2023.08.25 |
---|---|
PowerShell '문자열'에 하나의 따옴표를 사용할 수 있습니까? (0) | 2023.08.25 |
PHP-MySQL-MySQL 정수 필드를 안전하게 증가시키는 방법? (0) | 2023.08.25 |
if-statement의 () 연산자 크기 (0) | 2023.08.25 |
요청한 버전과 일치하는 NDK 버전이 없습니다. (0) | 2023.08.25 |