Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

[WMI] Queries...

Posted on 2004-11-04
11
Medium Priority
?
3,442 Views
Last Modified: 2012-06-27
I use this WMI query to get all running processes: select * from Win32_Process
But I would like to have something like: select * from Win32_Process order by Name

Of course, with WMI, the latter option just doesn't work, so I'm wondering if there's another way to tell the system to order the info in some particular order or do I have to sort it myself?

And no, I'm not using any WMI component set, just the wbemdisp.tlb type library. (Simply because I'm calling WMI from a simple console application. I don't want the additional VCL overhead included in my project.)

I assume the answer is: sort it yourself. But if someone can provide me an alternative solution purely based on the WMI type library then he (or she) will earn the points.
0
Comment
Question by:Wim ten Brink
  • 5
  • 5
11 Comments
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12494659
You can use an ActiveX Data Objects (ADO) disconnected Recordset to sort the data... no time to code it now, will find time later...
0
 
LVL 17

Author Comment

by:Wim ten Brink
ID: 12494791
Maybe. But then I need to import the ADO typelibrary in my application also. Makes it a bit more complicated but as long as I can avoid having to add VCL components, I'm happy. :-)
I do wonder if a WMI objectset is in any way compatible with an ADO recordset, though. If not, it's not an option because it just means I have to sort it myself again...
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12494888
well, (as far as I know) it is not compatible, if you were thinking of direct usage of ObjectSet as a RecordSet...

so, what I was actually suggesting was that you create an ADO disconnected R/set, loop thru your WMI and insert into your ADO... and from there you can use the SORT commands, etc... and you can do other more 'advanced' query with it.

Sorry if that made you happy for a while, only to make you disappointed again ;-)
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 17

Author Comment

by:Wim ten Brink
ID: 12495001
Am disappointed now. :-(
Actually, sorting the data myself isn't a real problem. If need be, I just dump the process names in a sorted stringlist, with a reference to the WMI objects linked to it. Thing is, sorting the data is not the problem. I just don't want to sort it myself. Too much trouble for something that should be quite easy... But apparantly it's not supported.
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12495002
Hmm... another idea is to export the WMI results to XML, then read it in using RecordSet... however, I only know of the IIS WMI objects that has the Export method... unsure about the others...
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12495013
> Actually, sorting the data myself isn't a real problem

Well, if you really do a loop and dump the whole chunk into a recordset instead, you can do sort by calling the ADO's Sort method, instead of implementing your own...
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12495022
Gosh... can't really help you more till tomorrow ... my harddisk crashed earlier on, and I'm replying this from a cyber cafe, lolx... wish me luck in fixing the hard disk, and I'll be back to you soon ;-)
0
 
LVL 17

Author Comment

by:Wim ten Brink
ID: 12495641
Good luck with your harddisk. I hope he gets better soon. ;-)
If not, let him rust in peace...
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 1000 total points
ID: 12498219
Workshop_Alex,

The answer to the original question is no. Perhaps MS will add it (to all of wmi) in the near future, as they have already done with the SMS wmi query processor. For SMS 2003, they call it "extended" WQL, and it supports the following additions to the WQL language:

DISTINCT
COUNT
JOIN
WHERE
SUBSTRING
ORDER BY
UPPER, LOWER, and DATEPART functions

...

Now....
 I know that you said above that sorting this manually is easy enough to do (true), But, what I am providing below is a means to perform the sorting for you in a dynamic fashion. By passing in the name of the property you wish to sort on, the utility function will create an interface object that extracts the interfaces from the object set and then orders them by the property value. The sorting is fairly intelligent, and is more than a simple string sort. For example, if the values are integer, then 2 will show before 10, etc.
The sorted set can then be walked using index and will return the ISWbemObject's in sorted order. While this is not "perfect" (wmi doing it for us), it does provide a generic and dynamic means of sorting objects in a set based on whatever property you wish to use.

Example of usage:

