AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

WMI: Refresh von Daten

Ein Thema von Profiler · begonnen am 27. Mär 2008 · letzter Beitrag vom 3. Apr 2008
Antwort Antwort
Seite 2 von 2     12   
Alter Mann

Registriert seit: 15. Nov 2003
Ort: Berlin
934 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#11

Re: WMI: Refresh von Daten

  Alt 30. Mär 2008, 19:02
Hi

Zitat:
ich möchte gern die Temperatur des Prozessors per WMI bekommen, was auch bereits funktioniert...
Nach dem Spruch bin ich davon ausgegangen das er es kann.

Was das Beispiel allerdings bewirken soll ist mir ein wenig unklar.
Gesetzt den Fall, das bereits eine WMI-Abfrage vorhanden ist, dann braucht
sie doch nur in periodischen Abständen wiederholt werden und die Werte sind aktuell.
Etwas anderes passiert im Beispiel auch nicht, die Aktualisierung erfolgt
durch erneuten Aufruf der Methode Refresh.

Zur Umsetzung:

Man nehme eine neue Anwendung, lege 3 Buttons, 2 Labels und eine Checkbox drauf.
Die Anordnung ist frei, es sollte auf die Länge der Texte geachtet werden.


Delphi-Quellcode:
  TMainForm = class(TForm)
    btnRefresh : TButton;
    btnRefresherCreate: TButton;
    btnRemove : TButton;
    lbCount : TLabel;
    lbInfo : TLabel;
    cbAutoReconnect : TCheckBox;
    procedure btnRefreshClick(Sender: TObject);
    procedure btnRefresherCreateClick(Sender: TObject);
    procedure btnRemoveClick(Sender: TObject);
  private
    { Private-Deklarationen }
    WmiRefresher : ISWbemRefresher;
    WmiRefreshItem : ISWbemRefreshableItem;
  public
    { Public-Deklarationen }
  end;
1. Zuerst erstellen wir uns ein Refresher-Objekt und weisen der Eigenschaft AutoReconnect einen entsprechenden
Wert zu, je nachdem ob die Verbindung zum WMI automatisch neu aufgebaut werden soll oder nicht.
2. Da die Funktion ISWbemRefresher.AddEnum einen gültigen Services benötigt, müssen wir uns denn nun besorgen.
3. Ist dies erfolgreich verlaufen, können wir nun über AddEnum den Services und die gewünschte Klasse übergeben.
Zurück bekommen wir ein Interface-Objekt vom Type ISWbemRefreshableItem. Dies benötigen wir, um es bei
bedarf auch wieder entfernen zu können.
4. Gleichzeitig wird die Anzahl der Einträge ausgegeben.

Delphi-Quellcode:
procedure TMainForm.btnRefresherCreateClick(Sender: TObject);
var
  Locator : ISWbemLocator;
  Services: ISWbemServices;
begin
  WmiRefresher := CoSWbemRefresher.Create; // 1.
  WmiRefresher.AutoReconnect := cbAutoReconnect.Checked;

  Locator := CoSWbemLocator.Create; // 2.
  Services:= Locator.ConnectServer('.', '', '', 'root\cimv2', '', '', 128, nil); // Wenn OS nicht XP dann 0, sonst 128
  if Services <> nil then
  begin
    WmiRefreshItem := WmiRefresher.AddEnum(ISWbemServicesEx(Services), 'Win32_Process', 0, nil); // 3.
    lbCount.Caption := 'refreshable Items: ' + IntToStr(WmiRefresher.Count); // 4.
  end;
end;
1. Nachdem der Refresher mittels der Methode Refresh die Werte aktualisiert hat erfolgt der
2. Abruf der Werte über eine Enumeration.
3. Anschließend erfolgt die Ausgabe selbiger.
Delphi-Quellcode:
procedure TMainForm.btnRefreshClick(Sender: TObject);
var
  ObjEnum : IEnumVariant;
  WMITmpObj : OleVariant;
  WmiRefItem : ISWbemRefreshableItem;
  Cnt : Cardinal;
