Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用delphi提高WMI性能?_Delphi_Wmi - Fatal编程技术网

如何使用delphi提高WMI性能?

如何使用delphi提高WMI性能?,delphi,wmi,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

我编写了一个简单的函数来使用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.

这是一般的经验法则

当你说你想检索很多额外的信息时,我想这意味着你会经常调用这个函数,可能是在一个循环中。对于性能调优,您只需将那些花费大量时间并且可以重用的东西从循环中取出,即缓存它们


在这种情况下,CreateOleObject可能会花费您大量的时间,作为第一次传递,我会将其置于循环之外(或多次调用),并将sWebLocator传递到函数中,作为第二步,您可能还希望将ConnectServer调用从函数中取出,并将sWMIService对象也传入。

以下是一些提高WMI性能的技巧

1.)重新利用对的呼叫

2.)重用WMI连接

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

3.)仅检索要使用的列

检索WMI的每个属性都有不同的源,如Windows注册表、WinAPi等,限制列将提高性能。阅读本文了解更多信息

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

按照以上提示,我重写了你的示例应用程序

{$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。很好,你又一次让我删除了我的低劣答案。:)除了你所说的,海报可能还想看看MagWMI,这是一套免费的Delphi包装器,可以让事情变得更简单。它在内部对信息进行一些缓存,从而使多个查询更加容易。包装器是免费的,附带了一个非常广泛的演示应用程序,可能会有所帮助。是的,这和我刚才说的差不多……不过我个人认为更好的通用模式是将缓存的服务变量传递给函数,这允许在测试框架中对这些变量进行DI和模拟,当然更好的方法是创建一个对象来封装连接和函数。这个示例应用程序只是一个概念证明。此外,第3点从未被提及,而且非常重要。是否可以修改上述函数,使其能够在一次调用中检索多个参数?例如:GetWMIInfo('Win32_LogicalDisk','Caption,FreeSpace,Size')。如果它能够像cmd那样检索所有现有分区的所有信息,那就太好了:wmic logicaldisk where mediatype=12获取标题、大小、自由空间/格式:LIST