Wednesday, 5 August 2009

Utilizando WMI (Windows Management Instrumentation) con Delphi

En éste artículo os mostraré como recuperar información del sistema utilizando los componentes del WMI (Windows Management Instrumentation) que de otra manera sería imposible. Los WMI Core Components, están instalados gratuitamente en cualquier máquina que tenga instalado Microsoft Windows con 32 bits. Mediante éste componente podremos obtener toda la información útil del sistema como al número de serie de la placa base, el modelo, la cantidad de memória RAM del sistema, el número de tarjetas de red instaladas, etc. Además de información detallada de cada proceso ejecutado en el sistema, o sea que disponemos de miles y miles de parámetros para observar sin tener que realizar un código complicado para extraerlos.

  • ¿Cómo lo utilizamos con Delphi?
Solo tenemos que crear nuestro proyecto e instalar el componente wbemdisp.TLB. De ésta manera, delphi nos creará un fichero .pas con las declaraciones del TLB. Entonces desde nuestro proyecto nos dirigimos a Tools -> Import component:

Ahora continuamos con el next, y añadimos el fichero a nuestro proyecto en curso:

Una vez creado el .pas obtendremos:

Ahora solo tenemos que utilizar el siguiente método para leer Strings de la clase que queramos. En el siguiente enlace encontraréis toda la información referente a todas las propiedades que podemos obtener a través del WMI: Win32 Classes.

GetWMIClassString:

uses
    WbemScripting_TLB, ActiveX;

function GetWMIClassString(wmiHost, wmiClass, wmiProperty: string): string;
var
    Locator: ISWbemLocator;
    Services: ISWbemServices;
    SObject: ISWbemObject;
    ObjSet: ISWbemObjectSet;
    SProp: ISWbemProperty;
    Enum: IEnumVariant;
    Value: Cardinal;
    TempObj: OleVariant;
    SN: string;
begin
    try
        Locator := CoSWbemLocator.Create;
        Services := Locator.ConnectServer(wmiHost, 'root\cimv2', '', '', '', '', 0, nil);
        ObjSet := Services.ExecQuery('SELECT * FROM ' + wmiClass, 'WQL', wbemFlagReturnImmediately and wbemFlagForwardOnly, nil);
        Enum := (ObjSet._NewEnum) as IEnumVariant;
        while (Enum.Next(1, TempObj, Value) = S_OK) do
        begin
            SObject := IUnknown(tempObj) as ISWBemObject;
            SProp := SObject.Properties_.Item(wmiProperty, 0);
            if VarIsNull(SProp.Get_Value) then
                result := ''
            else
            begin
                SN := SProp.Get_Value;
                result := SN;
            end;
        end;
    except
        on exception do
            result := '';
    end;
end;


Con éste método podremos leer todos los parámetros de tipo String de la clase que queramos. En el siguiente ejemplo, realizaré una llamada al Win32_BIOS para obtener todos sus parámetros de tipo texto y mostrarlos en un TMemo. Si miramos en la ayuda del MSDN, obtendremos la lista del Win32_BIOS:

class Win32_BIOS : CIM_BIOSElement
{
  uint16   BiosCharacteristics[];
  string   BIOSVersion[];
  string   BuildNumber;
  string   Caption;
  string   CodeSet;
  string   CurrentLanguage;
  string   Description;
  string   IdentificationCode;
  uint16   InstallableLanguages;
  datetime InstallDate;
  string   LanguageEdition;
  String   ListOfLanguages[];
  string   Manufacturer;
  string   Name;
  string   OtherTargetOS;
  boolean  PrimaryBIOS;
  datetime ReleaseDate;
  string   SerialNumber;
  string   SMBIOSBIOSVersion;
  uint16   SMBIOSMajorVersion;
  uint16   SMBIOSMinorVersion;
  boolean  SMBIOSPresent;
  string   SoftwareElementID;
  uint16   SoftwareElementState;
  string   Status;
  uint16   TargetOperatingSystem;
  string   Version;
};


Ahora si miramos el siguiente ejemplo, podremos ver la información devuelta:

procedure TForm3.Button1Click(Sender: TObject);
begin
    Memo1.lines.add('class Win32_BIOS : CIM_BIOSElement');
    Memo1.lines.add('BuildNumber ' + GetWMIClassString('', 'Win32_BIOS', 'BuildNumber'));
    Memo1.lines.add( 'Caption: ' + GetWMIClassString('', 'Win32_BIOS', 'Caption'));
    Memo1.lines.add('CodeSet: ' + GetWMIClassString('', 'Win32_BIOS', 'CodeSet'));
    Memo1.lines.add('CurrentLanguage: ' + GetWMIClassString('', 'Win32_BIOS', 'CurrentLanguage'));
    Memo1.lines.add('Description: '  + GetWMIClassString('', 'Win32_BIOS', 'Description'));
    Memo1.lines.add('IdentificationCode: ' + GetWMIClassString('', 'Win32_BIOS', 'IdentificationCode'));
    Memo1.lines.add('LanguageEdition: ' + GetWMIClassString('', 'Win32_BIOS', 'LanguageEdition'));
    Memo1.lines.add('Manufacturer: ' + GetWMIClassString('', 'Win32_BIOS', 'Manufacturer'));
    Memo1.lines.add('Name: ' + GetWMIClassString('', 'Win32_BIOS', 'Name'));
    Memo1.lines.add('OtherTargetOS: ' + GetWMIClassString('', 'Win32_BIOS', 'OtherTargetOS'));
    Memo1.lines.add('SerialNumber: ' + GetWMIClassString('', 'Win32_BIOS', 'SerialNumber'));
    Memo1.lines.add('SMBIOSBIOSVersion: ' + GetWMIClassString('', 'Win32_BIOS', 'SMBIOSBIOSVersion'));
    Memo1.lines.add('SMBIOSBIOSVersion: ' + GetWMIClassString('', 'Win32_BIOS', 'SoftwareElementID'));
    Memo1.lines.add('Status: ' + GetWMIClassString('', 'Win32_BIOS', 'Status'));
    Memo1.lines.add('Version: ' + GetWMIClassString('', 'Win32_BIOS', 'Version'));
end;



Si nos fijamos en la función getWMIClassString, vemos que el parámetro wmiHost está en blanco, y eso es debido a que podemos capturar los parámetros de equipos remotos. Si lo dejamos en blanco se obtienen los parámetros de nuestro equipo. Por la red encontraréis mucha más información, desde aquí solo doy una pincelada para que podáis comprobar la potencia del WMI y que utilizando poco código podemos obtener mucha información de nuestro S.O.

  • Enlaces de interés:
Get information Process using WMI and Delphi.
Get the PC Serial number using WMI and Delphi.

0 comments:

Post a Comment