begin
  WmiRefresher.Refresh(0); // 1.
  ObjEnum := (WmiRefresher._NewEnum) as IEnumVariant; // 2.
  while(ObjEnum.Next(1, WMITmpObj, Cnt) = S_OK) do
  begin
    WmiRefItem := IUnknown(WMITmpObj) as ISWbemRefreshableItem;
    if WmiRefItem.IsSet then
     lbInfo.Caption := 'Item with index ' + IntToStr(WmiRefItem.Index) + // 3.
                       ' is an enumerator containing ' +
                       IntToStr(WmiRefItem.ObjectSet.Count) +
                       ' proccess.'
     else
     lbInfo.Caption := 'Item with index ' + IntToStr(WmiRefItem.Index) +
                       ' is a single object';
  end;
end;
Da wir das ISWbemRefreshableItem zwischen gespeichert haben können wir dies mittels Remove
wieder vom Refresher gezielt entfernen, bzw. mittels DeleteAll alle entfernen.

Delphi-Quellcode:
procedure TMainForm.btnRemoveClick(Sender: TObject);
begin
  WmiRefresher.Remove(WmiRefreshItem.Index, 0);
end;
Das war es.

Es wird im diesen Beispiel die Anzeige der laufenden Prozesse angezeigt,
so das leicht die Funktionsfähigkeit überprüft werden kann.

Hier noch einmal alles zusammen:

Delphi-Quellcode:
unit frmMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, WbemScript, StdCtrls;

type
  TMainForm = class(TForm)
    btnRefresh: TButton;
    btnRefresherCreate: TButton;
    cbAutoReconnect: TCheckBox;
    lbCount: TLabel;
    lbInfo: TLabel;
    btnRemove: TButton;
    procedure btnRefreshClick(Sender: TObject);
    procedure btnRefresherCreateClick(Sender: TObject);
    procedure btnRemoveClick(Sender: TObject);
  private
    { Private-Deklarationen }
    WmiRefresher : ISWbemRefresher;
    WmiRefreshItem : ISWbemRefreshableItem;
  public
    { Public-Deklarationen }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

uses ActiveX;

procedure TMainForm.btnRefreshClick(Sender: TObject);
var
  ObjEnum : IEnumVariant;
  WMITmpObj : OleVariant;
  WmiRefItem : ISWbemRefreshableItem;
  Cnt : Cardinal;
begin
  WmiRefresher.Refresh(0);
  ObjEnum := (WmiRefresher._NewEnum) as IEnumVariant;
  while(ObjEnum.Next(1, WMITmpObj, Cnt) = S_OK) do
  begin
    WmiRefItem := IUnknown(WMITmpObj) as ISWbemRefreshableItem;
    if WmiRefItem.IsSet then
     lbInfo.Caption := 'Item with index ' + IntToStr(WmiRefItem.Index) +
                       ' is an enumerator containing ' +
                       IntToStr(WmiRefItem.ObjectSet.Count) +
                       ' proccess.'
     else
     lbInfo.Caption := 'Item with index ' + IntToStr(WmiRefItem.Index) +
                       ' is a single object';
  end;
end;

procedure TMainForm.btnRefresherCreateClick(Sender: TObject);
var
  Locator : ISWbemLocator;
  Services: ISWbemServices;
begin
  WmiRefresher := CoSWbemRefresher.Create;
  WmiRefresher.AutoReconnect := cbAutoReconnect.Checked;

  Locator := CoSWbemLocator.Create;
  Services:= Locator.ConnectServer('.', '', '', 'root\cimv2', '', '', 128, nil); // Wenn OS nicht XP dann 0, sonst 128
  if Services <> nil then
  begin
    WmiRefreshItem := WmiRefresher.AddEnum(ISWbemServicesEx(Services), 'Win32_Process', 0, nil);
    lbCount.Caption := 'refreshable Items: ' + IntToStr(WmiRefresher.Count);
  end;
end;

procedure TMainForm.btnRemoveClick(Sender: TObject);
begin
  WmiRefresher.Remove(WmiRefreshItem.Index, 0);
end;

end.
Entwickelt mit Delphi 7.

Gruß
  Mit Zitat antworten Zitat
hathor
(Gast)

n/a Beiträge
 
#12

Re: WMI: Refresh von Daten

  Alt 30. Mär 2008, 21:59
Hi,

ist WbemScript identisch mit WbemScripting_TLB.pas - wenn nicht, woher bekommt man es?
  Mit Zitat antworten Zitat
Profiler

Registriert seit: 30. Dez 2006
14 Beiträge
 
#13

Re: WMI: Refresh von Daten

  Alt 31. Mär 2008, 00:49
