Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

608 lines
15 KiB

// CDPlay.cpp : Implementation of CCDPlay
#include "windows.h"
#include "CDPlay.h"
#include "cdapi.h"
#include "cdplayer.h"
#include "literals.h"
#include "playres.h"
#include "tchar.h"
#include "trklst.h"
extern HINSTANCE g_dllInst;
extern BOOL g_fOleInitialized;
extern TCHAR g_szTimeSep[10];
/////////////////////////////////////////////////////////////////////////////
// CCDPlay
CCDPlay::CCDPlay()
{
m_hMenu = NULL;
m_hwndMain = NULL;
m_pSink = NULL;
m_dwRef = 0;
InitIcons();
}
CCDPlay::~CCDPlay()
{
//close device ...
//destroy objects
if (m_hIcon16)
{
DestroyIcon(m_hIcon16);
m_hIcon16 = NULL;
}
if (m_hIcon32)
{
DestroyIcon(m_hIcon32);
m_hIcon32 = NULL;
}
if (m_hMenu)
{
DestroyMenu(m_hMenu);
m_hMenu = NULL;
}
// Cleanup from cd player stuff
DeleteCriticalSection (&g_csTOCSerialize);
if (g_fOleInitialized)
{
OleUninitialize();
}
}
STDMETHODIMP CCDPlay::QueryInterface(REFIID riid, void** ppv)
{
*ppv = NULL;
if (IID_IUnknown == riid || IID_IMMComponent == riid)
{
*ppv = this;
}
if (IID_IMMComponentAutomation == riid)
{
*ppv = (IMMComponentAutomation*)this;
}
if (NULL==*ppv)
{
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CCDPlay::AddRef(void)
{
return ++m_dwRef;
}
STDMETHODIMP_(ULONG) CCDPlay::Release(void)
{
if (0!=--m_dwRef)
return m_dwRef;
delete this;
return 0;
}
STDMETHODIMP CCDPlay::GetInfo(MMCOMPDATA* mmCompData)
{
mmCompData->hiconSmall = m_hIcon16;
mmCompData->hiconLarge = m_hIcon32;
mmCompData->nAniResID = -1;
mmCompData->hInst = g_dllInst;
_tcscpy(mmCompData->szName,TEXT("CD"));
QueryVolumeSupport(&mmCompData->fVolume, &mmCompData->fPan);
//try to get the rect required by the ledwnd,
//this could change if there are large fonts involved
TCHAR szDisp[MAX_PATH];
LoadString(g_dllInst, STR_DISPLAY_LABELS, szDisp, sizeof(szDisp)/sizeof(TCHAR));
HWND hwndDisp = GetDlgItem(m_hwndMain,IDC_LED);
HDC hdc = GetDC(hwndDisp);
LOGFONT lf;
int iLogPelsY;
iLogPelsY = GetDeviceCaps( hdc, LOGPIXELSY );
ZeroMemory( &lf, sizeof(lf) );
HFONT hTempFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
GetObject(hTempFont,sizeof(lf),&lf);
lf.lfHeight = (-10 * iLogPelsY) / 72;
if (lf.lfCharSet == ANSI_CHARSET)
{
lf.lfWeight = FW_BOLD;
}
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = PROOF_QUALITY;
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
HFONT hDispFont = CreateFontIndirect(&lf);
HFONT hOrgFont = (HFONT)SelectObject(hdc,hDispFont);
GetClientRect(hwndDisp,&(mmCompData->rect));
DrawText( hdc, // handle to device context
szDisp, // pointer to string to draw
-1, // string length, in characters
&(mmCompData->rect), // pointer to struct with formatting dimensions
DT_CALCRECT|DT_EXPANDTABS|DT_NOPREFIX);
SelectObject(hdc,hOrgFont);
DeleteObject(hDispFont);
ReleaseDC(hwndDisp,hdc);
return S_OK;
}
BOOL CALLBACK
TransDlgProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
return FALSE;
}
extern HWND PASCAL WinFake(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, HWND hwndMain, IMMFWNotifySink* pSink);
STDMETHODIMP CCDPlay::Init(IMMFWNotifySink* pSink, HWND hwndMain, RECT* pRect, HWND* phwndComp, HMENU* phMenu)
{
HRESULT hr = S_OK;
//save sink pointer
m_pSink = pSink;
//load custom menu
m_hMenu = LoadMenu(g_dllInst,
MAKEINTRESOURCE(IDR_MAINMENU));
*phMenu = m_hMenu;
//create the main window here
//fake cd player into thinking it can go)
m_hwndMain = WinFake(g_dllInst,NULL,"",SW_NORMAL,hwndMain,pSink);
//set up pointer to main window of app
*phwndComp = m_hwndMain;
return hr;
}
void GetTOC(int cdrom, TCHAR* szNetQuery)
{
DWORD dwRet;
MCI_SET_PARMS mciSet;
unsigned long m_toc[101];
ZeroMemory( &mciSet, sizeof(mciSet) );
mciSet.dwTimeFormat = MCI_FORMAT_MSF;
mciSendCommand( g_Devices[ cdrom ]->hCd, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID)&mciSet );
MCI_STATUS_PARMS mciStatus;
long lAddress, lStartPos, lDiskLen;
int i;
ZeroMemory( &mciStatus, sizeof(mciStatus) );
mciStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
//
// NOTE: none of the mciSendCommand calls below bother to check the
// return code. This is asking for trouble... but if the
// commands fail we cannot do much about it.
//
dwRet = mciSendCommand( g_Devices[ cdrom ]->hCd, MCI_STATUS,
MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus);
int tracks = -1;
tracks = (UCHAR)mciStatus.dwReturn;
mciStatus.dwItem = MCI_STATUS_POSITION;
for ( i = 0; i < tracks; i++ )
{
mciStatus.dwTrack = i + 1;
dwRet = mciSendCommand( g_Devices[ cdrom ]->hCd, MCI_STATUS,
MCI_STATUS_ITEM | MCI_TRACK,
(DWORD_PTR)(LPVOID)&mciStatus);
lAddress = (long)mciStatus.dwReturn;
//converts "packed" time into pure frames
lAddress = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
(MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
(MCI_MSF_FRAME( lAddress));
m_toc[i] = lAddress;
if (i==0)
{
lStartPos = lAddress;
}
}
mciStatus.dwItem = MCI_STATUS_LENGTH;
dwRet = mciSendCommand( g_Devices[ cdrom ]->hCd, MCI_STATUS,
MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus);
/*
** Convert the total disk length into frames
*/
lAddress = (long)mciStatus.dwReturn;
lDiskLen = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
(MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
(MCI_MSF_FRAME( lAddress));
/*
** Now, determine the absolute start position of the sentinel
** track. That is, the special track that marks the end of the
** disk.
*/
lAddress = lStartPos + lDiskLen + 1; //dstewart: add one for true time
m_toc[i] = lAddress;
wsprintf(szNetQuery,TEXT("cd=%X"),tracks);
//add each frame stattime to query, include end time of disc
TCHAR tempstr[MAX_PATH];
for (i = 0; i < tracks+1; i++)
{
wsprintf(tempstr,TEXT("+%X"),m_toc[i]);
_tcscat(szNetQuery,tempstr);
}
}
STDMETHODIMP CCDPlay::OnAction(MMACTIONS mmActionID, LPVOID pAction)
{
HRESULT hr = S_OK;
switch (mmActionID)
{
case MMACTION_PLAY:
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_PLAY,0),0);
}
break;
case MMACTION_STOP:
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_STOP,0),0);
}
break;
case MMACTION_UNLOADMEDIA: //"eject"
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_EJECT,0),0);
}
break;
case MMACTION_NEXTTRACK:
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_NEXTTRACK,0),0);
}
break;
case MMACTION_PREVTRACK:
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_PREVTRACK,0),0);
}
break;
case MMACTION_PAUSE:
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_PAUSE,0),0);
}
break;
case MMACTION_REWIND:
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_SKIPBACK,0),0);
}
break;
case MMACTION_FFWD:
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_SKIPFORE,0),0);
}
break;
case MMACTION_NEXTMEDIA:
{
SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_EJECT,0),0);
}
break;
case MMACTION_GETMEDIAID:
{
MMMEDIAID* pID = (MMMEDIAID*)pAction;
if (pID->nDrive == -1)
{
pID->nDrive = g_CurrCdrom;
}
wsprintf( pID->szMediaID, g_szSectionF, g_Devices[pID->nDrive]->CdInfo.Id );
pID->dwMediaID = g_Devices[pID->nDrive]->CdInfo.Id;
pID->dwNumTracks = NUMTRACKS(pID->nDrive);
_tcscpy(pID->szArtist,ARTIST(pID->nDrive));
_tcscpy(pID->szTitle,TITLE(pID->nDrive));
PTRACK_INF t;
if (CURRTRACK(pID->nDrive)!=NULL)
{
t = FindTrackNodeFromTocIndex( CURRTRACK(pID->nDrive)->TocIndex, ALLTRACKS( pID->nDrive ) );
if (t)
{
_tcscpy(pID->szTrack,t->name);
}
}
}
break;
case MMACTION_GETNETQUERY:
{
MMNETQUERY* pQuery = (MMNETQUERY*)pAction;
if (pQuery->nDrive == -1)
{
pQuery->nDrive = g_CurrCdrom;
}
GetTOC(pQuery->nDrive,pQuery->szNetQuery);
}
break;
case MMACTION_READSETTINGS :
{
ReadSettings((void*)pAction);
UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_TRACK_TIME |
DISPLAY_UPD_TRACK_NAME );
}
break;
case MMACTION_GETTRACKINFO :
{
LPMMTRACKORDISC pInfo = (LPMMTRACKORDISC)pAction;
return (GetTrackInfo(pInfo));
}
break;
case MMACTION_GETDISCINFO :
{
LPMMTRACKORDISC pInfo = (LPMMTRACKORDISC)pAction;
return (GetDiscInfo(pInfo));
}
break;
case MMACTION_SETTRACK :
{
LPMMCHANGETRACK pTrack = (LPMMCHANGETRACK)pAction;
SetTrack(pTrack->nNewTrack);
}
break;
case MMACTION_SETDISC :
{
LPMMCHANGEDISC pDisc = (LPMMCHANGEDISC)pAction;
SetDisc(pDisc->nNewDisc);
}
break;
default:
{
hr = E_NOTIMPL;
}
break;
}
return hr;
}
//QueryVolumeSupport is just a helper function ... you don't have to do it this way
STDMETHODIMP CCDPlay::QueryVolumeSupport(BOOL* pVolume, BOOL* pPan)
{
*pVolume = FALSE;
*pPan = FALSE;
return S_OK;
}
//InitIcons is just a helper function ... you don't have to do it this way
void CCDPlay::InitIcons()
{
m_hIcon16 = NULL;
m_hIcon32 = NULL;
m_hIcon16 = (HICON)LoadImage(g_dllInst, MAKEINTRESOURCE(IDI_ICON_CDPLAY), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
m_hIcon32 = LoadIcon(g_dllInst, MAKEINTRESOURCE(IDI_ICON_CDPLAY));
}
/*
* 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
*/
void CCDPlay::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++;
}
}
//try to find and return the track info referenced by pInfo->nNumber
HRESULT CCDPlay::GetTrackInfo(LPMMTRACKORDISC pInfo)
{
HRESULT hr = E_FAIL;
if (pInfo)
{
int index = -1;
PTRACK_PLAY playlist;
for( playlist = SAVELIST(g_CurrCdrom);
playlist != NULL;
playlist = playlist->nextplay )
{
index++;
PTRACK_INF t = NULL;
t = FindTrackNodeFromTocIndex( playlist->TocIndex, ALLTRACKS( g_CurrCdrom ) );
if ((t) && (index == pInfo->nNumber))
{
int mtemp, stemp;
FigureTrackTime(g_CurrCdrom, t->TocIndex, &mtemp, &stemp );
TCHAR szDisplayTrack[TRACK_TITLE_LENGTH*2];
NormalizeNameForMenuDisplay(t->name,szDisplayTrack,sizeof(szDisplayTrack));
wsprintf(pInfo->szName,TEXT("%i. %s (%i%s%02i)"),t->TocIndex + 1,szDisplayTrack,mtemp,g_szTimeSep,stemp);
pInfo->nID = t->TocIndex;
if (playlist->TocIndex == CURRTRACK(g_CurrCdrom)->TocIndex)
{
pInfo->fCurrent = TRUE;
}
else
{
pInfo->fCurrent = FALSE;
}
hr = S_OK; //indicate that indexed track was found
} //end if track ok
} //end stepping
} //end if pinfo valid
return (hr);
}
HRESULT CCDPlay::GetDiscInfo(LPMMTRACKORDISC pInfo)
{
HRESULT hr = E_FAIL;
if (pInfo)
{
for(int i = 0; i < g_NumCdDevices; i++)
{
if (i == pInfo->nNumber)
{
TCHAR szDisplayTitle[TITLE_LENGTH*2];
NormalizeNameForMenuDisplay(TITLE(i),szDisplayTitle,sizeof(szDisplayTitle));
TCHAR szDisplayArtist[ARTIST_LENGTH*2];
NormalizeNameForMenuDisplay(ARTIST(i),szDisplayArtist,sizeof(szDisplayArtist));
if (g_Devices[i]->State & (CD_BEING_SCANNED | CD_NO_CD | CD_DATA_CD_LOADED | CD_IN_USE))
{
wsprintf(pInfo->szName,TEXT("<%c:> %s"),g_Devices[i]->drive,szDisplayTitle);
}
else
{
wsprintf(pInfo->szName,TEXT("<%c:> %s (%s)"),
g_Devices[i]->drive,szDisplayTitle,szDisplayArtist);
}
pInfo->nID = i;
if (i == g_CurrCdrom)
{
pInfo->fCurrent = TRUE;
}
else
{
pInfo->fCurrent = FALSE;
}
hr = S_OK;
} //end if match
} //end for
} //end if pinfo valid
return (hr);
}
void CCDPlay::SetTrack(int nTrack)
{
PTRACK_INF tr;
tr = ALLTRACKS( g_CurrCdrom );
if ( tr != NULL )
{
PTRACK_PLAY trCurrent = CURRTRACK(g_CurrCdrom);
tr = FindTrackNodeFromTocIndex(nTrack,ALLTRACKS(g_CurrCdrom));
if (tr->TocIndex != trCurrent->TocIndex)
{
PTRACK_PLAY p = NULL;
for (p = PLAYLIST(g_CurrCdrom); (p!=NULL) && (p->TocIndex != tr->TocIndex); p = p->nextplay);
if (p)
{
TimeAdjustSkipToTrack( g_CurrCdrom, p );
} //if not null
} //if not equal to current
} //if tr not null
}
void CCDPlay::SetDisc(int nDisc)
{
SwitchToCdrom(nDisc, FALSE);
MMONDISCCHANGED mmOnDisc;
mmOnDisc.nNewDisc = g_CurrCdrom;
mmOnDisc.fDisplayVolChange = TRUE;
g_pSink->OnEvent(MMEVENT_ONDISCCHANGED,&mmOnDisc);
}
extern "C"
HRESULT WINAPI CDPLAY_CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void ** ppvObj)
{
CCDPlay* pObj;
HRESULT hr = E_OUTOFMEMORY;
*ppvObj = NULL;
if (NULL!=pUnkOuter && IID_IUnknown!=riid)
{
return CLASS_E_NOAGGREGATION;
}
pObj = new CCDPlay();
if (NULL==pObj)
{
return hr;
}
hr = pObj->QueryInterface(riid, ppvObj);
if (FAILED(hr))
{
delete pObj;
}
return hr;
}