gpt4 book ai didi

Delphi - 使用 DeviceIoControl 传递 IOCTL_DISK_GET_LENGTH_INFO 来获取闪存介质物理大小(不是分区)

转载 作者:行者123 更新时间:2023-12-03 15:45:36 28 4
gpt4 key购买 nike

好吧,这是其他几个问题的结果。看来我对建议做了一些错误的事情,并且在使用建议的 API 获取媒体大小时出现了错误。对于我的新问题,我正在物理磁盘级别工作,而不是在分区或文件系统的范围内。

我在做什么

我正在尝试获取闪存卡从第一个 block 到最后一个 block 的大小、引导记录分区空间等。虽然我不需要它来转储卡中的信​​息,但我确实需要动态写入能力。我想说的是,无论卡片的大小如何,都将标记放在距离卡片末端较远的地方。有人建议我将 IOCTL_DISK_GET_LENGTH_INFO 传递给 DeviceIoControl,起初我没有结果,但现在我终于从 Windows 50 收到错误。

项目来源

这是主单元的 Pastebin 代码 (Delphi 2009) - http://clutchx2.pastebin.com/iMnq8kSx

这里是应用程序源代码和可执行文件,其中包含一个用于输出正在发生的状态的表单 - http://www.mediafire.com/?js8e6ci8zrjq0de

使用下载可能更容易,除非您只是寻找代码中的问题。我还将代码粘贴到此处。

unit Main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TfrmMain = class(TForm)
edtDrive: TEdit;
lblDrive: TLabel;
btnMethod1: TButton;
btnMethod2: TButton;
lblSpace: TLabel;
edtSpace: TEdit;
lblFail: TLabel;
edtFail: TEdit;
lblError: TLabel;
edtError: TEdit;
procedure btnMethod1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

TDiskExtent = record
DiskNumber: Cardinal;
StartingOffset: Int64;
ExtentLength: Int64;
end;
DISK_EXTENT = TDiskExtent;
PDiskExtent = ^TDiskExtent;
TVolumeDiskExtents = record
NumberOfDiskExtents: Cardinal;
Extents: array[0..0] of TDiskExtent;
end;
VOLUME_DISK_EXTENTS = TVolumeDiskExtents;
PVolumeDiskExtents = ^TVolumeDiskExtents;

var
frmMain: TfrmMain;

const
FILE_DEVICE_DISK = $00000007;
METHOD_BUFFERED = 0;
FILE_ANY_ACCESS = 0;
IOCTL_DISK_BASE = FILE_DEVICE_DISK;
IOCTL_VOLUME_BASE = DWORD('V');
IOCTL_DISK_GET_LENGTH_INFO = $80070017;
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = ((IOCTL_VOLUME_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or (0 shl 2) or METHOD_BUFFERED);

implementation

{$R *.dfm}

function GetLD(Drive: Char): Cardinal;
var
Buffer : String;
begin
Buffer := Format('\\.\%s:',[Drive]);
Result := CreateFile(PChar(Buffer),GENERIC_READ Or GENERIC_WRITE,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
If Result = INVALID_HANDLE_VALUE Then
begin
Result := CreateFile(PChar(Buffer),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
end;
end;

function GetPD(Drive: Byte): Cardinal;
var
Buffer : String;
begin
If Drive = 0 Then
begin
Result := INVALID_HANDLE_VALUE;
Exit;
end;
Buffer := Format('\\.\PHYSICALDRIVE%d',[Drive]);
Result := CreateFile(PChar(Buffer),GENERIC_READ Or GENERIC_WRITE,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
If Result = INVALID_HANDLE_VALUE Then
begin
Result := CreateFile(PChar(Buffer),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
end;
end;

function GetPhysicalDiskNumber(Drive: Char): Byte;
var
LD : DWORD;
DiskExtents : PVolumeDiskExtents;
DiskExtent : TDiskExtent;
BytesReturned : Cardinal;
begin
Result := 0;
LD := GetLD(Drive);
If LD = INVALID_HANDLE_VALUE Then Exit;
Try
DiskExtents := AllocMem(Max_Path);
DeviceIOControl(LD,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,nil,0,DiskExtents,Max_Path,BytesReturned,nil);
If DiskExtents^.NumberOfDiskExtents > 0 Then
begin
DiskExtent := DiskExtents^.Extents[0];
Result := DiskExtent.DiskNumber;
end;
Finally
CloseHandle(LD);
end;
end;

procedure TfrmMain.btnMethod1Click(Sender: TObject);
var
PD : DWORD;
CardSize: Int64;
BytesReturned: DWORD;
CallSuccess: Boolean;
begin
PD := GetPD(GetPhysicalDiskNumber(edtDrive.Text[1]));
If PD = INVALID_HANDLE_VALUE Then
Begin
ShowMessage('Invalid Physical Disk Handle');
Exit;
End;
CallSuccess := DeviceIoControl(PD, IOCTL_DISK_GET_LENGTH_INFO, nil, 0, @CardSize, SizeOf(CardSize), BytesReturned, nil);
if not CallSuccess then
begin
edtError.Text := IntToStr(GetLastError());
edtFail.Text := 'True';
end
else edtFail.Text := 'False';
CloseHandle(PD);
end;

end.

我在表单上放置了第二个方法按钮,这样如果我愿意,我可以在应用程序中编写一组不同的代码。只有最少的错误处理和保护措施,没有任何东西是通过源代码调试所必需的。

媒体类型和接口(interface)

我在索尼内存棒上使用 PSP 作为读卡器进行了尝试,因为我找不到在我的机器中使用 duo 的适配器。我的目标是 MS,一半的用户使用 PSP,而另一半则不使用 PSP。然而,这在 SD 卡上应该可以正常工作,这也是我工作的次要目标。我在 USB 存储卡读卡器和几张 SD 卡上尝试过此操作。

问题

现在我已经修复了我的尝试,但返回了一个错误。 50 ERROR_NOT_SUPPORTED 不支持该请求。

类似的应用程序

我找到了一个使用此 API 的应用程序以及许多我想要做的相关功能。我正准备调查它,该应用程序称为 DriveImage,其源代码在这里 - http://sourceforge.net/projects/diskimage/

我从该应用程序中真正注意到的唯一一件事是使用 TFileStream 并使用它来获取物理磁盘上的句柄。

最佳答案

我明白这里可能会发生什么。

试试这个:

对于每个“FILE_SHARE_READ”,将其更改为“FILE_SHARE_WRITE 或 FILE_SHARE_READ”

来自msdn:

“如果要使用\.\X: 打开卷,则必须使用 FILE_SHARE_WRITE | FILE_SHARE_READ,而不仅仅是 FILE_SHARE_WRITE。如果省略 FILE_SHARE_READ,则在大多数卷上都会收到 ERROR_NOT_SUPPORTED”

http://msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx

编辑:

你会讨厌这个,但它失败的真正原因是你对 IOCTL_DISK_GET_LENGTH_INFO 的定义是错误的。将其替换为:

((IOCTL_DISK_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0017 shl 2) or METHOD_BUFFERED);

结果是 0x7405C 而不是 0x80070017

关于Delphi - 使用 DeviceIoControl 传递 IOCTL_DISK_GET_LENGTH_INFO 来获取闪存介质物理大小(不是分区),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4581387/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com