如何使用delphi提高WMI性能?

时间:2012-04-17 21:34:43

标签: delphi wmi

我编写了一个简单的函数来使用WMI检索系统信息,将类和属性名称作为参数传递。当我执行像这样的函数

  Writeln('Procesor Id '+GetWMIInfo('Win32_Processor','Name'));
  Writeln('Mother Board Serial '+GetWMIInfo('Win32_BaseBoard','SerialNumber'));
  Writeln('BIOS Version '+GetWMIInfo('Win32_BIOS','Version'));

执行时间约为1300毫秒。

我需要检索很多附加信息,那么可以减少执行这个功能的时间吗?

这是一个带有函数

的示例应用程序
{$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.

2 个答案:

答案 0 :(得分:20)

这些是提高WMI性能的一些技巧

1。)重新使用CreateOleObject

的电话

2.。)重用WMI连接

更昂贵的任务之一是连接到WMI服务,因此重新使用该连接而不是每次调用该函数时创建一个连接。

3。)仅检索您要使用的列

检索WMI的每个属性都有不同的来源,如Windows注册表,WinAPi等,限制列将提高性能。阅读这篇文章了解更多信息How obtain the source of the WMI Data

4.。)执行WQL语句时使用WBEM_FLAG_FORWARD_ONLY标志。

按照上述提示,我重写了您的示例应用

{$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.

执行时间从1245秒到180毫秒(在我的笔记本电脑上)。

答案 1 :(得分:4)

这是一般的经验法则。

当你说你想要检索很多其他信息时,我认为这意味着你将在很多时候调用这个函数,可能是在一个循环中。对于性能调优,您只需要花费大量时间并且可以在循环之外重用它们,即缓存它们。

在这种情况下,CreateOleObject很可能在很大程度上耗费你的时间,作为第一遍我将它放在循环外(或多次调用)并将你的sWebLocator传递给函数,作为第二次传递你可能喜欢从函数中取出ConnectServer调用并同时传递sWMIService对象。