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