Interakcje z innymi aplikacjami
W tym rozdziale:
• Uruchamianie innych aplikacji z poziomu Excela
• Wykorzystanie automatyzacji do sterowania innymi aplikacjami
Uruchamianie innych aplikacji z poziomu Excela
Uruchamianie innych aplikacji z poziomu Excela jest bardzo często przydatną operacją. Dzięki niej można na przykład z poziomu Excela uruchomić inną aplikację Microsoft Office lub nawet DOS-owy skrypt wsadowy.
Zastosowanie funkcji Shell języka VBA
Funkcja Shell języka VBA powoduje, że uruchamianie innych programów jest stosunkowo proste. Poniżej przedstawiono kod procedury StartCalc, która uruchamia program calc.exe, czyli popularny Kalkulator systemu Windows.
Sub StartCalc()
Dim Program As String
Dim TaskID As Double
On Error Resume Next
Program = "calc.exe"
TaskID = Shell(Program, 1)
If Err <> 0 Then
MsgBox "Nie można uruchomić programu " & Program, vbCritical, "Błąd!"
End If
End Sub
Na rysunku 1 zaprezentowano okno aplikacji, która została uruchomiona za pomocą powyższej procedury.
Rysunek 1. Uruchamianie aplikacji Kalkulator z poziomu Excela
Funkcja Shell zwraca identyfikator zadania dla aplikacji. Identyfikator ten można następnie wykorzystać do uaktywnienia zadania. Drugi argument funkcji Shell określa sposób wyświetlania aplikacji (l oznacza aktywne okno o domyślnym rozmiarze). Informacje o innych wartościach tego argumentu można uzyskać w systemie pomocy.
Jeżeli wykonanie funkcji Shell nie powiedzie się, następuje wygenerowanie błędu. Z tego powodu w powyższej funkcji wykorzystano polecenie On Error, które wyświetla komunikat, jeżeli nie może znaleźć pliku wykonywalnego lub jeżeli wystąpi inny błąd.
Kod VBA nie zatrzymuje działania po uruchomieniu aplikacji za pomocą funkcji Shell. Mówiąc inaczej, funkcja Shell uruchamia aplikację w sposób asynchroniczny. Jeżeli za wywołaniem funkcji Shell w procedurze znajdują się dodatkowe instrukcje, będą one wykonywane równolegle z uruchomionym programem. Jeżeli dowolna instrukcja wymaga interwencji użytkownika (np. wyświetla się okno informacyjne), a aktywna jest inna aplikacja, zaczyna migać pasek tytułu Excela.
Czasami trzeba uruchomić aplikację za pomocą funkcji Shell i zatrzymać kod VBA do czasu jej zamknięcia. Może tak się zdarzyć, jeżeli na przykład uruchomiona aplikacja generuje plik, który jest używany w dalszej części kodu. Chociaż nie można wstrzymać wykonywania kodu, możesz utworzyć pętlę, która monitoruje stan aplikacji. Poniżej prezentuję przykład kodu wyświetlającego okno informacyjne w chwili zakończenia działania aplikacji uruchomionej za pomocą funkcji Shell.
Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Declare Function GetExitCodeProcess Lib "kernel32" _
(ByVal hProcess As Long, _
lpExitCode As Long) As Long
Sub StartCalc2()
Dim TaskID As Long
Dim hProc As Long
Dim lExitCode As Long
Dim ACCESS_TYPE As Integer, STILL_ACTIVE As Integer
Dim Program As String
ACCESS_TYPE = &H400 ' ?Val("&H400")=1024
STILL_ACTIVE = &H103 ' ?Val("&H103")=259
Program = "calc.exe"
On Error Resume Next
' Przekazanie zadania do powłoki
' uruchomienie programu przy użyciu funkcji Shell
TaskID = Shell(Program, 1)
' Pobieranie uchwytu procesu
hProc = OpenProcess(ACCESS_TYPE, False, TaskID)
If Err <> 0 Then
MsgBox "Nie można uruchomić programu " & _
Program, vbCritical, "Błąd!"
Exit Sub
End If
Do 'Pętla
' Sprawdź proces
GetExitCodeProcess hProc, lExitCode
' Zezwól na obsługę zdarzeń
DoEvents
Loop While lExitCode = STILL_ACTIVE
' Zadanie zakończone, wyświetlanie komunikatu
MsgBox Program & " został zamknięty."
End Sub
Funkcja OpenProcess otwiera istniejący proces. Parametry:
dwDesiredAccess - uprawnienia do procesu. Uprawnienia są porównywane z deskryptorami zabezpieczeń nałożonymi na proces. Parametr ten może przyjmować wartość jednej lub wielu flag uprawnień do procesu.
bInheritHandle - jeśli ten parametr ma wartość True, uchwyt może być dziedziczony; w przeciwnym wypadku uchwyt nie może być dziedziczony.
dwProcessId - identyfikator procesu, którego uchwyt ma być otworzony.
Wartość zwracana: jeśli funkcja się powiedzie, zwraca otwarty uchwyt określonego procesu. Jeśli funkcja się nie powiedzie, zwraca wartość NULL (0).
W czasie, kiedy pracuje uruchomiony wcześniej program, procedura wykonuje w pętli Do ... Loop funkcję GetExitCodeProcess, sprawdzając zwracaną wartość (lExitCode). Kiedy program zakończy działanie, zmienna lExitCode przyjmie inną wartość, pętla zakończy działanie i wykonywanie kodu VBA zostanie wznowione.
Skoroszyt z tym przykładem - UruchamianieKalkulatora.xlsm.
Uaktywnianie aplikacji z poziomu Excela.
W poprzednim podrozdziale omówiono sposoby uruchamiania aplikacji. W większości przypadków nie interesuje nas jednak uruchomienie nowej kopii aplikacji, ale uaktywnienie aplikacji, która już została wcześniej uruchomiona.
Wykorzystanie instrukcji AppActivate
W zaprezentowanej poniżej procedurze ActivateCalc wykorzystano instrukcję AppActivate w celu uaktywnienia działającej aplikacji (w tym przypadku jest to Kalkulator systemu Windows). Argumentem instrukcji AppActivate jest tytuł aplikacji (tekst na pasku tytułu). Jeżeli instrukcja AppActivate wygeneruje błąd, będzie to oznaczało, że Kalkulator nie został wcześniej uruchomiony. W takim przypadku procedura go uruchomi.
Sub ActivateCalc()
Dim AppFile As String
Dim CalcTaskID As Double
AppFile = "Calc.exe"
On Error Resume Next
AppActivate "Kalkulator"
If Err <> 0 Then
Err = 0
CalcTaskID = Shell(AppFile, 1)
If Err <> 0 Then MsgBox "Nie można uruchomić Kalkulatora"
End If
End Sub
Skoroszyt z tym przykładem - UruchamianieKalkulatora.xlsm.
Uaktywnianie aplikacji pakietu Microsoft Office
Jeżeli aplikacja należy do pakietu Office, do jej uaktywnienia można użyć metody ActivateMicrosoftApp obiektu Application. Na przykład wykonanie poniższej procedury spowoduje uruchomienie Worda:
Sub StartWord()
Application.ActivateMicrosoftApp xlMicrosoftWord
End Sub
Jeżeli w momencie wykonywania procedury Word był już uruchomiony, nastąpi jego uaktywnienie. W instrukcji wywołania tej metody można także wykorzystać inne stałe:
- xlMicrosoftPowerPoint
- xlMicrosoftMail
- xlMicrosoftAccess
- xlMi1crosoftFoxPro
- xlMicrosoftProject
- xlMicrosoftSchedulePlus (nieco starszy program pakietu Microsoft Office, przeznaczony do zarządzania czasem i zdarzeniami).
Wykorzystanie automatyzacji w programie Excel
W Excelu można napisać makro zarządzające pracą innej aplikacji, na przykhid Worda. Mówiąc ściślej, za pomocą makra w Excelu mozna zarządzać serwerem automatyzacji Worda. W takiej sytuacji Excel jest aplikacją klieneką, natomiast Word serwerem. Mozna też napisać aplikacją sterującą Excelem w Visual Basicu. Proces zarządzania aplikacją przez inną aplikację czasami nazywa się łączeniem i osadzaniem obiektów (ang. Objeet Linking and Embedding - OLE) lub po prostu automatyzacją.
Zalety automatyzacji są niezaprzeczalne. Na przyklad programista, który chce wygenerować wykres, może po prostu wykorzystać inną aplikację, pobraćz niej obiekty, uzyskać obiekt Chart, a następnie wykorzystywać jego właściwości i metody. Automatyzacja w pewnym sensie zaciera granice pomiędzy aplikacjami. Użytkownik Excela może pracować z obiektem Accessa i zupełnie nie zdawać sobie z tego sprawy.
Niektóre aplikacje, takie jak na przykład Excel, mogą działać zarówno jako aplikacja-klient, jak i jako aplikacja-serwer. Inne mogą działać wyłącznie jako aplikacje typu klient lub wyłącznie jako aplikacje typu serwer.
W tym podrozdziale zademonstrowano sposób użycia języka VBA w celu korzystania z obiektów innych aplikacji. W przykładach posługuję się Wordem, ale pojęcia te w równym stopniu dotyczą innych aplikacji udostępniających obiekty do automatyzacji - a takich aplikacji jest coraz więcej.
Działania z obiektami innych aplikacji z wykorzystaniem automatyzacji
Do osadzania w arkuszu Excela obiektu, na przykład dokumentu Worda, służy polecenie Wstaw obiekt, znajdujące się na w grupie opcji Tekst, na karcie Wstawianie. Dodatkowo można utworzyć obiekt i wykonywać z nim działania za pomocą kodu VBA (działania te stanowią sedno mechanizmu automatyzacji). W takim przypadku zazwyczaj mamy pełny dostęp do obiektów. Dla programistów taka technika zwykle jest korzystniejsza od osadzania obiektów w arkuszach. W przypadku osadzania obiektów użytkownik musi znać sposób posługiwania się aplikacją obiektu automatyzacji. Natomiast jeżeli do wykonywania działań z obiektem wykorzystamy język VBA, możemy tak zaprogramować obiekt, aby działania z nim sprowadzały się do prostych czynności, na przykład kliknięcia przycisku.
Wczesne i późne wiązanie
Przed wykonaniem działań z obiektem zewnętrznym należy utworzyć jego instancję. Można to zrobić na dwa sposoby: wykorzystując wczesne wiązanie (ang. early binding) lub późne wiązanie (ang. late binding). Termin wiązanie dotyczy dopasowywania utworzonych przez programistę wywołań funkcji do właściwego kodu implementującego funkcje.
Wczesne wiązanie
Aby wykorzystać wczesne wiązanie, należy utworzyć odwołanie do biblioteki obiektów poprzez wybranie polecenia Tools/References w edytorze Visual Basic. Na ekranie wyświetli się okno dialogowe podobne do tego, które zaprezentowano na rysunku 2. Aby utworzyć odwołanie, odszukaj i zaznacz na liście żądaną bibliotekę.
Rysunek 2. Dodawanie odwołania do pliku biblioteki obiektów
Po zdefiniowaniu odwołania do biblioteki obiektów można wykorzystać przeglądarkę obiektów (jak pokazano na rysunku 3) do przeglądania nazw obiektów oraz ich metod i właściwości. Aby uruchomić przeglądarkę obiektów, należy wcisnąć F2 w edytorze Visual Basic.
Rysunek 3. Za pomocą przeglądarki obiektów można uzyskać informacje o obiektach, do których zdefiniowano odwołania
W przypadku użycia wczesnego wiązania należy zdefiniować odwołanie do konkretnej wersji biblioteki obiektów. Na przykład możesz wprowadzić odwołanie do biblioteki Microsoft Word 10.0 Object Library (dla Worda 2002), Microsoft Word 11.0 Object Library (dla Worda 2003), Microsoft Word 12.0 Object Library (dla Worda 2007) lub Microsoft Word 14.0 Object Library (dla Worda 2010). Po zdefiniowaniu odwołania w celu utworzenia obiektu powinieneś użyć następującej instrukcji:
Dim WordApp As New Word.Application
Zastosowanie wczesnego wiązania do tworzenia obiektów, polegającego na skonfigurowaniu odwołania do biblioteki obiektów zazwyczaj jest wydajniejszym i szybszym rozwiązaniem niż użycie wiązania późnego. Wczesne wiązanie można jednak zastosować tylko wtedy, gdy obiekt jest zapisany w osobnym pliku biblioteki typu lub obiektu. Dodatkowo użytkownicy korzystający z aplikacji muszą zainstalować kopię określonej biblioteki.
Kolejną zaletą wczesnego wiązania jest możliwość wykorzystania stałych zdefiniowanych w bibliotece obiektu. Word, podobnie jak Excel, zawiera wiele predefiniowanych stałych, które można wykorzystać w kodzie VBA - ale tylko w przypadku wczesnego wiązania. W przypadku późnego wiązania można jedynie skorzystać z rzeczywistych wartości, a nie stałych.
Kolejną zaletą wczesnego wiązania jest umożliwienie wykorzystania przeglądarki obiektów edytora Visual Basic oraz opcji automatycznego wyświetlania listy składowych ułatwiającej dostęp do właściwości i metod (ang. Auto List Members). Mechanizmy te są niedostępne w przypadku wykorzystania późnego wiązania, ponieważ typ obiektu jest znany dopiero w fazie wykonywania programu.
Późne wiązanie
W fazie wykonywania programu wykorzystuje się funkcję CreateObject w celu utworzenia obiektu lub funkcję GetObject w celu uzyskania zapisanego instancji obiektu. Taki obiekt jest deklarowany jako ogólny typ Object, a odwołanie do niego jest określane w fazie wykonywania programu.
Późne wiązanie można wykorzystać nawet wtedy, kiedy nie jest znana wersja aplikacji zainstalowanej w systemie użytkownika. Na przykład wykonanie poniższego kodu spowoduje utworzenie obiektu typu Word (kod działa dla Worda 97 i wersji późniejszych):
Dim WordApp As Object
Set WordApp = CreateObject("Word.Application")
W przypadku zainstalowania wielu wersji Worda można utworzyć obiekt dla określonej wersji. Na przykład poniższa instrukcja utworzy obiekt Worda 2003:
Set WordApp = CreateObject("Word.Application.11")
Klucz rejestru Windows dla obiektu automatyzacji Worda, a także odwołanie do obiektu Application w języku VBA są takie same: Word.Application. Nie jest to jednak odwołanie do tego samego elementu. Deklaracja obiektu jako As Word.Application lub jako As New Word.Application dotyczy obiektu Application w bibliotece Word. Jednak wywołanie funkcji CreateObjectC ("Word.Application") dotyczy nazwy, pod jaką występuje najwyższa wersja Worda w rejestrze Windows. Nie jest to uniwersalna zasada dla wszystkich obiektów automatyzacji, ale obowiązuje dla głównych składników pakietu Office 2010.
Jeżeli użytkownik zastąpi Worda 2003 Wordem 2010, funkcja CreateObject ("Word.Application") dalej będzie działać prawidłowo, choć tym razem będzie odwoływać się do nowej aplikacji. Jeżeli jednak usuniemy Worda 2010, wykonanie funkcji CreateObject ("Word.Application.14"), w której użyto nazwy symbolicznej odpowiadającej Wordowi 2010, nie powiedzie się.
Funkcja CreateObject wykorzystana dla obiektu automatyzacji, na przykład Word.Application lub Excel.Application, zawsze tworzy nowy egzemplarz obiektu automatyzacji. Oznacza to, że zawsze zostanie uruchomiona nowa kopia tej części aplikacji, która bierze udział w automatyzacji. Nawet jeżeli dana instancja obiektu automatyzacji już działa, utworzony zostanie jego nowy egzemplarz, a następnie obiekt określonego typu.
Aby wykorzystać bieżący egzemplarz lub uruchomić aplikację i spowodować, aby został załadowany plik, należy skorzystać z funkcji GetObject.
W celu automatyzacji aplikacji pakietu Office zaleca się wykorzystanie wczesnego wiązania i odwołań do najwcześniejszej wersji produktu, która, jak się spodziewamy, jest zainstalowana w systemach klienckich. Jeżeli na przykład chcemy wykorzystać automatyzację dla Worda 2003, Worda 2007 oraz Worda 2010, w celu zachowania zgodności z wszystkimi trzema wersjami powinniśmy wykorzystać bibliotekę Worda 2003. Oczywiście oznacza to, że nie będzie można wykorzystać właściwości dostępnych w nowszych wersjach Worda.
Funkcja GetObject a CreateObject
Obie funkcje VBA, GetObject i CreateObject, zwracają odwołanie do obiektu, ale działają w inny sposób.
Funkcja CreateObject służy do tworzenia interfejsu do nowego egzemplarza aplikacji. Należy z niej skorzystać, jeżeli aplikacja nie działa. Nawet jeżeli egzemplarz aplikacji został wcześniej uruchomiony, funkcja spowoduje uruchomienie nowego egzemplarza aplikacji. Na przykład poniższa instrukcja spowoduje uruchomienie Excela, a obiekt zwrócony w zmiennej XLApp będzie odwołaniem do utworzonego obiektu Excel.Application:
Set XLApp = CreateObject("Excel.Application")
Funkcję GetObject wykorzystuje się z aplikacją, która już działa, lub w celu uruchomienia aplikacji z jednoczesnym załadowaniem pliku. Na przykład poniższa instrukcja spowoduje uruchomienie Excela i jednoczesne załadowanie pliku MójPlik.xlsx. Obiekt zwrócony w zmiennej XLBook będzie odwołaniem do obiektu Workbook (pliku MójPlik.xlsx).
Set XLBook = GetObject("C:\MójPlik.xlsx")
Prosty przykład późnego wiązania
W poniższym przykładzie zademonstrowano sposób utworzenia obiektu Worda za pomocą późnego wiązania. Procedura tworzy obiekt, wyświetla numer wersji, zamyka aplikację Worda, a następnie niszczy obiekt (zwalniając tym samym używany przez niego obszar pamięci):
Sub GetWordVersion()
Dim WordApp As Object
Set WordApp = CreateObject("Word.Application")
' WordApp.Visible = True
MsgBox WordApp.Version
WordApp.Quit
Set WordApp = Nothing
End Sub
Obiekt Worda utworzony w tej procedurze będzie niewidoczny. Aby zobaczyć obiekt w czasie, kiedy są z nim wykonywane działania, należy ustawić jego właściwość Visible na wartość True, tak jak pokazano poniżej:
WordApp.Visible = True
Przykład ten można też zaprogramować przy użyciu wczesnego wiązania. Zanim jednak będzie to możliwe, należy wybrać polecenie Tools/References, aby ustawić odwołania do biblioteki obiektów Worda i wprowadzić następujący kod:
Sub GetWordVersion()
Dim WordApp As New Word.Application
MsgBox WordApp.Version
WordApp.Quit
Set WordApp = Nothing
End Sub