10

I am trying to make delphi program Server And Client so To Secure my App and To Make Sure all user are under control i should give them a unique Key that can't be change to not lose them Handle, So i think it should be HDD Serial Number + Bios SN , but i remember that Bios Can Be Change When remove motherboard Battery so it will not be work . so my choose now is HDD Real serial number i am try this code below to get it but it didn'r work

    unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,WbemScripting_TLB,ActiveX;

type
  TForm4 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form4: TForm4;

implementation

{$R *.dfm}

function GetWMIstring (wmiHost, wmiClass, wmiProperty : string):string;
var  // These are all needed for the WMI querying process
  Locator:  ISWbemLocator;
  Services: ISWbemServices;
  SObject:  ISWbemObject;
  ObjSet:   ISWbemObjectSet;
  SProp:    ISWbemProperty;
  Enum:     IEnumVariant;
  Value:    Cardinal;
  TempObj:  OleVariant;
  SN: string;
begin
  try
  Locator := CoSWbemLocator.Create;  // Create the Location object
  // Connect to the WMI service, with the root\cimv2 namespace
   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 // Trap any exceptions (Not having WMI installed will cause one!)
   on exception do
    result := '';
   end;
end;

procedure TForm4.Button1Click(Sender: TObject);
var
x:string;
Y:string;

begin


    X:=GetWMIstring('','Win32_BIOS','SerialNumber');
    Y:=GetWMIstring('','Win32_DiskDrive"','SerialNumber')     ;

    ShowMessage(x+';'+y);
end;

end.

*so please can any one correct my Code or Give me another idea Best regard's*

Machavity
  • 30,841
  • 27
  • 92
  • 100
Anajehad Walaa
  • 137
  • 1
  • 1
  • 6

2 Answers2

24

Your code is not working because you are passing a double-quote in the WMI class name.

change this code

GetWMIstring('','Win32_DiskDrive"','SerialNumber');

To this

GetWMIstring('','Win32_DiskDrive','SerialNumber');

Btw, you can improve a lot your WMI function (GetWMIstring) if you follow the recommendations of the answer to this question How can I improve the WMI performance using delphi?.

Try this sample (this code use late binding and don't need the WbemScripting_TLB unit)

  uses
      ActiveX,
      ComObj;

    var
      FSWbemLocator : OLEVariant;
      FWMIService   : OLEVariant;

    function  GetWMIstring(const WMIClass, WMIProperty:string): string;
    const
      wbemFlagForwardOnly = $00000020;
    var
      FWbemObjectSet: OLEVariant;
      FWbemObject   : OLEVariant;
      oEnum         : IEnumvariant;
      iValue        : LongWord;
    begin;
      Result:='';
      FWbemObjectSet:= FWMIService.ExecQuery(Format('Select %s from %s',[WMIProperty, WMIClass]),'WQL',wbemFlagForwardOnly);
      oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
      if oEnum.Next(1, FWbemObject, iValue) = 0 then

  if not VarIsNull(FWbemObject.Properties_.Item(WMIProperty).Value) then

     Result:=FWbemObject.Properties_.Item(WMIProperty).Value;

    FWbemObject:=Unassigned;
    end;

    procedure TForm4.Button1Click(Sender: TObject);
    var
      x:string;
      Y:string;
    begin
      FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');

      X:=GetWMIstring('Win32_BIOS','SerialNumber');
      Y:=GetWMIstring('Win32_PhysicalMedia','SerialNumber');

      ShowMessage(x+';'+y);
    end;
Community
  • 1
  • 1
RRUZ
  • 134,889
  • 20
  • 356
  • 483
  • 1
    +1. Good eye! That extra `"` was hard to spot before you pointed it out. :-) – Ken White Nov 04 '12 at 03:38
  • thanks very much for quick response , i have remove the double-quote from the class i didn't notice it but it still return not found and about , improve it for delphi console i don't know how to convert it to delphi app – Anajehad Walaa Nov 04 '12 at 03:49
  • Maybe you are using Windows XP? the MSDN [documentation](http://msdn.microsoft.com/en-us/library/windows/desktop/aa394132%28v=vs.85%29.aspx) about this property (SerialNumber) says `..Windows Server 2003, Windows XP, Windows 2000, and Windows NT 4.0: This property is not available. ` – RRUZ Nov 04 '12 at 03:51
  • Yes i am :) so what i can do now ? – Anajehad Walaa Nov 04 '12 at 04:03
  • use the [`Win32_PhysicalMedia`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa394346%28v=vs.85%29.aspx) WMI class instead, but please modify your function to retrieve WMI data, I just posted a sample on my answer. – RRUZ Nov 04 '12 at 04:12
  • thank you i try it but the number back from function so short , so it think it's not real HDD SN so, that i try Win32_DiskDrive – Anajehad Walaa Nov 04 '12 at 04:24
  • can i ask how to avoid message "could not convert variant of type null into type olestr" when back with null value for HDD SN – Anajehad Walaa Nov 04 '12 at 05:24
  • i try the fallow code it's work thank all spicily RRUZ if not VarIsNull(FWbemObject.Properties_.Item(WMIProperty).Value) then Result:=FWbemObject.Properties_.Item(WMIProperty).Value; FWbemObject:=Unassigned; – Anajehad Walaa Nov 04 '12 at 06:24
  • it worked if system has only one harddisk, what if more harddisk? – ET Worker Nov 25 '16 at 08:35
0

You should avoid, when more devices installed, PHYSICALDRIVE0 may not be first in WMI database. In my case (on my PC) is the PHYSICALDRIVE1 first in the result and PHYSICALDRIVE0 is second in order. I added where to sql query to select the PHYSICALDRIVE0 only and now it is OK. For Win32_DiskDrive is property name DeviceID, for Win32_PhysicalDrive is property name Tag. Here are changed parts of code:

function  GetWMIstring(const WMIClass, WMIProperty, WMIWhere:string): string;
var qry:string;
...
  qry:='SELECT '+WMIProperty+' FROM '+WMIClass;
  if WMIWhere<>'' then qry:=qry + ' WHERE '+WMIWhere;
  FWbemObjectSet:= FWMIService.ExecQuery(qry,'WQL',wbemFlagForwardOnly);
...
  x:=GetWMIstring('Win32_DiskDrive','SerialNumber','DeviceID="\\\\.\\PHYSICALDRIVE0"'));
  y:=GetWMIstring('Win32_PhysicalMedia','SerialNumber','Tag="\\\\.\\PHYSICALDRIVE0"'));

Dont forget to Call CoInitialize before calling this function !!!

xjikka
  • 9
  • 2
  • Can you edit your answer to be more clear? What does "is first be me" mean? And if you tell to call "CoInitialize", how can your code (that looks really strange to me with the three dots on the second and sixth line) work without it? – Nico Haase Apr 03 '18 at 14:13