お知らせ

電子会議

ライブラリ

FDelphi サイト全文検索

Delphi FAQ一覧

サンプル蔵



FDelphi FAQ
15番会議室「FAQ編纂委員会」に寄せられた「よくある質問の答え」

[Q]
Delphi2.0Jで、DriveComboBox、DirectoryListBox、FileListBoxを配置して、 ディレクトリー選択のフォームを作っています。ところが、次のような操作 は、よくあると思うんですが、エラーメッセージが出て、収拾がつかなくな ります。回避する方法はありませんか? (I) 旧ドライブ不正の場合  (1) DriveComboBoxで、フロッピーをセットしたドライブを指定。  (2) フロッピーを抜く。  (3) 他のHDドライブなどを指定。  ここで、FileListBoxのファイルの表示が元のFDのもののままで、 「I/Oエラー(21)」か、「ファイルへのアクセスが拒否されました」どちらか のエラーメッセージが、元のフロッピーを戻してそのドライブを指定しない 限り、出続けます。

[A]
 コンポを使った、FDがらみのエラーは、上の(I)のほかに、

(II) 新ドライブが不正の場合
 あるドライブが正しく表示できている状態から、未準備FDを指定。

(III) 新旧異なるドライブが不正の場合
 (I)の(1)、(2)の後、
 (3) 他の未準備ドライブを指定。

(IV) 新旧同じドライブで表示更新の場合
 (I)の(1)、(2)の後、
 (3) 異なるフロッピーを入れて指定。

 以下の例では、これらのエラーに対処するため、次のような方法を組み合
わせました。

 (A) システムエラー:
   SetErrorMode(SEM_FAILCRITICALERRORS);

 (B) FileListBox を更新できないエラー:
   FileListBox を破棄し、新たに生成。

 (B) DirectoryListBox を更新できないエラー:
   DirectoryListBox を破棄し、新たに生成。

 実際には、破棄、生成を逆にして、フォーム上で、あからさまに消え、現
れるのを、少しでも、単なる更新表示であるかのように見せました。
[例]
{----- ここから Form1 ユニット: 
       DriveComboBox1 を配置
       DirectoryListBox[1]、[2]、および ------------------------------
       FileListBox[1]、[2] は動的に生成配置
}
unit DrvFileU;

  (...略...)
type
  TArrDirectoryListBox=array[1..2] of TDirectoryListBox;
  TArrFileListBox=array[1..2] of TFileListBox;

  TForm1 = class(TForm)
  (...略...)
  private
    { Private 宣言 }
    FileListBox
          : TArrFileListBox;     {FileListBox[]は動的に作成}
    DirectoryListBox
          : TArrDirectoryListBox;{DirectoryListBox[]も動的に作成}
    gDrive,                      {Globalな現ドライブ}
    fDrive                       {以前のドライブ}
          : char;
    gDBox,                       {GlobalなDirectoryListBox番号}
    gFBox: integer;              {GlobalなFileListBox番号}

  (メンバー関数の宣言...略...)
  end;
var
  Form1: TForm1;
  uOldMode: UINT;                {エラーモード}

  (...略...)

{単にドライブ番号が無効かどうかだけ知らせる}
function DriveState(cDrive: char): boolean;
begin
  Result:=true;
  uOldMode:=SetErrorMode(SEM_FAILCRITICALERRORS);
  if DiskSize(ord(UpCase(cDrive))-ord('A')+1)=-1 then
    Result:=false;
  SetErrorMode(uOldMode);
end; {DriveState}

function OtherBox(iBox: integer): integer;
{iBox=1: 2; =2: 1}
begin case iBox of 1: Result:=2; 2: Result:=1; end; end;

function GetNearHD(iDrive: integer): char;
(*ドライブ番号iDrive(カレント=0; 1以上が'A'以上に相当)
 以外の、iDriveに近いハードディスクドライブを求める。
 戻り値はドライブ記号'A'〜'Z'*)
var
  i,j,k: integer;
  cDrive: char;
begin
  cDrive:='A'; i:=0;
  repeat
    k:=iDrive; i:=-i;
    if i=0 then i:=1
    else if i=-1 then
    else if i>0 then inc(i);
    inc(k,i);
    if (k>=1) and (k<=27) then begin
      cDrive:=chr(k+ord('A')-1);
      j:=GetDriveType(PChar(cDrive+':\'));
      if (iDrive<>k) and (j=DRIVE_FIXED) then begin
        break;
      end;
    end;
  until false;
  Result:=cDrive;
end;

{DriveComboBox1表示更新}
procedure TForm1.UpdateDrive(
          okDrive: Char; var badDrive: Char);
begin
  DriveComboBox1.Drive:=okDrive;
  badDrive:=okDrive;
end; {UpdateDrive}

procedure TForm1.FormCreate(Sender: TObject);
begin
  gDrive:=DriveComboBox1.Drive;
  fDrive:=gDrive;
  {FileListBox[] 動的生成}
  gDBox:=1; gFBox:=1;
  CreateFileListBox(gFBox);
  CreateDirectoryListBox(gDBox);
  DriveComboBox1.DirList:=DirectoryListBox[gDBox];
  Application.OnException:=AppExcept;
end; {FormCreate}

{FileListBox[] 動的生成}
procedure TForm1.CreateFileListBox(iBox: integer);
begin
  FileListBox[iBox]:=TFileListBox.Create(Form1);
  with FileListBox[iBox] do begin
    Parent:=Self;
    Name:='FileListBox'+IntToStr(iBox);
    SetBounds(176,16,145,160);
      {FileListBox1をフォームに一度置いてみて、位置・大きさを
       メモり、削除する。そのときの値を使う}
  end;
end; {CreateFileListBox}

{DirectoryListBox[iBox]生成}
procedure TForm1.CreateDirectoryListBox(iBox: integer);
begin
  DirectoryListBox[iBox]:=TDirectoryListBox.Create(Form1);
  with DirectoryListBox[iBox] do begin
    Parent:=Self;
    Name:='DirectoryListBox'+IntToStr(iBox);
    SetBounds(16,16,145,160);
    FileList:=FileListBox[iBox];
  end;
end;

{FileListBox[]の破棄・生成}
procedure TForm1.RenewFileListBox(
          okDrive: Char; var badDrive: Char);
var
  jFBox: integer;
begin
  jFBox:=OtherBox(gFBox);
  CreateFileListBox(jFBox); {先に新規のFileListBox作成}
  DriveComboBox1.Drive:=okDrive;
  DriveComboBox1.DirList:=DirectoryListBox[gDBox];
  DirectoryListBox[gDBox].FileList:=FileListBox[jFBox];
  FileListBox[gFBox].Free; {使えなくなった古いのは廃棄}
  gFBox:=jFBox;
  badDrive:=okDrive;
end; {RenewFileListBox}

{DirectorylistBox[]、FileListBox[]の破棄・生成}
procedure TForm1.RenewDirFileBox(
          okDrive: Char; var badDrive: Char);
var
  jDBox,jFBox: integer;
begin
  jDBox:=OtherBox(gDBox);
  jFBox:=OtherBox(gFBox);
  DriveComboBox1.Drive:=okDrive;
  ChDir(okDrive+':\');
  CreateFileListBox(jFBox); {新規のFileListBox作成}
  CreateDirectoryListBox(jDBox);
  DriveComboBox1.DirList:=DirectoryListBox[jDBox];
  DirectoryListBox[jDBox].Update;
  FileListBox[jFBox].Update;
  FileListBox[gFBox].Free; {使えなくなった古いのは廃棄}
  DirectoryListBox[gDBox].Free;
  gDBox:=jDBox; gFBox:=jFBox;
  badDrive:=okDrive;
end; {RenewDirFileBox}

procedure TForm1.AppExcept(Sender: TObject; E: Exception);
begin
  if E is EInOutError then begin
    if EInOutError(E).ErrorCode in
      [2,   {ファイルが見つかりません−同ドライブ表示更新の場合}
      5,    {ファイルアクセスが拒否されました:(*E1)}
      21]   {ドライブの準備ができていない:(*E2)}
      then begin
      if (UpCase(fDrive)=UpCase(gDrive)) and DriveState(gDrive)
        then begin
        RenewDirFileBox(gDrive,fDrive);
      end else if DriveState(gDrive) and
        (not DriveState(fDrive)) then begin
        RenewFileListBox(gDrive,fDrive);
      end else if DriveState(fDrive) and
        (not DriveState(gDrive)) then begin
        ErrMes:=gDrive+':ドライブの準備ができていません';
        ShowMessage(ErrMes);
        UpdateDrive(fDrive,gDrive);
      end
    end;
  end;
end; {AppExcept}

procedure TForm1.DriveComboBox1Click(Sender: TObject);
var
  aDrive: char;
begin
  fDrive:=DriveComboBox1.Drive;
  gDrive:=(DriveComboBox1.Items[DriveComboBox1.ItemIndex])[1];
  if (UpCase(fDrive)=UpCase(gDrive)) and DriveState(gDrive)
    then begin
    DirectoryListBox[gDBox].Update;
    FileListBox[gFBox].Update;
  end else if (not DriveState(fDrive)) and
    (not DriveState(gDrive)) then begin
    {FDにはもはやアクセスできない}
    aDrive:=gDrive;
    gDrive:=GetNearHD(ord(UpCase(aDrive))-ord('A')+1);
    ShowMessage(UpCase(fDrive)+':ドライブ、'+UpCase(aDrive)+
      ':ドライブには'#13+'アクセスできませんので'#13+
      gDrive+':ドライブを表示します。');
    UpdateDrive(gDrive,fDrive);
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DirectoryListBox[gDBox].Free;
  FileListBox[gFBox].Free;
end;
end.
{----- ここまで ----------------------------------------------------}

【補足】
 (1) DriveComboBox1 をクリックしてドライブを選ぶとき、コードのように
旧ドライブと新ドライブを、fDrive、gDrive で取得できます。OnChange で
はこれがうまく取得できません。

 (2) 未準備ドライブにアクセスする方は、比較的たちがよいですが、フロ
ッピードライブ(F:とします)を表示後、抜いて、他のドライブを指定する
場合は、F: のルートを表示させていたか、ルート以外のディレクトリーを
表示させていたかで、それぞれ、(*E2)、(*E1) のエラーとなりますので、
いずれも、FileListBox[] を破棄・生成しました。

 (3) 未準備ドライブを指定したときはメッセージを出すべきでしょうが、
ドライブを抜いて、他の、アクセス可能なドライブを指定したときは、黙っ
て、そのドライブを表示すべきです。上のコードでそのことを実現しました。


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum FDELPHIに寄せられる質問の中から、よくある質問への回答を FDELPHIのメンバーがまとめたものです。 したがって、これらの回答はボーランド株式会社がサポートする公式のものではなく、掲示されている内容についての問い合わせは受けられない場合があります。

Copyright 1996-1998 Delphi Users' ForumFAQ編纂委員会