/******************************Module*Header*******************************\ * Module Name: cdapimci.c * * This module encapsulates the CD-ROM device into a set of callable apis. * The api's are implemented using the cdaudio mci interface. * * Created: 26-04-93 * Author: Stephen Estrop [StephenE] * * Copyright (c) 1993 - 1995 Microsoft Corporation. All rights reserved. \**************************************************************************/ #pragma warning( once : 4201 4214 ) #define NOOLE #include /* required for all Windows applications */ #include #include #include "playres.h" #include "cdplayer.h" #include "cdapi.h" #include "scan.h" #include "trklst.h" #include "..\cdopt\cdopt.h" #ifdef __cplusplus extern "C" { #endif /* ------------------------------------------------------------------------- ** ** High level routines ** ** ------------------------------------------------------------------------- */ BOOL g_fCDOpen = TRUE; /******************************Public*Routine******************************\ * OpenCdRom * * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ MCIDEVICEID OpenCdRom( TCHAR chDrive, LPDWORD lpdwErrCode ) { MCI_OPEN_PARMS mciOpen; TCHAR szElementName[4]; TCHAR szAliasName[32]; DWORD dwFlags; DWORD dwAliasCount = GetCurrentTime(); DWORD dwRet; ZeroMemory( &mciOpen, sizeof(mciOpen) ); mciOpen.lpstrDeviceType = (LPTSTR)MCI_DEVTYPE_CD_AUDIO; wsprintf( szElementName, TEXT("%c:"), chDrive ); wsprintf( szAliasName, TEXT("SJE%lu:"), dwAliasCount ); mciOpen.lpstrElementName = szElementName; mciOpen.lpstrAlias = szAliasName; OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(os); GetVersionEx(&os); if (os.dwPlatformId == VER_PLATFORM_WIN32_NT) { dwFlags = MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE | MCI_OPEN_ALIAS | MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_WAIT; } else { dwFlags = MCI_OPEN_ELEMENT | MCI_OPEN_ALIAS | MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_WAIT; } dwRet = mciSendCommand(0, MCI_OPEN, dwFlags, (DWORD_PTR)(LPVOID)&mciOpen); if ( dwRet == MMSYSERR_NOERROR ) { MCI_SET_PARMS mciSet; ZeroMemory( &mciSet, sizeof(mciSet) ); mciSet.dwTimeFormat = MCI_FORMAT_MSF; mciSendCommand( mciOpen.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID)&mciSet ); } else { /* ** Only return the error code if we have been given a valid pointer */ if (lpdwErrCode != NULL) { *lpdwErrCode = dwRet; } mciOpen.wDeviceID = 0; } return mciOpen.wDeviceID; } /******************************Public*Routine******************************\ * CloseCdRom * * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ void CloseCdRom( MCIDEVICEID DevHandle ) { mciSendCommand( DevHandle, MCI_CLOSE, 0L, 0L ); } /******************************Public*Routine******************************\ * CheckStatus * * Check return code for known bad codes and inform * user how to correct (if possible) the problem. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void CheckStatus( LPSTR szCaller, DWORD status, int cdrom ) { #if DBG TCHAR s[200]; TCHAR err[100]; #endif if (status==ERROR_SUCCESS) return; /* switch (status) { case MCIERR_HARDWARE: NoMediaUpdate( cdrom ); break; } */ #if DBG mciGetErrorString( status, err, sizeof(err) / sizeof(TCHAR) ); wsprintf( s, IdStr( STR_ERR_GEN ), g_Devices[cdrom]->drive, err ); OutputDebugString (s); OutputDebugString (TEXT("\r\n")); #endif } /******************************Public*Routine******************************\ * CheckUnitCdrom * * Queries the device state, checking to see if a disc has been ejected or * inserted. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void CheckUnitCdrom( int cdrom, BOOL fForceRescan ) { DWORD status; if ((cdrom < 0) || (cdrom >= MAX_CD_DEVICES)) { return; } if (fForceRescan) { // Close Device to force read of correct TOC if (g_Devices[cdrom]->hCd != 0L) { CloseCdRom (g_Devices[cdrom]->hCd); g_Devices[cdrom]->hCd = 0L; } } if ( g_Devices[cdrom]->hCd == 0L ) { g_Devices[cdrom]->hCd = OpenCdRom( g_Devices[cdrom]->drive, NULL ); if ( g_Devices[cdrom]->hCd == 0 ) { return; } else { /* ** Force a rescan of this disc. */ g_Devices[cdrom]->State = CD_NO_CD; } } status = TestUnitReadyCdrom( g_Devices[cdrom]->hCd ); if (g_Devices[cdrom]->State & CD_NO_CD) { if (status == ERROR_SUCCESS) { /* ** A new disc has been inserted, scan it now. */ RescanDevice( g_hwndApp, cdrom ); } } else { if (status != ERROR_SUCCESS) { /* ** Disc has been ejected. */ NoMediaUpdate( cdrom ); } } } /******************************Public*Routine******************************\ * NoMediaUpdate * * Update the user display when it is found that no media is in the device. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void NoMediaUpdate( int cdrom ) { BOOL fChangePlayButtons; if ( cdrom == g_CurrCdrom ) { fChangePlayButtons = TRUE; } else { fChangePlayButtons = FALSE; } g_Devices[cdrom]->State = (CD_NO_CD | CD_STOPPED); if (fChangePlayButtons) { g_pSink->OnEvent(MMEVENT_ONMEDIAUNLOADED,NULL); //tell the UI to gray out the button HWND hwndTrackButton = GetDlgItem(GetParent(g_hwndApp),IDB_TRACK); if (hwndTrackButton) { EnableWindow(hwndTrackButton,FALSE); } SetPlayButtonsEnableState(); } //tell the playlist // Drive has been ejected if (g_pSink) { LPCDOPT pOpt = (LPCDOPT)g_pSink->GetOptions(); LPCDOPTIONS pCDOpts = NULL; LPCDUNIT pUnit = NULL; if (pOpt) { pCDOpts = pOpt->GetCDOpts(); } if (pCDOpts) { pUnit = pCDOpts->pCDUnitList; } //scan the list to find the one we want for (int index = 0; index < cdrom; index++) { if (pUnit) { pUnit = pUnit->pNext; } } if (pUnit) { pUnit->dwTitleID = CDTITLE_NODISC; pUnit->dwNumTracks = 0; pUnit->szNetQuery[0] = '\0'; pOpt->DiscChanged(pUnit); } } //end if sink TimeAdjustInitialize( cdrom ); } /******************************Public*Routine******************************\ * EjectTheCdromDisc * * Eject the disc from the specified cdrom device. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL EjectTheCdromDisc( int cdrom ) { DWORD status; /* ** Stop the drive first */ status = StopCdrom( g_Devices[cdrom]->hCd ); /* ** Eject the disc */ status = EjectCdrom( g_Devices[cdrom]->hCd ); CheckStatus( "EjectCdrom", status, cdrom ); return status == ERROR_SUCCESS; } /******************************Public*Routine******************************\ * PlayCurrTrack * * Set cdrom device playing from start MSF to end MSF of current * track. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL PlayCurrTrack( int cdrom ) { DWORD status; MCI_PLAY_PARMS pam; int min,sec,endindex; PTRACK_PLAY tr; tr = CURRTRACK( cdrom ); if (tr==NULL) { return( FALSE ); } sec = TRACK_S(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurSec; min = TRACK_M(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurMin; min+= (sec / 60); sec = (sec % 60); pam.dwFrom = MCI_MAKE_MSF( min, sec, TRACK_F(cdrom,tr->TocIndex) ); endindex = FindContiguousEnd( cdrom, tr ); pam.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,endindex), TRACK_S(cdrom,endindex), TRACK_F(cdrom,endindex) ); #if DBG { long lAddress, lEndPos, lStartPos; dprintf( TEXT("Playing from : %2.2d:%2.2d:%2.2d"), MCI_MSF_MINUTE(pam.dwFrom), MCI_MSF_SECOND(pam.dwFrom), MCI_MSF_FRAME( pam.dwFrom) ); dprintf( TEXT("Playing to : %2.2d:%2.2d:%2.2d"), MCI_MSF_MINUTE(pam.dwTo), MCI_MSF_SECOND(pam.dwTo), MCI_MSF_FRAME( pam.dwTo) ); lAddress = pam.dwFrom; lStartPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) + (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) + (MCI_MSF_FRAME(lAddress)); lAddress = pam.dwTo; lEndPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) + (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) + (MCI_MSF_FRAME(lAddress)); lAddress = lEndPos - lStartPos; lStartPos = MCI_MAKE_MSF((lAddress / FRAMES_PER_MINUTE), (lAddress % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND, (lAddress % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND); lAddress = lStartPos; dprintf( TEXT("Play length : %2.2d:%2.2d:%2.2d"), MCI_MSF_MINUTE(lAddress), MCI_MSF_SECOND(lAddress), MCI_MSF_FRAME( lAddress) ); } #endif status = PlayCdrom( g_Devices[cdrom]->hCd, &pam ); CheckStatus( "PlayCurrTrack", status, cdrom ); return status == ERROR_SUCCESS; } /******************************Public*Routine******************************\ * StopTheCdromDrive * * Tell the cdrom device to stop playing * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL StopTheCdromDrive( int cdrom ) { DWORD status; status = StopCdrom( g_Devices[cdrom]->hCd ); CheckStatus( "StopCdrom", status, cdrom ); return status == ERROR_SUCCESS; } /******************************Public*Routine******************************\ * PauseTheCdromDrive * * Tell the cdrom device to pause playing * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL PauseTheCdromDrive( int cdrom ) { DWORD status; status = PauseCdrom( g_Devices[cdrom]->hCd ); CheckStatus( "PauseCdrom", status, cdrom ); return status == ERROR_SUCCESS; } /******************************Public*Routine******************************\ * ResumeTheCdromDrive * * Tell the cdrom device to resume playing * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL ResumeTheCdromDrive( int cdrom ) { DWORD status; status = ResumeCdrom( g_Devices[cdrom]->hCd, cdrom ); CheckStatus( "ResumeCdrom", status, cdrom ); if ( status == ERROR_NOT_READY ) { NoMediaUpdate( cdrom ); } return status == ERROR_SUCCESS; } /******************************Public*Routine******************************\ * SeekToCurrSecond * * Seek to the position on the disc represented by the * current time (position) information in gDevices, and * continue playing to the end of the current track. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL SeekToCurrSecond( int cdrom ) { DWORD status; int endindex; PTRACK_PLAY tr; UCHAR StartingF, StartingS, StartingM; /* ** Build starting and ending positions for play */ tr = CDTIME(cdrom).CurrTrack; if (tr == NULL) { return FALSE; } StartingM = (TRACK_M(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurMin); StartingS = (TRACK_S(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurSec); StartingF = (TRACK_F(cdrom,tr->TocIndex)); if (StartingS > 59) { StartingM++; StartingS -= (UCHAR)60; } if (g_Devices[ cdrom ]->State & CD_PLAYING) { MCI_PLAY_PARMS mciPlay; endindex = FindContiguousEnd( cdrom, tr ); mciPlay.dwFrom = MCI_MAKE_MSF( StartingM, StartingS, StartingF ); mciPlay.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,endindex), TRACK_S(cdrom,endindex), TRACK_F(cdrom,endindex) ); status = PlayCdrom( g_Devices[ cdrom ]->hCd, &mciPlay ); } else { MCI_SEEK_PARMS mciSeek; mciSeek.dwTo = MCI_MAKE_MSF( StartingM, StartingS, StartingF ); status = SeekCdrom( g_Devices[ cdrom ]->hCd, &mciSeek ); } CheckStatus( "SeekToCurrSec", status, cdrom ); return status == ERROR_SUCCESS; } /******************************Public*Routine******************************\ * GetCurrPos * * Query cdrom device for its current position and status * and return information in callers buffer. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL GetCurrPos( int cdrom, PCURRPOS CpPtr ) { DWORD status; DWORD dwStatus; DWORD dwTrack = 0; DWORD dwAbsPos; BOOL fNT; OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(os); GetVersionEx(&os); if (os.dwPlatformId == VER_PLATFORM_WIN32_NT) { fNT = TRUE; } else { fNT = FALSE; } /* ** Tell lower layer what we want it to do...in this case, ** we need to specify which SubQData format we want returned. ** This is exported from scsicdrom.sys to the user layer ** so that it could be implemented in one call, instead of ** four separate calls (there are four SubQData formats) */ /* ** Set up for current position SubQData format. */ if (CDTIME(cdrom).CurrTrack != NULL) { if (fNT) { status = StatusTrackPosCdrom ( g_Devices[ cdrom ]->hCd, &dwStatus, &dwTrack, &dwAbsPos); } else { status = GetCdromCurrentPosition( g_Devices[ cdrom ]->hCd, &dwAbsPos ); } } else { status = MCIERR_INTERNAL; } if (status == ERROR_SUCCESS) { int iTrack; LONG lAbsPosF; LONG lStartPos; LONG lTrackPos; if (!fNT) { iTrack = (int)GetCdromCurrentTrack( g_Devices[ cdrom ]->hCd ); } else { iTrack = (int)dwTrack; } if (!fNT) { CpPtr->AudioStatus = GetCdromMode( g_Devices[ cdrom ]->hCd ); } else { CpPtr->AudioStatus = dwStatus; } CpPtr->Track = iTrack; CpPtr->Index = 1; iTrack--; lStartPos = (TRACK_M(cdrom, iTrack ) * FRAMES_PER_MINUTE) + (TRACK_S(cdrom, iTrack ) * FRAMES_PER_SECOND) + (TRACK_F(cdrom, iTrack )); lAbsPosF = (MCI_MSF_MINUTE(dwAbsPos) * FRAMES_PER_MINUTE) + (MCI_MSF_SECOND(dwAbsPos) * FRAMES_PER_SECOND) + (MCI_MSF_FRAME(dwAbsPos)); lTrackPos = lAbsPosF - lStartPos; /* ** Are we in the track lead in zone ? */ if ( lTrackPos < 0 ) { /* ** Have we just entered the lead in zone */ if (!g_Devices[cdrom]->fProcessingLeadIn) { g_Devices[cdrom]->fProcessingLeadIn = TRUE; /* ** Is the track that we are currently in the next track ** that we actually want to play. If it is then everything is ** OK. If it isn't then we need to hack the current position ** information so that it looks like we sre still playing the ** previous track. */ if ( CURRTRACK(cdrom)->nextplay && CURRTRACK(cdrom)->nextplay->TocIndex == iTrack) { g_Devices[cdrom]->fShowLeadIn = TRUE; } else { g_Devices[cdrom]->fShowLeadIn = FALSE; } } g_Devices[cdrom]->fShowLeadIn = FALSE; if (g_Devices[cdrom]->fShowLeadIn) { CpPtr->Index = 0; lTrackPos = -lTrackPos; } else { CpPtr->Track = iTrack; iTrack--; lTrackPos = lAbsPosF - g_Devices[cdrom]->toc.TrackData[iTrack].AddressF; } } else { g_Devices[cdrom]->fShowLeadIn = FALSE; g_Devices[cdrom]->fProcessingLeadIn = FALSE; } CpPtr->m = (int)(lTrackPos / FRAMES_PER_MINUTE); CpPtr->s = (int)(lTrackPos % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND; CpPtr->f = (int)(lTrackPos % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND; CpPtr->ab_m = (int)MCI_MSF_MINUTE(dwAbsPos); CpPtr->ab_s = (int)MCI_MSF_SECOND(dwAbsPos); CpPtr->ab_f = (int)MCI_MSF_FRAME(dwAbsPos); /* ** Round up to the nearest second. */ if (CpPtr->f > (FRAMES_PER_SECOND / 2) ) { if ( ++CpPtr->s > 59 ) { CpPtr->s = 0; CpPtr->m++; } } else { CpPtr->f = 0; } if (CpPtr->ab_f > (FRAMES_PER_SECOND / 2) ) { if ( ++CpPtr->ab_s > 59 ) { CpPtr->ab_s = 0; CpPtr->ab_m++; } } else { CpPtr->ab_f = 0; } } else { ZeroMemory( CpPtr, sizeof(*CpPtr) ); } CheckStatus( "GetCurrPos", status, cdrom ); return status==ERROR_SUCCESS; } /******************************Public*Routine******************************\ * SeekToTrackAndHold * * Seek to specified track and enter hold state. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL SeekToTrackAndHold( int cdrom, int tindex ) { DWORD status; MCI_SEEK_PARMS sam; sam.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,tindex), TRACK_S(cdrom,tindex), TRACK_F(cdrom,tindex) ); status = SeekCdrom( g_Devices[ cdrom ]->hCd, &sam ); CheckStatus( "SeekToTrackAndHold", status, cdrom ); return status == ERROR_SUCCESS; } /* ------------------------------------------------------------------------- ** ** Low level routines ** ** ------------------------------------------------------------------------- */ /******************************Public*Routine******************************\ * GetCdromTOC * * This routine will get the table of contents from * a CDRom device. * * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD GetCdromTOC( MCIDEVICEID DevHandle, PCDROM_TOC TocPtr ) { MCI_STATUS_PARMS mciStatus; long lAddress, lStartPos, lDiskLen; int i; DWORD dwRet; #if DBG dprintf( TEXT("Reading TOC for drive %d"), DevHandle ); #endif ZeroMemory( &mciStatus, sizeof(mciStatus) ); mciStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; // // NOTE: none of the mciSendCommand calls below bother to check the // return code. This is asking for trouble... but if the // commands fail we cannot do much about it. // dwRet = mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus); TocPtr->FirstTrack = 1; TocPtr->LastTrack = (UCHAR)mciStatus.dwReturn; mciStatus.dwItem = MCI_STATUS_POSITION; for ( i = 0; i < TocPtr->LastTrack; i++ ) { mciStatus.dwTrack = i + 1; dwRet = mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD_PTR)(LPVOID)&mciStatus); TocPtr->TrackData[i].TrackNumber = (UCHAR)(i + 1); lAddress = TocPtr->TrackData[i].Address = (long)mciStatus.dwReturn; lStartPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) + (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) + (MCI_MSF_FRAME( lAddress)); TocPtr->TrackData[i].AddressF = lStartPos; } mciStatus.dwItem = MCI_STATUS_LENGTH; dwRet = mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus); /* ** Convert the absolute start address of the first track ** into Frames */ lAddress = TocPtr->TrackData[0].Address; lStartPos = TocPtr->TrackData[0].AddressF; /* ** Convert the total disk length into Frames */ lAddress = (long)mciStatus.dwReturn; lDiskLen = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) + (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) + (MCI_MSF_FRAME(lAddress)); /* ** Now, determine the absolute start position of the sentinel ** track. That is, the special track that marks the end of the ** disk. */ lAddress = lStartPos + lDiskLen; TocPtr->TrackData[i].TrackNumber = 0; TocPtr->TrackData[i].Address = MCI_MAKE_MSF((lAddress / FRAMES_PER_MINUTE), (lAddress % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND, (lAddress % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND); return (TocPtr->LastTrack != 0) ? ERROR_SUCCESS : MCIERR_INTERNAL; } /******************************Public*Routine******************************\ * StopCdrom * * This routine will stop a CDRom device that is playing. * * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD StopCdrom( MCIDEVICEID DevHandle ) { MCI_GENERIC_PARMS mciGen; ZeroMemory( &mciGen, sizeof(mciGen) ); return mciSendCommand( DevHandle, MCI_STOP, 0L, (DWORD_PTR)(LPVOID)&mciGen ); } /******************************Public*Routine******************************\ * PauseCdrom * * This routine will pause a CDRom device. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD PauseCdrom( MCIDEVICEID DevHandle ) { MCI_GENERIC_PARMS mciGen; ZeroMemory( &mciGen, sizeof(mciGen) ); return mciSendCommand( DevHandle, MCI_PAUSE, 0L, (DWORD_PTR)(LPVOID)&mciGen ); } /******************************Public*Routine******************************\ * ResumeCdrom * * This routine will resume a paused CDRom device. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD ResumeCdrom( MCIDEVICEID DevHandle, int cdrom ) { MCI_GENERIC_PARMS mciGen; DWORD dwRet; static int fCanResume = -1; ZeroMemory( &mciGen, sizeof(mciGen) ); switch (fCanResume) { case -1: dwRet = mciSendCommand( DevHandle, MCI_RESUME, MCI_TO, (DWORD_PTR)(LPVOID)&mciGen ); fCanResume = (dwRet == MMSYSERR_NOERROR ? 1 : 0); if (0 == fCanResume) { dwRet = (PlayCurrTrack( cdrom ) ? MMSYSERR_NOERROR : MCIERR_HARDWARE); } break; case 0: dwRet = (PlayCurrTrack( cdrom ) ? MMSYSERR_NOERROR : MCIERR_HARDWARE); break; case 1: dwRet = mciSendCommand( DevHandle, MCI_RESUME, MCI_TO, (DWORD_PTR)(LPVOID)&mciGen ); break; } return dwRet; } /******************************Public*Routine******************************\ * PlayCdrom * * This routine plays a CDRom device starting and ending at the MSF * positions specified in the structure passed in. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD PlayCdrom( MCIDEVICEID DevHandle, MCI_PLAY_PARMS *mciPlay ) { return mciSendCommand( DevHandle, MCI_PLAY, MCI_FROM | MCI_TO, (DWORD_PTR)(LPVOID)mciPlay ); } /******************************Public*Routine******************************\ * IsCdromTrackAudio * * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ BOOL IsCdromTrackAudio( CDHANDLE DevHandle, int iTrackNumber ) { MCI_STATUS_PARMS mciStatus; ZeroMemory( &mciStatus, sizeof(mciStatus) ); mciStatus.dwItem = MCI_CDA_STATUS_TYPE_TRACK; mciStatus.dwTrack = iTrackNumber + 1; mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD_PTR)(LPVOID)&mciStatus); return mciStatus.dwReturn == (DWORD)MCI_CDA_TRACK_AUDIO; } /******************************Public*Routine******************************\ * GetCdromCurrentPosition * * Gets the current ABSOLUTE position of the specified cdrom device. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD GetCdromCurrentPosition( CDHANDLE DevHandle, DWORD *lpdwPosition ) { MCI_STATUS_PARMS mciStatus; DWORD dwErr; ZeroMemory( &mciStatus, sizeof(mciStatus) ); mciStatus.dwItem = MCI_STATUS_POSITION; dwErr = mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus ); *lpdwPosition = (long)mciStatus.dwReturn; return dwErr; } /******************************Public*Routine******************************\ * GetCdromMode * * Gets the current mode of the cdrom. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD GetCdromMode( MCIDEVICEID DevHandle ) { MCI_STATUS_PARMS mciStatus; ZeroMemory( &mciStatus, sizeof(mciStatus) ); mciStatus.dwItem = MCI_STATUS_MODE; mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus ); return (DWORD)mciStatus.dwReturn; } /******************************Public*Routine******************************\ * GetCdromCurrentTrack * * Gets the current track of the cdrom. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD GetCdromCurrentTrack( MCIDEVICEID DevHandle ) { MCI_STATUS_PARMS mciStatus; ZeroMemory( &mciStatus, sizeof(mciStatus) ); mciStatus.dwItem = MCI_STATUS_CURRENT_TRACK; mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus ); return (DWORD)mciStatus.dwReturn; } /******************************Public*Routine******************************\ * SeekCdrom * * This routine seek to an MSF address on the audio CD and enters * a hold (paused) state. * * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD SeekCdrom( MCIDEVICEID DevHandle, MCI_SEEK_PARMS *mciSeek ) { return mciSendCommand( DevHandle, MCI_SEEK, MCI_TO, (DWORD_PTR)(LPVOID)mciSeek ); } /******************************Public*Routine******************************\ * EjectCdrom * * This routine will eject a disc from a CDRom device or close the tray if * it is open. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD EjectCdrom( MCIDEVICEID DevHandle ) { MCI_SET_PARMS mciSet; DWORD mmr = ERROR_SUCCESS; ZeroMemory( &mciSet, sizeof(mciSet) ); if ((GetCdromMode(DevHandle) == (DWORD)MCI_MODE_OPEN) && g_fCDOpen) { mmr = mciSendCommand( DevHandle, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD_PTR)(LPVOID)&mciSet ); if (mmr == ERROR_SUCCESS) { g_fCDOpen = FALSE; } } else { mmr = mciSendCommand( DevHandle, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD_PTR)(LPVOID)&mciSet ); if (mmr == ERROR_SUCCESS) { g_fCDOpen = TRUE; } } return (mmr); } /******************************Public*Routine******************************\ * TestUnitReadyCdrom * * This routine will retrieve the status of the CDRom device. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD TestUnitReadyCdrom( MCIDEVICEID DevHandle ) { MCI_STATUS_PARMS mciStatus; ZeroMemory( &mciStatus, sizeof(mciStatus) ); mciStatus.dwItem = MCI_STATUS_MEDIA_PRESENT; if ( mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus ) == MMSYSERR_NOERROR ) { return mciStatus.dwReturn ? ERROR_SUCCESS : ERROR_NOT_READY; } return ERROR_NOT_READY; } /******************************Public*Routine******************************\ * StatusTrackPosCdrom * * This routine will retrieve the * status, current track, and current position of the CDRom device. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ DWORD StatusTrackPosCdrom( MCIDEVICEID DevHandle, DWORD * pStatus, DWORD * pTrack, DWORD * pPos ) { DWORD dwErr; MCI_STATUS_PARMS mciStatus; PSTATUSTRACKPOS pSTP = NULL; STATUSTRACKPOS stp; ZeroMemory( &mciStatus, sizeof(mciStatus) ); // Note: This is a non-standard MCI call (I.E. HACK!) // the only reason for this behavior is it reduces // the number of IOCTL's per 1/2 second on the HeartBeat // thread for updating the timer display from ~15 to only // ~1 on average. Resulting in a major reduction in // system traffic on the SCSI or IDE bus. // Note: we are passing down a structre to MCICDA containing // the position, track, and status values which it will // fill in for us and return. mciStatus.dwItem = MCI_STATUS_TRACK_POS; mciStatus.dwReturn = (DWORD_PTR)&stp; dwErr = mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus ); if (dwErr == MMSYSERR_NOERROR) { pSTP = (PSTATUSTRACKPOS)mciStatus.dwReturn; if (pSTP) { if (pStatus) *pStatus = pSTP->dwStatus; if (pTrack) *pTrack = pSTP->dwTrack; if (pPos) *pPos = pSTP->dwDiscTime; pSTP = NULL; } } return dwErr; } // End StatusTrackPosCdrom #ifdef __cplusplus }; #endif