2010-05-03 12 views
12

Sto usando Delphi 2010 e quando ho creato un'applicazione console che stampa "Hello World", richiede 111 kb. Se voglio interrogare WMI con Delphi, aggiungo le unità WBEMScripting_TLB, ActiveX e Variants al mio progetto. Se eseguo una semplice query WMI, la mia dimensione eseguibile passa a 810 kb. ICome utilizzare WMI con Delphi senza aumentare drasticamente le dimensioni del file dell'applicazione?

Esiste comunque una query su WMI senza una così grande aggiunta alla dimensione del file? Perdona la mia ignoranza, ma perché non ho questo problema con C++?

Ecco il mio codice:

program WMITest; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, 
    WBEMScripting_TLB, 
    ActiveX, 
    Variants; 

function GetWMIstring(wmiHost, root, wmiClass, wmiProperty: string): string; 
var 
    Services: ISWbemServices; 
    SObject: ISWbemObject; 
    ObjSet: ISWbemObjectSet; 
    SProp: ISWbemProperty; 
    Enum: IEnumVariant; 
    Value: Cardinal; 
    TempObj: OLEVariant; 
    loc: TSWbemLocator; 
    SN: string; 
    i: integer; 
begin 
    Result := ''; 
    i := 0; 
    try 
    loc := TSWbemLocator.Create(nil); 
    Services := Loc.ConnectServer(wmiHost, root {'root\cimv2'}, '', '', '', '', 
     0, nil); 
    ObjSet := Services.ExecQuery('SELECT * FROM ' + wmiClass, 'WQL', 
     wbemFlagReturnImmediately and wbemFlagForwardOnly, nil); 
    Enum := (ObjSet._NewEnum) as IEnumVariant; 
    if not VarIsNull(Enum) then 
     try 
     while Enum.Next(1, TempObj, Value) = S_OK do 
     begin 
      try 
      SObject := IUnknown(TempObj) as ISWBemObject; 
      except SObject := nil; 
      end; 
      TempObj := Unassigned; 
      if SObject <> nil then 
      begin 
      SProp := SObject.Properties_.Item(wmiProperty, 0); 
      SN := SProp.Get_Value; 
      if not VarIsNull(SN) then 
      begin 
       if varisarray(SN) then 
       begin 
       for i := vararraylowbound(SN, 1) to vararrayhighbound(SN, 1) do 
        result := vartostr(SN[i]); 
       end 
       else 
       Result := SN; 
       Break; 
      end; 
      end; 
     end; 
     SProp := nil; 
     except 
     Result := ''; 
     end 
    else 
     Result := ''; 
    Enum := nil; 
    Services := nil; 
    ObjSet := nil; 
    except 
    on E: Exception do 
     Result := e.message; 
    end; 
end; 

begin 
    try 
    WriteLn('hello world'); 
    WriteLn(GetWMIstring('.', 'root\CIMV2', 'Win32_OperatingSystem', 
     'Caption')); 
    WriteLn('done'); 

    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
end. 

UPDATE: Quando compilo il following sample from MSDN con Microsoft Visual C++ 2008 (applicazione di console), è di 76 kb.

+0

Quando si dice "con C++", quale compilatore C++ stai usando? C++ Builder? Visual C++? GCC? Quale versione? –

+4

Perché "un'applicazione console che stampa" Hello World "" ha alcun tipo di punto dati significativo per le dimensioni dell'eseguibile? –

+0

È un sistema di riferimento per utenti non Delphi che possono avere familiarità con la risoluzione del problema utilizzando C/C++. – Mick

risposta

26

@Mick, è possibile accedere al WMI senza importare WBEMScripting da Delphi, utilizzando le interfacce IBindCtx e IMoniker.

Controllare questo semplice codice (testato in Delphi 2010 e Windows 7), la dimensione del file exe è 174 kb.

program WmiTest; 

{$APPTYPE CONSOLE} 


uses 
    SysUtils 
    ,ActiveX 
    ,ComObj 
    ,Variants; 


