Skip to content
The Road to Delphi — Delphi, VCL, VCL Styles, UxTheme and WinAPI

Reading the SMBios Tables using Delphi

, ,

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

[sourcecode language=”text” wraplines=”false”]

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
[/sourcecode]

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

[sourcecode language=”delphi” wraplines=”false”]
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;
[/sourcecode]

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.

[sourcecode language=”delphi” wraplines=”false”]
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;
[/sourcecode]

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

[sourcecode language=”delphi” wraplines=”false”]
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;
[/sourcecode]

Now to retrieve a text string from a SMBios table

[sourcecode language=”delphi” wraplines=”false”]
//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;
[/sourcecode]

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)

[sourcecode language=”delphi” wraplines=”false”]
//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.
[/sourcecode]

Sample project

This console application show how use this unit

[sourcecode language=”delphi” wraplines=”false”]
{$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.
[/sourcecode]

Check these samples images of the console App.

Additional Information

Check the next resources to get more info about the SMBios

20 responses

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

    1. François, while I wrote this article had the same memories..like reading the Bios and CMOS memory using Turbo Pascal – those were good times :)

  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.

    1. Sorry for that, the images only shows the output of the app, so don’t worry. for that.

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

  4. Chrisna Obaja Avatar
    Chrisna Obaja

    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.

    1. In Delphi 7, you can replace the generics with a TList or an dynamic array,

      1. I am successfully modified unit “uSMBIOS” for Delphi 7 using dynamic array like you suggested.
        Thank you once more.

        1. You are welcome, glad to help you

        2. ivica,

          I also have Delphi 7. I really don’t understand Generics.Collections and stuff like that.

          Could you be so kind as to share your Delphi 7 version of this code?

          I am sure I am not alone :)

          1. Leave your email and i will send you working example for D7.

        3. ivica, could you share modified code for delphi7… (oztruva@gmail.com)

  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. Richard Avatar
    Richard

    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?

    1. Riichard, these fileds store the handles of the cache structure table (type 7), you must decode this table using the SMBIOS spec http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf and then compare the handle values.

  10. […] nicht mehr unter Win 64bit funktioniert haben. Eine sehr gute Anleitung findest du hier: http://theroadtodelphi.wordpress.com…-using-delphi/ Lg, […]

Leave a Reply