Somebody asked me to help him get a working delphi code for SWbemRefresher. I obviously tried the first natural approach of using the WbemScripting_TLB unit but that didn’t work.
So, since I couldn’t get the early binding to work (using the interfaces and such) and since the VBS code from MSDN works (I previously tested it), I went with late binding just as VBS, which obviously worked. here’s the code:
http://msdn.microsoft.com/en-us/library/aa393838%28VS.85%29.aspx
function GetObject(Value: String): IUnknown;
// from russel: http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_20875677.html
var pUnk: IUnknown;
pmk: IMoniker;
pbc: IBindCtx;
cbEaten: LongInt;
clsid: TGUID;
begin
// Check value to determine if this is a programmatic id or a moniker
if (CLSIDFromProgID(PWideChar(WideString(Value)), clsid) = S_OK) then
begin
// Attempt to get the active object, clear the result on failure
if not(GetActiveObject(clsid, nil, result) = S_OK) then result:=nil;
end
else
begin
// Moniker name
if (CreateBindCtx(0, pbc) = S_OK) then
begin
if (MkParseDisplayName(pbc, StringToOleStr(Value), cbEaten, pmk) = S_OK) then
begin
// Attempt to bind the moniker, clear the result on failure
if not(BindMoniker(pmk, 0, IUnknown, result) = S_OK) then result:=nil;
// Release the moniker
pmk:=nil;
end;
// Release the bind context
pbc:=nil;
end;
end;
end;
procedure getprocesslate;
var objServicesCimv2,
objServicesDefault,
objRefreshableItem1,
objRefreshableItem2,
RefreshableItem,
objRefresher:OleVariant;
i:integer;
begin
// Get namespace connections
objServicesCimv2 := GetObject('winmgmts:root\cimv2');
objServicesDefault := GetObject('winmgmts:root\default');
// Create a refresher object
objRefresher := CreateOleObject('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.
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.
objRefreshableItem2 := objRefresher.AddEnum(objServicesCimv2, 'Win32_Process').ObjectSet;
// Display number of items in refresher and update the data.
ShowMessage('Number of items in refresher = ' +inttostr( objRefresher.Count));
objRefresher.Refresh;
// Iterate through the refresher. SWbemRefreshable
// Item.IsSet checks for whether the item is an enumerator.
for i := 1 to objRefresher.Count do
begin
RefreshableItem:=objRefresher.Item(i);
if RefreshableItem.IsSet then
ShowMessage('Item with index ' + IntToStr(RefreshableItem.Index) +
' is an enumerator containing ' + IntToStr(RefreshableItem.ObjectSet.Count) + ' processes')
else
ShowMessage('Item with index ' + IntToStr(RefreshableItem.Index) +
' is a single object containing WMI version ' + objRefreshableItem1.VersionCurrentlyRunning);
end;
end;
Hi!
Could you expand this example and show how could this be used to show all processes in a memo?
Regards,
David
well, there is really not much to explain. The demo is the exact translation of the MSDN example. what you probably need is to read up on late binding. I wouldn’t be able to refer you a good article on the subject so just google for “delphi late binding” (no quotes). the one on delphi.about.com seems ok, but then it really depends on your level of experience if it’s too abstract or lacking info.
since I really don’t have time to make full-blown demos working out of the box and usable out of the box, here is a modification of the Running Processes WMI example which you can find on my site in the delphi/WMI section. basically, I copy pasted the listbox-population code into the msdn translation.
no type checking is done anywhere (well, only at the variant to interface assignment there should be done a check. after casting to IUnknown, one should test if it supports the ISWbemObjectSet interface or not and act accordingly)
adapting it should be trivial. yeah, another 5 minutes I couldn’t spend on it 😛
procedure getprocesslate;
var objServicesCimv2,
objServicesDefault,
objRefreshableItem1,
objRefreshableItem2,
RefreshableItem,
objRefresher:OleVariant;
i, j:integer;
ObjectSet: ISWbemObjectSet;
SObject: ISWbemObject;
propSet : ISWbemPropertySet;
SProp: ISWbemProperty;
propEnum,
Enum: IEnumVariant;
tempObj1,
tempObj2,
spropvalue: OleVariant;
Count,
Value: Cardinal;
sValue: String;
tmp:string;
begin
// Get namespace connections
objServicesCimv2 := GetObject('winmgmts:root\cimv2');
objServicesDefault := GetObject('winmgmts:root\default');
// Create a refresher object
objRefresher := CreateOleObject('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.
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.
objRefreshableItem2 := objRefresher.AddEnum(objServicesCimv2, 'Win32_Process').ObjectSet;
// Display number of items in refresher and update the data.
ShowMessage('Number of items in refresher = ' +inttostr( objRefresher.Count));
objRefresher.Refresh;
// Iterate through the refresher. SWbemRefreshable
// Item.IsSet checks for whether the item is an enumerator.
for j := 1 to objRefresher.Count do
begin
RefreshableItem:=objRefresher.Item(j);
if RefreshableItem.IsSet then
begin
ShowMessage('Item with index ' + IntToStr(RefreshableItem.Index) +
' is an enumerator containing ' + IntToStr(RefreshableItem.ObjectSet.Count) + ' processes');
form1.ListBox1.Clear;
ObjectSet:=ISWbemObjectSet(IUnknown(RefreshableItem.ObjectSet));
Enum := (ObjectSet._NewEnum) as IEnumVariant;
try
i:=0;
while (Enum.Next(1, tempObj1, Value) = S_OK) do
try
tmp:='';
SObject := IUnknown(tempObj1) as SWBemObject;
try
propSet := SObject.Properties_;
propEnum := (propSet._NewEnum) as IEnumVariant;
try
while (propEnum.Next(1, tempObj2, Value) = S_OK) do
try
SProp := IUnknown(tempObj2) as SWBemProperty;
if (SProp.Name'Name') and (SProp.Name'ProcessId')
and (SProp.Name'ParentProcessId') and (SProp.Name'CreationDate') and (SProp.Name'ExecutablePath') then
continue;
// now get the value of the property
sValue := '';
spropvalue:=SProp.Get_Value;
try
if VarIsNull(spropvalue) then
sValue := ''
else
case SProp.CIMType of
wbemCimtypeSint8, wbemCimtypeUint8, wbemCimtypeSint16, wbemCimtypeUint16,
wbemCimtypeSint32, wbemCimtypeUint32, wbemCimtypeSint64:
sValue := IntToStr(spropvalue);
wbemCimtypeString, wbemCimtypeUint64:
if VarIsArray(spropvalue) then
begin
if VarArrayHighBound(spropvalue, 1) > 0 then
for Count := 1 to VarArrayHighBound(spropvalue, 1) do
sValue := sValue + ' ' + spropvalue[Count];
end
else
sValue := spropvalue;
wbemCimtypeDatetime:sValue:=spropvalue//DateTimeToStr(spropvalue)
else
Exception.Create('Unknown type');
end;
finally
spropvalue:=unassigned;
end;
case i of
0:tmp:=tmp+' [CreationDate='+sValue+']';
1:tmp:=tmp+' [Path='+sValue+']';
2:tmp:=sValue+tmp;
3:tmp:=tmp+' [Parent PID='+sValue+']';
4:tmp:=tmp+' [PID='+sValue+']';
end;
i:=(i+1) mod 5;
if i=0 then
form1.ListBox1.items.add(tmp);
finally
sProp:=nil;
tempObj2:=NULL;
end;
finally
propEnum:=nil;
propSet:=nil;
end;
finally
sObject:=nil;
end;
finally
tempObj2:=NULL;
end;
finally
enum.Reset;
enum:=nil;
end;
end else
ShowMessage('Item with index ' + IntToStr(RefreshableItem.Index) +
' is a single object containing WMI version ' + objRefreshableItem1.VersionCurrentlyRunning);
end;
end;
I am really impressed with the content of your blog. It is easy to determine that you are fervent about your writing. If I had your writing ability, I know I would be successful. I have bookmarked your site and look forward to more updates.
objServicesCimv2 := GetObject(‘winmgmts:root\cimv2′);
[DCC Error]Unmain.pas(87):E2010 Incompatible types:’HGDIOBJ’ and ‘string’
you’ll need to check your uses clause and declarations. objServicesCimv2 is of type variant in my code so definitely not HGDIOBJ and GetObject returns IInterface not string.
OR, GetObject gets a string parameter and not a HGDIOBJ.
So, in order to track it down, do the following:
– put editor cursor after “GetObject(” (with the bracket) and before < <'winmgmts>> and press ctrl+space. this will show you the parameter(s) expected by GetObject function. You should see there “Value: String”. If that is not the case, then your problem is that you did not use the GetObject function provided in the article.
If you did, then objServicesCimv2 is not declared as variant but something else, but in this case you should get an error like ‘Incompatible types: ‘HGDIOBJ’ and ‘IIUnknown’
My bet is that you are using a different GetObject function than the one in the article.