PDA

Ver la Versión Completa : Numero de serie del disco duro


seoane
11-10-2006, 18:29:34
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.


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

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

Disk:= CreateFile(PChar('\\.\' + Letra + ':'),GENERIC_READ,FILE_SHARE_READ


Realiza este cambio, y vuelve a probar:

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.