var  wmiServices:   ISWbemServices;
     wmiSorted:     ISWbemSortedSet;
     wmiProcess:    ISWbemObject;
     dwIndex:       Integer;
begin

  // Get the services object
  if (WmiGetObject('winmgmts:root\cimv2', ISWbemServices, wmiServices) = S_OK) then
  begin
     // Execute a query and sort the result based on a specific property
     wmiSorted:=WmiExecSorted(wmiServices.ExecQuery('select * from Win32_Process', 'WQL', wbemFlagReturnWhenComplete, nil), 'ProcessID');
     try
        // Do whatever with sorted list of objects
        for dwIndex:=0 to wmiSorted.Count-1 do
        begin
           wmiProcess:=wmiSorted.Item[dwIndex];
           try
              ShowMessage(String(wmiProcess.Properties_.Item('Name', 0).Get_Value));
           finally
              // Release interface
              wmiProcess:=nil;
           end;
        end;
     finally
        // Release interface
        wmiSorted:=nil;
     end;
     // Release interface
     wmiServices:=nil;
  end;

end;


The source code that supports the above example is listed below.

Hope this helps,
Russell


------------------------------------------

unit WmiUtil;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit           :  WmiUtil
//   Date           :  11.05.2004
//   Author         :  rllibby
//
//   Description    :  Set of utility routines for WMI handling
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows,
  SysUtils,
  Classes,
  ComObj,
  ActiveX,
  WbemScripting_Tlb;

////////////////////////////////////////////////////////////////////////////////
//   Sorting type record declaration
////////////////////////////////////////////////////////////////////////////////
type
  PObjSortEntry     =  ^TObjSortEntry;
  TObjSortEntry     =  packed record
     Obj:           IUnknown;
     Value:         OleVariant;
  end;

////////////////////////////////////////////////////////////////////////////////
//   ISWbemSortedSet interface declaration
////////////////////////////////////////////////////////////////////////////////
type
  ISWbemSortedSet   =  interface
     function       GetCount: Integer;
     function       GetItem(Index: Integer): ISWbemObject;
     property       Count: Integer read GetCount;
     property       Item[Index: Integer]: ISWbemObject read GetItem;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Utility routines
////////////////////////////////////////////////////////////////////////////////
function   WmiGetObject(Value: String; iidResult: TGUID; out Obj): HResult;
function   WmiExecSorted(ObjectSet: ISWbemObjectSet; OrderBy: String): ISWbemSortedSet;

implementation

function ObjEntrySortCompare(Item1, Item2: Pointer): Integer;
var  lpItem1:       PObjSortEntry;
     lpItem2:       PObjSortEntry;
begin

  // Get items
  lpItem1:=Item1;
  lpItem2:=Item2;

  // Check item1 for unassigned and null
  if (VarType(lpItem1^.Value) in [varEmpty, varNull]) then
  begin
     // Check second item
     if (VarType(lpItem2^.Value) in [varEmpty, varNull]) then
        result:=0
     else
        result:=-1;
  end
  // Check item2 for unassigned and null
  else if (VarType(lpItem2^.Value) in [varEmpty, varNull]) then
  begin
     // Check first item
     if (VarType(lpItem1^.Value) in [varEmpty, varNull]) then
        result:=0
     else
        result:=1;
  end
  else
  begin
     // Compare variants
     if (lpItem1^.Value < lpItem2^.Value) then
        result:=-1
     else if (lpItem1^.Value > lpItem2^.Value) then
        result:=1
     else
        result:=0;
  end;

end;

////////////////////////////////////////////////////////////////////////////////
//   Sorted class definition (not creatable externally)
////////////////////////////////////////////////////////////////////////////////
type
  TWbemSortedSet    =  class(TObject, IUnknown, ISWbemSortedSet)
  private
     // Private declarations
     FRefCount:     Integer;
     FSortList:     TInterfaceList;
     procedure      AddSorted(ObjectSet: ISWbemObjectSet; OrderBy: String);
  protected
     // Protected declarations
     function       QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
     function       _AddRef: Integer; stdcall;
     function       _Release: Integer; stdcall;
     function       GetCount: Integer;
     function       GetItem(Index: Integer): ISWbemObject;
  public
     // Public declarations
     constructor    Create(ObjectSet: ISWbemObjectSet; OrderBy: String);
     destructor     Destroy; override;
     property       Count: Integer read GetCount;
     property       Item[Index: Integer]: ISWbemObject read GetItem;
  end;

function TWbemSortedSet.QueryInterface(const IID: TGUID; out Obj): HResult;
begin

  // Get the requested interface
  if GetInterface(IID, Obj) then
     // Success
     result:=S_OK
  else
     // No such interface
     result:=E_NOINTERFACE;

end;
function TWbemSortedSet._AddRef: Integer;
begin

  // Increment the ref count
  result:=InterlockedIncrement(FRefCount);

end;

function TWbemSortedSet._Release: Integer;
begin

  // Decrement the ref count
  result:=InterlockedDecrement(FRefCount);

  // Destroy the component if the count reaches zero
  if (result = 0) then Destroy;

end;

procedure TWbemSortedSet.AddSorted(ObjectSet: ISWbemObjectSet; OrderBy: String);
var  pevEnum:       IEnumVariant;
     lpEntry:       PObjSortEntry;
     ovItem:        OleVariant;
     objSort:       TList;
     dwFetch:       LongWord;
begin

  // Create sorting list
  objSort:=TList.Create;

  // Resource protection
  try
     // Get enumerator from the set
     pevEnum:=ObjectSet._NewEnum as IEnumVariant;
     // Resource protection
     try
        // Enumerate the interfaces and add to the list
        while (pevEnum.Next(1, ovItem, dwFetch) = S_OK) do
        begin
           // Resource protection
           try
              // Create record for sorting
              lpEntry:=AllocMem(SizeOf(TObjSortEntry));
              // Save interface
              lpEntry^.Obj:=ovItem;
              // Get the value
              if (OrderBy = EmptyStr) then
                 // Use null value
                 lpEntry^.Value:=Null
              else
                 // Get the property value
                 lpEntry^.Value:=ISWbemObject(IDispatch(ovItem)).Properties_.Item(OrderBy, 0).Get_Value;
              // Add entry to list
              objSort.Add(lpEntry);
           finally
              // Clear variant
              ovItem:=Unassigned;
           end;
        end;
        // Sort the list
        objSort.Sort(ObjEntrySortCompare);
        // Now add to the interface list
        for dwFetch:=0 to Pred(objSort.Count) do
        begin
           // Get entry
           lpEntry:=objSort[dwFetch];
           // Add to list
           FSortList.Add(lpEntry^.Obj);
        end;
     finally
        // Release interface
        pevEnum:=nil;
     end;
  finally
     // Clear all items
     for dwFetch:=Pred(objSort.Count) downto 0 do
     begin
        // Get entry
        lpEntry:=objSort[dwFetch];
        // Release interface and clear variant
        lpEntry^.Obj:=nil;
        lpEntry^.Value:=Unassigned;
        // Free entry memory
        FreeMem(lpEntry);
     end;
     // Free the sorting list
     objSort.Free;
  end;

end;

function TWbemSortedSet.GetCount: Integer;
begin

  // Return the list count
  result:=FSortList.Count;

end;

function TWbemSortedSet.GetItem(Index: Integer): ISWbemObject;
begin

  // Return the item at the desired index
  result:=FSortList[Index] as ISWbemObject;

end;

constructor TWbemSortedSet.Create(ObjectSet: ISWbemObjectSet; OrderBy: String);
begin

  // Perform inherited
  inherited Create;

  // Set starting ref count
  FRefCount:=0;

  // Create list
  FSortList:=TInterfaceList.Create;

  // Add to the interface list in sorted order
  AddSorted(ObjectSet, OrderBy);

end;

destructor TWbemSortedSet.Destroy;
begin

  // Free the interface list
  FSortList.Free;

  // Perform inherited
  inherited Destroy;

end;

function WmiExecSorted(ObjectSet: ISWbemObjectSet; OrderBy: String): ISWbemSortedSet;
begin

  // Create sorted set interface
  result:=TWbemSortedSet.Create(ObjectSet, OrderBy);

end;

function WmiGetObject(Value: String; iidResult: TGUID; out Obj): HResult;
var  pmk:        IMoniker;
     pbc:        IBindCtx;
     cbEaten:    LongInt;
begin

  // Try to access the object using a moniker
  result:=CreateBindCtx(0, pbc);

  // Check result code
  if (result = S_OK) then
  begin
     // Parse the moniker display name
     result:=MkParseDisplayName(pbc, StringToOleStr(Value), cbEaten, pmk);
     // Check result code
     if (result = S_OK) then
     begin
        // Attempt to bind the moniker
        result:=BindMoniker(pmk, 0, iidResult, Obj);
        // Release the interface
        pmk:=nil;
     end;
     // Release interface
     pbc:=nil;
  end;

end;

end.
0
 
LVL 17

Author Comment

by:Wim ten Brink
ID: 12502551
Yep, One nice way to sort the objectset, rllibby. Real nice piece of code. But I had a simpler solution in mind already where I just use a dynamic array of SWbemObject on which I could do a simple QuickSort. I just need to enumerate the objects in the objectset and add them to the array. I've tested it and it works great. And it's a lot less complex too. ;-)

Still, if no better options are given, you'll be given the point(A) for this nice piece of code. Still, one thing... Your WmiGetObject() function is nice, but I just use this code:

const
  sQuery = 'select * from Win32_Process';
var
  Enum: IEnumVariant;
  I: Integer;
  Item: SWbemObject;
  List: array of SWbemObject;
  ObjectSet: ISWbemObjectSet;
  Services: ISWbemServices;
begin
  Services := CoSWbemLocator.Create.ConnectServer( '', 'root\cimv2', '', '', '', '', 0, nil );
  ObjectSet := Services.ExecQuery( sQuery, 'WQL', wbemFlagBidirectional, nil );
  Enum := ObjectSet._NewEnum as IEnumVariant;
  SetLength( List, ObjectSet.Count );
  I := Low( List );
  while NextItem( Enum, SWBemObject, Item ) do begin
    if ( I > High( List ) ) then SetLength( List, I );
    List[ I ] := Item;
    Inc( I );
  end;
  // Here, code for a QuickSort or other sorting routine is required...

This is just a lot easier in my opinion... ;-)
Still have to create a better sorting routine, though. But that's not a real problem. I have all the objects as properly typed values already, so I don't have to work on that. It's just that I disliked having to add this additional code.

And to enumerate objects in an objectset, I use:

function NextItem( var Enum: IEnumVARIANT; const riid: TGUID; out ppObject ): Boolean;
var
  OleProperty: OleVariant;
  NumProp: LongWord;
begin
  try
    Result := Succeeded( Enum.Next( 1, OleProperty, NumProp ) ) and ( NumProp > 0 ) and Succeeded( IDispatch( OleProperty ).QueryInterface( riid, ppObject ) );
  except
    Result := False;
    IUnknown( ppObject ) := nil;
  end;
end;

Above little function works great for returning an object of the preferred class and is often the only location in my code where I use an OleVariant...

Apparantly Extended WMI has a sort option with the 'ORDER BY' keywords. Too bad I also have to support the old-style WMI...
0
 
LVL 17

Author Comment

by:Wim ten Brink
ID: 12613018
It wasn't really the answer I was looking for but hey, it did gave me some new ideas. And the information about extended WMI was interesting too. Still, the solution I have now seems to work better.
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Is your OST file inaccessible, Need to transfer OST file from one computer to another? Want to convert OST file to PST? If the answer to any of the above question is yes, then look no further. With the help of Stellar OST to PST Converter, you can e…
Suggested Courses

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question