DelphiでHDDを直接読み取る方法とエラーの解決法

このQ&Aのポイント
  • DelphiからHDDを直接読み取る方法として、Win32APIのSetFilePointerとReadFileを使用します。
  • しかし、125GB辺りでエラーが発生し、以降のセクタが読み取れません。どなたか解決法を教えてください。
  • 質問者の環境はWindows7(32bit)で、USB外付けHDDの250GBを使用しています。
回答を見る
  • ベストアンサー

DelphiからHDDを直接読みたいのですが・・

最終的には数テラの容量があるハードディスクドライブを,Delphi6からWin32APIのSetFilePointerで位置付けて,ReadFileでセクタを直接読み取りたいと思っていますが,現在,125GB辺りでエラーが発生し,以降がのセクタが読めません。(DelphiXEでも同じエラーとなります)  参考にできる日本語のサンプルも乏しく困り果てています。  どなたか,お教えください。  m(_ _)m  よろしくお願いいたします。 【動作環境】 OS:Windows7 (32) professional 言語: Delphi6(personal) 及びDelphi XE メモリ:2GB 対象ドライブ:USB外付けHDD 250GB(1論理ドライブWindows7でフォーマット) 名称:\\.\PHYSICALDRIVE1 CylindersLo : 30401 CylindersHi : 0 TracksPerCylinder : 255 SectorsPerTrack : 63 BytesPerSector: 512 【問題点】 セクタ0からセクタ245127535までは読める様なのですが,1セクタ進めて245127536セクタを読み込もうとすると,SetFilePointerはエラーなしで通過するも,ReadFileでエラーとなってしまいます。 エラーが起きた時のSetFilePointerとReadFileに与えたパラメータは次の通りです。 Stsector : 245,127,536 real ofset: 125,505,298,432 p_hi: 58 p_lo: 951,246,848 p_hiの戻り値: 58 【プログラムのソース】 var DHandle : Thandle; // ハンドル drv_cnt : integer; // 接続ドライブ数 drvname : String; // 扱おうとするドライブの名称 sectorSize: integer; // セクタのサイズ SectorNum : word; // セクタ番号 Max_num : word; // 読み込もうとするバイト数 buf : array[0..4095*2] of byte; // 読み取りデータの格納域 STsector : int64; // 読み込み開始のセクタ番号 //----------------------------------------------------------- function getSector:boolean; // ダイレクト読み取り var dwRet : integer; // Seekのリターンコード dwSize : DWORD; // 読み取ったバイト数 iRet : Boolean; // Readのリターンコード real_ofs : int64; // 読み込もうとする位置(先頭からのバイト数) p_lo : integer; // SetFilePointerで使用するseek相対位置の下位32bit p_hi : integer; // 上位32bit begin result := false; SectorNum := 1; //一度に読むセクタ数 Max_num := SectorNum * SECTORSIZE; // 一度に読むバイト数 // ハンドルの取得 DHandle:=CreateFile(PChar(drvname),GENERIC_READ or GENERIC_WRITE, 0,nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0 ); if DHandle = INVALID_HANDLE_VALUE then begin // Openエラー処理 showmessage('open device エラー'); exit; end else begin // real_ofs := STsector * SECTORSIZE; // seek位置をバイト単位で取得 p_hi := real_ofs div 2147483648; // 上位32bitを計算 p_lo := real_ofs mod 2147483648; // 下位32bitを計算 dwRet:= SetFilePointer(DHandle, p_lo, @p_hi, FILE_BEGIN ); // seek if dwRet <> -1 then begin // 1セクタ分をbuf[]へ読み込み iRet := ReadFile(DHandle,buf,Max_num,dwSize,nil); if iRet = False then begin // Readエラー処理 showmessage('Read device エラー'); CloseHandle(DHandle); exit; end // dump_Buf; 読み取ったバッファの16進ダンプルーチン呼び出し end else begin // seekエラー処理 showmessage('Seek エラー'); CloseHandle(DHandle); exit; end; end; CloseHandle(DHandle); result := true; end; ※申し訳ありません,先頭の空白がGooによって自動的に削除されてしまうようです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

未テストなので、間違っていたらスミマセン。 2点ほど。 1.セクタサイズ等の変数はIntegerでなく、Cardinalではないですか? 2.上位32ビットと下位32ビットの計算値は、2147483648ではなくて、4294967296ではないでしょうか? 以上です。

shinchann
質問者

補足

