|
|
// 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; }
|