70-536 Managing Computers

Poniższy artykuł pochodzi z serii Przygotowań do egzaminu 70-536.

Nasze aplikacje często potrzebują informacji na temat np. uruchomionych procesów lub ilość podłączonych urządzeń magazynujących itp. Ponad to często może okazać się przydatne zareagowanie na uruchomienie jakiegoś procesu. Do realizacji tego typu zadań możemy wykorzystać w .NET Framework klasy Process czy też Windows Management Instrumentation (WMI).

Analiza procesów

Do wyświetlenia wszystkich aktualnie uruchomionych procesów możemy użyć statycznej metody Process.GetProcesses. Poniższy kod przedstawia wykorzystanie tej metody, która wyświetli Id (PID) procesu i jego nazwę. Zastrzegam, że procesy uruchomione przez innych użytkowników mogą być tutaj nie widoczne.

   1: // C#
   2: foreach (Process p in Process.GetProcesses())
   3: Console.WriteLine("{0}: {1}", p.Id, p.ProcessName);

Aby wyszukać proces po konkretnym jego ID można użyć Process.GetProcessById, natomiast wyszukiwanie po nazwie Process.GetProcessesByName. Jeśli chcielibyśmy pobrać aktualnie uruchomiony proces- Process.GetCurrentProcess.

Po utworzeniu instancji procesu można uzyskać dostęp do listy modułów ładowanych przez ten proces. Służy do tego metoda Process.Modules. Tutaj znowu małe zastrzeżenie – może ona być wywołana kiedy mamy odpowiednio duże uprawnienia w systemie. Jeśli nie posiadamy odpowiednich ustawień środowisko CLR wyrzuci nam wyjątek Win32Exception. Poniższy kod pokazuje realizacje metody Process.Modules

   1: // C#
   2: foreach (Process p in Process.GetProcesses())
   3: {
   4: Console.WriteLine("{0}: {1}", p.Id.ToString(), p.ProcessName);
   5: try
   6: {
   7: foreach (ProcessModule pm in p.Modules)
   8: Console.WriteLine(" {0}: {1}", pm.ModuleName,
   9: pm.ModuleMemorySize.ToString());
  10: }
  11: catch (System.ComponentModel.Win32Exception ex)
  12: {
  13: Console.WriteLine(" Unable to list modules");
  14: }
  15: }

Kilka przydatnych właściwości klasy Process:

  • BasePriority – piorytet procesu
  • ExitCode – po tym jak proces się zakończy uzupełniania jest właściwość ExitCode i ExitTime. Jeżeli ExitCode przechowuje wartość zero tzn. że proces zakończył się bezbłędnie. Każda inna wartość różna od zera wskazuje na to, że proces został zamknięty z błędem.
  • ExitTime – czas zakończenia procesu.
  • HasExited – wartość logiczna określająca czy proces jest w stanie zamykania
  • ID – jasne ;)
  • MachineName – nazwa komputera na którym został uruchomiony dany proces.
  • Modules – lista modułów ładowanych przez proces.
  • NonpagedMemorySize64 – ilość niestronicowanej pamięci przeznaczonej na proces. Niestronicowana pamięć musi być przechowywana w pamięci RAM.
  • PagedMemorySize64 – ilość stronicowanej pamięci przeznaczonej na proces. Pamięć stronicowana może być przenoszona do pliku stronicowania.
  • ProcessName – nazwa procesu która jest zazwyczaj taka sama jak nazwa pliku wykonywalnego.
  • TotalProcessorTime – łączny czas trwania procesu

Jeśli chcemy uruchomić nowy proces musimy wywołać metodę Process.Start,  w parametrze musimy podać nazwę procesu oraz możemy jako dodatkowy parametr dodać command-line. Dzięki temu możemy otworzyć przeglądarkę a w dodatkowym parametrze przekazać stronę która ma się wyświetlić, odpalić MS WORD z jakimś konkretnym dokumentem itd.

Accessing Management Information

Windows udostępnia nam wiele informacji o komputerze i systemie operacyjnym poprzez WMI. Informacje te mogą być nam potrzebne bo to one determinują np. ustawiania naszej aplikacji czy też  jakich narzędzi użyć do zarządzania komputerem .

