aehimself 424 Posted October 10 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
Anders Melander 2137 Posted October 10 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. 1 Share this post Link to post
aehimself 424 Posted October 10 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
Anders Melander 2137 Posted October 10 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
aehimself 424 Posted October 11 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
Anders Melander 2137 Posted October 11 The code I posted doesn't raise an exeption... Share this post Link to post
aehimself 424 Posted October 11 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
Anders Melander 2137 Posted October 11 Yes - so don't use the IDispatch API. Another option is to use ExecQuery but I don't know how it performs - and I don't know the query syntax. Share this post Link to post