Pregunta

I'm writing an application that's going to work with audio CDs and mixed CDs. I would like to have a method of determining whether there is an audio or mixed-type (with at least one audio track) disc currently in the drive that the application uses.

So far, I was able to identify that the drive is a CD-ROM by GetDriveType. However, it turns out that identifying the media that is actually inside the drive is not that easy. This is what I've got so far :

int drive_has_audio_disc(const char *root_path)
{
  char volume_name[MAX_PATH+1];
  BOOL winapi_rv;
  DWORD fs_flags;
  int rv;

  winapi_rv = GetVolumeInformation(root_path, volume_name, sizeof(volume_name),
    NULL, NULL, &fs_flags, NULL, 0);
  if(winapi_rv != 0)
  {
    rv = (strcmp(volume_name, "Audio CD") == 0 &&
      (fs_flags & FILE_READ_ONLY_VOLUME));
  }
  else
  {
    rv = (GetLastError() == ERROR_INVALID_PARAMETER) ? 0 : -1;
  }
  return rv;
}

However, it relies on the fact that Windows assigns the name "Audio CD" to all discs that are recognized as audio. This doesn't feel right, and is going to fail miserably on mixed-mode CDs, since their name in Windows is determined by the volume name of the data track. Also, the else block is here because I've noticed that GetVolumeInformation returns an error with GetLastError equal to ERROR_INVALID_PARAMETER when there is no disc in the drive at all.

Ideally, I'm looking for something like the CDROM_DISC_STATUS ioctl present on Linux. It returns CDS_NO_INFO, CDS_AUDIO, CDS_MIXED, or some other values, depending on the contents of the disc.

Is there any other way of handling this? And what about mixed-mode discs?

¿Fue útil?

Solución

You can use the CD-ROM I/O Control Codes, in particular the IOCTL_CDROM_READ_TOC. The structure it returns looks like this:

struct TRACK_DATA {
  UCHAR Reserved;
  UCHAR Control  :4;
  UCHAR Adr  :4;
  UCHAR TrackNumber;
  UCHAR Reserved1;
  UCHAR Address[4];
} 

struct CDROM_TOC {
  UCHAR      Length[2];
  UCHAR      FirstTrack;
  UCHAR      LastTrack;
  TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
};

You can find an example of how to retrieve it on Larry Osterman's blog. From this you should be able to determine the exact disc type. If not, check out other IOCTLs, I'm sure there should be one that gives you the necessary info.

Otros consejos

I once had to do something similar for a project, but with DVDs instead. You can use DeviceIoControl(IOCTL_SCSI_PASS_THROUGH) to send a MultiMedia Commands (MMC) GET CONFIGURATION command directly to the drive to retrieve its currently active Profile, which is based on the specific type of disc that is currently loaded.

The CD profiles are:

0x0008 CD-ROM
0x0009 CD-R
0x000A CD-RW
0x0020 Double Density CD-ROM
0x0021 Double Density CD-R
0x0022 Double Density CD-RW

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top