Po pierwsze musimy zdefiniować nasz zakres zarządzania poprzez stworzenie nowego obiektu ManagementScope i wywołać ManagementScope.Call. Typowym zakresem zarządzania jest \\<computer_
name>\root\cimv2 Jak zrealizować to w kodzie pokazuje poniższy kod:

   1: // C#
   2: ManagementScope scope =
   3: new ManagementScope(@"\\localhost\root\cimv2");
   4: scope.Connect();

 

Należy również stworzyć WMI Query Language (WQL) zapytania za pomocą instancji ObjectQuery, które będą realizowane w zakresie określonym przez użytkownika. WQL jest podzbiorem
Structured Query Language (SQL) z rozszerzeniami do wspierania powiadomień o zdarzeniach WMI i innych jego specyficznych cech. Poniższy przykładowy kod demonstruje sposób wyszukiwania wszystkich obiektów w obiekcie Win32_OperatingSystem. Jednakże, istnieje wiele różnych obiektów WMI, więcej na: http://msdn.microsoft.com/en-us/library/aa394554.aspx.

   1: // C#
   2: ObjectQuery query = new ObjectQuery(
   3: "SELECT * FROM Win32_OperatingSystem");

Z zdefiniowanego zakresu i zapytania można wykonać zapytanie poprzez utworzenie obiektu ManagementObjectSearcher i wywołanie metody ManagementObjectSearcher.Get przy tworzeniu ManagementObjectCollection:

   1: // C#
   2: ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
   3: ManagementObjectCollection queryCollection = searcher.Get();

 

Alternatywnie można przeciążyć konstruktor ManagementObjectSearcher w którym przekażemy zapytanie:

   1: ManagementObjectSearcher searcher =
   2: new ManagementObjectSearcher(
   3: "SELECT * FROM Win32_LogicalDisk");
   4: ManagementObjectCollection queryCollection = searcher.Get();

Można oczywiście iteracyjnie przejść przez obiekty ManagementObject i uzyskać bezpośredni dostęp do właściwości obiektów. Poniższy kod w pętli wypisuje kilka właściwości zawartych w Win32_OperatingSystem.

   1: // C#
   2: foreach (ManagementObject m in queryCollection)
   3: {
   4: Console.WriteLine("Computer Name : {0}", m["csname"]);
   5: Console.WriteLine("Windows Directory : {0}", m["WindowsDirectory"]);
   6: Console.WriteLine("Operating System: {0}", m["Caption"]);
   7: Console.WriteLine("Version: {0}", m["Version"]);
   8: Console.WriteLine("Manufacturer : {0}", m["Manufacturer"]);
   9: }

 

Poniższy  kod demonstruje sposób wyszukiwania informacji na komputerze lokalnym o systemie operacyjnym:

   1: //C#
   2: // Perform the query
   3: ManagementObjectSearcher searcher =
   4: new ManagementObjectSearcher(
   5: "SELECT * FROM Win32_OperatingSystem");
   6: ManagementObjectCollection queryCollection = searcher.Get();
   7: // Display the data from the query
   8: foreach (ManagementObject m in queryCollection)
   9: {
  10: // Display the remote computer information
  11: Console.WriteLine("Computer Name : {0}", m["csname"]);
  12: Console.WriteLine("Windows Directory : {0}", m["WindowsDirectory"]);
  13: Console.WriteLine("Operating System: {0}", m["Caption"]);
  14: Console.WriteLine("Version: {0}", m["Version"]);
  15: Console.WriteLine("Manufacturer : {0}", m["Manufacturer"]);
  16: }

Wyświetlanie dysków:

   1: //C#
   2: // Create a scope to identify the computer to query
   3: ManagementScope scope = new ManagementScope(@"\\localhost\root\cimv2");
   4: scope.Connect();
   5: // Create a query for operating system details
   6: ObjectQuery query =
   7: new ObjectQuery("SELECT * FROM Win32_LogicalDisk");
   8: // Perform the query
   9: ManagementObjectSearcher searcher =
  10: new ManagementObjectSearcher(scope, query);
  11: ManagementObjectCollection queryCollection = searcher.Get();
  12: // Display the data from the query
  13: foreach (ManagementObject m in queryCollection)
  14: {
  15: // Display the remote computer information
  16: Console.WriteLine("{0} {1}", m["Name"].ToString(),
  17: m["Description"].ToString());
  18: }

 

Czekanie za zdarzenia WMI

