2012-04-17 11 views
13

私はWMIを使ってシステム情報を取得する簡単な関数を書いて、パラメータとしてクラスとプロパティ名を渡しました。このような関数を実行するとdelphiを使用して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. 

答えて

19

これらは、WMIのパフォーマンスを向上させるためにいくつかのヒント

1.)CreateOleObject

2にコールを再利用している)WMI接続

より高価な課題の一つはへの接続を行うことで再利用WMIサービスを使用するので、関数を呼び出すたびに1つのconnecitonを作成するのではなく、そのconnecitonを再利用します。

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ミリ秒から行きます。

+6

+1。ニース、もう一度あなたは私の下位の答えを削除させます。 :)あなたが言ったことに加えて、ポスターは、物事をより簡単にするDelphiラッパーの無料セットであるMagWMIを見たいかもしれません。内部的には、複数のクエリをはるかに簡単にする情報のキャッシングを行います。ラッパーは無料で、本当に大規模なデモアプリケーションが付属しています。 –

+2

これは私が言っていたものとほとんど同じですが、個人的にはキャッシュされたサービスのバールを関数に渡すのがより良い一般的なパターンだと思うので、テストフレームワークでそれらの変数をDIとモックすることができます。 –

+0

もちろん、接続と機能をカプセル化するオブジェクトを作成する方が良いです。このサンプルアプリケーションは単なる概念証明です。またポイント3は決して言及されず、非常に重要です。 – RRUZ

4

これは一般的な経験則です。

多くの追加情報を取得したいと思う場合は、この機能を多くの場合ループで呼び出すことになります。パフォーマンスをチューニングするには、時間がかかるものを取り除くだけで、ループの外に出て再利用することができます。つまり、キャッシュします。

このケースでは、CreateOleObjectは時間の大部分を費やしている可能性があります。最初のパスでは、ループ(または複数の呼び出し)の外側に配置し、sWebLocatorを関数に渡します。関数からConnectServer呼び出しを受け取り、sWMIServiceオブジェクトも渡したいと思うかもしれません。

関連する問題