Hi vielen Dank für die ausführliche Erklärung! Ich werde mich morgen bzw. nachher damit beschäftigen.

Gruß
Profiler
  Mit Zitat antworten Zitat
Profiler

Registriert seit: 30. Dez 2006
14 Beiträge
 
#14

Re: WMI: Refresh von Daten

  Alt 2. Apr 2008, 16:07
Hi,

ich habe mich jetzt schon mehrere Tage damit beschäftigt, aber irgendwie will es nicht richtig funktionieren. Ich habe mir folgende Klasse gebaut:

Delphi-Quellcode:
  TwmiInfo = class(TObject)
  private
    _Select, _From, _Root: String;
    _Instances: TList;
    _wmiRefresher : ISWbemRefresher;
    _wmiRefreshItem : ISWbemRefreshableItem;
    _refreshTime: Cardinal;
    constructor Create(Root, Select, From: String);
    procedure RefresherCreate;
  public
    procedure getInfo;
    procedure refresh;
    function getInstances: TList;
    property refreshTime: Cardinal read _refreshTime;
  end;
...
Delphi-Quellcode:
constructor TwmiInfo.Create(Root, Select, From: String);
begin
  Inherited Create;
  _Root := Root;
  _Select := Select;
  _From := From;
  _Instances := TList.Create;
  RefresherCreate;
end;

procedure TwmiInfo.RefresherCreate;
var
  Locator : ISWbemLocator;
  Services: ISWbemServices;
begin
  _wmiRefresher := CoSWbemRefresher.Create;
  _wmiRefresher.AutoReconnect := True;

  Locator := CoSWbemLocator.Create;
  Services:= Locator.ConnectServer('.', _Root, '', '', '', '', 128, nil); // Wenn OS nicht XP dann 0, sonst 128
  if Services <> nil then
  begin
    _wmiRefreshItem := _wmiRefresher.AddEnum(ISWbemServicesEx(Services), _From, 0, nil);
  end;
end;

function TwmiInfo.getInstances: TList;
begin
  if _Instances.Count = 0 then
    raise NoInstancesFound.Create('getInstances');
  Result := _Instances;
end;

procedure TwmiInfo.getInfo;
var
  wmiLocator: TSWbemLocator;
  wmiServices: ISWbemServices;
  aObjSet : ISWbemObjectSet;
  aNVSDummy : IDispatch;
  Enum, propEnum : IEnumVARIANT;
  vOut : OleVariant;
  dwRetrieved : LongWord;
  wmiProp: SWBemProperty;
  wmiObject: SWBemObject;
  lwValue: LongWord;
  inst: TwmiInstance;
begin
  _Instances.Clear;
  wmiLocator := TSWbemLocator.Create(nil);
  wmiServices := wmiLocator.ConnectServer('.',_Root,'','','','',128, nil);
  aObjSet := wmiServices.ExecQuery('SELECT '+_Select+' FROM '+_From, 'WQL', 0,
    aNVSDummy);
  if aObjSet.Count = 0 then begin
    raise NoInstancesFound.Create('SELECT '+_Select+' FROM '+_From);
    exit;
  end;
  Enum := aObjSet._NewEnum as IEnumVARIANT;
  while Enum.Next(1, vOut, dwRetrieved) = S_OK do begin
    wmiObject := IUnknown(vOut) as SWBemObject;
    inst := TwmiInstance.Create;
    propEnum := (wmiObject.Properties_._NewEnum) as IEnumVariant;
    while (propEnum.Next (1, vOut, lwValue) = S_OK) do begin
      wmiProp := IUnknown(vOut) as SWBemProperty;
      inst.PropName.Add(VarToStr(wmiProp.Name));
      inst.PropValue.Add(VarToStr(wmiProp.Get_Value));
    end;
    _Instances.Add(inst);
  end;
end;

procedure TwmiInfo.refresh;
var
  ObjEnum : IEnumVariant;
  WMITmpObj : OleVariant;
  WmiRefItem : ISWbemRefreshableItem;
  Cnt : Cardinal;
  aObjSet : ISWbemObjectSet;
  Enum, propEnum : IEnumVARIANT;
  vOut : OleVariant;
  dwRetrieved : LongWord;
  wmiProp: SWBemProperty;
  wmiObject: SWBemObject;
  lwValue: LongWord;
  inst: TwmiInstance;
