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

  1. // CDPlay.cpp : Implementation of CCDPlay
  2. #include "windows.h"
  3. #include "CDPlay.h"
  4. #include "cdapi.h"
  5. #include "cdplayer.h"
  6. #include "literals.h"
  7. #include "playres.h"
  8. #include "tchar.h"
  9. #include "trklst.h"
  10. extern HINSTANCE g_dllInst;
  11. extern BOOL g_fOleInitialized;
  12. extern TCHAR g_szTimeSep[10];
  13. /////////////////////////////////////////////////////////////////////////////
  14. // CCDPlay
  15. CCDPlay::CCDPlay()
  16. {
  17. m_hMenu = NULL;
  18. m_hwndMain = NULL;
  19. m_pSink = NULL;
  20. m_dwRef = 0;
  21. InitIcons();
  22. }
  23. CCDPlay::~CCDPlay()
  24. {
  25. //close device ...
  26. //destroy objects
  27. if (m_hIcon16)
  28. {
  29. DestroyIcon(m_hIcon16);
  30. m_hIcon16 = NULL;
  31. }
  32. if (m_hIcon32)
  33. {
  34. DestroyIcon(m_hIcon32);
  35. m_hIcon32 = NULL;
  36. }
  37. if (m_hMenu)
  38. {
  39. DestroyMenu(m_hMenu);
  40. m_hMenu = NULL;
  41. }
  42. // Cleanup from cd player stuff
  43. DeleteCriticalSection (&g_csTOCSerialize);
  44. if (g_fOleInitialized)
  45. {
  46. OleUninitialize();
  47. }
  48. }
  49. STDMETHODIMP CCDPlay::QueryInterface(REFIID riid, void** ppv)
  50. {
  51. *ppv = NULL;
  52. if (IID_IUnknown == riid || IID_IMMComponent == riid)
  53. {
  54. *ppv = this;
  55. }
  56. if (IID_IMMComponentAutomation == riid)
  57. {
  58. *ppv = (IMMComponentAutomation*)this;
  59. }
  60. if (NULL==*ppv)
  61. {
  62. return E_NOINTERFACE;
  63. }
  64. AddRef();
  65. return S_OK;
  66. }
  67. STDMETHODIMP_(ULONG) CCDPlay::AddRef(void)
  68. {
  69. return ++m_dwRef;
  70. }
  71. STDMETHODIMP_(ULONG) CCDPlay::Release(void)
  72. {
  73. if (0!=--m_dwRef)
  74. return m_dwRef;
  75. delete this;
  76. return 0;
  77. }
  78. STDMETHODIMP CCDPlay::GetInfo(MMCOMPDATA* mmCompData)
  79. {
  80. mmCompData->hiconSmall = m_hIcon16;
  81. mmCompData->hiconLarge = m_hIcon32;
  82. mmCompData->nAniResID = -1;
  83. mmCompData->hInst = g_dllInst;
  84. _tcscpy(mmCompData->szName,TEXT("CD"));
  85. QueryVolumeSupport(&mmCompData->fVolume, &mmCompData->fPan);
  86. //try to get the rect required by the ledwnd,
  87. //this could change if there are large fonts involved
  88. TCHAR szDisp[MAX_PATH];
  89. LoadString(g_dllInst, STR_DISPLAY_LABELS, szDisp, sizeof(szDisp)/sizeof(TCHAR));
  90. HWND hwndDisp = GetDlgItem(m_hwndMain,IDC_LED);
  91. HDC hdc = GetDC(hwndDisp);
  92. LOGFONT lf;
  93. int iLogPelsY;
  94. iLogPelsY = GetDeviceCaps( hdc, LOGPIXELSY );
  95. ZeroMemory( &lf, sizeof(lf) );
  96. HFONT hTempFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  97. GetObject(hTempFont,sizeof(lf),&lf);
  98. lf.lfHeight = (-10 * iLogPelsY) / 72;
  99. if (lf.lfCharSet == ANSI_CHARSET)
  100. {
  101. lf.lfWeight = FW_BOLD;
  102. }
  103. lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  104. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  105. lf.lfQuality = PROOF_QUALITY;
  106. lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
  107. HFONT hDispFont = CreateFontIndirect(&lf);
  108. HFONT hOrgFont = (HFONT)SelectObject(hdc,hDispFont);
  109. GetClientRect(hwndDisp,&(mmCompData->rect));
  110. DrawText( hdc, // handle to device context
  111. szDisp, // pointer to string to draw
  112. -1, // string length, in characters
  113. &(mmCompData->rect), // pointer to struct with formatting dimensions
  114. DT_CALCRECT|DT_EXPANDTABS|DT_NOPREFIX);
  115. SelectObject(hdc,hOrgFont);
  116. DeleteObject(hDispFont);
  117. ReleaseDC(hwndDisp,hdc);
  118. return S_OK;
  119. }
  120. BOOL CALLBACK
  121. TransDlgProc(
  122. HWND hwnd,
  123. UINT message,
  124. WPARAM wParam,
  125. LPARAM lParam
  126. )
  127. {
  128. return FALSE;
  129. }
  130. extern HWND PASCAL WinFake(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, HWND hwndMain, IMMFWNotifySink* pSink);
  131. STDMETHODIMP CCDPlay::Init(IMMFWNotifySink* pSink, HWND hwndMain, RECT* pRect, HWND* phwndComp, HMENU* phMenu)
  132. {
  133. HRESULT hr = S_OK;
  134. //save sink pointer
  135. m_pSink = pSink;
  136. //load custom menu
  137. m_hMenu = LoadMenu(g_dllInst,
  138. MAKEINTRESOURCE(IDR_MAINMENU));
  139. *phMenu = m_hMenu;
  140. //create the main window here
  141. //fake cd player into thinking it can go)
  142. m_hwndMain = WinFake(g_dllInst,NULL,"",SW_NORMAL,hwndMain,pSink);
  143. //set up pointer to main window of app
  144. *phwndComp = m_hwndMain;
  145. return hr;
  146. }
  147. void GetTOC(int cdrom, TCHAR* szNetQuery)
  148. {
  149. DWORD dwRet;
  150. MCI_SET_PARMS mciSet;
  151. unsigned long m_toc[101];
  152. ZeroMemory( &mciSet, sizeof(mciSet) );
  153. mciSet.dwTimeFormat = MCI_FORMAT_MSF;
  154. mciSendCommand( g_Devices[ cdrom ]->hCd, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID)&mciSet );
  155. MCI_STATUS_PARMS mciStatus;
  156. long lAddress, lStartPos, lDiskLen;
  157. int i;
  158. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  159. mciStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  160. //
  161. // NOTE: none of the mciSendCommand calls below bother to check the
  162. // return code. This is asking for trouble... but if the
  163. // commands fail we cannot do much about it.
  164. //
  165. dwRet = mciSendCommand( g_Devices[ cdrom ]->hCd, MCI_STATUS,
  166. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus);
  167. int tracks = -1;
  168. tracks = (UCHAR)mciStatus.dwReturn;
  169. mciStatus.dwItem = MCI_STATUS_POSITION;
  170. for ( i = 0; i < tracks; i++ )
  171. {
  172. mciStatus.dwTrack = i + 1;
  173. dwRet = mciSendCommand( g_Devices[ cdrom ]->hCd, MCI_STATUS,
  174. MCI_STATUS_ITEM | MCI_TRACK,
  175. (DWORD_PTR)(LPVOID)&mciStatus);
  176. lAddress = (long)mciStatus.dwReturn;
  177. //converts "packed" time into pure frames
  178. lAddress = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  179. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  180. (MCI_MSF_FRAME( lAddress));
  181. m_toc[i] = lAddress;
  182. if (i==0)
  183. {
  184. lStartPos = lAddress;
  185. }
  186. }
  187. mciStatus.dwItem = MCI_STATUS_LENGTH;
  188. dwRet = mciSendCommand( g_Devices[ cdrom ]->hCd, MCI_STATUS,
  189. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus);
  190. /*
  191. ** Convert the total disk length into frames
  192. */
  193. lAddress = (long)mciStatus.dwReturn;
  194. lDiskLen = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  195. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  196. (MCI_MSF_FRAME( lAddress));
  197. /*
  198. ** Now, determine the absolute start position of the sentinel
  199. ** track. That is, the special track that marks the end of the
  200. ** disk.
  201. */
  202. lAddress = lStartPos + lDiskLen + 1; //dstewart: add one for true time
  203. m_toc[i] = lAddress;
  204. wsprintf(szNetQuery,TEXT("cd=%X"),tracks);
  205. //add each frame stattime to query, include end time of disc
  206. TCHAR tempstr[MAX_PATH];
  207. for (i = 0; i < tracks+1; i++)
  208. {
  209. wsprintf(tempstr,TEXT("+%X"),m_toc[i]);
  210. _tcscat(szNetQuery,tempstr);
  211. }
  212. }
  213. STDMETHODIMP CCDPlay::OnAction(MMACTIONS mmActionID, LPVOID pAction)
  214. {
  215. HRESULT hr = S_OK;
  216. switch (mmActionID)
  217. {
  218. case MMACTION_PLAY:
  219. {
  220. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_PLAY,0),0);
  221. }
  222. break;
  223. case MMACTION_STOP:
  224. {
  225. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_STOP,0),0);
  226. }
  227. break;
  228. case MMACTION_UNLOADMEDIA: //"eject"
  229. {
  230. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_EJECT,0),0);
  231. }
  232. break;
  233. case MMACTION_NEXTTRACK:
  234. {
  235. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_NEXTTRACK,0),0);
  236. }
  237. break;
  238. case MMACTION_PREVTRACK:
  239. {
  240. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_PREVTRACK,0),0);
  241. }
  242. break;
  243. case MMACTION_PAUSE:
  244. {
  245. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_PAUSE,0),0);
  246. }
  247. break;
  248. case MMACTION_REWIND:
  249. {
  250. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_SKIPBACK,0),0);
  251. }
  252. break;
  253. case MMACTION_FFWD:
  254. {
  255. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_SKIPFORE,0),0);
  256. }
  257. break;
  258. case MMACTION_NEXTMEDIA:
  259. {
  260. SendMessage(m_hwndMain,WM_COMMAND,MAKEWPARAM(IDM_PLAYBAR_EJECT,0),0);
  261. }
  262. break;
  263. case MMACTION_GETMEDIAID:
  264. {
  265. MMMEDIAID* pID = (MMMEDIAID*)pAction;
  266. if (pID->nDrive == -1)
  267. {
  268. pID->nDrive = g_CurrCdrom;
  269. }
  270. wsprintf( pID->szMediaID, g_szSectionF, g_Devices[pID->nDrive]->CdInfo.Id );
  271. pID->dwMediaID = g_Devices[pID->nDrive]->CdInfo.Id;
  272. pID->dwNumTracks = NUMTRACKS(pID->nDrive);
  273. _tcscpy(pID->szArtist,ARTIST(pID->nDrive));
  274. _tcscpy(pID->szTitle,TITLE(pID->nDrive));
  275. PTRACK_INF t;
  276. if (CURRTRACK(pID->nDrive)!=NULL)
  277. {
  278. t = FindTrackNodeFromTocIndex( CURRTRACK(pID->nDrive)->TocIndex, ALLTRACKS( pID->nDrive ) );
  279. if (t)
  280. {
  281. _tcscpy(pID->szTrack,t->name);
  282. }
  283. }
  284. }
  285. break;
  286. case MMACTION_GETNETQUERY:
  287. {
  288. MMNETQUERY* pQuery = (MMNETQUERY*)pAction;
  289. if (pQuery->nDrive == -1)
  290. {
  291. pQuery->nDrive = g_CurrCdrom;
  292. }
  293. GetTOC(pQuery->nDrive,pQuery->szNetQuery);
  294. }
  295. break;
  296. case MMACTION_READSETTINGS :
  297. {
  298. ReadSettings((void*)pAction);
  299. UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_TRACK_TIME |
  300. DISPLAY_UPD_TRACK_NAME );
  301. }
  302. break;
  303. case MMACTION_GETTRACKINFO :
  304. {
  305. LPMMTRACKORDISC pInfo = (LPMMTRACKORDISC)pAction;
  306. return (GetTrackInfo(pInfo));
  307. }
  308. break;
  309. case MMACTION_GETDISCINFO :
  310. {
  311. LPMMTRACKORDISC pInfo = (LPMMTRACKORDISC)pAction;
  312. return (GetDiscInfo(pInfo));
  313. }
  314. break;
  315. case MMACTION_SETTRACK :
  316. {
  317. LPMMCHANGETRACK pTrack = (LPMMCHANGETRACK)pAction;
  318. SetTrack(pTrack->nNewTrack);
  319. }
  320. break;
  321. case MMACTION_SETDISC :
  322. {
  323. LPMMCHANGEDISC pDisc = (LPMMCHANGEDISC)pAction;
  324. SetDisc(pDisc->nNewDisc);
  325. }
  326. break;
  327. default:
  328. {
  329. hr = E_NOTIMPL;
  330. }
  331. break;
  332. }
  333. return hr;
  334. }
  335. //QueryVolumeSupport is just a helper function ... you don't have to do it this way
  336. STDMETHODIMP CCDPlay::QueryVolumeSupport(BOOL* pVolume, BOOL* pPan)
  337. {
  338. *pVolume = FALSE;
  339. *pPan = FALSE;
  340. return S_OK;
  341. }
  342. //InitIcons is just a helper function ... you don't have to do it this way
  343. void CCDPlay::InitIcons()
  344. {
  345. m_hIcon16 = NULL;
  346. m_hIcon32 = NULL;
  347. m_hIcon16 = (HICON)LoadImage(g_dllInst, MAKEINTRESOURCE(IDI_ICON_CDPLAY), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  348. m_hIcon32 = LoadIcon(g_dllInst, MAKEINTRESOURCE(IDI_ICON_CDPLAY));
  349. }
  350. /*
  351. * NormalizeNameForMenuDisplay
  352. This function turns a string like "Twist & Shout" into
  353. "Twist && Shout" because otherwise it will look like
  354. "Twist _Shout" in the menu due to the accelerator char
  355. */
  356. void CCDPlay::NormalizeNameForMenuDisplay(TCHAR* szInput, TCHAR* szOutput, DWORD cbLen)
  357. {
  358. ZeroMemory(szOutput,cbLen);
  359. WORD index1 = 0;
  360. WORD index2 = 0;
  361. for (; index1 < _tcslen(szInput); index1++)
  362. {
  363. szOutput[index2] = szInput[index1];
  364. if (szOutput[index2] == TEXT('&'))
  365. {
  366. szOutput[++index2] = TEXT('&');
  367. }
  368. index2++;
  369. }
  370. }
  371. //try to find and return the track info referenced by pInfo->nNumber
  372. HRESULT CCDPlay::GetTrackInfo(LPMMTRACKORDISC pInfo)
  373. {
  374. HRESULT hr = E_FAIL;
  375. if (pInfo)
  376. {
  377. int index = -1;
  378. PTRACK_PLAY playlist;
  379. for( playlist = SAVELIST(g_CurrCdrom);
  380. playlist != NULL;
  381. playlist = playlist->nextplay )
  382. {
  383. index++;
  384. PTRACK_INF t = NULL;
  385. t = FindTrackNodeFromTocIndex( playlist->TocIndex, ALLTRACKS( g_CurrCdrom ) );
  386. if ((t) && (index == pInfo->nNumber))
  387. {
  388. int mtemp, stemp;
  389. FigureTrackTime(g_CurrCdrom, t->TocIndex, &mtemp, &stemp );
  390. TCHAR szDisplayTrack[TRACK_TITLE_LENGTH*2];
  391. NormalizeNameForMenuDisplay(t->name,szDisplayTrack,sizeof(szDisplayTrack));
  392. wsprintf(pInfo->szName,TEXT("%i. %s (%i%s%02i)"),t->TocIndex + 1,szDisplayTrack,mtemp,g_szTimeSep,stemp);
  393. pInfo->nID = t->TocIndex;
  394. if (playlist->TocIndex == CURRTRACK(g_CurrCdrom)->TocIndex)
  395. {
  396. pInfo->fCurrent = TRUE;
  397. }
  398. else
  399. {
  400. pInfo->fCurrent = FALSE;
  401. }
  402. hr = S_OK; //indicate that indexed track was found
  403. } //end if track ok
  404. } //end stepping
  405. } //end if pinfo valid
  406. return (hr);
  407. }
  408. HRESULT CCDPlay::GetDiscInfo(LPMMTRACKORDISC pInfo)
  409. {
  410. HRESULT hr = E_FAIL;
  411. if (pInfo)
  412. {
  413. for(int i = 0; i < g_NumCdDevices; i++)
  414. {
  415. if (i == pInfo->nNumber)
  416. {
  417. TCHAR szDisplayTitle[TITLE_LENGTH*2];
  418. NormalizeNameForMenuDisplay(TITLE(i),szDisplayTitle,sizeof(szDisplayTitle));
  419. TCHAR szDisplayArtist[ARTIST_LENGTH*2];
  420. NormalizeNameForMenuDisplay(ARTIST(i),szDisplayArtist,sizeof(szDisplayArtist));
  421. if (g_Devices[i]->State & (CD_BEING_SCANNED | CD_NO_CD | CD_DATA_CD_LOADED | CD_IN_USE))
  422. {
  423. wsprintf(pInfo->szName,TEXT("<%c:> %s"),g_Devices[i]->drive,szDisplayTitle);
  424. }
  425. else
  426. {
  427. wsprintf(pInfo->szName,TEXT("<%c:> %s (%s)"),
  428. g_Devices[i]->drive,szDisplayTitle,szDisplayArtist);
  429. }
  430. pInfo->nID = i;
  431. if (i == g_CurrCdrom)
  432. {
  433. pInfo->fCurrent = TRUE;
  434. }
  435. else
  436. {
  437. pInfo->fCurrent = FALSE;
  438. }
  439. hr = S_OK;
  440. } //end if match
  441. } //end for
  442. } //end if pinfo valid
  443. return (hr);
  444. }
  445. void CCDPlay::SetTrack(int nTrack)
  446. {
  447. PTRACK_INF tr;
  448. tr = ALLTRACKS( g_CurrCdrom );
  449. if ( tr != NULL )
  450. {
  451. PTRACK_PLAY trCurrent = CURRTRACK(g_CurrCdrom);
  452. tr = FindTrackNodeFromTocIndex(nTrack,ALLTRACKS(g_CurrCdrom));
  453. if (tr->TocIndex != trCurrent->TocIndex)
  454. {
  455. PTRACK_PLAY p = NULL;
  456. for (p = PLAYLIST(g_CurrCdrom); (p!=NULL) && (p->TocIndex != tr->TocIndex); p = p->nextplay);
  457. if (p)
  458. {
  459. TimeAdjustSkipToTrack( g_CurrCdrom, p );
  460. } //if not null
  461. } //if not equal to current
  462. } //if tr not null
  463. }
  464. void CCDPlay::SetDisc(int nDisc)
  465. {
  466. SwitchToCdrom(nDisc, FALSE);
  467. MMONDISCCHANGED mmOnDisc;
  468. mmOnDisc.nNewDisc = g_CurrCdrom;
  469. mmOnDisc.fDisplayVolChange = TRUE;
  470. g_pSink->OnEvent(MMEVENT_ONDISCCHANGED,&mmOnDisc);
  471. }
  472. extern "C"
  473. HRESULT WINAPI CDPLAY_CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void ** ppvObj)
  474. {
  475. CCDPlay* pObj;
  476. HRESULT hr = E_OUTOFMEMORY;
  477. *ppvObj = NULL;
  478. if (NULL!=pUnkOuter && IID_IUnknown!=riid)
  479. {
  480. return CLASS_E_NOAGGREGATION;
  481. }
  482. pObj = new CCDPlay();
  483. if (NULL==pObj)
  484. {
  485. return hr;
  486. }
  487. hr = pObj->QueryInterface(riid, ppvObj);
  488. if (FAILED(hr))
  489. {
  490. delete pObj;
  491. }
  492. return hr;
  493. }