在Windows> = XP上使用Delphi 7,如何从计算机中检索每个磁盘的磁盘签名?最好不要使用WMI或Diskpart。
如果有可能,也要快......
谢谢。
稍后编辑:
Documentation: http://pcsupport.about.com/od/termsd/g/disk-signature.htm
MBR disks: http://diddy.boot-land.net/firadisk/files/signature.htm
GPT disks: http://thestarman.pcministry.com/asm/mbr/GPT.htm
How to get it with DiskPart (method found on Google when searching "disk signature"):
Diskpart >> list disk >> select disk [n] >>
detail disk >> Disk ID: 0E35445B for MBR disks
and GUID: 55FD03F2-6B11-49DF-8167-D30B94A4509D for GPT Disks
答案 0 :(得分:4)
您可以使用DeviceIoControl
和IOCTL_DISK_GET_DRIVE_LAYOUT_EX
来获取所需的信息。
program DiskSignatureGuid;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
type
TDriveLayoutInformationMbr = record
Signature: DWORD;
end;
TDriveLayoutInformationGpt = record
DiskId: TGuid;
StartingUsableOffset: Int64;
UsableLength: Int64;
MaxPartitionCount: DWORD;
end;
TPartitionInformationMbr = record
PartitionType: Byte;
BootIndicator: Boolean;
RecognizedPartition: Boolean;
HiddenSectors: DWORD;
end;
TPartitionInformationGpt = record
PartitionType: TGuid;
PartitionId: TGuid;
Attributes: Int64;
Name: array [0..35] of WideChar;
end;
TPartitionInformationEx = record
PartitionStyle: Integer;
StartingOffset: Int64;
PartitionLength: Int64;
PartitionNumber: DWORD;
RewritePartition: Boolean;
case Integer of
0: (Mbr: TPartitionInformationMbr);
1: (Gpt: TPartitionInformationGpt);
end;
TDriveLayoutInformationEx = record
PartitionStyle: DWORD;
PartitionCount: DWORD;
DriveLayoutInformation: record
case Integer of
0: (Mbr: TDriveLayoutInformationMbr);
1: (Gpt: TDriveLayoutInformationGpt);
end;
PartitionEntry: array [0..15] of TPartitionInformationGpt;
//hard-coded maximum of 16 partitions
end;
const
PARTITION_STYLE_MBR = 0;
PARTITION_STYLE_GPT = 1;
PARTITION_STYLE_RAW = 2;
const
IOCTL_DISK_GET_DRIVE_LAYOUT_EX = $00070050;
procedure Main;
const
// Max number of drives assuming primary/secondary, master/slave topology
MAX_IDE_DRIVES = 16;
var
i: Integer;
Drive: string;
hDevice: THandle;
DriveLayoutInfo: TDriveLayoutInformationEx;
BytesReturned: DWORD;
begin
for i := 0 to MAX_IDE_DRIVES - 1 do
begin
Drive := '\\.\PHYSICALDRIVE' + IntToStr(i);
hDevice := CreateFile(PChar(Drive), 0, FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if hDevice <> INVALID_HANDLE_VALUE then
begin
if DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, nil, 0,
@DriveLayoutInfo, SizeOf(DriveLayoutInfo), BytesReturned, nil) then
begin
case DriveLayoutInfo.PartitionStyle of
PARTITION_STYLE_MBR:
Writeln(Drive + ', MBR, ' +
IntToHex(DriveLayoutInfo.DriveLayoutInformation.Mbr.Signature, 8));
PARTITION_STYLE_GPT:
Writeln(Drive + ', GPT, ' +
GUIDToString(DriveLayoutInfo.DriveLayoutInformation.Gpt.DiskId));
PARTITION_STYLE_RAW:
Writeln(Drive + ', RAW');
end;
end;
CloseHandle(hDevice);
end;
end;
end;
begin
Main;
Readln;
end.
请注意,由于0
传递给dwDesiredAccess
CreateFile
参数,因此不需要提升权限。在documentation:
对磁盘或卷的直接访问受到限制......要成功调用,必须满足以下要求:
- 来电者必须具有管理权限。
- dwCreationDisposition参数必须具有OPEN_EXISTINGflag。
- 打开卷或软盘时,dwShareMode参数必须具有FILE_SHARE_WRITEflag。
注意 dwDesiredAccess 参数可以为零,允许应用程序在不访问设备的情况下查询设备属性。 这对于确定软盘大小的应用程序很有用 磁盘驱动器及其支持的格式,无需软盘 例如,在一个驱动器中。它也可以用于阅读统计数据 无需更高级别的数据读/写权限。
答案 1 :(得分:2)
取决于“磁盘签名”是什么。我不知道那是什么。我知道以下代码返回:
- \\?\ide#disksandisk_sdssdx120gg25___________________r201____#5&20f0fb49&0&0.0.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
- \\?\ide#diskst1000dm003-9yn162______________________hp13____#5&33aaabee&0&1.0.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
那些“磁盘签名”?
它使用Windows Setup API:
procedure GetDisks(slDisks: TStrings);
var
InterfaceDevInfo: HDEVINFO;
index: DWORD;
status: BOOL;
Name: string;
begin
{ Get the interface device information set that contains all devices of event class. }
InterfaceDevInfo := SetupDiGetClassDevs(
@GUID_DEVINTERFACE_DISK,
nil, // Enumerator
0, // Parent Window
(DIGCF_PRESENT or DIGCF_INTERFACEDEVICE) // Only Devices present & Interface class
);
if InterfaceDevInfo = HDEVINFO(INVALID_HANDLE_VALUE) then
begin
RaiseEnumerateDisksError('SetupDiGetClassDevs failed', GetLastError);
Exit;
end;
{ Enumerate all the disk devices }
Index := 0;
while (True) do
begin
Status := GetDeviceProperty(InterfaceDevInfo, index, Name);
if not Status then
Break;
slDisks.Add(Name);
Inc(Index);
end;
SetupDiDestroyDeviceInfoList(InterfaceDevInfo);
end;
function GetDeviceProperty(InterfaceDevInfo: HDEVINFO; Index: LongWord;
out Name: string): Boolean;
var
interfaceData: TSPDeviceInterfaceData;
interfaceDetailData: PSPDeviceInterfaceDetailData;
status: BOOL;
interfaceDetailDataSize: LongInt;
reqSize: Cardinal;
errorCode: LongInt;
begin
Result := False;
ZeroMemory(@interfaceData, SizeOf(InterfaceData));
interfaceData.cbSize := SizeOf(interfaceData);
//Retreiving context structure for specified device interface
status := SetupDiEnumDeviceInterfaces(
InterfaceDevInfo, // Interface Device Info handle
nil, // Device Info data
GUID_DEVINTERFACE_DISK, // Interface registered by driver
Index, // Member
interfaceData); // Device Interface Data
if not status then
begin
errorCode := GetLastError;
if (errorCode = ERROR_NO_MORE_ITEMS ) then
begin
//no more interfaces, exit returning default value of False
Exit;
end
else
begin
RaiseEnumerateDisksError('SetupDiEnumDeviceInterfaces failed.', errorCode);
end;
end;
// Find out required buffer size, so pass nil
status := SetupDiGetDeviceInterfaceDetail(
InterfaceDevInfo, // Interface Device info handle
@interfaceData, // Interface data for the event class
nil, // Checking for buffer size
0, // Checking for buffer size
reqSize, // Buffer size required to get the detail data
nil); // Checking for buffer size
// This call returns ERROR_INSUFFICIENT_BUFFER with reqSize
// set to the required buffer size. Ignore the above error and
// pass a bigger penis to get the detail data
if not status then
begin
errorCode := GetLastError;
if errorCode <> ERROR_INSUFFICIENT_BUFFER then
begin
RaiseEnumerateDisksError('SetupDiGetDeviceInterfaceDetail failed.', errorCode);
Exit;
end;
end;
// Allocate memory to get the interface detail data
// This contains the devicepath we need to open the device
interfaceDetailDataSize := reqSize;
GetMem(interfaceDetailData, interfaceDetailDataSize);
ZeroMemory(interfaceDetailData, interfaceDetailDataSize);
interfaceDetailData.cbSize := SizeOf(TSPDeviceInterfaceDetailData);
// ineerfaceDetailData.cbSize := 5; //ansi version
// ineerfaceDetailData.cbSize := 6; //unicode version
//Getting interface detail data into properly sized buffer...
status := SetupDiGetDeviceInterfaceDetail(
InterfaceDevInfo, // Interface Device info handle
@interfaceData, // Interface data for the event class
interfaceDetailData, // Interface detail data
interfaceDetailDataSize, // Interface detail data size
reqSize, // Buffer size required to get the detail data
nil); // Interface device info
if not Status then
begin
RaiseEnumerateDisksError('Error in SetupDiGetDeviceInterfaceDetail', GetLastError);
Exit;
end;
// Now we have the device path.
Name := PChar(@interfaceDetailData.DevicePath[0]);
(*
//DevicePath is suitable for a CreateFile, whish is what i want in the end
hDevice := CreateFile(
PChar(interfaceDetailData.DevicePath), // device interface name
GENERIC_READ or GENERIC_WRITE, // dwDesiredAccess
FILE_SHARE_READ or FILE_SHARE_WRITE, // dwShareMode
nil, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDistribution
0, // dwFlagsAndAttributes
0 // hTemplateFile
);
*)
Result := True;
end;
答案 2 :(得分:1)
我在几台计算机上测试了这段代码并且可以正常运行:
MBR磁盘:
磁盘签名/标识符是一个4字节(长字)数字,它是在首次创建主引导记录/分区表时随机生成的,并以字节偏移量1B8(十六进制)或440(十进制)到1BB(十六进制)存储)或MBR磁盘扇区(0)中的443(dec)。因此,在任何MBR磁盘上,您都可以直接从该位置读取它:
const
// Max number of drives assuming primary/secondary, master/slave topology
MAX_IDE_DRIVES = 16;
var
i: Integer;
RawMBR: array[0..511] of Byte;
btsIO: DWORD;
hDevice: THandle;
s: string;
begin
s := '';
for i := 0 to MAX_IDE_DRIVES - 1 do
begin
hDevice := CreateFile(PChar('\\.\PHYSICALDRIVE' + IntToStr(i)), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hDevice <> INVALID_HANDLE_VALUE then
begin
SetFilePointer(hDevice, 0, nil, FILE_BEGIN); //MBR starts in sector 0
if not ReadFile(hDevice, RawMBR[0], 512, btsIO, nil) then
begin
CloseHandle(hDevice);
Continue;
end;
CloseHandle(hDevice);
s := s + 'Disk ' + IntToStr(i) + ' = ' + IntToHex(RawMBR[443], 2) + ' ' +
IntToHex(RawMBR[442], 2) + ' ' + IntToHex(RawMBR[441], 2) +
' ' + IntToHex(RawMBR[440], 2) + #13#10;
end;
end;
ShowMessage(s);
end;
GPT磁盘:
磁盘签名/标识符是一个16字节(GUID)编号,它是在GPT首次创建时随机生成的,并以字节偏移038(十六进制)或56(十进制)到047(十六进制)或71(十二进制)存储)在GPT磁盘扇区(1)。因此,在任何GPT磁盘上,您都可以直接从该位置读取它:
const
// Max number of drives assuming primary/secondary, master/slave topology
MAX_IDE_DRIVES = 16;
var
i: Integer;
RawMBR: array[0..511] of Byte;
btsIO: DWORD;
hDevice: THandle;
s: string;
begin
s := '';
for i := 0 to MAX_IDE_DRIVES - 1 do
begin
hDevice := CreateFile(PChar('\\.\PHYSICALDRIVE' + IntToStr(i)), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hDevice <> INVALID_HANDLE_VALUE then
begin
SetFilePointer(hDevice, 512, nil, FILE_BEGIN); //GPT starts in sector 1
if not ReadFile(hDevice, RawMBR[0], 512, btsIO, nil) then
begin
CloseHandle(hDevice);
Continue;
end;
CloseHandle(hDevice);
s := s + 'Disk ' + IntToStr(i) + ' = ' + IntToHex(RawMBR[59], 2) +
' ' + IntToHex(RawMBR[58], 2) + ' ' + IntToHex(RawMBR[57], 2) +
' ' + IntToHex(RawMBR[56], 2) + ' - ' + IntToHex(RawMBR[61], 2) +
' ' + IntToHex(RawMBR[60], 2) + ' - ' + IntToHex(RawMBR[63], 2) +
' ' + IntToHex(RawMBR[62], 2) + ' - ' + IntToHex(RawMBR[64], 2) +
' ' + IntToHex(RawMBR[65], 2) + ' - ' + IntToHex(RawMBR[66], 2) +
' ' + IntToHex(RawMBR[67], 2) + ' ' + IntToHex(RawMBR[68], 2) +
' ' + IntToHex(RawMBR[69], 2) + ' ' + IntToHex(RawMBR[70], 2) +
' ' + IntToHex(RawMBR[71], 2) +
#13#10;
end;
end;
ShowMessage(s);
end;
好的,现在让我们把它们结合起来:
procedure TForm1.Button1Click(Sender: TObject);
const
// Max number of drives assuming primary/secondary, master/slave topology
MAX_IDE_DRIVES = 16;
var
i: Integer;
DiskType: Byte;
RawMBR: array[0..511] of Byte;
btsIO: DWORD;
hDevice: THandle;
s: string;
begin
s := '';
for i := 0 to MAX_IDE_DRIVES - 1 do
begin
hDevice := CreateFile(PChar('\\.\PHYSICALDRIVE' + IntToStr(i)), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hDevice <> INVALID_HANDLE_VALUE then
begin
SetFilePointer(hDevice, 512, nil, FILE_BEGIN); //sector 1 for GPT
if not ReadFile(hDevice, RawMBR[0], 512, btsIO, nil) then
begin
CloseHandle(hDevice);
Continue;
end;
if (IntToHex(RawMBR[0], 2) + IntToHex(RawMBR[1], 2) +
IntToHex(RawMBR[2], 2) + IntToHex(RawMBR[3], 2) +
IntToHex(RawMBR[4], 2) + IntToHex(RawMBR[5], 2) +
IntToHex(RawMBR[6], 2) + IntToHex(RawMBR[7], 2)) =
'4546492050415254' then //EFI PART
DiskType := 1 //GPT
else
begin
DiskType := 0; //MBR
SetFilePointer(hDevice, 0, nil, FILE_BEGIN); //sector 0 for MBR
if not ReadFile(hDevice, RawMBR[0], 512, btsIO, nil) then
begin
CloseHandle(hDevice);
Continue;
end;
end;
CloseHandle(hDevice);
if DiskType = 0 then
s := s + 'Disk ' + IntToStr(i) + ' = ' + IntToHex(RawMBR[443], 2) + ' ' +
IntToHex(RawMBR[442], 2) + ' ' + IntToHex(RawMBR[441], 2) +
' ' + IntToHex(RawMBR[440], 2) + #13#10
else
s := s + 'Disk ' + IntToStr(i) + ' = ' + IntToHex(RawMBR[59], 2) +
' ' + IntToHex(RawMBR[58], 2) + ' ' + IntToHex(RawMBR[57], 2) +
' ' + IntToHex(RawMBR[56], 2) + ' - ' + IntToHex(RawMBR[61], 2) +
' ' + IntToHex(RawMBR[60], 2) + ' - ' + IntToHex(RawMBR[63], 2) +
' ' + IntToHex(RawMBR[62], 2) + ' - ' + IntToHex(RawMBR[64], 2) +
' ' + IntToHex(RawMBR[65], 2) + ' - ' + IntToHex(RawMBR[66], 2) +
' ' + IntToHex(RawMBR[67], 2) + ' ' + IntToHex(RawMBR[68], 2) +
' ' + IntToHex(RawMBR[69], 2) + ' ' + IntToHex(RawMBR[70], 2) +
' ' + IntToHex(RawMBR[71], 2) +
#13#10;
end;
end;
ShowMessage(s);
end;
此代码需要提升权限才能访问磁盘。