Giz*_*eat 6 delphi wmi freepascal lazarus
我在处理逻辑驱动器时遇到了一些问题.为清楚起见,无论分区如何,我对"物理磁盘"(PD)的定义都是原始磁盘."逻辑驱动器"(LD)指的是诸如驱动器E:,驱动器F:等的卷.
使用RRUZ(我的英雄SO成员)中的示例并实现WMI类我已经创建了一个用于读取磁盘的Freepascal程序.我通过\.\ PhyscialDiskX解决了PD问题,RRUZ(这里)创建的示例工作得很好.我可以读取PD的所有字节没有问题.
我对逻辑卷使用相同的句柄技术,它是\?\ E:或\?\ F:等.然后我使用IOCTL_DISK_GET_LENGTH_INFO来获取PD或LV的长度,然后读取字节范围,直到ReadBytes = TotalLength.我在MSDN网站上看到,它将自动检索传递的任何设备句柄的大小 - PD或LD都一样.事实上,我已经检查了我的程序returnzt WinHex,FTK Imager,HxD和其他几个低级磁盘工具返回的szie值.除了由0或1个起始位置引起的1字节差异外,它们匹配.
但是,出于某种原因,我的程序无法在Windows 7 Pro 64位上获得最终的32Kb,尽管以管理员身份运行该程序.它读取整个磁盘,然后读取最终缓冲区(以64Kb缓冲区完成)BytesRead返回-1.使用调试器我计算出以下值:
493,846,527 exact LV size of Drive F:
493,813,760 total bytes read at time of failure
32,767 bytes missing
Run Code Online (Sandbox Code Playgroud)
结果如下
BytesRead := FileRead(hDiskHandle, Buffer, (DiskSize - TotalBytesRead));
Run Code Online (Sandbox Code Playgroud)
在最终缓冲区读取时为-1.这是测试磁盘末尾的行,通过说"如果剩余读取的数量小于缓冲区大小的大小,则只尝试读取剩余的内容".因此,FileRead最后要求存储的字节值为32,767(因为此时的DiskSize - TotalBytesRead为32,767,这意味着要读取磁盘的剩余字节数).指定大小的缓冲区为64Kb.我的理解是你可以减少缓冲区而不是更多(FileRead状态:" 缓冲区必须至少是Count字节长.不执行检查 "?这是正确的吗?如果不是那么这可能是(也可能是)这个问题.
我不知道是不是因为IOCTL_DISK_GET_LENGTH_INFO,缓冲存储还是别的什么?希望有人能帮忙吗?我还在Lazarus Freepascal论坛上贴了一些截图.这是我的相关代码部分:
手柄:
// Create handle to source disk. Abort if fails
hSelectedDisk := CreateFileW(PWideChar(SourceDevice), FILE_READ_DATA,
FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if hSelectedDisk = INVALID_HANDLE_VALUE then
begin
RaiseLastOSError;
end
Run Code Online (Sandbox Code Playgroud)
计算给定设备的大小离子字节:
ExactDiskSize := GetDiskLengthInBytes(hSelectedDisk);
Run Code Online (Sandbox Code Playgroud)
现在读取设备并将输入存储为平面文件
ImageResult := WindowsImageDisk(hSelectedDisk, ExactDiskSize, HashChoice, hImageName);
Run Code Online (Sandbox Code Playgroud)
上述功能:
function GetDiskLengthInBytes(hSelectedDisk : THandle) : Int64;
const
// These are defined at the MSDN.Microsoft.com website for DeviceIOControl
// and https://forum.tuts4you.com/topic/22361-deviceiocontrol-ioctl-codes/
{
IOCTL_DISK_GET_DRIVE_GEOMETRY = $0070000
IOCTL_DISK_GET_PARTITION_INFO = $0074004
IOCTL_DISK_SET_PARTITION_INFO = $007C008
IOCTL_DISK_GET_DRIVE_LAYOUT = $007400C
IOCTL_DISK_SET_DRIVE_LAYOUT = $007C010
IOCTL_DISK_VERIFY = $0070014
IOCTL_DISK_FORMAT_TRACKS = $007C018
IOCTL_DISK_REASSIGN_BLOCKS = $007C01C
IOCTL_DISK_PERFORMANCE = $0070020
IOCTL_DISK_IS_WRITABLE = $0070024
IOCTL_DISK_LOGGING = $0070028
IOCTL_DISK_FORMAT_TRACKS_EX = $007C02C
IOCTL_DISK_HISTOGRAM_STRUCTURE = $0070030
IOCTL_DISK_HISTOGRAM_DATA = $0070034
IOCTL_DISK_HISTOGRAM_RESET = $0070038
IOCTL_DISK_REQUEST_STRUCTURE = $007003C
IOCTL_DISK_REQUEST_DATA = $0070040
IOCTL_DISK_CONTROLLER_NUMBER = $0070044
IOCTL_DISK_GET_PARTITION_INFO_EX = $0070048
IOCTL_DISK_SET_PARTITION_INFO_EX = $007C04C
IOCTL_DISK_GET_DRIVE_LAYOUT_EX = $0070050
IOCTL_DISK_SET_DRIVE_LAYOUT_EX = $007C054
IOCTL_DISK_CREATE_DISK = $007C058
IOCTL_DISK_GET_LENGTH_INFO = $007405C // Our constant...
SMART_GET_VERSION = $0074080
SMART_SEND_DRIVE_COMMAND = $007C084
SMART_RCV_DRIVE_DATA = $007C088
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX = $00700A0
IOCTL_DISK_UPDATE_DRIVE_SIZE = $007C0C8
IOCTL_DISK_GROW_PARTITION = $007C0D0
IOCTL_DISK_GET_CACHE_INFORMATION = $00740D4
IOCTL_DISK_SET_CACHE_INFORMATION = $007C0D8
IOCTL_DISK_GET_WRITE_CACHE_STATE = $00740DC
IOCTL_DISK_DELETE_DRIVE_LAYOUT = $007C100
IOCTL_DISK_UPDATE_PROPERTIES = $0070140
IOCTL_DISK_FORMAT_DRIVE = $007C3CC
IOCTL_DISK_SENSE_DEVICE = $00703E0
IOCTL_DISK_INTERNAL_SET_VERIFY = $0070403
IOCTL_DISK_INTERNAL_CLEAR_VERIFY = $0070407
IOCTL_DISK_INTERNAL_SET_NOTIFY = $0070408
IOCTL_DISK_CHECK_VERIFY = $0074800
IOCTL_DISK_MEDIA_REMOVAL = $0074804
IOCTL_DISK_EJECT_MEDIA = $0074808
IOCTL_DISK_LOAD_MEDIA = $007480C
IOCTL_DISK_RESERVE = $0074810
IOCTL_DISK_RELEASE = $0074814
IOCTL_DISK_FIND_NEW_DEVICES = $0074818
IOCTL_DISK_GET_MEDIA_TYPES = $0070C00
}
IOCTL_DISK_GET_LENGTH_INFO = $0007405C;
type
TDiskLength = packed record
Length : Int64;
end;
var
BytesReturned: DWORD;
DLength: TDiskLength;
ByteSize: int64;
begin
BytesReturned := 0;
// Get the length, in bytes, of the physical disk
if not DeviceIOControl(hSelectedDisk, IOCTL_DISK_GET_LENGTH_INFO, nil, 0,
@DLength, SizeOf(TDiskLength), BytesReturned, nil) then
raise Exception.Create('Unable to determine byte capacity of disk.');
ByteSize := DLength.Length;
ShowMessage(IntToStr(ByteSize));
result := ByteSize;
end;
Run Code Online (Sandbox Code Playgroud)
磁盘阅读器功能
function WindowsImageDisk(hDiskHandle : THandle; DiskSize : Int64; HashChoice : Integer; hImageName : THandle) : Int64;
var
Buffer : array [0..65535] of Byte; // 1048576 (1Mb) or 262144 (240Kb) or 131072 (120Kb buffer) or 65536 (64Kb buffer)
BytesRead : integer;
NewPos, SectorCount,
TotalBytesRead, BytesWritten, TotalBytesWritten : Int64;
...
// Now to seek to start of device
FileSeek(hDiskHandle, 0, 0);
repeat
// Read device in buffered segments. Hash the disk and image portions as we go
if (DiskSize - TotalBytesRead) < SizeOf(Buffer) then
begin
// Read 65535 or less bytes
BytesRead := FileRead(hDiskHandle, Buffer, (DiskSize - TotalBytesRead));
BytesWritten := FileWrite(hImageName, Buffer, BytesRead);
end
else
begin
// Read 65536 (64kb) at a time
BytesRead := FileRead(hDiskHandle, Buffer, SizeOf(Buffer));
BytesWritten := FileWrite(hImageName, Buffer, BytesRead);
end;
if BytesRead = -1 then
begin
ShowMessage('There was a read error encountered. Aborting');
// ERROR IS THROWN AT THIS POINT ONLY WITH LD's - not PD's
exit;
end
else
begin
inc(TotalBytesRead, BytesRead);
inc(TotalBytesWritten, BytesWritten);
NewPos := NewPos + BytesRead;
...
until (TotalBytesRead = DiskSize);
Run Code Online (Sandbox Code Playgroud)
小智 7
可能是边界检查错误.从MSDN引用(CreateFile,关于打开物理驱动器和卷的注释,您称之为逻辑驱动器):
要读取或写入卷的最后几个扇区,必须调用DeviceIoControl并指定FSCTL_ALLOW_EXTENDED_DASD_IO