Playing Audio CDs, part 3 - MCI

Today, I want to talk about one of the most weird and wonderful APIs in all of Windows.  It's also one of the oldest - the creation date on the source file is April 25, 1990.

This API is the MCI command set.  It's an example of defining two separate APIs that do exactly the same thing -   There are really only two different MCI APIs, mciSendString and mciSendCommand.  They are utterly identical, the only difference between the two of them is that mciSendString sends its commands using strings, and mciSendCommand uses buffers.  There's a parser in winmm.dll that converts the parameters to mciSendString into the buffers specified by mciSendCommand.

The MCI commands can be used for most multimedia functions - you can play audio CDs with the APIs, you can play videos (not wmv videos, but AVI files), you can play wave files.  It's really quite an extraordinary API set.

So here's the CD player specialization for MCI strings:

CMCIStringCDPlayer::CMCIStringCDPlayer(void){}CMCIStringCDPlayer::~CMCIStringCDPlayer(void){}HRESULT CMCIStringCDPlayer::Initialize(void){    MCIERROR mciError;    TCHAR mciReturnBuffer[512];    mciError = mciSendString("status cdaudio media present", mciReturnBuffer, sizeof(mciReturnBuffer), NULL);    if (mciError != 0)    {        printf("MCI Error %x determining CD media status\n",mciError);        return HRESULT_FROM_WIN32(mciError);    }    if (stricmp(mciReturnBuffer, "true") != 0)    {        printf("No media in CDRom drive\n");        return E_FAIL;    }    return S_OK;}HRESULT CMCIStringCDPlayer::DumpTrackList(){    MCIERROR mciError;    TCHAR mciReturnBuffer[512];    mciError = mciSendString("status cdaudio number of tracks", mciReturnBuffer, sizeof(mciReturnBuffer), NULL);    if (mciError != 0)    {        printf("MCI Error %x determining CD media track count\n",mciError);        return HRESULT_FROM_WIN32(mciError);    }    sscanf(mciReturnBuffer, "%d", &_TrackCount);    for (int i = 0 ; i < _TrackCount ; i += 1)    {        TCHAR mciCommandBuffer[512];        DWORD trackHours, trackMinutes, trackSeconds;        sprintf(mciCommandBuffer, "status cdaudio length track %d", i+1);        mciError = mciSendString(mciCommandBuffer, mciReturnBuffer, sizeof(mciReturnBuffer), NULL);        if (mciError != 0)        {            printf("MCI Error %x determining track length\n",mciError);            return HRESULT_FROM_WIN32(mciError);        }        printf("Track %d: Length %s\n", i, mciReturnBuffer);    }    return S_OK;}HRESULT CMCIStringCDPlayer::PlayTrack(int TrackNumber){    printf("Next article\n");    return E_FAIL;}

Following the pattern of the WMP articles, this one only dumps the contents of the CD tracks.  The first thing you'll notice is that the MCI string APIs use strings for their parameters (no duh, that's why they're called string APIs).  But the strings you specify are pretty verbose - for instance, to retrieve the number of tracks, you say "status cdaudio number of tracks".  The first word in the command string is the verb - MCI supports verbs like open , set, cut, paste, play, spin, etc.  You can even tell the MCI commands to open or close the CDRom door (with "set cdaudio door open").

The other thing to notice is that audio tracks are )ORIGIN 1, not )ORIGIN 0.  The other thing to notice is that the length of a track is returned in m:s:f format, or minutes:seconds:frames.

Tomorrow, I'll add the playback functions.