?
Solved

Get BIOS serial number

Posted on 2004-11-02
11
Medium Priority
?
9,618 Views
Last Modified: 2008-01-09
sorry. it's a repeated question;

I want to get bios serial number.
I had a code, and it worked, but unfortunatlly NOT now!
maybe because of new version of delphi (7), or WindowsXP, or my hardware! I don't know.
here is my code:

function GetBiosInfoAsText: string;
var
  P, Q: PAnsiChar;
begin
  Q := nil;
  P := PChar(Ptr($FE000));
  repeat
    if Q <> nil then begin
      if not (P^ in [#10, #13, #32..#126, #169, #184]) then begin
        if (P^ = #0) and (P - Q >= 8) then begin
          Result := Result + TrimRight(string(Q)) + #13#10;
        end;
        Q := nil;
      end;
    end else
      if P^ in [#33..#126, #169, #184] then
        Q := P;
    Inc(P);
  until P > PChar(Ptr($FFFFF));
  Result := TrimRight(Result);
end;

I will thank you for your attention.
0
Comment
Question by:mehdi_m
11 Comments
 
LVL 7

Expert Comment

by:LRHGuy
ID: 12479206
I tried your code here with Delphi7 on Win ME and it works fine!
0
 
LVL 12

Expert Comment

by:esoftbg
ID: 12480677
I tested your code with Delphi 7 under Windows XP, SP2 and it raises an exception:
Access violation at address 00450D20 in module 'Q_21192399.exe'. Read of address 000FE000.
I think about it succeed or not depends on the hardware ....
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12481385
uses
  ActiveX, WbemScripting_TLB;

function GetSerialNumber: string;
const
  sQuery = 'select SerialNumber from Win32_BIOS';
var
  Item: SWbemObject;
  NumProp: LongWord;
  ObjectSet: ISWbemObjectSet;
  OleProperty: OleVariant;
begin
  ObjectSet := CoSWbemLocator.Create.ConnectServer( '', 'root\cimv2', '', '', '', '', 0, nil ).ExecQuery( sQuery, 'WQL', wbemFlagBidirectional, nil );
  if Succeeded( (ObjectSet._NewEnum as IEnumVariant).Next( 1, OleProperty, NumProp ) ) and ( NumProp > 0 ) and Succeeded( IDispatch( OleProperty ).QueryInterface( SWBemObject, Item ) ) then begin
    Result := VarToStr( Item.Properties_.Item( 'SerialNumber', 0 ) );
  end else begin
    Result := '<Not found>';
  end;
end;

WMI is so powerful to get this kind of information... :-)

http://www.workshop-alex.org/sources/WbemScripting_TLB/WbemScripting_TLB.html or http://www.workshop-alex.org/sources/WbemScripting_TLB/WbemScripting_TLB.pas for that WMI unit for Delphi 7 if you don't want to create it yourself...

The method you've chosen might or might not work but it sure does violate the rules of decent programming by just viewing the contents of a fixed memory address. On some systems, the BIOS information might not even be at that location to begin with. Especially on WinXP which does NOT allow those kinds of hacks...
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:mehdi_m
ID: 12484836
Dear Workshop_Alex

I tried it. but the result of function is just one space (Result := ' ')

Could you help me why?
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12488761
Weird. Maybe that really is the serial number of the BIOS. Do you have any way to check the BIOS number in some other way?
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12492369
I tried the code on my system at work, using Delphi 5. It could be that this makes a difference. I've created a VBScript version of the query which looks like this:

'----------------------<Start>----------------------
Dim refWMIService
Dim colBIOS
Dim refItem
Set refWMIService = GetObject( "winMgmts:" )
set colBIOS = refWMIService.ExecQuery( "select SerialNumber from Win32_BIOS" )
for each refItem in colBIOS
  WScript.echo "Serial number: " & refItem.SerialNumber
Next
'----------------------<Stop>----------------------

The above code should display the right serial number. If this too is a space then I think your BIOS serial number is indeed a space. On my system, I get a value of SerialNumber = SYS-1234567890 which is a pretty typical number too.
You could replace "Win32_BIOS" in the query with "CIM_BIOSElement" but I just get the same value. So, thinking there might be a flaw in this, I just used 'Computer Management' to check the serial number there. But on W2K I don't see any serial number there.

If you want to use some BIOS value as part of some copy-security, maybe you should use SMBIOSBIOSVersion or BIOSVersion (requires XP) instead of the SerialNumber.
0
 

Author Comment

by:mehdi_m
ID: 12502980
Thank you very much, you may right that my SerialNumber is ' '.
Can you help me on how to check it in 'Computer Management' ?

As a matter of fact I just need an unique code. when I use SMBIOSBIOSVersion or BIOSVersion in your previous delphi code, it raised an exception EVariantTypeCastError with message 'Could not convert variant of type (Dispatch) into type (String)'.
and when I use "CIM_BIOSElement" istead of "Win32_BIOS" it raised exception EOleException with message 'Invalid query'.

It would be very good for me to do the operation in Delphi instead of VBScript. or is there anyway to run VBScript in Delphi? I don't know.

0
 

Author Comment

by:mehdi_m
ID: 12503006
Thank you very much, you may right that my SerialNumber is ' '.
Can you help me on how to check it in 'Computer Management' ?
Is this value: "Coputer Managment\Servises and Applications\WMI Control\Properties\Root\CIMV2\ms_409" my serial number?

As a matter of fact I just need an unique code. when I use SMBIOSBIOSVersion or BIOSVersion in your previous delphi code, it raised an exception EVariantTypeCastError with message 'Could not convert variant of type (Dispatch) into type (String)'.
and when I use "CIM_BIOSElement" istead of "Win32_BIOS" it raised exception EOleException with message 'Invalid query'.

It would be very good for me to do the operation in Delphi instead of VBScript. or is there anyway to run VBScript in Delphi? I don't know.
0
 

Author Comment

by:mehdi_m
ID: 12503027
:) excuse me of twise sending . please read the second one (11/05/2004 02:48AM )
0
 
LVL 17

Accepted Solution

by:
Wim ten Brink earned 500 total points
ID: 12533132
Well, the VBScript example is just a test to see what it would return. The Delphi WMI code I posted just does the same. I just added the script so you could check if the error is related to Delphi or not.

I've searched in my own Computer management for the BIOS serial number and didn't find it. Apparantly MS doesn't consider it important enough. I can't access the branch you've mentioned either, except through some WMI enumeration tool I've once written. Apparantly "root\CIMV2\ms_409" is NOT where the serial number is stored.

But if you want to get the whole BIOS information just for an unique value, you could use this code:

function SerialNumber: string;
const
  sQuery = 'select SerialNumber from Win32_BIOS';
var
  Item: SWbemObject;
  NumProp: LongWord;
  ObjectSet: ISWbemObjectSet;
  OleProperty: OleVariant;
begin
  ObjectSet := CoSWbemLocator.Create.ConnectServer( '', 'root\cimv2', '', '', '', '', 0, nil ).ExecQuery( sQuery, 'WQL', wbemFlagBidirectional, nil );
  if Succeeded( ( ObjectSet._NewEnum as IEnumVariant ).Next( 1, OleProperty, NumProp ) ) and ( NumProp > 0 ) and Succeeded( IDispatch( OleProperty ).QueryInterface( SWBemObject, Item ) ) then begin
    Result := Item.Path_.RelPath;
  end
  else begin
    Result := '<Unknown>';
  end;
end;

In this case it returns the whole path for the BIOS information. On my system, this path is:
> Win32_BIOS.Name="Default System BIOS",SoftwareElementID="Default System BIOS",SoftwareElementState=3,TargetOperatingSystem=0,Version="Award Modular BIOS v6.0"
Not too unique, though...

Or use:

function SerialNumber: string;
const
  sQuery = 'select SerialNumber from Win32_BIOS';
var
  Item: SWbemObject;
  NumProp: LongWord;
  ObjectSet: ISWbemObjectSet;
  OleProperty: OleVariant;
begin
  ObjectSet := CoSWbemLocator.Create.ConnectServer( '', 'root\cimv2', '', '', '', '', 0, nil ).ExecQuery( sQuery, 'WQL', wbemFlagBidirectional, nil );
  if Succeeded( ( ObjectSet._NewEnum as IEnumVariant ).Next( 1, OleProperty, NumProp ) ) and ( NumProp > 0 ) and Succeeded( IDispatch( OleProperty ).QueryInterface( SWBemObject, Item ) ) then begin
    Result := Item.GetObjectText_(0);
  end
  else begin
    Result := '<Unknown>';
  end;
end;

In which case you get:
------------------------------------------------------------------
instance of Win32_BIOS
{
      Name = "Default System BIOS";
      SerialNumber = "SYS-1234567890";
      SoftwareElementID = "Default System BIOS";
      SoftwareElementState = 3;
      TargetOperatingSystem = 0;
      Version = "Award Modular BIOS v6.0";
};
------------------------------------------------------------------

There could also be a problem with your WMI version, though. It's a bit version-dependant and strongly related to the Internet Explorer version you use and the Windows version you use. And the hardware might have it's effects too. It's sometimes just a bit of trial-and-error. It could also be an access rights problem, with the administrator denying some users access to WMI, but that's unlikely.

I'm not sure why you get the 'Could not convert variant of type (Dispatch) into type (String)' message unless you forget to typecast the SerialNumber property to string by using "VarToStr( Item.Properties_.Item( 'SerialNumber', 0 ) );". The VarToStr is very important here.

But try to use the "Result := Item.GetObjectText_(0);" solution I posted above and tell me what it's result is. That might help.
0
 

Author Comment

by:mehdi_m
ID: 12710608
Dear Alex

Sorry to answer you so late, and thank you for your help. 'm now sure that my BIOS SerialNumber is just a space. and your two above codes worked well.

thank you.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses
Course of the Month13 days, 20 hours left to enroll

807 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question