Możemy oczywiście reagować na zdarzenia WMI które są wywoływane przez zmiany w eksploatacji
statusu systemu poprzez tworzenie instancji WqlEventQuery. Aby utworzyć instancje klasy WqlEventQuery musimy przekazać w jej konstruktorze nazwę klasy zdarzenia, zapytanie przerwania oraz stanu. Następnie przy pomocy WqlEventQuery tworzymy instancje klasy ManagementEventWatcher. Wywołamy w niej metode WaitForNextEvent którą wykorzystamy do przechwytu utworzenia nowego zdarzenia. Poniższy kod pokazuje utworzenie zapytania WQL które w razie wykrycia nowego procesu informacje o nim.

   1: //C#
   2: // Create event query to be notified within 1 second of a change
   3: // in a service
   4: WqlEventQuery query = new WqlEventQuery("__InstanceCreationEvent",
   5: new TimeSpan(0, 0, 1),
   6: "TargetInstance isa \"Win32_Process\"");
   7: // Initialize an event watcher and subscribe to events that match this query
   8: ManagementEventWatcher watcher = new ManagementEventWatcher(query);
   9: // Block until the next event occurs
  10: ManagementBaseObject e = watcher.WaitForNextEvent();
  11: // Display information from the event
  12: Console.WriteLine("Process {0} has been created, path is: {1}",
  13: ((ManagementBaseObject)e["TargetInstance"])["Name"],
  14: ((ManagementBaseObject)e["TargetInstance"])["ExecutablePath"]);
  15: // Cancel the subscription
  16: watcher.Stop();

 

Reagowanie na zdarzenia WMI przy pomocy Event Handler

Aby zareagować na zdarzenie WMI nasz EventHandler musi akceptować dwa parametry: parametr object i EventArrivedEventArgs. Poniższy kod pokazuje, jak obsługiwać zdarzenia WMI asynchronicznie.
Wykonuje dokładnie te same zadania, co kod w poprzednim przykładzie:

   1: //C#
   2: static void Main(string[] args)
   3: {
   4: ManagementEventWatcher watcher = null;
   5: EventReceiver receiver = new EventReceiver();
   6: // Create the watcher and register the callback
   7: watcher = GetWatcher(
   8: new EventArrivedEventHandler(receiver.OnEventArrived));
   9: // Watcher starts to listen to the Management Events.
  10: watcher.Start();
  11: // Run until the user presses a key
  12: Console.ReadKey();
  13: watcher.Stop();
  14: }
  15: // Create a ManagementEventWatcher object.
  16: public static ManagementEventWatcher GetWatcher(
  17: EventArrivedEventHandler handler)
  18: {
  19: // Create event query to be notified within 1 second of a
  20: // change in a service
  21: WqlEventQuery query = new WqlEventQuery("__InstanceCreationEvent",
  22: new TimeSpan(0, 0, 1),
  23: "TargetInstance isa \"Win32_Process\"");
  24: // Initialize an event watcher and subscribe to events that
  25: // match this query
  26: ManagementEventWatcher watcher = new ManagementEventWatcher(query);
  27: // Attach the EventArrived property to
  28: // EventArrivedEventHandler method with the
  29: // required handler to allow watcher object communicate to
  30: // the application.
  31: watcher.EventArrived += new EventArrivedEventHandler(handler);
  32: return watcher;
  33: }
  34: // Handle the event and display the ManagementBaseObject
  35: // properties.
  36: class EventReceiver
  37: {
  38: public void OnEventArrived(object sender,
  39: EventArrivedEventArgs e)
  40: {
  41: // EventArrivedEventArgs is a management event.
  42: ManagementBaseObject evt = e.NewEvent;
  43: // Display information from the event
  44: Console.WriteLine("Process {0} has been created, path is: {1}",
  45: ((ManagementBaseObject)
  46: evt["TargetInstance"])["Name"],
  47: ((ManagementBaseObject)
  48: evt["TargetInstance"])["ExecutablePath"]);
  49: }
  50: }

Tyle na dzisiaj. Korzystając z okazji chciałbym Wam wszystkim życzyć wesołych, rodzinnych Świąt Bożego Narodzenia. Odpoczywajcie bo jest na to najlepszy czas…oczywiście nie od Naszej strony bo już w pierwszy dzień świąt nowy wpis. Trzymajcie się!!

Kolejna artykuł z serii to 70-536: Understanding CAS

Tagi: , , ,

Pingbacks and trackbacks (2)+

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading


Eastgroup.pl na facebooku