Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

I/O error 21 1

Status
Not open for further replies.

dba2

Programmer
May 23, 2002
16
GB
I am using C++Builder 4 under W2K and have written a program which uses TDriveComboBox. If I try to access a CD drive with no CD present I get an 'I/O error 21' dialog popping up but cannot find a way to trap the message to change it to a more meaningful one.

Can anyone help please?
 
Off the top of my head i would do a check of which drives there are available and store them in the "Items" (check it's properties), by doing this You have full control in which locations it's allowed to select. There might be far better and simpler solutions but it's a starter at least.
I take it that You have tried to use the try...catch thing.
 
Many thanks for the response Totte. I didn't explain that I want the CD drive to be available but need to replace the "I/O error 21" with a message like "Please insert a CD".
I have inserted try-catches at all levels in the program but can't trap it. A work colleague with much more experience of C++Builder than I have has also come across the same problem with the same combination of C++Builder and OS versions. He has not been able to find a solution but the answer must be out there somewhere!
 
The problem with try...catch statments is that if you don't know exactly what to catch, you can do a catch-all.
Code:
try
{
   // do something
}
catch (EConvertError &error)
{
   // catches only integer conversion error
}
catch (...)
{
   // catches everything else
}

Without knowing exactly what error 21 sends, it is hard to catch. Another proactive approach is to determine before hand if there is a CD. You can use GetDriveType and GetVolumeInformation. Post here if you need examples of these. James P. Cottingham

I am the Unknown lead by the Unknowing.
I have done so much with so little
for so long that they think I am now
qualified to do anything with nothing.
 
Many thanks James, this may be heading in the right direction. I have added catch(...) everywhere to create a ShowMessage to try to locate the problem but still no progress. I am already using GetDriveType but not GetVolumeInformation, it would be helpful if you could post samples please. BTW I notice from the GetVolumeInformation help file that SetErrorMode with SEM_FAILCRITICALERRORS set, should prevent system from displaying a prompt message to 'Insert a CD' but I'm not getting that message from within the program. If I select the CD drive in 'My Computer' I get the prompt to 'Insert a CD'.

David Aston
 
The source code for this example comes from Borland C++ Builder How-To: The Definitive C++ Builder Problem-Solver by John Miano, Tom Cabanski, and Harold Howe. [All rights reserved, etc] If you can find this book, it is a "keeper." Also see Howe's web site at This particular example has a TForm, two TLabels, a TComboBox named cbPath which is a drop down list, and a TMemo named mInfo. This project is a form which shows all the drives in the drop down. When the user opens that up and selects a new drive, the memo box shows the drive info. Of interest to you is the part where the drive info does not display.

This project has one user created function
Code:
void __fastcall GetDriveInfo(void)
. In the form create section, the project has the following code to collect the drive info for the combo box.
Code:
  char *lpDrives, *lpItem;

  //Determine how big a buffer is needed to hold all the logical device paths
  dwSize = GetLogicalDriveStrings(0, NULL);
  //Initialize a buffer of the proper size
  lpDrives = new char[dwSize];
  //Get the logical drives
  GetLogicalDriveStrings(dwSize, lpDrives);
  //Initialize a working variable
  lpItem = lpDrives;
  //While there are more items in the list
  //(end of list is indicated by a 0 length string
  while (strlen(lpItem) != 0)
  {
    //Add the current item to the path list
    cbPath->Items->Add(lpItem);
    //Increment the pointer to the next path item in the list
    lpItem += strlen(lpItem) + 1;
  }

  //If there are some logical device paths
  if (cbPath->Items->Count)
  {
    //Make the first item the default
    cbPath->ItemIndex = 0;
    //Load the drive info for the default device path
    GetDriveInfo();
  }

  //Free the memory allocated for the device paths
  delete [] lpDrives;
On the combo box's OnChange method, the project calls the GetDriveInfo() function. This allows the memo box to display drive info when the user changes the drive. The main thing about GetDriveInfo() that you need is when GetVolumeInformation fails, your error code displays the "drive not ready message."
Code:
void __fastcall TForm1::GetDriveInfo(void)
{
  UINT Type;
  String s;
  char lpVolumeName[255], lpFileSystemName[100], szBuffer[512];
  DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;

  //Clear the info display
  mInfo->Clear();

  //Get the drive type
  Type = GetDriveType(cbPath->Items->Strings[cbPath->ItemIndex].c_str());
  //Update the display accoring to the drive type
  switch (Type)
  {
    case 0:
      s = "Unknown";
      break;
    case 1:
      s = "Does not exist";
      break;
    case DRIVE_REMOVABLE:
      s = "Removable Disk Drive";
      break;
    case DRIVE_FIXED:
      s = "Fixed Disk Drive";
      break;
    case DRIVE_REMOTE:
      s = "Network Drive";
      break;
    case DRIVE_CDROM:
      s = "CD ROM Drive";
      break;
    case DRIVE_RAMDISK:
      s = "RAM Disk";
  }

  mInfo->Lines->Add("Device Type: " + s);

  //Check the volume information.  Returns TRUE on success
  if (GetVolumeInformation(cbPath->Items->Strings[cbPath->ItemIndex].c_str(),
                           lpVolumeName,
                           255,
                           &dwVolumeSerialNumber,
                           &dwMaximumComponentLength,
                           &dwFileSystemFlags,
                           lpFileSystemName,
                           100))
  {
    //Update the display with the information
    wsprintf(szBuffer, "Volume Name: %s", lpVolumeName);
    mInfo->Lines->Add(szBuffer);
    wsprintf(szBuffer, "Serial Number: %u", dwVolumeSerialNumber);
    mInfo->Lines->Add(szBuffer);
    wsprintf(szBuffer, "File System: %s", lpFileSystemName);
    mInfo->Lines->Add(szBuffer);
  }
  //GetVolumeInformation failed
  else
    //No disk in removable drive or drive not ready
    mInfo->Lines->Add("DRIVE IS NOT READY");
}
James P. Cottingham

I am the Unknown lead by the Unknowing.
I have done so much with so little
for so long that they think I am now
qualified to do anything with nothing.
 
Many thanks again James, that suggestion has enabled me to find that the cause of the problem is associated with using a TDriveComboBox. If I use the TComboBox I don't get the error! PS I'm trying to order the book but as you probably know it's generally no longer available.

David Aston
 
Originally, you indicated that you wanted to TRAP the dialog from popping up... Try this:

UINT prevErrorMode;

// save off the current error mode
prevErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);


// access the media... or not, but the error will come
// in the form of a return code, and no dialog


// restore the error mode
SetErrorMode(prevErrorMode);
 
I've just noticed your response pmaia, sorry for the delay in responding!
Yes I do want to trap the dialog so I can replace it with my own message but since the error is not trappable within the DriveSelectionComboBoxChange() function/method I can't quite see how this will help me to resolve this particular problem?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top