Fórum Número de série físico do HD... :: Solução :: ! #231252
10/05/2004
0
Acredito, ter conseguido um código definitivo para leitura do número de série físico do HD... apenas, não tenho certeza se funcionará em todos os discos, pois pelo que pude perceber ele opera com comandos S.M.A.R.T e os discos mais antigos não suportam esta funcionalidade... é necessário verificar ainda se mesmo o disco suportando, se o desligamento dessa ´feature´ no setup da placa-mãe não afeta a leitura...
Quem se interessar em testar...
// Extracting IDE(ATA) disk serial number.
// (c) 2000-2003 Alex Konshin
// mailto:akonshin@earthlink.net
// http://home.earthlink.net/~akonshin/index.htm
//
// 30 Jul 2000 created
// 22 Oct 2003 refactoring
unit IdeSN;
interface
//-------------------------------------------------------------
// Tries to extract the serial number from the first IDE disk that is found in the system.
// Returns an empty string if IDE disk is not found.
function GetIdeSN : String;
//-------------------------------------------------------------
// Tries to extract the serial number from specified IDE disk.
//
// Parameters:
// ControllerNumber - SCSI port number of the controller.
// DriveNumber - Device index (0..4).
//
// Raises OSError exception in case of any error during this operation.
//
// Notes:
// 1. The parameter ControllerNumber is ignored on Windows 9x/ME platforms and should be 0.
// 2. This function CAN NOT extract SCSI disk serial number.
//
function GetIdeDiskSerialNumber( ControllerNumber, DriveNumber : Integer ) : String;
//=============================================================
implementation
uses
Windows,
SysUtils; // only for Win32Platform, SysErrorMessage and class Exception
{$IFDEF VER150}
{$DEFINE VER140}
{$ENDIF}
{$IFNDEF VER140}
procedure RaiseLastOSError;
begin
RaiseLastWin32Error;
end;
{$ENDIF}
//-------------------------------------------------------------
// Tries to extract the serial number from specified IDE disk.
//
// Parameters:
// ControllerNumber - SCSI port number of the controller.
// DriveNumber - SCSI port number of the controller.
// Notes:
// 1. The parameter ControllerNumber is ignored on Windows 9x/ME platforms and should be 0.
// 2. This function CAN NOT extract SCSI disk serial number.
//
function GetIdeDiskSerialNumber( ControllerNumber, DriveNumber : Integer ) : String;
type
TSrbIoControl = packed record
HeaderLength : ULONG;
Signature : Array[0..7] of Char;
Timeout : ULONG;
ControlCode : ULONG;
ReturnCode : ULONG;
Length : ULONG;
end;
SRB_IO_CONTROL = TSrbIoControl;
PSrbIoControl = ^TSrbIoControl;
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;
IDEREGS = TIDERegs;
PIDERegs = ^TIDERegs;
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;
SENDCMDINPARAMS = TSendCmdInParams;
PSendCmdInParams = ^TSendCmdInParams;
TIdSector = packed record
wGenConfig : Word;
wNumCyls : Word;
wReserved : Word;
wNumHeads : Word;
wBytesPerTrack : Word;
wBytesPerSector : Word;
wSectorsPerTrack : Word;
wVendorUnique : Array[0..2] of Word;
sSerialNumber : Array[0..19] of Char;
wBufferType : Word;
wBufferSize : Word;
wECCSize : Word;
sFirmwareRev : Array[0..7] of Char;
sModelNumber : Array[0..39] of Char;
wMoreVendorUnique : Word;
wDoubleWordIO : Word;
wCapabilities : Word;
wReserved1 : Word;
wPIOTiming : Word;
wDMATiming : Word;
wBS : Word;
wNumCurrentCyls : Word;
wNumCurrentHeads : Word;
wNumCurrentSectorsPerTrack : Word;
ulCurrentSectorCapacity : ULONG;
wMultSectorStuff : Word;
ulTotalAddressableSectors : ULONG;
wSingleWordDMA : Word;
wMultiWordDMA : Word;
bReserved : Array[0..127] of Byte;
end;
PIdSector = ^TIdSector;
const
IDE_ID_FUNCTION = $EC;
IDENTIFY_BUFFER_SIZE = 512;
DFP_RECEIVE_DRIVE_DATA = $0007c088;
IOCTL_SCSI_MINIPORT = $0004d008;
IOCTL_SCSI_MINIPORT_IDENTIFY = $001b0501;
DataSize = sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE;
BufferSize = SizeOf(SRB_IO_CONTROL)+DataSize;
W9xBufferSize = IDENTIFY_BUFFER_SIZE+16;
var
hDevice : THandle;
cbBytesReturned : DWORD;
s : String;
pInData : PSendCmdInParams;
pOutData : Pointer; // PSendCmdInParams;
Buffer : Array[0..BufferSize-1] of Byte;
srbControl : TSrbIoControl absolute Buffer;
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;
begin
Result := ´´;
FillChar(Buffer,BufferSize,#0);
if Win32Platform=VER_PLATFORM_WIN32_NT then
begin // Windows NT, Windows 2000
Str(ControllerNumber,s);
// Get SCSI port handle
hDevice := CreateFile(
PChar(´\\.\Scsi´+s+´:´),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
if hDevice=INVALID_HANDLE_VALUE then RaiseLastOSError;
try
srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL);
System.Move(´SCSIDISK´,srbControl.Signature,8);
srbControl.Timeout := 2;
srbControl.Length := DataSize;
srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;
pInData := PSendCmdInParams(PChar(@Buffer)+SizeOf(SRB_IO_CONTROL));
pOutData := pInData;
with pInData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := DriveNumber;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0 or ((DriveNumber and 1) shl 4);
bCommandReg := IDE_ID_FUNCTION;
end;
end;
if not DeviceIoControl( hDevice, IOCTL_SCSI_MINIPORT, @Buffer, BufferSize, @Buffer, BufferSize, cbBytesReturned, nil ) then RaiseLastOSError;
finally
CloseHandle(hDevice);
end;
end
else
begin // Windows 95 OSR2, Windows 98
hDevice := CreateFile( ´\\.\SMARTVSD´, 0, 0, nil, CREATE_NEW, 0, 0 );
if hDevice=INVALID_HANDLE_VALUE then RaiseLastOSError;
try
pInData := PSendCmdInParams(@Buffer);
pOutData := PChar(@pInData^.bBuffer);
with pInData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := DriveNumber;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0 or ((DriveNumber and 1) shl 4);
bCommandReg := IDE_ID_FUNCTION;
end;
end;
if not DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA, pInData, SizeOf(TSendCmdInParams)-1, pOutData, W9xBufferSize, cbBytesReturned, nil ) then RaiseLastOSError;
finally
CloseHandle(hDevice);
end;
end;
with PIdSector(PChar(pOutData)+16)^ do
begin
ChangeByteOrder(sSerialNumber,SizeOf(sSerialNumber));
SetString(Result,sSerialNumber,SizeOf(sSerialNumber));
end;
Result := Trim(Result);
end;
//-------------------------------------------------------------
function GetIdeSN : String;
var
iController, iDrive, maxController : Integer;
begin
Result := ´´;
maxController := 15;
if Win32Platform<>VER_PLATFORM_WIN32_NT then maxController := 0;
for iController := 0 to maxController do
begin
for iDrive := 0 to 4 do
begin
try
Result := GetIdeDiskSerialNumber(iController,iDrive);
if Result<>´´ then Exit;
except
// ignore exceptions
end;
end;
end;
end;
end.Exemplo de utilização :
procedure GetIDESerial; var S: String; begin S:= GetIdeSN; if S <> ´´ then edtSN.Text:= S; end;
Peço que postem os resultados dos testes e em qual equipamento (HD e Sistema Operacional)... eu já testei com Windows 95R2 / 98 / 98SE / 2000 e só consegui extrair o serial de HDs >= 4GB...
Espero ter ajudado.
T+
Vinicius
Vinicius2k
Curtir tópico
+ 0Posts
10/05/2004
Vinicius2k
T+
Gostei + 0
11/05/2004
Marco Salles
Rodei e Beleza...Agradecemos a solidariedade de nosso amigo Vinicius.2K
por esta relevante contribuição...
Uso delphi 5.0 e Sistema Operacional :WINDOWS-XP
[b:5ecbba1c2a]So uma observação[/b:5ecbba1c2a]: Isto não ocorreu...Não sei se é porque , eu criei um a aplicação e Depois criei uma unit onde eu [b:5ecbba1c2a]colei[/b:5ecbba1c2a] os métodos sugeridos, e depois no form Principal eu Chamei os Métodos da Unit [b:5ecbba1c2a]UIdeSN[/b:5ecbba1c2a]......O resultado é que [b:5ecbba1c2a]Não houve exceção [/b:5ecbba1c2a] :?: :?: :?:
Gostei + 0
11/05/2004
Vinicius2k
Sobre a exceção, acredito que tenha alguma relação com as diretivas de compilação existentes no código e talvez com o conjunto Delphi + OS... o meu Delphi é o 7... mas ele só levanta a exceção com o debug ligado, no meu caso...
T+
Vinicius
Gostei + 0
27/04/2005
Marco Salles
[URL=http://www.imageshack.us][img:4217f5bf1c]http://img35.echo.cx/img35/808/imagemaplicativohd3pm.jpg[/img:4217f5bf1c][/URL]
Porém , gerei um executavel , e o Gravei no Disquete... Ao rodar o Aplicativo Via Disquete No Computador Do Cliente (Windows 98 Com HD >4.0G) eu não obtenho Numero Nenhum.. O Que sera que estou fazendo de errado :cry: :cry: :cry:
Gostei + 0
27/04/2005
Gandalf.nho
Gostei + 0
27/04/2005
Marco Salles
:wink: É o que eu Tb pensei a principio.. Vou voltar la e depois eu Post
Gostei + 0
27/04/2005
Vinicius2k
- O disco precisa ter suporte a S.M.A.R.T, mas ele não precisa estar habilitado no BIOS... basta que o suporte exista.
- Este código não é suportado Windows 95 (primeira versão). Só funciona em Windows 95 OSR2/98/98SE/Me/NT4/2000/XP.
- Windows 9x: SMARTVSD.VXD precisa estar instalado. É necessário copiá-lo da pasta C:\Windows\System para a pasta C:\Windows\System\IoSubsys e reiniciar a máquina.
:wink:
T+
Gostei + 0
27/04/2005
Cabelo
blz?
Cara testei aqui e blz.. rodou legal..
Rodei num micro com HD de 40 GB e um com 8 GB e nos dois ele leu perfeitamente..
Gostei + 0
27/04/2005
Cabelo
No meu micro tenho dois HD´s..
Quando tento ler o serial, trava o micro..
Estou no SO win98..
tem idéia do pq?
Gostei + 0
27/04/2005
Vinicius2k
Nunca testei este código em máquinas com mais de um disco físico (apenas com mais de uma partição), por isso não sei o que pode ser.
Vou tentar testar isto também, mas como vc disse que é Win 9X, vc observou a necessidade do SMARTVSD.VXD na \system\iosubsys ?
T+
Gostei + 0
27/04/2005
Marco Salles
Como saber isto :?: :?: :?: :?: :cry: :cry: :cry:
Cabelo:
Viniciu:
Esta nun entendi :?: :?: :?:
Gostei + 0
27/04/2005
Christian_adriano
Também tinha colocado algo parecido nesse tópico : [url]http://forum.devmedia.com.br/viewtopic.php?t=58960&highlight=scsisn&sid=5cd283bbe592f0cf221b136382f13541[/url]
Nesse post coloquei tb algo para pegar seriais de HD ´Scsi´ tb.
t+
Christian.
Gostei + 0
27/04/2005
Marco Salles
Do tópico
http://forum.devmedia.com.br/viewtopic.php?t=58960&highlight=scsisn&sid=5cd283bbe592f0cf221b136382f13541
[b:48160374a0]Ultima dica do Cristian....[/b:48160374a0]
Favor me comunicar...
[b:48160374a0]Não da para entender qual a função , que modifica o valor da variável Resultado [/b:48160374a0]:cry: :cry: :cry:
Desse modo , [b:48160374a0]PegarserialASCSI [/b:48160374a0]a gente so ta lendo o Valor Da VAriavel Resultado, que a principio e LIXO :?: :?: :?: :?:
:arrow: :arrow: Note que[b:48160374a0] Resultado [/b:48160374a0]não é um método , mas sim uma variável
Agora quanto a função [b:48160374a0]GetIdeSN[/b:48160374a0] Retornou o [b:48160374a0]mesmo valor [/b:48160374a0]que a função originau [b:48160374a0]GetIDESerial[/b:48160374a0] do [b:48160374a0]Vinicius[/b:48160374a0] :P :P :P :P :P Como era de se esperar :wink:
Gostei + 0
27/04/2005
Christian_adriano
procedure RetornarSerial; begin sDeviceName := ParamStr(1); if Trim(sDeviceName) = ´´ then begin Resultado := ´´; Exit; end; hDevice := GetDeviceHandle(sDeviceName); if hDevice=INVALID_HANDLE_VALUE then Resultado := ´´ //(´Error on GetDeviceHandle: ´ + SysErrorMessage(GetLastError)) else try sSerNum := ScsiHddSerialNumber(hDevice); if Trim(sSerNum) = ´´ then Resultado := ´´ //(´Error on DeviceIoControl: ´ + SysErrorMessage(GetLastError)) else Resultado := Trim(sSerNum); finally CloseHandle(hDevice); end; end;
Usar esse para pegar seriais de HD ´Scsi´ :
function RetornarSerial : String; begin sDeviceName := ParamStr(1); if Trim(sDeviceName) = ´´ then begin result := ´´; Exit; end; hDevice := GetDeviceHandle(sDeviceName); if hDevice=INVALID_HANDLE_VALUE then Result := ´´ //(´Error on GetDeviceHandle: ´ + SysErrorMessage(GetLastError)) else try sSerNum := ScsiHddSerialNumber(hDevice); if Trim(sSerNum) = ´´ then Result := ´´ //(´Error on DeviceIoControl: ´ + SysErrorMessage(GetLastError)) else Result := Trim(sSerNum); finally CloseHandle(hDevice); end; end;
´
É só vc alterar a forma de pegar o serial:
De:
[color=red:5f0c460cc4]procedure RetornarSerial;[/color:5f0c460cc4]
Para:
[color=red:5f0c460cc4]function RetornarSerial : String;[/color:5f0c460cc4]
implementei daquela forma conforme a minha necessidade.
t+
Christian.
Gostei + 0
28/04/2005
Marco Salles
I Mais , declarei a Função
type TScsiPassThrough = record Length : Word; ........... .......... end; Function RetornarSerial : String; var hDevice : THandle = 0; sSerNum, sDeviceName, Resultado : String;
:arrow: Para ela ser visto em outro formulário
Mas ao chamar a Função em outra Unit
procedure TForm1.Button1Click(Sender: TObject); begin Edit1.Text:=RetornarSerial; end;
Não obtenho nada no edit1.text :cry: :cry: :cry: :cry:
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)