420 lines
10 KiB
C++
420 lines
10 KiB
C++
|
/******************************Module*Header*******************************\
|
||
|
* Module Name: scan.c
|
||
|
*
|
||
|
* Code for scanning the available CD Rom devices.
|
||
|
*
|
||
|
*
|
||
|
* Created: 02-11-93
|
||
|
* Author: Stephen Estrop [StephenE]
|
||
|
*
|
||
|
* Copyright (c) 1993 Microsoft Corporation
|
||
|
\**************************************************************************/
|
||
|
#pragma warning( once : 4201 4214 )
|
||
|
|
||
|
#define NOOLE
|
||
|
|
||
|
#include <windows.h> /* required for all Windows applications */
|
||
|
#include <windowsx.h>
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <tchar.h> /* contains portable ascii/unicode macros */
|
||
|
|
||
|
#include "playres.h"
|
||
|
#include "cdplayer.h"
|
||
|
#include "cdapi.h"
|
||
|
#include "scan.h"
|
||
|
#include "trklst.h"
|
||
|
#include "database.h"
|
||
|
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* ScanForCdromDevices
|
||
|
*
|
||
|
* Returns the number of CD-ROM devices installed in the system.
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - StephenE - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
int
|
||
|
ScanForCdromDevices(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
DWORD dwDrives;
|
||
|
TCHAR chDrive[] = TEXT("A:\\");
|
||
|
int iNumDrives;
|
||
|
|
||
|
iNumDrives = 0;
|
||
|
|
||
|
for (dwDrives = GetLogicalDrives(); dwDrives != 0; dwDrives >>= 1 ) {
|
||
|
|
||
|
/*
|
||
|
** Is there a logical drive ??
|
||
|
*/
|
||
|
if (dwDrives & 1) {
|
||
|
|
||
|
if ( GetDriveType(chDrive) == DRIVE_CDROM ) {
|
||
|
|
||
|
g_Devices[iNumDrives] = (CDROM*)AllocMemory( sizeof(CDROM) );
|
||
|
|
||
|
g_Devices[iNumDrives]->drive = chDrive[0];
|
||
|
g_Devices[iNumDrives]->State = CD_BEING_SCANNED;
|
||
|
|
||
|
iNumDrives++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Go look at the next drive
|
||
|
*/
|
||
|
chDrive[0] = chDrive[0] + 1;
|
||
|
}
|
||
|
|
||
|
return iNumDrives;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* RescanDevice
|
||
|
*
|
||
|
*
|
||
|
* This routine is called to scan the disc in a given cdrom by
|
||
|
* reading its table of contents. If the cdrom is playing the user is
|
||
|
* notified that the music will stop.
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - StephenE - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
void RescanDevice(
|
||
|
HWND hwndNotify,
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
TOC_THREAD_PARMS *ptoc;
|
||
|
HWND hwndButton;
|
||
|
int iMsgBoxRtn;
|
||
|
|
||
|
if ( g_Devices[cdrom]->State & CD_PLAYING ) {
|
||
|
|
||
|
TCHAR s1[256];
|
||
|
TCHAR s2[256];
|
||
|
|
||
|
_tcscpy( s1, IdStr( STR_CANCEL_PLAY ) );
|
||
|
_tcscpy( s2, IdStr( STR_RESCAN ) );
|
||
|
|
||
|
iMsgBoxRtn = MessageBox( g_hwndApp, s1, s2,
|
||
|
MB_APPLMODAL | MB_DEFBUTTON1 |
|
||
|
MB_ICONQUESTION | MB_YESNO);
|
||
|
|
||
|
if ( iMsgBoxRtn == IDYES ) {
|
||
|
|
||
|
hwndButton = g_hwndControls[INDEX(IDM_PLAYBAR_STOP)];
|
||
|
|
||
|
SendMessage( hwndButton, WM_LBUTTONDOWN, 0, 0L );
|
||
|
SendMessage( hwndButton, WM_LBUTTONUP, 0, 0L );
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Attempt to read table of contents of disc in this drive. We
|
||
|
** now spawn off a separate thread to do this. Note that the child
|
||
|
** thread frees the storage allocated below.
|
||
|
*/
|
||
|
ptoc = (TOC_THREAD_PARMS*)AllocMemory( sizeof(TOC_THREAD_PARMS) );
|
||
|
ptoc->hwndNotify = hwndNotify;
|
||
|
ptoc->cdrom = cdrom;
|
||
|
ReadTableOfContents( ptoc );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* ReadTableofContents
|
||
|
*
|
||
|
* This function reads in the table of contents (TOC) for the specified cdrom.
|
||
|
* All TOC's are read on a worker thread. The hi-word of thread_info variable
|
||
|
* is a boolean that states if the display should been updated after the TOC
|
||
|
* has been reads. The lo-word of thread_info is the id of the cdrom device
|
||
|
* to be read.
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - StephenE - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
void
|
||
|
ReadTableOfContents(
|
||
|
TOC_THREAD_PARMS *ptoc
|
||
|
)
|
||
|
{
|
||
|
DWORD dwThreadId;
|
||
|
int cdrom;
|
||
|
|
||
|
cdrom = ptoc->cdrom;
|
||
|
g_Devices[ cdrom ]->fIsTocValid = FALSE;
|
||
|
g_Devices[cdrom]->fShowLeadIn = FALSE;
|
||
|
g_Devices[cdrom]->fProcessingLeadIn = FALSE;
|
||
|
|
||
|
if (g_Devices[ cdrom ]->hThreadToc != NULL) {
|
||
|
|
||
|
/*
|
||
|
** We have a thread TOC handle see if the thread is
|
||
|
** still running. If so just return, otherwise
|
||
|
*/
|
||
|
switch ( WaitForSingleObject(g_Devices[ cdrom ]->hThreadToc, 0L) ) {
|
||
|
|
||
|
/*
|
||
|
** Thread has finished to continue
|
||
|
*/
|
||
|
case WAIT_OBJECT_0:
|
||
|
break;
|
||
|
|
||
|
/*
|
||
|
** The thread is still running so just return
|
||
|
*/
|
||
|
case WAIT_TIMEOUT:
|
||
|
default:
|
||
|
{
|
||
|
LocalFree( ptoc );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CloseHandle( g_Devices[ cdrom ]->hThreadToc );
|
||
|
}
|
||
|
|
||
|
g_Devices[ cdrom ]->hThreadToc = CreateThread(
|
||
|
NULL, 0L, (LPTHREAD_START_ROUTINE)TableOfContentsThread,
|
||
|
(LPVOID)ptoc, 0L, &dwThreadId );
|
||
|
|
||
|
/*
|
||
|
** For now I will kill the app if I cannot create the
|
||
|
** ReadTableOfContents thread. This is probably a bit
|
||
|
** harsh.
|
||
|
*/
|
||
|
|
||
|
if (g_Devices[ cdrom ]->hThreadToc == NULL) {
|
||
|
FatalApplicationError( STR_NO_RES, GetLastError() );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* TableOfContentsThread
|
||
|
*
|
||
|
* This is the worker thread that reads the table of contents for the
|
||
|
* specified cdrom.
|
||
|
*
|
||
|
* Before the thread exits we post a message to the UI threads main window to
|
||
|
* notify it that the TOC for this cdrom has been updated. It then examines the
|
||
|
* database to determine if this cdrom is known and updates the screen ccordingly.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - StephenE - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
void
|
||
|
TableOfContentsThread(
|
||
|
TOC_THREAD_PARMS *ptoc
|
||
|
)
|
||
|
{
|
||
|
DWORD status = 0;
|
||
|
UCHAR num, numaudio;
|
||
|
int cdrom;
|
||
|
HWND hwndNotify;
|
||
|
|
||
|
// This serializes access to this function
|
||
|
// between multiple threads and the CDPlayer_OnTocRead
|
||
|
// function on the main thread.
|
||
|
// This prevents resource contention on CDROM Multi-changers
|
||
|
EnterCriticalSection (&g_csTOCSerialize);
|
||
|
|
||
|
cdrom = ptoc->cdrom;
|
||
|
hwndNotify = ptoc->hwndNotify;
|
||
|
|
||
|
LocalFree( ptoc );
|
||
|
|
||
|
/*
|
||
|
** Try to read the TOC from the drive.
|
||
|
*/
|
||
|
|
||
|
#ifdef USE_IOCTLS
|
||
|
|
||
|
status = GetCdromTOC( g_Devices[cdrom]->hCd, &(g_Devices[cdrom]->toc) );
|
||
|
num = g_Devices[cdrom]->toc.LastTrack - g_Devices[cdrom]->toc.FirstTrack+1;
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
numaudio = 0;
|
||
|
|
||
|
/*
|
||
|
** Look for audio tracks...
|
||
|
*/
|
||
|
for( i = 0; i < num; i++ ) {
|
||
|
|
||
|
if ( (g_Devices[cdrom]->toc.TrackData[i].Control &
|
||
|
TRACK_TYPE_MASK ) == AUDIO_TRACK ) {
|
||
|
|
||
|
numaudio++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Need to check if we got data tracks or audio
|
||
|
** tracks back...if there is a mix, strip out
|
||
|
** the data tracks...
|
||
|
*/
|
||
|
if (status == ERROR_SUCCESS) {
|
||
|
|
||
|
|
||
|
/*
|
||
|
** If there aren't any audio tracks, then we (most likely)
|
||
|
** have a data CD loaded.
|
||
|
*/
|
||
|
|
||
|
if (numaudio == 0) {
|
||
|
|
||
|
status == ERROR_UNRECOGNIZED_MEDIA;
|
||
|
g_Devices[cdrom]->State = CD_DATA_CD_LOADED | CD_STOPPED;
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
g_Devices[cdrom]->State = CD_LOADED | CD_STOPPED;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
g_Devices[cdrom]->State = CD_NO_CD | CD_STOPPED;
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
{
|
||
|
MCIDEVICEID wDeviceID;
|
||
|
DWORD dwCDPlayerMode = 0L;
|
||
|
|
||
|
OSVERSIONINFO os;
|
||
|
os.dwOSVersionInfoSize = sizeof(os);
|
||
|
GetVersionEx(&os);
|
||
|
if (os.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
||
|
{
|
||
|
if (g_Devices[cdrom]->hCd == 0) {
|
||
|
g_Devices[cdrom]->hCd = OpenCdRom( g_Devices[cdrom]->drive,
|
||
|
&status );
|
||
|
}
|
||
|
wDeviceID = g_Devices[cdrom]->hCd;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wDeviceID = OpenCdRom( g_Devices[cdrom]->drive, &status );
|
||
|
}
|
||
|
|
||
|
if ( wDeviceID != 0 ) {
|
||
|
|
||
|
int i;
|
||
|
|
||
|
numaudio = 0;
|
||
|
status = GetCdromTOC( wDeviceID, &(g_Devices[cdrom]->toc) );
|
||
|
|
||
|
/*
|
||
|
** Need to check if we got data tracks or audio
|
||
|
** tracks back...if there is a mix, strip out
|
||
|
** the data tracks...
|
||
|
*/
|
||
|
if ( status == ERROR_SUCCESS) {
|
||
|
num = g_Devices[cdrom]->toc.LastTrack -
|
||
|
g_Devices[cdrom]->toc.FirstTrack + 1;
|
||
|
|
||
|
for( i = 0; i < num; i++ ) {
|
||
|
|
||
|
if ( IsCdromTrackAudio(wDeviceID, i) ) {
|
||
|
|
||
|
numaudio++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dwCDPlayerMode = GetCdromMode( wDeviceID );
|
||
|
|
||
|
OSVERSIONINFO os;
|
||
|
os.dwOSVersionInfoSize = sizeof(os);
|
||
|
GetVersionEx(&os);
|
||
|
if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||
|
{
|
||
|
CloseCdRom( wDeviceID );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Need to check if we got data tracks or audio
|
||
|
** tracks back...if there is a mix, strip out
|
||
|
** the data tracks...
|
||
|
*/
|
||
|
if (status == ERROR_SUCCESS) {
|
||
|
|
||
|
/*
|
||
|
** If there aren't any audio tracks, then we (most likely)
|
||
|
** have a data CD loaded.
|
||
|
*/
|
||
|
|
||
|
if (numaudio == 0) {
|
||
|
|
||
|
g_Devices[cdrom]->State = CD_DATA_CD_LOADED | CD_STOPPED;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
g_Devices[cdrom]->State = CD_LOADED;
|
||
|
|
||
|
switch (dwCDPlayerMode) {
|
||
|
|
||
|
case MCI_MODE_PAUSE:
|
||
|
g_Devices[cdrom]->State |= CD_PAUSED;
|
||
|
break;
|
||
|
|
||
|
case MCI_MODE_PLAY:
|
||
|
g_Devices[cdrom]->State |= CD_PLAYING;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
g_Devices[cdrom]->State |= CD_STOPPED;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
if (status == (DWORD)MCIERR_MUST_USE_SHAREABLE) {
|
||
|
g_Devices[cdrom]->State = CD_IN_USE;
|
||
|
}
|
||
|
|
||
|
if (g_Devices[cdrom]->State != CD_IN_USE) {
|
||
|
g_Devices[cdrom]->State = CD_NO_CD | CD_STOPPED;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
** Notify the UI thread that a TOC has been read and then terminate the
|
||
|
** thread.
|
||
|
*/
|
||
|
|
||
|
PostMessage( hwndNotify, WM_NOTIFY_TOC_READ,
|
||
|
(WPARAM)cdrom, (LPARAM)numaudio );
|
||
|
|
||
|
LeaveCriticalSection (&g_csTOCSerialize);
|
||
|
|
||
|
ExitThread( 1L );
|
||
|
}
|