begin
  _wmiRefresher.Refresh(0);
  ObjEnum := (_wmiRefresher._NewEnum) as IEnumVariant;
  while(ObjEnum.Next(1, WMITmpObj, Cnt) = S_OK) do
  begin
    WmiRefItem := IUnknown(WMITmpObj) as ISWbemRefreshableItem;
    if WmiRefItem.IsSet then begin
  _Instances.Clear;
  aObjSet := WmiRefItem.ObjectSet;
  if aObjSet.Count = 0 then begin
    raise NoInstancesFound.Create('SELECT '+_Select+' FROM '+_From);
    exit;
  end;
  Enum := aObjSet.Get__NewEnum as IEnumVARIANT;
  while Enum.Next(1, vOut, dwRetrieved) = S_OK do begin
    wmiObject := IUnknown(vOut) as SWBemObject;
    inst := TwmiInstance.Create;
    propEnum := (wmiObject.Properties_._NewEnum) as IEnumVariant;
    while (propEnum.Next (1, vOut, lwValue) = S_OK) do begin
      wmiProp := IUnknown(vOut) as SWBemProperty;
      inst.PropName.Add(VarToStr(wmiProp.Name));
      inst.PropValue.Add(VarToStr(lwValue));
    end;
    _Instances.Add(inst);
  end;
    end;
  end;
  _refreshTime := GetTickCount;
end;
Der Aufruf erfolgt folgendermaßen:
Delphi-Quellcode:
function getTemperature(Index: Integer = 0): integer;
var
    wmiInfo: TwmiInfo;
    PropIndex: Integer;
begin
  result := 0;
  wmiInfo := TwmiInfo.Create('root\WMI', 'CurrentTemperature', 'MSAcpi_ThermalZoneTemperature');
  wmiInfo.getInfo;
  //[*]
  if Index >= wmiInfo.getInstances.Count then exit;
  PropIndex := TwmiInstance(wmiInfo.getInstances.Items[Index]).PropName.IndexOf('CurrentTemperature');
  Result := StrToInt(TwmiInstance(wmiInfo.getInstances.Items[Index]).PropValue.Strings[PropIndex]);
  Result := (Result div 10)-273;
end;
Soweit funktioniert es auch, wenn ich im Constructor NICHT RefresherCreate aufrufe, nur halt mit nicht aktuellen Werten, aber sobald ich dies tue (egal ob ich dann beim Aufruf noch die Refresh-Funktion aufrufe oder nicht - siehe[*]), fliegt in der Zeile:
    _wmiRefreshItem := _wmiRefresher.AddEnum(ISWbemServicesEx(Services), _From, 0, nil); in RefresherCreate eine EOleException mit dem Hinweis: "Allgemeiner Fehler"

Eine Idee, woran das liegen kann?

Gruß
Profiler
  Mit Zitat antworten Zitat
Alter Mann

Registriert seit: 15. Nov 2003
Ort: Berlin
934 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#15

Re: WMI: Refresh von Daten

  Alt 2. Apr 2008, 17:40
Hi

Ich bin mir nicht 100% sicher, aber ich glaube es liegt daran, das zweimal
hinter einander eine Verbindung zum WMI aufgebaut wird.
Speicher mal den Locator und Service zwischen und verwende diese für getInfo.

Ansonsten auf den ersten Blick schwer durchschaubar, könnte ich mal alles bekommen?

Gruß
  Mit Zitat antworten Zitat
Profiler

Registriert seit: 30. Dez 2006
14 Beiträge
 
#16

Re: WMI: Refresh von Daten

  Alt 2. Apr 2008, 17:56
Hi, erstmal danke für dein Einsatz bei diesem Thema

Das was ich gepostet habe ist alles was irgendwie was mit WMI zu tun hat, weil alles zu schicken würde nur mehr Aufwand für dich bedeuten und hätte glaube auch keinen Sinn. Der Fehler muss in dem geposteten Code liegen. Da ist die wmi-Klasse und die Funktion, die ich extern aufrufe, um an die Temperatur zu kommen.

Dass es an dem Doppelconnect liegt hatte ich mir auch schon gedacht, aber bis zum 2. Verbindungsversuch kommt er gar nicht. Ich erzeuge mir ein TwmiInfo-Objekt und dabei wird ja der Konstruktor aufgerufen und somit auch die TwmiInfo.RefresherCreate Prozedur und da kommt dann auch schon der Fehler nach dem 1. Verbindungsversuch, welcher nichtmal fehlschlägt.

