Хорошо, это результат пары других вопросов. Похоже, что я делал что-то не так с предложениями, и в этот момент возникла ошибка при использовании предложенного 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.
Я поместил в форму кнопку второго метода, чтобы я мог написать другой набор кода в приложение, если мне так хочется. Только минимальная обработка ошибок и защита - нет ничего, что не было бы необходимо для отладки этого через источник.
Тип носителя и интерфейс
Я попробовал это на Sony Memory Stick, используя PSP в качестве считывателя, потому что я не могу найти адаптер для использования дуэта в моей машине. Цель - MS, и половина моих пользователей использует PSP для читателя, наполовину нет. Однако это должно работать на SD-картах, и это также является второстепенной целью для моей работы. Я пробовал это на устройстве чтения карт памяти USB и нескольких SD-картах.
Проблема
Теперь, когда я исправил попытку, мне возвращается ошибка. 50 ERROR_NOT_SUPPORTED Запрос не поддерживается.
Аналогичное приложение
Я нашел приложение, которое использует этот API, а также множество связанных функций для того, что я пытаюсь сделать. Я собираюсь разобраться в этом, приложение называется DriveImage и его источник здесь - http://sourceforge.net/projects/diskimage/
Единственное, что я действительно заметил в этом приложении - это использование TFileStream и использование его для получения дескриптора на физическом диске.