Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Trucos (https://www.clubdelphi.com/foros/forumdisplay.php?f=52)
-   -   Numero de serie del disco duro (https://www.clubdelphi.com/foros/showthread.php?t=80767)

seoane 11-10-2006 18:29:34

Numero de serie del disco duro
 
Este truco sirve para obtener información sobre dispositivos de almacenamiento (discos duros, disquetes, memorias usb), aunque la información disponible puede variar de un tipo de dispositivo a otro.

Código Delphi [-]
const
  METHOD_BUFFERED = 0;
  FILE_ANY_ACCESS = 0;
  FILE_DEVICE_MASS_STORAGE = $2D;
  IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;

  IOCTL_STORAGE_QUERY_PROPERTY =
    (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or
    ($500 shl 2) or  METHOD_BUFFERED;

type
  PSTORAGE_DESCRIPTOR_HEADER = ^TSTORAGE_DESCRIPTOR_HEADER;
  TSTORAGE_DESCRIPTOR_HEADER = packed record
    Version: ULONG;
    Size: ULONG;
  end;

  PSTORAGE_DEVICE_DESCRIPTOR = ^STORAGE_DEVICE_DESCRIPTOR;
  STORAGE_DEVICE_DESCRIPTOR = packed record
    Version: ULONG;
    Size: ULONG;
    DeviceType: UCHAR;
    DeviceTypeModifier: UCHAR;
    RemovableMedia: Boolean;
    CommandQueueing: Boolean;
    VendorIdOffset: ULONG;
    ProductIdOffset: ULONG;
    ProductRevisionOffset: ULONG;
    SerialNumberOffset: ULONG;
    BusType: ULONG;
    RawPropertiesLength: ULONG;
    RawDeviceProperties: array[0..0] of UCHAR;
  end;

// Descodifica el numero de serie
function DecodeSerialNumber(SerialNumber: string): string;
var
  i: Integer;
begin
  Result:= EmptyStr;
  while Length(SerialNumber) > 0 do
  begin
    if TryStrToInt('$'+Copy(SerialNumber,1,4),i) then
    begin
      Result:= Result + Char(Lo(i)) + Char(Hi(i));
      Delete(SerialNumber,1,4);
    end else
    begin
      Result:= EmptyStr;
      Exit;
    end;
  end;
  Result:= Trim(Result);
end;

// Obtiene la informacion sobre el dispositivo
// Parametros:
//   Letra: Letra de la unidad (A,B,C,D...)
//   VendorId: Identificacion del vendedor
//   ProductId: Identificacion del producto
//   SerialNumber: Numero de serie
//   Extraible: Indica si el dispositivo es extraible (disquete, memoria usb)
//
function GetSerialNumber(Letra: Char; var VendorId: string; var ProductId: string;
  var SerialNumber: string; var Extraible: Boolean): string;
var
  Disk: THandle;
  Size: Cardinal;
  Buffer: Pointer;
  DeviceDescriptor: PSTORAGE_DEVICE_DESCRIPTOR;
begin
  Result:= EmptyStr;
  Disk:= CreateFile(PChar('\\.\' + Letra + ':'),GENERIC_READ,FILE_SHARE_READ
    or FILE_SHARE_WRITE,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if Disk <> INVALID_HANDLE_VALUE then
  begin
    GetMem(Buffer,12);
    try
      FillChar(Buffer^,12,0);
      if DeviceIOControl(Disk, IOCTL_STORAGE_QUERY_PROPERTY,
        Buffer,12,Buffer,12,Size, nil) then
      begin
        FreeMem(Buffer);
        Size:= PSTORAGE_DESCRIPTOR_HEADER(Buffer).Size;
        GetMem(Buffer, Size);
        FillChar(Buffer^,Size,0);
        if DeviceIOControl(Disk, IOCTL_STORAGE_QUERY_PROPERTY,
          Buffer,12,Buffer,Size,Size, nil) then
          begin
            DeviceDescriptor:= Buffer;
            Extraible:= DeviceDescriptor.RemovableMedia;
            if DeviceDescriptor.VendorIdOffset > 0 then
              VendorId:= String(PChar(Buffer) + DeviceDescriptor.VendorIdOffset)
            else
              VendorId:= EmptyStr;
            if DeviceDescriptor.ProductIdOffset > 0 then
              ProductId:= String(PChar(Buffer) + DeviceDescriptor.ProductIdOffset)
            else
              ProductId:= EmptyStr;
            if (DeviceDescriptor.SerialNumberOffset > 0) and
               (DeviceDescriptor.SerialNumberOffset < Size) then
              SerialNumber:= String(PChar(Buffer) + DeviceDescriptor.SerialNumberOffset)
            else
              SerialNumber:= EmptyStr;
          end else Result:= SysErrormessage(GetLastError);
      end else Result:= SysErrormessage(GetLastError);
    finally
      FreeMem(Buffer);
    end;
    CloseHandle(Disk);
  end else Result:= SysErrormessage(GetLastError);
end;

Un ejemplo de uso
Código Delphi [-]
var
  VendorId: string;
  ProductId: string;
  SerialNumber: string;
  Extraible: Boolean;
  Mensaje: string;
begin
  Mensaje:= GetSerialNumber('C', VendorId, ProductId, SerialNumber, Extraible);
  if Mensaje = EmptyStr then
  begin
    ShowMessage
    (
      'VendorId: '     + VendorID     + #13 +
      'ProductId: '    + ProductId    + #13 +
      'SerialNumber: ' + DecodeSerialNumber(SerialNumber) + #13 +
      'Extraible: '    + BoolToStr(Extraible,TRUE)
     );
  end else
    ShowMessage(Mensaje);
end;

En el ejemplo anterior intentamos obtener la información del Disco C, si no podemos mostramos el mensaje de error que nos devuelve la función GetSerialNumber. También hay que fijarse en que el numero de serie necesita ser descodificado, y que algunas memorias usb no muestran el numero de serie.

zarzuela 01-12-2006 23:11:00

ESTE TRUCO ESTA MUY BUENO, ME GUSTARIA QUE ME ENVIEN UNO DE COMO PASAR DIRECTORIOS DE UN DISCO A ATRO

ArdiIIa 04-01-2007 11:23:05

Muy bueno Seoane y muy completo parece, aunque seguramente con una llamda al API
Código Delphi [-]
GetVolumeInformation
en la mayoría de los casos sobra...

ArdiIIa 04-01-2007 11:26:47

Lo siento, quería decir que con una simple llamada al API
GetVolumeInformation, En la mayoria de los casos bastaría.

seoane 04-01-2007 13:04:20

Ardilla, el numero de serie que devuelve GetVolumeInformation, no se corresponde con el numero de serie físico del disco duro, solo sirve para identificar a la partición (compruebalo, cada partición devuelve un numero distinto aunque pertenezcan al mismo disco duro) y además cambia al formatear la partición. Son cosas completamente diferentes ...

rretamar 10-02-2007 13:48:47

Había un componente que daba los datos fisicos de un HD (fabricante, número de serie, y varias cosas más), pero era un componente (comercial) que usaba llamadas a una librería VXD (en Win9X) o un archivo .SYS (en versión para Win NT o superior). Se llamaba TVICPORT y es comercial.

Fuera de ese componente, no he encontrado la forma de obtener esos valores. Es una época los usaba como una medida de protección contra copia para un software que escribí.

Saludos, Tux

Gangster 22-04-2007 00:27:09

Hola una Pregunta esta funcion la estoy implementando dentro de un form nuevo toda esta funcion la pongo dentro de un unit nuevo todo esto lo pongo abajo de Implementation en el unit y lo corro y solo me da el product ID del disco duro no me da lo demas que necesito que es el serial el que me interesa no se qu eeste haciendo mal tengo el disco con dos particiones pero no me da el serial solo el producto ID no se si tenga mal eso de que este todo debajo del Implementation por favor si me pueden decir como ponerlo este truquito en Delphi 7 para que me trabaje Gracias.

Espero Respuesta

seoane 23-04-2007 15:51:24

Ganster, si el ProductId que obtienes es correcto, es que la función y lo demás funciona correctamente. El problema puede ser que algunos fabricantes no incluyen el numero de serie en sus discos, sobre todo si se trata de un disco usb. ¿Es un disco usb?

Gangster 24-04-2007 00:20:51

es un disco Tipo Ide Marca Hitachi, y ya lo probe en mi casa con un disco marca western tipo IDE y tambn me da el puro product ID entonces no se porque no me da bn lo otro que viene en el showmessage, asi como tal esta ahi asi la copie y la meti en un project nuevo, todo en un solo UNIT ojala y pueda decirme alguna otra razon o algo mal que este haciendo y gracias por contestar, Estoy trabajando en delphi 7.

seoane 24-04-2007 00:47:40

Pues Gangster, lo acabo de volver a probar por si al copiarlo se me hubiera pasado algo, pero a mi me funciona bien. Así que no se que puede estar ocurriendo.

¿Seguro que lo copias exactamente como yo lo pongo? Si haces algún cambio, por pequeño que sea, puede que sea ese el problema.

Gangster 24-04-2007 03:02:02

Hola Seoane ya lo probe con discos que solo tienen la particion C y si trabaja tu funcion, pero en los discos que tienen otra letra mas al C como particion ahi es cuando me falla la funcion, no sabes que letra es la que se le pasa en la funcion getserialnumber, cuando tienes en un solo disco Duro pero con la particion C y D o dos particiones gracias por tus respuestas y por tratar de darme razones en lo que haya hecho mal.

seoane 24-04-2007 03:12:29

Gangster, vamos a probar una cosa. En esta linea:
Código Delphi [-]
Disk:= CreateFile(PChar('\\.\' + Letra + ':'),GENERIC_READ,FILE_SHARE_READ

Realiza este cambio, y vuelve a probar:
Código Delphi [-]
Disk:= CreateFile(PChar('\\.\PHYSICALDRIVE0'),GENERIC_READ,FILE_SHARE_READ
De esta manera te tendría que dar los datos del primer disco duro, \\.\PHYSICALDRIVE1 los del segundo, etc. Si te funciona no te sera muy difícil cambiar la función para que reciba como parámetro el número en vez de la letra.

Gangster 24-04-2007 03:34:36

Hola Seoane lo probe y me da lo mismo se me hace que me explique mal es que tengo un solo disco duro, pero lo tengo partido en dos pedazos un pedazo para el C y otro para la letra D, donde el C tengo el windows XP y el otro solo de almacen, entonces al ponerle la letra C a la funcion, me da el modelo de mi disco pero no me da el serial nummber, esa es mi duda que lo probe con otros discos con la pura letra C osea una sola particion completa del disco duro y si sirve y estos que tienen partido el disco duro no lo encuentra gracias por tus respuestas.

Gangster 24-04-2007 03:38:26

Hola Seoane lo probe y me da lo mismo se me hace que me explique mal es que tengo un solo disco duro, pero lo tengo partido en dos pedazos un pedazo para el C y otro para la letra D, donde el C tengo el windows XP y el otro solo de almacen, entonces al ponerle la letra C a la funcion, me da el modelo de mi disco pero no me da el serial nummber, esa es mi duda que lo probe con otros discos con la pura letra C osea una sola particion completa del disco duro y si sirve y estos que tienen partido el disco duro no lo encuentra gracias por tus respuestas.

seoane 24-04-2007 04:30:36

Te entendí perfectamente Gangster, por eso te dije lo de \\.\PHYSICALDRIVE0, ya que este hace referencia al disco duro físico, sin importar las particiones. No se lo que esta pasando, a mi me funciona, lo probé en mi equipo que también tiene el disco participando y funciona. Y el hecho de que a ti te funcione en unos equipos y en otros no, me hace pensar que le problema este en tu sistema. Pero la verdad es que no se me ocurre donde ....

Gangster 24-04-2007 22:30:50

Hola Seoane ya la probe con mas discos duros tu funcion y si es buena pero en algunos modelos de discos duros, que son pues de marcas comerciales, porque pues aqui donde trabajo y hago mis aplicaciones en delphi,usamos discos de un tipo y no sirvio esta funcion pero en otros si, entonces en donde no sirvio tu funcion los probe con un programa llamado everest que te dice informacion interna de cualquier ordenador y este si me daba el numero de serie fisico de los discos duros donde esta funcion no trabajaba, de todos modos si sirve esta funcion,en algunos discos duros entonces no queda mas que usarla y que te toque un disco duro que si la acepte, gracias por tus respuestas y seguiremos por aqui en este foro porque me queda mucho por seguir aprendiendo de dlephi gracias por todo.

JoAnCa 22-10-2007 23:43:46

Hola Seoane
Gracias por tu truco, este codigo hace rato lo estaba buscando, el que me diera el ProductoID de los discos duros (al fin lo encontré)
Otra cosa, como obtener la capacidad total del Disco independientemente de las particiones que tenga, en los trucos y foros, lo que me he encontrado me dan la de la particion seleccionada, no la del disco total.

seoane 23-10-2007 23:43:22

Jose Caceres, prueba con esto:
http://www.clubdelphi.com/foros/showpost.php?p=182741&postcount=5

MAXIUM 11-03-2009 18:45:16

Efectivamente puedo dar fe de que no funciona en todos los discos duros, lo probé en un SATA II particionado con S.O. WinXP.


La franja horaria es GMT +2. Ahora son las 15:51:49.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi