Using SWbemRefresher in delphi

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;

Related posts

Tags: ,

5 Responses to “Using SWbemRefresher in delphi”

  1. David says:

    Hi!

    Could you expand this example and show how could this be used to show all processes in a memo?

    Regards,
    David

    • ciuly says:

      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;

  2. 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.

  3. Xiao Guang says:

    objServicesCimv2 := GetObject(‘winmgmts:root\cimv2′);

    [DCC Error]Unmain.pas(87):E2010 Incompatible types:’HGDIOBJ’ and ‘string’

    • ciuly says:

      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.

Leave a Reply

This blog is kept spam free by WP-SpamFree.