Centrum skryptów - Systemy operacyjne

Jak odczekać dopóki jedna aplikacja nie zakończy działania przed uruchomieniem kolejnej?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak odczekać dopóki jedna aplikacja nie zakończy działania przed uruchomieniem kolejnej?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Mam skrypt uruchamiający dwie aplikacje, jednak druga z nich nie może się uruchomić, dopóki pierwsza nie zakończy działania. Jak mogę się upewnić, że mój drugi program nie zostanie uruchomiony przed zakończeniem działania pierwszego?

-- OR

Cześć Skrypciarze! Odpowiedź

Cześć, OR. Nie tak dawno piszący te słowa Skrypciarz przeczytał artykuł o Walterze Mossbergu, który pisuje felietony na temat nowoczesnych technologii dla magazynu Wall Street Journal (j.ang.) Wall Street Journal. W artykule tym pojawia się spekulacja, że Mossberg, wysyłający dwa artykuły w tygodniu i ponadto posiadający jakieś jeszcze małe źródło dochodu, zarabia rocznie około miliona dolarów. Każdy, kto przeczytał ten artykuł, pewnie zaczął się zastanawiać: „Cóż, Walter Mossberg, który pisuje dwa razy w tygodniu zarabia milion dolarów rocznie, więc Skrypciarz pisujący do rubryki Cześć Skrypciarze musi zarabiać ok. 2,5 miliona!”

Prawdę mówiąc, Microsoft nie pochwala ujawniania informacji o dochodach pracowników. Ale jedno możemy wam powiedzieć: nie, piszący te słowa Skrypciarz nie zarabia 2,5 miliona rocznie. Microsoft płaci dokładnie tyle, ile uważa za stosowne.

No właśnie. Au!

Ale to nic, naprawdę. Może i Walter Mossberg zarabia kupę kasy, ale nigdy nie dowie się, co znaczy mieć satysfakcję z powodu z napisania skryptu uruchamiającego aplikację i czekającego dopóki nie skończy ona działać przed uruchomieniem kolejnej:

strComputer = "."



Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")



Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")



errReturn = objProcess.Create("Notepad.exe", null, null, intProcessID)



Set colMonitoredProcesses = objWMIService. _        

    ExecNotificationQuery("select * From __InstanceDeletionEvent " _ 

        & " within 1 where TargetInstance isa 'Win32_Process'")



Do While True

    Set objLatestProcess = colMonitoredProcesses.NextEvent

    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then

        Exit Do

    End If

Loop

errReturn = objProcess.Create("Calc.exe", null, null, intProcessID)

Niektórzy z Was – może nawet sam Walter Mossberg – mogą się poczuć dotknięci. Można by chyba użyćdużo prostszego skryptu, takiego, który wygląda następująco:

Set objShell = CreateObject("Wscript.Shell")



objShell.Run "Notepad.exe", ,True

objShell.Run "Calc.exe"

No cóż, nie bardzo. Mamy po temu dwa powody. Po pierwsze, wszelkie próby zastosowania powyższego skryptu, z jakiś niewyjaśnionych powodów, spełzły na niczym: po zakończeniu działania pierwszego programu były problemy z uruchomieniem drugiego. Nie mamy pewności dlaczego tak się dzieje, więc zdecydowaliśmy się pójść inną, bardziej skomplikowaną drogą.

Po drugie, co ważniejsze, pierwszy skrypt może zadziałać także w przypadku zdalnego komputera. Wystarczy tylko zrobić kilka rzeczy. Najpierw przypisujemy nazwę tego komputera do zmiennej strComputer. Potem pozbywamy się aplikacji Notepad.exe oraz Calc.exe i zastępujemy je aplikacjami, które: 1) nie wymagają widocznego okna; oraz 2) będą samodzielnie działać, a następnie kończyć działanie. (Nadają się do tego zarówno skrypty, jak i pliki wsadowe.)

Po co nam te warunki? To proste: ze względów bezpieczeństwa nie możemy utworzyć widocznego procesu na zdalnym komputerze. Możemy uruchomić Notatnik na zdalnym komputerze, ale to wystąpienie Notatnika będzie działać w ukrytym oknie i użytkownicy nigdy go nie zobaczą. A skoro go nie widzą, będzie im niezwykle ciężko użyć tej aplikacji, a następnie ją zamknąć.

Czy to ma sens? No cóż, w sumie to nie ma znaczenia. To po prostu tak działa.

Uwaga:

Co zrobić, jeśli chcemy uruchomić aplikację z interfejsem graficznym na zdalnym komputerze, a ponadto chcemy, aby działała ona w widocznym oknie? Wszystko na ten temat można znaleźć w tym archiwalnym artykule Skrypciarzy.

 

Jeżeli chodzi o sam skrypt, rozpoczynamy od połączenia się z usługą WMI na lokalnym komputerze. Następnie stosujemy poniższy wiersz kodu w celu bezpośredniego połączenia się z klasą Win32_Process:

Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")

Po połączeniu uruchamiamy wystąpienie aplikacji Notatnik za pomocą następującego wiersza kodu:

