The Road to Delphi

Delphi – Free Pascal – Oxygene

Reading the SMBios Tables using Delphi

20 Comments

UPDATE : If you want access the SMBIOS using Delphi or Free Pascal try the TSMBIOS project.


 

The system management BIOS (SMBIOS)   is a specification of how the system vendors present management information about their products in a standard format, so you can use the  SMBIOS to discover information about the hardware platform, such as the system manufacturer, the system BIOS version, processor installed characteristics  and so on. From windows you can acceess the SMBIOS tables using the WMI or the WinApi. In this article I will show how  you can gain access to the SMBios tables using the WMI and Delphi.

The SMBIOS Tables

The tables are located directly adjacent to each other in memory. Each table is composed of a 4-byte header, a specific structure , and an optional string table.

Header

This is the header description of each table

The type field present in the header define how each table must be interpreted, this is a list of a few table types

  • BIOS Information (Type 0)
  • System Information (Type 1)
  • System Enclosure (Type 3)
  • Processor Information (Type 4)
  • Cache Information (Type 7)
  • System Slots (Type 9)
  • Physical Memory Array (Type 16)
  • Memory Device (Type 17)
  • Memory Array Mapped Address (Type 19)
  • System Boot Information (Type 32)

Text Strings

The text strings associated with a given SMBIOS table are appended directly after the formatted portion of the structure. Each string is terminated with a null (00h) BYTE and the set of strings is terminated with an additional null (00h) BYTE. When the formatted portion of a SMBIOS structure references a string, it does so by specifying a non-zero string number within the structure’s string-set. For example, if a string field contains 02h, it references the second string following the formatted portion of the SMBIOS structure. If a string field references no string, a null (0) is placed in that string field.

Check the next representation of a BIOS Table (Type


 db 0 ; Indicates BIOS Structure Type            |
 db 13h ; Length of information in bytes         | Header of the table
 dw ? ; Reserved for handle                      |

 db 01h ; String 1 is the Vendor Name            |
 db 02h ; String 2 is the BIOS version           |
 dw 0E800h ; BIOS Starting Address               |
 db 03h ; String 3 is the BIOS Build Date        | formatted portion
 db 1 ; Size of BIOS ROM is 128K (64K * (1 + 1)) |
 dq BIOS_Char ; BIOS Characteristics             |
 db 0 ; BIOS Characteristics Extension Byte 1    |

 db ‘System BIOS Vendor Name’,0 ;                |
 db ‘4.04’,0 ;                                   | Text Strings (unformatted portion)
 db ‘00/00/0000’,0 ;                             |

 db 0 ; End of structure

WMI

Now which you know the basics about the SMBios table structures, you need a way to retrieve such tables.  the WMI provides a way to get  the raw SMBIOS data in a single buffer using the class MSSmBios_RawSMBiosTables this class is in the root\WMI namespace and is available since Windows XP.

Check this small snippet to retrieve the SMBios tables buffer contained in the SMBiosData property

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  vArray        : variant;
  Value         : integer;
  i             : integer;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //connect to the Wmi service
  FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\WMI', '', '');
  //execute the WQL sentence
  FWbemObjectSet := FWMIService.ExecQuery('SELECT * FROM MSSmBios_RawSMBiosTables', 'WQL', wbemFlagForwardOnly);
  oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumvariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    //store the size of the buffer
    FSize := FWbemObject.Size;
    GetMem(FBuffer, FSize);
    //get the addtional properties like the SMBIos version
    FDmiRevision:= FWbemObject.DmiRevision;
    FSmbiosMajorVersion :=FWbemObject.SmbiosMajorVersion;
    FSmbiosMinorVersion :=FWbemObject.SmbiosMinorVersion;

    //get the buffer of the SMBios tables
    vArray := FWbemObject.SMBiosData;

    FWbemObject := Unassigned;
  end;
end;

Delphi

From the Delphi side we need to create a few structures to hold the data of the tables and write some helper functions to parse the information.

type
  // http://www.dmtf.org/standards/smbios
  SMBiosTables = (
    BIOSInformation = 0,
    SystemInformation = 1,
    BaseBoardInformation = 2,
    EnclosureInformation = 3,
    ProcessorInformation = 4,
    MemoryControllerInformation = 5,
    MemoryModuleInformation = 6,
    CacheInformation = 7,
    PortConnectorInformation = 8,
    SystemSlotsInformation = 9,
    OnBoardDevicesInformation = 10,
    OEMStrings = 11,
    SystemConfigurationOptions = 12,
    BIOSLanguageInformation = 13,
    GroupAssociations = 14,
    SystemEventLog = 15,
    PhysicalMemoryArray = 16,
    MemoryDevice = 17,
    MemoryErrorInformation = 18,
    MemoryArrayMappedAddress = 19,
    MemoryDeviceMappedAddress = 20,
    EndofTable = 127); //for more tables check the official specifications http://www.dmtf.org/standards/smbios

  //the header of each SMBios table
  TSmBiosTableHeader = packed record
    TableType: Byte;
    Length: Byte;
    Handle: Word;
  end;

  //this is a helper record to store the header and index of each table stored in the buffer
  TSMBiosTableEntry = record
    Header: TSmBiosTableHeader;
    Index : Integer;
  end;

  //this is the record to store Bios information about the table Type 0
  TBiosInfo = packed record
    Header: TSmBiosTableHeader;
    Vendor: Byte;
    Version: Byte;
    StartingSegment: Word;
    ReleaseDate: Byte;
    BiosRomSize: Byte;
    Characteristics: Int64;
    ExtensionBytes : array [0..1] of Byte;
  end;

The next code show how you can parse the buffer with the raw data and fill a Generic TList of TSMBiosTableEntry records.

function GetSMBiosTablesList(Buffer : PByteArray): TList;
Var
  Index : integer;
  Header: TSmBiosTableHeader;
  Entry : TSMBiosTableEntry;
begin
  Result    := TList.Create;
  Index     := 0;
  repeat
    //read the header
    Move(Buffer[Index], Header, SizeOf(Header));
    Entry.Header:=Header;
    Entry.Index:=Index;
    //add to the list
    Result.Add(Entry);

    //check if the tale type is 127 (end of tables)
    if Header.TableType=Ord(SMBiosTables.EndofTable) then break;

    //increase the Index in the length of the formatted data
    inc(Index, Header.Length);

    //Text strings zone

    //check for the boundaries of the buffer
    if Index+1>FSize then
      Break;

    //check for $00 $00 -> table termination
    while not((Buffer[Index] = 0) and (Buffer[Index + 1] = 0)) do
    if Index+1>FSize then
     Break
    else
     inc(Index);

    inc(Index, 2);
  until (Index>FSize);
end;

Now to retrieve a text string from a SMBios table

//the Entry Parameter is the buffer to the unformatted data
//The index is the number of the text string to retrieve
function GetSMBiosString(Entry, Index: integer): AnsiString;
var
  i: integer;
  p: PAnsiChar;
begin
  Result := '';
  for i := 1 to Index do
  begin
    p := PAnsiChar(@Buffer[Entry]);
    if i = Index then
    begin
      Result := p;
      break;
    end
    else
      inc(Entry, StrLen(p) + 1);
  end;
end;

A unit to retrieve the Smbios tables

Here I leave a unit to retrieve and parse the SMBios tables, the unit does not cover all the tables types (you can read the official specification)

//Author Rodrigo Ruz V.
//2011-08-01

unit uSMBIOS;

interface

uses
  SysUtils,
  Windows,
  Generics.Collections,
  Classes;

type
  // http://www.dmtf.org/standards/smbios
  SMBiosTables = (
    BIOSInformation = 0,
    SystemInformation = 1,
    BaseBoardInformation = 2,
    EnclosureInformation = 3,
    ProcessorInformation = 4,
    MemoryControllerInformation = 5,
    MemoryModuleInformation = 6,
    CacheInformation = 7,
    PortConnectorInformation = 8,
    SystemSlotsInformation = 9,
    OnBoardDevicesInformation = 10,
    OEMStrings = 11,
    SystemConfigurationOptions = 12,
    BIOSLanguageInformation = 13,
    GroupAssociations = 14,
    SystemEventLog = 15,
    PhysicalMemoryArray = 16,
    MemoryDevice = 17,
    MemoryErrorInformation = 18,
    MemoryArrayMappedAddress = 19,
    MemoryDeviceMappedAddress = 20,
    EndofTable = 127);

  TSmBiosTableHeader = packed record
    TableType: Byte;
    Length: Byte;
    Handle: Word;
  end;

  TBiosInfo = packed record
    Header: TSmBiosTableHeader;
    Vendor: Byte;
    Version: Byte;
    StartingSegment: Word;
    ReleaseDate: Byte;
    BiosRomSize: Byte;
    Characteristics: Int64;
    ExtensionBytes : array [0..1] of Byte;
  end;

  TSysInfo = packed record
    Header: TSmBiosTableHeader;
    Manufacturer: Byte;
    ProductName: Byte;
    Version: Byte;
    SerialNumber: Byte;
    UUID: array [0 .. 15] of Byte;
    WakeUpType: Byte;
  end;

  TBaseBoardInfo = packed record
    Header: TSmBiosTableHeader;
    Manufacturer: Byte;
    Product: Byte;
    Version: Byte;
    SerialNumber: Byte;
  end;

  TEnclosureInfo = packed record
    Header: TSmBiosTableHeader;
    Manufacturer: Byte;
    &Type: Byte;
    Version: Byte;
    SerialNumber: Byte;
    AssetTagNumber: Byte;
    BootUpState: Byte;
    PowerSupplyState: Byte;
    ThermalState: Byte;
    SecurityStatus: Byte;
    OEM_Defined: DWORD;
  end;

  TProcessorInfo = packed record
    Header: TSmBiosTableHeader;
    SocketDesignation: Byte;
    ProcessorType: Byte;
    ProcessorFamily: Byte;
    ProcessorManufacturer: Byte;
    ProcessorID: Int64; // QWORD;
    ProcessorVersion: Byte;
    Voltaje: Byte;
    ExternalClock: Word;
    MaxSpeed: Word;
    CurrentSpeed: Word;
    Status: Byte;
    ProcessorUpgrade: Byte;
    L1CacheHandler: Word;
    L2CacheHandler: Word;
    L3CacheHandler: Word;
    SerialNumber: Byte;
    AssetTag: Byte;
    PartNumber: Byte;
  end;

  TCacheInfo = packed record
    Header: TSmBiosTableHeader;
    SocketDesignation: Byte;
    CacheConfiguration: DWORD;
    MaximumCacheSize: Word;
    InstalledSize: Word;
    SupportedSRAMType: Word;
    CurrentSRAMType: Word;
    CacheSpeed: Byte;
    ErrorCorrectionType: Byte;
    SystemCacheType: Byte;
    Associativity: Byte;
  end;

  TSMBiosTableEntry = record
    Header: TSmBiosTableHeader;
    Index : Integer;
  end;

  TSMBios = class
  private
    FSize: integer;
    FBuffer: PByteArray;
    FDataString: AnsiString;
    FBiosInfo: TBiosInfo;
    FSysInfo: TSysInfo;
    FBaseBoardInfo: TBaseBoardInfo;
    FEnclosureInfo: TEnclosureInfo;
    FProcessorInfo: TProcessorInfo;
    FBiosInfoIndex: Integer;
    FSysInfoIndex: Integer;
    FBaseBoardInfoIndex: Integer;
    FEnclosureInfoIndex: Integer;
    FProcessorInfoIndex: Integer;
    FDmiRevision: Integer;
    FSmbiosMajorVersion: Integer;
    FSmbiosMinorVersion: Integer;
    FSMBiosTablesList: TList;
    procedure LoadSMBIOS;
    procedure ReadSMBiosTables;
    function GetHasBiosInfo: Boolean;
    function GetHasSysInfo: Boolean;
    function GetHasBaseBoardInfo: Boolean;
    function GetHasEnclosureInfo: Boolean;
    function GetHasProcessorInfo: Boolean;
    function GetSMBiosTablesList:TList;
  public
    constructor Create;
    destructor Destroy; override;

    function SearchSMBiosTable(TableType: SMBiosTables): integer;
    function GetSMBiosTableIndex(TableType: SMBiosTables): integer;
    function GetSMBiosString(Entry, Index: integer): AnsiString;

    property Size: integer read FSize;
    property Buffer: PByteArray read FBuffer;
    property DataString: AnsiString read FDataString;
    property DmiRevision: Integer read FDmiRevision;
    property SmbiosMajorVersion : Integer read FSmbiosMajorVersion;
    property SmbiosMinorVersion : Integer read FSmbiosMinorVersion;
    property SMBiosTablesList : TList read FSMBiosTablesList;

    property BiosInfo: TBiosInfo read FBiosInfo Write FBiosInfo;
    property BiosInfoIndex: Integer read FBiosInfoIndex Write FBiosInfoIndex;
    property HasBiosInfo : Boolean read GetHasBiosInfo;
    property SysInfo: TSysInfo read FSysInfo Write FSysInfo;
    property SysInfoIndex: Integer read FSysInfoIndex Write FSysInfoIndex;
    property HasSysInfo : Boolean read GetHasSysInfo;
    property BaseBoardInfo: TBaseBoardInfo read FBaseBoardInfo write FBaseBoardInfo;
    property BaseBoardInfoIndex: Integer read FBaseBoardInfoIndex Write FBaseBoardInfoIndex;
    property HasBaseBoardInfo : Boolean read GetHasBaseBoardInfo;
    property EnclosureInfo: TEnclosureInfo read FEnclosureInfo write FEnclosureInfo;
    property EnclosureInfoIndex: Integer read FEnclosureInfoIndex Write FEnclosureInfoIndex;
    property HasEnclosureInfo : Boolean read GetHasEnclosureInfo;
    property ProcessorInfo: TProcessorInfo read FProcessorInfo write FProcessorInfo;
    property ProcessorInfoIndex: Integer read FProcessorInfoIndex Write FProcessorInfoIndex;
    property HasProcessorInfo : Boolean read GetHasProcessorInfo;
  end;

implementation

uses
  ComObj,
  ActiveX,
  Variants;

{ TSMBios }
constructor TSMBios.Create;
begin
  Inherited;
  FBuffer := nil;
  FSMBiosTablesList:=nil;
  LoadSMBIOS;
  ReadSMBiosTables;
end;

destructor TSMBios.Destroy;
begin
  if Assigned(FBuffer) and (FSize > 0) then
    FreeMem(FBuffer);

  if Assigned(FSMBiosTablesList) then
    FSMBiosTablesList.Free;

  Inherited;
end;

function TSMBios.GetHasBaseBoardInfo: Boolean;
begin
  Result:=FBaseBoardInfoIndex>=0;
end;

function TSMBios.GetHasBiosInfo: Boolean;
begin
  Result:=FBiosInfoIndex>=0;
end;

function TSMBios.GetHasEnclosureInfo: Boolean;
begin
  Result:=FEnclosureInfoIndex>=0;
end;

function TSMBios.GetHasProcessorInfo: Boolean;
begin
  Result:=FProcessorInfoIndex>=0;
end;

function TSMBios.GetHasSysInfo: Boolean;
begin
  Result:=FSysInfoIndex>=0;
end;

function TSMBios.SearchSMBiosTable(TableType: SMBiosTables): integer;
Var
  Index  : integer;
  Header : TSmBiosTableHeader;
begin
  Index     := 0;
  repeat
    Move(Buffer[Index], Header, SizeOf(Header));

    if Header.TableType = Ord(TableType) then
      break
    else
    begin
       inc(Index, Header.Length);
       if Index+1>FSize then
       begin
         Index:=-1;
         Break;
       end;

      while not((Buffer[Index] = 0) and (Buffer[Index + 1] = 0)) do
       if Index+1>FSize then
       begin
         Index:=-1;
         Break;
       end
       else
       inc(Index);

       inc(Index, 2);
    end;
  until (Index>FSize);
  Result := Index;
end;

function TSMBios.GetSMBiosString(Entry, Index: integer): AnsiString;
var
  i: integer;
  p: PAnsiChar;
begin
  Result := '';
  for i := 1 to Index do
  begin
    p := PAnsiChar(@Buffer[Entry]);
    if i = Index then
    begin
      Result := p;
      break;
    end
    else
      inc(Entry, StrLen(p) + 1);
  end;
end;

function TSMBios.GetSMBiosTableIndex(TableType: SMBiosTables): integer;
Var
 Entry : TSMBiosTableEntry;
begin
 Result:=-1;
  for Entry in FSMBiosTablesList do
    if Entry.Header.TableType=Ord(TableType)  then
    begin
      Result:=Entry.Index;
      Break;
    end;
end;

function TSMBios.GetSMBiosTablesList: TList;
Var
  Index : integer;
  Header: TSmBiosTableHeader;
  Entry    : TSMBiosTableEntry;
begin
  Result    := TList.Create;
  Index     := 0;
  repeat
    Move(Buffer[Index], Header, SizeOf(Header));
    Entry.Header:=Header;
    Entry.Index:=Index;
    Result.Add(Entry);

    if Header.TableType=Ord(SMBiosTables.EndofTable) then break;

    inc(Index, Header.Length);// + 1);
    if Index+1>FSize then
      Break;

    while not((Buffer[Index] = 0) and (Buffer[Index + 1] = 0)) do
    if Index+1>FSize then
     Break
    else
     inc(Index);

    inc(Index, 2);
  until (Index>FSize);
end;

procedure TSMBios.LoadSMBIOS;
const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator: OLEVariant;
  FWMIService: OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject: OLEVariant;
  oEnum: IEnumvariant;
  iValue: LongWord;
  vArray: variant;
  Value: integer;
  i: integer;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\WMI', '', '');
  FWbemObjectSet := FWMIService.ExecQuery('SELECT * FROM MSSmBios_RawSMBiosTables', 'WQL', wbemFlagForwardOnly);
  oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumvariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FSize := FWbemObject.Size;
    GetMem(FBuffer, FSize);

    FDmiRevision:= FWbemObject.DmiRevision;
    FSmbiosMajorVersion :=FWbemObject.SmbiosMajorVersion;
    FSmbiosMinorVersion :=FWbemObject.SmbiosMinorVersion;

    vArray := FWbemObject.SMBiosData;

    if (VarType(vArray) and VarArray) <> 0 then
      for i := VarArrayLowBound(vArray, 1) to VarArrayHighBound(vArray, 1) do
      begin
        Value := vArray[i];
        Buffer[i] := Value;
        if Value in [$20..$7E] then
          FDataString := FDataString + AnsiString(Chr(Value))
        else
          FDataString := FDataString + '.';
      end;

    FSMBiosTablesList:=GetSMBiosTablesList;
    FWbemObject := Unassigned;
  end;
end;

procedure TSMBios.ReadSMBiosTables;
begin
  FBiosInfoIndex := GetSMBiosTableIndex(BIOSInformation);
  if FBiosInfoIndex >= 0 then
    Move(Buffer[FBiosInfoIndex], FBiosInfo, SizeOf(FBiosInfo));

  FSysInfoIndex := GetSMBiosTableIndex(SystemInformation);
  if FSysInfoIndex >= 0 then
    Move(Buffer[FSysInfoIndex], FSysInfo, SizeOf(FSysInfo));

  FBaseBoardInfoIndex := GetSMBiosTableIndex(BaseBoardInformation);
  if FBaseBoardInfoIndex >= 0 then
    Move(Buffer[FBaseBoardInfoIndex], FBaseBoardInfo, SizeOf(FBaseBoardInfo));

  FEnclosureInfoIndex := GetSMBiosTableIndex(EnclosureInformation);
  if FEnclosureInfoIndex >= 0 then
    Move(Buffer[FEnclosureInfoIndex], FEnclosureInfo, SizeOf(FEnclosureInfo));

  FProcessorInfoIndex := GetSMBiosTableIndex(ProcessorInformation);
  if FProcessorInfoIndex >= 0 then
    Move(Buffer[FProcessorInfoIndex], FProcessorInfo, SizeOf(FProcessorInfo));
end;

end.

Sample project

This console application show how use this unit

{$APPTYPE CONSOLE}

uses
  Classes,
  SysUtils,
  ActiveX,
  ComObj,
  uSMBIOS in 'uSMBIOS.pas';

procedure GetMSSmBios_RawSMBiosTablesInfo;
Var
  SMBios : TSMBios;
  UUID   : Array[0..31] of Char;
  Entry  : TSMBiosTableEntry;
begin
  SMBios:=TSMBios.Create;
  try
    With SMBios do
    begin
        Writeln(Format('%d SMBios tables found',[SMBiosTablesList.Count]));
        Writeln('');

        Writeln('Type Handle Length Index');
        for Entry in SMBiosTablesList do
          Writeln(Format('%3d  %4x   %3d    %4d',[Entry.Header.TableType, Entry.Header.Handle, Entry.Header.Length, Entry.Index]));

      Readln;

      if HasBiosInfo then
      begin
        WriteLn('Bios Information');
        WriteLn('Vendor        '+GetSMBiosString(BiosInfoIndex + BiosInfo.Header.Length, BiosInfo.Vendor));
        WriteLn('Version       '+GetSMBiosString(BiosInfoIndex + BiosInfo.Header.Length, BiosInfo.Version));
        WriteLn('Start Segment '+IntToHex(BiosInfo.StartingSegment,4));
        WriteLn('ReleaseDate   '+GetSMBiosString(BiosInfoIndex + BiosInfo.Header.Length, BiosInfo.ReleaseDate));
        WriteLn(Format('Bios Rom Size %d k',[64*(BiosInfo.BiosRomSize+1)]));
        WriteLn('');
      end;

      if HasSysInfo then
      begin
        WriteLn('System Information');
        WriteLn('Manufacter    '+GetSMBiosString(SysInfoIndex + SysInfo.Header.Length, SysInfo.Manufacturer));
        WriteLn('Product Name  '+GetSMBiosString(SysInfoIndex + SysInfo.Header.Length, SysInfo.ProductName));
        WriteLn('Version       '+GetSMBiosString(SysInfoIndex + SysInfo.Header.Length, SysInfo.Version));
        WriteLn('Serial Number '+GetSMBiosString(SysInfoIndex + SysInfo.Header.Length, SysInfo.SerialNumber));
        BinToHex(@SysInfo.UUID,UUID,SizeOf(SysInfo.UUID));
        WriteLn('UUID          '+UUID);

        WriteLn('');
      end;

      if HasBaseBoardInfo then
      begin
        WriteLn('BaseBoard Information');
        WriteLn('Manufacter    '+GetSMBiosString(BaseBoardInfoIndex + BaseBoardInfo.Header.Length, BaseBoardInfo.Manufacturer));
        WriteLn('Product       '+GetSMBiosString(BaseBoardInfoIndex + BaseBoardInfo.Header.Length, BaseBoardInfo.Product));
        WriteLn('Version       '+GetSMBiosString(BaseBoardInfoIndex + BaseBoardInfo.Header.Length, BaseBoardInfo.Version));
        WriteLn('Serial Number '+GetSMBiosString(BaseBoardInfoIndex + BaseBoardInfo.Header.Length, BaseBoardInfo.SerialNumber));
        WriteLn('');
      end;

      if HasEnclosureInfo then
      begin
        WriteLn('Enclosure Information');
        WriteLn('Manufacter    '+GetSMBiosString(EnclosureInfoIndex + EnclosureInfo.Header.Length, EnclosureInfo.Manufacturer));
        WriteLn('Version       '+GetSMBiosString(EnclosureInfoIndex + EnclosureInfo.Header.Length, EnclosureInfo.Version));
        WriteLn('Serial Number '+GetSMBiosString(EnclosureInfoIndex + EnclosureInfo.Header.Length, EnclosureInfo.SerialNumber));
        WriteLn('Asset Tag Number '+GetSMBiosString(EnclosureInfoIndex + EnclosureInfo.Header.Length, EnclosureInfo.AssetTagNumber));
        WriteLn('');
      end;

      if HasProcessorInfo then
      begin
        WriteLn('Processor Information');
        WriteLn('Socket Designation     '+GetSMBiosString(ProcessorInfoIndex + ProcessorInfo.Header.Length, ProcessorInfo.SocketDesignation));
        WriteLn('Processor Manufacturer '+GetSMBiosString(ProcessorInfoIndex + ProcessorInfo.Header.Length, ProcessorInfo.ProcessorManufacturer));
        WriteLn('Serial Number          '+GetSMBiosString(ProcessorInfoIndex + ProcessorInfo.Header.Length, ProcessorInfo.SerialNumber));
        WriteLn('Asset Tag              '+GetSMBiosString(ProcessorInfoIndex + ProcessorInfo.Header.Length, ProcessorInfo.AssetTag));
        WriteLn('Part Number            '+GetSMBiosString(ProcessorInfoIndex + ProcessorInfo.Header.Length, ProcessorInfo.PartNumber));
        WriteLn('');
      end;
    end;
  finally
   SMBios.Free;
  end;
end;

begin
 try
    CoInitialize(nil);
    try
      GetMSSmBios_RawSMBiosTablesInfo;
    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;
 Writeln('Press Enter to exit');
 Readln;
end.

Check these samples images of the console App.

Additional Information

Check the next resources to get more info about the SMBios

Author: Rodrigo

Just another Delphi guy.

20 thoughts on “Reading the SMBios Tables using Delphi

  1. Very nice. I haven’t been fiddling with hardware for a long time. Reminds me of DOS era :)

  2. Hi. This is just something for me right now. Unfortunately I have great difficulties reading grey characters on black background. Hope what is written there are just examples on output.

  3. wow THIS VERY AWESOME!!! thanks Rodrigo, really love ur article.

  4. Rodrigo: I give you 5* thumbs, all of your tutorial article are very clear and detail. Thanks a lot. God bless you.

    regards

  5. Great article, old solution with whole bios dump not working anymore.
    Delphi 7 is not support generic (Generics.Collections). Is it there a workaround for delphi 7.

    Thank you.

  6. Thank you for this posting, i am currently using your code to write a reader for all the tables, hopefully i can share it with you when it’s complete

  7. It was failed to compiled using Lazarus.. :(
    Would you mind to make it works to compile using Lazarus too??

    I’m newbie.. But I want to use your Unit for my knowledge..

    Thank You,
    Onix Tan.

  8. Thanks very much for sharing your knowledge and Delphi code, it saved me alot of work.

  9. Pingback: SMBios: BiosHelp geht nicht - Delphi-PRAXiS

  10. Thanks for this excellent example. I’ve been trying to get some of the numeric values out of SMBIOS, like L1 Cache Handle which is a WORD value. In my tests L1, L2 and L3 contain 770, 772 and 771 respectively. I think this might be pointing to these values in a similar way to the way strings are handled in SMBIOS because clearly these aren’t proper values. This is different to CoreCount which has the correct value when I load the the buffer into the ProcessorInfo. Try as I might, I cannot seem to get it to reference correctly and return decent values. Could I ask if you have found a way to do this? I’m wondering if you might have a GetSMBIOSWord equivalent?

  11. Pingback: SMBios Ungenauigkeiten? - Delphi-PRAXiS

Leave a comment