3875 lines
88 KiB
C++
3875 lines
88 KiB
C++
/******************************Module*Header*******************************\
|
||
* Module Name: cdplayer.c
|
||
*
|
||
* CD Playing application
|
||
*
|
||
*
|
||
* Created: 02-11-93
|
||
* Author: Stephen Estrop [StephenE]
|
||
*
|
||
* Copyright (c) 1993 - 1995 Microsoft Corporation. All rights reserved.
|
||
\**************************************************************************/
|
||
#pragma warning( once : 4201 4214 )
|
||
|
||
#include <windows.h> /* required for all Windows applications */
|
||
#include <shellapi.h>
|
||
#include <windowsx.h>
|
||
|
||
#include <ole2.h>
|
||
#include <shlobj.h>
|
||
#include <dbt.h>
|
||
|
||
#include "..\main\mmfw.h"
|
||
#include "..\main\resource.h"
|
||
#include "..\main\mmenu.h"
|
||
#include "..\cdopt\cdopt.h"
|
||
#include "..\cdnet\cdnet.h"
|
||
|
||
#define NOMENUHELP
|
||
#define NOBTNLIST
|
||
#define NOTRACKBAR
|
||
#define NODRAGLIST
|
||
#define NOUPDOWN
|
||
#include <commctrl.h> /* want toolbar and status bar */
|
||
|
||
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include <tchar.h> /* contains portable ascii/unicode macros */
|
||
#include <stdarg.h>
|
||
#include <stdlib.h>
|
||
|
||
#define GLOBAL /* This allocates storage for the public globals */
|
||
|
||
|
||
#include "playres.h"
|
||
#include "cdplayer.h"
|
||
#include "ledwnd.h"
|
||
#include "cdapi.h"
|
||
#include "scan.h"
|
||
#include "trklst.h"
|
||
#include "database.h"
|
||
#include "commands.h"
|
||
#include "literals.h"
|
||
|
||
//#ifndef WM_CDPLAYER_COPYDATA
|
||
#define WM_CDPLAYER_COPYDATA (WM_USER+0x100)
|
||
//#endif
|
||
|
||
IMMFWNotifySink* g_pSink;
|
||
ATOM g_atomCDClass = NULL;
|
||
extern HINSTANCE g_hInst;
|
||
|
||
void GetTOC(int cdrom, TCHAR* szNetQuery);
|
||
|
||
/* -------------------------------------------------------------------------
|
||
** Private functions
|
||
** -------------------------------------------------------------------------
|
||
*/
|
||
int
|
||
CopyWord(
|
||
TCHAR *szWord,
|
||
TCHAR *szSource
|
||
);
|
||
|
||
void
|
||
AppendTrackToPlayList(
|
||
PTRACK_PLAY pHead,
|
||
PTRACK_PLAY pInsert
|
||
);
|
||
|
||
BOOL
|
||
IsTrackFileNameValid(
|
||
LPTSTR lpstFileName,
|
||
int *piCdRomIndex,
|
||
int *piTrackIndex,
|
||
BOOL fScanningTracks,
|
||
BOOL fQuiet
|
||
);
|
||
|
||
TCHAR *
|
||
ParseTrackList(
|
||
TCHAR *szTrackList,
|
||
int *piCdRomIndex
|
||
);
|
||
|
||
int
|
||
ParseCommandLine(
|
||
LPTSTR lpstr,
|
||
int *piTrackToSeekTo,
|
||
BOOL fQuiet
|
||
);
|
||
|
||
void
|
||
HandlePassedCommandLine(
|
||
LPTSTR lpCmdLine,
|
||
BOOL fCheckCDRom
|
||
);
|
||
|
||
int
|
||
FindMostSuitableDrive(
|
||
void
|
||
);
|
||
|
||
void
|
||
AskUserToInsertCorrectDisc(
|
||
DWORD dwID
|
||
);
|
||
|
||
#ifndef USE_IOCTLS
|
||
BOOL CheckMCICDA (TCHAR chDrive);
|
||
#endif // ! USE_IOCTLS
|
||
|
||
BOOL
|
||
CDPlay_CopyData(
|
||
HWND hwnd,
|
||
PCOPYDATASTRUCT lpcpds
|
||
);
|
||
|
||
/* -------------------------------------------------------------------------
|
||
** Private Globals
|
||
** -------------------------------------------------------------------------
|
||
*/
|
||
|
||
HBRUSH g_hBrushBkgd;
|
||
|
||
TCHAR g_szTimeSep[10];
|
||
int g_AcceleratorCount;
|
||
BOOL g_fInCopyData = FALSE;
|
||
|
||
HCURSOR g_hcurs = NULL;
|
||
|
||
//---------------------------------------------------------------------------
|
||
// Stuff required to make drag/dropping of a shortcut file work on Chicago
|
||
//---------------------------------------------------------------------------
|
||
BOOL
|
||
ResolveLink(
|
||
TCHAR * szFileName
|
||
);
|
||
|
||
BOOL g_fOleInitialized = FALSE;
|
||
|
||
|
||
/*
|
||
** these values are defined by the UI gods...
|
||
*/
|
||
const int dxButton = 24;
|
||
const int dyButton = 22;
|
||
const int dxBitmap = 16;
|
||
const int dyBitmap = 16;
|
||
const int xFirstButton = 8;
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* WinMain
|
||
*
|
||
*
|
||
* Windows recognizes this function by name as the initial entry point
|
||
* for the program. This function calls the application initialization
|
||
* routine, if no other instance of the program is running, and always
|
||
* calls the instance initialization routine. It then executes a message
|
||
* retrieval and dispatch loop that is the top-level control structure
|
||
* for the remainder of execution. The loop is terminated when a WM_QUIT
|
||
* message is received, at which time this function exits the application
|
||
* instance by returning the value passed by PostQuitMessage().
|
||
*
|
||
* If this function must abort before entering the message loop, it
|
||
* returns the conventional value NULL.
|
||
*
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
HWND PASCAL
|
||
WinFake(
|
||
HINSTANCE hInstance,
|
||
HINSTANCE hPrevInstance,
|
||
LPSTR lpCmdLine,
|
||
int nCmdShow,
|
||
HWND hwndMain,
|
||
IMMFWNotifySink* pSink
|
||
)
|
||
{
|
||
g_pSink = pSink;
|
||
|
||
g_fBlockNetPrompt = FALSE;
|
||
|
||
g_fSelectedOrder = TRUE;
|
||
g_fIntroPlay = FALSE;
|
||
g_fContinuous = FALSE;
|
||
g_fRepeatSingle = FALSE;
|
||
|
||
#ifdef DBG
|
||
/*
|
||
** This removes the Gdi batch feature. It ensures that the screen
|
||
** is updated after every gdi call - very useful for debugging.
|
||
*/
|
||
GdiSetBatchLimit(1);
|
||
#endif
|
||
|
||
/*
|
||
** Save the instance handle in static variable, which will be used in
|
||
** many subsequence calls from this application to Windows.
|
||
*/
|
||
g_hInst = hInstance;
|
||
g_lpCmdLine = lpCmdLine;
|
||
|
||
InitializeCriticalSection (&g_csTOCSerialize);
|
||
|
||
/*
|
||
** Initialize the cdplayer application.
|
||
*/
|
||
CdPlayerStartUp(hwndMain);
|
||
|
||
return g_hwndApp;
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* InitInstance
|
||
*
|
||
*
|
||
* This function is called at initialization time for every instance of
|
||
* this application. This function performs initialization tasks that
|
||
* cannot be shared by multiple instances.
|
||
*
|
||
* In this case, we save the instance handle in a static variable and
|
||
* create and display the main program window.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
InitInstance(
|
||
HANDLE hInstance,
|
||
HWND hwndMain
|
||
)
|
||
{
|
||
HWND hwnd;
|
||
|
||
/*
|
||
** Load in some strings
|
||
*/
|
||
|
||
_tcscpy( g_szArtistTxt, IdStr( STR_HDR_ARTIST ) );
|
||
_tcscpy( g_szTitleTxt, IdStr( STR_HDR_TITLE ) );
|
||
_tcscpy( g_szUnknownTxt, IdStr( STR_UNKNOWN ) );
|
||
_tcscpy( g_szTrackTxt, IdStr( STR_HDR_TRACK ) );
|
||
|
||
g_szTimeSep[0] = TEXT(':');
|
||
g_szTimeSep[1] = g_chNULL;
|
||
GetLocaleInfo( GetUserDefaultLCID(), LOCALE_STIME, g_szTimeSep, 10 );
|
||
|
||
|
||
/*
|
||
** Initialize the my classes. We do this here because the dialog
|
||
** that we are about to create contains two windows on my class.
|
||
** The dialog would fail to be created if the classes was not registered.
|
||
*/
|
||
g_fDisplayT = TRUE;
|
||
InitLEDClass( g_hInst );
|
||
Init_SJE_TextClass( g_hInst );
|
||
|
||
WNDCLASS cls;
|
||
cls.lpszClassName = g_szSJE_CdPlayerClass;
|
||
cls.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
|
||
cls.hIcon = NULL;
|
||
cls.lpszMenuName = NULL;
|
||
cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
||
cls.hInstance = (HINSTANCE)hInstance;
|
||
cls.style = CS_DBLCLKS;
|
||
cls.lpfnWndProc = DefDlgProc;
|
||
cls.cbClsExtra = 0;
|
||
cls.cbWndExtra = DLGWINDOWEXTRA;
|
||
if ( !RegisterClass(&cls) )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
g_hcurs = LoadCursor(g_hInst,MAKEINTRESOURCE(IDC_CURSOR_HAND));
|
||
|
||
/*
|
||
** Create a main window for this application instance.
|
||
*/
|
||
hwnd = CreateDialog( g_hInst, MAKEINTRESOURCE(IDR_CDPLAYER),
|
||
hwndMain, MyMainWndProc );
|
||
|
||
|
||
/*
|
||
** If window could not be created, return "failure"
|
||
*/
|
||
if ( !hwnd )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
g_hwndApp = hwnd;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CdPlayerStartUp
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-95 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CdPlayerStartUp(
|
||
HWND hwndMain
|
||
)
|
||
{
|
||
/*
|
||
** Reseed random generator
|
||
*/
|
||
srand( GetTickCount() );
|
||
|
||
|
||
/*
|
||
** Set error mode popups for critical errors (like
|
||
** no disc in drive) OFF.
|
||
*/
|
||
SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
|
||
|
||
|
||
/*
|
||
** Scan device chain for CDROM devices... Terminate if none found.
|
||
*/
|
||
g_NumCdDevices = ScanForCdromDevices( );
|
||
|
||
if ( g_NumCdDevices == 0 )
|
||
{
|
||
LPTSTR lpstrTitle;
|
||
LPTSTR lpstrText;
|
||
|
||
lpstrTitle = (TCHAR*)AllocMemory( STR_MAX_STRING_LEN * sizeof(TCHAR) );
|
||
lpstrText = (TCHAR*)AllocMemory( STR_MAX_STRING_LEN * sizeof(TCHAR) );
|
||
|
||
_tcscpy( lpstrText, IdStr(STR_NO_CDROMS) );
|
||
_tcscpy( lpstrTitle, IdStr(STR_CDPLAYER) );
|
||
|
||
MessageBox( NULL, lpstrText, lpstrTitle,
|
||
MB_APPLMODAL | MB_ICONINFORMATION |
|
||
MB_OK | MB_SETFOREGROUND );
|
||
|
||
LocalFree( (HLOCAL)lpstrText );
|
||
LocalFree( (HLOCAL)lpstrTitle );
|
||
|
||
ExitProcess( (UINT)-1 );
|
||
}
|
||
|
||
#ifndef USE_IOCTLS
|
||
// Make sure we have a functional MCI (CD Audio)
|
||
OSVERSIONINFO os;
|
||
os.dwOSVersionInfoSize = sizeof(os);
|
||
GetVersionEx(&os);
|
||
if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||
{
|
||
if (! CheckMCICDA (g_Devices[0]->drive))
|
||
{
|
||
ExitProcess( (UINT)-1 );
|
||
}
|
||
}
|
||
#endif // ! USE_IOCTLS
|
||
|
||
/*
|
||
** Perform initializations that apply to a specific instance
|
||
** This function actually creates the CdPlayer window. (Note that it is
|
||
** not visible yet). If we get here we know that there is a least one
|
||
** cdrom device detected which may have a music cd in it. If it does
|
||
** contain a music cdrom the table of contents will have been read and
|
||
** cd database queryed to determine if the music cd is known. Therefore
|
||
** on the WM_INITDIALOG message we should update the "Artist", "Title" and
|
||
** "Track" fields of the track info display and adjust the enable state
|
||
** of the play buttons.
|
||
*/
|
||
|
||
if ( !InitInstance( g_hInst, hwndMain ) )
|
||
{
|
||
FatalApplicationError( STR_TERMINATE );
|
||
}
|
||
|
||
|
||
/*
|
||
** Restore ourselves from the ini file
|
||
*/
|
||
ReadSettings(NULL);
|
||
|
||
/*
|
||
** Scan command the command line. If we were given any valid commandline
|
||
** args we have to adjust the nCmdShow parameter. (ie. start minimized
|
||
** if the user just wants us to play a certain track. ScanCommandLine can
|
||
** overide the default playlist for all the cd-rom devices installed. It
|
||
** modifies the global flag g_fPlay and returns the index of the first
|
||
** CD-Rom that should be played.
|
||
*/
|
||
g_CurrCdrom = g_LastCdrom = 0;
|
||
}
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CompleteCdPlayerStartUp
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-95 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CompleteCdPlayerStartUp(
|
||
void
|
||
)
|
||
{
|
||
int iTrackToSeekTo = -1;
|
||
int i;
|
||
|
||
g_fStartedInTray = FALSE;
|
||
|
||
/*
|
||
** Scan command the command line. If we were given any valid
|
||
** commandline args we have to adjust the nCmdShow parameter. (ie.
|
||
** start minimized if the user just wants us to play a certain
|
||
** track. ScanCommandLine can overide the default playlist for all
|
||
** the cd-rom devices installed. It modifies the global flag
|
||
** g_fPlay and returns the index of the first CD-Rom that should be
|
||
** played.
|
||
**
|
||
*/
|
||
g_CurrCdrom = g_LastCdrom = ParseCommandLine( GetCommandLine(),
|
||
&iTrackToSeekTo, FALSE );
|
||
/*
|
||
** If the message box prompting the user to insert the correct cd disc in
|
||
** the drive was displayed, ParseCommandLine will return -1, in which case
|
||
** find the most suitable drive, also make sure that we don't come up
|
||
** playing.
|
||
*/
|
||
if (g_LastCdrom == -1)
|
||
{
|
||
g_fPlay = FALSE;
|
||
g_CurrCdrom = g_LastCdrom = FindMostSuitableDrive();
|
||
}
|
||
|
||
for ( i = 0; i < g_NumCdDevices; i++) {
|
||
|
||
TimeAdjustInitialize( i );
|
||
}
|
||
|
||
/*
|
||
** All the rescan threads are either dead or in the act of dying.
|
||
** It is now safe to initalize the time information for each
|
||
** cdrom drive.
|
||
*/
|
||
if ( iTrackToSeekTo != -1 ) {
|
||
|
||
PTRACK_PLAY tr;
|
||
|
||
tr = PLAYLIST( g_CurrCdrom );
|
||
if ( tr != NULL ) {
|
||
|
||
for( i = 0; i < iTrackToSeekTo; i++, tr = tr->nextplay );
|
||
|
||
TimeAdjustSkipToTrack( g_CurrCdrom, tr );
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
** if we are in random mode, then we need to shuffle the play lists.
|
||
*/
|
||
|
||
if (!g_fSelectedOrder)
|
||
{
|
||
ComputeAndUseShufflePlayLists();
|
||
}
|
||
SetPlayButtonsEnableState();
|
||
|
||
|
||
/*
|
||
** Start the heart beat time. This timer is responsible for:
|
||
** 1. detecting new or ejected cdroms.
|
||
** 2. flashing the LED display if we are in paused mode.
|
||
** 3. Incrementing the LED display if we are in play mode.
|
||
*/
|
||
UINT_PTR timerid = SetTimer( g_hwndApp, HEARTBEAT_TIMER_ID, HEARTBEAT_TIMER_RATE,
|
||
(TIMERPROC)HeartBeatTimerProc );
|
||
|
||
if (!g_fPlay)
|
||
{
|
||
//"play" wasn't on the command line, but maybe the user wants it on startup anyway
|
||
HKEY hKey;
|
||
LONG lRet;
|
||
|
||
lRet = RegOpenKey( HKEY_CURRENT_USER, g_szRegistryKey, &hKey );
|
||
|
||
if ( (lRet == ERROR_SUCCESS) )
|
||
{
|
||
DWORD dwType, dwLen;
|
||
|
||
dwLen = sizeof( g_fPlay );
|
||
if ( ERROR_SUCCESS != RegQueryValueEx(hKey, g_szStartCDPlayingOnStart,
|
||
0L, &dwType, (LPBYTE)&g_fPlay,
|
||
&dwLen) )
|
||
{
|
||
g_fPlay = FALSE; //default to not playing
|
||
}
|
||
|
||
RegCloseKey(hKey);
|
||
}
|
||
}
|
||
|
||
//Don't start if player was started in tray mode.
|
||
//This prevents the user from getting an unexpected blast on boot.
|
||
if (( g_fPlay ) && (!g_fStartedInTray))
|
||
{
|
||
CdPlayerPlayCmd();
|
||
}
|
||
|
||
if (g_CurrCdrom != 0)
|
||
{
|
||
//didn't use the default player, so jump to the new one
|
||
MMONDISCCHANGED mmOnDisc;
|
||
mmOnDisc.nNewDisc = g_CurrCdrom;
|
||
mmOnDisc.fDisplayVolChange = FALSE;
|
||
g_pSink->OnEvent(MMEVENT_ONDISCCHANGED,&mmOnDisc);
|
||
}
|
||
|
||
if (g_Devices[g_CurrCdrom]->State & CD_LOADED)
|
||
{
|
||
//need to set track button on main ui
|
||
HWND hwndTrackButton = GetDlgItem(GetParent(g_hwndApp),IDB_TRACK);
|
||
if (hwndTrackButton)
|
||
{
|
||
EnableWindow(hwndTrackButton,TRUE);
|
||
}
|
||
}
|
||
|
||
//cd was already playing; let's update the main ui
|
||
if (g_Devices[g_CurrCdrom]->State & CD_PLAYING)
|
||
{
|
||
g_pSink->OnEvent(MMEVENT_ONPLAY,NULL);
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* MyMainWndProc
|
||
*
|
||
* Use the message crackers to dispatch the dialog messages to appropirate
|
||
* message handlers. The message crackers are portable between 16 and 32
|
||
* bit versions of Windows.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
INT_PTR CALLBACK
|
||
MyMainWndProc(
|
||
HWND hwnd,
|
||
UINT message,
|
||
WPARAM wParam,
|
||
LPARAM lParam
|
||
)
|
||
{
|
||
switch ( message ) {
|
||
|
||
HANDLE_MSG( hwnd, WM_INITDIALOG, CDPlay_OnInitDialog );
|
||
HANDLE_MSG( hwnd, WM_DRAWITEM, CDPlay_OnDrawItem );
|
||
HANDLE_MSG( hwnd, WM_COMMAND, CDPlay_OnCommand );
|
||
HANDLE_MSG( hwnd, WM_DESTROY, CDPlay_OnDestroy );
|
||
HANDLE_MSG( hwnd, WM_SIZE, CDPlay_OnSize );
|
||
HANDLE_MSG( hwnd, WM_ENDSESSION, CDPlay_OnEndSession );
|
||
HANDLE_MSG( hwnd, WM_WININICHANGE, CDPlay_OnWinIniChange );
|
||
HANDLE_MSG( hwnd, WM_CTLCOLORSTATIC, Common_OnCtlColor );
|
||
HANDLE_MSG( hwnd, WM_CTLCOLORDLG, Common_OnCtlColor );
|
||
HANDLE_MSG( hwnd, WM_MEASUREITEM, Common_OnMeasureItem );
|
||
HANDLE_MSG( hwnd, WM_NOTIFY, CDPlay_OnNotify );
|
||
|
||
HANDLE_MSG( hwnd, WM_DROPFILES, CDPlay_OnDropFiles );
|
||
|
||
case WM_DEVICECHANGE:
|
||
return CDPlay_OnDeviceChange (hwnd, wParam, lParam);
|
||
|
||
case WM_SETFOCUS :
|
||
{
|
||
//move focus to next window in tab order
|
||
HWND hwndNext = GetNextDlgTabItem(GetParent(hwnd),hwnd,FALSE);
|
||
|
||
//if the next window just lost focus, we need to go the other way
|
||
if (hwndNext == (HWND)wParam)
|
||
{
|
||
hwndNext = GetNextDlgTabItem(GetParent(hwnd),hwnd,TRUE);
|
||
}
|
||
|
||
SetFocus(hwndNext);
|
||
|
||
return 0;
|
||
}
|
||
break;
|
||
|
||
case WM_ERASEBKGND:
|
||
return 1;
|
||
|
||
case WM_CLOSE:
|
||
return CDPlay_OnClose(hwnd, FALSE);
|
||
|
||
case WM_COPYDATA:
|
||
return CDPlay_CopyData( hwnd, (PCOPYDATASTRUCT)lParam );
|
||
|
||
case WM_CDPLAYER_COPYDATA:
|
||
return CDPlay_OnCopyData( hwnd, (PCOPYDATASTRUCT)lParam );
|
||
|
||
case WM_NOTIFY_TOC_READ:
|
||
return CDPlay_OnTocRead( (int)wParam );
|
||
|
||
case WM_NOTIFY_FIRST_SCAN:
|
||
{
|
||
for ( int i = 0; i < g_NumCdDevices; i++ )
|
||
{
|
||
RescanDevice( hwnd, i );
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnInitDialog
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
CDPlay_OnInitDialog(
|
||
HWND hwnd,
|
||
HWND hwndFocus,
|
||
LPARAM lParam
|
||
)
|
||
{
|
||
int i;
|
||
|
||
g_hBrushBkgd = CreateSolidBrush( GetSysColor(COLOR_BTNFACE) );
|
||
|
||
EnumChildWindows( hwnd, ChildEnumProc, (LPARAM)hwnd );
|
||
|
||
DragAcceptFiles( hwnd, TRUE );
|
||
|
||
/*
|
||
** Initialize and read the TOC for all the detected CD-ROMS
|
||
*/
|
||
SetPlayButtonsEnableState();
|
||
|
||
for ( i = 0; i < g_NumCdDevices; i++ )
|
||
{
|
||
ASSERT(g_Devices[i]->State == CD_BEING_SCANNED);
|
||
ASSERT(g_Devices[i]->hCd == 0L);
|
||
|
||
TimeAdjustInitialize( i );
|
||
|
||
g_Devices[i]->State = CD_NO_CD;
|
||
}
|
||
|
||
PostMessage(hwnd,WM_NOTIFY_FIRST_SCAN,0,0);
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnWinIniChange
|
||
*
|
||
* Updates the time format separator and the LED display
|
||
*
|
||
* History:
|
||
* 29-09-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CDPlay_OnWinIniChange(
|
||
HWND hwnd,
|
||
LPCTSTR lpszSectionName
|
||
)
|
||
{
|
||
GetLocaleInfo( GetUserDefaultLCID(), LOCALE_STIME, g_szTimeSep, 10 );
|
||
UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_DISC_TIME | DISPLAY_UPD_TRACK_TIME );
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnDrawItem
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
CDPlay_OnDrawItem(
|
||
HWND hwnd,
|
||
const DRAWITEMSTRUCT *lpdis
|
||
)
|
||
{
|
||
if (lpdis->CtlType == ODT_MENU)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
int i;
|
||
|
||
i = INDEX(lpdis->CtlID);
|
||
|
||
switch (lpdis->CtlType) {
|
||
|
||
case ODT_BUTTON:
|
||
|
||
/*
|
||
** See if the fast foreward or backward buttons has been pressed or
|
||
** released. If so execute the seek command here. Do nothing on
|
||
** the WM_COMMAND message.
|
||
*/
|
||
if ( lpdis->CtlID == IDM_PLAYBAR_SKIPBACK
|
||
|| lpdis->CtlID == IDM_PLAYBAR_SKIPFORE ) {
|
||
|
||
if (lpdis->itemAction & ODA_SELECT ) {
|
||
|
||
g_AcceleratorCount = 0;
|
||
CdPlayerSeekCmd( hwnd, (lpdis->itemState & ODS_SELECTED),
|
||
lpdis->CtlID );
|
||
}
|
||
}
|
||
|
||
/*
|
||
** Now draw the button according to the buttons state information.
|
||
*/
|
||
|
||
/*
|
||
case ODT_COMBOBOX:
|
||
if (lpdis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) {
|
||
|
||
switch (lpdis->CtlID) {
|
||
|
||
case IDC_ARTIST_NAME:
|
||
DrawDriveItem( lpdis->hDC, &lpdis->rcItem,
|
||
lpdis->itemData,
|
||
(ODS_SELECTED & lpdis->itemState) );
|
||
break;
|
||
|
||
}
|
||
}
|
||
*/
|
||
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnCommand
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CDPlay_OnCommand(
|
||
HWND hwnd,
|
||
int id,
|
||
HWND hwndCtl,
|
||
UINT codeNotify
|
||
)
|
||
{
|
||
switch( id )
|
||
{
|
||
case IDM_NET_CD:
|
||
{
|
||
MMNET* pNet = (MMNET*)hwndCtl;
|
||
if (pNet->discid==0)
|
||
{
|
||
//if disc id is 0, then we want to manually get the info for the current cd
|
||
GetInternetDatabase(g_CurrCdrom,g_Devices[g_CurrCdrom]->CdInfo.Id,TRUE,TRUE,pNet->hwndCallback,NULL);
|
||
}
|
||
else if ((pNet->discid==-1) || (pNet->fForceNet))
|
||
{
|
||
//if disc id is -1, then we want to get just the batches
|
||
int cdrom = g_CurrCdrom;
|
||
|
||
if (pNet->fForceNet)
|
||
{
|
||
//try to find the correct cdrom for this guy
|
||
for(int i = 0; i < g_NumCdDevices; i++)
|
||
{
|
||
if (pNet->discid == g_Devices[i]->CdInfo.Id)
|
||
{
|
||
//if the id was found in the player, physically rescan it
|
||
pNet->pData2 = NULL;
|
||
cdrom = i;
|
||
break;
|
||
}
|
||
} //end for
|
||
} //end if force net
|
||
|
||
GetInternetDatabase(cdrom,pNet->fForceNet ? pNet->discid : 0,TRUE,TRUE,pNet->hwndCallback,pNet->pData2);
|
||
}
|
||
else
|
||
{
|
||
for(int i = 0; i < g_NumCdDevices; i++)
|
||
{
|
||
if (pNet->discid == g_Devices[i]->CdInfo.Id)
|
||
{
|
||
//don't hit the net, just scan the entry
|
||
GetInternetDatabase(i,g_Devices[i]->CdInfo.Id,FALSE,TRUE,pNet->hwndCallback,pNet->pData);
|
||
UpdateDisplay(DISPLAY_UPD_TITLE_NAME|DISPLAY_UPD_LED);
|
||
}
|
||
} //end for
|
||
}
|
||
|
||
}
|
||
break;
|
||
|
||
case IDM_OPTIONS_NORMAL :
|
||
{
|
||
//turn randomness off if it is on
|
||
if (!g_fSelectedOrder)
|
||
{
|
||
if ( LockALLTableOfContents() )
|
||
{
|
||
FlipBetweenShuffleAndOrder();
|
||
}
|
||
}
|
||
g_fRepeatSingle = FALSE;
|
||
g_fIntroPlay = FALSE;
|
||
g_fSelectedOrder = TRUE;
|
||
g_fContinuous = FALSE;
|
||
}
|
||
break;
|
||
|
||
case IDM_OPTIONS_RANDOM:
|
||
if ( LockALLTableOfContents() )
|
||
{
|
||
g_fSelectedOrder = FALSE;
|
||
ComputeAndUseShufflePlayLists();
|
||
g_fIntroPlay = FALSE;
|
||
g_fContinuous = TRUE;
|
||
g_fRepeatSingle = FALSE;
|
||
}
|
||
break;
|
||
|
||
//case IDM_OPTIONS_MULTI:
|
||
//g_fSingleDisk = !g_fSingleDisk;
|
||
//break;
|
||
|
||
case IDM_OPTIONS_REPEAT_SINGLE :
|
||
{
|
||
//turn randomness off if it is on
|
||
if (!g_fSelectedOrder)
|
||
{
|
||
if ( LockALLTableOfContents() )
|
||
{
|
||
FlipBetweenShuffleAndOrder();
|
||
}
|
||
}
|
||
g_fRepeatSingle = TRUE;
|
||
g_fIntroPlay = FALSE;
|
||
g_fSelectedOrder = TRUE;
|
||
g_fContinuous = FALSE;
|
||
}
|
||
break;
|
||
|
||
case IDM_OPTIONS_INTRO:
|
||
//turn randomness off if it is on
|
||
if (!g_fSelectedOrder)
|
||
{
|
||
if ( LockALLTableOfContents() )
|
||
{
|
||
FlipBetweenShuffleAndOrder();
|
||
}
|
||
}
|
||
g_fIntroPlay = TRUE;
|
||
g_fSelectedOrder = TRUE;
|
||
g_fContinuous = FALSE;
|
||
g_fRepeatSingle = FALSE;
|
||
break;
|
||
|
||
case IDM_OPTIONS_CONTINUOUS:
|
||
//turn randomness off if it is on
|
||
if (!g_fSelectedOrder)
|
||
{
|
||
if ( LockALLTableOfContents() )
|
||
{
|
||
FlipBetweenShuffleAndOrder();
|
||
}
|
||
}
|
||
g_fContinuous = TRUE;
|
||
g_fIntroPlay = FALSE;
|
||
g_fSelectedOrder = TRUE;
|
||
g_fRepeatSingle = FALSE;
|
||
break;
|
||
|
||
case IDM_TIME_REMAINING:
|
||
g_fDisplayT = TRUE;
|
||
g_fDisplayD = g_fDisplayTr = g_fDisplayDr = FALSE;
|
||
UpdateDisplay( DISPLAY_UPD_LED );
|
||
break;
|
||
|
||
case IDM_TRACK_REMAINING:
|
||
g_fDisplayTr = TRUE;
|
||
g_fDisplayD = g_fDisplayDr = g_fDisplayT = FALSE;
|
||
UpdateDisplay( DISPLAY_UPD_LED );
|
||
break;
|
||
|
||
case IDM_DISC_REMAINING:
|
||
g_fDisplayDr = TRUE;
|
||
g_fDisplayD = g_fDisplayTr = g_fDisplayT = FALSE;
|
||
UpdateDisplay( DISPLAY_UPD_LED );
|
||
break;
|
||
|
||
case IDM_PLAYBAR_EJECT:
|
||
CdPlayerEjectCmd();
|
||
break;
|
||
|
||
case IDM_PLAYBAR_PLAY:
|
||
/*
|
||
** If we currently in PLAY mode and the command came from
|
||
** a keyboard accelerator then assume that the user really
|
||
** means Pause. This is because the Ctrl-P key sequence
|
||
** is a toggle between Play and Paused. codeNotify is 1 when
|
||
** the WM_COMMAND message came from an accelerator and 0 when
|
||
** it cam from a menu.
|
||
*/
|
||
if ((g_State & CD_PLAYING) && (codeNotify == 1))
|
||
{
|
||
CdPlayerPauseCmd();
|
||
}
|
||
else
|
||
{
|
||
CdPlayerPlayCmd();
|
||
}
|
||
break;
|
||
|
||
case IDM_PLAYBAR_PAUSE:
|
||
CdPlayerPauseCmd();
|
||
break;
|
||
|
||
case IDM_PLAYBAR_STOP:
|
||
CdPlayerStopCmd();
|
||
break;
|
||
|
||
case IDM_PLAYBAR_PREVTRACK:
|
||
CdPlayerPrevTrackCmd();
|
||
break;
|
||
|
||
case IDM_PLAYBAR_NEXTTRACK:
|
||
CdPlayerNextTrackCmd();
|
||
break;
|
||
|
||
case IDM_DATABASE_EXIT:
|
||
PostMessage( hwnd, WM_CLOSE, 0, 0L );
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* CDPlay_OnDestroy
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CDPlay_OnDestroy(
|
||
HWND hwnd
|
||
)
|
||
{
|
||
int i;
|
||
|
||
for ( i = 0; i < g_NumCdDevices; i++ ) {
|
||
|
||
if (g_fStopCDOnExit) {
|
||
|
||
if ( g_Devices[i]->State & CD_PLAYING
|
||
|| g_Devices[i]->State & CD_PAUSED ) {
|
||
|
||
StopTheCdromDrive( i );
|
||
}
|
||
}
|
||
|
||
#ifdef USE_IOCTLS
|
||
if ( g_Devices[i]->hCd != NULL ) {
|
||
CloseHandle( g_Devices[i]->hCd );
|
||
}
|
||
#else
|
||
if ( g_Devices[i]->hCd != 0L ) {
|
||
|
||
CloseCdRom( g_Devices[i]->hCd );
|
||
g_Devices[i]->hCd = 0L;
|
||
}
|
||
#endif
|
||
|
||
|
||
ErasePlayList(i);
|
||
EraseSaveList(i);
|
||
EraseTrackList(i);
|
||
|
||
LocalFree( (HLOCAL) g_Devices[i] );
|
||
|
||
}
|
||
|
||
if (g_hBrushBkgd) {
|
||
DeleteObject( g_hBrushBkgd );
|
||
}
|
||
|
||
WinHelp( hwnd, g_HelpFileName, HELP_QUIT, 0 );
|
||
|
||
PostQuitMessage( 0 );
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* CDPlay_OnClose
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
CDPlay_OnClose(
|
||
HWND hwnd,
|
||
BOOL fShuttingDown
|
||
)
|
||
{
|
||
/*
|
||
** If we are playing or paused and the "don't stop playing
|
||
** on exit" flag set, then we need to tell the user that he is about
|
||
** to go into stupid mode. Basically CD Player can only perform as expected
|
||
** if the user has not mucked about with the play list, hasn't put the
|
||
** app into random mode or intro play mode or continuous play mode or
|
||
** multi-disc mode.
|
||
*/
|
||
if ( !fShuttingDown && !g_fStopCDOnExit
|
||
&& (g_State & (CD_PLAYING | CD_PAUSED) ) ) {
|
||
|
||
if ( !g_fSelectedOrder || g_fIntroPlay || g_fContinuous
|
||
|| !g_fSingleDisk || !PlayListMatchesAvailList() ) {
|
||
|
||
TCHAR s1[256];
|
||
TCHAR s2[256];
|
||
int iMsgBoxRtn;
|
||
|
||
_tcscpy( s1, IdStr( STR_EXIT_MESSAGE ) );
|
||
_tcscpy( s2, IdStr( STR_CDPLAYER ) );
|
||
|
||
iMsgBoxRtn = MessageBox( g_hwndApp, s1, s2,
|
||
MB_APPLMODAL | MB_DEFBUTTON1 |
|
||
MB_ICONQUESTION | MB_YESNO);
|
||
|
||
if ( iMsgBoxRtn == IDNO ) {
|
||
return TRUE;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
//WriteSettings();
|
||
|
||
return DestroyWindow( hwnd );
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnEndSession
|
||
*
|
||
* If the session is really ending make sure that we stop the CD Player
|
||
* from playing and that all the ini file stuff is saved away.
|
||
*
|
||
* History:
|
||
* dd-mm-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CDPlay_OnEndSession(
|
||
HWND hwnd,
|
||
BOOL fEnding
|
||
)
|
||
{
|
||
if ( fEnding ) {
|
||
CDPlay_OnClose( hwnd, fEnding );
|
||
}
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* CDPlay_OnSize
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CDPlay_OnSize(
|
||
HWND hwnd,
|
||
UINT state,
|
||
int cx,
|
||
int cy
|
||
)
|
||
{
|
||
if (g_fIsIconic && (state != SIZE_MINIMIZED)) {
|
||
SetWindowText( hwnd, IdStr( STR_CDPLAYER ) );
|
||
}
|
||
g_fIsIconic = (state == SIZE_MINIMIZED);
|
||
|
||
SetWindowPos(GetDlgItem(g_hwndApp,IDC_LED),
|
||
hwnd,
|
||
0,
|
||
0,
|
||
cx,
|
||
cy,
|
||
SWP_NOACTIVATE);
|
||
}
|
||
|
||
/*
|
||
* NormalizeNameForMenuDisplay
|
||
This function turns a string like "Twist & Shout" into
|
||
"Twist && Shout" because otherwise it will look like
|
||
"Twist _Shout" in the menu due to the accelerator char
|
||
*/
|
||
extern "C" void NormalizeNameForMenuDisplay(TCHAR* szInput, TCHAR* szOutput, DWORD cbLen)
|
||
{
|
||
ZeroMemory(szOutput,cbLen);
|
||
WORD index1 = 0;
|
||
WORD index2 = 0;
|
||
for (; index1 < _tcslen(szInput); index1++)
|
||
{
|
||
szOutput[index2] = szInput[index1];
|
||
if (szOutput[index2] == TEXT('&'))
|
||
{
|
||
szOutput[++index2] = TEXT('&');
|
||
}
|
||
index2++;
|
||
}
|
||
}
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnNotify
|
||
*
|
||
* Time to display the little tool tips. Also, change the status bar
|
||
* so that it displays a longer version of the tool tip text.
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
LRESULT
|
||
CDPlay_OnNotify(
|
||
HWND hwnd,
|
||
int idFrom,
|
||
NMHDR *pnmhdr
|
||
)
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL
|
||
CDPlay_CopyData(
|
||
HWND hwnd,
|
||
PCOPYDATASTRUCT lpcpds
|
||
)
|
||
{
|
||
LPTSTR lpCmdLine;
|
||
|
||
// Make a copy of the passed command line as we are not supposed
|
||
// to write into the one passed in the WM_COPYDATA message.
|
||
lpCmdLine = (TCHAR*)AllocMemory( lpcpds->cbData );
|
||
_tcscpy( lpCmdLine, (LPCTSTR)lpcpds->lpData );
|
||
|
||
PostMessage (hwnd, WM_CDPLAYER_COPYDATA, 0, (LPARAM)(LPVOID)lpCmdLine);
|
||
return TRUE;
|
||
} // End CopyData
|
||
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnCopyData
|
||
*
|
||
* Handles command lines passed from other intances of CD Player
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
CDPlay_OnCopyData(
|
||
HWND hwnd,
|
||
PCOPYDATASTRUCT lpcpds
|
||
)
|
||
{
|
||
LPTSTR lpCmdLine;
|
||
BOOL fWasPlaying = FALSE;
|
||
BOOL fUpdate;
|
||
int iTrack = -1;
|
||
int iCdRom;
|
||
|
||
// Prevent Re-entrancy while
|
||
// we are opening/closing CD's
|
||
if (g_fInCopyData)
|
||
return FALSE;
|
||
g_fInCopyData = TRUE;
|
||
|
||
/*
|
||
** Make a copy of the passed command line as we are not supposed
|
||
** to write into the one passed in the WM_COPYDATA message.
|
||
*/
|
||
//lpCmdLine = AllocMemory( lpcpds->cbData );
|
||
//_tcscpy( lpCmdLine, (LPCTSTR)lpcpds->lpData );
|
||
|
||
lpCmdLine = (LPTSTR)(LPVOID)lpcpds;
|
||
if (lpCmdLine == NULL)
|
||
{
|
||
g_fInCopyData = FALSE;
|
||
return 0L;
|
||
}
|
||
|
||
|
||
iCdRom = ParseCommandLine( lpCmdLine, &iTrack, FALSE );
|
||
if (iCdRom < 0 && iTrack < 0) {
|
||
LocalFree( (HLOCAL)lpCmdLine );
|
||
g_fInCopyData = FALSE;
|
||
return 0L;
|
||
}
|
||
|
||
// Check if it is just an update command?!?
|
||
fUpdate = IsUpdateOptionGiven (lpCmdLine);
|
||
if ((fUpdate) && (iTrack == -1))
|
||
{
|
||
if ((iCdRom >= 0) && (iCdRom < g_NumCdDevices))
|
||
{
|
||
CheckUnitCdrom(iCdRom, TRUE);
|
||
}
|
||
|
||
LocalFree( (HLOCAL)lpCmdLine );
|
||
g_fInCopyData = FALSE;
|
||
return 0L;
|
||
}
|
||
|
||
/*
|
||
** Remember our current playing state as we need to temporarly
|
||
** stop the CD if it is currently playing.
|
||
*/
|
||
if ( g_State & (CD_PLAYING | CD_PAUSED) )
|
||
{
|
||
|
||
#ifdef DBG
|
||
dprintf(TEXT("Auto Stopping"));
|
||
#endif
|
||
|
||
while( !LockALLTableOfContents() )
|
||
{
|
||
|
||
MSG msg;
|
||
|
||
#if DBG
|
||
dprintf(TEXT("Busy waiting for TOC to become valid!"));
|
||
#endif
|
||
|
||
GetMessage( &msg, NULL, WM_NOTIFY_TOC_READ, WM_NOTIFY_TOC_READ );
|
||
DispatchMessage( &msg );
|
||
}
|
||
|
||
CdPlayerStopCmd();
|
||
fWasPlaying = TRUE;
|
||
}
|
||
|
||
|
||
/*
|
||
** Figure what has been passed and act on it accordingly.
|
||
*/
|
||
HandlePassedCommandLine( lpCmdLine, FALSE );
|
||
|
||
|
||
/*
|
||
** If we were playing make sure that we are still playing the
|
||
** new track(s)
|
||
*/
|
||
if ( fWasPlaying || g_fPlay )
|
||
{
|
||
|
||
#ifdef DBG
|
||
dprintf(TEXT("Trying to autoplay"));
|
||
#endif
|
||
|
||
while( !LockTableOfContents(g_CurrCdrom) )
|
||
{
|
||
|
||
MSG msg;
|
||
|
||
#ifdef DBG
|
||
dprintf(TEXT("Busy waiting for TOC to become valid!"));
|
||
#endif
|
||
|
||
GetMessage( &msg, NULL, WM_NOTIFY_TOC_READ, WM_NOTIFY_TOC_READ );
|
||
DispatchMessage( &msg );
|
||
}
|
||
|
||
CdPlayerPlayCmd();
|
||
}
|
||
|
||
/*
|
||
** Free the local copy of the command line.
|
||
*/
|
||
LocalFree( (HLOCAL)lpCmdLine );
|
||
|
||
g_fInCopyData = FALSE;
|
||
return 0L;
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnTocRead
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
CDPlay_OnTocRead(
|
||
int iDriveRead
|
||
)
|
||
{
|
||
static int iNumRead = 0;
|
||
|
||
// This serializes processing between this
|
||
// function and the various Table of Content Threads
|
||
// Preventing resource contention on CDROM Multi-Changers.
|
||
EnterCriticalSection (&g_csTOCSerialize);
|
||
|
||
/*
|
||
** Have we finished the initial read of the CD-Rom TOCs ?
|
||
** If so we have to re-open the device. We only need to do this
|
||
** on Daytona because MCI device handles are not shared between threads.
|
||
*/
|
||
iNumRead++;
|
||
|
||
#ifndef USE_IOCTLS
|
||
OSVERSIONINFO os;
|
||
os.dwOSVersionInfoSize = sizeof(os);
|
||
GetVersionEx(&os);
|
||
if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||
{
|
||
if (iNumRead <= g_NumCdDevices) {
|
||
|
||
/*
|
||
** Now, open the cdrom device on the UI thread.
|
||
*/
|
||
g_Devices[iDriveRead]->hCd =
|
||
OpenCdRom( g_Devices[iDriveRead]->drive, NULL );
|
||
}
|
||
}
|
||
#endif
|
||
|
||
|
||
/*
|
||
** This means that one of the threads dedicated to reading the
|
||
** toc has finished. iDriveRead contains the relevant cdrom id.
|
||
*/
|
||
LockALLTableOfContents();
|
||
|
||
if ( g_Devices[iDriveRead]->State & CD_LOADED )
|
||
{
|
||
/*
|
||
** We have a CD loaded, so generate unique ID
|
||
** based on TOC information.
|
||
*/
|
||
g_Devices[iDriveRead]->CdInfo.Id = ComputeNewDiscId( iDriveRead );
|
||
|
||
/*
|
||
** Check database for this compact disc
|
||
*/
|
||
AddFindEntry( iDriveRead, g_Devices[iDriveRead]->CdInfo.Id,
|
||
&(g_Devices[iDriveRead]->toc) );
|
||
|
||
//plop this into the punit table
|
||
//try to find the drive in the unit table
|
||
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 < iDriveRead; index++)
|
||
{
|
||
if (pUnit)
|
||
{
|
||
pUnit = pUnit->pNext;
|
||
}
|
||
}
|
||
|
||
if (pUnit)
|
||
{
|
||
pUnit->dwTitleID = g_Devices[iDriveRead]->CdInfo.Id;
|
||
pUnit->dwNumTracks = g_Devices[iDriveRead]->CdInfo.NumTracks;
|
||
GetTOC(iDriveRead,pUnit->szNetQuery);
|
||
pOpt->DiscChanged(pUnit);
|
||
}
|
||
} //end if gpsink
|
||
}
|
||
|
||
/*
|
||
** If we have completed the initialization of the Cd-Rom drives we can
|
||
** now complete the startup processing of the application.
|
||
*/
|
||
if (iNumRead == g_NumCdDevices)
|
||
{
|
||
CompleteCdPlayerStartUp();
|
||
}
|
||
else {
|
||
|
||
/*
|
||
** if we are in random mode, then we need to shuffle the play lists.
|
||
** but only if we can lock all the cd devices.
|
||
*/
|
||
|
||
TimeAdjustInitialize( iDriveRead );
|
||
|
||
if ( g_fSelectedOrder == FALSE ) {
|
||
if ( LockALLTableOfContents() ) {
|
||
ComputeAndUseShufflePlayLists();
|
||
}
|
||
}
|
||
|
||
ComputeDriveComboBox();
|
||
|
||
if (iDriveRead == g_CurrCdrom)
|
||
{
|
||
if (g_fPlay)
|
||
{
|
||
CdPlayerPlayCmd();
|
||
}
|
||
SetPlayButtonsEnableState();
|
||
}
|
||
|
||
}
|
||
|
||
LeaveCriticalSection (&g_csTOCSerialize);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnDeviceChange
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
|
||
BOOL
|
||
CDPlay_OnDeviceChange(
|
||
HWND hwnd,
|
||
WPARAM wParam,
|
||
LPARAM lParam)
|
||
{
|
||
UINT uiEvent = (UINT)wParam;
|
||
DWORD_PTR dwData = (DWORD_PTR)lParam;
|
||
|
||
switch (uiEvent)
|
||
{
|
||
case DBT_DEVICEARRIVAL: // Insertion
|
||
case DBT_DEVICEREMOVECOMPLETE: // Ejection
|
||
if ((PDEV_BROADCAST_HDR)dwData)
|
||
{
|
||
switch (((PDEV_BROADCAST_HDR)dwData)->dbch_devicetype)
|
||
{
|
||
case DBT_DEVTYP_VOLUME:
|
||
{
|
||
TCHAR chDrive[4] = TEXT("A:\\");
|
||
INT i,j,drive;
|
||
DWORD dwCurr;
|
||
PDEV_BROADCAST_VOLUME pdbv;
|
||
DWORD dwMask, dwDrives;
|
||
|
||
pdbv = (PDEV_BROADCAST_VOLUME)dwData;
|
||
dwMask = pdbv->dbcv_unitmask;
|
||
dwDrives = GetLogicalDrives();
|
||
dwMask &= dwDrives;
|
||
|
||
if (dwMask)
|
||
{
|
||
// Check all drives for match
|
||
for (i = 0; i < 32; i++)
|
||
{
|
||
dwCurr = 1 << i;
|
||
if (dwCurr & dwMask)
|
||
{
|
||
// Check drive
|
||
chDrive[0] = TEXT('A') + i;
|
||
if ( GetDriveType(chDrive) == DRIVE_CDROM )
|
||
{
|
||
// Find Associated Drive structure
|
||
drive = -1;
|
||
for (j = 0; j < g_NumCdDevices; j++)
|
||
{
|
||
if (g_Devices[j]->drive == chDrive[0])
|
||
drive = j;
|
||
}
|
||
// Structure not found, make one
|
||
if (drive == -1)
|
||
{
|
||
#ifdef DBG
|
||
dprintf (TEXT("CDPlay_OnDeviceChange - didn't find drive"));
|
||
#endif
|
||
if (g_NumCdDevices > MAX_CD_DEVICES)
|
||
{
|
||
// Error - not enough device slots
|
||
break;
|
||
}
|
||
|
||
g_Devices[g_NumCdDevices] = (CDROM*)AllocMemory( sizeof(CDROM) );
|
||
if (NULL == g_Devices[g_NumCdDevices])
|
||
{
|
||
// Error - unable to get enough memory
|
||
break;
|
||
}
|
||
g_Devices[g_NumCdDevices]->drive = chDrive[0];
|
||
drive = g_NumCdDevices;
|
||
g_NumCdDevices++;
|
||
}
|
||
|
||
// Insert/Eject new drive
|
||
if (uiEvent == DBT_DEVICEARRIVAL)
|
||
{
|
||
// Drive has been inserted
|
||
// The Shell should inform us using
|
||
// the AUTOPLAY through WM_COPYDDATA
|
||
|
||
//This is only necessary to detect discs with
|
||
//more than just redbook audio on them ...
|
||
//to prevent a double-scan of any discs that
|
||
//are normal audio, we need to block the "get it now"
|
||
//net prompt when scanning this way
|
||
g_fBlockNetPrompt = TRUE;
|
||
CheckUnitCdrom(drive,TRUE);
|
||
g_fBlockNetPrompt = FALSE;
|
||
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
NoMediaUpdate (drive);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
default:
|
||
// Not a logical volume message
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case DBT_DEVICEQUERYREMOVE: // Permission to remove a device is requested.
|
||
case DBT_DEVICEQUERYREMOVEFAILED: // Request to remove a device has been canceled.
|
||
case DBT_DEVICEREMOVEPENDING: // Device is about to be removed. Can not be denied.
|
||
case DBT_DEVICETYPESPECIFIC: // Device-specific event.
|
||
case DBT_CONFIGCHANGED: // Current configuration has changed.
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return TRUE;
|
||
} // End CDPlay_OnDeviceChange
|
||
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CDPlay_OnDropFiles
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CDPlay_OnDropFiles(
|
||
HWND hwnd,
|
||
HDROP hdrop
|
||
)
|
||
{
|
||
int cFiles;
|
||
int cGoodFiles;
|
||
int iTextLen;
|
||
int i;
|
||
TCHAR szFileName[MAX_PATH+3];
|
||
LPTSTR lpCommandLine;
|
||
BOOL fWasPlaying = FALSE;
|
||
|
||
// Prevent Re-entrancy while we are
|
||
// Opening and closing CD's
|
||
if (g_fInCopyData)
|
||
return;
|
||
g_fInCopyData = TRUE;
|
||
|
||
|
||
/*
|
||
** Determine how many files were passed to us.
|
||
*/
|
||
cFiles = DragQueryFile( hdrop, (UINT)-1, (LPTSTR)NULL, 0 );
|
||
|
||
/*
|
||
** Calculate the length of the command line each filename should be
|
||
** separated by a space character
|
||
*/
|
||
iTextLen = _tcslen( g_szCdplayer );
|
||
iTextLen += _tcslen( g_szPlayOption );
|
||
iTextLen += _tcslen( g_szTrackOption );
|
||
for ( cGoodFiles = cFiles, i = 0; i < cFiles; i++ ) {
|
||
|
||
int unused1, unused2;
|
||
|
||
DragQueryFile( hdrop, i, szFileName, MAX_PATH );
|
||
|
||
|
||
if (IsTrackFileNameValid( szFileName, &unused1,
|
||
&unused2, TRUE, FALSE )) {
|
||
|
||
// Add on 3 extra characters - one for the space and
|
||
// two for quote marks, we do this because the filename
|
||
// given may contain space characters.
|
||
iTextLen += _tcslen( szFileName ) + 2 + 1;
|
||
}
|
||
else {
|
||
cGoodFiles--;
|
||
}
|
||
}
|
||
|
||
/*
|
||
** If the none of the dropped files are valid tracks just return
|
||
*/
|
||
if (cGoodFiles < 1) {
|
||
g_fInCopyData = FALSE;
|
||
return;
|
||
}
|
||
|
||
|
||
/*
|
||
** Allocate a chunk of memory big enough for all the options and
|
||
** filenames. Don't forget the NULL.
|
||
*/
|
||
lpCommandLine = (TCHAR*)AllocMemory(sizeof(TCHAR) * (iTextLen + 1));
|
||
|
||
|
||
/*
|
||
** Add a dummy intial command line arg. This is because the
|
||
** first arg is always the name of the invoked application. We ignore
|
||
** this paramter. Also if we are currently playing we need to
|
||
** add the -play option to command line as well as stop the CD.
|
||
*/
|
||
_tcscpy( lpCommandLine, g_szCdplayer );
|
||
if ( g_State & (CD_PLAYING | CD_PAUSED) ) {
|
||
|
||
CdPlayerStopCmd();
|
||
fWasPlaying = TRUE;
|
||
|
||
_tcscat( lpCommandLine, g_szPlayOption );
|
||
}
|
||
|
||
|
||
/*
|
||
** If there is more than one file name specified then we should constuct
|
||
** a new playlist from the given files.
|
||
*/
|
||
if ( cGoodFiles > 1) {
|
||
_tcscat( lpCommandLine, g_szTrackOption );
|
||
}
|
||
|
||
|
||
/*
|
||
** Build up the command line.
|
||
*/
|
||
for ( i = 0; i < cFiles; i++ ) {
|
||
|
||
int unused1, unused2;
|
||
|
||
DragQueryFile( hdrop, i, szFileName, MAX_PATH );
|
||
|
||
if (IsTrackFileNameValid( szFileName, &unused1,
|
||
&unused2, TRUE, TRUE )) {
|
||
|
||
_tcscat( lpCommandLine, TEXT("\'") );
|
||
_tcscat( lpCommandLine, szFileName );
|
||
_tcscat( lpCommandLine, TEXT("\'") );
|
||
_tcscat( lpCommandLine, g_szBlank );
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
** now process the newly constructed command line.
|
||
*/
|
||
HandlePassedCommandLine( lpCommandLine, FALSE );
|
||
|
||
|
||
/*
|
||
** If we were playing make sure that we are still playing the
|
||
** new track(s)
|
||
*/
|
||
if ( fWasPlaying ) {
|
||
|
||
CdPlayerPlayCmd();
|
||
}
|
||
|
||
LocalFree( lpCommandLine );
|
||
DragFinish( hdrop );
|
||
|
||
g_fInCopyData = FALSE;
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* ResolveLink
|
||
*
|
||
* Takes the shortcut (shell link) file pointed to be szFileName and
|
||
* resolves the link returning the linked file name in szFileName.
|
||
*
|
||
* szFileName must point to at least MAX_PATH amount of TCHARS. The function
|
||
* return TRUE if the link was successfully resolved and FALSE otherwise.
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
* 03-11-95 - ShawnB - Unicode enabled
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
ResolveLink(
|
||
TCHAR *szFileName
|
||
)
|
||
{
|
||
return FALSE;
|
||
}
|
||
//#endif
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* FatalApplicationError
|
||
*
|
||
* Call this function if something "bad" happens to the application. It
|
||
* displays an error message and then kills itself.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
FatalApplicationError(
|
||
INT uIdStringResource,
|
||
...
|
||
)
|
||
{
|
||
va_list va;
|
||
TCHAR chBuffer1[ STR_MAX_STRING_LEN ];
|
||
TCHAR chBuffer2[ STR_MAX_STRING_LEN ];
|
||
|
||
/*
|
||
** Load the relevant messages
|
||
*/
|
||
va_start(va, uIdStringResource);
|
||
wvsprintf(chBuffer1, IdStr(uIdStringResource), va);
|
||
va_end(va);
|
||
|
||
_tcscpy( chBuffer2, IdStr(STR_FATAL_ERROR) ); /*"CD Player: Fatal Error"*/
|
||
|
||
/*
|
||
** How much of the application do we need to kill
|
||
*/
|
||
|
||
if (g_hwndApp) {
|
||
|
||
if ( IsWindowVisible(g_hwndApp) ) {
|
||
BringWindowToTop(g_hwndApp);
|
||
}
|
||
|
||
MessageBox( g_hwndApp, chBuffer1, chBuffer2,
|
||
MB_ICONSTOP | MB_OK | MB_APPLMODAL | MB_SETFOREGROUND );
|
||
|
||
DestroyWindow( g_hwndApp );
|
||
|
||
}
|
||
else {
|
||
|
||
MessageBox( NULL, chBuffer1, chBuffer2,
|
||
MB_APPLMODAL | MB_ICONSTOP | MB_OK | MB_SETFOREGROUND );
|
||
}
|
||
|
||
ExitProcess( (UINT)-1 );
|
||
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* IdStr
|
||
*
|
||
* Loads the given string resource ID into the passed storage.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
LPTSTR
|
||
IdStr(
|
||
int idResource
|
||
)
|
||
{
|
||
static TCHAR chBuffer[ STR_MAX_STRING_LEN ];
|
||
|
||
if (LoadString(g_hInst, idResource, chBuffer, STR_MAX_STRING_LEN) == 0)
|
||
{
|
||
return TEXT("");
|
||
}
|
||
|
||
return chBuffer;
|
||
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* CheckMenuItemIfTrue
|
||
*
|
||
* If "flag" TRUE the given menu item is checked, otherwise it is unchecked.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CheckMenuItemIfTrue(
|
||
HMENU hMenu,
|
||
UINT idItem,
|
||
BOOL flag
|
||
)
|
||
{
|
||
UINT uFlags;
|
||
|
||
if (flag) {
|
||
uFlags = MF_CHECKED | MF_BYCOMMAND;
|
||
}
|
||
else {
|
||
uFlags = MF_UNCHECKED | MF_BYCOMMAND;
|
||
}
|
||
|
||
CheckMenuItem( hMenu, idItem, uFlags );
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ReadSettings
|
||
*
|
||
* Read app settings from ini file.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
ReadSettings(
|
||
void* pData
|
||
)
|
||
{
|
||
LPCDOPT pOpt = NULL;
|
||
LPCDOPTDATA pOptionData = (LPCDOPTDATA)pData;
|
||
|
||
//if no option data, get some!
|
||
if (pOptionData == NULL)
|
||
{
|
||
pOpt = (LPCDOPT)g_pSink->GetOptions();
|
||
if( pOpt )
|
||
{
|
||
LPCDOPTIONS pOptions = pOpt->GetCDOpts();
|
||
pOptionData = pOptions->pCDData;
|
||
}
|
||
}
|
||
|
||
//if we still don't have it, bail out!
|
||
if (pOptionData == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
g_fStopCDOnExit = pOptionData->fExitStop;
|
||
|
||
//if being called because of user dialog setting, reset the play mode flag
|
||
if (pData != NULL)
|
||
{
|
||
g_fPlay = pOptionData->fStartPlay;
|
||
}
|
||
|
||
if ( g_NumCdDevices < 2 )
|
||
{
|
||
g_fMultiDiskAvailable = FALSE;
|
||
g_fSingleDisk = TRUE;
|
||
}
|
||
else {
|
||
g_fMultiDiskAvailable = TRUE;
|
||
g_fSingleDisk = FALSE;
|
||
}
|
||
|
||
g_fDisplayD = FALSE;
|
||
g_fDisplayDr = FALSE;
|
||
g_fDisplayT = FALSE;
|
||
g_fDisplayTr = FALSE;
|
||
|
||
switch (pOptionData->fDispMode)
|
||
{
|
||
case CDDISP_CDTIME :
|
||
{
|
||
g_fDisplayD = TRUE;
|
||
}
|
||
break;
|
||
|
||
case CDDISP_CDREMAIN :
|
||
{
|
||
g_fDisplayDr = TRUE;
|
||
}
|
||
break;
|
||
|
||
case CDDISP_TRACKTIME :
|
||
{
|
||
g_fDisplayT = TRUE;
|
||
}
|
||
break;
|
||
|
||
case CDDISP_TRACKREMAIN :
|
||
{
|
||
g_fDisplayTr = TRUE;
|
||
}
|
||
break;
|
||
}
|
||
|
||
g_IntroPlayLength = pOptionData->dwIntroTime;
|
||
|
||
//set into correct mode
|
||
g_fSelectedOrder = (pOptionData->dwPlayMode != IDM_MODE_RANDOM);
|
||
|
||
//if not selected order (i.e. we're in random mode) then also make it continuous.
|
||
if (!g_fSelectedOrder)
|
||
{
|
||
g_fContinuous = TRUE;
|
||
}
|
||
|
||
/*
|
||
** Make sure that the LED display format is correct
|
||
*/
|
||
if ( g_fDisplayT == FALSE && g_fDisplayTr == FALSE
|
||
&& g_fDisplayDr == FALSE && g_fDisplayD == FALSE)
|
||
{
|
||
g_fDisplayT = TRUE;
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* LockTableOfContents
|
||
*
|
||
* This function is used to determine if it is valid for the UI thread
|
||
* to access the table of contents for the specified CD Rom. If this
|
||
* function returns FALSE the UI thread should NOT touch the table of
|
||
* contents for this CD Rom.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
LockTableOfContents(
|
||
int cdrom
|
||
)
|
||
{
|
||
DWORD dwRet;
|
||
|
||
if (g_Devices[cdrom]->fIsTocValid) {
|
||
return TRUE;
|
||
}
|
||
|
||
if (g_Devices[cdrom]->hThreadToc == NULL) {
|
||
return FALSE;
|
||
}
|
||
|
||
dwRet = WaitForSingleObject(g_Devices[cdrom]->hThreadToc, 0L );
|
||
if (dwRet == WAIT_OBJECT_0) {
|
||
|
||
GetExitCodeThread( g_Devices[cdrom]->hThreadToc, &dwRet );
|
||
g_Devices[cdrom]->fIsTocValid = (BOOL)dwRet;
|
||
CloseHandle( g_Devices[cdrom]->hThreadToc );
|
||
g_Devices[cdrom]->hThreadToc = NULL;
|
||
}
|
||
|
||
return g_Devices[cdrom]->fIsTocValid;
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* LockAllTableOfContents
|
||
*
|
||
* This function is used to determine if it is valid for the UI thread
|
||
* to access the table of contents for the ALL the cdroms devices.
|
||
* The function returns FALSE the UI thread should NOT touch the table of
|
||
* contents for any CD Rom.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
LockALLTableOfContents(
|
||
void
|
||
)
|
||
{
|
||
BOOL fLock;
|
||
int i;
|
||
|
||
for (i = 0, fLock = TRUE; fLock && (i < g_NumCdDevices); i++) {
|
||
fLock = LockTableOfContents(i);
|
||
}
|
||
|
||
return fLock;
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* AllocMemory
|
||
*
|
||
* Allocates a memory of the given size. This function will terminate the
|
||
* application if the allocation failed. Memory allocated by this function
|
||
* must be freed with LocalFree. The memory should not be locked or unlocked.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
LPVOID
|
||
AllocMemory(
|
||
UINT uSize
|
||
)
|
||
{
|
||
LPVOID lp;
|
||
lp = LocalAlloc( LPTR, uSize );
|
||
if (lp == NULL) {
|
||
|
||
/*
|
||
** No memory - no application, simple !
|
||
*/
|
||
|
||
FatalApplicationError( STR_FAIL_INIT );
|
||
}
|
||
|
||
return lp;
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* SetPlayButtonsEnableState
|
||
*
|
||
* Sets the play buttons enable state to match the state of the current
|
||
* cdrom device. See below...
|
||
*
|
||
*
|
||
* CDPlayer buttons enable state table
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ
|
||
* <20>E=Enabled D=Disabled <20> Play <20> Pause <20> Eject <20> Stop <20> Other <20>DataB <20>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ
|
||
* <20>Disk in use <20> D <20> D <20> D <20> D <20> D <20> D <20>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ
|
||
* <20>No music cd or data cdrom <20> D <20> D <20> E <20> D <20> D <20> D <20>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ
|
||
* <20>Music cd (playing) <20> D <20> E <20> E <20> E <20> E <20> E <20>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ
|
||
* <20>Music cd (paused) <20> E <20> E <20> E <20> E <20> E <20> E <20>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ
|
||
* <20>Music cd (stopped) <20> E <20> D <20> E <20> D <20> E <20> E <20>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
SetPlayButtonsEnableState(
|
||
void
|
||
)
|
||
{
|
||
BOOL fMusicCdLoaded;
|
||
BOOL fActivePlayList;
|
||
int i;
|
||
|
||
/*
|
||
** Do we have a music cd loaded.
|
||
*/
|
||
if (g_State & (CD_BEING_SCANNED | CD_NO_CD | CD_DATA_CD_LOADED | CD_IN_USE))
|
||
{
|
||
fMusicCdLoaded = FALSE;
|
||
}
|
||
else
|
||
{
|
||
fMusicCdLoaded = TRUE;
|
||
}
|
||
|
||
/*
|
||
** Is there an active playlist
|
||
*/
|
||
if ( (CDTIME(g_CurrCdrom).TotalMin == 0) && (CDTIME(g_CurrCdrom).TotalSec == 0) )
|
||
{
|
||
fActivePlayList = FALSE;
|
||
}
|
||
else
|
||
{
|
||
fActivePlayList = TRUE;
|
||
}
|
||
|
||
//tell the main UI about the track button
|
||
HWND hwndTrackButton = GetDlgItem(GetParent(g_hwndApp),IDB_TRACK);
|
||
if (hwndTrackButton)
|
||
{
|
||
EnableWindow(hwndTrackButton,(fMusicCdLoaded & fActivePlayList));
|
||
}
|
||
|
||
//just turn off all "old" cdplayer buttons, since they are not used in this app
|
||
EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)], FALSE );
|
||
EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)], FALSE );
|
||
EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_PAUSE)], FALSE );
|
||
|
||
/*
|
||
** Do the remaining buttons
|
||
*/
|
||
|
||
for ( i = IDM_PLAYBAR_PREVTRACK; i <= IDM_PLAYBAR_NEXTTRACK; i++ )
|
||
{
|
||
EnableWindow( g_hwndControls[INDEX(i)], FALSE );
|
||
}
|
||
|
||
/*
|
||
** If the drive is in use then we must diable the eject button.
|
||
*/
|
||
EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_EJECT)], FALSE );
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* HeartBeatTimerProc
|
||
*
|
||
* This function is responsible for.
|
||
*
|
||
* 1. detecting new or ejected cdroms.
|
||
* 2. flashing the LED display if we are in paused mode.
|
||
* 3. Incrementing the LED display if we are in play mode.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void CALLBACK
|
||
HeartBeatTimerProc(
|
||
HWND hwnd,
|
||
UINT uMsg,
|
||
UINT idEvent,
|
||
DWORD dwTime
|
||
)
|
||
{
|
||
static DWORD dwTickCount;
|
||
DWORD dwMod;
|
||
|
||
++dwTickCount;
|
||
|
||
dwMod = (dwTickCount % 6);
|
||
|
||
/*
|
||
** Check for "letting go" of drive every 3 seconds
|
||
*/
|
||
if ( 0 == dwMod )
|
||
{
|
||
for (int i = 0; i < g_NumCdDevices; i++)
|
||
{
|
||
if ( (!(g_Devices[i]->State & CD_EDITING))
|
||
&& (!(g_Devices[i]->State & CD_PLAYING)) )
|
||
{
|
||
CheckUnitCdrom(i,FALSE);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( g_State & CD_PLAYING ) {
|
||
|
||
if ( LockALLTableOfContents() ) {
|
||
SyncDisplay();
|
||
}
|
||
}
|
||
|
||
/*
|
||
** If we are paused and NOT skipping flash the display.
|
||
*/
|
||
|
||
else if ((g_State & CD_PAUSED) && !(g_State & CD_SEEKING)) {
|
||
|
||
HWND hwnd;
|
||
|
||
switch ( dwMod ) {
|
||
|
||
case 2:
|
||
case 5:
|
||
case 8:
|
||
case 11:
|
||
if ( g_fIsIconic ) {
|
||
//Next two lines removed to fix tooltip bug:<mwetzel 08.26.97>
|
||
//SetWindowText( g_hwndApp, g_szBlank );
|
||
//UpdateWindow( g_hwndApp );
|
||
}
|
||
else {
|
||
|
||
hwnd = g_hwndControls[INDEX(IDC_LED)];
|
||
|
||
g_fFlashLed = TRUE;
|
||
//SetWindowText( hwnd, g_szBlank );
|
||
g_fFlashLed = FALSE;
|
||
}
|
||
break;
|
||
|
||
case 0:
|
||
case 3:
|
||
case 6:
|
||
case 9:
|
||
UpdateDisplay( DISPLAY_UPD_LED );
|
||
break;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* SkipBeatTimerProc
|
||
*
|
||
* This function is responsible for advancing or retreating the current
|
||
* playing position.
|
||
*
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void CALLBACK
|
||
SkipBeatTimerProc(
|
||
HWND hwnd,
|
||
UINT uMsg,
|
||
UINT idEvent,
|
||
DWORD dwTime
|
||
)
|
||
{
|
||
|
||
/*
|
||
** Deteremine if it is time to accelerate the skipping frequency.
|
||
*/
|
||
switch (++g_AcceleratorCount) {
|
||
|
||
case SKIP_ACCELERATOR_LIMIT1:
|
||
KillTimer( hwnd, idEvent );
|
||
SetTimer( hwnd, idEvent, SKIPBEAT_TIMER_RATE2, (TIMERPROC)SkipBeatTimerProc );
|
||
break;
|
||
|
||
case SKIP_ACCELERATOR_LIMIT2:
|
||
KillTimer( hwnd, idEvent );
|
||
SetTimer( hwnd, idEvent, SKIPBEAT_TIMER_RATE3, (TIMERPROC)SkipBeatTimerProc );
|
||
break;
|
||
}
|
||
|
||
if ( LockALLTableOfContents() ) {
|
||
if ( idEvent == IDM_PLAYBAR_SKIPFORE) {
|
||
|
||
TimeAdjustIncSecond( g_CurrCdrom );
|
||
|
||
/*
|
||
** When TimeAjustIncSecond gets to the end of the last track
|
||
** it sets CURRTRACK(g_CurrCdrom) equal to NULL. When this
|
||
** occurs we effectively reset the CD Player
|
||
*/
|
||
if ( CURRTRACK(g_CurrCdrom) == NULL ) {
|
||
|
||
if ( g_State & (CD_WAS_PLAYING | CD_PAUSED) ) {
|
||
|
||
SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)],
|
||
WM_LBUTTONDOWN, 0, 0L );
|
||
|
||
SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)],
|
||
WM_LBUTTONUP, 0, 0L );
|
||
}
|
||
else {
|
||
|
||
/*
|
||
** Seek to the first playable track.
|
||
*/
|
||
CURRTRACK(g_CurrCdrom) = FindFirstTrack( g_CurrCdrom );
|
||
if ( CURRTRACK(g_CurrCdrom) != NULL ) {
|
||
|
||
TimeAdjustSkipToTrack( g_CurrCdrom,
|
||
CURRTRACK(g_CurrCdrom) );
|
||
|
||
UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_TRACK_TIME |
|
||
DISPLAY_UPD_TRACK_NAME );
|
||
|
||
SetPlayButtonsEnableState();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
TimeAdjustDecSecond( g_CurrCdrom );
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* UpdateDisplay
|
||
*
|
||
* This routine updates the display according to the flags that
|
||
* are passed in. The display consists of the LED display, the
|
||
* track and title names, the disc and track lengths and the cdrom
|
||
* combo-box.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
UpdateDisplay(
|
||
DWORD Flags
|
||
)
|
||
{
|
||
TCHAR lpsz[55];
|
||
TCHAR lpszIcon[75];
|
||
PTRACK_PLAY tr;
|
||
int track;
|
||
int mtemp, stemp, m, s;
|
||
|
||
/*
|
||
** Check for valid flags
|
||
*/
|
||
|
||
if ( Flags == 0 ) {
|
||
return;
|
||
}
|
||
|
||
ZeroMemory(lpsz,sizeof(lpsz));
|
||
|
||
/*
|
||
** Grab current track information
|
||
*/
|
||
|
||
if (CURRTRACK(g_CurrCdrom) != NULL) {
|
||
|
||
track = CURRTRACK(g_CurrCdrom)->TocIndex + FIRSTTRACK(g_CurrCdrom);
|
||
}
|
||
else {
|
||
|
||
track = 0;
|
||
}
|
||
|
||
/*
|
||
** Update the LED box?
|
||
*/
|
||
|
||
|
||
if (Flags & DISPLAY_UPD_LED) {
|
||
|
||
/*
|
||
** Update LED box
|
||
*/
|
||
|
||
if (g_fDisplayT) {
|
||
|
||
if (Flags & DISPLAY_UPD_LEADOUT_TIME) {
|
||
|
||
wsprintf( lpsz, TRACK_TIME_LEADOUT_FORMAT,
|
||
//track,
|
||
CDTIME(g_CurrCdrom).TrackCurMin,
|
||
g_szTimeSep,
|
||
CDTIME(g_CurrCdrom).TrackCurSec );
|
||
}
|
||
else {
|
||
|
||
wsprintf( lpsz, TRACK_TIME_FORMAT,
|
||
//track,
|
||
CDTIME(g_CurrCdrom).TrackCurMin,
|
||
g_szTimeSep,
|
||
CDTIME(g_CurrCdrom).TrackCurSec );
|
||
}
|
||
}
|
||
|
||
if (g_fDisplayTr) {
|
||
|
||
if (Flags & DISPLAY_UPD_LEADOUT_TIME) {
|
||
|
||
wsprintf( lpsz, TRACK_REM_FORMAT, //track - 1,
|
||
CDTIME(g_CurrCdrom).TrackCurMin,
|
||
g_szTimeSep,
|
||
CDTIME(g_CurrCdrom).TrackCurSec );
|
||
}
|
||
else {
|
||
|
||
wsprintf( lpsz, TRACK_REM_FORMAT, //track,
|
||
CDTIME(g_CurrCdrom).TrackRemMin,
|
||
g_szTimeSep,
|
||
CDTIME(g_CurrCdrom).TrackRemSec );
|
||
}
|
||
}
|
||
|
||
if (g_fDisplayD)
|
||
{
|
||
/*
|
||
** Compute remaining time, then sub from total time
|
||
*/
|
||
|
||
mtemp = stemp = m = s =0;
|
||
|
||
if (CURRTRACK(g_CurrCdrom) != NULL)
|
||
{
|
||
for ( tr = CURRTRACK(g_CurrCdrom)->nextplay;
|
||
tr != NULL;
|
||
tr = tr->nextplay )
|
||
{
|
||
|
||
FigureTrackTime( g_CurrCdrom, tr->TocIndex, &mtemp, &stemp );
|
||
|
||
m+=mtemp;
|
||
s+=stemp;
|
||
|
||
}
|
||
|
||
m+= CDTIME(g_CurrCdrom).TrackRemMin;
|
||
s+= CDTIME(g_CurrCdrom).TrackRemSec;
|
||
}
|
||
|
||
m += (s / 60);
|
||
s = (s % 60);
|
||
|
||
CDTIME(g_CurrCdrom).RemMin = m;
|
||
CDTIME(g_CurrCdrom).RemSec = s;
|
||
|
||
//convert to a total number of seconds remaining
|
||
s = (m*60) + s;
|
||
|
||
//convert total time to a number of seconds
|
||
DWORD stotal = (CDTIME(g_CurrCdrom).TotalMin*60) + CDTIME(g_CurrCdrom).TotalSec;
|
||
|
||
//subtract time remaining from total time
|
||
stotal = stotal - s;
|
||
|
||
m = (stotal / 60);
|
||
s = (stotal % 60);
|
||
|
||
wsprintf( lpsz, DISC_TIME_FORMAT,
|
||
m,
|
||
g_szTimeSep,
|
||
s);
|
||
}
|
||
|
||
if (g_fDisplayDr) {
|
||
|
||
/*
|
||
** Compute remaining time
|
||
*/
|
||
|
||
mtemp = stemp = m = s =0;
|
||
|
||
if (CURRTRACK(g_CurrCdrom) != NULL) {
|
||
|
||
for ( tr = CURRTRACK(g_CurrCdrom)->nextplay;
|
||
tr != NULL;
|
||
tr = tr->nextplay ) {
|
||
|
||
FigureTrackTime( g_CurrCdrom, tr->TocIndex, &mtemp, &stemp );
|
||
|
||
m+=mtemp;
|
||
s+=stemp;
|
||
|
||
}
|
||
|
||
m+= CDTIME(g_CurrCdrom).TrackRemMin;
|
||
s+= CDTIME(g_CurrCdrom).TrackRemSec;
|
||
|
||
}
|
||
|
||
m+= (s / 60);
|
||
s = (s % 60);
|
||
|
||
CDTIME(g_CurrCdrom).RemMin = m;
|
||
CDTIME(g_CurrCdrom).RemSec = s;
|
||
|
||
wsprintf( lpsz, DISC_REM_FORMAT,
|
||
CDTIME(g_CurrCdrom).RemMin,
|
||
g_szTimeSep,
|
||
CDTIME(g_CurrCdrom).RemSec );
|
||
}
|
||
|
||
SetWindowText( g_hwndControls[INDEX(IDC_LED)], lpsz );
|
||
|
||
if (Flags != DISPLAY_UPD_LED)
|
||
{
|
||
InvalidateRect(g_hwndControls[INDEX(IDC_LED)],NULL,FALSE);
|
||
UpdateWindow(g_hwndControls[INDEX(IDC_LED)]);
|
||
}
|
||
|
||
|
||
if (g_fIsIconic) {
|
||
//Next four lines changed to fix tooltip bugs: <mwetzel 08.26.97>
|
||
if( g_Devices[g_CurrCdrom]->State & CD_PAUSED )
|
||
wsprintf( lpszIcon, IdStr( STR_CDPLAYER_PAUSED), lpsz );
|
||
else
|
||
wsprintf( lpszIcon, IdStr( STR_CDPLAYER_TIME ), lpsz );
|
||
SetWindowText( g_hwndApp, lpszIcon );
|
||
}
|
||
}
|
||
|
||
//update the framework window to show the time
|
||
if ((CURRTRACK(g_CurrCdrom)) && (lpsz[0] != TEXT('\0')))
|
||
{
|
||
//might already be pre-pending track number
|
||
if (lpsz[0] != TEXT('['))
|
||
{
|
||
wsprintf(lpszIcon,TEXT("[%i] %s"),CURRTRACK(g_CurrCdrom)->TocIndex+1,lpsz);
|
||
}
|
||
else
|
||
{
|
||
_tcscpy(lpszIcon,lpsz);
|
||
}
|
||
MMSETTITLE mmTitle;
|
||
mmTitle.mmInfoText = MMINFOTEXT_DESCRIPTION;
|
||
mmTitle.szTitle = lpszIcon;
|
||
g_pSink->OnEvent(MMEVENT_SETTITLE,&mmTitle);
|
||
}
|
||
|
||
/*
|
||
** Update Title?
|
||
*/
|
||
|
||
if (Flags & DISPLAY_UPD_TITLE_NAME)
|
||
{
|
||
ComputeDriveComboBox( );
|
||
|
||
SetWindowText( g_hwndControls[INDEX(IDC_TITLE_NAME)],
|
||
(LPCTSTR)TITLE(g_CurrCdrom) );
|
||
|
||
//update the framework window to show the title
|
||
MMSETTITLE mmTitle;
|
||
mmTitle.mmInfoText = MMINFOTEXT_TITLE;
|
||
mmTitle.szTitle = TITLE(g_CurrCdrom);
|
||
g_pSink->OnEvent(MMEVENT_SETTITLE,&mmTitle);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* Common_OnCtlColor
|
||
*
|
||
* Here we return a brush to paint the background with. The brush is the same
|
||
* color as the face of a button. We also set the text background color so
|
||
* that static controls draw correctly. This function is shared with the
|
||
* disk info/editing dialog box.
|
||
*
|
||
* History:
|
||
* dd-mm-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
HBRUSH
|
||
Common_OnCtlColor(
|
||
HWND hwnd,
|
||
HDC hdc,
|
||
HWND hwndChild,
|
||
int type
|
||
)
|
||
{
|
||
SetBkColor( hdc, GetSysColor(COLOR_BTNFACE) );
|
||
return g_hBrushBkgd;
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* Common_OnMeasureItem
|
||
*
|
||
* All items are the same height and width.
|
||
*
|
||
* We only have to update the height field for owner draw combo boxes and
|
||
* list boxes. This function is shared with the disk edit/info dialog box.
|
||
*
|
||
* History:
|
||
* dd-mm-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
Common_OnMeasureItem(
|
||
HWND hwnd,
|
||
MEASUREITEMSTRUCT *lpMeasureItem
|
||
)
|
||
{
|
||
if (lpMeasureItem->CtlType == ODT_MENU)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
HFONT hFont;
|
||
int cyBorder, cyDelta;
|
||
LOGFONT lf;
|
||
|
||
hFont = GetWindowFont( hwnd );
|
||
|
||
if ( hFont != NULL ) {
|
||
|
||
GetObject( hFont, sizeof(lf), &lf );
|
||
}
|
||
else {
|
||
SystemParametersInfo( SPI_GETICONTITLELOGFONT,
|
||
sizeof(lf), (LPVOID)&lf, 0 );
|
||
}
|
||
|
||
cyDelta = ABS( lf.lfHeight ) / 2;
|
||
cyBorder = GetSystemMetrics( SM_CYBORDER );
|
||
|
||
//
|
||
// Ensure enough room between chars.
|
||
//
|
||
if (cyDelta < 4 * cyBorder) {
|
||
cyDelta = 4 * cyBorder;
|
||
}
|
||
|
||
lpMeasureItem->itemHeight = ABS( lf.lfHeight ) + cyDelta;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* DrawTrackItem
|
||
*
|
||
* This routine draws the information in a cell of the track name
|
||
* combo box.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
DrawTrackItem(
|
||
HDC hdc,
|
||
const RECT *r,
|
||
DWORD item,
|
||
BOOL selected
|
||
)
|
||
{
|
||
SIZE si;
|
||
int i;
|
||
int cxTrk;
|
||
PTRACK_INF t;
|
||
TCHAR s[ARTIST_LENGTH];
|
||
TCHAR szTrk[16];
|
||
|
||
/*
|
||
** Check for invalid items
|
||
*/
|
||
|
||
if ( item == (DWORD)-1 ) {
|
||
|
||
return;
|
||
}
|
||
|
||
if ( ALLTRACKS(g_CurrCdrom) == NULL ) {
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
/*
|
||
** Check selection status, and set up to draw correctly
|
||
*/
|
||
|
||
if ( selected ) {
|
||
|
||
SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
|
||
SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
|
||
}
|
||
else {
|
||
|
||
SetBkColor( hdc, GetSysColor(COLOR_WINDOW));
|
||
SetTextColor( hdc, GetSysColor(COLOR_WINDOWTEXT));
|
||
}
|
||
|
||
/*
|
||
** Get track info
|
||
*/
|
||
|
||
t = FindTrackNodeFromTocIndex( item, ALLTRACKS( g_CurrCdrom ) );
|
||
|
||
|
||
if ( (t != NULL) && (t->name != NULL) ) {
|
||
|
||
/*
|
||
** Do we need to munge track name (clip to listbox)?
|
||
*/
|
||
|
||
wsprintf(szTrk, TEXT("<%02d> "), t->TocIndex + FIRSTTRACK(g_CurrCdrom));
|
||
GetTextExtentPoint( hdc, szTrk, _tcslen(szTrk), &si );
|
||
cxTrk = si.cx;
|
||
|
||
i = _tcslen( t->name ) + 1;
|
||
|
||
do {
|
||
GetTextExtentPoint( hdc, t->name, --i, &si );
|
||
|
||
} while( si.cx > (r->right - r->left - cxTrk) );
|
||
|
||
ZeroMemory( s, TRACK_TITLE_LENGTH * sizeof( TCHAR ) );
|
||
_tcsncpy( s, t->name, i );
|
||
|
||
}
|
||
else {
|
||
|
||
_tcscpy( s, g_szBlank );
|
||
i = 1;
|
||
|
||
}
|
||
|
||
/*
|
||
** Draw track name
|
||
*/
|
||
|
||
ExtTextOut( hdc, r->left, r->top,
|
||
ETO_OPAQUE | ETO_CLIPPED,
|
||
r, s, i, NULL );
|
||
|
||
/*
|
||
** draw track number
|
||
*/
|
||
if ( t != NULL ) {
|
||
ExtTextOut( hdc, r->right - cxTrk, r->top, ETO_CLIPPED,
|
||
r, szTrk, _tcslen( szTrk ), NULL );
|
||
}
|
||
|
||
}
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* HandlePassedCommandLine
|
||
*
|
||
* This function gets called to handle command line options that are passed to
|
||
* CDPlayer as the result of the WM_DROPFILES or WM_COPYDATA messages.
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
HandlePassedCommandLine(
|
||
LPTSTR lpCmdLine,
|
||
BOOL fCheckCDRom
|
||
)
|
||
{
|
||
|
||
int i;
|
||
int iTrack = -1, iCDrom;
|
||
|
||
iCDrom = ParseCommandLine( lpCmdLine, &iTrack, TRUE );
|
||
if ((iCDrom < 0) || (iCDrom >= g_NumCdDevices))
|
||
return;
|
||
|
||
|
||
// CheckUnitCDRom to reload Table of Contents
|
||
if ( fCheckCDRom )
|
||
{
|
||
|
||
CheckUnitCdrom(iCDrom, TRUE);
|
||
|
||
while( !LockTableOfContents(iCDrom) )
|
||
{
|
||
|
||
MSG msg;
|
||
|
||
GetMessage( &msg, NULL, WM_NOTIFY_TOC_READ, WM_NOTIFY_TOC_READ );
|
||
DispatchMessage( &msg );
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
if (iCDrom != g_CurrCdrom)
|
||
{
|
||
HWND hwndBtn = g_hwndControls[INDEX(IDC_ARTIST_NAME)];
|
||
|
||
SwitchToCdrom( iCDrom, TRUE );
|
||
SetPlayButtonsEnableState();
|
||
SendMessage( hwndBtn, CB_SETCURSEL, (WPARAM)iCDrom, 0 );
|
||
}
|
||
#endif
|
||
|
||
/*
|
||
** Initialize the new play list for each drive.
|
||
*/
|
||
for ( i = 0; i < g_NumCdDevices; i++)
|
||
{
|
||
TimeAdjustInitialize( i );
|
||
}
|
||
|
||
// Set Current Track to specified track
|
||
if ( iTrack != -1 )
|
||
{
|
||
PTRACK_PLAY tr;
|
||
|
||
tr = PLAYLIST( iCDrom );
|
||
if ( tr != NULL )
|
||
{
|
||
for( i = 0; i < iTrack; i++, tr = tr->nextplay );
|
||
TimeAdjustSkipToTrack( iCDrom, tr );
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* IsUpdateOptionGiven
|
||
*
|
||
* Checks the command line to see if the "-update" option has been passed.
|
||
*
|
||
* History:
|
||
* dd-mm-95 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
IsUpdateOptionGiven(
|
||
LPTSTR lpstr
|
||
)
|
||
{
|
||
TCHAR chOption[MAX_PATH];
|
||
|
||
|
||
/*
|
||
** Start by converting everything to upper case.
|
||
*/
|
||
CharUpperBuff( lpstr, _tcslen(lpstr) );
|
||
|
||
/*
|
||
** The first parameter on the command line is always the
|
||
** string used invoke the program. ie cdplayer.exe
|
||
*/
|
||
lpstr += _tcsspn( lpstr, g_szBlank );
|
||
lpstr += CopyWord( chOption, lpstr );
|
||
|
||
|
||
/*
|
||
** Remove leading space
|
||
*/
|
||
lpstr += _tcsspn( lpstr, g_szBlank );
|
||
|
||
|
||
/*
|
||
** process any command line options
|
||
*/
|
||
while ( (*lpstr == g_chOptionHyphen) || (*lpstr == g_chOptionSlash) ) {
|
||
|
||
/*
|
||
** pass over the option delimeter
|
||
*/
|
||
lpstr++;
|
||
|
||
/*
|
||
** Copy option and skip over it.
|
||
*/
|
||
lpstr += CopyWord( chOption, lpstr );
|
||
|
||
|
||
/*
|
||
** Is this the play option ?? If so, don't bother processing anymore
|
||
** options.
|
||
*/
|
||
if ( 0 == _tcscmp( chOption, g_szUpdate ) ) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
** Remove leading space
|
||
*/
|
||
lpstr += _tcsspn( lpstr, g_szBlank );
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* ParseCommandLine
|
||
*
|
||
* Here we look to see if we have been asked to play a particular track.
|
||
* The format of the command line is:
|
||
*
|
||
*
|
||
* CDPlayer command options.
|
||
*
|
||
* CDPLAYER {Options}
|
||
*
|
||
* Options : -play | {Sub-Options}
|
||
* Sub-Options : {-track tracklist} | trackname
|
||
* trackname : filename | drive letter
|
||
* tracklist : filename+
|
||
*
|
||
* -track A track list if a list of tracks that the user wants
|
||
* to play. It overides any play list that may already be stored
|
||
* for the current cd.
|
||
*
|
||
* -play Start playing the current play list. If -play is not specified
|
||
* CD Player seeks to the first track in the play list.
|
||
*
|
||
*
|
||
* On Windows NT the format of [file] is:
|
||
* d:\track(nn).cda
|
||
*
|
||
* where d: is the drive letter of the cdrom that you want to play
|
||
* and \track(nn) is the track number that you want to play.
|
||
*
|
||
* Therefore to play track 8 from a cd-rom drive mapped to e:
|
||
*
|
||
* cdplayer /play e:\track08.cda
|
||
*
|
||
* On Chicago the file is actually a riff CDDA file which contains
|
||
* all the info required to locate the disc and track.
|
||
*
|
||
* Returns the index of the CD-Rom drive which should be played first. Can return
|
||
* -1 iff the caller passed FALSE for the fQuiet parameter and the message box was
|
||
* actually displayed. This should only occur when the user trys to start a new
|
||
* copy of cdplayer passing it the track.cda file of a disk that is not inserted
|
||
* in any of the current CD-Drives attached to the machine.
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
int
|
||
ParseCommandLine(
|
||
LPTSTR lpstr,
|
||
int *piTrackToSeekTo,
|
||
BOOL fQuiet
|
||
)
|
||
{
|
||
|
||
TCHAR chOption[MAX_PATH];
|
||
BOOL fTrack = FALSE;
|
||
int iCdRomIndex = -1; // Assume Failure until proven otherwise
|
||
int ii;
|
||
|
||
for (ii = 0; ii < g_NumCdDevices; ii++) {
|
||
g_Devices[ii]->fKilledPlayList = FALSE;
|
||
}
|
||
|
||
|
||
/*
|
||
** Start by converting everything to upper case.
|
||
*/
|
||
CharUpperBuff( lpstr, _tcslen(lpstr) );
|
||
|
||
#if DBG
|
||
#ifdef UNICODE
|
||
dprintf( TEXT("CD Player Command line : %ls"), lpstr );
|
||
#else
|
||
dprintf( "CD Player Command line : %s", lpstr );
|
||
#endif
|
||
#endif
|
||
|
||
/*
|
||
** The first parameter on the command line is always the
|
||
** string used invoke the program. ie cdplayer.exe
|
||
*/
|
||
lpstr += _tcsspn( lpstr, g_szBlank );
|
||
lpstr += CopyWord( chOption, lpstr );
|
||
|
||
|
||
/*
|
||
** Remove leading space
|
||
*/
|
||
lpstr += _tcsspn( lpstr, g_szBlank );
|
||
|
||
|
||
/*
|
||
** process any command line options
|
||
*/
|
||
while ( (*lpstr == g_chOptionHyphen) || (*lpstr == g_chOptionSlash) ) {
|
||
|
||
/*
|
||
** pass over the option delimeter
|
||
*/
|
||
lpstr++;
|
||
|
||
/*
|
||
** Copy option and skip over it.
|
||
*/
|
||
lpstr += CopyWord( chOption, lpstr );
|
||
|
||
|
||
/*
|
||
** Is this a command line option we understand - ignore ones
|
||
** we don't understand.
|
||
*/
|
||
if ( 0 == _tcscmp( chOption, g_szTrack ) )
|
||
{
|
||
|
||
if ( !fTrack )
|
||
{
|
||
lpstr = ParseTrackList( lpstr, &iCdRomIndex );
|
||
fTrack = TRUE;
|
||
}
|
||
}
|
||
else if ( 0 == _tcscmp( chOption, g_szPlay ) )
|
||
{
|
||
g_fPlay = TRUE;
|
||
}
|
||
else if ( 0 == _tcscmp( chOption, g_szTray) )
|
||
{
|
||
g_fStartedInTray = TRUE;
|
||
}
|
||
else
|
||
{
|
||
#if DBG
|
||
#ifdef UNICODE
|
||
dprintf(TEXT("Ignoring unknown option %ls\n"), chOption );
|
||
#else
|
||
dprintf("Ignoring unknown option %s\n", chOption );
|
||
#endif
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
** Remove leading space
|
||
*/
|
||
lpstr += _tcsspn( lpstr, g_szBlank );
|
||
}
|
||
|
||
|
||
/*
|
||
** parse remaining command line parameters
|
||
*/
|
||
|
||
if ( (*lpstr != g_chNULL) && !fTrack) {
|
||
|
||
/*
|
||
** Copy track name and skip over it. Sometimes the shell
|
||
** gives us quoted strings and sometimes it doesn't. If the
|
||
** string is not quoted assume that remainder of the command line
|
||
** is the track name.
|
||
*/
|
||
if ( (*lpstr == TEXT('\'')) || (*lpstr == TEXT('\"')) ) {
|
||
lpstr += CopyWord( chOption, lpstr );
|
||
}
|
||
else {
|
||
_tcscpy(chOption, lpstr);
|
||
}
|
||
|
||
if ( IsTrackFileNameValid( chOption, &iCdRomIndex,
|
||
piTrackToSeekTo, FALSE, fQuiet ) )
|
||
{
|
||
//if the user passed in a track, turn off start-up random mode
|
||
if (!g_fSelectedOrder)
|
||
{
|
||
g_fSelectedOrder = TRUE;
|
||
SendMessage(GetParent(g_hwndApp),WM_COMMAND,MAKEWPARAM(IDM_MODE_NORMAL,0),(LPARAM)0);
|
||
}
|
||
ResetPlayList( iCdRomIndex );
|
||
}
|
||
#if DBG
|
||
#ifdef UNICODE
|
||
dprintf(TEXT("Seeking to track %ls\n"), chOption );
|
||
#else
|
||
dprintf("Seeking to track %s\n", chOption );
|
||
#endif
|
||
#endif
|
||
}
|
||
|
||
return iCdRomIndex;
|
||
}
|
||
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* ParseTrackList
|
||
*
|
||
* Each track is separated by a ' ' character. The track list is terminated
|
||
* by the NULL, '/' or '-' character.
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
TCHAR *
|
||
ParseTrackList(
|
||
TCHAR *szTrackList,
|
||
int *piCdRomIndex
|
||
)
|
||
{
|
||
TCHAR chTrack[MAX_PATH];
|
||
int iTrackIndex;
|
||
int iCdRom = -1; // Assume failure, until proven otherwise
|
||
BOOL fPlayListErased = FALSE;
|
||
|
||
|
||
ZeroMemory (&chTrack, sizeof (chTrack)); // Make Prefix happy.
|
||
|
||
/*
|
||
** Remove any stray white space
|
||
*/
|
||
|
||
szTrackList += _tcsspn( szTrackList, g_szBlank );
|
||
|
||
/*
|
||
** While there are still valid characters to process
|
||
*/
|
||
|
||
while ( (*szTrackList != g_chNULL)
|
||
&& (*szTrackList != g_chOptionHyphen)
|
||
&& (*szTrackList != g_chOptionSlash) ) {
|
||
|
||
/*
|
||
** Copy the track name and skip over it.
|
||
*/
|
||
szTrackList += CopyWord( chTrack, szTrackList );
|
||
|
||
/*
|
||
** Now check that we have been given a valid filename
|
||
*/
|
||
|
||
if ( IsTrackFileNameValid( chTrack, &iCdRom, &iTrackIndex, TRUE, FALSE ) ) {
|
||
|
||
PTRACK_PLAY pt;
|
||
|
||
/*
|
||
** If this is the first valid file given nuke the
|
||
** existing play lists and prepare for a new list. Note that
|
||
** things are complicated by the fact that we could be given
|
||
** files from more than one CD-Rom drive.
|
||
*/
|
||
|
||
if (! g_Devices[iCdRom]->fKilledPlayList)
|
||
{
|
||
/*
|
||
** Kill the old play and save lists.
|
||
*/
|
||
|
||
ErasePlayList( iCdRom );
|
||
EraseSaveList( iCdRom );
|
||
|
||
PLAYLIST( iCdRom ) = NULL;
|
||
SAVELIST( iCdRom ) = NULL;
|
||
|
||
fPlayListErased = TRUE;
|
||
|
||
g_Devices[iCdRom]->fKilledPlayList = TRUE;
|
||
*piCdRomIndex = iCdRom;
|
||
}
|
||
|
||
pt = (TRACK_PLAY*)AllocMemory( sizeof(TRACK_PLAY) );
|
||
|
||
pt->TocIndex = iTrackIndex;
|
||
pt->min = 0;
|
||
pt->sec = 0;
|
||
|
||
/*
|
||
** Is this the first track on this devices play list ?
|
||
*/
|
||
|
||
if ( PLAYLIST(iCdRom) == NULL ) {
|
||
|
||
PLAYLIST(iCdRom) = pt;
|
||
pt->nextplay = pt->prevplay = NULL;
|
||
}
|
||
else {
|
||
|
||
/*
|
||
** append this track to the end of the current play list
|
||
*/
|
||
|
||
AppendTrackToPlayList( PLAYLIST(iCdRom), pt );
|
||
}
|
||
}
|
||
else {
|
||
|
||
/*
|
||
** Put up a message box warning the user that the given
|
||
** track name is invalid and that we can't play it.
|
||
*/
|
||
|
||
;
|
||
}
|
||
|
||
/*
|
||
** Remove any stray white space
|
||
*/
|
||
szTrackList += _tcsspn( szTrackList, g_szBlank );
|
||
}
|
||
|
||
/*
|
||
** If we have erased the play list we have to go off and reset the
|
||
** saved play list.
|
||
*/
|
||
|
||
if ( fPlayListErased ) {
|
||
SAVELIST( iCdRom ) = CopyPlayList( PLAYLIST(iCdRom) );
|
||
}
|
||
|
||
return szTrackList;
|
||
}
|
||
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* CopyWord
|
||
*
|
||
* Copies one from szSource to szWord - assumes that words are delimited
|
||
* by ' ' characters. szSource MUST point to the begining of the word.
|
||
*
|
||
* Returns length of word copied.
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
int
|
||
CopyWord(
|
||
TCHAR *szWord,
|
||
TCHAR *szSource
|
||
)
|
||
{
|
||
int n, nReturn;
|
||
|
||
/*
|
||
** Copy the track name
|
||
*/
|
||
if ( (*szSource == TEXT('\'')) || (*szSource == TEXT('\"')) ) {
|
||
|
||
TCHAR ch = *szSource;
|
||
|
||
/*
|
||
** Remember which quote character it was
|
||
** According to the DOCS " is invalid in a filename...
|
||
*/
|
||
|
||
n = 0;
|
||
|
||
/*
|
||
** Move over the initial quote, then copy the filename
|
||
*/
|
||
|
||
while ( *++szSource && *szSource != ch ) {
|
||
szWord[n++] = *szSource;
|
||
}
|
||
nReturn = n + (*szSource == ch ? 2 : 1);
|
||
}
|
||
else {
|
||
|
||
n = _tcscspn( szSource, g_szBlank );
|
||
_tcsncpy( szWord, szSource, n );
|
||
nReturn = n;
|
||
}
|
||
|
||
szWord[n] = g_chNULL;
|
||
|
||
return nReturn;
|
||
}
|
||
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* IsTrackFileNameValid
|
||
*
|
||
* This function returns true if the specified filename is a valid CD track.
|
||
|
||
* On NT track filenames must be of the form:
|
||
* d:\track(n).cda where d: is the CD-Rom device and \track(n).cda
|
||
* is the index of the track to be played (starting from 1).
|
||
*
|
||
* On Chicago the track filename is actually a riff CDDA file which contains
|
||
* the track info that we require.
|
||
*
|
||
* If the filename is valid the function true and sets piCdromIndex and
|
||
* piTrackIndex to the correct values.
|
||
*
|
||
* History:
|
||
* 29-09-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL
|
||
IsTrackFileNameValid(
|
||
LPTSTR lpstFileName,
|
||
int *piCdRomIndex,
|
||
int *piTrackIndex,
|
||
BOOL fScanningTracks,
|
||
BOOL fQuiet
|
||
)
|
||
{
|
||
#define RIFF_RIFF 0x46464952
|
||
#define RIFF_CDDA 0x41444443
|
||
|
||
RIFFCDA cda;
|
||
HANDLE hFile;
|
||
TCHAR chDriveLetter;
|
||
int i;
|
||
TCHAR szFileName[MAX_PATH];
|
||
TCHAR szPath[MAX_PATH];
|
||
SHFILEINFO shInfo;
|
||
DWORD cbRead;
|
||
|
||
|
||
//
|
||
// If we are not constructing a track play list it is valid to just specify
|
||
// a drive letter, in which case we select that drive and start playing
|
||
// at the first track on it. All the tracks are played in sequential
|
||
// order.
|
||
//
|
||
if ( !fScanningTracks) {
|
||
|
||
//
|
||
// Map the drive letter onto the internal CD-Rom index used by CDPlayer.
|
||
//
|
||
chDriveLetter = *lpstFileName;
|
||
for ( i = 0; i < g_NumCdDevices; i++ ) {
|
||
|
||
if (g_Devices[i]->drive == chDriveLetter) {
|
||
|
||
*piCdRomIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we mapped the drive OK check to see if we should play all
|
||
// the tracks or just the current play list for that drive. If we
|
||
// didn't map the drive OK assume that its the first part of a
|
||
// RIFF filename and fall through to the code below that opens the
|
||
// RIFF file and parses its contents.
|
||
//
|
||
if ( i != g_NumCdDevices ) {
|
||
|
||
//
|
||
// If next character is only a colon ':' then play the
|
||
// the entire disk starting from the first track.
|
||
//
|
||
if ( 0 == _tcscmp(lpstFileName + 1, g_szColon) ) {
|
||
|
||
*piTrackIndex = 0;
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// If the next two characters are colon backslash ":\" then
|
||
// we seek to the specified drive and play only those tracks that
|
||
// are in the default playlist for the current disk in that drive.
|
||
// All we need to do to achive this is return FALSE.
|
||
//
|
||
if ( 0 == _tcscmp(lpstFileName + 1, g_szColonBackSlash) ) {
|
||
return FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Otherwise, open the file and read the CDA info. The file name may be a
|
||
// link to .cda in which case we need to get the shell to resolve the link for
|
||
// us. We take a copy of the file name because the ResolveLink function
|
||
// modifies the file name string in place.
|
||
//
|
||
_tcscpy(szFileName, lpstFileName);
|
||
if (0L == SHGetFileInfo( szFileName, 0L, &shInfo,
|
||
sizeof(shInfo), SHGFI_ATTRIBUTES)) {
|
||
return FALSE;
|
||
}
|
||
|
||
if ((shInfo.dwAttributes & SFGAO_LINK) == SFGAO_LINK) {
|
||
|
||
if (!g_fOleInitialized)
|
||
{
|
||
g_fOleInitialized = SUCCEEDED(OleInitialize(NULL));
|
||
}
|
||
|
||
if (!ResolveLink(szFileName)) {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
// Make sure file exists
|
||
if (GetFileAttributes (szFileName) == ((DWORD)-1)) {
|
||
// Get Full path to file
|
||
if (0 == SearchPath (NULL, szFileName, NULL,
|
||
MAX_PATH, szPath, NULL)) {
|
||
return FALSE;
|
||
}
|
||
} else {
|
||
_tcscpy (szPath, szFileName);
|
||
}
|
||
|
||
// Open file and read in CDA info
|
||
hFile = CreateFile (szFileName, GENERIC_READ,
|
||
FILE_SHARE_READ, NULL,
|
||
OPEN_EXISTING, 0, NULL);
|
||
if (INVALID_HANDLE_VALUE == hFile) {
|
||
return FALSE;
|
||
}
|
||
|
||
ReadFile(hFile, &cda, sizeof(cda), &cbRead, NULL);
|
||
CloseHandle (hFile);
|
||
|
||
//
|
||
// Make sure its a RIFF CDDA file
|
||
//
|
||
if ( (cda.dwRIFF != RIFF_RIFF) || (cda.dwCDDA != RIFF_CDDA) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Make sure that we have this disc loaded.
|
||
//
|
||
for ( i = 0; i < g_NumCdDevices; i++ ) {
|
||
|
||
if (g_Devices[i]->CdInfo.Id == cda.DiscID) {
|
||
|
||
*piCdRomIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// If we didn't map the drive OK return FALSE AND set the
|
||
// returned CD-ROM index to -1 but only if the caller asked us
|
||
// to complain about an incorrect CD being inserted in the drive.
|
||
//
|
||
if ( i == g_NumCdDevices ) {
|
||
|
||
if (!fQuiet) {
|
||
AskUserToInsertCorrectDisc(cda.DiscID);
|
||
*piCdRomIndex = -1;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
*piTrackIndex = cda.wTrack - 1;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* AppendTrackToPlayList
|
||
*
|
||
* Appends the TRACK_PLAY record pointed to by pAppend to the end of the
|
||
* double linked list pointed to by pHead.
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
AppendTrackToPlayList(
|
||
PTRACK_PLAY pHead,
|
||
PTRACK_PLAY pAppend
|
||
)
|
||
{
|
||
PTRACK_PLAY pp = pHead;
|
||
|
||
while (pp->nextplay != NULL) {
|
||
pp = pp->nextplay;
|
||
}
|
||
|
||
pp->nextplay = pAppend;
|
||
pAppend->prevplay = pp;
|
||
pAppend->nextplay = NULL;
|
||
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* FindMostSuitableDrive
|
||
*
|
||
* Tries to determine the best drive to make the current drive. Returns the
|
||
* drive.
|
||
*
|
||
* We should choose the first disc that is playing if any are playing.
|
||
*
|
||
* New dstewart: Else choose the drive that is selected in the CDUNIT table
|
||
*
|
||
* Else we should choose the first disc with a music disk in it if there
|
||
* any drives with music discs in them.
|
||
*
|
||
* Else we should chose the first drive that is available if any of the
|
||
* drives are available.
|
||
*
|
||
* Else just choose the first (ie. zeroth) drive.
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
int
|
||
FindMostSuitableDrive(
|
||
void
|
||
)
|
||
{
|
||
int iDisc;
|
||
|
||
/*
|
||
** Check for a playing drive
|
||
*/
|
||
for ( iDisc = 0; iDisc < g_NumCdDevices; iDisc++ ) {
|
||
|
||
if ( g_Devices[iDisc]->State & (CD_PLAYING | CD_PAUSED) ) {
|
||
return iDisc;
|
||
}
|
||
}
|
||
|
||
//check the current default drive
|
||
LPCDOPT pOpt = (LPCDOPT)g_pSink->GetOptions();
|
||
LPCDOPTIONS pCDOpts = NULL;
|
||
LPCDUNIT pUnit = NULL;
|
||
int iDefDrive = 0;
|
||
|
||
if (pOpt)
|
||
{
|
||
pCDOpts = pOpt->GetCDOpts();
|
||
}
|
||
|
||
if (pCDOpts)
|
||
{
|
||
pUnit = pCDOpts->pCDUnitList;
|
||
}
|
||
|
||
//scan the list to find the one we want
|
||
for (int index = 0; index < g_NumCdDevices; index++)
|
||
{
|
||
if (pUnit)
|
||
{
|
||
if (pUnit->fDefaultDrive)
|
||
{
|
||
iDefDrive = index;
|
||
|
||
//if this is the default AND it has a disc loaded, go for it
|
||
if ( g_Devices[index]->State & CD_LOADED )
|
||
{
|
||
return index;
|
||
}
|
||
}
|
||
|
||
pUnit = pUnit->pNext;
|
||
|
||
}
|
||
}
|
||
|
||
/*
|
||
** Check for a drive with a music disk in it
|
||
*/
|
||
for ( iDisc = 0; iDisc < g_NumCdDevices; iDisc++ )
|
||
{
|
||
if ( g_Devices[iDisc]->State & CD_LOADED )
|
||
{
|
||
return iDisc;
|
||
}
|
||
}
|
||
|
||
/*
|
||
** If the default drive is not in use, use it
|
||
*/
|
||
if ( (g_Devices[iDefDrive]->State & (CD_BEING_SCANNED | CD_IN_USE)) == 0 )
|
||
{
|
||
return iDefDrive;
|
||
}
|
||
|
||
/*
|
||
** Check for any drive that is not in use
|
||
*/
|
||
for ( iDisc = 0; iDisc < g_NumCdDevices; iDisc++ )
|
||
{
|
||
if ( (g_Devices[iDisc]->State & (CD_BEING_SCANNED | CD_IN_USE)) == 0 )
|
||
{
|
||
return iDisc;
|
||
}
|
||
}
|
||
|
||
/*
|
||
** Ok, no disc are loaded, but all disc are in use, just use the default
|
||
*/
|
||
return iDefDrive;
|
||
}
|
||
|
||
|
||
/*****************************Private*Routine******************************\
|
||
* AskUserToInsertCorrectDisc
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
AskUserToInsertCorrectDisc(
|
||
DWORD dwID
|
||
)
|
||
{
|
||
TCHAR szMsgBoxTitle[32];
|
||
TCHAR szDiskTitle[TITLE_LENGTH];
|
||
TCHAR szArtistName[ARTIST_LENGTH];
|
||
TCHAR szFormat[STR_MAX_STRING_LEN];
|
||
TCHAR szText[STR_MAX_STRING_LEN + TITLE_LENGTH];
|
||
|
||
LPCDDATA pData = (LPCDDATA)g_pSink->GetData();
|
||
|
||
_tcscpy(szDiskTitle,g_szNothingThere);
|
||
|
||
if(pData)
|
||
{
|
||
//
|
||
// Try to read in title from the options database
|
||
//
|
||
|
||
if (pData->QueryTitle(dwID))
|
||
{
|
||
//
|
||
// We found an entry for this disc, so copy all the information
|
||
// from the title database
|
||
|
||
LPCDTITLE pCDTitle = NULL;
|
||
|
||
if (pData->LockTitle(&pCDTitle,dwID))
|
||
{
|
||
_tcscpy(szDiskTitle,pCDTitle->szTitle);
|
||
_tcscpy(szArtistName,pCDTitle->szArtist);
|
||
pData->UnlockTitle(pCDTitle,FALSE);
|
||
} //end if title locked
|
||
} //end if title found
|
||
}
|
||
|
||
/*
|
||
** If the disk title was found in the database display it.
|
||
*/
|
||
if (_tcscmp(szDiskTitle, g_szNothingThere) != 0)
|
||
{
|
||
_tcscpy( szFormat, IdStr(STR_DISK_NOT_THERE_K) );
|
||
wsprintf(szText, szFormat, szDiskTitle, szArtistName);
|
||
}
|
||
else
|
||
{
|
||
_tcscpy( szText, IdStr(STR_DISK_NOT_THERE) );
|
||
}
|
||
|
||
//
|
||
// If CD Player is minimized make sure it is restored
|
||
// before displaying the MessageBox
|
||
//
|
||
if (IsIconic(g_hwndApp)) {
|
||
|
||
WINDOWPLACEMENT wndpl;
|
||
|
||
wndpl.length = sizeof(WINDOWPLACEMENT);
|
||
GetWindowPlacement(g_hwndApp, &wndpl);
|
||
wndpl.showCmd = SW_RESTORE;
|
||
SetWindowPlacement(g_hwndApp, &wndpl);
|
||
}
|
||
|
||
_tcscpy( szMsgBoxTitle, IdStr(STR_CDPLAYER) );
|
||
MessageBox( g_hwndApp, szText, szMsgBoxTitle,
|
||
MB_SETFOREGROUND | MB_ICONINFORMATION | MB_APPLMODAL | MB_OK);
|
||
}
|
||
|
||
|
||
#ifndef USE_IOCTLS
|
||
BOOL CheckMCICDA (TCHAR chDrive)
|
||
{
|
||
DWORD cchLen;
|
||
DWORD dwResult;
|
||
DWORD dwErr;
|
||
CDHANDLE hCD;
|
||
TCHAR szPath[MAX_PATH];
|
||
TCHAR szText[512];
|
||
TCHAR szTitle[MAX_PATH];
|
||
|
||
// Make sure the mcicda.dll exists
|
||
cchLen = NUMELEMS(szPath);
|
||
dwResult = SearchPath (NULL, TEXT ("mcicda.dll"), NULL,
|
||
cchLen, szPath, NULL);
|
||
if ((! dwResult) ||
|
||
(0xFFFFFFFF == GetFileAttributes (szPath)))
|
||
{
|
||
// Give Missing MCICDA.DLL error message
|
||
GetSystemDirectory (szPath, cchLen);
|
||
|
||
_tcscpy( szTitle, IdStr( STR_MCICDA_MISSING ) );
|
||
wsprintf (szText, szTitle, szPath);
|
||
_tcscpy( szTitle, IdStr( STR_CDPLAYER ) );
|
||
|
||
MessageBox( NULL, szText, szTitle,
|
||
MB_APPLMODAL | MB_ICONINFORMATION |
|
||
MB_OK | MB_SETFOREGROUND );
|
||
return FALSE;
|
||
}
|
||
|
||
// Make sure mcicda.dll service is up and running
|
||
hCD = OpenCdRom (chDrive, &dwErr);
|
||
if (! hCD)
|
||
{
|
||
DWORD SessionId = 0;
|
||
ProcessIdToSessionId( GetCurrentProcessId(), &SessionId );
|
||
|
||
// Error loading media device driver.
|
||
if (SessionId != 0){ //Remote connection user
|
||
_tcscpy( szText, IdStr( STR_MCICDA_NOT_AVAIL ) );
|
||
}
|
||
else {
|
||
_tcscpy( szText, IdStr( STR_MCICDA_NOT_WORKING ) );
|
||
}
|
||
|
||
_tcscpy( szTitle, IdStr( STR_CDPLAYER ) );
|
||
|
||
MessageBox( NULL, szText, szTitle,
|
||
MB_APPLMODAL | MB_ICONINFORMATION |
|
||
MB_OK | MB_SETFOREGROUND );
|
||
return FALSE;
|
||
}
|
||
|
||
// Close Device
|
||
CloseCdRom (hCD);
|
||
return TRUE;
|
||
}
|
||
#endif // ! USE_IOCTLS
|
||
|
||
|
||
#if DBG
|
||
/******************************Public*Routine******************************\
|
||
* CDAssert
|
||
*
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
CDAssert(
|
||
LPSTR x,
|
||
LPSTR file,
|
||
int line
|
||
)
|
||
{
|
||
TCHAR buff[128];
|
||
|
||
wsprintf( buff, TEXT("%s \nat line %d of %s"), x, line, file );
|
||
MessageBox( NULL, buff, TEXT("Assertion Failure:"), MB_APPLMODAL | MB_OK );
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* dprintf
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
* dd-mm-94 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
void
|
||
dprintf(
|
||
TCHAR *lpszFormat,
|
||
...
|
||
)
|
||
{
|
||
TCHAR buf[512];
|
||
UINT n;
|
||
va_list va;
|
||
static int iPrintOutput = -1;
|
||
|
||
if (iPrintOutput == -1) {
|
||
iPrintOutput = GetProfileInt( TEXT("MMDEBUG"), TEXT("CdPlayer"), 0);
|
||
}
|
||
|
||
if (iPrintOutput) {
|
||
|
||
n = wsprintf(buf, TEXT("CdPlayer: <%d>"), GetCurrentThreadId() );
|
||
|
||
va_start(va, lpszFormat);
|
||
n += wvsprintf(buf+n, lpszFormat, va);
|
||
va_end(va);
|
||
|
||
buf[n++] = '\n';
|
||
buf[n] = 0;
|
||
OutputDebugString(buf);
|
||
}
|
||
|
||
}
|
||
#endif // End #ifdef DBG
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ChildEnumProc
|
||
*
|
||
* Gets the position of each child control window. As saves the associated
|
||
* window handle for later use.
|
||
*
|
||
* History:
|
||
* 18-11-93 - StephenE - Created
|
||
*
|
||
\**************************************************************************/
|
||
BOOL CALLBACK
|
||
ChildEnumProc(
|
||
HWND hwndChild,
|
||
LPARAM hwndParent
|
||
)
|
||
{
|
||
int index = 0;
|
||
|
||
index = INDEX(GetDlgCtrlID( hwndChild ));
|
||
|
||
if ((index > -1) && (index < NUM_OF_CONTROLS))
|
||
{
|
||
g_hwndControls[index] = hwndChild;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|