好的,这是其他几个问题的结果。看来我对这些建议做了一些错误,并且在使用建议的API获取媒体大小时,此时出现了错误。我的问题的新手我在物理磁盘级别工作,而不是在分区或文件系统的范围内。
我在做什么
我正在尝试从第一个块到最后一个,启动记录分区空间和所有的闪存卡的大小。虽然我不需要它从卡片中转储信息,但我确实需要动态写作能力。我想能够说,尽管它的尺寸可能是多大,但是距离卡片的末端还有一个标记。有人建议我将IOCTL_DISK_GET_LENGTH_INFO传递给DeviceIoControl,起初我没有结果,但现在我终于从Windows 50收到错误了。
项目来源
以下是主单元的粘贴码(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.
我在表单上放了第二个方法按钮,所以如果我愿意的话,我可以在应用程序中编写一组不同的代码。只有最小的错误处理和安全措施,没有必要通过源调试这一点。
媒体类型&接口
我在使用PSP作为阅读器的索尼记忆棒上试过这个,因为我找不到适配器在我的机器上使用二人组。目标是一个MS,我的一半用户使用PSP为读者一半。但是这应该可以在SD卡上正常工作,这也是我工作的次要目标。我在USB存储卡读卡器和几张SD卡上试过这个。
问题
既然我已经修复了我的尝试,我就会收到错误。 50 ERROR_NOT_SUPPORTED不支持请求。
类似的应用程序
我找到了一个使用此API的应用程序,以及我正在尝试的许多相关功能。我正准备调查它的应用程序名为DriveImage,其源代码在此处 - http://sourceforge.net/projects/diskimage/
我从该应用程序中唯一注意到的是使用TFileStream并使用它来获取物理磁盘上的句柄。
答案 0 :(得分:5)
我看到这里可能会发生什么。
试试这个:
对于每个“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
答案 1 :(得分:3)
这个问题已经回答了。作为替代方法,您可以使用IOCTL_DISK_GET_DRIVE_GEOMETRY来获取磁盘大小。这是我在项目中使用的工作代码:
const
IOCTL_DISK_GET_DRIVE_GEOMETRY = $00070000;
type
{$MINENUMSIZE 4}
TMediaType = (
Unknown, // Format is unknown
F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector
F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector
F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector
F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector
F3_720_512, // 3.5", 720KB, 512 bytes/sector
F5_360_512, // 5.25", 360KB, 512 bytes/sector
F5_320_512, // 5.25", 320KB, 512 bytes/sector
F5_320_1024, // 5.25", 320KB, 1024 bytes/sector
F5_180_512, // 5.25", 180KB, 512 bytes/sector
F5_160_512, // 5.25", 160KB, 512 bytes/sector
RemovableMedia, // Removable media other than floppy
FixedMedia, // Fixed hard disk media
F3_120M_512 // 3.5", 120M Floppy
);
{$MINENUMSIZE 1}
PDiskGeometry = ^TDiskGeometry;
TDiskGeometry = packed record
Cylinders: int64;
MediaType: TMediaType;
TracksPerCylinder: DWORD;
SectorsPerTrack: DWORD;
BytesPerSector: DWORD;
end;
var
H: THandle;
BytesReturned: DWORD;
DG: TDiskGeometry;
DSize: int64;
begin
H:= CreateFile(PChar('\\.\G:'), GENERIC_READ,
FILE_SHARE_WRITE or FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if Handle = INVALID_HANDLE_VALUE then
raise Exception.Create('OOps!');
if not DeviceIOControl(H, IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0,
@DG, SizeOf(TDiskGeometry), BytesReturned, nil) then
raise Exception.Create('OOps #2!');
DSize:= DG.Cylinders * DG.TracksPerCylinder;
DSize:= DSize * (DG.SectorsPerTrack * DG.BytesPerSector);
ShowMessage(IntToStr(DSize));
end;