![]() |
Re: WMI: Refresh von Daten
Hi
Zitat:
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:
1. Zuerst erstellen wir uns ein Refresher-Objekt und weisen der Eigenschaft AutoReconnect einen entsprechenden
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; 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:
1. Nachdem der Refresher mittels der Methode Refresh die Werte aktualisiert hat erfolgt der
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; 2. Abruf der Werte über eine Enumeration. 3. Anschließend erfolgt die Ausgabe selbiger.
Delphi-Quellcode:
Da wir das ISWbemRefreshableItem zwischen gespeichert haben können wir dies mittels Remove
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; wieder vom Refresher gezielt entfernen, bzw. mittels DeleteAll alle entfernen.
Delphi-Quellcode:
Das war es.
procedure TMainForm.btnRemoveClick(Sender: TObject);
begin WmiRefresher.Remove(WmiRefreshItem.Index, 0); end; 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:
Entwickelt mit Delphi 7.
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. Gruß |
Re: WMI: Refresh von Daten
Hi,
ist WbemScript identisch mit WbemScripting_TLB.pas - wenn nicht, woher bekommt man es? |
Re: WMI: Refresh von Daten
Hi vielen Dank für die ausführliche Erklärung! Ich werde mich morgen bzw. nachher damit beschäftigen.
Gruß Profiler |
Re: WMI: Refresh von Daten
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:
Der Aufruf erfolgt folgendermaßen:
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;
Delphi-Quellcode:
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:
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;
Delphi-Quellcode:
in RefresherCreate eine EOleException mit dem Hinweis: "Allgemeiner Fehler"
_wmiRefreshItem := _wmiRefresher.AddEnum(ISWbemServicesEx(Services), _From, 0, nil);
Eine Idee, woran das liegen kann? Gruß Profiler |
Re: WMI: Refresh von Daten
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ß |
Re: WMI: Refresh von Daten
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; |
Re: WMI: Refresh von Daten
Ja, so etwas meinte ich.
Aber zu spät, habe etwas improvisiert und speichere dies
Delphi-Quellcode:
in einer ObjectList zwischen.
TWmiValue = class
public Name : WideString; Value: WideString; end; Momentan kommt hier schon ein Fehler vom Typ 'Nicht Unterstützt'
Delphi-Quellcode:
Mal sehen was es darüber bei Google gibt.
WmiRefreshItem := WmiRefresher.AddEnum(ISWbemServicesEx(Services), 'MSAcpi_ThermalZoneTemperature', 0, nil);
|
Re: WMI: Refresh von Daten
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: ![]() 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? |
Re: WMI: Refresh von Daten
Hi,
ich glaube schon, das ich die Parameter richtig übergeben habe. Erst recht, da dieser '3'-Zeiler(VB2K5) den gleichen Fehler meldet. Zitat:
Mal schauen, was da noch so kommt. |
Re: WMI: Refresh von Daten
Also ich bekomms irgendwie net hin, kommt immer der gleiche Fehler :/
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:19 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz