Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

DriveComboBox & I/O Error 21

Posted on 1999-01-04
11
Medium Priority
?
947 Views
Last Modified: 2010-04-04
Using D4. How to stop I/O Error 21 when trying to access removeable media when no media present (i.e Floppy Drive - no disk, CD - No Disk, ZipDrive - No Disk). This is driving me mental. I have a project with the similar components and code that I worked on in D2. If I run the EXE from that old project I just get a message box saying Invalid filename.
Please help it's doin my ed in.

xpher.
0
Comment
Question by:xpher
  • 5
  • 3
  • 3
11 Comments
 
LVL 3

Expert Comment

by:williams2
ID: 1354395
To do this there is a small part of the API making it possible to safetest a drive without having it to load anything. It described to stop the annoying "Please insert Disc in Driva A" dialog, but actually this is the only one I can't make working on my machine, and if it is a problem on my machine, it's possible that I'm not the only one.

BUT ..here's your answer (you should though test it on your floppy drive too, to see if I'm right):

function IsDriveReady(DriveLetter : char) : Boolean;
var  OldErrorMode : Word;
  OldDirectory : string;
  Error: Integer;
begin
  OldErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  {$I-}
  ChDir(DriveLetter + ':\');
  Error:= IoResult;
  Result:=  Error=0;
  {$I+}
  SetErrorMode(OldErrorMode);
end;


Regards,
Williams
0
 
LVL 1

Author Comment

by:xpher
ID: 1354396
Hi williams2
I've tried this with no great success. Also variable OldDirectory isn't used in your function. The line
GetDir(0, OldDirectory); should be placed in line after OldErrorMode :=

Thanks anyway

xpher
0
 
LVL 5

Expert Comment

by:heathprovost
ID: 1354397
Try this:

function DriveReady(DriveLetter : char) : Boolean;
var
  Error: Integer;
begin
  {$I-}
  ChDir(DriveLetter + ':\');
  {$I+}
  Error:= IoResult;
  Result:=  Error = 0;
end;

This is how I have always done it, not sure why williams2 code didnt work, I think because it is checking IOResult before enabling IO checking again ($I+).  Also, I dont think you really need the SetErrorMode stuff, I never have needed it anyway.

Hope this helps
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 3

Expert Comment

by:williams2
ID: 1354398
I just took it out of some code I have used some time ago and removed the unecessary stuff, but allright this one is tottally tested (Remeber to include "Uses Windows;" ):

function IsDriveReady(DriveLetter : char) : Boolean;
var
  OldErrorMode : Word;
begin
  OldErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  {$I-}
  ChDir(DriveLetter + ':\');
  Result:=  IoResult=0;
  {$I+}
  SetErrorMode(OldErrorMode);
end;

But you still won't find a solution for the A drive, besides Windows doesn't examine the floppy drive, so why would you?

This method is commonly known by WinAPI to do "Safe examinations", (You may try reading the FAQ at Inprise.com)

regards,
Williams
0
 
LVL 1

Author Comment

by:xpher
ID: 1354399
Heathprovost
Thanks but it is no more than I've tried already. If you would like to send me a sample of code of function in use with a DriveCombo I could check against my several attempts cluttering my hard drive.

To williams2
Regarding comment about windows not examining the floppy, it surely does if you try to access it even if no disk in drive?

Regards
Chris
0
 
LVL 5

Accepted Solution

by:
heathprovost earned 150 total points
ID: 1354400
VERY INTERESTING!!!  I think I got it though.  I didnt realize exactly what you were doing.  The actual problem is not with the DriveComboBox, But with the DirectoryListBox attached to it. It does NOT check drive for readiness, and there is no way to fix it short of modifying the original delphi source code (DriveChange method is private :( ).  The easiest thing to do is not to attach the ListBox to it, and then add the following to the DriveComboBox change event:

procedure TForm1.DriveComboBox1Change(Sender: TObject);
begin
  if DriveReady(DriveComboBox1.Drive) then //test if drive ready
        DirectoryListBox1.Drive := DriveComboBox1.Drive //set if ready
  else
    DriveComboBox1.Drive := 'C'; //reset to known good drive
end;

Just use the DriveReady code I posted earilier to test
Hope this helps
0
 
LVL 3

Expert Comment

by:williams2
ID: 1354401
To heathprovost


"This is how I have always done it, not sure why williams2 code didnt work, I think because it is checking IOResult before enabling IO checking again ($I+)"

You ALWAYS have to go check the IOResult before enabling IO Check to avoid exceptions. Not all OS's accept this.

"Also, I dont think you really need the SetErrorMode stuff, I never have needed it anyway."

You don't think so? I guess you should go have a check at the Win32 API guide then. Not doing it sure makes a lot of mess running in Windows NT

To Chris:
I can only speak from my experience. The way I described it is ensured to stop ALL I/O requesters, but whether I check the IOResult or not I still get an error checking the A-drive, but weird enough only the A-drive.

And I can ensure you, that heathprovost's example will do at least the same.

Regards,
Williams
0
 
LVL 5

Expert Comment

by:heathprovost
ID: 1354402
To Williams2

"You ALWAYS have to go check the IOResult before enabling IO Check to avoid exceptions. Not all OS's accept this"

I dont think that is correct. I may be wrong but at least Inprose agrees with me. Here is the example given in the Delphi 3 help file for IOResult

var

  F: file of Byte;
begin
  if OpenDialog1.Execute then begin
    AssignFile(F, OpenDialog1.FileName);
    {$I-}
    Reset(F);
    {$I+}
    if IOResult = 0 then
      MessageDlg('File size in bytes: ' + IntToStr(FileSize(F)),
        mtInformation, [mbOk], 0);
    else
      MessageDlg('File access error', mtWarning, [mbOk], 0);
  end;
end;

I aint arguing with you or anything, I was only guessing a reason as to why your code didnt work.  That was the only thing I found different than the Help files example.  If you are right they need to fix the damn help file :)

"You don't think so? I guess you should go have a check at the Win32 API guide then. Not doing it sure makes a lot of mess running in Windows NT"

I read the API and I would have to agree with you on this point. I suggest that xpher use Williams2 code to actually check the drive instead of mine, or at least implement his code which changes errormode.

Were is xpher anyway? I answered 3 hours ago and no response.

BTW williams2, do you agree with the reasoning in my answer? That should do it shouldnt it?
0
 
LVL 3

Expert Comment

by:williams2
ID: 1354403
Yes heathprovost, I certainly do agree with your reasoning :-)

I know that Delphi writes this, but even though I have had experiences, that an error occured until I turned the IOResult checking inside the {$I+}, why? I don't know.

but I sure have had my problems with this thing as I am building a remote file access system. Some OS installations does accept silent checking of drives when disabling IOChecking, while I have had experiences that NT Server + Workstation doesn't.

But the question was regarding the file combobox, why I don't see why he should accept my answer prior to yours, so I don't have a problem with that :-) . I was just making a point that some OS's accept this, and some don't

Regards,
Williams
0
 
LVL 1

Author Comment

by:xpher
ID: 1354404
Apologies for delay in replying but haven't had a lot of time. Also wanted to try out all possibilities from your comments etc.
Williams2
Hate rejecting anybody but at the end of the day the last answer from heathprovost got to the root of problem. (Although I did slip a message in there to give info to user).
Heathprovost
Thanks the last one clinched it.

Regards
Xpher
0
 
LVL 3

Expert Comment

by:williams2
ID: 1354405
Ok, everybody. I know this is a little late, but I just think you should know, that I found a generel solution to the problem, even BAD errors won't generate any alarm:

function IsDriveReady(DriveLetter : char): Boolean;
var
  DrvNum: byte;
  EMode: Word;
begin
  result := false;
  DrvNum := ord(DriveLetter);
  if DrvNum >= ord('a') then dec(DrvNum,$20);
  EMode := SetErrorMode(SEM_FAILCRITICALERRORS);
  try
    if DiskSize(DrvNum-$40) <> -1 then result := true;
  finally
    SetErrorMode(EMode);
  end;
end;

I just wanted you to know, because this one works with all drives I know.

Regards,
Williams
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
In response to a need for security and privacy, and to continue fostering an environment members can turn to for support, solutions, and education, Experts Exchange has created anonymous question capabilities. This new feature is available to our Pr…
Suggested Courses

927 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question