I wrote a simple function to retrieve system information using the WMI, passing as parameter the class and the property name. when I execute the function like this
Writeln('Procesor Id '+GetWMIInfo('Win32_Processor','Name'));
Writeln('Mother Board Serial '+GetWMIInfo('Win32_BaseBoard','SerialNumber'));
Writeln('BIOS Version '+GetWMIInfo('Win32_BIOS','Version'));
The execution time is about 1300 ms.
I need retrieve a lot of additional information, So Is possible reduce the time of execution of this function?
This is a sample application with the function
{$APPTYPE CONSOLE}
uses
Diagnostics,
SysUtils,
ActiveX,
ComObj,
Variants;
function GetWMIInfo(const WMIClass, WMIProperty:string): string;
var
sWbemLocator : OLEVariant;
sWMIService : OLEVariant;
sWbemObjectSet: OLEVariant;
sWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
begin;
Result:='';
sWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
sWMIService := sWbemLocator.ConnectServer('', 'root\CIMV2', '', '');
sWbemObjectSet:= sWMIService.ExecQuery('SELECT * FROM '+WMIClass,'WQL');
oEnum := IUnknown(sWbemObjectSet._NewEnum) as IEnumVariant;
if oEnum.Next(1, sWbemObject, iValue) = 0 then
Result:=sWbemObject.Properties_.Item(WMIProperty).Value;
end;
var
SW : TStopwatch;
begin
try
CoInitialize(nil);
try
SW.Reset;
SW.Start;
Writeln('Procesor Id '+GetWMIInfo('Win32_Processor','Name'));
Writeln('Mother Board Serial '+GetWMIInfo('Win32_BaseBoard','SerialNumber'));
Writeln('BIOS Version '+GetWMIInfo('Win32_BIOS','Version'));
SW.Stop;
Writeln('Elapsed ms '+FormatFloat('#,0.000',SW.Elapsed.TotalMilliseconds));
finally
CoUninitialize;
end;
except
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Readln;
end.
These are some tips to improve the WMI performance
1.) Reutilize the call to CreateOleObject
2.) Reuse the WMI Connection
One of more expensive tasks is make a connection to the WMI services, so reutilize that conneciton instead of create one conneciton each time which call the function.
3.) Only retrieve the columns which you want to use
Every property which retrieve the WMI has different sources like the Windows registry, the WinAPi and so on, restricting the columns will improve the performance. read this article for more info How obtain the source of the WMI Data
4.) Use the WBEM_FLAG_FORWARD_ONLY flag when you execute the WQL sentence.
Following the above tips I rewrote your sample app
{$APPTYPE CONSOLE}
uses
Diagnostics,
SysUtils,
ActiveX,
ComObj,
Variants;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
function GetWMIInfo(const WMIClass, WMIProperty:string): string;
const
wbemFlagForwardOnly = $00000020;
var
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
begin;
Result:='';
FWbemObjectSet:= FWMIService.ExecQuery(Format('Select %s from %s',[WMIProperty, WMIClass]),'WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
if oEnum.Next(1, FWbemObject, iValue) = 0 then
Result:=FWbemObject.Properties_.Item(WMIProperty).Value;
end;
var
SW : TStopwatch;
begin
try
CoInitialize(nil);
try
SW.Reset;
SW.Start;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
Writeln('Procesor Id '+GetWMIInfo('Win32_Processor','Name'));
Writeln('Mother Board Serial '+GetWMIInfo('Win32_BaseBoard','SerialNumber'));
Writeln('BIOS Version '+GetWMIInfo('Win32_BIOS','Version'));
SW.Stop;
Writeln('Elapsed ms '+FormatFloat('#,0.000',SW.Elapsed.TotalMilliseconds));
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Readln;
end.
And the execution goes from 1245 to 180 ms (on my laptop).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With