GARANTIR DESCONTO

Fórum Número de série físico do HD... :: Solução :: ! #231252

10/05/2004

0

Amigos,

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

Vinicius2k

Responder

Posts

10/05/2004

Vinicius2k

Só uma observação : desliguem o Debug ou rodem a aplicação de teste ´por fora´ do Delphi. Ele sempre e levanta uma exceção antes de extrair o serial e ainda não consegui identificar a razão...
T+


Responder

Gostei + 0

11/05/2004

Marco Salles

Este topico js vem rodando ha tempos aqui no forum.....Surge uma esperança inovadora..Torcemos para que seje a palavra final no assunto]
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

Só uma observação : desliguem o Debug ou rodem a aplicação de teste ´por fora´ do Delphi. Ele sempre e levanta uma exceção antes de extrair o serial e ainda não consegui identificar a razão...


[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] :?: :?: :?:


Responder

Gostei + 0

11/05/2004

Vinicius2k

Obrigado Marco, mas o mérito é todo de quem desenvolveu o código... eu só o encontrei... :D

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


Responder

Gostei + 0

27/04/2005

Marco Salles

:P :P Ao Longo desse tempo , eu sempre indico , este tópico, quando o assunto é leitura do número de série físico do HD.

[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:


Responder

Gostei + 0

27/04/2005

Gandalf.nho

Talvez ele precise ser rodado a partir do HD para funcionar.


Responder

Gostei + 0

27/04/2005

Marco Salles

Talvez ele precise ser rodado a partir do HD para funcionar.


:wink: É o que eu Tb pensei a principio.. Vou voltar la e depois eu Post


Responder

Gostei + 0

27/04/2005

Vinicius2k

Existem adendos que precisam ser feitos a este tópico, que não foram mencionados originalmente, mas encontrei estas informações durante este tempo :

- 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+


Responder

Gostei + 0

27/04/2005

Cabelo

E aí Vinicius..

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


Responder

Gostei + 0

27/04/2005

Cabelo

Cara.. deu um pequeno erro..

No meu micro tenho dois HD´s..

Quando tento ler o serial, trava o micro..

Estou no SO win98..

tem idéia do pq?


Responder

Gostei + 0

27/04/2005

Vinicius2k

E ae Junior !

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+


Responder

Gostei + 0

27/04/2005

Marco Salles

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.


Como saber isto :?: :?: :?: :?: :cry: :cry: :cry:

Cabelo:
Estou no SO win98..


Viniciu:
mas como vc disse que é Win 9X


Esta nun entendi :?: :?: :?:


Responder

Gostei + 0

27/04/2005

Christian_adriano

Olá Vinicius,

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.


Responder

Gostei + 0

27/04/2005

Marco Salles

Se alguem conseguir usar :

Do tópico
http://forum.devmedia.com.br/viewtopic.php?t=58960&highlight=scsisn&sid=5cd283bbe592f0cf221b136382f13541
[b:48160374a0]Ultima dica do Cristian....[/b:48160374a0]

Forma de Usar: function PegarSerialSCSI : String; begin Result := Trim(Resultado); end; Abraços, Christian.


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:


Responder

Gostei + 0

27/04/2005

Christian_adriano

Olá Colega ´Marco Salles´, é o seguinte vc pode usar em vez do código :

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.


Responder

Gostei + 0

28/04/2005

Marco Salles

Obrigado amigo [b:b4c06b6808]christian_adriano[/b:b4c06b6808] , eu ja tentei esta forma anteriormente ....
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:


Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar