WMI - Sprawdzanie istnienia klasy

0

Pytanie do specjalistów usługi WMI z poziomu Delphi (Windows Management Instrumentation).

Program, który staram się ukończyć używa zapytań WMI do pobierania danych o kompie.
Używam raptem kilka klas z przestrzeni nazw "root\CIMV2" (na przykład Win32_OperatingSystem, Win32_PnPEntity, etc...).

Pytanie. Czy istnieje prosta metoda sprawdzenia czy dana klasa istnieje w danej przestrzeni klas?
Na przykład: Używam klasy Win32_OperatingSystem z "root\CIMV2". Istnieje możliwość, że akurat ta klasa nie jest dostępna na komputerze użytkownika. Jak to sprawdzić?

Używam takiego rozwiązania, że pobieram WSZYSTKIE dostępne klasy i potem sprawdzam, czy dana klasa znajduje się na liście. Wykonanie poniższego kodu zajmuje na
moim PC ponad 1s. Jest to zbyt długi czas...

Zatem, znacie może lepszy sposób?

Kod:

var
   WMI_ClassesList : TStringList; // List with supported classes

// ...
   // Get Available WMI Classes
   WMI_GetAvailableWMI_Classes(WMI_ClassesList); // Get classes into list


procedure WMI_GetAvailableWMI_Classes(const AList: TStringList); // This procedure takes to much time!
var
   objSWbemLocator   : OleVariant;
   objWMIService     : OleVariant;
   colItems          : OleVariant;
   colItem           : OleVariant;
begin
   AList.Clear;
   try
      objSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      objWMIService := objSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
      colItems := objWMIService.SubclassesOf();

      AList.BeginUpdate;
      for colItem in GetOleVariantEnum(colItems) do
         begin
            AList.Add(colItem.Path_.Class);
         end;
      AList.EndUpdate;

   finally
      objSWbemLocator:= Unassigned;
      objWMIService := Unassigned;
      colItem := Unassigned;
      colItems := Unassigned;
   end;
end;

// ...

   // Check If Class (Win32_OperatingSystem) Exists in NameSpace (root\CIMV2)
   if WMI_ClassesList .IndexOf('Win32_OperatingSystem') <> -1 then
      begin
         
      end


Chętnie wysłucham pomysłów...
-Pawel

0

Przekaż szukaną klasę do funkcji i zrób early exit zamiast dodawać do listy - powinno zaoszczędzić trochę czasu jeśli sprawdzasz tylko jedną klasę.
1s to aż tak dużo? Robisz to pewnie tylko jednorazowo.

Jeśli brak tej klasy to wyjątkowa sytuacja to możesz po prostu próbować z niej skorzystać i rzucić... wyjątek

0

na samym WMI się nie znam ale po pierwsze do TStringList możesz dać sorted na true i wtedy duplicated na ignore abyś miał tylko unikalne posortowane nazwy klas. Wtedy indexof powinien nieco przyspieszyć. Jeśli jednak to nie pomoże to spróbuj TDictionary zamiast TStringList i metodą TryGetValue dowiesz się czy istnieje ;)

0

zrób ten odczyt w osobnym wątku

0

Hmm, to chyba niedobre rozwiązanie... ponieważ ta procedura musi być wykonana przed każdą inną - i tak wszystko musi poczekać. Więc osobny watek nic tu nie da.

0

Podsumuję moje próby...

  1. Nie iterowanie po wszystkich klasach, a użycie wyjątku (jeśli klasa nie istnieje) nie działa. Aplikacja się wiesza (Access Violation). Nie wiedzieć czemu, obsługa wyjątku try, except nie działa... pewnie coś z interfejsami com... nie znam się.
  2. Przejście całej pętli (po wszystkich klasach) daje zbliżony czas do przejścia po klasach, których używam (27 z 1209, po upewnieniu się , że moje istnieją, Break). Zatem nie opłaca się.

Wniosek. Zostawiłem jak jest. Jakoś muszę żyć z tą niecałą sekundą (średnio 0.8 s). Ale, co dziwne, pierwsze wywołanie tej funkcji (iterującej po klasach WMI danej przestrzenii nazw) zawsze trwa dłużej, czasem nawet 5s... może to antywirus...

-Pawel

0

Ja takie coś stosuję.

if Assigned(zmienna_klasy) 
then 
showmessage('klasa istnieje') 
else 
showmessage('brak klasy');
0

Koniec końców, zrobiłem mały system pamięci podręcznej.
Pierwsze uruchomienie odpala funkcję, która sprawdza wszystkie dostępne klasy WMI. Te które używam zapisuję do pliku.
Każde kolejne odpalenie programu korzysta z danych pliku. To czy użytkownik nie zmienił komputera sprawdzam poprzez dodanie identyfikatora komputera (który składa się z kilku danych, typu nazwa komputera, użytkownika, rozmiar partycji), który jest sprawdzany przy uruchomieniu programu.
Jeśli identyfikator jest taki sam (czyli program odpalany na znanej konfiguracji) to wczytuje dane z pamięci podręcznej, jeśli nie to wczytuje wszystkie klasy...
Dzięki temu trwa to o wiele krócej. Zazwyczaj czas wyszukania wszystkich klas trwa około 1s... niestety, często (jak program nie jest odpalany jakiś czas) trwa to o wiele dłużej.... 5, 7s (rejestrowałem nawet 11s! Być może jest tak z powodu AV, w końcu zmieniam wciąż exe na inny...). Opcja z pamięcią podręczną skraca ten czas do milisekund....
Dzięki za sugestie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1