Jmaurin
asked on
Machine unique ID - how to?
Hi...
Please, how can i generate machine unique ID?
I can't use processor serial because some machines don't have it.
I wanna unique ID for a lot of machines on my network (including Pentium (100Mhz), Pentium 2, Athlon, P4, etc etc...)
Please, how can i generate machine unique ID?
I can't use processor serial because some machines don't have it.
I wanna unique ID for a lot of machines on my network (including Pentium (100Mhz), Pentium 2, Athlon, P4, etc etc...)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I can get HDD serial number under Windows 2000 / XP ...., (can't get it under Win 95 / 98 / Millenium)
esoftbg, you mean about the logical volume HDD ... you have serials for C:, D:, etc...
after format of this logical drives, this numbers are changed...
If you mean physical HDD serial:
https://www.experts-exchange.com/questions/20490497/HDD-physical-serial-number.html
Another tips is to get CPU or BIOS serials, there are such examples/components on the internet, but I don't think you can use it user Windows 2003 Server for example...
after format of this logical drives, this numbers are changed...
If you mean physical HDD serial:
https://www.experts-exchange.com/questions/20490497/HDD-physical-serial-number.html
Another tips is to get CPU or BIOS serials, there are such examples/components on the internet, but I don't think you can use it user Windows 2003 Server for example...
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
This code extracts the physical serial number from HDDs:
unit Unit1_Q_21134979;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, DBT, StdCtrls;
const
IDE_ID_FUNCTION = $EC; // Returns ID sector for ATA.
CAP_IDE_ID_FUNCTION = 1; // ATAPI ID command supported
IDENTIFY_BUFFER_SIZE = 512;
DFP_RECEIVE_DRIVE_DATA = $0007c088;
type
TForm1 = class(TForm)
SpeedButton1: TSpeedButton;
ListBox: TListBox;
procedure SpeedButton1Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
function Physical_SN(Id: Integer): Int64;
end;
USHORT = Word;
TIdBuffer = array [0..IDENTIFY_BUFFER_SIZE-1 ] of Byte;
TGetVersionOutParams = packed record
bVersion : BYTE; // Binary driver version.
bRevision : BYTE; // Binary driver revision.
bReserved : BYTE; // Not used.
bIDEDeviceMap : BYTE; // Bit map of IDE devices.
fCapabilities : DWORD; // Bit mask of driver capabilities.
dwReserved : Array[0..3] of DWORD; // For future use.
end;
TIdSector = packed record
wGenConfig : USHORT;
wNumCyls : USHORT;
wReserved : USHORT;
wNumHeads : USHORT;
wBytesPerTrack : USHORT;
wBytesPerSector : USHORT;
wSectorsPerTrack : USHORT;
wVendorUnique : Array[0..2] of USHORT;
sSerialNumber : Array[0..19] of CHAR;
wBufferType : USHORT;
wBufferSize : USHORT;
wECCSize : USHORT;
sFirmwareRev : Array[0..7] of CHAR;
sModelNumber : Array[0..39] of CHAR;
wMoreVendorUnique : USHORT;
wDoubleWordIO : USHORT;
wCapabilities : USHORT;
wReserved1 : USHORT;
wPIOTiming : USHORT;
wDMATiming : USHORT;
wBS : USHORT;
wNumCurrentCyls : USHORT;
wNumCurrentHeads : USHORT;
wNumCurrentSectorsPerTrack : USHORT;
ulCurrentSectorCapacity : ULONG;
wMultSectorStuff : USHORT;
ulTotalAddressableSectors : ULONG;
wSingleWordDMA : USHORT;
wMultiWordDMA : USHORT;
bReserved : Array[0..127] of BYTE;
end;
TDriverStatus = packed record
bDriverError : Byte; // Error code from driver, or 0 if no error.
bIDEStatus : Byte; // Contents of IDE Error register. Only valid when bDriverError is SMART_IDE_ERROR.
bReserved : Array[0..1] of Byte; // Reserved for future expansion.
dwReserved : Array[0..1] of DWORD; // Reserved for future expansion.
end;
TSendCmdOutParams = packed record
cBufferSize : DWORD; // Size of bBuffer in bytes
DriverStatus : TDriverStatus; // Driver status structure.
bBuffer : Array[0..0] of BYTE; // Buffer of arbitrary length in which to store the data read from the drive.
end;
TIDERegs = packed record
bFeaturesReg : BYTE; // Used for specifying SMART "commands".
bSectorCountReg : BYTE; // IDE sector count register
bSectorNumberReg : BYTE; // IDE sector number register
bCylLowReg : BYTE; // IDE low order cylinder value
bCylHighReg : BYTE; // IDE high order cylinder value
bDriveHeadReg : BYTE; // IDE drive/head register
bCommandReg : BYTE; // Actual IDE command.
bReserved : BYTE; // reserved for future use. Must be zero.
end;
TSendCmdInParams = packed record
cBufferSize : DWORD; // Buffer size in bytes
irDriveRegs : TIDERegs; // Structure with drive register values.
bDriveNumber : BYTE; // Physical drive number to send command to (0,1,2,3).
bReserved : Array[0..2] of Byte; // Reserved for future expansion.
dwReserved : Array[0..3] of DWORD; // For future use.
bBuffer : Array[0..0] of Byte; // Input buffer.
end;
var
Form1: TForm1;
var
aIdBuffer: TIdBuffer;
Id_Sector: TIdSector absolute aIdBuffer;
function DirectIdentify(I: DWORD): Boolean;
implementation
{$R *.dfm}
var
OSVersionInfo: TOSVersionInfo;
function GetPhysicalDriveHandle(Dri veNum: Byte; DesireAccess: ACCESS_MASK): THandle;
var
S: string;
begin
OSVersionInfo.dwOSVersionI nfoSize := SizeOf(OSVersionInfo);
GetVersionEx(OSVersionInfo );
if OSVersionInfo.dwPlatformId =VER_PLATF ORM_WIN32_ NT then // Windows NT, Windows 2000
begin
Str(DriveNum,s); // avoid SysUtils
Result := CreateFile( PChar('\\.\PhysicalDrive'+ S), DesireAccess, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
end
else // Windows 95 OSR2, Windows 98
Result := CreateFile( '\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 );
{$ifdef debug}
if Result=INVALID_HANDLE_VALU E then
OutputDebugString(PChar('E rror on CreateFile: '+SysErrorMessage(GetLastE rror)));
{$endif}
end;
function SmartIdentifyDirect( hDevice : THandle; bDriveNum : Byte; bIDCmd : Byte; var IdSector : TIdSector; var IdSectorSize : LongInt ) : BOOL;
const
BufferSize = SizeOf(TSendCmdOutParams)+ IDENTIFY_B UFFER_SIZE -1;
var
SCIP: TSendCmdInParams;
Buffer : Array [0..BufferSize-1] of Byte;
SCOP : TSendCmdOutParams absolute Buffer;
dwBytesReturned : DWORD;
begin
FillChar(SCIP,SizeOf(TSend CmdInParam s)-1,#0);
FillChar(Buffer,BufferSize ,#0);
dwBytesReturned := 0;
IdSectorSize := 0;
// Set up data structures for IDENTIFY command.
with SCIP do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := bDriveNum;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4);
bCommandReg := bIDCmd; // The command can either be IDE identify or ATAPI identify.
end;
end;
Result := DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA, @SCIP, SizeOf(TSendCmdInParams)-1 , @SCOP, BufferSize, dwBytesReturned, nil );
if Result then
begin
IdSectorSize := dwBytesReturned-SizeOf(TSe ndCmdOutPa rams)+1;
if IdSectorSize<=0 then IdSectorSize := 0 else System.Move(SCOP.bBuffer,I dSector,Id SectorSize );
end;
end;
function DirectIdentify(I: DWORD): Boolean;
var
B: Boolean;
hDevice: THandle;
nIdSectorSize: LongInt;
begin
B := False;
FillChar(aIdBuffer, SizeOf(aIdBuffer), #0);
try
hDevice := GetPhysicalDriveHandle(I, GENERIC_READ or GENERIC_WRITE);
try
{$ifdef debug}
OutputDebugString(PChar('G etPhysical DriveHandl e return '+IntToHex(hDevice,8)));
{$endif}
if (hDevice<>INVALID_HANDLE_V ALUE) then
try
B := SmartIdentifyDirect(hDevic e, 0, IDE_ID_FUNCTION, Id_Sector, nIdSectorSize);
finally
{$ifdef debug}
OutputDebugString('PrintId SectorInfo end');
{$endif}
end;
finally
Result := B;
CloseHandle(hDevice);
end;
except
Result := False;
end;
end;
function Hex_To_Dec(S: string): Int64;
var
C: Char;
J: Integer;
II: Int64;
IH: Int64;
begin
IH := 0;
try
II := 1;
while (S<>'') do
begin
C := S[Length(S)];
if (C in ['0'..'9']) then
J := StrToInt(C)
else
J := Ord(C) - 55;
IH := IH + II * J;
Delete(S,Length(S),1);
II := II * 16;
end;
finally
Result := IH;
end;
end;
procedure ChangeByteOrder( var Data; Size : Integer );
var
ptr: PChar;
i: Integer;
c: Char;
begin
ptr := @Data;
for i := 0 to (Size shr 1)-1 do
begin
c := ptr^;
ptr^ := (ptr+1)^;
(ptr+1)^ := c;
Inc(ptr,2);
end;
end;
function TForm1.Physical_SN(Id: Integer): Int64;
type
TacOutBuffer = array[0..40] of Char;
var
I: Integer;
IH: Int64;
acOutBuffer: TacOutBuffer;
T: string;
begin
IH := 0;
try
DirectIdentify(Id);
with Id_Sector do
begin
ChangeByteOrder(sSerialNum ber, SizeOf(sSerialNumber));
acOutBuffer[SizeOf(sSerial Number)] := #0;
StrLCopy(acOutBuffer, sSerialNumber, SizeOf(sSerialNumber));
I := 0;
T := '';
while (acOutBuffer[I] in [#32..#127]) do
begin
T := T + acOutBuffer[I];
Inc(I);
end;
T := Trim(T);
ListBox.Items.Add(Char(Id+ 67) + ':');
ListBox.Items.Add('Hex. Serial num:' + T);
IH := Hex_To_Dec(T);
ListBox.Items.Add('Dec. Serial num:' + IntToStr(IH));
end;
finally
Result := IH;
end;
end;
procedure TForm1.SpeedButton1Click(S ender: TObject);
begin
ListBox.Clear;
Physical_SN(0); // C:
Physical_SN(1); // D:
Physical_SN(2); // E:
end;
end.
unit Unit1_Q_21134979;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, DBT, StdCtrls;
const
IDE_ID_FUNCTION = $EC; // Returns ID sector for ATA.
CAP_IDE_ID_FUNCTION = 1; // ATAPI ID command supported
IDENTIFY_BUFFER_SIZE = 512;
DFP_RECEIVE_DRIVE_DATA = $0007c088;
type
TForm1 = class(TForm)
SpeedButton1: TSpeedButton;
ListBox: TListBox;
procedure SpeedButton1Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
function Physical_SN(Id: Integer): Int64;
end;
USHORT = Word;
TIdBuffer = array [0..IDENTIFY_BUFFER_SIZE-1
TGetVersionOutParams = packed record
bVersion : BYTE; // Binary driver version.
bRevision : BYTE; // Binary driver revision.
bReserved : BYTE; // Not used.
bIDEDeviceMap : BYTE; // Bit map of IDE devices.
fCapabilities : DWORD; // Bit mask of driver capabilities.
dwReserved : Array[0..3] of DWORD; // For future use.
end;
TIdSector = packed record
wGenConfig : USHORT;
wNumCyls : USHORT;
wReserved : USHORT;
wNumHeads : USHORT;
wBytesPerTrack : USHORT;
wBytesPerSector : USHORT;
wSectorsPerTrack : USHORT;
wVendorUnique : Array[0..2] of USHORT;
sSerialNumber : Array[0..19] of CHAR;
wBufferType : USHORT;
wBufferSize : USHORT;
wECCSize : USHORT;
sFirmwareRev : Array[0..7] of CHAR;
sModelNumber : Array[0..39] of CHAR;
wMoreVendorUnique : USHORT;
wDoubleWordIO : USHORT;
wCapabilities : USHORT;
wReserved1 : USHORT;
wPIOTiming : USHORT;
wDMATiming : USHORT;
wBS : USHORT;
wNumCurrentCyls : USHORT;
wNumCurrentHeads : USHORT;
wNumCurrentSectorsPerTrack
ulCurrentSectorCapacity : ULONG;
wMultSectorStuff : USHORT;
ulTotalAddressableSectors : ULONG;
wSingleWordDMA : USHORT;
wMultiWordDMA : USHORT;
bReserved : Array[0..127] of BYTE;
end;
TDriverStatus = packed record
bDriverError : Byte; // Error code from driver, or 0 if no error.
bIDEStatus : Byte; // Contents of IDE Error register. Only valid when bDriverError is SMART_IDE_ERROR.
bReserved : Array[0..1] of Byte; // Reserved for future expansion.
dwReserved : Array[0..1] of DWORD; // Reserved for future expansion.
end;
TSendCmdOutParams = packed record
cBufferSize : DWORD; // Size of bBuffer in bytes
DriverStatus : TDriverStatus; // Driver status structure.
bBuffer : Array[0..0] of BYTE; // Buffer of arbitrary length in which to store the data read from the drive.
end;
TIDERegs = packed record
bFeaturesReg : BYTE; // Used for specifying SMART "commands".
bSectorCountReg : BYTE; // IDE sector count register
bSectorNumberReg : BYTE; // IDE sector number register
bCylLowReg : BYTE; // IDE low order cylinder value
bCylHighReg : BYTE; // IDE high order cylinder value
bDriveHeadReg : BYTE; // IDE drive/head register
bCommandReg : BYTE; // Actual IDE command.
bReserved : BYTE; // reserved for future use. Must be zero.
end;
TSendCmdInParams = packed record
cBufferSize : DWORD; // Buffer size in bytes
irDriveRegs : TIDERegs; // Structure with drive register values.
bDriveNumber : BYTE; // Physical drive number to send command to (0,1,2,3).
bReserved : Array[0..2] of Byte; // Reserved for future expansion.
dwReserved : Array[0..3] of DWORD; // For future use.
bBuffer : Array[0..0] of Byte; // Input buffer.
end;
var
Form1: TForm1;
var
aIdBuffer: TIdBuffer;
Id_Sector: TIdSector absolute aIdBuffer;
function DirectIdentify(I: DWORD): Boolean;
implementation
{$R *.dfm}
var
OSVersionInfo: TOSVersionInfo;
function GetPhysicalDriveHandle(Dri
var
S: string;
begin
OSVersionInfo.dwOSVersionI
GetVersionEx(OSVersionInfo
if OSVersionInfo.dwPlatformId
begin
Str(DriveNum,s); // avoid SysUtils
Result := CreateFile( PChar('\\.\PhysicalDrive'+
end
else // Windows 95 OSR2, Windows 98
Result := CreateFile( '\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 );
{$ifdef debug}
if Result=INVALID_HANDLE_VALU
OutputDebugString(PChar('E
{$endif}
end;
function SmartIdentifyDirect( hDevice : THandle; bDriveNum : Byte; bIDCmd : Byte; var IdSector : TIdSector; var IdSectorSize : LongInt ) : BOOL;
const
BufferSize = SizeOf(TSendCmdOutParams)+
var
SCIP: TSendCmdInParams;
Buffer : Array [0..BufferSize-1] of Byte;
SCOP : TSendCmdOutParams absolute Buffer;
dwBytesReturned : DWORD;
begin
FillChar(SCIP,SizeOf(TSend
FillChar(Buffer,BufferSize
dwBytesReturned := 0;
IdSectorSize := 0;
// Set up data structures for IDENTIFY command.
with SCIP do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := bDriveNum;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4);
bCommandReg := bIDCmd; // The command can either be IDE identify or ATAPI identify.
end;
end;
Result := DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA, @SCIP, SizeOf(TSendCmdInParams)-1
if Result then
begin
IdSectorSize := dwBytesReturned-SizeOf(TSe
if IdSectorSize<=0 then IdSectorSize := 0 else System.Move(SCOP.bBuffer,I
end;
end;
function DirectIdentify(I: DWORD): Boolean;
var
B: Boolean;
hDevice: THandle;
nIdSectorSize: LongInt;
begin
B := False;
FillChar(aIdBuffer, SizeOf(aIdBuffer), #0);
try
hDevice := GetPhysicalDriveHandle(I, GENERIC_READ or GENERIC_WRITE);
try
{$ifdef debug}
OutputDebugString(PChar('G
{$endif}
if (hDevice<>INVALID_HANDLE_V
try
B := SmartIdentifyDirect(hDevic
finally
{$ifdef debug}
OutputDebugString('PrintId
{$endif}
end;
finally
Result := B;
CloseHandle(hDevice);
end;
except
Result := False;
end;
end;
function Hex_To_Dec(S: string): Int64;
var
C: Char;
J: Integer;
II: Int64;
IH: Int64;
begin
IH := 0;
try
II := 1;
while (S<>'') do
begin
C := S[Length(S)];
if (C in ['0'..'9']) then
J := StrToInt(C)
else
J := Ord(C) - 55;
IH := IH + II * J;
Delete(S,Length(S),1);
II := II * 16;
end;
finally
Result := IH;
end;
end;
procedure ChangeByteOrder( var Data; Size : Integer );
var
ptr: PChar;
i: Integer;
c: Char;
begin
ptr := @Data;
for i := 0 to (Size shr 1)-1 do
begin
c := ptr^;
ptr^ := (ptr+1)^;
(ptr+1)^ := c;
Inc(ptr,2);
end;
end;
function TForm1.Physical_SN(Id: Integer): Int64;
type
TacOutBuffer = array[0..40] of Char;
var
I: Integer;
IH: Int64;
acOutBuffer: TacOutBuffer;
T: string;
begin
IH := 0;
try
DirectIdentify(Id);
with Id_Sector do
begin
ChangeByteOrder(sSerialNum
acOutBuffer[SizeOf(sSerial
StrLCopy(acOutBuffer, sSerialNumber, SizeOf(sSerialNumber));
I := 0;
T := '';
while (acOutBuffer[I] in [#32..#127]) do
begin
T := T + acOutBuffer[I];
Inc(I);
end;
T := Trim(T);
ListBox.Items.Add(Char(Id+
ListBox.Items.Add('Hex. Serial num:' + T);
IH := Hex_To_Dec(T);
ListBox.Items.Add('Dec. Serial num:' + IntToStr(IH));
end;
finally
Result := IH;
end;
end;
procedure TForm1.SpeedButton1Click(S
begin
ListBox.Clear;
Physical_SN(0); // C:
Physical_SN(1); // D:
Physical_SN(2); // E:
end;
end.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Just another idea.... something I practise...
the serial numbers used for activation of my software are encrypted strings, which contains the customer name. and there is a point in the contract, which doesn't allow them to publish this information and penalty about this...
The other way is to activate your software via web site. Thus you can track when someone wants to active his software with wrong serial or serial, that was alredy used before...
the serial numbers used for activation of my software are encrypted strings, which contains the customer name. and there is a point in the contract, which doesn't allow them to publish this information and penalty about this...
The other way is to activate your software via web site. Thus you can track when someone wants to active his software with wrong serial or serial, that was alredy used before...
Comment only
Hi
I see that we are once again looking at unique PC identification - often for registering software.
If you are looking at a unique PC ID on the Network - all PC's on a Network (the original question) have a unique ID - its the PC Name!!!!!!
This is 100% true - however the really, really, unique ID under windows is the SID - the Security Identifier.
All PC's have a SID - its what identifies them under Windows. This is why when you change a PC on a network and give it the same name as the old one, things dont work out - because Windows uses the SID - not the Name.
Voodooman
Hi
I see that we are once again looking at unique PC identification - often for registering software.
If you are looking at a unique PC ID on the Network - all PC's on a Network (the original question) have a unique ID - its the PC Name!!!!!!
This is 100% true - however the really, really, unique ID under windows is the SID - the Security Identifier.
All PC's have a SID - its what identifies them under Windows. This is why when you change a PC on a network and give it the same name as the old one, things dont work out - because Windows uses the SID - not the Name.
Voodooman
The SID is still the only unique ID on a Windows network - the rest is rubbish
Voodooman
Voodooman
ASKER
Another problem: MAC is too big...
Another problem: if machine doesnt have lan card, just dial up connection (rare, i'm on a network!) but is possible...
another idea?