function GetWMIstring(wmiHost, root, wmiClass, wmiProperty: string): string; 
var 
    objWMIService : OLEVariant; 
    colItems  : OLEVariant; 
    colItem  : OLEVariant; 
    oEnum   : IEnumvariant; 
    iValue  : LongWord; 

    function GetWMIObject(const objectName: String): IDispatch; 
    var 
    chEaten: Integer; 
    BindCtx: IBindCtx;//for access to a bind context 
    Moniker: IMoniker;//Enables you to use a moniker object 
    begin 
    OleCheck(CreateBindCtx(0, bindCtx)); 
    OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));//Converts a string into a moniker that identifies the object named by the string 
    OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));//Binds to the specified object 
    end; 

begin 
    objWMIService := GetWMIObject(Format('winmgmts:\\%s\%s',[wmiHost,root])); 
    colItems  := objWMIService.ExecQuery(Format('SELECT * FROM %s',[wmiClass]),'WQL',0); 
    oEnum   := IUnknown(colItems._NewEnum) as IEnumVariant; 
    while oEnum.Next(1, colItem, iValue) = 0 do 
    begin 
    Result:=colItem.Properties_.Item(wmiProperty, 0); //you can improve this code ;) , storing the results in an TString. 
    end; 
end; 

begin 
try 
    CoInitialize(nil); 
    try   
     WriteLn(GetWMIstring('.', 'root\CIMV2', 'Win32_OperatingSystem','Caption')); 
     Readln; 
    finally 
    CoUninitialize; 
    end; 
except 
    on E:Exception do 
    Begin 
     Writeln(E.Classname, ': ', E.Message); 
     Readln; 
    End; 
    end; 
end. 
+0

Questo è * esattamente * quello che stavo cercando! – Mick

+0

ho ** no ** idea di come funzioni, ma mi piace! –

+2

@IanBoyd controlla questo articolo [Accesing the WMI from Object Pascal Code (Delphi, Oxygene, FreePascal)] (http://theroadtodelphi.wordpress.com/2010/12/01/accesing-the-wmi-from-pascal-code -delphi-oxygene-freepascal /) – RRUZ

0

Bene, non conosco WBEMScripting_TLB, ma ActiveX.pas è un'unità piuttosto grande. Sono quasi 7000 linee sulla mia installazione D2010. Se devi inserire una quantità significativa di questo nel tuo codice, allora puoi aspettarti che aggiunga qualche centinaio di K alla tua dimensione EXE.

Quanto è grande il TLB, a proposito?

6

ActiveX e/o Varianti aggiungerebbero 36 KB al massimo.
E 'WBEMScripting_TLB che aggiunge circa 650KB al progetto.
Non è enorme nelle righe di codice, ma più che dichiarare alcune classi, interfacce e costanti, lo include OleServer nei suoi usi.
E che porta l'interoControlsunità con la sua pesante bagaglio.

+0

Vero. Poi di nuovo, questo non è più "bagaglio pesante". Diamine, l'intero eseguibile "drasticamente aumentato" si adatterebbe comunque su un floppy da 1,44 MB! –

+1

Vedendolo così ... Tuttavia, è un aumento di fattore 7, e non si adatterà più al floppy 360K - quelli che in realtà floppano. :-) –

2

quando delphi crea un eseguibile, collega in modo statico le librerie delphi runtime. questo si traduce in un eseguibile più grande, tuttavia poiché il rtl è collegato staticamente, l'implementazione è più semplice e c'è un elemento di proofing futuro.

è possibile configurare delphi per utilizzare i pacchetti di runtime abilitando Build with runtime packages nello Project/Options. tuttavia, dovrai assicurarti che i pacchetti delphi rtl siano disponibili e potresti riscontrare problemi con il debug.

questo comportamento di collegamento statico vs runtime spiega probabilmente le differenze che si verificano tra delphi e C++.

1

La differenza che si vede, in parte comunque, è perché VC++ utilizza librerie di runtime collegate dinamicamente per impostazione predefinita; le librerie di runtime vengono caricate dalle DLL quando l'app viene eseguita e pertanto il codice non è presente nell'eseguibile.

Delphi, OTOH, per collegamenti predefiniti in tutto il codice della libreria di runtime a meno che non si crei con i pacchetti runtime abilitati. Questa differenza nelle configurazioni predefinite rappresenterà la maggior parte delle differenze di dimensioni tra i file eseguibili.

Problemi correlati