Hast du vielleicht noch eine Idee?

Gruß
Profiler

PS: Evtl. hilft dir noch folgender Code, welcher in der gleichen Unit steht:
Delphi-Quellcode:
  // eigene Exceptions
  wmiException = class(Exception);
  NoInstancesFound = class(wmiException)
  public
    constructor Create(Query: String);
  end;

  // Instanzklasse für WMI-Daten
  TwmiInstance = class(TObject)
  private
    _PropName: TStringList;
    _PropValue: TStringList;
  public
    constructor Create;
    destructor Destroy; override;
    property PropName: TStringList read _PropName write _PropName;
    property PropValue: TStringList read _PropValue write _PropValue;
  end;

// ...

constructor NoInstancesFound.Create(Query: String);
begin
  Inherited Create('Keine WMI-Daten gefunden! '+Query);
end;

constructor TwmiInstance.Create;
begin
  Inherited Create;
  _PropName := TStringList.Create;
  _PropValue := TStringList.Create;
end;

destructor TwmiInstance.Destroy;
begin
  if Assigned(_PropName) then _PropName.Free;
  if Assigned(_PropValue) then _PropValue.Free;
  Inherited Destroy;
end;
  Mit Zitat antworten Zitat
Alter Mann

Registriert seit: 15. Nov 2003
Ort: Berlin
934 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#17

Re: WMI: Refresh von Daten

  Alt 2. Apr 2008, 18:22
Ja, so etwas meinte ich.

Aber zu spät, habe etwas improvisiert und speichere dies
Delphi-Quellcode:
  TWmiValue = class
  public
    Name : WideString;
    Value: WideString;
  end;
in einer ObjectList zwischen.

Momentan kommt hier schon ein Fehler vom Typ 'Nicht Unterstützt'
WmiRefreshItem := WmiRefresher.AddEnum(ISWbemServicesEx(Services), 'MSAcpi_ThermalZoneTemperature', 0, nil); Mal sehen was es darüber bei Google gibt.
  Mit Zitat antworten Zitat
Profiler

Registriert seit: 30. Dez 2006
14 Beiträge
 
#18

Re: WMI: Refresh von Daten

  Alt 2. Apr 2008, 18:49
Evtl. unterstützt nicht jeder Rechner die 'MSAcpi_ThermalZoneTemperature'. Du kannst bei dir zum Test auch das Win32_Process wieder nehmen, das sollte ja analog funktionieren.
Um zu sehen was für WMI-Klassen bei dir unterstützt werden, kannst du auch einen WMI-Explorer nehmen oder z.b. das hier: WMI Code Creator 1.0

Gruß
Profiler

EDIT: Da fällt mir noch ein: hast du beachtet, dass 'Win32_Process' im Namespace 'root\CIMV2' und 'MSAcpi_ThermalZoneTemperature' in 'root\WMI' untergebracht ist?
  Mit Zitat antworten Zitat
Alter Mann

Registriert seit: 15. Nov 2003
Ort: Berlin
934 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#19

Re: WMI: Refresh von Daten

  Alt 2. Apr 2008, 19:04
Hi,

ich glaube schon, das ich die Parameter richtig übergeben habe.
Erst recht, da dieser '3'-Zeiler(VB2K5) den gleichen Fehler meldet.
Zitat:
Public Function GetCpuTemperature()
Dim Temperature As Double
Try
Dim TempSearcher As New Management.ManagementObjectSearcher("root\WMI", "SELECT * FROM MSAcpi_ThermalZoneTemperature")
For Each TempSensor As Management.ManagementObject In TempSearcher.Get()
Temperature = CDbl(TempSensor("CurrentTemperature"))
Temperature = (Temperature - 2732) / 10.0
Next
Catch err As Management.ManagementException
MessageBox.Show("Fehler: " & err.Message)
End Try
Return Temperature
End Function
Mit anderen Worten, in der MSDN kein Eintrag, immer die gleiche Fehlermeldung, da scheint etwas anderes Faul zu sein.

Mal schauen, was da noch so kommt.
  Mit Zitat antworten Zitat
Profiler

Registriert seit: 30. Dez 2006
14 Beiträge
 
#20

Re: WMI: Refresh von Daten

  Alt 3. Apr 2008, 23:43
Also ich bekomms irgendwie net hin, kommt immer der gleiche Fehler :/
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:13 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz