Jump to content
aehimself

How to check if a specific class exists in WMI?

Recommended Posts

Hello,

 

A long time ago I wrote a component which queries WMI via a custom provider. This provider might or might not be installed so the whole method was in a Try..Except block. Failure meant no provider is installed so data is attempted to be gathered by other means.

Browsing @RRUZ's WMI generator I found the method .SubclassesOf... this is exactly what I needed! Got rid of the except block and replaced it with the enumeration of subclasses.

 

Now I'm getting complaints that the application hangs and yes, it seems to be spending a LOOOOONG time in the While enum.Next loop.

 

Am I doing something wrong? Should I somehow filter it further to have less items in the enum? Is there a quicker way to see if a specific class exists in WMI?

 

I'd appreciate your input :)

 

Method in question is here.

Share this post


Link to post
48 minutes ago, aehimself said:

Is there a quicker way to see if a specific class exists in WMI?

Yes. It's been almost a decade since I did anything with WMI, but if I look at the code I used to get a class by name:

 

function TWindowsManagementClassList.GetItem(const APath: string): IWindowsManagementClassObject;
var
  Instance: IWbemClassObject;
  CallResult: IWbemCallResult;
begin
  // Try to resolve from cache
  if (FItems <> nil) and (FItems.TryGetValue(AnsiUpperCase(APath), Result)) then
    exit;

  WmiCheck(FConnection.Services.GetObject(APath, WBEM_FLAG_RETURN_WBEM_COMPLETE, FConnection.Context, Instance, CallResult));

  if (Instance <> nil) then
  begin
    Result := TWindowsManagementClassObject.Create(FConnection, Instance);

    if (FItems = nil) then
      FItems := TDictionary<string, IWindowsManagementClassObject>.Create;

    // Add item to cache
    FItems.Add(AnsiUpperCase(APath), Result);
  end else
    Result := nil;
end;

then it should be easy to create a similar ones that doesn't bug out if the class doesn't exist:

function TWindowsManagementClassList.FindItem(const APath: string): IWindowsManagementClassObject;
var
  Instance: IWbemClassObject;
  CallResult: IWbemCallResult;
begin
  // Try to resolve from cache
  if (FItems <> nil) and (FItems.TryGetValue(AnsiUpperCase(APath), Result)) then
    exit;

  if (not Succeeded(FConnection.Services.GetObject(APath, WBEM_FLAG_RETURN_WBEM_COMPLETE, FConnection.Context, Instance, CallResult))) then
    Instance := nil;

  if (Instance <> nil) then
  begin
    Result := TWindowsManagementClassObject.Create(FConnection, Instance);

    if (FItems = nil) then
      FItems := TDictionary<string, IWindowsManagementClassObject>.Create;

    // Add item to cache
    FItems.Add(AnsiUpperCase(APath), Result);
  end else
    Result := nil;
end;

function TWindowsManagementClassList.Exists(const APath: string): boolean;
var
  Instance: IWbemClassObject;
  CallResult: IWbemCallResult;
begin
  // Try to resolve from cache
  if (FItems <> nil) and (FItems.ContainsKey(AnsiUpperCase(APath))) then
    exit(True);

  if (Succeeded(FConnection.Services.GetObject(APath, WBEM_FLAG_RETURN_WBEM_COMPLETE, FConnection.Context, Instance, CallResult))) then
    exit(True);

  Result := False;
end;

Of course the above examples are using my framework, but you get the idea, I'm sure.

  • Thanks 1

Share this post


Link to post
1 hour ago, Anders Melander said:

Of course the above examples are using my framework, but you get the idea, I'm sure.

When I did a quick search I realized that WMIService should have a .Get method as well. Your code at the first glance is doing something similar so I should continue digging in that direction.

 

Thank you, Anders!

Share this post


Link to post
34 minutes ago, aehimself said:

Your code at the first glance is doing something similar

Yes; I'm using the COM API. You are using the IDispatch scripting API, which is a layer on top of the COM API.

Share this post


Link to post

Took some time to find a working Delphi code but it seems that unfordunately wmiservice.Get also raises an exception if the class was not found.

 

Probably I'll just revert to the try..except method. Note to self: don't fix something what's not broken...

Share this post


Link to post

I meant via the IDispatch version, like this:

wbemlocator := CreateOleObject('WbemScripting.SWbemLocator');
wmiservice := wbemlocator.ConnectServer('', 'root\cimv2', '', '');
wmiservice.Get('MSFT_VSInstance');

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×