早速のご指導ありがとうございます。 教えてGooを見ておられるDelphi使いの方がおられるのですね。 投稿先を誤ったかなと思っていました。 引数の型を何種類か試してみましたがCardinalだったのですね。 「マイナスの数値を指定すると戻ることができる」などの記述を読み誤っていました。 また,このプログラムを作り始めてから,数値型やポインタの理解を混乱していました。 なぜ250GBのちょうど半分でエラーとなっていたかも判りすっきりしました。 おかげさまで,ちゃんと読み込んでいるようです。 大変助かりました。 重ねてお礼を申し上げます。ありがとうございました。

関連するQ&A

  • Delphi の文字列型stringについて

     以下のコードで string は AnsiString、Char は AnsiChar です。  buf: array[1..16] of Char; を  buf :string[16]; と宣言しては意図通りに動きません。なぜでしょう?  TPerson = record   Age : Integer;   Name: string[30];  end;  TPersonArray = array of TPerson; procedure TForm1.Nantoka; var  i,j: Integer;  buf: array[1..16] of Char; //buf :string[16]; ではダメ!  Fs : TFileStream;  R : TPersonArray; begin  SetLength(R, 100); //配列のサイズを決定  for i := 0 to 99 do //動的配列の添え字は常に0から始まる  begin   R[i].Age := Random(100);   for j := 1 to 16 do buf[j] := Chr( Random(26)+97 );   //buf :string[16]; では buf[j] が'文字'にならない!   R[i].Name := 'Stream '+buf;  end; end;

  • delphi try文の使い方

    下記コードのようにエラーを回避したいのですが、try文が機能せずエラーになります。 procedure TForm1.Button1Click(Sender: TObject); var p:integer; begin edit1.text:='abc'; try p:=strtoint(edit1.Text); except p:=-1; end; label1.Caption:=inttostr(p); end; try文の使い方がわかりません。

  • [Delphi]入れ子(?)になったプロシージャ

    こんにちは、honiyonです。  あるプロシージャだけが呼び出す関数がある為、次のように定義しました。  procedure Subfunc;   function funcA:integer;   begin    ~    function funcB;    ~   end;   function funcB:integer;   begin    ~    function funcA;    ~   end;  begin   ~  end;  funcAとfuncBは協調して動作するのですが、当然funcAからfuncBは見えていませんので、「funcBが見つからない」とエラーになります。  しかし、この場合どのようにfuncBの存在を定義すれば良いのかわかりません。  あまりこのような形で作成するケースが少ないようで、資料がなく困っています(^^;;  宜しくお願いします(..

  • Delphiで論理積の足し算?

    Delphiでa=17を 0x0Fで論理積したものにb=2を足したいのですが [DCC エラー] SDIMAIN.pas(92): E2015 この型には指定した演算子は使えません となります。Integer型の論理積や足し算をしてInteger型に代入する方法はありますか? procedure TSDIAppForm.Button1Click(Sender: TObject); var a, b, c : Integer; begin a := 17; b := 2; c := (a and #$0F) + b; //c := a + b; ShowMessage(Format('c=%6d', [c])); end;

  • Delphi XE5をアップデートしたら(2)

    前回アップデートしたら例外処理がおかしくなったという質問をしましたが、 あれから、いろいろやっていたら、exeファイルから実行すると正常にエラーメッセージが出て、RAD Studioから実行すると(デバッグモード?)、ShowMessageのエラーメッセージが出ないことがわかりました。 もしかしたらupdateは関係ないかもわかりません。 (今となっては検証しようがありません) でも、これってデバッガモード(?)の正常な動作なんでしょうか? //前回の質問 Delphi Xe5 Starterを使っています。 今日update2をインストールしたら、動作がおかしくなりました。 プログラムは次の通りです。 ------------------------------------------------- procedure TForm1.TestDoButtonClick(Sender: TObject); var Rep, pattern: string; begin pattern := FindEdit.Text; Rep := ReplaceEdit.Text; try Memo2.Lines.Text := TRegEx.Replace(Memo1.Lines.Text, pattern, Rep, []); except ShowMessage('正規表現にエラーがあります'); end; end; ---------------------------------- たしか、アップデートする前には正規表現にエラーがあれば、「正規表現にエラーがあります」が表示されたはずですが、システム?のエラー表示が出て、プログラムが停止します。 どこか間違ってますか?

  • FirebirdへのDelphiによるデータ入力

    Deldhi2010とFirebird2.5を使っています。 下記のコードでデータを入力しているのですが、実行中の他のプログラムで入力済みのデータが見えません。また、二つのPCで入力していくとTest_Noが二重に登録されます。入力したデータがデータベースに反映されていないように見えます。しかし、表示コードにもトランザクションを適応すると問題は解決しますが、理由がわかりません。ご指導よろしくお願いいたします。 (入力コード) procedure TForm.ButtonRegClick(Sender: TObject); var I:Integer; begin if not TIBTransaction.InTransaction then IBTransaction.StartTransaction; try with TIBQuery do begin Close; SQL.Clear; SQL.Add('select max(Test_No) from TESTDB'); Open; I:=FieldByName('max').AsInteger; // Close; SQL.Clear; SQL.Add('insert into TESTDB (Test_No,TempText) values (:TN,:TT)'); ParamByName('TN').AsInteger:=I+1; ParamByName('TT').AsString:='Test'; ExecSQL; end; IBTransaction.Commit; except IBTransaction.Rollback; ShowMessage('Reg Error !!'); end; (表示コード) with TStringGrid do begin RowCount:=1; Rows[0].Clear; end; with TIBQuery do begin Close; SQL.Clear; SQL.Add('select * from TESTDB order by Test_No'); Open; I:=0; First; while not Eof do begin inc(I); TStringGrid.RowCount:=I; TStringGrid.Cells[0,I-1]:=IntToStr(FieldByName('Test_No').AsInteger); TStringGrid.Cells[1,I-1]:=FieldByName('TempText').AsString; Next; end; end;

  • Delphi indy無効なメールアドレス送信

    お世話になります。 Delphi で Indy10 を使いメール送信をしているのですが、無効なメールアドレスの対処方法がわかりません。 以下のコーディングでエラーの場合メッセージを出しているのですが、素通りです。From.Address に指定しているメールアドレスには、Returned mail: see transcript for detailsメールが届いているので、エラーにならないのでしょうか?  皆様、どうかよろしくお願いいたします。 Try try SMTP.Connect; SMTP.Authenticate; SMTP.Send(Msg); except on exception do begin ShowMessage('メール送信に失敗しました'); end; end; Finally if SMTP.Connected then SMTP.Disconnect; Msg.Free; Provider.Free; Login.Free; SMTP.Free; end;

  • [Delphi] StrToInt64がしたい

    16バイトの文字列を8バイトのint64型に変換したいです 下記コードのようにやってみたのですが上手く動きません 何か間違っている、他に方法などがありましたら教えてください。 function HexToInt64(const S: string): Int64; const hexstr : string = '0123456789abcdefABCDEF'; var I,L,h,m: Integer; j: Int64; p: PByteArray; test: string; begin result:=-1; p := @j; L:=Length(s); test:= ''; if L <> 16 then Exit; for i:=1 to L do if Pos(s[i], hexstr)<=0 then Exit; h:= strtoint('$' + Copy(S,0,8)); CopyMemory(@p[0], @h, 8); m:= strtoint('$' + Copy(S,9,8)); CopyMemory(@p[8], @m, 8); CopyMemory(@j, @p, 16); result:=j; end;

  • 最大公約数を再帰で求める(pascal)

    入力した整数値の最大公約数を出力するプログラムを再帰呼び出しの形式で作れ、という課題が出ました。 再帰でない形式は下のように作れたのですが、再帰形式がどうしてもできません。どなたかご教授ください。 function gcd(a,b:integer):integer; {関数部} var tmp:integer; begin if a<b then begin tmp:=b; b:=a; a:=tmp end; repeat tmp:=b; b:=a mod b; a:=tmp until b=0; gcd:=a end; repeat {計算部、i=n=入力した個数、max=入力できる最大数} i:=i+1; n:=n+1; data[i]:=x; writeln('値:'); readln(x); until (x=0) or (i=max); if i>=2 then begin p:=gcd(data[1],data[2]); if i>=3 then begin for i:= 3 to n do begin p:=gcd(p,data[i]) end; writeln('最大公約数:',p) end else begin writeln('最大公約数:',p) end;

  • DelphiのInputQueryで整数値を入力させたい

    DelphiのInputQueryで整数値を入力させたい のですが、 var Val: Integer; begin Val := 1; InputQuery('個数入力', '個数(1~49):', Val, 1, 49, 1); end; とすると、3番目の引数の型が合っていないとのコンパイルエラーが出ます。 ヘルプでは以下のように書いてあるのですが、何か宣言が必要なのでしょうか? 一番下の例を使いたいのですが… Delphi の構文: function InputQuery(const ACaption, APrompt: string; var Value: string): Boolean; function InputQuery(const ACaption, APrompt: WideString; var Value: WideString): Boolean; overload; function InputQuery(const ACaption, APrompt: WideString; var Value: string): Boolean; overload; function InputQuery(const ACaption, APrompt: WideString; var Value: Double, Min: Double = Low(Integer); Max: Double = High(Integer); Decimals: Integer = 1): Boolean; overload; function InputQuery(const ACaption, APrompt: WideString; var Value: Integer, Min: Integer = Low(Integer); Max: Integer = High(Integer); Increment: Integer = 1): Boolean; overload;

専門家に質問してみよう