errReturn = objProcess.Create("Notepad.exe", null, null, intProcessID)

Jak widać, wywołujemy metodę Create oraz cztery parametry:

  • Notepad.exe – nazwa pliku wykonywalnego (lub skryptu), który chcemy uruchomić. Jeżeli ten plik lub skrypt nie znajduje się w katalogu Windows, należy podać pełną ścieżkę dostępu.
  • Null – parametr opcjonalny, służący do określenia katalogu roboczego. Ponieważ domyślny katalog dla aplikacji Notatnik w pełni nam odpowiada, przekazujemy parametr Null; to tak, jakbyśmy powiedzieli: „użyj wartości domyślnej”.
  • Null – kolejny opcjonalny parametr, umożliwiający nam określenie opcji początkowych dla procesu. Po raz kolejny, wartości domyślne nam wystarczą, zatem przekazujemy parametr Null.
  • intProcessID – parametr wyjściowy. Po uruchomieniu skryptu i aplikacji Notatnik, do tego parametru zostanie automatycznie przypisany identyfikator procesu. W ten sposób będziemy wiedzieć, co się dzieje z naszą kopią aplikacji Notatnik nawet, gdy na komputerze będzie uruchomionych kilka jej kopii.

Kiedy aplikacja Notatnik już działa, ustawiamy subskrypcję zdarzeń w celu monitorowania klasy __InstanceDeletionEvent:

Set colMonitoredProcesses = objWMIService. _        

    ExecNotificationQuery("Select * From __InstanceDeletionEvent " _ 

        & " Within 1 Where TargetInstance ISA 'Win32_Process'")

Jak sama nazwa wskazuje, wystąpienia tej klasy są tworzone za każdym razem, gdy usunięty zostaje jakiś obiekt. Nas oczywiście nie interesują wszystkie obiekty, a jedynie procesy. Dlatego też dodajemy klauzulę Where, która ograniczy subskrypcję zdarzeń do obiektów (TargetInstance) należących do klasy (ISA) Win32_Process.

Uwaga:

No tak, dużo informacji jak na jeden akapit. Bardziej przystępne wprowadzenie do zdarzeń WMI można znaleźć w webcaście Scripting Week 2 (j.ang.).

 

To nas sprowadza do następującego wiersza kodu:

Do While True

    Set objLatestProcess = colMonitoredProcesses.NextEvent

    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then

        Exit Do

    End If

Loop

Uruchamiamy tu „niekończącą się” pętlę, która zatrzyma skrypt dopóki proces nie zostanie usunięty; do tego posłużą nam następujące dwa wiersze kodu:

Do While True

    Set objLatestProcess = colMonitoredProcesses.NextEvent

Kiedy zadziała wiersz 2, skrypt „zablokuje się” (tzn. zatrzyma), dopóki jakiś obiekt procesu nie zostanie usunięty (tzn. dopóki proces nie zostanie zakończony). Kiedy proces zostanie już usunięty, sprawdzamy, czy jego identyfikator był taki sam, jak identyfikator procesu, który utworzyliśmy:

If objLatestProcess.TargetInstance.ProcessID = intProcessID Then

Identyfikator procesu musi zawsze być unikalny, więc jeśli identyfikatory te są jednakowe, może to oznaczać tylko jedno: utworzone przez nas wystąpienie aplikacji Notatnik zostało zamknięte. Teraz z kolei wywołujemy polecenie Exit Do i opuszczamy niekończącą się pętlę.

Co się natomiast dzieje, jeżeli identyfikatory procesów się nie zgadzają? W takim wypadku będzie to oznaczać, że nasze wystąpienie aplikacji Notatnik ciągle działa, a zamknęliśmy jakiś inny proces. W ten sposób kontynuujemy działanie pętli i czekamy na następne zawiadomienie o zdarzeniu (o następnym procesie, który mamy usunąć).

Kiedy ostatecznie opuszczamy pętlę, wywołujemy metodę Create i uruchamiamy drugą aplikację, w tym przypadku Calc.exe:

errReturn = objProcess.Create("Calc.exe", null, null, intProcessID)

No i na tym koniec naszej pracy.

Prawda, że to brzmi jak artykuł wart 2,5 miliona dolarów? Zwłaszcza jeżeli weźmiemy pod uwagę to, ile innych pożytecznych rzeczy robią Skrypciarze. Na przykład w przyszłym tygodniu Skrypciarze będą obsługiwać stoisko na konferencji TechEd 2007 (j.ang.). Jeżeli bierzecie udział w TechEd (a tak jest, nieprawdaż?), przejdźcie przez Partners Expo Hall i poszukajcie standu CMP Media (stanowisko 1301): będą tam Skrypciarze rozdający egzemplarze Dr. Scripto’s Fun Book i laleczki Dr Scripto. Ponadto piszący te słowa Skrypciarz będzie wtedy liczył swoje zarobki, a zatem będzie miał całe mnóstwo czasu na pogawędki z odwiedzającymi.

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne