![]() |
WMI: Refresh von Daten
Hallo,
ich möchte gern die Temperatur des Prozessors per WMI bekommen, was auch bereits funktioniert, nur sind die Daten veraltet. Ich habe in der MSDN ein bisschen rumgelesen und erfahren, dass es eine Refresh-Funktion gibt. Dort ist auch ein Beispielcode beschrieben, aber ich bekomme ihn nicht in Delphi umgesetzt. Könnt ihr mir dabei Helfen? Hier der Beispielcode:
Code:
Wie muss dieses Beispiel in Delphi umgesetzt werden?
' Get namespace connections
set objServicesCimv2 = GetObject("winmgmts:root\cimv2") set objServicesDefault = GetObject("winmgmts:root\default") ' Create a refresher object set objRefresher = CreateObject("WbemScripting.SWbemRefresher") ' Add a single object (SWbemObjectEx) to the refresher. The "@" ' is used because _CIMOMIdentification is a singleton class- only ' one instance exists. Note that the ' SWbemRefreshableItem.Object property must ' be specified or the SWbemRefresher.Refresh call will fail. set objRefreshableItem1 = objRefresher. _ Add (objServicesDefault, "__CIMOMIdentification=@").Object ' Add an enumerator (SWbemObjectSet object) ' to the refresher. Note that the ' SWbemRefreshableItem.ObjectSet property ' must be specified or the SWbemRefresher.Refresh call will fail. set objRefreshableItem2 = objRefresher. _ AddEnum (objServicesCimv2, "Win32_Process").ObjectSet ' Display number of items in refresher and update the data. MsgBox "Number of items in refresher = " & objRefresher.Count objRefresher.Refresh ' Iterate through the refresher. SWbemRefreshable ' Item.IsSet checks for whether the item is an enumerator. for each RefreshableItem in objRefresher if RefreshableItem.IsSet then MsgBox "Item with index " & RefreshableItem.Index &_ " is an enumerator containing "_ & RefreshableItem.ObjectSet.Count & " processes" else MsgBox "Item with index " & RefreshableItem.Index _ & " is a single object containing WMI version "_ & objRefreshableItem1.VersionCurrentlyRunning end if next Gruß Profiler |
Re: WMI: Refresh von Daten
|
Re: WMI: Refresh von Daten
Hallo,
danke für die rasche Antwort! Die MAGWMI uni habe ich schon versucht, die Funktionen dort geben mir auch nur die nicht aktuellen Werte zurück. Eine Refresher ist dort leider auch nicht verwendet wurden. Hast du sonst noch eine Idee oder kann mir sonst noch jemand bei dem beschriebenen Problem helfen? Gruß Profiler |
Re: WMI: Refresh von Daten
schau mal hier..vielleicht nen Ansatz
![]() |
Re: WMI: Refresh von Daten
Ich habe bereits ein Tool geschrieben, was mir die Temperaturen aus dem Embedden Controller von IBM ThinkPad Notebooks auslesen kann, aber ich würde gerne noch das Auslesen per WMI hinbekommen. Das Auslesen funktioniert ja bereis, aber wenn ich mir die Temperaturen per WMI hole, dann sind die nicht aktuell, wenn ich diese mit denen aus dem EC oder von anderen Tools vergleiche. Ich muss also wissen, wie das mit dem Refresher funktioniert.
Gruß Profiler PS: Mein Tool findet ihr unter ![]() |
Re: WMI: Refresh von Daten
Hallo Profiler,
ich gehe mal davon aus, dass du die 'Microsoft WMI Scripting V1.2 Library' als Typlib verwendest. In diesem guten Stück gibt es ISWbemRefresher, ISWbemRefresher und ISWbemObjectEx. Gruß |
Re: WMI: Refresh von Daten
Ja in dieser Annahme gehst du richtig. Ich weiss auch, dass es dort solche Refreshertypen und Interfaces gibt, aber ich bekomme es einfach nicht hin, vielleicht kannst du mir ein Beispiel zeigen, wie ich einen Wert refreshe?
Ein Objekt von ISWbemObjectEx sozusagen hat ja eine Refresh_(...) - Funktion, nur wie bekomme ich den WMI-Wert in solch ein Objekt? Ich finde nur Funktionen, die mir ein ISWbemObject zurückliefern, welche die Refresh_ - Funktion nicht implementiert :( Gruß Profiler |
Re: WMI: Refresh von Daten
Hi Profiler,
liest du dir eigentlich Deine eigenen Beispiele durch?! Steht doch alles drin, ist zwar VB, aber alles da. Gruß |
Re: WMI: Refresh von Daten
Zitat:
er wollte ja auch eine Hilfe zur Umstellung von VB nach Delphi!! :gruebel: |
Re: WMI: Refresh von Daten
Hi Der.Kaktus,
genauso sieht es aus! Das Beispiel ist direkt aus der MSDN und wird so wohl auch funktionieren, aber ich bekomme es nicht in Delphi umgesetzt, dabei bräuchte ich eure Hilfe! Gruß Profiler |
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 14:24 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-2025 by Thomas Breitkreuz