Windows NT 4.0 source code leak
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.

5617 lines
128 KiB

4 years ago
  1. /******************************Module*Header*******************************\
  2. * Module Name: cdplayer.c
  3. *
  4. * CD Playing application
  5. *
  6. *
  7. * Created: 02-11-93
  8. * Author: Stephen Estrop [StephenE]
  9. *
  10. * Copyright (c) 1993 - 1995 Microsoft Corporation. All rights reserved.
  11. \**************************************************************************/
  12. #pragma warning( once : 4201 4214 )
  13. #include <windows.h> /* required for all Windows applications */
  14. #include <shellapi.h>
  15. #include <windowsx.h>
  16. #include <ole2.h>
  17. #include <shlobj.h>
  18. #include <dbt.h>
  19. #define NOMENUHELP
  20. #define NOBTNLIST
  21. #define NOTRACKBAR
  22. #define NODRAGLIST
  23. #define NOUPDOWN
  24. #include <commctrl.h> /* want toolbar and status bar */
  25. #include <string.h>
  26. #include <stdio.h>
  27. #include <tchar.h> /* contains portable ascii/unicode macros */
  28. #include <stdarg.h>
  29. #include <stdlib.h>
  30. #define GLOBAL /* This allocates storage for the public globals */
  31. #include "resource.h"
  32. #include "cdplayer.h"
  33. #include "ledwnd.h"
  34. #include "cdapi.h"
  35. #include "scan.h"
  36. #include "trklst.h"
  37. #include "database.h"
  38. #include "commands.h"
  39. #include "buttons.h"
  40. #include "preferen.h"
  41. #include "literals.h"
  42. //#ifndef WM_CDPLAYER_COPYDATA
  43. #define WM_CDPLAYER_COPYDATA (WM_USER+0x100)
  44. //#endif
  45. /* -------------------------------------------------------------------------
  46. ** Private functions
  47. ** -------------------------------------------------------------------------
  48. */
  49. void
  50. StartSndVol(
  51. DWORD unused
  52. );
  53. int
  54. CopyWord(
  55. TCHAR *szWord,
  56. TCHAR *szSource
  57. );
  58. void
  59. AppendTrackToPlayList(
  60. PTRACK_PLAY pHead,
  61. PTRACK_PLAY pInsert
  62. );
  63. BOOL
  64. IsTrackFileNameValid(
  65. LPTSTR lpstFileName,
  66. int *piCdRomIndex,
  67. int *piTrackIndex,
  68. BOOL fScanningTracks,
  69. BOOL fQuiet
  70. );
  71. TCHAR *
  72. ParseTrackList(
  73. TCHAR *szTrackList,
  74. int *piCdRomIndex
  75. );
  76. int
  77. ParseCommandLine(
  78. LPTSTR lpstr,
  79. int *piTrackToSeekTo,
  80. BOOL fQuiet
  81. );
  82. void
  83. HandlePassedCommandLine(
  84. LPTSTR lpCmdLine,
  85. BOOL fCheckCDRom
  86. );
  87. int
  88. FindMostSuitableDrive(
  89. void
  90. );
  91. void
  92. AskUserToInsertCorrectDisc(
  93. DWORD dwID
  94. );
  95. #ifndef USE_IOCTLS
  96. BOOL CheckMCICDA (TCHAR chDrive);
  97. #endif // ! USE_IOCTLS
  98. BOOL
  99. CDPlay_CopyData(
  100. HWND hwnd,
  101. PCOPYDATASTRUCT lpcpds
  102. );
  103. /* -------------------------------------------------------------------------
  104. ** Private Globals
  105. ** -------------------------------------------------------------------------
  106. */
  107. RECT rcToolbar;
  108. RECT rcStatusbar;
  109. RECT rcTrackInfo;
  110. RECT rcControls[NUM_OF_CONTROLS];
  111. long cyTrackInfo;
  112. int cyMenuCaption;
  113. HICON hIconCdPlayer;
  114. HBRUSH g_hBrushBkgd;
  115. BOOL g_fTitlebarShowing = TRUE;
  116. BOOL g_fVolumeController;
  117. BOOL g_fTrackInfoVisible = 1;
  118. TCHAR g_szTimeSep[10];
  119. int g_AcceleratorCount;
  120. BOOL g_fInCopyData = FALSE;
  121. CRITICAL_SECTION g_csTOCSerialize;
  122. //---------------------------------------------------------------------------
  123. // Stuff required to make drag/dropping of a shortcut file work on Chicago
  124. //---------------------------------------------------------------------------
  125. BOOL
  126. ResolveLink(
  127. TCHAR * szFileName
  128. );
  129. BOOL g_fOleInitialized = FALSE;
  130. void CALLBACK
  131. ToolTipsTimerFunc(
  132. HWND hwnd,
  133. UINT uMsg,
  134. UINT idEvent,
  135. DWORD dwTime
  136. );
  137. WNDPROC g_lpfnToolTips;
  138. #define TOOLTIPS_TIMER_ID 0x5236
  139. #define TOOLTIPS_TIMER_LEN 150
  140. TBBUTTON tbButtons[DEFAULT_TBAR_SIZE] = {
  141. { IDX_SEPARATOR, 1, 0, TBSTYLE_SEP },
  142. { IDX_1, IDM_DATABASE_EDIT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0,0, 0, -1 },
  143. { IDX_SEPARATOR, 2, 0, TBSTYLE_SEP },
  144. { IDX_2, IDM_TIME_REMAINING, TBSTATE_CHECKED | TBSTATE_ENABLED, TBSTYLE_CHECK | TBSTYLE_GROUP, 0,0, 0, -1 },
  145. { IDX_3, IDM_TRACK_REMAINING, TBSTATE_ENABLED, TBSTYLE_CHECK | TBSTYLE_GROUP, 0,0, 0, -1 },
  146. { IDX_4, IDM_DISC_REMAINING, TBSTATE_ENABLED, TBSTYLE_CHECK | TBSTYLE_GROUP, 0,0, 0, -1 },
  147. { IDX_SEPARATOR, 3, 0, TBSTYLE_SEP },
  148. { IDX_5, IDM_OPTIONS_RANDOM, TBSTATE_ENABLED, TBSTYLE_CHECK, 0,0, 0, -1 },
  149. { IDX_6, IDM_OPTIONS_MULTI, TBSTATE_ENABLED, TBSTYLE_CHECK, 0,0, 0, -1 },
  150. { IDX_7, IDM_OPTIONS_CONTINUOUS, TBSTATE_ENABLED, TBSTYLE_CHECK, 0,0, 0, -1 },
  151. { IDX_8, IDM_OPTIONS_INTRO, TBSTATE_ENABLED, TBSTYLE_CHECK, 0,0, 0, -1 }
  152. };
  153. BITMAPBTN tbPlaybar[] = {
  154. { IDX_1, IDM_PLAYBAR_PLAY, 0 },
  155. { IDX_2, IDM_PLAYBAR_PAUSE, 0 },
  156. { IDX_3, IDM_PLAYBAR_STOP, 0 },
  157. { IDX_4, IDM_PLAYBAR_PREVTRACK, 0 },
  158. { IDX_5, IDM_PLAYBAR_SKIPBACK, 0 },
  159. { IDX_6, IDM_PLAYBAR_SKIPFORE, 0 },
  160. { IDX_7, IDM_PLAYBAR_NEXTTRACK, 0 },
  161. { IDX_8, IDM_PLAYBAR_EJECT, 0 }
  162. };
  163. /*
  164. ** these values are defined by the UI gods...
  165. */
  166. const int dxButton = 24;
  167. const int dyButton = 22;
  168. const int dxBitmap = 16;
  169. const int dyBitmap = 16;
  170. const int xFirstButton = 8;
  171. /* -------------------------------------------------------------------------
  172. ** Try to prevent multiple cdplayers
  173. ** -------------------------------------------------------------------------
  174. */
  175. #pragma data_seg(".sdata")
  176. int g_iInUse = -1;
  177. #pragma data_seg()
  178. /******************************Public*Routine******************************\
  179. * WinMain
  180. *
  181. *
  182. * Windows recognizes this function by name as the initial entry point
  183. * for the program. This function calls the application initialization
  184. * routine, if no other instance of the program is running, and always
  185. * calls the instance initialization routine. It then executes a message
  186. * retrieval and dispatch loop that is the top-level control structure
  187. * for the remainder of execution. The loop is terminated when a WM_QUIT
  188. * message is received, at which time this function exits the application
  189. * instance by returning the value passed by PostQuitMessage().
  190. *
  191. * If this function must abort before entering the message loop, it
  192. * returns the conventional value NULL.
  193. *
  194. *
  195. * History:
  196. * 18-11-93 - StephenE - Created
  197. *
  198. \**************************************************************************/
  199. int PASCAL
  200. WinMain(
  201. HINSTANCE hInstance,
  202. HINSTANCE hPrevInstance,
  203. LPSTR lpCmdLine,
  204. int nCmdShow
  205. )
  206. {
  207. MSG msg;
  208. BOOL fFirstInstance = (InterlockedIncrement( &g_iInUse ) == 0);
  209. HACCEL hAccel;
  210. #ifdef DBG
  211. /*
  212. ** This removes the Gdi batch feature. It ensures that the screen
  213. ** is updated after every gdi call - very useful for debugging.
  214. */
  215. GdiSetBatchLimit(1);
  216. #endif
  217. /*
  218. ** Save the instance handle in static variable, which will be used in
  219. ** many subsequence calls from this application to Windows.
  220. */
  221. g_hInst = hInstance;
  222. g_lpCmdLine = lpCmdLine;
  223. /*
  224. ** If CDPlayer is already running try to bring it to the top.
  225. ** If we can't find its window it probably means that the it has
  226. ** either crashed or not got around to creating it yet.
  227. */
  228. if ( !fFirstInstance ) {
  229. CdPlayerAlreadyRunning();
  230. if (g_fOleInitialized) {
  231. OleUninitialize();
  232. }
  233. InterlockedDecrement( &g_iInUse );
  234. return FALSE;
  235. }
  236. InitializeCriticalSection (&g_csTOCSerialize);
  237. /*
  238. ** Initialize the cdplayer application.
  239. */
  240. CdPlayerStartUp();
  241. /*
  242. ** If the "-Play" command line option was specified we need to start
  243. ** minimized and non active.
  244. */
  245. if (IsPlayOptionGiven( GetCommandLine() )) {
  246. nCmdShow = SW_SHOWMINNOACTIVE;
  247. }
  248. /*
  249. ** Try to load the accelerator table for the app
  250. */
  251. hAccel = LoadAccelerators( hInstance, MAKEINTRESOURCE(IDR_ACCELTABLE) );
  252. /*
  253. ** Make the window visible; update its client area
  254. */
  255. ShowWindow( g_hwndApp, nCmdShow );
  256. UpdateWindow( g_hwndApp );
  257. /*
  258. ** Acquire and dispatch messages until a WM_QUIT message is received.
  259. */
  260. while ( GetMessage( &msg, NULL, 0, 0 ) ) {
  261. if ( hAccel && TranslateAccelerator(g_hwndApp, hAccel, &msg) ) {
  262. continue;
  263. }
  264. if ( !IsDialogMessage( g_hwndApp, &msg ) ) {
  265. TranslateMessage( &msg );
  266. DispatchMessage( &msg );
  267. }
  268. }
  269. // Cleanup
  270. DeleteCriticalSection (&g_csTOCSerialize);
  271. if (g_fOleInitialized) {
  272. OleUninitialize();
  273. }
  274. InterlockedDecrement( &g_iInUse );
  275. return msg.wParam;
  276. }
  277. /*****************************Private*Routine******************************\
  278. * InitInstance
  279. *
  280. *
  281. * This function is called at initialization time for every instance of
  282. * this application. This function performs initialization tasks that
  283. * cannot be shared by multiple instances.
  284. *
  285. * In this case, we save the instance handle in a static variable and
  286. * create and display the main program window.
  287. *
  288. * History:
  289. * 18-11-93 - StephenE - Created
  290. *
  291. \**************************************************************************/
  292. BOOL
  293. InitInstance(
  294. HANDLE hInstance
  295. )
  296. {
  297. HWND hwnd;
  298. WNDCLASS cls;
  299. /*
  300. ** Load in some strings
  301. */
  302. _tcscpy( g_szArtistTxt, IdStr( STR_HDR_ARTIST ) );
  303. _tcscpy( g_szTitleTxt, IdStr( STR_HDR_TITLE ) );
  304. _tcscpy( g_szUnknownTxt, IdStr( STR_UNKNOWN ) );
  305. _tcscpy( g_szTrackTxt, IdStr( STR_HDR_TRACK ) );
  306. g_szTimeSep[0] = TEXT(':');
  307. g_szTimeSep[1] = g_chNULL;
  308. GetLocaleInfo( GetUserDefaultLCID(), LOCALE_STIME, g_szTimeSep, 10 );
  309. /*
  310. ** Load the applications icon
  311. */
  312. hIconCdPlayer = LoadIcon( hInstance, MAKEINTRESOURCE(IDR_CDPLAYER_ICON) );
  313. g_hbmTrack = LoadBitmap( hInstance, MAKEINTRESOURCE(IDR_TRACK) );
  314. CheckSysColors();
  315. /*
  316. ** Initialize the my classes. We do this here because the dialog
  317. ** that we are about to create contains two windows on my class.
  318. ** The dialog would fail to be created if the classes was not registered.
  319. */
  320. g_fDisplayT = TRUE;
  321. InitLEDClass( g_hInst );
  322. Init_SJE_TextClass( g_hInst );
  323. cls.lpszClassName = g_szSJE_CdPlayerClass;
  324. cls.hCursor = LoadCursor(NULL, IDC_ARROW);
  325. cls.hIcon = hIconCdPlayer;
  326. cls.lpszMenuName = NULL;
  327. cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  328. cls.hInstance = hInstance;
  329. cls.style = CS_DBLCLKS;
  330. cls.lpfnWndProc = DefDlgProc;
  331. cls.cbClsExtra = 0;
  332. cls.cbWndExtra = DLGWINDOWEXTRA;
  333. if ( !RegisterClass(&cls) ) {
  334. return FALSE;
  335. }
  336. /*
  337. ** Create a main window for this application instance.
  338. */
  339. hwnd = CreateDialog( g_hInst, MAKEINTRESOURCE(IDR_CDPLAYER),
  340. (HWND)NULL, MainWndProc );
  341. /*
  342. ** If window could not be created, return "failure"
  343. */
  344. if ( !hwnd ) {
  345. return FALSE;
  346. }
  347. g_hwndApp = hwnd;
  348. return TRUE;
  349. }
  350. /*****************************Private*Routine******************************\
  351. * CdPlayerAlreadyRunning
  352. *
  353. *
  354. *
  355. * History:
  356. * dd-mm-95 - StephenE - Created
  357. *
  358. \**************************************************************************/
  359. void
  360. CdPlayerAlreadyRunning(
  361. void
  362. )
  363. {
  364. COPYDATASTRUCT cpds;
  365. HWND hwndFind;
  366. DWORD dwForeGndThreadID = 0L;
  367. HWND hwndForeGnd;
  368. hwndFind = FindWindow( g_szSJE_CdPlayerClass, NULL );
  369. /*
  370. ** If the foreground window is an instance of cdplayer don't
  371. ** forward the command line to it. This just confuses the user
  372. ** as his app suddenly starts play without him pressing play.
  373. ** This is only a problem on Chicago when the user inserts a
  374. ** a new disc into the drive.
  375. */
  376. hwndForeGnd = GetForegroundWindow();
  377. if (hwndForeGnd != NULL) {
  378. dwForeGndThreadID = GetWindowThreadProcessId(hwndForeGnd, NULL);
  379. }
  380. if ( (hwndFind != NULL) &&
  381. (IsIconic(hwndFind) ||
  382. GetWindowThreadProcessId(hwndFind, NULL) != dwForeGndThreadID) ) {
  383. /*
  384. ** First parse the command line to see if the play command has
  385. ** been specified. If "play" has been specified then don't bother
  386. ** restoring the other instance of CDPlayer.
  387. */
  388. if (! IsPlayOptionGiven( GetCommandLine() )) {
  389. hwndFind = GetLastActivePopup( hwndFind );
  390. if ( IsIconic( hwndFind ) ) {
  391. ShowWindow( hwndFind, SW_RESTORE );
  392. }
  393. BringWindowToTop( hwndFind );
  394. SetForegroundWindow( hwndFind );
  395. }
  396. /*
  397. ** Now transfer our command line to the other instance of
  398. ** CDPlayer. We don't do any track/disc validation here but
  399. ** rather defer everything to the cdplayer that is already running.
  400. */
  401. cpds.dwData = 0L;
  402. cpds.cbData = (_tcslen(GetCommandLine()) + 1) * sizeof(TCHAR);
  403. cpds.lpData = AllocMemory(cpds.cbData);
  404. if (cpds.lpData == NULL) {
  405. // Error - not enough memory to continue
  406. return;
  407. }
  408. _tcscpy((LPTSTR)cpds.lpData, GetCommandLine());
  409. SendMessage(hwndFind, WM_COPYDATA, 0, (LPARAM)(LPVOID)&cpds);
  410. LocalFree((HLOCAL)cpds.lpData);
  411. }
  412. else if (hwndFind != NULL) {
  413. UINT cch, cchInsert;
  414. UINT cchCmd, cchUpdate;
  415. LPTSTR lpstr;
  416. // Tell primary instance to just update,
  417. // In case this CD was just inserted
  418. cchUpdate = _tcslen (g_szUpdateOption);
  419. cchCmd = _tcslen(GetCommandLine());
  420. cch = cchUpdate + cchCmd;
  421. cpds.dwData = 0L;
  422. cpds.cbData = (cch + 1) * sizeof(TCHAR);
  423. cpds.lpData = AllocMemory(cpds.cbData);
  424. if (cpds.lpData == NULL) {
  425. // Error - not enough memory to continue
  426. return;
  427. }
  428. //
  429. // Insert the -UPDATE option between cdplayer.exe
  430. // parameter and rest of parameters
  431. //
  432. // find insertion point
  433. lpstr = (LPTSTR)GetCommandLine();
  434. cchInsert = _tcsspn(lpstr, g_szBlank);
  435. lpstr += cchInsert;
  436. cchInsert += _tcscspn(lpstr, g_szBlank);
  437. lpstr += cchInsert;
  438. _tcsncpy((LPTSTR)cpds.lpData, GetCommandLine(), cchInsert);
  439. ((LPTSTR)cpds.lpData)[cchInsert] = 0;
  440. _tcscat((LPTSTR)cpds.lpData, g_szUpdateOption);
  441. cchInsert += cchUpdate;
  442. ((LPTSTR)cpds.lpData)[cchInsert] = 0;
  443. _tcscat((LPTSTR)cpds.lpData, lpstr);
  444. SendMessage(hwndFind, WM_COPYDATA, 0, (LPARAM)(LPVOID)&cpds);
  445. LocalFree((HLOCAL)cpds.lpData);
  446. }
  447. }
  448. /*****************************Private*Routine******************************\
  449. * CdPlayerStartUp
  450. *
  451. *
  452. *
  453. * History:
  454. * dd-mm-95 - StephenE - Created
  455. *
  456. \**************************************************************************/
  457. void
  458. CdPlayerStartUp(
  459. void
  460. )
  461. {
  462. /*
  463. ** Reseed random generator
  464. */
  465. srand( GetTickCount() );
  466. /*
  467. ** Set error mode popups for critical errors (like
  468. ** no disc in drive) OFF.
  469. */
  470. SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
  471. /*
  472. ** Scan device chain for CDROM devices... Terminate if none found.
  473. */
  474. g_NumCdDevices = ScanForCdromDevices( );
  475. if ( g_NumCdDevices == 0 ) {
  476. LPTSTR lpstrTitle;
  477. LPTSTR lpstrText;
  478. lpstrTitle = AllocMemory( STR_MAX_STRING_LEN * sizeof(TCHAR) );
  479. lpstrText = AllocMemory( STR_MAX_STRING_LEN * sizeof(TCHAR) );
  480. _tcscpy( lpstrText, IdStr(STR_NO_CDROMS) );
  481. _tcscpy( lpstrTitle, IdStr(STR_CDPLAYER) );
  482. MessageBox( NULL, lpstrText, lpstrTitle,
  483. MB_APPLMODAL | MB_ICONINFORMATION |
  484. MB_OK | MB_SETFOREGROUND );
  485. LocalFree( (HLOCAL)lpstrText );
  486. LocalFree( (HLOCAL)lpstrTitle );
  487. ExitProcess( (UINT)-1 );
  488. }
  489. #ifndef USE_IOCTLS
  490. // Make sure we have a functional MCI (CD Audio)
  491. if (! CheckMCICDA (g_Devices[0]->drive)) {
  492. ExitProcess( (UINT)-1 );
  493. }
  494. #endif // ! USE_IOCTLS
  495. /*
  496. ** Perform initializations that apply to a specific instance
  497. ** This function actually creates the CdPlayer window. (Note that it is
  498. ** not visible yet). If we get here we know that there is a least one
  499. ** cdrom device detected which may have a music cd in it. If it does
  500. ** contain a music cdrom the table of contents will have been read and
  501. ** cd database queryed to determine if the music cd is known. Therefore
  502. ** on the WM_INITDIALOG message we should update the "Artist", "Title" and
  503. ** "Track" fields of the track info display and adjust the enable state
  504. ** of the play buttons.
  505. */
  506. if ( !InitInstance( g_hInst ) ) {
  507. FatalApplicationError( STR_TERMINATE );
  508. }
  509. /*
  510. ** Restore ourselves from the ini file
  511. */
  512. ReadSettings();
  513. /*
  514. ** Scan command the command line. If we were given any valid commandline
  515. ** args we have to adjust the nCmdShow parameter. (ie. start minimized
  516. ** if the user just wants us to play a certain track. ScanCommandLine can
  517. ** overide the default playlist for all the cd-rom devices installed. It
  518. ** modifies the global flag g_fPlay and returns the index of the first
  519. ** CD-Rom that should be played.
  520. */
  521. g_CurrCdrom = g_LastCdrom = 0;
  522. /*
  523. ** Check to see if the volume controller piglett can be found on
  524. ** the path.
  525. */
  526. {
  527. TCHAR chBuffer[8];
  528. LPTSTR lptstr;
  529. g_fVolumeController = (SearchPath( NULL, g_szSndVol32,
  530. NULL, 8, chBuffer, &lptstr ) != 0L);
  531. }
  532. }
  533. /*****************************Private*Routine******************************\
  534. * CompleteCdPlayerStartUp
  535. *
  536. *
  537. *
  538. * History:
  539. * dd-mm-95 - StephenE - Created
  540. *
  541. \**************************************************************************/
  542. void
  543. CompleteCdPlayerStartUp(
  544. void
  545. )
  546. {
  547. int iTrackToSeekTo = -1;
  548. int i;
  549. /*
  550. ** Scan command the command line. If we were given any valid
  551. ** commandline args we have to adjust the nCmdShow parameter. (ie.
  552. ** start minimized if the user just wants us to play a certain
  553. ** track. ScanCommandLine can overide the default playlist for all
  554. ** the cd-rom devices installed. It modifies the global flag
  555. ** g_fPlay and returns the index of the first CD-Rom that should be
  556. ** played.
  557. **
  558. */
  559. g_CurrCdrom = g_LastCdrom = ParseCommandLine( GetCommandLine(),
  560. &iTrackToSeekTo, FALSE );
  561. /*
  562. ** If the message box prompting the user to insert the correct cd disc in
  563. ** the drive was displayed, ParseCommandLine will return -1, in which case
  564. ** find the most suitable drive, also make sure that we don't come up
  565. ** playing.
  566. */
  567. if (g_LastCdrom == -1) {
  568. g_fPlay = FALSE;
  569. g_CurrCdrom = g_LastCdrom = FindMostSuitableDrive();
  570. }
  571. /*
  572. ** If there was no commandline specifed and there is more
  573. ** than one drive available try to select the best drive to make the
  574. ** current drive.
  575. **
  576. ** We should choose the first disc that is playing if any are
  577. ** playing.
  578. **
  579. ** Else we should choose the first disc with a music disk in
  580. ** it if there any drives with music discs in them.
  581. **
  582. ** Else we should chose the first drive that is available if
  583. ** any of the drives are available.
  584. **
  585. ** Else just choose the first (ie. zeroth) drive.
  586. */
  587. if (g_lpCmdLine && !*g_lpCmdLine && g_NumCdDevices > 1) {
  588. g_CurrCdrom = g_LastCdrom = FindMostSuitableDrive();
  589. }
  590. for ( i = 0; i < g_NumCdDevices; i++) {
  591. TimeAdjustInitialize( i );
  592. }
  593. /*
  594. ** All the rescan threads are either dead or in the act of dying.
  595. ** It is now safe to initalize the time information for each
  596. ** cdrom drive.
  597. */
  598. if ( iTrackToSeekTo != -1 ) {
  599. PTRACK_PLAY tr;
  600. tr = PLAYLIST( g_CurrCdrom );
  601. if ( tr != NULL ) {
  602. for( i = 0; i < iTrackToSeekTo; i++, tr = tr->nextplay );
  603. TimeAdjustSkipToTrack( g_CurrCdrom, tr );
  604. }
  605. }
  606. /*
  607. ** if we are in random mode, then we need to shuffle the play lists.
  608. */
  609. if (!g_fSelectedOrder) {
  610. ComputeAndUseShufflePlayLists();
  611. }
  612. SetPlayButtonsEnableState();
  613. /*
  614. ** Start the heart beat time. This timer is responsible for:
  615. ** 1. detecting new or ejected cdroms.
  616. ** 2. flashing the LED display if we are in paused mode.
  617. ** 3. Incrementing the LED display if we are in play mode.
  618. */
  619. SetTimer( g_hwndApp, HEARTBEAT_TIMER_ID, HEARTBEAT_TIMER_RATE,
  620. HeartBeatTimerProc );
  621. if ( g_fPlay ) {
  622. CdPlayerPlayCmd();
  623. }
  624. /*
  625. ** Make sure that the focus is on a suitable control
  626. */
  627. if (g_State & (CD_NO_CD | CD_DATA_CD_LOADED)) {
  628. SetFocus( g_hwndControls[INDEX(IDM_PLAYBAR_EJECT)] );
  629. }
  630. else if ((g_State & CD_IN_USE) == 0) {
  631. if (g_State & (CD_PLAYING | CD_PAUSED)) {
  632. SetFocus( g_hwndControls[INDEX(IDM_PLAYBAR_PAUSE)] );
  633. }
  634. else {
  635. SetFocus( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)] );
  636. }
  637. }
  638. }
  639. /******************************Public*Routine******************************\
  640. * MainWndProc
  641. *
  642. * Use the message crackers to dispatch the dialog messages to appropirate
  643. * message handlers. The message crackers are portable between 16 and 32
  644. * bit versions of Windows.
  645. *
  646. * History:
  647. * 18-11-93 - StephenE - Created
  648. *
  649. \**************************************************************************/
  650. BOOL CALLBACK
  651. MainWndProc(
  652. HWND hwnd,
  653. UINT message,
  654. WPARAM wParam,
  655. LPARAM lParam
  656. )
  657. {
  658. switch ( message ) {
  659. HANDLE_MSG( hwnd, WM_INITDIALOG, CDPlay_OnInitDialog );
  660. HANDLE_MSG( hwnd, WM_INITMENUPOPUP, CDPlay_OnInitMenuPopup );
  661. HANDLE_MSG( hwnd, WM_SYSCOLORCHANGE, CDPlay_OnSysColorChange );
  662. HANDLE_MSG( hwnd, WM_DRAWITEM, CDPlay_OnDrawItem );
  663. HANDLE_MSG( hwnd, WM_COMMAND, CDPlay_OnCommand );
  664. HANDLE_MSG( hwnd, WM_DESTROY, CDPlay_OnDestroy );
  665. HANDLE_MSG( hwnd, WM_SIZE, CDPlay_OnSize );
  666. HANDLE_MSG( hwnd, WM_ENDSESSION, CDPlay_OnEndSession );
  667. HANDLE_MSG( hwnd, WM_WININICHANGE, CDPlay_OnWinIniChange );
  668. HANDLE_MSG( hwnd, WM_CTLCOLORSTATIC, Common_OnCtlColor );
  669. HANDLE_MSG( hwnd, WM_CTLCOLORDLG, Common_OnCtlColor );
  670. HANDLE_MSG( hwnd, WM_MEASUREITEM, Common_OnMeasureItem );
  671. HANDLE_MSG( hwnd, WM_NOTIFY, CDPlay_OnNotify );
  672. HANDLE_MSG( hwnd, WM_MENUSELECT, CDPlay_OnMenuSelect );
  673. HANDLE_MSG( hwnd, WM_LBUTTONDBLCLK, CDPlay_OnLButtonDown );
  674. HANDLE_MSG( hwnd, WM_NCHITTEST, CDPlay_OnNCHitTest );
  675. HANDLE_MSG( hwnd, WM_PAINT, CDPlay_OnPaint );
  676. HANDLE_MSG( hwnd, WM_DROPFILES, CDPlay_OnDropFiles );
  677. case WM_DEVICECHANGE:
  678. return CDPlay_OnDeviceChange (hwnd, wParam, lParam);
  679. case WM_ACTIVATEAPP:
  680. if ((BOOL)wParam) {
  681. if (g_State & CD_PLAYING) {
  682. SetFocus( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)] );
  683. }
  684. else {
  685. SetFocus( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)] );
  686. }
  687. }
  688. return 1;
  689. case WM_ERASEBKGND:
  690. return 1;
  691. case WM_CLOSE:
  692. return CDPlay_OnClose(hwnd, FALSE);
  693. case WM_NCLBUTTONDBLCLK:
  694. if (g_fTitlebarShowing) {
  695. return DefWindowProc( hwnd, message, wParam, lParam );
  696. }
  697. return HANDLE_WM_NCLBUTTONDBLCLK( hwnd, wParam, lParam,
  698. CDPlay_OnLButtonDown );
  699. case WM_COPYDATA:
  700. return CDPlay_CopyData( hwnd, (PCOPYDATASTRUCT)lParam );
  701. case WM_CDPLAYER_COPYDATA:
  702. return CDPlay_OnCopyData( hwnd, (PCOPYDATASTRUCT)lParam );
  703. case WM_NOTIFY_TOC_READ:
  704. return CDPlay_OnTocRead( (int)wParam );
  705. default:
  706. return FALSE;
  707. }
  708. }
  709. /*****************************Private*Routine******************************\
  710. * CDPlay_OnInitDialog
  711. *
  712. *
  713. *
  714. * History:
  715. * 18-11-93 - StephenE - Created
  716. *
  717. \**************************************************************************/
  718. BOOL
  719. CDPlay_OnInitDialog(
  720. HWND hwnd,
  721. HWND hwndFocus,
  722. LPARAM lParam
  723. )
  724. {
  725. LOGFONT lf;
  726. int iLogPelsY;
  727. HDC hdc;
  728. int i;
  729. hdc = GetDC( hwnd );
  730. iLogPelsY = GetDeviceCaps( hdc, LOGPIXELSY );
  731. ReleaseDC( hwnd, hdc );
  732. ZeroMemory( &lf, sizeof(lf) );
  733. #ifdef JAPAN
  734. //fix kksuzuka: #2238
  735. lf.lfHeight = (-10 * iLogPelsY) / 72; /* 10pt */
  736. lf.lfWeight = 400; /* normal */
  737. lf.lfCharSet = SHIFTJIS_CHARSET;
  738. #else
  739. lf.lfHeight = (-8 * iLogPelsY) / 72; /* 8pt */
  740. lf.lfWeight = 400; /* normal */
  741. lf.lfCharSet = ANSI_CHARSET;
  742. #endif
  743. lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  744. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  745. lf.lfQuality = PROOF_QUALITY;
  746. lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
  747. _tcscpy( lf.lfFaceName, g_szAppFontName );
  748. g_hDlgFont = CreateFontIndirect(&lf);
  749. #ifdef DAYTONA
  750. if (g_hDlgFont) {
  751. SendDlgItemMessage( hwnd, IDC_ARTIST_NAME,
  752. WM_SETFONT, (WPARAM)(g_hDlgFont), 0L );
  753. SendDlgItemMessage( hwnd, IDC_TITLE_NAME,
  754. WM_SETFONT, (WPARAM)(g_hDlgFont), 0L );
  755. SendDlgItemMessage( hwnd, IDC_TRACK_LIST,
  756. WM_SETFONT, (WPARAM)(g_hDlgFont), 0L );
  757. }
  758. #endif
  759. cyMenuCaption = GetSystemMetrics( SM_CYMENU ) +
  760. GetSystemMetrics( SM_CYCAPTION );
  761. g_hBrushBkgd = CreateSolidBrush( rgbFace );
  762. BtnCreateBitmapButtons( hwnd, g_hInst, IDR_PLAYBAR, BBS_TOOLTIPS,
  763. tbPlaybar, NUM_OF_BUTTONS, 16, 15 );
  764. /*
  765. ** Before I go off creating toolbars and status bars
  766. ** I need to create a list of all the child windows positions
  767. ** so that I can manipulate them when displaying the toolbar,
  768. ** status bar and disk info.
  769. */
  770. EnumChildWindows( hwnd, ChildEnumProc, (LPARAM)hwnd );
  771. AdjustChildButtons(hwnd);
  772. EnumChildWindows( hwnd, ChildEnumProc, (LPARAM)hwnd );
  773. if ( CreateToolbarsAndStatusbar(hwnd) == FALSE ) {
  774. /*
  775. ** No toolbar - no application, simple !
  776. */
  777. FatalApplicationError( STR_FAIL_INIT );
  778. }
  779. DragAcceptFiles( hwnd, TRUE );
  780. /*
  781. ** Initialize and read the TOC for all the detected CD-ROMS
  782. */
  783. SetPlayButtonsEnableState();
  784. for ( i = 0; i < g_NumCdDevices; i++ ) {
  785. ASSERT(g_Devices[i]->State == CD_BEING_SCANNED);
  786. ASSERT(g_Devices[i]->hCd == 0L);
  787. TimeAdjustInitialize( i );
  788. g_Devices[i]->State = CD_NO_CD;
  789. RescanDevice( hwnd, i );
  790. }
  791. return FALSE;
  792. }
  793. #ifdef DAYTONA
  794. /*****************************Private*Routine******************************\
  795. * CDPlay_OnPaint
  796. *
  797. * Paints the hilight under the menu but only if the toolbar is NOT visible.
  798. * I use IsWindowVisible to get the TRUE visiblity status of the toolbar.
  799. *
  800. * History:
  801. * 18-11-93 - StephenE - Created
  802. *
  803. \**************************************************************************/
  804. void
  805. CDPlay_OnPaint(
  806. HWND hwnd
  807. )
  808. {
  809. HDC hdc;
  810. PAINTSTRUCT ps;
  811. RECT rc;
  812. hdc = BeginPaint( hwnd, &ps );
  813. CheckSysColors();
  814. GetClientRect( hwnd, &rc );
  815. if (!IsWindowVisible( g_hwndToolbar)) {
  816. PatB( hdc, 0, 0, rc.right, 1, rgbHilight );
  817. ExcludeClipRect( hdc, 0, 0, rc.right, 1 );
  818. }
  819. if ( ps.fErase ) {
  820. DefWindowProc( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 );
  821. }
  822. EndPaint( hwnd, &ps );
  823. }
  824. #endif
  825. /*****************************Private*Routine******************************\
  826. * CDPlay_OnInitMenuPopup
  827. *
  828. *
  829. * History:
  830. * 18-11-93 - StephenE - Created
  831. *
  832. \**************************************************************************/
  833. void
  834. CDPlay_OnInitMenuPopup(
  835. HWND hwnd,
  836. HMENU hMenu,
  837. UINT item,
  838. BOOL fSystemMenu
  839. )
  840. {
  841. switch ( item ) {
  842. case 0:
  843. /*
  844. ** Do we have a music cd loaded.
  845. */
  846. if (g_State & (CD_BEING_SCANNED | CD_IN_USE | CD_NO_CD | CD_DATA_CD_LOADED)) {
  847. EnableMenuItem(hMenu, IDM_DATABASE_EDIT, MF_GRAYED | MF_BYCOMMAND);
  848. }
  849. else {
  850. EnableMenuItem(hMenu, IDM_DATABASE_EDIT, MF_ENABLED | MF_BYCOMMAND);
  851. }
  852. break;
  853. case 1:
  854. CheckMenuItemIfTrue( hMenu, IDM_VIEW_STATUS, g_fStatusbarVisible );
  855. CheckMenuItemIfTrue( hMenu, IDM_VIEW_TRACKINFO, g_fTrackInfoVisible );
  856. CheckMenuItemIfTrue( hMenu, IDM_VIEW_TOOLBAR, g_fToolbarVisible );
  857. CheckMenuItemIfTrue( hMenu, IDM_TIME_REMAINING, g_fDisplayT );
  858. CheckMenuItemIfTrue( hMenu, IDM_TRACK_REMAINING, g_fDisplayTr );
  859. CheckMenuItemIfTrue( hMenu, IDM_DISC_REMAINING, g_fDisplayDr );
  860. if (g_fVolumeController) {
  861. EnableMenuItem(hMenu, IDM_VIEW_VOLUME, MF_ENABLED | MF_BYCOMMAND);
  862. }
  863. else {
  864. EnableMenuItem(hMenu, IDM_VIEW_VOLUME, MF_GRAYED | MF_BYCOMMAND);
  865. }
  866. break;
  867. case 2:
  868. CheckMenuItemIfTrue( hMenu, IDM_OPTIONS_RANDOM, !g_fSelectedOrder );
  869. //if (g_fMultiDiskAvailable) {
  870. // CheckMenuItemIfTrue( hMenu, IDM_OPTIONS_MULTI, !g_fSingleDisk );
  871. //}
  872. CheckMenuItemIfTrue( hMenu, IDM_OPTIONS_CONTINUOUS, g_fContinuous );
  873. CheckMenuItemIfTrue( hMenu, IDM_OPTIONS_INTRO, g_fIntroPlay );
  874. break;
  875. }
  876. }
  877. /*****************************Private*Routine******************************\
  878. * CDPlay_OnSysColorChange
  879. *
  880. *
  881. *
  882. * History:
  883. * 18-11-93 - StephenE - Created
  884. *
  885. \**************************************************************************/
  886. void
  887. CDPlay_OnSysColorChange(
  888. HWND hwnd
  889. )
  890. {
  891. CheckSysColors();
  892. if (g_hBrushBkgd) {
  893. DeleteObject(g_hBrushBkgd);
  894. g_hBrushBkgd = CreateSolidBrush( rgbFace );
  895. }
  896. BtnUpdateColors( hwnd );
  897. FORWARD_WM_SYSCOLORCHANGE(g_hwndToolbar, SendMessage);
  898. }
  899. /*****************************Private*Routine******************************\
  900. * CDPlay_OnWinIniChange
  901. *
  902. * Updates the time format separator and the LED display
  903. *
  904. * History:
  905. * 29-09-94 - StephenE - Created
  906. *
  907. \**************************************************************************/
  908. void
  909. CDPlay_OnWinIniChange(
  910. HWND hwnd,
  911. LPCTSTR lpszSectionName
  912. )
  913. {
  914. int cy;
  915. RECT rc;
  916. cy = GetSystemMetrics( SM_CYMENU ) + GetSystemMetrics( SM_CYCAPTION );
  917. if ( cy != cyMenuCaption ) {
  918. GetWindowRect( hwnd, &rc );
  919. rc.bottom += cy - cyMenuCaption;
  920. SetWindowPos( hwnd, HWND_TOP, 0, 0,
  921. rc.right - rc.left, rc.bottom - rc.top,
  922. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
  923. cyMenuCaption = cy;
  924. }
  925. GetLocaleInfo( GetUserDefaultLCID(), LOCALE_STIME, g_szTimeSep, 10 );
  926. UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_DISC_TIME | DISPLAY_UPD_TRACK_TIME );
  927. }
  928. /*****************************Private*Routine******************************\
  929. * CDPlay_OnDrawItem
  930. *
  931. *
  932. *
  933. * History:
  934. * 18-11-93 - StephenE - Created
  935. *
  936. \**************************************************************************/
  937. BOOL
  938. CDPlay_OnDrawItem(
  939. HWND hwnd,
  940. const DRAWITEMSTRUCT *lpdis
  941. )
  942. {
  943. int i;
  944. i = INDEX(lpdis->CtlID);
  945. switch (lpdis->CtlType) {
  946. case ODT_BUTTON:
  947. /*
  948. ** See if the fast foreward or backward buttons has been pressed or
  949. ** released. If so execute the seek command here. Do nothing on
  950. ** the WM_COMMAND message.
  951. */
  952. if ( lpdis->CtlID == IDM_PLAYBAR_SKIPBACK
  953. || lpdis->CtlID == IDM_PLAYBAR_SKIPFORE ) {
  954. if (lpdis->itemAction & ODA_SELECT ) {
  955. g_AcceleratorCount = 0;
  956. CdPlayerSeekCmd( hwnd, (lpdis->itemState & ODS_SELECTED),
  957. lpdis->CtlID );
  958. }
  959. }
  960. /*
  961. ** Now draw the button according to the buttons state information.
  962. */
  963. tbPlaybar[i].fsState = LOBYTE(lpdis->itemState);
  964. if (lpdis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) {
  965. BtnDrawButton( hwnd, lpdis->hDC, (int)lpdis->rcItem.right,
  966. (int)lpdis->rcItem.bottom,
  967. &tbPlaybar[i] );
  968. }
  969. else if (lpdis->itemAction & ODA_FOCUS) {
  970. BtnDrawFocusRect(lpdis->hDC, &lpdis->rcItem, lpdis->itemState);
  971. }
  972. return TRUE;
  973. case ODT_COMBOBOX:
  974. if (lpdis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) {
  975. switch (lpdis->CtlID) {
  976. case IDC_ARTIST_NAME:
  977. DrawDriveItem( lpdis->hDC, &lpdis->rcItem,
  978. lpdis->itemData,
  979. (ODS_SELECTED & lpdis->itemState) );
  980. break;
  981. case IDC_TRACK_LIST:
  982. DrawTrackItem( lpdis->hDC, &lpdis->rcItem,
  983. lpdis->itemData,
  984. (ODS_SELECTED & lpdis->itemState) );
  985. break;
  986. }
  987. }
  988. return TRUE;
  989. }
  990. return FALSE;
  991. }
  992. /*****************************Private*Routine******************************\
  993. * CDPlay_OnCommand
  994. *
  995. *
  996. *
  997. * History:
  998. * 18-11-93 - StephenE - Created
  999. *
  1000. \**************************************************************************/
  1001. void
  1002. CDPlay_OnCommand(
  1003. HWND hwnd,
  1004. int id,
  1005. HWND hwndCtl,
  1006. UINT codeNotify
  1007. )
  1008. {
  1009. /*
  1010. ** Comobo box notification ?
  1011. */
  1012. int index, i;
  1013. HWND hwndCtrl;
  1014. PTRACK_PLAY tr;
  1015. switch( id ) {
  1016. case IDC_TRACK_LIST:
  1017. switch (codeNotify) {
  1018. case CBN_SELENDOK:
  1019. hwndCtrl = g_hwndControls[INDEX(IDC_TRACK_LIST)];
  1020. index = SendMessage( hwndCtrl, CB_GETCURSEL, 0, 0L );
  1021. tr = PLAYLIST( g_CurrCdrom );
  1022. if ( tr != NULL ) {
  1023. PTRACK_PLAY trCurrent = CURRTRACK(g_CurrCdrom);
  1024. for( i = 0; tr && (i < index); i++, tr = tr->nextplay );
  1025. if (tr != trCurrent) {
  1026. TimeAdjustSkipToTrack( g_CurrCdrom, tr );
  1027. }
  1028. }
  1029. break;
  1030. case CBN_CLOSEUP:
  1031. {
  1032. // Here we have to check that the track currently playing
  1033. // is actually the same track thats selected in the combo box.
  1034. PTRACK_PLAY trCurrent = CURRTRACK(g_CurrCdrom);
  1035. hwndCtrl = g_hwndControls[INDEX(IDC_TRACK_LIST)];
  1036. index = SendMessage( hwndCtrl, CB_GETCURSEL, 0, 0L );
  1037. tr = PLAYLIST( g_CurrCdrom );
  1038. if (tr != NULL && trCurrent != NULL) {
  1039. for( i = 0; tr && (i < index); i++, tr = tr->nextplay );
  1040. // If tr and trCurrent don't point to the same thing
  1041. // then we need to change the combo boxes selection.
  1042. if ( tr != trCurrent ) {
  1043. for( i = 0, tr = PLAYLIST( g_CurrCdrom );
  1044. tr && tr != trCurrent; i++, tr = tr->nextplay );
  1045. if ( tr != NULL ) {
  1046. ComboBox_SetCurSel( hwndCtrl, i);
  1047. }
  1048. }
  1049. }
  1050. break;
  1051. }
  1052. }
  1053. break;
  1054. case IDC_ARTIST_NAME:
  1055. if (codeNotify == CBN_SELCHANGE) {
  1056. i = g_CurrCdrom;
  1057. hwndCtrl = g_hwndControls[INDEX(IDC_ARTIST_NAME)];
  1058. index = SendMessage( hwndCtrl, CB_GETCURSEL, 0, 0L );
  1059. SwitchToCdrom( index, TRUE );
  1060. SetPlayButtonsEnableState();
  1061. if ( g_CurrCdrom == i ) {
  1062. SendMessage( hwndCtrl, CB_SETCURSEL, (WPARAM)i, 0 );
  1063. }
  1064. }
  1065. break;
  1066. case IDM_VIEW_VOLUME:
  1067. {
  1068. HANDLE hThread;
  1069. DWORD dwThreadId;
  1070. /*
  1071. ** We WinExec sndvol on a separate thread because winexec
  1072. ** is a potentially lengthy call. If we are playing a cd
  1073. ** when we try to start sndvol the LED display freezes
  1074. ** for a short time this looks real ugly.
  1075. */
  1076. hThread = CreateThread( NULL, 0L,
  1077. (LPTHREAD_START_ROUTINE)StartSndVol,
  1078. NULL, 0L, &dwThreadId );
  1079. if ( hThread != INVALID_HANDLE_VALUE ) {
  1080. CloseHandle( hThread );
  1081. }
  1082. }
  1083. break;
  1084. case IDM_VIEW_TOOLBAR:
  1085. ShowToolbar();
  1086. break;
  1087. case IDM_VIEW_STATUS:
  1088. ShowStatusbar();
  1089. break;
  1090. case IDM_VIEW_TRACKINFO:
  1091. ShowTrackInfo();
  1092. break;
  1093. case IDM_OPTIONS_RANDOM:
  1094. if ( LockALLTableOfContents() ) {
  1095. FlipBetweenShuffleAndOrder();
  1096. g_fSelectedOrder = !g_fSelectedOrder;
  1097. }
  1098. break;
  1099. //case IDM_OPTIONS_MULTI:
  1100. //g_fSingleDisk = !g_fSingleDisk;
  1101. //break;
  1102. case IDM_OPTIONS_INTRO:
  1103. g_fIntroPlay = !g_fIntroPlay;
  1104. break;
  1105. case IDM_OPTIONS_CONTINUOUS:
  1106. g_fContinuous = !g_fContinuous;
  1107. break;
  1108. case IDM_OPTIONS_PREFERENCES:
  1109. DialogBox( g_hInst, MAKEINTRESOURCE(IDR_PREFERENCES), hwnd, PreferencesDlgProc );
  1110. break;
  1111. case IDM_TIME_REMAINING:
  1112. g_fDisplayT = TRUE;
  1113. g_fDisplayTr = g_fDisplayDr = FALSE;
  1114. if (codeNotify == 0) {
  1115. UpdateToolbarTimeButtons();
  1116. }
  1117. UpdateDisplay( DISPLAY_UPD_LED );
  1118. break;
  1119. case IDM_TRACK_REMAINING:
  1120. g_fDisplayTr = TRUE;
  1121. g_fDisplayDr = g_fDisplayT = FALSE;
  1122. if (codeNotify == 0) {
  1123. UpdateToolbarTimeButtons();
  1124. }
  1125. UpdateDisplay( DISPLAY_UPD_LED );
  1126. break;
  1127. case IDM_DISC_REMAINING:
  1128. g_fDisplayDr = TRUE;
  1129. g_fDisplayTr = g_fDisplayT = FALSE;
  1130. if (codeNotify == 0) {
  1131. UpdateToolbarTimeButtons();
  1132. }
  1133. UpdateDisplay( DISPLAY_UPD_LED );
  1134. break;
  1135. case IDM_PLAYBAR_EJECT:
  1136. CdPlayerEjectCmd();
  1137. break;
  1138. case IDM_PLAYBAR_PLAY:
  1139. /*
  1140. ** If we currently in PLAY mode and the command came from
  1141. ** a keyboard accelerator then assume that the user really
  1142. ** means Pause. This is because the Ctrl-P key sequence
  1143. ** is a toggle between Play and Paused. codeNotify is 1 when
  1144. ** the WM_COMMAND message came from an accelerator and 0 when
  1145. ** it cam from a menu.
  1146. */
  1147. if ((g_State & CD_PLAYING) && (codeNotify == 1)) {
  1148. CdPlayerPauseCmd();
  1149. }
  1150. else {
  1151. CdPlayerPlayCmd();
  1152. }
  1153. break;
  1154. case IDM_PLAYBAR_PAUSE:
  1155. CdPlayerPauseCmd();
  1156. break;
  1157. case IDM_PLAYBAR_STOP:
  1158. CdPlayerStopCmd();
  1159. break;
  1160. case IDM_PLAYBAR_PREVTRACK:
  1161. CdPlayerPrevTrackCmd();
  1162. break;
  1163. case IDM_PLAYBAR_NEXTTRACK:
  1164. CdPlayerNextTrackCmd();
  1165. break;
  1166. case IDM_DATABASE_EXIT:
  1167. PostMessage( hwnd, WM_CLOSE, 0, 0L );
  1168. break;
  1169. case IDM_DATABASE_EDIT:
  1170. CdDiskInfoDlg();
  1171. break;
  1172. case IDM_HELP_TOPICS:
  1173. WinHelp(hwnd, g_HelpFileName, HELP_FINDER, 0);
  1174. break;
  1175. case IDM_HELP_ABOUT:
  1176. ShellAbout( hwnd, IdStr(STR_CDPLAYER), g_szEmpty, hIconCdPlayer );
  1177. break;
  1178. }
  1179. UpdateToolbarButtons();
  1180. }
  1181. /******************************Public*Routine******************************\
  1182. * CDPlay_OnDestroy
  1183. *
  1184. *
  1185. *
  1186. * History:
  1187. * dd-mm-93 - StephenE - Created
  1188. *
  1189. \**************************************************************************/
  1190. void
  1191. CDPlay_OnDestroy(
  1192. HWND hwnd
  1193. )
  1194. {
  1195. int i;
  1196. for ( i = 0; i < g_NumCdDevices; i++ ) {
  1197. if (g_fStopCDOnExit) {
  1198. if ( g_Devices[i]->State & CD_PLAYING
  1199. || g_Devices[i]->State & CD_PAUSED ) {
  1200. StopTheCdromDrive( i );
  1201. }
  1202. }
  1203. #ifdef USE_IOCTLS
  1204. if ( g_Devices[i]->hCd != NULL ) {
  1205. CloseHandle( g_Devices[i]->hCd );
  1206. }
  1207. #else
  1208. if ( g_Devices[i]->hCd != 0L ) {
  1209. CloseCdRom( g_Devices[i]->hCd );
  1210. g_Devices[i]->hCd = 0L;
  1211. }
  1212. #endif
  1213. LocalFree( (HLOCAL) g_Devices[i] );
  1214. }
  1215. if (g_hBrushBkgd) {
  1216. DeleteObject( g_hBrushBkgd );
  1217. }
  1218. if ( g_hDlgFont ) {
  1219. DeleteObject( g_hDlgFont );
  1220. }
  1221. WinHelp( hwnd, g_HelpFileName, HELP_QUIT, 0 );
  1222. PostQuitMessage( 0 );
  1223. }
  1224. /******************************Public*Routine******************************\
  1225. * CDPlay_OnClose
  1226. *
  1227. *
  1228. *
  1229. * History:
  1230. * dd-mm-93 - StephenE - Created
  1231. *
  1232. \**************************************************************************/
  1233. BOOL
  1234. CDPlay_OnClose(
  1235. HWND hwnd,
  1236. BOOL fShuttingDown
  1237. )
  1238. {
  1239. /*
  1240. ** If we are playing or paused and the brain dead "don't stop playing
  1241. ** on exit" flag set, then we need to tell the user that he is about
  1242. ** to go into stupid mode. Basically CD Player can only perform as expected
  1243. ** if the user has not mucked about with the play list, hasn't put the
  1244. ** app into random mode or intro play mode or continuous play mode or
  1245. ** multi-disc mode.
  1246. */
  1247. if ( !fShuttingDown && !g_fStopCDOnExit
  1248. && (g_State & (CD_PLAYING | CD_PAUSED) ) ) {
  1249. if ( !g_fSelectedOrder || g_fIntroPlay || g_fContinuous
  1250. || !g_fSingleDisk || !PlayListMatchesAvailList() ) {
  1251. TCHAR s1[256];
  1252. TCHAR s2[256];
  1253. int iMsgBoxRtn;
  1254. _tcscpy( s1, IdStr( STR_EXIT_MESSAGE ) );
  1255. _tcscpy( s2, IdStr( STR_CDPLAYER ) );
  1256. iMsgBoxRtn = MessageBox( g_hwndApp, s1, s2,
  1257. MB_APPLMODAL | MB_DEFBUTTON1 |
  1258. MB_ICONQUESTION | MB_YESNO);
  1259. if ( iMsgBoxRtn == IDNO ) {
  1260. return TRUE;
  1261. }
  1262. }
  1263. }
  1264. WriteSettings();
  1265. return DestroyWindow( hwnd );
  1266. }
  1267. /*****************************Private*Routine******************************\
  1268. * CDPlay_OnEndSession
  1269. *
  1270. * If the session is really ending make sure that we stop the CD Player
  1271. * from playing and that all the ini file stuff is saved away.
  1272. *
  1273. * History:
  1274. * dd-mm-93 - StephenE - Created
  1275. *
  1276. \**************************************************************************/
  1277. void
  1278. CDPlay_OnEndSession(
  1279. HWND hwnd,
  1280. BOOL fEnding
  1281. )
  1282. {
  1283. if ( fEnding ) {
  1284. CDPlay_OnClose( hwnd, fEnding );
  1285. }
  1286. }
  1287. /******************************Public*Routine******************************\
  1288. * CDPlay_OnSize
  1289. *
  1290. *
  1291. *
  1292. * History:
  1293. * dd-mm-93 - StephenE - Created
  1294. *
  1295. \**************************************************************************/
  1296. void
  1297. CDPlay_OnSize(
  1298. HWND hwnd,
  1299. UINT state,
  1300. int cx,
  1301. int cy
  1302. )
  1303. {
  1304. if (g_fIsIconic && (state != SIZE_MINIMIZED)) {
  1305. SetWindowText( hwnd, IdStr( STR_CDPLAYER ) );
  1306. }
  1307. g_fIsIconic = (state == SIZE_MINIMIZED);
  1308. if (IsWindow(g_hwndStatusbar)) {
  1309. SendMessage( g_hwndStatusbar, WM_SIZE, 0, 0L );
  1310. }
  1311. if (IsWindow(g_hwndToolbar)) {
  1312. SendMessage( g_hwndToolbar, WM_SIZE, 0, 0L );
  1313. }
  1314. }
  1315. /*****************************Private*Routine******************************\
  1316. * CDPlay_OnNotify
  1317. *
  1318. * Time to display the little tool tips. Also, change the status bar
  1319. * so that it displays a longer version of the tool tip text.
  1320. *
  1321. * History:
  1322. * dd-mm-94 - StephenE - Created
  1323. *
  1324. \**************************************************************************/
  1325. LRESULT
  1326. CDPlay_OnNotify(
  1327. HWND hwnd,
  1328. int idFrom,
  1329. NMHDR *pnmhdr
  1330. )
  1331. {
  1332. switch (pnmhdr->code) {
  1333. case TTN_NEEDTEXT:
  1334. {
  1335. LPTOOLTIPTEXT lpTt;
  1336. LPTSTR lpstr;
  1337. UINT msgId;
  1338. lpTt = (LPTOOLTIPTEXT)pnmhdr;
  1339. msgId = lpTt->hdr.idFrom;
  1340. /*
  1341. ** If we are paused, the pause button will cause the device
  1342. ** to play. So we change the ToolTip text to show "Play"
  1343. ** when the cursor is over "Pause". We should not need to
  1344. ** check that a music CD is loaded because the CD_PAUSED
  1345. ** state can only be set after Play starts.
  1346. */
  1347. if ( (g_State & CD_PAUSED)
  1348. && (msgId == IDM_PLAYBAR_PAUSE || msgId == IDM_PLAYBAR_PLAY)) {
  1349. msgId = IDM_PLAYBAR_RESUME;
  1350. }
  1351. LoadString( g_hInst, msgId, lpTt->szText, sizeof(lpTt->szText) );
  1352. lpstr = IdStr(lpTt->hdr.idFrom + MENU_STRING_BASE);
  1353. if (*lpstr) {
  1354. SendMessage( g_hwndStatusbar, SB_SETTEXT, SBT_NOBORDERS|255,
  1355. (LPARAM)lpstr );
  1356. SendMessage(g_hwndStatusbar, SB_SIMPLE, 1, 0L);
  1357. UpdateWindow(g_hwndStatusbar);
  1358. }
  1359. }
  1360. break;
  1361. }
  1362. return TRUE;
  1363. }
  1364. /*****************************Private*Routine******************************\
  1365. * CDPlay_OnNCHitTest
  1366. *
  1367. * Here we pretend that the client area is really the caption if we are in
  1368. * mini-mode. This allows the user to move the player to a new position.
  1369. *
  1370. * History:
  1371. * dd-mm-94 - StephenE - Created
  1372. *
  1373. \**************************************************************************/
  1374. UINT
  1375. CDPlay_OnNCHitTest(
  1376. HWND hwnd,
  1377. int x,
  1378. int y
  1379. )
  1380. {
  1381. UINT ht = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc );
  1382. if (!g_fTitlebarShowing && (ht == HTCLIENT) ) {
  1383. ht = HTCAPTION;
  1384. }
  1385. SetWindowLong(hwnd, DWL_MSGRESULT, ht);
  1386. return ht;
  1387. }
  1388. /*****************************Private*Routine******************************\
  1389. * CDPlay_OnLButtonDown
  1390. *
  1391. * This function processes the WM_LBUTTONDBLCLK and WM_NCLBUTTONDBLCLK
  1392. * messages. Here we determine if it is possible for CD Player to go
  1393. * into mini-mode or whether CD Player should be restored from min-mode.
  1394. *
  1395. * History:
  1396. * dd-mm-94 - StephenE - Created
  1397. *
  1398. \**************************************************************************/
  1399. void
  1400. CDPlay_OnLButtonDown(
  1401. HWND hwnd,
  1402. BOOL fDoubleClick,
  1403. int x,
  1404. int y,
  1405. UINT keyFlags
  1406. )
  1407. {
  1408. static UINT uID;
  1409. const DWORD dwTransientStyle = (WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX);
  1410. DWORD dwStyle;
  1411. RECT rc;
  1412. int xpos, ypos, dx, dy;
  1413. if (!(g_fToolbarVisible || g_fStatusbarVisible || g_fTrackInfoVisible)) {
  1414. dwStyle = GetWindowLong( hwnd, GWL_STYLE );
  1415. GetWindowRect( hwnd, &rc );
  1416. xpos = rc.left;
  1417. dx = rc.right - rc.left;
  1418. if (g_fTitlebarShowing) {
  1419. dwStyle &= ~dwTransientStyle;
  1420. uID = SetWindowLong( hwnd, GWL_ID, 0 );
  1421. ypos = rc.top + cyMenuCaption;
  1422. dy = (rc.bottom - rc.top) - cyMenuCaption;
  1423. }
  1424. else {
  1425. dwStyle |= dwTransientStyle;
  1426. SetWindowLong( hwnd, GWL_ID, uID );
  1427. ypos = rc.top - cyMenuCaption;
  1428. dy = (rc.bottom - rc.top) + cyMenuCaption;
  1429. }
  1430. if (g_fTitlebarShowing) {
  1431. DWORD dwExStyle;
  1432. dwExStyle = GetWindowLong( hwnd, GWL_EXSTYLE );
  1433. dwExStyle |= WS_EX_WINDOWEDGE;
  1434. SetWindowLong( hwnd, GWL_STYLE, dwStyle );
  1435. SetWindowLong( hwnd, GWL_EXSTYLE, dwExStyle );
  1436. }
  1437. else {
  1438. SetWindowLong( hwnd, GWL_STYLE, dwStyle );
  1439. }
  1440. g_fTitlebarShowing = !g_fTitlebarShowing;
  1441. SetWindowPos( hwnd, NULL, xpos, ypos, dx, dy,
  1442. SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
  1443. }
  1444. }
  1445. BOOL
  1446. CDPlay_CopyData(
  1447. HWND hwnd,
  1448. PCOPYDATASTRUCT lpcpds
  1449. )
  1450. {
  1451. LPTSTR lpCmdLine;
  1452. // Make a copy of the passed command line as we are not supposed
  1453. // to write into the one passed in the WM_COPYDATA message.
  1454. lpCmdLine = AllocMemory( lpcpds->cbData );
  1455. _tcscpy( lpCmdLine, (LPCTSTR)lpcpds->lpData );
  1456. PostMessage (hwnd, WM_CDPLAYER_COPYDATA, 0, (LPARAM)(LPVOID)lpCmdLine);
  1457. return TRUE;
  1458. } // End CopyData
  1459. /*****************************Private*Routine******************************\
  1460. * CDPlay_OnCopyData
  1461. *
  1462. * Handles command lines passed from other intances of CD Player
  1463. *
  1464. * History:
  1465. * dd-mm-94 - StephenE - Created
  1466. *
  1467. \**************************************************************************/
  1468. BOOL
  1469. CDPlay_OnCopyData(
  1470. HWND hwnd,
  1471. PCOPYDATASTRUCT lpcpds
  1472. )
  1473. {
  1474. LPTSTR lpCmdLine;
  1475. BOOL fWasPlaying = FALSE;
  1476. BOOL fUpdate;
  1477. int iTrack = -1;
  1478. int iCdRom;
  1479. // Prevent Re-entrancy while
  1480. // we are opening/closing CD's
  1481. if (g_fInCopyData)
  1482. return FALSE;
  1483. g_fInCopyData = TRUE;
  1484. /*
  1485. ** Make a copy of the passed command line as we are not supposed
  1486. ** to write into the one passed in the WM_COPYDATA message.
  1487. */
  1488. //lpCmdLine = AllocMemory( lpcpds->cbData );
  1489. //_tcscpy( lpCmdLine, (LPCTSTR)lpcpds->lpData );
  1490. lpCmdLine = (LPTSTR)(LPVOID)lpcpds;
  1491. if (lpCmdLine == NULL)
  1492. {
  1493. g_fInCopyData = FALSE;
  1494. return 0L;
  1495. }
  1496. iCdRom = ParseCommandLine( lpCmdLine, &iTrack, FALSE );
  1497. if (iCdRom < 0 && iTrack < 0) {
  1498. LocalFree( (HLOCAL)lpCmdLine );
  1499. g_fInCopyData = FALSE;
  1500. return 0L;
  1501. }
  1502. // Check if it is just an update command?!?
  1503. fUpdate = IsUpdateOptionGiven (lpCmdLine);
  1504. if ((fUpdate) && (iTrack == -1))
  1505. {
  1506. if ((iCdRom >= 0) && (iCdRom < g_NumCdDevices))
  1507. {
  1508. CheckUnitCdrom(iCdRom, TRUE);
  1509. }
  1510. LocalFree( (HLOCAL)lpCmdLine );
  1511. g_fInCopyData = FALSE;
  1512. return 0L;
  1513. }
  1514. /*
  1515. ** Remember our current playing state as we need to temporarly
  1516. ** stop the CD if it is currently playing.
  1517. */
  1518. if ( g_State & (CD_PLAYING | CD_PAUSED) )
  1519. {
  1520. #ifdef DBG
  1521. dprintf("Auto Stopping");
  1522. #endif
  1523. while( !LockALLTableOfContents() )
  1524. {
  1525. MSG msg;
  1526. #if DBG
  1527. dprintf("Busy waiting for TOC to become valid!");
  1528. #endif
  1529. GetMessage( &msg, NULL, WM_NOTIFY_TOC_READ, WM_NOTIFY_TOC_READ );
  1530. DispatchMessage( &msg );
  1531. }
  1532. CdPlayerStopCmd();
  1533. fWasPlaying = TRUE;
  1534. }
  1535. /*
  1536. ** Figure what has been passed and act on it accordingly.
  1537. */
  1538. HandlePassedCommandLine( lpCmdLine, TRUE );
  1539. /*
  1540. ** If we were playing make sure that we are still playing the
  1541. ** new track(s)
  1542. */
  1543. if ( fWasPlaying || g_fPlay )
  1544. {
  1545. #ifdef DBG
  1546. dprintf("Trying to autoplay");
  1547. #endif
  1548. while( !LockTableOfContents(g_CurrCdrom) )
  1549. {
  1550. MSG msg;
  1551. #ifdef DBG
  1552. dprintf("Busy waiting for TOC to become valid!");
  1553. #endif
  1554. GetMessage( &msg, NULL, WM_NOTIFY_TOC_READ, WM_NOTIFY_TOC_READ );
  1555. DispatchMessage( &msg );
  1556. }
  1557. CdPlayerPlayCmd();
  1558. }
  1559. /*
  1560. ** Free the local copy of the command line.
  1561. */
  1562. LocalFree( (HLOCAL)lpCmdLine );
  1563. g_fInCopyData = FALSE;
  1564. return 0L;
  1565. }
  1566. /*****************************Private*Routine******************************\
  1567. * CDPlay_OnTocRead
  1568. *
  1569. *
  1570. *
  1571. * History:
  1572. * dd-mm-94 - StephenE - Created
  1573. *
  1574. \**************************************************************************/
  1575. BOOL
  1576. CDPlay_OnTocRead(
  1577. int iDriveRead
  1578. )
  1579. {
  1580. static int iNumRead = 0;
  1581. // This serializes processing between this
  1582. // function and the various Table of Content Threads
  1583. // Preventing resource contention on CDROM Multi-Changers.
  1584. EnterCriticalSection (&g_csTOCSerialize);
  1585. /*
  1586. ** Have we finished the initial read of the CD-Rom TOCs ?
  1587. ** If so we have to re-open the device. We only need to do this
  1588. ** on Daytona because MCI device handles are not shared between threads.
  1589. */
  1590. iNumRead++;
  1591. #ifndef USE_IOCTLS
  1592. #ifdef DAYTONA
  1593. if (iNumRead <= g_NumCdDevices) {
  1594. /*
  1595. ** Now, open the cdrom device on the UI thread.
  1596. */
  1597. g_Devices[iDriveRead]->hCd =
  1598. OpenCdRom( g_Devices[iDriveRead]->drive, NULL );
  1599. }
  1600. #endif
  1601. #endif
  1602. /*
  1603. ** This means that one of the threads dedicated to reading the
  1604. ** toc has finished. iDriveRead contains the relevant cdrom id.
  1605. */
  1606. LockALLTableOfContents();
  1607. if ( g_Devices[iDriveRead]->State & CD_LOADED ) {
  1608. /*
  1609. ** We have a CD loaded, so generate unique ID
  1610. ** based on TOC information.
  1611. */
  1612. g_Devices[iDriveRead]->CdInfo.Id = ComputeNewDiscId( iDriveRead );
  1613. /*
  1614. ** Check database for this compact disc
  1615. */
  1616. AddFindEntry( iDriveRead, g_Devices[iDriveRead]->CdInfo.Id,
  1617. &(g_Devices[iDriveRead]->toc) );
  1618. }
  1619. /*
  1620. ** If we have completed the initialization of the Cd-Rom drives we can
  1621. ** now complete the startup processing of the application.
  1622. */
  1623. if (iNumRead == g_NumCdDevices) {
  1624. CompleteCdPlayerStartUp();
  1625. }
  1626. else {
  1627. /*
  1628. ** if we are in random mode, then we need to shuffle the play lists.
  1629. ** but only if we can lock all the cd devices.
  1630. */
  1631. TimeAdjustInitialize( iDriveRead );
  1632. if ( g_fSelectedOrder == FALSE ) {
  1633. if ( LockALLTableOfContents() ) {
  1634. ComputeAndUseShufflePlayLists();
  1635. }
  1636. }
  1637. ComputeDriveComboBox();
  1638. if (iDriveRead == g_CurrCdrom) {
  1639. SetPlayButtonsEnableState();
  1640. }
  1641. }
  1642. LeaveCriticalSection (&g_csTOCSerialize);
  1643. return TRUE;
  1644. }
  1645. /*****************************Private*Routine******************************\
  1646. * SubClassedToolTips
  1647. *
  1648. * If the tooltips window is being hidden we need to reset the status bar
  1649. * to its normal display. In all instance we pass the message on the
  1650. * the tooltip window proc for processing. This is all done by use of a timer.
  1651. * If the timer fires it means that the tooltips have been invisible for
  1652. * a reasonable length of time. We always kill the timer when the tooltips
  1653. * are about to be displayed, this means that if the user is displaying the
  1654. * tips quickly we won't see the annoying flicker.
  1655. *
  1656. * History:
  1657. * dd-mm-94 - StephenE - Created
  1658. *
  1659. \**************************************************************************/
  1660. LRESULT CALLBACK
  1661. SubClassedToolTips(
  1662. HWND hwnd,
  1663. UINT uMsg,
  1664. WPARAM wParam,
  1665. LPARAM lParam
  1666. )
  1667. {
  1668. if ( (uMsg == WM_SHOWWINDOW) && ((BOOL)wParam == FALSE) ) {
  1669. SetTimer( g_hwndApp, TOOLTIPS_TIMER_ID, TOOLTIPS_TIMER_LEN,
  1670. ToolTipsTimerFunc );
  1671. }
  1672. else if ( uMsg == WM_MOVE ) {
  1673. KillTimer( g_hwndApp, TOOLTIPS_TIMER_ID );
  1674. }
  1675. return CallWindowProc(g_lpfnToolTips, hwnd, uMsg, wParam, lParam);
  1676. }
  1677. /*****************************Private*Routine******************************\
  1678. * ToolTipsTimerFunc
  1679. *
  1680. * If this timer fires it means its time to remove the tooltips text on
  1681. * the status bar.
  1682. *
  1683. * History:
  1684. * dd-mm-94 - StephenE - Created
  1685. *
  1686. \**************************************************************************/
  1687. void CALLBACK
  1688. ToolTipsTimerFunc(
  1689. HWND hwnd,
  1690. UINT uMsg,
  1691. UINT idEvent,
  1692. DWORD dwTime
  1693. )
  1694. {
  1695. KillTimer( g_hwndApp, TOOLTIPS_TIMER_ID );
  1696. SendMessage(g_hwndStatusbar, SB_SIMPLE, 0, 0L);
  1697. }
  1698. /*****************************Private*Routine******************************\
  1699. * CDPlay_OnMenuSelect
  1700. *
  1701. *
  1702. *
  1703. * History:
  1704. * dd-mm-94 - StephenE - Created
  1705. *
  1706. \**************************************************************************/
  1707. void
  1708. CDPlay_OnMenuSelect(
  1709. HWND hwnd,
  1710. HMENU hmenu,
  1711. int item,
  1712. HMENU hmenuPopup,
  1713. UINT flags
  1714. )
  1715. {
  1716. TCHAR szString[STR_MAX_STRING_LEN + 1];
  1717. /*
  1718. ** Is it time to end the menu help ?
  1719. */
  1720. if ( (flags == 0xFFFFFFFF) && (hmenu == NULL) ) {
  1721. SendMessage(g_hwndStatusbar, SB_SIMPLE, 0, 0L);
  1722. }
  1723. /*
  1724. ** Do we have a separator, popup or the system menu ?
  1725. */
  1726. else if ( flags & MF_POPUP ) {
  1727. SendMessage(g_hwndStatusbar, SB_SIMPLE, 0, 0L);
  1728. }
  1729. else if (flags & MF_SYSMENU) {
  1730. if (flags & MF_SEPARATOR) {
  1731. szString[0] = g_chNULL;
  1732. }
  1733. else {
  1734. int id = -1;
  1735. switch (item) {
  1736. case SC_RESTORE:
  1737. id = STR_SYSMENU_RESTORE;
  1738. break;
  1739. case SC_MOVE:
  1740. id = STR_SYSMENU_MOVE;
  1741. break;
  1742. case SC_SIZE:
  1743. id = STR_SYSMENU_SIZE;
  1744. break;
  1745. case SC_MINIMIZE:
  1746. id = STR_SYSMENU_MINIMIZE;
  1747. break;
  1748. case SC_MAXIMIZE:
  1749. id = STR_SYSMENU_MAXIMIZE;
  1750. break;
  1751. case SC_CLOSE:
  1752. id = STR_SYSMENU_CLOSE;
  1753. break;
  1754. #ifdef DAYTONA
  1755. case SC_TASKLIST:
  1756. id = STR_SYSMENU_SWITCH;
  1757. break;
  1758. #endif
  1759. }
  1760. _tcscpy( szString, IdStr(id) );
  1761. }
  1762. SendMessage( g_hwndStatusbar, SB_SETTEXT, SBT_NOBORDERS|255,
  1763. (LPARAM)(LPTSTR)szString );
  1764. SendMessage( g_hwndStatusbar, SB_SIMPLE, 1, 0L );
  1765. UpdateWindow(g_hwndStatusbar);
  1766. }
  1767. /*
  1768. ** Hopefully its one of ours
  1769. */
  1770. else {
  1771. if (flags & MF_SEPARATOR) {
  1772. szString[0] = g_chNULL;
  1773. }
  1774. else {
  1775. _tcscpy( szString, IdStr(item + MENU_STRING_BASE) );
  1776. }
  1777. SendMessage( g_hwndStatusbar, SB_SETTEXT, SBT_NOBORDERS|255,
  1778. (LPARAM)(LPTSTR)szString );
  1779. SendMessage( g_hwndStatusbar, SB_SIMPLE, 1, 0L );
  1780. UpdateWindow(g_hwndStatusbar);
  1781. }
  1782. }
  1783. /*****************************Private*Routine******************************\
  1784. * CDPlay_OnDeviceChange
  1785. *
  1786. *
  1787. *
  1788. * History:
  1789. * dd-mm-94 - StephenE - Created
  1790. *
  1791. \**************************************************************************/
  1792. BOOL
  1793. CDPlay_OnDeviceChange(
  1794. HWND hwnd,
  1795. WPARAM wParam,
  1796. LPARAM lParam)
  1797. {
  1798. UINT uiEvent = (UINT)wParam;
  1799. DWORD dwData = (DWORD)lParam;
  1800. switch (uiEvent)
  1801. {
  1802. case DBT_DEVICEARRIVAL: // Insertion
  1803. case DBT_DEVICEREMOVECOMPLETE: // Ejection
  1804. if ((PDEV_BROADCAST_HDR)dwData)
  1805. {
  1806. switch (((PDEV_BROADCAST_HDR)dwData)->dbch_devicetype)
  1807. {
  1808. case DBT_DEVTYP_VOLUME:
  1809. {
  1810. TCHAR chDrive[4] = TEXT("A:\\");
  1811. INT i,j,drive;
  1812. DWORD dwCurr;
  1813. PDEV_BROADCAST_VOLUME pdbv;
  1814. DWORD dwMask, dwDrives;
  1815. pdbv = (PDEV_BROADCAST_VOLUME)dwData;
  1816. dwMask = pdbv->dbcv_unitmask;
  1817. dwDrives = GetLogicalDrives();
  1818. dwMask &= dwDrives;
  1819. if (dwMask)
  1820. {
  1821. // Check all drives for match
  1822. for (i = 0; i < 32; i++)
  1823. {
  1824. dwCurr = 1 << i;
  1825. if (dwCurr & dwMask)
  1826. {
  1827. // Check drive
  1828. chDrive[0] = TEXT('A') + i;
  1829. if ( GetDriveType(chDrive) == DRIVE_CDROM )
  1830. {
  1831. // Find Associated Drive structure
  1832. drive = -1;
  1833. for (j = 0; j < g_NumCdDevices; j++)
  1834. {
  1835. if (g_Devices[j]->drive == chDrive[0])
  1836. drive = j;
  1837. }
  1838. // Structure not found, make one
  1839. if (drive == -1)
  1840. {
  1841. #ifdef DBG
  1842. dprintf ("CDPlay_OnDeviceChange - didn't find drive");
  1843. #endif
  1844. if (g_NumCdDevices > MAX_CD_DEVICES)
  1845. {
  1846. // Error - not enough device slots
  1847. break;
  1848. }
  1849. g_Devices[g_NumCdDevices] = AllocMemory( sizeof(CDROM) );
  1850. if (NULL == g_Devices[g_NumCdDevices])
  1851. {
  1852. // Error - unable to get enough memory
  1853. break;
  1854. }
  1855. g_Devices[g_NumCdDevices]->drive = chDrive[0];
  1856. drive = g_NumCdDevices;
  1857. g_NumCdDevices++;
  1858. }
  1859. // Insert/Eject new drive
  1860. if (uiEvent == DBT_DEVICEARRIVAL) {
  1861. // Drive has been inserted
  1862. // Do nothing for an inserted CD-ROM
  1863. // The Shell should inform us using
  1864. // the AUTOPLAY through WM_COPYDDATA
  1865. }
  1866. else {
  1867. // Drive has been ejected
  1868. NoMediaUpdate (drive);
  1869. }
  1870. }
  1871. }
  1872. }
  1873. }
  1874. break;
  1875. }
  1876. default:
  1877. // Not a logical volume message
  1878. break;
  1879. }
  1880. }
  1881. break;
  1882. case DBT_DEVICEQUERYREMOVE: // Permission to remove a device is requested.
  1883. case DBT_DEVICEQUERYREMOVEFAILED: // Request to remove a device has been canceled.
  1884. case DBT_DEVICEREMOVEPENDING: // Device is about to be removed. Can not be denied.
  1885. case DBT_DEVICETYPESPECIFIC: // Device-specific event.
  1886. case DBT_CONFIGCHANGED: // Current configuration has changed.
  1887. default:
  1888. break;
  1889. }
  1890. return TRUE;
  1891. } // End CDPlay_OnDeviceChange
  1892. /*****************************Private*Routine******************************\
  1893. * CDPlay_OnDropFiles
  1894. *
  1895. *
  1896. *
  1897. * History:
  1898. * dd-mm-94 - StephenE - Created
  1899. *
  1900. \**************************************************************************/
  1901. void
  1902. CDPlay_OnDropFiles(
  1903. HWND hwnd,
  1904. HDROP hdrop
  1905. )
  1906. {
  1907. int cFiles;
  1908. int cGoodFiles;
  1909. int iTextLen;
  1910. int i;
  1911. TCHAR szFileName[MAX_PATH+3];
  1912. LPTSTR lpCommandLine;
  1913. BOOL fWasPlaying = FALSE;
  1914. // Prevent Re-entrancy while we are
  1915. // Opening and closing CD's
  1916. if (g_fInCopyData)
  1917. return;
  1918. g_fInCopyData = TRUE;
  1919. /*
  1920. ** Determine how many files were passed to us.
  1921. */
  1922. cFiles = DragQueryFile( hdrop, (UINT)-1, (LPTSTR)NULL, 0 );
  1923. /*
  1924. ** Calculate the length of the command line each filename should be
  1925. ** separated by a space character
  1926. */
  1927. iTextLen = _tcslen( g_szCdplayer );
  1928. iTextLen += _tcslen( g_szPlayOption );
  1929. iTextLen += _tcslen( g_szTrackOption );
  1930. for ( cGoodFiles = cFiles, i = 0; i < cFiles; i++ ) {
  1931. int unused1, unused2;
  1932. DragQueryFile( hdrop, i, szFileName, MAX_PATH );
  1933. if (IsTrackFileNameValid( szFileName, &unused1,
  1934. &unused2, TRUE, FALSE )) {
  1935. // Add on 3 extra characters - one for the space and
  1936. // two for quote marks, we do this because the filename
  1937. // given may contain space characters.
  1938. iTextLen += _tcslen( szFileName ) + 2 + 1;
  1939. }
  1940. else {
  1941. cGoodFiles--;
  1942. }
  1943. }
  1944. /*
  1945. ** If the none of the dropped files are valid tracks just return
  1946. */
  1947. if (cGoodFiles < 1) {
  1948. g_fInCopyData = FALSE;
  1949. return;
  1950. }
  1951. /*
  1952. ** Allocate a chunk of memory big enough for all the options and
  1953. ** filenames. Don't forget the NULL.
  1954. */
  1955. lpCommandLine = AllocMemory(sizeof(TCHAR) * (iTextLen + 1));
  1956. /*
  1957. ** Add a dummy intial command line arg. This is because the
  1958. ** first arg is always the name of the invoked application. We ignore
  1959. ** this paramter. Also if we are currently playing we need to
  1960. ** add the -play option to command line as well as stop the CD.
  1961. */
  1962. _tcscpy( lpCommandLine, g_szCdplayer );
  1963. if ( g_State & (CD_PLAYING | CD_PAUSED) ) {
  1964. CdPlayerStopCmd();
  1965. fWasPlaying = TRUE;
  1966. _tcscat( lpCommandLine, g_szPlayOption );
  1967. }
  1968. /*
  1969. ** If there is more than one file name specified then we should constuct
  1970. ** a new playlist from the given files.
  1971. */
  1972. if ( cGoodFiles > 1) {
  1973. _tcscat( lpCommandLine, g_szTrackOption );
  1974. }
  1975. /*
  1976. ** Build up the command line.
  1977. */
  1978. for ( i = 0; i < cFiles; i++ ) {
  1979. int unused1, unused2;
  1980. DragQueryFile( hdrop, i, szFileName, MAX_PATH );
  1981. if (IsTrackFileNameValid( szFileName, &unused1,
  1982. &unused2, TRUE, TRUE )) {
  1983. _tcscat( lpCommandLine, TEXT("\'") );
  1984. _tcscat( lpCommandLine, szFileName );
  1985. _tcscat( lpCommandLine, TEXT("\'") );
  1986. _tcscat( lpCommandLine, g_szBlank );
  1987. }
  1988. }
  1989. /*
  1990. ** now process the newly constructed command line.
  1991. */
  1992. HandlePassedCommandLine( lpCommandLine, FALSE );
  1993. /*
  1994. ** If we were playing make sure that we are still playing the
  1995. ** new track(s)
  1996. */
  1997. if ( fWasPlaying ) {
  1998. CdPlayerPlayCmd();
  1999. }
  2000. LocalFree( lpCommandLine );
  2001. DragFinish( hdrop );
  2002. g_fInCopyData = FALSE;
  2003. }
  2004. /*****************************Private*Routine******************************\
  2005. * ResolveLink
  2006. *
  2007. * Takes the shortcut (shell link) file pointed to be szFileName and
  2008. * resolves the link returning the linked file name in szFileName.
  2009. *
  2010. * szFileName must point to at least MAX_PATH amount of TCHARS. The function
  2011. * return TRUE if the link was successfully resolved and FALSE otherwise.
  2012. *
  2013. * History:
  2014. * dd-mm-94 - StephenE - Created
  2015. * 03-11-95 - ShawnB - Unicode enabled
  2016. *
  2017. \**************************************************************************/
  2018. BOOL
  2019. ResolveLink(
  2020. TCHAR *szFileName
  2021. )
  2022. {
  2023. #ifndef UNICODE
  2024. char cszPath[MAX_PATH];
  2025. WCHAR wszPath[MAX_PATH];
  2026. MultiByteToWideChar(CP_ACP, 0, szFileName, -1, wszPath, MAX_PATH);
  2027. lstrcpy (cszPath, szFileName);
  2028. #endif // End !UNICODE
  2029. IShellLink * psl = NULL;
  2030. HRESULT hres;
  2031. int iCountTries;
  2032. const int MAX_TRIES = 3;
  2033. if (!g_fOleInitialized) {
  2034. return FALSE;
  2035. }
  2036. //
  2037. // Sometimes on Chicago I keep getting an error code from
  2038. // CoCreateInstance that implies that the server is busy,
  2039. // so I'll give it a chance to get its act together.
  2040. //
  2041. for ( iCountTries = 0; iCountTries < MAX_TRIES; iCountTries++ ) {
  2042. hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC,
  2043. &IID_IShellLink, (LPVOID *)&psl);
  2044. if ( SUCCEEDED(hres) ) {
  2045. break;
  2046. }
  2047. Sleep(100);
  2048. }
  2049. //
  2050. // Make sure we that have the interface before proceeding
  2051. //
  2052. if (SUCCEEDED(hres) && psl != NULL) {
  2053. IPersistFile *ppf;
  2054. psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (LPVOID *)&ppf);
  2055. if ( NULL != ppf ) {
  2056. #ifdef UNICODE
  2057. hres = ppf->lpVtbl->Load(ppf, szFileName, 0);
  2058. #else
  2059. hres = ppf->lpVtbl->Load(ppf, wszPath, 0);
  2060. #endif
  2061. ppf->lpVtbl->Release(ppf);
  2062. if ( FAILED(hres) ) {
  2063. psl->lpVtbl->Release(psl);
  2064. psl = NULL;
  2065. return FALSE;
  2066. }
  2067. }
  2068. else {
  2069. psl->lpVtbl->Release(psl);
  2070. psl = NULL;
  2071. return FALSE;
  2072. }
  2073. }
  2074. if ( NULL != psl ) {
  2075. psl->lpVtbl->Resolve(psl, NULL, SLR_NO_UI);
  2076. #ifdef UNICODE
  2077. hres = psl->lpVtbl->GetPath(psl, szFileName, MAX_PATH, NULL, 0);
  2078. #else
  2079. hres = psl->lpVtbl->GetPath(psl, cszPath, MAX_PATH, NULL, 0);
  2080. #endif
  2081. psl->lpVtbl->Release(psl);
  2082. #ifndef UNICODE
  2083. if (SUCCEEDED(hres))
  2084. {
  2085. lstrcpy (szFileName, cszPath);
  2086. }
  2087. #endif
  2088. return SUCCEEDED(hres);
  2089. }
  2090. return FALSE;
  2091. }
  2092. //#endif
  2093. /*****************************Private*Routine******************************\
  2094. * ShowStatusbar
  2095. *
  2096. * If the status bar is not visible:
  2097. * Expand the client window, position the status bar and make it visible.
  2098. * else
  2099. * Hide the status bar, and then contract the client window.
  2100. *
  2101. * History:
  2102. * 18-11-93 - StephenE - Created
  2103. *
  2104. \**************************************************************************/
  2105. void
  2106. ShowStatusbar(
  2107. void
  2108. )
  2109. {
  2110. RECT rcApp;
  2111. GetWindowRect( g_hwndApp, &rcApp );
  2112. if (g_fStatusbarVisible) {
  2113. ShowWindow( g_hwndStatusbar, SW_HIDE );
  2114. rcApp.bottom -= rcStatusbar.bottom;
  2115. SetWindowPos( g_hwndApp, HWND_TOP,
  2116. 0, 0,
  2117. (int)(rcApp.right - rcApp.left),
  2118. (int)(rcApp.bottom - rcApp.top),
  2119. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
  2120. }
  2121. else {
  2122. rcApp.bottom += rcStatusbar.bottom;
  2123. SetWindowPos( g_hwndApp, HWND_TOP,
  2124. 0, 0,
  2125. (int)(rcApp.right - rcApp.left),
  2126. (int)(rcApp.bottom - rcApp.top),
  2127. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
  2128. ShowWindow( g_hwndStatusbar, SW_SHOW );
  2129. }
  2130. g_fStatusbarVisible = !g_fStatusbarVisible;
  2131. }
  2132. /*****************************Private*Routine******************************\
  2133. * ShowToolbar
  2134. *
  2135. * If the tool bar is not visible:
  2136. * Grow the client window, position the child controls and show toolbar
  2137. * else
  2138. * Hide the tool bar, position controls and contract client window.
  2139. *
  2140. * History:
  2141. * 18-11-93 - StephenE - Created
  2142. *
  2143. \**************************************************************************/
  2144. void
  2145. ShowToolbar(
  2146. void
  2147. )
  2148. {
  2149. RECT rcApp;
  2150. HDWP hdwp;
  2151. LONG lIncrement;
  2152. int i;
  2153. GetWindowRect( g_hwndApp, &rcApp );
  2154. if (g_fToolbarVisible) {
  2155. lIncrement = -rcToolbar.bottom;
  2156. ShowWindow( g_hwndToolbar, SW_HIDE );
  2157. }
  2158. else {
  2159. lIncrement = rcToolbar.bottom;
  2160. }
  2161. /*
  2162. ** First resize the application.
  2163. */
  2164. rcApp.bottom += lIncrement;
  2165. SetWindowPos( g_hwndApp, HWND_TOP,
  2166. 0, 0,
  2167. (int)(rcApp.right - rcApp.left),
  2168. (int)(rcApp.bottom - rcApp.top),
  2169. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
  2170. /*
  2171. ** Now move the buttons and the track info stuff.
  2172. */
  2173. hdwp = BeginDeferWindowPos( 20 );
  2174. for ( i = 0; i < NUM_OF_CONTROLS; i++ ) {
  2175. rcControls[i].top += lIncrement;
  2176. hdwp = DeferWindowPos( hdwp,
  2177. g_hwndControls[i],
  2178. HWND_TOP,
  2179. (int)rcControls[i].left,
  2180. (int)rcControls[i].top,
  2181. 0, 0,
  2182. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER );
  2183. }
  2184. ASSERT(hdwp != NULL);
  2185. EndDeferWindowPos( hdwp );
  2186. if (!g_fToolbarVisible) {
  2187. ShowWindow( g_hwndToolbar, SW_SHOW );
  2188. }
  2189. g_fToolbarVisible = !g_fToolbarVisible;
  2190. }
  2191. /*****************************Private*Routine******************************\
  2192. * ShowTrackInfo
  2193. *
  2194. * If the track info is not visible:
  2195. * Expand the client window, position the track info and make it visible.
  2196. * else
  2197. * Hide the track info, and then contract the client window.
  2198. *
  2199. * History:
  2200. * 18-11-93 - StephenE - Created
  2201. *
  2202. \**************************************************************************/
  2203. void
  2204. ShowTrackInfo(
  2205. void
  2206. )
  2207. {
  2208. RECT rcApp;
  2209. int i;
  2210. GetWindowRect( g_hwndApp, &rcApp );
  2211. if (g_fTrackInfoVisible) {
  2212. for ( i = IDC_TRACKINFO_FIRST - IDC_CDPLAYER_FIRST;
  2213. i < NUM_OF_CONTROLS; i++ ) {
  2214. ShowWindow( g_hwndControls[i], SW_HIDE );
  2215. }
  2216. rcApp.bottom -= cyTrackInfo;
  2217. SetWindowPos( g_hwndApp, HWND_TOP,
  2218. 0, 0,
  2219. (int)(rcApp.right - rcApp.left),
  2220. (int)(rcApp.bottom - rcApp.top),
  2221. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
  2222. }
  2223. else {
  2224. rcApp.bottom += cyTrackInfo;
  2225. SetWindowPos( g_hwndApp, HWND_TOP,
  2226. 0, 0,
  2227. (int)(rcApp.right - rcApp.left),
  2228. (int)(rcApp.bottom - rcApp.top),
  2229. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
  2230. for ( i = IDC_TRACKINFO_FIRST - IDC_CDPLAYER_FIRST;
  2231. i < NUM_OF_CONTROLS; i++ ) {
  2232. ShowWindow( g_hwndControls[i], SW_SHOW );
  2233. }
  2234. }
  2235. g_fTrackInfoVisible = !g_fTrackInfoVisible;
  2236. }
  2237. /******************************Public*Routine******************************\
  2238. * ChildEnumProc
  2239. *
  2240. * Gets the position of each child control window. As saves the associated
  2241. * window handle for later use.
  2242. *
  2243. * History:
  2244. * 18-11-93 - StephenE - Created
  2245. *
  2246. \**************************************************************************/
  2247. BOOL CALLBACK
  2248. ChildEnumProc(
  2249. HWND hwndChild,
  2250. LPARAM hwndParent
  2251. )
  2252. {
  2253. int index;
  2254. index = INDEX(GetDlgCtrlID( hwndChild ));
  2255. GetWindowRect( hwndChild, &rcControls[index] );
  2256. MapWindowPoints( NULL, (HWND)hwndParent, (LPPOINT)&rcControls[index], 2 );
  2257. g_hwndControls[index] = hwndChild;
  2258. return TRUE;
  2259. }
  2260. /*****************************Private*Routine******************************\
  2261. * CreateToolbarAndStatusbar
  2262. *
  2263. *
  2264. *
  2265. * History:
  2266. * 18-11-93 - StephenE - Created
  2267. *
  2268. \**************************************************************************/
  2269. BOOL
  2270. CreateToolbarsAndStatusbar(
  2271. HWND hwnd
  2272. )
  2273. {
  2274. HDC hdc;
  2275. int RightOfPane[2];
  2276. RECT rcApp;
  2277. HWND hwndToolbarTips;
  2278. GetClientRect( hwnd, &rcApp );
  2279. cyTrackInfo = (rcApp.bottom - rcApp.top)
  2280. - rcControls[IDC_TRACKINFO_FIRST - IDC_CDPLAYER_FIRST].top;
  2281. g_hwndToolbar = CreateToolbarEx( hwnd,
  2282. WS_CHILD | TBSTYLE_TOOLTIPS,
  2283. ID_TOOLBAR, NUMBER_OF_BITMAPS,
  2284. g_hInst, IDR_TOOLBAR, tbButtons,
  2285. DEFAULT_TBAR_SIZE, dxBitmap, dyBitmap,
  2286. dxBitmap, dyBitmap, sizeof(TBBUTTON) );
  2287. if ( g_hwndToolbar == NULL ) {
  2288. return FALSE;
  2289. }
  2290. /*
  2291. ** Calculate the size of the toolbar. The WM_SIZE message forces the
  2292. ** toolbar to recalculate its size and thus return the correct value to
  2293. ** us.
  2294. */
  2295. SendMessage( g_hwndToolbar, WM_SIZE, 0, 0L );
  2296. GetClientRect( g_hwndToolbar, &rcToolbar );
  2297. hwndToolbarTips = (HWND)SendMessage( g_hwndToolbar, TB_GETTOOLTIPS, 0, 0L );
  2298. if (hwndToolbarTips) {
  2299. g_lpfnToolTips = SubclassWindow( hwndToolbarTips, SubClassedToolTips );
  2300. }
  2301. g_hwndStatusbar = CreateStatusWindow( WS_CHILD | WS_BORDER,
  2302. g_szEmpty, hwnd, ID_STATUSBAR );
  2303. if ( g_hwndStatusbar == NULL ) {
  2304. return FALSE;
  2305. }
  2306. /*
  2307. ** Partition the status bar window into two. The first partion is
  2308. ** 1.5 inches long. The other partition fills the remainder of
  2309. ** the bar.
  2310. */
  2311. hdc = GetWindowDC( hwnd );
  2312. #ifdef JAPAN
  2313. //fix kksuzuka: #4131
  2314. RightOfPane[0] = (rcApp.right-rcApp.left) / 2;
  2315. #else
  2316. RightOfPane[0] = (GetDeviceCaps(hdc, LOGPIXELSX) * 3) / 2;
  2317. #endif
  2318. RightOfPane[1] = -1;
  2319. ReleaseDC( hwnd, hdc );
  2320. SendMessage( g_hwndStatusbar, SB_SETPARTS, 2, (LPARAM)RightOfPane );
  2321. GetClientRect( g_hwndStatusbar, &rcStatusbar );
  2322. return TRUE;
  2323. }
  2324. /*****************************Private*Routine******************************\
  2325. * AdjustChildButtons
  2326. *
  2327. * The child buttons should be aligned with the right hand edge of the
  2328. * track info controls. They should be be positioned so that vertically they
  2329. * are in the centre of the space between the track info controls and
  2330. * the top of the dialog box.
  2331. *
  2332. * The buttons are positioned such that the left hand edge of a button is
  2333. * flush with the right hand edge of the next button. The play button is
  2334. * 3 times the width of the other buttons.
  2335. *
  2336. *
  2337. * History:
  2338. * 18-11-93 - StephenE - Created
  2339. *
  2340. \**************************************************************************/
  2341. void
  2342. AdjustChildButtons(
  2343. HWND hwnd
  2344. )
  2345. {
  2346. int cyVerticalSpace;
  2347. int cxFromLeft;
  2348. int i, x, y, cx, cy;
  2349. SIZE sizeLed;
  2350. HDC hdc;
  2351. HFONT hFont;
  2352. TCHAR szDisplay[16];
  2353. RECT rc;
  2354. /*
  2355. ** Calculate the max size that the display LED needs to be
  2356. */
  2357. hdc = GetWindowDC( hwnd );
  2358. hFont = SelectObject( hdc, hLEDFontL );
  2359. wsprintf( szDisplay, TRACK_REM_FORMAT, 0, 0, TEXT("M"), 0 );
  2360. GetTextExtentPoint32( hdc, szDisplay, _tcslen(szDisplay), &sizeLed );
  2361. SelectObject( hdc, hFont );
  2362. ReleaseDC( hwnd, hdc );
  2363. /*
  2364. ** Set the size of the CD Player window based on the max size of the LED display
  2365. ** and the width of the buttons.
  2366. */
  2367. GetWindowRect( hwnd, &rc );
  2368. SetWindowPos( hwnd, HWND_TOP, 0, 0,
  2369. (4 * GetSystemMetrics(SM_CXBORDER)) + (5 * xFirstButton) +
  2370. (5 * dxButton) + sizeLed.cx,
  2371. rc.bottom - rc.top,
  2372. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE );
  2373. /*
  2374. ** Now work out hown much vertical space there is between the menu and the buttons
  2375. ** and the buttons and the tack info display.
  2376. */
  2377. cyVerticalSpace = (rcControls[INDEX(IDC_TRACKINFO_FIRST)].top -
  2378. (2 * dyButton)) / 3;
  2379. cxFromLeft = (4 * xFirstButton) + sizeLed.cx;
  2380. /*
  2381. ** There are 3 buttons on the top row. The first button is 3 times
  2382. ** the width of the other buttons, it gets adjusted first.
  2383. */
  2384. y = cyVerticalSpace;
  2385. x = cxFromLeft;
  2386. SetWindowPos( g_hwndControls[0], HWND_TOP,
  2387. x, y, 3 * dxButton, dyButton, SWP_NOACTIVATE | SWP_NOZORDER );
  2388. x += (3 * dxButton);
  2389. for ( i = 1; i < 3; i++ ) {
  2390. SetWindowPos( g_hwndControls[i], HWND_TOP,
  2391. x, y, dxButton, dyButton, SWP_NOACTIVATE | SWP_NOZORDER );
  2392. x += dxButton;
  2393. }
  2394. /*
  2395. ** There are 5 buttons on the bottom row.
  2396. */
  2397. y = dyButton + (2 * cyVerticalSpace);
  2398. x = cxFromLeft;
  2399. for ( i = 0; i < 5; i++ ) {
  2400. SetWindowPos( g_hwndControls[i + 3], HWND_TOP,
  2401. x, y, dxButton, dyButton, SWP_NOACTIVATE | SWP_NOZORDER );
  2402. x += dxButton;
  2403. }
  2404. /*
  2405. ** Now adjust the LED window position.
  2406. */
  2407. y = cyVerticalSpace;
  2408. x = xFirstButton; /* see toolbar.h and toolbar.c for definition. */
  2409. cx = (2 * xFirstButton) + sizeLed.cx;
  2410. cy = (2 * dyButton) + cyVerticalSpace;
  2411. SetWindowPos( g_hwndControls[INDEX(IDC_LED)], HWND_TOP,
  2412. x, y, cx, cy, SWP_NOACTIVATE | SWP_NOZORDER );
  2413. /*
  2414. ** Now expand (or shrink) the track info controls to fit the available space.
  2415. */
  2416. cx = (4 * xFirstButton) + (5 * dxButton) + sizeLed.cx;
  2417. ComboBox_GetDroppedControlRect( g_hwndControls[INDEX(IDC_COMBO1)], &rc );
  2418. i = rc.bottom - rc.top;
  2419. SetWindowPos( g_hwndControls[INDEX(IDC_COMBO1)],
  2420. HWND_TOP,
  2421. 0, 0,
  2422. cx - rcControls[INDEX(IDC_COMBO1)].left,
  2423. rcControls[INDEX(IDC_COMBO1)].bottom -
  2424. rcControls[INDEX(IDC_COMBO1)].top + i,
  2425. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE );
  2426. SetWindowPos( g_hwndControls[INDEX(IDC_EDIT1)],
  2427. HWND_TOP,
  2428. 0, 0,
  2429. cx - rcControls[INDEX(IDC_EDIT1)].left,
  2430. rcControls[INDEX(IDC_EDIT1)].bottom -
  2431. rcControls[INDEX(IDC_EDIT1)].top,
  2432. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE );
  2433. SetWindowPos( g_hwndControls[INDEX(IDC_COMBO2)],
  2434. HWND_TOP,
  2435. 0, 0,
  2436. cx - rcControls[INDEX(IDC_COMBO2)].left,
  2437. rcControls[INDEX(IDC_COMBO2)].bottom -
  2438. rcControls[INDEX(IDC_COMBO2)].top + i,
  2439. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE );
  2440. }
  2441. /******************************Public*Routine******************************\
  2442. * FatalApplicationError
  2443. *
  2444. * Call this function if something "bad" happens to the application. It
  2445. * displays an error message and then kills itself.
  2446. *
  2447. * History:
  2448. * 18-11-93 - StephenE - Created
  2449. *
  2450. \**************************************************************************/
  2451. void
  2452. FatalApplicationError(
  2453. INT uIdStringResource,
  2454. ...
  2455. )
  2456. {
  2457. va_list va;
  2458. TCHAR chBuffer1[ STR_MAX_STRING_LEN ];
  2459. TCHAR chBuffer2[ STR_MAX_STRING_LEN ];
  2460. /*
  2461. ** Load the relevant messages
  2462. */
  2463. va_start(va, uIdStringResource);
  2464. wvsprintf(chBuffer1, IdStr(uIdStringResource), va);
  2465. va_end(va);
  2466. _tcscpy( chBuffer2, IdStr(STR_FATAL_ERROR) ); /*"CD Player: Fatal Error"*/
  2467. /*
  2468. ** How much of the application do we need to kill
  2469. */
  2470. if (g_hwndApp) {
  2471. if ( IsWindowVisible(g_hwndApp) ) {
  2472. BringWindowToTop(g_hwndApp);
  2473. }
  2474. MessageBox( g_hwndApp, chBuffer1, chBuffer2,
  2475. MB_ICONSTOP | MB_OK | MB_APPLMODAL | MB_SETFOREGROUND );
  2476. DestroyWindow( g_hwndApp );
  2477. }
  2478. else {
  2479. MessageBox( NULL, chBuffer1, chBuffer2,
  2480. MB_APPLMODAL | MB_ICONSTOP | MB_OK | MB_SETFOREGROUND );
  2481. }
  2482. ExitProcess( (UINT)-1 );
  2483. }
  2484. /******************************Public*Routine******************************\
  2485. * IdStr
  2486. *
  2487. * Loads the given string resource ID into the passed storage.
  2488. *
  2489. * History:
  2490. * 18-11-93 - StephenE - Created
  2491. *
  2492. \**************************************************************************/
  2493. LPTSTR
  2494. IdStr(
  2495. int idResource
  2496. )
  2497. {
  2498. static TCHAR chBuffer[ STR_MAX_STRING_LEN ];
  2499. if (LoadString(g_hInst, idResource, chBuffer, STR_MAX_STRING_LEN) == 0) {
  2500. return g_szEmpty;
  2501. }
  2502. return chBuffer;
  2503. }
  2504. /******************************Public*Routine******************************\
  2505. * CheckMenuItemIfTrue
  2506. *
  2507. * If "flag" TRUE the given menu item is checked, otherwise it is unchecked.
  2508. *
  2509. * History:
  2510. * 18-11-93 - StephenE - Created
  2511. *
  2512. \**************************************************************************/
  2513. void
  2514. CheckMenuItemIfTrue(
  2515. HMENU hMenu,
  2516. UINT idItem,
  2517. BOOL flag
  2518. )
  2519. {
  2520. UINT uFlags;
  2521. if (flag) {
  2522. uFlags = MF_CHECKED | MF_BYCOMMAND;
  2523. }
  2524. else {
  2525. uFlags = MF_UNCHECKED | MF_BYCOMMAND;
  2526. }
  2527. CheckMenuItem( hMenu, idItem, uFlags );
  2528. }
  2529. /******************************Public*Routine******************************\
  2530. * ReadSettings
  2531. *
  2532. * Read app settings from ini file.
  2533. *
  2534. * History:
  2535. * 18-11-93 - StephenE - Created
  2536. *
  2537. \**************************************************************************/
  2538. void
  2539. ReadSettings(
  2540. void
  2541. )
  2542. {
  2543. HKEY hKey;
  2544. LONG lRet;
  2545. /*
  2546. ** See if the user has setting information stored in the registry.
  2547. ** If so read the stuff from there. Otherwise fall thru and try to
  2548. ** get the stuff from cdplayer.ini.
  2549. */
  2550. lRet = RegOpenKey( HKEY_CURRENT_USER, g_szRegistryKey, &hKey );
  2551. if ( (lRet == ERROR_SUCCESS) ) {
  2552. DWORD dwTmp, dwType, dwLen;
  2553. int x, y;
  2554. int cxApp, cyApp;
  2555. int cxDesktop, cyDesktop;
  2556. RECT rcApp, rcDesktop;
  2557. // Save settings on exit ?
  2558. dwLen = sizeof( g_fSaveOnExit );
  2559. if ( ERROR_SUCCESS != RegQueryValueEx( hKey,
  2560. g_szSaveSettingsOnExit,
  2561. 0L,
  2562. &dwType,
  2563. (LPBYTE)&g_fSaveOnExit,
  2564. &dwLen ) ) {
  2565. g_fSaveOnExit = TRUE;
  2566. }
  2567. // Small LED font
  2568. dwLen = sizeof( g_fSmallLedFont );
  2569. RegQueryValueEx( hKey, g_szSmallFont, 0L, &dwType,
  2570. (LPBYTE)&g_fSmallLedFont, &dwLen );
  2571. if (g_fSmallLedFont) {
  2572. LED_ToggleDisplayFont(g_hwndControls[INDEX(IDC_LED)], g_fSmallLedFont );
  2573. }
  2574. // Enable Tooltips
  2575. dwLen = sizeof( g_fToolTips );
  2576. if ( ERROR_SUCCESS != RegQueryValueEx( hKey, g_szToolTips, 0L, &dwType,
  2577. (LPBYTE)&g_fToolTips, &dwLen ) ) {
  2578. g_fToolTips = TRUE;
  2579. }
  2580. /*
  2581. ** Stop CD playing on exit
  2582. **
  2583. ** As this is a new setting it might not present in systems
  2584. ** that have upgraded.
  2585. */
  2586. dwLen = sizeof( g_fStopCDOnExit );
  2587. if ( ERROR_SUCCESS != RegQueryValueEx(hKey, g_szStopCDPlayingOnExit,
  2588. 0L, &dwType, (LPBYTE)&g_fStopCDOnExit,
  2589. &dwLen) ) {
  2590. g_fStopCDOnExit = TRUE;
  2591. }
  2592. // Play in selected order
  2593. dwLen = sizeof( g_fSelectedOrder );
  2594. if ( ERROR_SUCCESS != RegQueryValueEx( hKey,
  2595. g_szInOrderPlay, 0L,
  2596. &dwType,
  2597. (LPBYTE)&g_fSelectedOrder,
  2598. &dwLen ) ) {
  2599. g_fSelectedOrder = TRUE;
  2600. }
  2601. // Use single disk
  2602. /*
  2603. dwLen = sizeof( dwTmp );
  2604. if ( ERROR_SUCCESS != RegQueryValueEx( hKey,
  2605. g_szMultiDiscPlay,
  2606. 0L,
  2607. &dwType,
  2608. (LPBYTE)&dwTmp,
  2609. &dwLen ) ) {
  2610. dwTmp = FALSE;
  2611. }
  2612. g_fSingleDisk = !(BOOL)dwTmp;
  2613. */
  2614. //if ( g_NumCdDevices < 2 ) {
  2615. g_fMultiDiskAvailable = FALSE;
  2616. g_fSingleDisk = TRUE;
  2617. //}
  2618. //else {
  2619. // g_fMultiDiskAvailable = TRUE;
  2620. //}
  2621. // Current track time
  2622. dwLen = sizeof( g_fDisplayT );
  2623. RegQueryValueEx( hKey, g_szDisplayT, 0L, &dwType,
  2624. (LPBYTE)&g_fDisplayT, &dwLen );
  2625. // Time remaining for this track
  2626. dwLen = sizeof( g_fDisplayTr );
  2627. RegQueryValueEx( hKey, g_szDisplayTr, 0L, &dwType,
  2628. (LPBYTE)&g_fDisplayTr, &dwLen );
  2629. // Time remaining for this play list
  2630. dwLen = sizeof( g_fDisplayDr );
  2631. RegQueryValueEx( hKey, g_szDisplayDr, 0L, &dwType,
  2632. (LPBYTE)&g_fDisplayDr, &dwLen );
  2633. // Intro play (default 10Secs)
  2634. dwLen = sizeof( g_fIntroPlay );
  2635. RegQueryValueEx( hKey, g_szIntroPlay, 0L, &dwType,
  2636. (LPBYTE)&g_fIntroPlay, &dwLen );
  2637. dwLen = sizeof( g_IntroPlayLength );
  2638. RegQueryValueEx( hKey, g_szIntroPlayLen, 0L, &dwType,
  2639. (LPBYTE)&g_IntroPlayLength, &dwLen );
  2640. /*
  2641. ** As this is a new setting it might not present in systems
  2642. ** that have upgraded.
  2643. */
  2644. if (g_IntroPlayLength == 0) {
  2645. g_IntroPlayLength = INTRO_DEFAULT_LEN;
  2646. }
  2647. // Continuous play (loop at end)
  2648. dwLen = sizeof( g_fContinuous );
  2649. RegQueryValueEx( hKey, g_szContinuousPlay, 0L, &dwType,
  2650. (LPBYTE)&g_fContinuous, &dwLen );
  2651. // Show toolbar
  2652. dwLen = sizeof( g_fToolbarVisible );
  2653. RegQueryValueEx( hKey, g_szToolbar, 0L, &dwType,
  2654. (LPBYTE)&g_fToolbarVisible, &dwLen );
  2655. // Show track information
  2656. dwLen = sizeof( g_fTrackInfoVisible );
  2657. RegQueryValueEx( hKey, g_szDiscAndTrackDisplay, 0L, &dwType,
  2658. (LPBYTE)&g_fTrackInfoVisible, &dwLen );
  2659. // Show track status bar
  2660. dwLen = sizeof( g_fStatusbarVisible );
  2661. RegQueryValueEx( hKey, g_szStatusBar, 0L, &dwType,
  2662. (LPBYTE)&g_fStatusbarVisible, &dwLen );
  2663. // X pos
  2664. dwLen = sizeof( x );
  2665. RegQueryValueEx( hKey, g_szWindowOriginX, 0L, &dwType,
  2666. (LPBYTE)&x, &dwLen );
  2667. // Y pos
  2668. dwLen = sizeof( y );
  2669. RegQueryValueEx( hKey, g_szWindowOriginY, 0L, &dwType,
  2670. (LPBYTE)&y, &dwLen );
  2671. GetClientRect( g_hwndApp, &rcApp );
  2672. GetWindowRect( GetDesktopWindow(), &rcDesktop );
  2673. cxDesktop = (rcDesktop.right - rcDesktop.left);
  2674. cyDesktop = (rcDesktop.bottom - rcDesktop.top);
  2675. cxApp = (rcApp.right - rcApp.left);
  2676. cyApp = (rcApp.bottom - rcApp.top);
  2677. if ( x < 0) {
  2678. x = 0;
  2679. }
  2680. else if ( x > cxDesktop ) {
  2681. x = (cxDesktop - cxApp);
  2682. }
  2683. if ( y < 0) {
  2684. y = 0;
  2685. }
  2686. else if ( y > cyDesktop ) {
  2687. y = (cyDesktop - cyApp);
  2688. }
  2689. SetWindowPos( g_hwndApp, HWND_TOP, x, y, 0, 0,
  2690. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE );
  2691. /*
  2692. ** Make sure that the LED display format is correct
  2693. */
  2694. if ( g_fDisplayT == FALSE && g_fDisplayTr == FALSE
  2695. && g_fDisplayDr == FALSE ) {
  2696. g_fDisplayT = TRUE;
  2697. }
  2698. RegCloseKey( hKey );
  2699. }
  2700. else {
  2701. RECT r;
  2702. TCHAR s[80],t[80];
  2703. int i, j;
  2704. if (lRet == ERROR_SUCCESS) {
  2705. // presumably dwDesposition == REG_CREATED_NEW_KEY
  2706. RegCloseKey( hKey );
  2707. }
  2708. g_fSmallLedFont = GetPrivateProfileInt( g_szSettings,
  2709. g_szSmallFont,
  2710. FALSE,
  2711. g_IniFileName );
  2712. if (g_fSmallLedFont) {
  2713. LED_ToggleDisplayFont(g_hwndControls[INDEX(IDC_LED)], g_fSmallLedFont );
  2714. }
  2715. g_fToolTips = GetPrivateProfileInt( g_szSettings, g_szToolTips,
  2716. TRUE, g_IniFileName );
  2717. /*
  2718. ** Get disc play settings
  2719. */
  2720. i = GetPrivateProfileInt( g_szSettings, g_szInOrderPlay,
  2721. FALSE, g_IniFileName );
  2722. j = GetPrivateProfileInt( g_szSettings, g_szRandomPlay,
  2723. FALSE, g_IniFileName );
  2724. /*
  2725. ** Because the orignal CD Player had a silly way of recording
  2726. ** whether the state was random or inorder play we need the following
  2727. ** state table.
  2728. **
  2729. ** if i == j => g_fSelectedOrder = TRUE;
  2730. ** else => g_fSelectedOrder = i;
  2731. */
  2732. if ( i == j ) {
  2733. g_fSelectedOrder = TRUE;
  2734. }
  2735. else {
  2736. g_fSelectedOrder = (BOOL)i;
  2737. }
  2738. //i = GetPrivateProfileInt( g_szSettings, g_szMultiDiscPlay,
  2739. // 3, g_IniFileName );
  2740. //if (i == 0 || i == 3) {
  2741. // g_fSingleDisk = TRUE;
  2742. //}
  2743. //else {
  2744. // g_fSingleDisk = FALSE;
  2745. //}
  2746. //if ( g_NumCdDevices < 2 ) {
  2747. g_fMultiDiskAvailable = FALSE;
  2748. g_fSingleDisk = TRUE;
  2749. //}
  2750. //else {
  2751. /// g_fMultiDiskAvailable = TRUE;
  2752. //}
  2753. g_fIntroPlay = (BOOL)GetPrivateProfileInt( g_szSettings,
  2754. g_szIntroPlay,
  2755. FALSE,
  2756. g_IniFileName );
  2757. g_IntroPlayLength = (BOOL)GetPrivateProfileInt( g_szSettings,
  2758. g_szIntroPlayLen,
  2759. INTRO_DEFAULT_LEN,
  2760. g_IniFileName );
  2761. g_fContinuous = (BOOL)GetPrivateProfileInt( g_szSettings,
  2762. g_szContinuousPlay,
  2763. FALSE, g_IniFileName );
  2764. g_fSaveOnExit = (BOOL)GetPrivateProfileInt( g_szSettings,
  2765. g_szSaveSettingsOnExit,
  2766. TRUE,
  2767. g_IniFileName );
  2768. g_fStopCDOnExit = (BOOL)GetPrivateProfileInt( g_szSettings,
  2769. g_szStopCDPlayingOnExit,
  2770. TRUE,
  2771. g_IniFileName );
  2772. g_fDisplayT = (BOOL)GetPrivateProfileInt( g_szSettings,
  2773. g_szDisplayT,
  2774. TRUE, g_IniFileName );
  2775. g_fDisplayTr = (BOOL)GetPrivateProfileInt( g_szSettings,
  2776. g_szDisplayTr,
  2777. FALSE, g_IniFileName );
  2778. g_fDisplayDr = (BOOL)GetPrivateProfileInt( g_szSettings,
  2779. g_szDisplayDr,
  2780. FALSE, g_IniFileName );
  2781. /*
  2782. ** When the app is created the toolbar is inially NOT shown. Therefore
  2783. ** only show it if the user requests it.
  2784. */
  2785. g_fToolbarVisible = (BOOL)GetPrivateProfileInt( g_szSettings,
  2786. g_szToolbar,
  2787. FALSE, g_IniFileName );
  2788. /*
  2789. ** When the app is created the track info stuff is initially shown.
  2790. ** Therefore only hide it if the user requests it.
  2791. */
  2792. g_fTrackInfoVisible = (BOOL)GetPrivateProfileInt( g_szSettings,
  2793. g_szDiscAndTrackDisplay,
  2794. TRUE, g_IniFileName );
  2795. /*
  2796. ** When the app is created the statusbar is initially NOT shown.
  2797. ** Therefore only show it if the user requests it.
  2798. */
  2799. g_fStatusbarVisible = (BOOL)GetPrivateProfileInt( g_szSettings,
  2800. g_szStatusBar,
  2801. TRUE, g_IniFileName );
  2802. GetWindowRect( g_hwndApp, &r );
  2803. wsprintf(t, TEXT("%d %d"),r.left, r.top);
  2804. GetPrivateProfileString( g_szSettings, g_szWindowOrigin, t, s, 80,
  2805. g_IniFileName );
  2806. _stscanf(s, TEXT("%d %d"), &r.left, &r.top);
  2807. SetWindowPos( g_hwndApp, HWND_TOP, r.left, r.top, 0, 0,
  2808. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE );
  2809. }
  2810. /*
  2811. ** Update the various buttons, toolbars and statusbar
  2812. */
  2813. if (g_fToolbarVisible) {
  2814. g_fToolbarVisible = FALSE;
  2815. ShowToolbar();
  2816. }
  2817. if (!g_fTrackInfoVisible) {
  2818. g_fTrackInfoVisible = TRUE;
  2819. ShowTrackInfo();
  2820. }
  2821. if (g_fStatusbarVisible) {
  2822. g_fStatusbarVisible = FALSE;
  2823. ShowStatusbar();
  2824. }
  2825. /*
  2826. ** If there is only one disc drive available remove the "Multidisc play"
  2827. ** menu item. UpdateToolbarButtons below will take care of the
  2828. ** Multidisc toolbar button.
  2829. */
  2830. //if ( !g_fMultiDiskAvailable ) {
  2831. {
  2832. HMENU hMenu = GetSubMenu( GetMenu(g_hwndApp), 2 );
  2833. DeleteMenu( hMenu, IDM_OPTIONS_MULTI, MF_BYCOMMAND );
  2834. }
  2835. UpdateToolbarButtons();
  2836. UpdateToolbarTimeButtons();
  2837. }
  2838. /******************************Public*Routine******************************\
  2839. * UpdateToolbarButtons
  2840. *
  2841. * Ensures that the toolbar buttons are in the correct state.
  2842. *
  2843. * History:
  2844. * 18-11-93 - StephenE - Created
  2845. *
  2846. \**************************************************************************/
  2847. void
  2848. UpdateToolbarButtons(
  2849. void
  2850. )
  2851. {
  2852. LRESULT lResult;
  2853. /*
  2854. ** Read the current state of the button. If the current button state
  2855. ** does not match (!g_fSelectedOrder) we need to toggle the button state.
  2856. */
  2857. lResult = SendMessage( g_hwndToolbar, TB_ISBUTTONCHECKED,
  2858. IDM_OPTIONS_RANDOM, 0L );
  2859. if ( g_fSelectedOrder || (lResult == 0L) ) {
  2860. SendMessage( g_hwndToolbar, TB_CHECKBUTTON,
  2861. IDM_OPTIONS_RANDOM, (LPARAM)!g_fSelectedOrder );
  2862. }
  2863. /*
  2864. ** Whats the current visible state of the multi-disk button ?
  2865. ** If lResult != 0 the button is already visible.
  2866. */
  2867. lResult = SendMessage( g_hwndToolbar, TB_ISBUTTONHIDDEN,
  2868. IDM_OPTIONS_MULTI, 0L );
  2869. /*
  2870. ** Does the multi-disk button visible state match the g_fMultiDiskAvailable
  2871. ** flag ? If so we need to toggle the buttons visible state.
  2872. */
  2873. //if ( !(g_fMultiDiskAvailable && lResult) ) {
  2874. SendMessage( g_hwndToolbar, TB_HIDEBUTTON, IDM_OPTIONS_MULTI,
  2875. MAKELPARAM( !g_fMultiDiskAvailable, 0) );
  2876. //}
  2877. /*
  2878. ** If there are multiple discs available does the current
  2879. ** state of the MULTI disc button match the state of (!g_fSingleDisk)
  2880. */
  2881. if (g_fMultiDiskAvailable) {
  2882. lResult = SendMessage( g_hwndToolbar, TB_ISBUTTONCHECKED,
  2883. IDM_OPTIONS_MULTI, 0L );
  2884. if ( g_fSingleDisk || (lResult == 0L) ) {
  2885. SendMessage( g_hwndToolbar, TB_CHECKBUTTON,
  2886. IDM_OPTIONS_MULTI, (LPARAM)!g_fSingleDisk );
  2887. }
  2888. }
  2889. /*
  2890. ** Read the current state of the button. If the current button state
  2891. ** does not match g_fContinuous we need to toggle the button state.
  2892. */
  2893. lResult = SendMessage( g_hwndToolbar, TB_ISBUTTONCHECKED,
  2894. IDM_OPTIONS_CONTINUOUS, (LPARAM)0L );
  2895. if ( !(g_fContinuous && lResult) ) {
  2896. SendMessage( g_hwndToolbar, TB_CHECKBUTTON,
  2897. IDM_OPTIONS_CONTINUOUS, (LPARAM)g_fContinuous );
  2898. }
  2899. /*
  2900. ** Read the current state of the button. If the current button state
  2901. ** does not match g_fIntroPlay we need to toggle the button state.
  2902. */
  2903. lResult = SendMessage( g_hwndToolbar, TB_ISBUTTONCHECKED,
  2904. IDM_OPTIONS_INTRO, (LPARAM)0L );
  2905. if ( !(g_fIntroPlay && lResult) ) {
  2906. SendMessage( g_hwndToolbar, TB_CHECKBUTTON,
  2907. IDM_OPTIONS_INTRO, (LPARAM)g_fIntroPlay );
  2908. }
  2909. /*
  2910. ** Turn the tool tips on or off
  2911. */
  2912. EnableToolTips( g_fToolTips );
  2913. }
  2914. /******************************Public*Routine******************************\
  2915. * UpdateToolbarTimeButtons
  2916. *
  2917. * Ensures that the time remaining toolbar buttons are in the correct state.
  2918. * This function should only be called from the LED wndproc when it receives
  2919. * a mouse button up message.
  2920. *
  2921. * History:
  2922. * 18-11-93 - StephenE - Created
  2923. *
  2924. \**************************************************************************/
  2925. void
  2926. UpdateToolbarTimeButtons(
  2927. void
  2928. )
  2929. {
  2930. if (g_fDisplayT) {
  2931. SendMessage( g_hwndToolbar, TB_CHECKBUTTON,
  2932. IDM_TIME_REMAINING, (LPARAM)g_fDisplayT );
  2933. }
  2934. else if (g_fDisplayTr) {
  2935. SendMessage( g_hwndToolbar, TB_CHECKBUTTON,
  2936. IDM_TRACK_REMAINING, (LPARAM)g_fDisplayTr );
  2937. }
  2938. else if (g_fDisplayDr) {
  2939. SendMessage( g_hwndToolbar, TB_CHECKBUTTON,
  2940. IDM_DISC_REMAINING, (LPARAM)g_fDisplayDr );
  2941. }
  2942. }
  2943. /******************************Public*Routine******************************\
  2944. * LockTableOfContents
  2945. *
  2946. * This function is used to determine if it is valid for the UI thread
  2947. * to access the table of contents for the specified CD Rom. If this
  2948. * function returns FALSE the UI thread should NOT touch the table of
  2949. * contents for this CD Rom.
  2950. *
  2951. * History:
  2952. * 18-11-93 - StephenE - Created
  2953. *
  2954. \**************************************************************************/
  2955. BOOL
  2956. LockTableOfContents(
  2957. int cdrom
  2958. )
  2959. {
  2960. DWORD dwRet;
  2961. if (g_Devices[cdrom]->fIsTocValid) {
  2962. return TRUE;
  2963. }
  2964. if (g_Devices[cdrom]->hThreadToc == NULL) {
  2965. return FALSE;
  2966. }
  2967. dwRet = WaitForSingleObject(g_Devices[cdrom]->hThreadToc, 0L );
  2968. if (dwRet == WAIT_OBJECT_0) {
  2969. GetExitCodeThread( g_Devices[cdrom]->hThreadToc, &dwRet );
  2970. g_Devices[cdrom]->fIsTocValid = (BOOL)dwRet;
  2971. CloseHandle( g_Devices[cdrom]->hThreadToc );
  2972. g_Devices[cdrom]->hThreadToc = NULL;
  2973. }
  2974. return g_Devices[cdrom]->fIsTocValid;
  2975. }
  2976. /******************************Public*Routine******************************\
  2977. * LockAllTableOfContents
  2978. *
  2979. * This function is used to determine if it is valid for the UI thread
  2980. * to access the table of contents for the ALL the cdroms devices.
  2981. * The function returns FALSE the UI thread should NOT touch the table of
  2982. * contents for any CD Rom.
  2983. *
  2984. * History:
  2985. * 18-11-93 - StephenE - Created
  2986. *
  2987. \**************************************************************************/
  2988. BOOL
  2989. LockALLTableOfContents(
  2990. void
  2991. )
  2992. {
  2993. BOOL fLock;
  2994. int i;
  2995. for (i = 0, fLock = TRUE; fLock && (i < g_NumCdDevices); i++) {
  2996. fLock = LockTableOfContents(i);
  2997. }
  2998. return fLock;
  2999. }
  3000. /******************************Public*Routine******************************\
  3001. * AllocMemory
  3002. *
  3003. * Allocates a memory of the given size. This function will terminate the
  3004. * application if the allocation failed. Memory allocated by this function
  3005. * must be freed with LocalFree. The memory should not be locked or unlocked.
  3006. *
  3007. * History:
  3008. * 18-11-93 - StephenE - Created
  3009. *
  3010. \**************************************************************************/
  3011. LPVOID
  3012. AllocMemory(
  3013. UINT uSize
  3014. )
  3015. {
  3016. LPVOID lp;
  3017. lp = LocalAlloc( LPTR, uSize );
  3018. if (lp == NULL) {
  3019. /*
  3020. ** No memory - no application, simple !
  3021. */
  3022. FatalApplicationError( STR_FAIL_INIT );
  3023. }
  3024. return lp;
  3025. }
  3026. /******************************Public*Routine******************************\
  3027. * SetPlayButtonsEnableState
  3028. *
  3029. * Sets the play buttons enable state to match the state of the current
  3030. * cdrom device. See below...
  3031. *
  3032. *
  3033. * CDPlayer buttons enable state table
  3034. * Ŀ
  3035. * E=Enabled D=Disabled Play Pause Eject Stop Other DataB
  3036. * Ĵ
  3037. * Disk in use D D D D D D
  3038. * Ĵ
  3039. * No music cd or data cdrom D D E D D D
  3040. * Ĵ
  3041. * Music cd (playing) D E E E E E
  3042. * Ĵ
  3043. * Music cd (paused) E E E E E E
  3044. * Ĵ
  3045. * Music cd (stopped) E D E D E E
  3046. *
  3047. *
  3048. * Note that the DataB(ase) button is actually on the toolbar.
  3049. *
  3050. * History:
  3051. * 18-11-93 - StephenE - Created
  3052. *
  3053. \**************************************************************************/
  3054. void
  3055. SetPlayButtonsEnableState(
  3056. void
  3057. )
  3058. {
  3059. BOOL fEnable;
  3060. BOOL fMusicCdLoaded;
  3061. BOOL fActivePlayList;
  3062. int i;
  3063. /*
  3064. ** Do we have a music cd loaded.
  3065. */
  3066. if (g_State & (CD_BEING_SCANNED | CD_NO_CD | CD_DATA_CD_LOADED | CD_IN_USE)) {
  3067. fMusicCdLoaded = FALSE;
  3068. }
  3069. else {
  3070. fMusicCdLoaded = TRUE;
  3071. }
  3072. /*
  3073. ** Is there an active playlist
  3074. */
  3075. if ( (CDTIME(g_CurrCdrom).TotalMin == 0) && (CDTIME(g_CurrCdrom).TotalSec == 0) ) {
  3076. fActivePlayList = FALSE;
  3077. }
  3078. else {
  3079. fActivePlayList = TRUE;
  3080. }
  3081. /*
  3082. ** Do the play button
  3083. */
  3084. if ( fMusicCdLoaded
  3085. && fActivePlayList
  3086. && ((g_State & CD_STOPPED) || (g_State & CD_PAUSED))) {
  3087. fEnable = TRUE;
  3088. }
  3089. else {
  3090. fEnable = FALSE;
  3091. }
  3092. EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)], fEnable );
  3093. /*
  3094. ** Do the stop and pause buttons
  3095. */
  3096. if ( fMusicCdLoaded
  3097. && fActivePlayList
  3098. && ((g_State & CD_PLAYING) || (g_State & CD_PAUSED))) {
  3099. EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)], TRUE );
  3100. EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_PAUSE)], TRUE );
  3101. }
  3102. else {
  3103. EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)], FALSE );
  3104. EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_PAUSE)], FALSE );
  3105. }
  3106. /*
  3107. ** Do the remaining buttons
  3108. */
  3109. for ( i = IDM_PLAYBAR_PREVTRACK; i <= IDM_PLAYBAR_NEXTTRACK; i++ ) {
  3110. EnableWindow( g_hwndControls[INDEX(i)], (fMusicCdLoaded && fActivePlayList) );
  3111. }
  3112. /*
  3113. ** If the drive is in use then we must diable the eject button.
  3114. */
  3115. EnableWindow( g_hwndControls[INDEX(IDM_PLAYBAR_EJECT)],
  3116. (g_State & (CD_BEING_SCANNED | CD_IN_USE)) ? FALSE : TRUE );
  3117. /*
  3118. ** Now do the database button on the toolbar.
  3119. */
  3120. SendMessage( g_hwndToolbar, TB_ENABLEBUTTON,
  3121. IDM_DATABASE_EDIT, (LPARAM)fMusicCdLoaded );
  3122. /*
  3123. ** Make sure that the keyboard focus is on the Eject button
  3124. ** if we have not got a CD loaded.
  3125. */
  3126. if ( GetFocus() == NULL ) {
  3127. if ( g_State & (CD_NO_CD | CD_DATA_CD_LOADED) ) {
  3128. SetFocus( g_hwndControls[INDEX(IDM_PLAYBAR_EJECT)] );
  3129. }
  3130. }
  3131. }
  3132. /******************************Public*Routine******************************\
  3133. * HeartBeatTimerProc
  3134. *
  3135. * This function is responsible for.
  3136. *
  3137. * 1. detecting new or ejected cdroms.
  3138. * 2. flashing the LED display if we are in paused mode.
  3139. * 3. Incrementing the LED display if we are in play mode.
  3140. *
  3141. * History:
  3142. * 18-11-93 - StephenE - Created
  3143. *
  3144. \**************************************************************************/
  3145. void CALLBACK
  3146. HeartBeatTimerProc(
  3147. HWND hwnd,
  3148. UINT uMsg,
  3149. UINT idEvent,
  3150. DWORD dwTime
  3151. )
  3152. {
  3153. static DWORD dwTickCount;
  3154. int i;
  3155. DWORD dwMod;
  3156. ++dwTickCount;
  3157. dwMod = (dwTickCount % 6);
  3158. /*
  3159. ** Check for new/ejected cdroms, do this every three seconds.
  3160. */
  3161. #if 0
  3162. // Note: This code no longer necessary, it is done on the
  3163. // WM_DEVICECHANGE message instead!!!
  3164. if ( 0 == dwMod ) {
  3165. for (i = 0; i < g_NumCdDevices; i++) {
  3166. if ( (!(g_Devices[i]->State & CD_EDITING))
  3167. && (!(g_Devices[i]->State & CD_PLAYING)) ) {
  3168. CheckUnitCdrom(i, FALSE);
  3169. }
  3170. }
  3171. }
  3172. #endif
  3173. if ( g_State & CD_PLAYING ) {
  3174. if ( LockALLTableOfContents() ) {
  3175. SyncDisplay();
  3176. }
  3177. }
  3178. /*
  3179. ** If we are paused and NOT skipping flash the display.
  3180. */
  3181. else if ((g_State & CD_PAUSED) && !(g_State & CD_SEEKING)) {
  3182. HWND hwnd;
  3183. switch ( dwMod ) {
  3184. case 2:
  3185. case 5:
  3186. case 8:
  3187. case 11:
  3188. if ( g_fIsIconic ) {
  3189. SetWindowText( g_hwndApp, g_szBlank );
  3190. UpdateWindow( g_hwndApp );
  3191. }
  3192. else {
  3193. hwnd = g_hwndControls[INDEX(IDC_LED)];
  3194. g_fFlashLed = TRUE;
  3195. SetWindowText( hwnd, g_szBlank );
  3196. g_fFlashLed = FALSE;
  3197. }
  3198. break;
  3199. case 0:
  3200. case 3:
  3201. case 6:
  3202. case 9:
  3203. UpdateDisplay( DISPLAY_UPD_LED );
  3204. break;
  3205. }
  3206. }
  3207. }
  3208. /******************************Public*Routine******************************\
  3209. * SkipBeatTimerProc
  3210. *
  3211. * This function is responsible for advancing or retreating the current
  3212. * playing position.
  3213. *
  3214. *
  3215. * History:
  3216. * 18-11-93 - StephenE - Created
  3217. *
  3218. \**************************************************************************/
  3219. void CALLBACK
  3220. SkipBeatTimerProc(
  3221. HWND hwnd,
  3222. UINT uMsg,
  3223. UINT idEvent,
  3224. DWORD dwTime
  3225. )
  3226. {
  3227. /*
  3228. ** Deteremine if it is time to accelerate the skipping frequency.
  3229. */
  3230. switch (++g_AcceleratorCount) {
  3231. case SKIP_ACCELERATOR_LIMIT1:
  3232. KillTimer( hwnd, idEvent );
  3233. SetTimer( hwnd, idEvent, SKIPBEAT_TIMER_RATE2, SkipBeatTimerProc );
  3234. break;
  3235. case SKIP_ACCELERATOR_LIMIT2:
  3236. KillTimer( hwnd, idEvent );
  3237. SetTimer( hwnd, idEvent, SKIPBEAT_TIMER_RATE3, SkipBeatTimerProc );
  3238. break;
  3239. }
  3240. if ( LockALLTableOfContents() ) {
  3241. if ( idEvent == IDM_PLAYBAR_SKIPFORE) {
  3242. TimeAdjustIncSecond( g_CurrCdrom );
  3243. /*
  3244. ** When TimeAjustIncSecond gets to the end of the last track
  3245. ** it sets CURRTRACK(g_CurrCdrom) equal to NULL. When this
  3246. ** occurs we effectively reset the CD Player
  3247. */
  3248. if ( CURRTRACK(g_CurrCdrom) == NULL ) {
  3249. if ( g_State & (CD_WAS_PLAYING | CD_PAUSED) ) {
  3250. SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)],
  3251. WM_LBUTTONDOWN, 0, 0L );
  3252. SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)],
  3253. WM_LBUTTONUP, 0, 0L );
  3254. }
  3255. else {
  3256. /*
  3257. ** Seek to the first playable track.
  3258. */
  3259. CURRTRACK(g_CurrCdrom) = FindFirstTrack( g_CurrCdrom );
  3260. if ( CURRTRACK(g_CurrCdrom) != NULL ) {
  3261. TimeAdjustSkipToTrack( g_CurrCdrom,
  3262. CURRTRACK(g_CurrCdrom) );
  3263. UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_TRACK_TIME |
  3264. DISPLAY_UPD_TRACK_NAME );
  3265. SetPlayButtonsEnableState();
  3266. SetFocus( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)] );
  3267. }
  3268. }
  3269. }
  3270. }
  3271. else {
  3272. TimeAdjustDecSecond( g_CurrCdrom );
  3273. }
  3274. }
  3275. }
  3276. /******************************Public*Routine******************************\
  3277. * UpdateDisplay
  3278. *
  3279. * This routine updates the display according to the flags that
  3280. * are passed in. The display consists of the LED display, the
  3281. * track and title names, the disc and track lengths and the cdrom
  3282. * combo-box.
  3283. *
  3284. * History:
  3285. * 18-11-93 - StephenE - Created
  3286. *
  3287. \**************************************************************************/
  3288. void
  3289. UpdateDisplay(
  3290. DWORD Flags
  3291. )
  3292. {
  3293. TCHAR lpsz[55];
  3294. TCHAR lpszIcon[75];
  3295. PTRACK_PLAY tr;
  3296. int track;
  3297. int mtemp, stemp, m, s;
  3298. /*
  3299. ** Check for valid flags
  3300. */
  3301. if ( Flags == 0 ) {
  3302. return;
  3303. }
  3304. /*
  3305. ** Grab current track information
  3306. */
  3307. if (CURRTRACK(g_CurrCdrom) != NULL) {
  3308. track = CURRTRACK(g_CurrCdrom)->TocIndex + FIRSTTRACK(g_CurrCdrom);
  3309. }
  3310. else {
  3311. track = 0;
  3312. }
  3313. /*
  3314. ** Update the LED box?
  3315. */
  3316. if (Flags & DISPLAY_UPD_LED) {
  3317. /*
  3318. ** Update LED box
  3319. */
  3320. if (g_fDisplayT) {
  3321. if (Flags & DISPLAY_UPD_LEADOUT_TIME) {
  3322. wsprintf( lpsz, TRACK_TIME_LEADOUT_FORMAT,
  3323. track,
  3324. CDTIME(g_CurrCdrom).TrackCurMin,
  3325. g_szTimeSep,
  3326. CDTIME(g_CurrCdrom).TrackCurSec );
  3327. }
  3328. else {
  3329. wsprintf( lpsz, TRACK_TIME_FORMAT,
  3330. track,
  3331. CDTIME(g_CurrCdrom).TrackCurMin,
  3332. g_szTimeSep,
  3333. CDTIME(g_CurrCdrom).TrackCurSec );
  3334. }
  3335. }
  3336. if (g_fDisplayTr) {
  3337. if (Flags & DISPLAY_UPD_LEADOUT_TIME) {
  3338. wsprintf( lpsz, TRACK_REM_FORMAT, track - 1,
  3339. CDTIME(g_CurrCdrom).TrackCurMin,
  3340. g_szTimeSep,
  3341. CDTIME(g_CurrCdrom).TrackCurSec );
  3342. }
  3343. else {
  3344. wsprintf( lpsz, TRACK_REM_FORMAT, track,
  3345. CDTIME(g_CurrCdrom).TrackRemMin,
  3346. g_szTimeSep,
  3347. CDTIME(g_CurrCdrom).TrackRemSec );
  3348. }
  3349. }
  3350. if (g_fDisplayDr) {
  3351. /*
  3352. ** Compute remaining time
  3353. */
  3354. mtemp = stemp = m = s =0;
  3355. if (CURRTRACK(g_CurrCdrom) != NULL) {
  3356. for ( tr = CURRTRACK(g_CurrCdrom)->nextplay;
  3357. tr != NULL;
  3358. tr = tr->nextplay ) {
  3359. FigureTrackTime( g_CurrCdrom, tr->TocIndex, &mtemp, &stemp );
  3360. m+=mtemp;
  3361. s+=stemp;
  3362. }
  3363. m+= CDTIME(g_CurrCdrom).TrackRemMin;
  3364. s+= CDTIME(g_CurrCdrom).TrackRemSec;
  3365. }
  3366. m+= (s / 60);
  3367. s = (s % 60);
  3368. CDTIME(g_CurrCdrom).RemMin = m;
  3369. CDTIME(g_CurrCdrom).RemSec = s;
  3370. wsprintf( lpsz, DISC_REM_FORMAT,
  3371. CDTIME(g_CurrCdrom).RemMin,
  3372. g_szTimeSep,
  3373. CDTIME(g_CurrCdrom).RemSec );
  3374. }
  3375. SetWindowText( g_hwndControls[INDEX(IDC_LED)], lpsz );
  3376. if (g_fIsIconic) {
  3377. wsprintf( lpszIcon, IdStr( STR_CDPLAYER_TIME ), lpsz );
  3378. SetWindowText( g_hwndApp, lpszIcon );
  3379. }
  3380. }
  3381. /*
  3382. ** Update Title?
  3383. */
  3384. if (Flags & DISPLAY_UPD_TITLE_NAME) {
  3385. ComputeDriveComboBox( );
  3386. SetWindowText( g_hwndControls[INDEX(IDC_TITLE_NAME)],
  3387. (LPCTSTR)TITLE(g_CurrCdrom) );
  3388. }
  3389. /*
  3390. ** Update track name?
  3391. */
  3392. if (Flags & DISPLAY_UPD_TRACK_NAME) {
  3393. HWND hwnd;
  3394. hwnd = g_hwndControls[INDEX(IDC_TRACK_LIST)];
  3395. if (CURRTRACK(g_CurrCdrom) != NULL) {
  3396. track = 0;
  3397. for( tr = PLAYLIST(g_CurrCdrom);
  3398. tr != CURRTRACK(g_CurrCdrom);
  3399. tr = tr->nextplay, track++ );
  3400. ComboBox_SetCurSel( hwnd, track );
  3401. }
  3402. else {
  3403. ComboBox_SetCurSel( hwnd, 0 );
  3404. }
  3405. }
  3406. /*
  3407. ** Update disc time?
  3408. */
  3409. if (Flags & DISPLAY_UPD_DISC_TIME) {
  3410. wsprintf( lpsz,
  3411. IdStr( STR_TOTAL_PLAY ), /*"Total Play: %02d:%02d m:s", */
  3412. CDTIME(g_CurrCdrom).TotalMin,
  3413. g_szTimeSep,
  3414. CDTIME(g_CurrCdrom).TotalSec,
  3415. g_szTimeSep );
  3416. SendMessage( g_hwndStatusbar, SB_SETTEXT, 0, (LPARAM)lpsz );
  3417. }
  3418. /*
  3419. ** Update track time?
  3420. */
  3421. if (Flags & DISPLAY_UPD_TRACK_TIME) {
  3422. wsprintf( lpsz,
  3423. IdStr( STR_TRACK_PLAY ), /* "Track: %02d:%02d m:s", */
  3424. CDTIME(g_CurrCdrom).TrackTotalMin,
  3425. g_szTimeSep,
  3426. CDTIME(g_CurrCdrom).TrackTotalSec,
  3427. g_szTimeSep );
  3428. SendMessage( g_hwndStatusbar, SB_SETTEXT, 1, (LPARAM)lpsz );
  3429. }
  3430. }
  3431. /******************************Public*Routine******************************\
  3432. * Common_OnCtlColor
  3433. *
  3434. * Here we return a brush to paint the background with. The brush is the same
  3435. * color as the face of a button. We also set the text background color so
  3436. * that static controls draw correctly. This function is shared with the
  3437. * disk info/editing dialog box.
  3438. *
  3439. * History:
  3440. * dd-mm-93 - StephenE - Created
  3441. *
  3442. \**************************************************************************/
  3443. HBRUSH
  3444. Common_OnCtlColor(
  3445. HWND hwnd,
  3446. HDC hdc,
  3447. HWND hwndChild,
  3448. int type
  3449. )
  3450. {
  3451. SetBkColor( hdc, rgbFace );
  3452. return g_hBrushBkgd;
  3453. }
  3454. /******************************Public*Routine******************************\
  3455. * Common_OnMeasureItem
  3456. *
  3457. * All items are the same height and width.
  3458. *
  3459. * We only have to update the height field for owner draw combo boxes and
  3460. * list boxes. This function is shared with the disk edit/info dialog box.
  3461. *
  3462. * History:
  3463. * dd-mm-93 - StephenE - Created
  3464. *
  3465. \**************************************************************************/
  3466. BOOL
  3467. Common_OnMeasureItem(
  3468. HWND hwnd,
  3469. MEASUREITEMSTRUCT *lpMeasureItem
  3470. )
  3471. {
  3472. HFONT hFont;
  3473. int cyBorder;
  3474. LOGFONT lf;
  3475. hFont = GetWindowFont( hwnd );
  3476. #ifdef JAPAN
  3477. //fix kksuzuka: #3116
  3478. //in 16, 20, 24 dot font, some charcters, such as "g" or "p", needs more rooms.
  3479. {
  3480. UINT iHeight;
  3481. if ( hFont != NULL )
  3482. {
  3483. GetObject( hFont, sizeof(lf), &lf );
  3484. }
  3485. else
  3486. {
  3487. SystemParametersInfo( SPI_GETICONTITLELOGFONT,
  3488. sizeof(lf), (LPVOID)&lf, 0 );
  3489. }
  3490. iHeight = ABS( lf.lfHeight );
  3491. lpMeasureItem->itemHeight = iHeight / 2 * 3;
  3492. }
  3493. #else
  3494. if ( hFont != NULL ) {
  3495. GetObject( hFont, sizeof(lf), &lf );
  3496. cyBorder = GetSystemMetrics( SM_CYBORDER );
  3497. lpMeasureItem->itemHeight = ABS( lf.lfHeight ) + (4 * cyBorder);
  3498. }
  3499. else {
  3500. lpMeasureItem->itemHeight = 14;
  3501. }
  3502. #endif
  3503. return TRUE;
  3504. }
  3505. /******************************Public*Routine******************************\
  3506. * DrawTrackItem
  3507. *
  3508. * This routine draws the information in a cell of the track name
  3509. * combo box.
  3510. *
  3511. * History:
  3512. * 18-11-93 - StephenE - Created
  3513. *
  3514. \**************************************************************************/
  3515. void
  3516. DrawTrackItem(
  3517. HDC hdc,
  3518. const RECT *r,
  3519. DWORD item,
  3520. BOOL selected
  3521. )
  3522. {
  3523. SIZE si;
  3524. int i;
  3525. int cxTrk;
  3526. PTRACK_INF t;
  3527. TCHAR s[ARTIST_LENGTH];
  3528. TCHAR szTrk[16];
  3529. /*
  3530. ** Check for invalid items
  3531. */
  3532. if ( item == (DWORD)-1 ) {
  3533. return;
  3534. }
  3535. if ( ALLTRACKS(g_CurrCdrom) == NULL ) {
  3536. return;
  3537. }
  3538. /*
  3539. ** Check selection status, and set up to draw correctly
  3540. */
  3541. if ( selected ) {
  3542. SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
  3543. SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
  3544. }
  3545. else {
  3546. SetBkColor( hdc, GetSysColor(COLOR_WINDOW));
  3547. SetTextColor( hdc, GetSysColor(COLOR_WINDOWTEXT));
  3548. }
  3549. /*
  3550. ** Get track info
  3551. */
  3552. t = FindTrackNodeFromTocIndex( item, ALLTRACKS( g_CurrCdrom ) );
  3553. if ( (t != NULL) && (t->name != NULL) ) {
  3554. /*
  3555. ** Do we need to munge track name (clip to listbox)?
  3556. */
  3557. wsprintf(szTrk, TEXT("<%02d> "), t->TocIndex + FIRSTTRACK(g_CurrCdrom));
  3558. GetTextExtentPoint( hdc, szTrk, _tcslen(szTrk), &si );
  3559. cxTrk = si.cx;
  3560. i = _tcslen( t->name ) + 1;
  3561. do {
  3562. GetTextExtentPoint( hdc, t->name, --i, &si );
  3563. } while( si.cx > (r->right - r->left - cxTrk) );
  3564. ZeroMemory( s, TRACK_TITLE_LENGTH * sizeof( TCHAR ) );
  3565. _tcsncpy( s, t->name, i );
  3566. }
  3567. else {
  3568. _tcscpy( s, g_szBlank );
  3569. i = 1;
  3570. }
  3571. /*
  3572. ** Draw track name
  3573. */
  3574. ExtTextOut( hdc, r->left, r->top,
  3575. ETO_OPAQUE | ETO_CLIPPED,
  3576. r, s, i, NULL );
  3577. /*
  3578. ** draw track number
  3579. */
  3580. if ( t != NULL ) {
  3581. ExtTextOut( hdc, r->right - cxTrk, r->top, ETO_CLIPPED,
  3582. r, szTrk, _tcslen( szTrk ), NULL );
  3583. }
  3584. }
  3585. /******************************Public*Routine******************************\
  3586. * DrawDriveItem
  3587. *
  3588. * This routine draws the information in a cell of the drive/artist
  3589. * combo box.
  3590. *
  3591. * History:
  3592. * 18-11-93 - StephenE - Created
  3593. *
  3594. \**************************************************************************/
  3595. void
  3596. DrawDriveItem(
  3597. HDC hdc,
  3598. const RECT *r,
  3599. DWORD item,
  3600. BOOL selected
  3601. )
  3602. {
  3603. SIZE si;
  3604. int i;
  3605. int j;
  3606. int cxDrv;
  3607. TCHAR szDrv[16];
  3608. /*
  3609. ** Check for invalid items
  3610. */
  3611. if ( item == (DWORD)-1 ) {
  3612. return;
  3613. }
  3614. /*
  3615. ** Check selection status, and set up to draw correctly
  3616. */
  3617. if (selected) {
  3618. SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
  3619. SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
  3620. }
  3621. else {
  3622. SetBkColor( hdc, GetSysColor(COLOR_WINDOW));
  3623. SetTextColor( hdc, GetSysColor(COLOR_WINDOWTEXT));
  3624. }
  3625. /*
  3626. ** Do we need to munge artist name (clip)?
  3627. */
  3628. wsprintf( szDrv, TEXT("<%c:> "), g_Devices[item]->drive );
  3629. j = _tcslen( szDrv );
  3630. GetTextExtentPoint( hdc, szDrv, j, &si );
  3631. cxDrv = si.cx;
  3632. i = _tcslen( ARTIST(item) ) + 1;
  3633. do {
  3634. GetTextExtentPoint( hdc, ARTIST(item), --i, &si );
  3635. } while( si.cx > (r->right - r->left - cxDrv) );
  3636. /*
  3637. ** Draw artist name
  3638. */
  3639. ExtTextOut( hdc, r->left, r->top, ETO_OPAQUE | ETO_CLIPPED, r,
  3640. ARTIST(item), i, NULL );
  3641. /*
  3642. ** draw drive letter
  3643. */
  3644. ExtTextOut( hdc, r->right - cxDrv, r->top, ETO_CLIPPED, r,
  3645. szDrv, j, NULL );
  3646. }
  3647. /*****************************Private*Routine******************************\
  3648. * StartSndVol
  3649. *
  3650. * Trys to start sndvol (the NT sound volume piglet).
  3651. *
  3652. * History:
  3653. * dd-mm-94 - StephenE - Created
  3654. *
  3655. \**************************************************************************/
  3656. void
  3657. StartSndVol(
  3658. DWORD unused
  3659. )
  3660. {
  3661. /*
  3662. ** WinExec returns a value greater than 31 if suceeds
  3663. */
  3664. g_fVolumeController = (WinExec( "sndvol32", SW_SHOW ) > 31);
  3665. ExitThread( 0 );
  3666. }
  3667. /*****************************Private*Routine******************************\
  3668. * EnableToolTips
  3669. *
  3670. * Enables or disables the display of tool tips according to the fEnable
  3671. * parameter
  3672. *
  3673. * History:
  3674. * 18-09-94 - StephenE - Created
  3675. *
  3676. \**************************************************************************/
  3677. void
  3678. EnableToolTips(
  3679. BOOL fEnable
  3680. )
  3681. {
  3682. HWND hwndTips;
  3683. hwndTips = (HWND)SendMessage( g_hwndApp, TB_GETTOOLTIPS, 0, 0L );
  3684. SendMessage( hwndTips, TTM_ACTIVATE, fEnable, 0L );
  3685. hwndTips = (HWND)SendMessage( g_hwndToolbar, TB_GETTOOLTIPS, 0, 0L );
  3686. SendMessage( hwndTips, TTM_ACTIVATE, fEnable, 0L );
  3687. }
  3688. /*****************************Private*Routine******************************\
  3689. * HandlePassedCommandLine
  3690. *
  3691. * This function gets called to handle command line options that are passed to
  3692. * CDPlayer as the result of the WM_DROPFILES or WM_COPYDATA messages.
  3693. *
  3694. * History:
  3695. * dd-mm-94 - StephenE - Created
  3696. *
  3697. \**************************************************************************/
  3698. void
  3699. HandlePassedCommandLine(
  3700. LPTSTR lpCmdLine,
  3701. BOOL fCheckCDRom
  3702. )
  3703. {
  3704. int i;
  3705. int iTrack = -1, iCDrom;
  3706. iCDrom = ParseCommandLine( lpCmdLine, &iTrack, TRUE );
  3707. if ((iCDrom < 0) || (iCDrom >= g_NumCdDevices))
  3708. return;
  3709. // CheckUnitCDRom to reload Table of Contents
  3710. if ( fCheckCDRom )
  3711. {
  3712. CheckUnitCdrom(iCDrom, TRUE);
  3713. while( !LockTableOfContents(iCDrom) )
  3714. {
  3715. MSG msg;
  3716. GetMessage( &msg, NULL, WM_NOTIFY_TOC_READ, WM_NOTIFY_TOC_READ );
  3717. DispatchMessage( &msg );
  3718. }
  3719. }
  3720. if (iCDrom != g_CurrCdrom)
  3721. {
  3722. HWND hwndBtn = g_hwndControls[INDEX(IDC_ARTIST_NAME)];
  3723. SwitchToCdrom( iCDrom, TRUE );
  3724. SetPlayButtonsEnableState();
  3725. SendMessage( hwndBtn, CB_SETCURSEL, (WPARAM)iCDrom, 0 );
  3726. }
  3727. /*
  3728. ** Initialize the new play list for each drive.
  3729. */
  3730. for ( i = 0; i < g_NumCdDevices; i++)
  3731. {
  3732. TimeAdjustInitialize( i );
  3733. }
  3734. // Set Current Track to specified track
  3735. if ( iTrack != -1 )
  3736. {
  3737. PTRACK_PLAY tr;
  3738. tr = PLAYLIST( g_CurrCdrom );
  3739. if ( tr != NULL )
  3740. {
  3741. for( i = 0; i < iTrack; i++, tr = tr->nextplay );
  3742. TimeAdjustSkipToTrack( g_CurrCdrom, tr );
  3743. }
  3744. }
  3745. }
  3746. /******************************Public*Routine******************************\
  3747. * IsPlayOptionGiven
  3748. *
  3749. * Checks the command line to see if the "-play" option has been passed.
  3750. *
  3751. * History:
  3752. * dd-mm-95 - StephenE - Created
  3753. *
  3754. \**************************************************************************/
  3755. BOOL
  3756. IsPlayOptionGiven(
  3757. LPTSTR lpstr
  3758. )
  3759. {
  3760. TCHAR chOption[MAX_PATH];
  3761. /*
  3762. ** Start by converting everything to upper case.
  3763. */
  3764. CharUpperBuff( lpstr, _tcslen(lpstr) );
  3765. /*
  3766. ** The first parameter on the command line is always the
  3767. ** string used invoke the program. ie cdplayer.exe
  3768. */
  3769. lpstr += _tcsspn( lpstr, g_szBlank );
  3770. lpstr += CopyWord( chOption, lpstr );
  3771. /*
  3772. ** Remove leading space
  3773. */
  3774. lpstr += _tcsspn( lpstr, g_szBlank );
  3775. /*
  3776. ** process any command line options
  3777. */
  3778. while ( (*lpstr == g_chOptionHyphen) || (*lpstr == g_chOptionSlash) ) {
  3779. /*
  3780. ** pass over the option delimeter
  3781. */
  3782. lpstr++;
  3783. /*
  3784. ** Copy option and skip over it.
  3785. */
  3786. lpstr += CopyWord( chOption, lpstr );
  3787. /*
  3788. ** Is this the play option ?? If so, don't bother processing anymore
  3789. ** options.
  3790. */
  3791. if ( 0 == _tcscmp( chOption, g_szPlay ) ) {
  3792. return TRUE;
  3793. }
  3794. /*
  3795. ** Remove leading space
  3796. */
  3797. lpstr += _tcsspn( lpstr, g_szBlank );
  3798. }
  3799. return FALSE;
  3800. }
  3801. /******************************Public*Routine******************************\
  3802. * IsUpdateOptionGiven
  3803. *
  3804. * Checks the command line to see if the "-update" option has been passed.
  3805. *
  3806. * History:
  3807. * dd-mm-95 - StephenE - Created
  3808. *
  3809. \**************************************************************************/
  3810. BOOL
  3811. IsUpdateOptionGiven(
  3812. LPTSTR lpstr
  3813. )
  3814. {
  3815. TCHAR chOption[MAX_PATH];
  3816. /*
  3817. ** Start by converting everything to upper case.
  3818. */
  3819. CharUpperBuff( lpstr, _tcslen(lpstr) );
  3820. /*
  3821. ** The first parameter on the command line is always the
  3822. ** string used invoke the program. ie cdplayer.exe
  3823. */
  3824. lpstr += _tcsspn( lpstr, g_szBlank );
  3825. lpstr += CopyWord( chOption, lpstr );
  3826. /*
  3827. ** Remove leading space
  3828. */
  3829. lpstr += _tcsspn( lpstr, g_szBlank );
  3830. /*
  3831. ** process any command line options
  3832. */
  3833. while ( (*lpstr == g_chOptionHyphen) || (*lpstr == g_chOptionSlash) ) {
  3834. /*
  3835. ** pass over the option delimeter
  3836. */
  3837. lpstr++;
  3838. /*
  3839. ** Copy option and skip over it.
  3840. */
  3841. lpstr += CopyWord( chOption, lpstr );
  3842. /*
  3843. ** Is this the play option ?? If so, don't bother processing anymore
  3844. ** options.
  3845. */
  3846. if ( 0 == _tcscmp( chOption, g_szUpdate ) ) {
  3847. return TRUE;
  3848. }
  3849. /*
  3850. ** Remove leading space
  3851. */
  3852. lpstr += _tcsspn( lpstr, g_szBlank );
  3853. }
  3854. return FALSE;
  3855. }
  3856. /*****************************Private*Routine******************************\
  3857. * ParseCommandLine
  3858. *
  3859. * Here we look to see if we have been asked to play a particular track.
  3860. * The format of the command line is:
  3861. *
  3862. *
  3863. * CDPlayer command options.
  3864. *
  3865. * CDPLAYER {Options}
  3866. *
  3867. * Options : -play | {Sub-Options}
  3868. * Sub-Options : {-track tracklist} | trackname
  3869. * trackname : filename | drive letter
  3870. * tracklist : filename+
  3871. *
  3872. * -track A track list if a list of tracks that the user wants
  3873. * to play. It overides any play list that may already be stored
  3874. * for the current cd.
  3875. *
  3876. * -play Start playing the current play list. If -play is not specified
  3877. * CD Player seeks to the first track in the play list.
  3878. *
  3879. *
  3880. * On Windows NT the format of [file] is:
  3881. * d:\track(nn).cda
  3882. *
  3883. * where d: is the drive letter of the cdrom that you want to play
  3884. * and \track(nn) is the track number that you want to play.
  3885. *
  3886. * Therefore to play track 8 from a cd-rom drive mapped to e:
  3887. *
  3888. * cdplayer /play e:\track08.cda
  3889. *
  3890. * On Chicago the file is actually a riff CDDA file which contains
  3891. * all the info required to locate the disc and track.
  3892. *
  3893. * Returns the index of the CD-Rom drive which should be played first. Can return
  3894. * -1 iff the caller passed FALSE for the fQuiet parameter and the message box was
  3895. * actually displayed. This should only occur when the user trys to start a new
  3896. * copy of cdplayer passing it the track.cda file of a disk that is not inserted
  3897. * in any of the current CD-Drives attached to the machine.
  3898. *
  3899. * History:
  3900. * dd-mm-94 - StephenE - Created
  3901. *
  3902. \**************************************************************************/
  3903. int
  3904. ParseCommandLine(
  3905. LPTSTR lpstr,
  3906. int *piTrackToSeekTo,
  3907. BOOL fQuiet
  3908. )
  3909. {
  3910. TCHAR chOption[MAX_PATH];
  3911. BOOL fTrack = FALSE;
  3912. int iCdRomIndex = -1; // Assume Failure until proven otherwise
  3913. int ii;
  3914. for (ii = 0; ii < g_NumCdDevices; ii++) {
  3915. g_Devices[ii]->fKilledPlayList = FALSE;
  3916. }
  3917. /*
  3918. ** Start by converting everything to upper case.
  3919. */
  3920. CharUpperBuff( lpstr, _tcslen(lpstr) );
  3921. #if DBG
  3922. #ifdef UNICODE
  3923. dprintf( "CD Player Command line : %ls", lpstr );
  3924. #else
  3925. dprintf( "CD Player Command line : %s", lpstr );
  3926. #endif
  3927. #endif
  3928. /*
  3929. ** The first parameter on the command line is always the
  3930. ** string used invoke the program. ie cdplayer.exe
  3931. */
  3932. lpstr += _tcsspn( lpstr, g_szBlank );
  3933. lpstr += CopyWord( chOption, lpstr );
  3934. /*
  3935. ** Remove leading space
  3936. */
  3937. lpstr += _tcsspn( lpstr, g_szBlank );
  3938. /*
  3939. ** process any command line options
  3940. */
  3941. while ( (*lpstr == g_chOptionHyphen) || (*lpstr == g_chOptionSlash) ) {
  3942. /*
  3943. ** pass over the option delimeter
  3944. */
  3945. lpstr++;
  3946. /*
  3947. ** Copy option and skip over it.
  3948. */
  3949. lpstr += CopyWord( chOption, lpstr );
  3950. /*
  3951. ** Is this a command line option we understand - ignore ones
  3952. ** we don't understand.
  3953. */
  3954. if ( 0 == _tcscmp( chOption, g_szTrack ) ) {
  3955. if ( !fTrack ) {
  3956. lpstr = ParseTrackList( lpstr, &iCdRomIndex );
  3957. fTrack = TRUE;
  3958. }
  3959. }
  3960. else if ( 0 == _tcscmp( chOption, g_szPlay ) ) {
  3961. g_fPlay = TRUE;
  3962. }
  3963. else {
  3964. #if DBG
  3965. #ifdef UNICODE
  3966. dprintf("Ignoring unknown option %ls\n", chOption );
  3967. #else
  3968. dprintf("Ignoring unknown option %s\n", chOption );
  3969. #endif
  3970. #endif
  3971. }
  3972. /*
  3973. ** Remove leading space
  3974. */
  3975. lpstr += _tcsspn( lpstr, g_szBlank );
  3976. }
  3977. /*
  3978. ** parse remaining command line parameters
  3979. */
  3980. if ( (*lpstr != g_chNULL) && !fTrack) {
  3981. /*
  3982. ** Copy track name and skip over it. Sometimes the shell
  3983. ** gives us quoted strings and sometimes it doesn't. If the
  3984. ** string is not quoted assume that remainder of the command line
  3985. ** is the track name.
  3986. */
  3987. if ( (*lpstr == TEXT('\'')) || (*lpstr == TEXT('\"')) ) {
  3988. lpstr += CopyWord( chOption, lpstr );
  3989. }
  3990. else {
  3991. _tcscpy(chOption, lpstr);
  3992. }
  3993. if ( IsTrackFileNameValid( chOption, &iCdRomIndex,
  3994. piTrackToSeekTo, FALSE, fQuiet ) ) {
  3995. ResetPlayList( iCdRomIndex );
  3996. }
  3997. #if DBG
  3998. #ifdef UNICODE
  3999. dprintf("Seeking to track %ls\n", chOption );
  4000. #else
  4001. dprintf("Seeking to track %s\n", chOption );
  4002. #endif
  4003. #endif
  4004. }
  4005. return iCdRomIndex;
  4006. }
  4007. /*****************************Private*Routine******************************\
  4008. * ParseTrackList
  4009. *
  4010. * Each track is separated by a ' ' character. The track list is terminated
  4011. * by the NULL, '/' or '-' character.
  4012. *
  4013. * History:
  4014. * dd-mm-94 - StephenE - Created
  4015. *
  4016. \**************************************************************************/
  4017. TCHAR *
  4018. ParseTrackList(
  4019. TCHAR *szTrackList,
  4020. int *piCdRomIndex
  4021. )
  4022. {
  4023. TCHAR chTrack[MAX_PATH];
  4024. int iTrackIndex;
  4025. int iCdRom = -1; // Assume failure, until proven otherwise
  4026. BOOL fPlayListErased = FALSE;
  4027. /*
  4028. ** Remove any stray white space
  4029. */
  4030. szTrackList += _tcsspn( szTrackList, g_szBlank );
  4031. /*
  4032. ** While there are still valid characters to process
  4033. */
  4034. while ( (*szTrackList != g_chNULL)
  4035. && (*szTrackList != g_chOptionHyphen)
  4036. && (*szTrackList != g_chOptionSlash) ) {
  4037. /*
  4038. ** Copy the track name and skip over it.
  4039. */
  4040. szTrackList += CopyWord( chTrack, szTrackList );
  4041. /*
  4042. ** Now check that we have been given a valid filename
  4043. */
  4044. if ( IsTrackFileNameValid( chTrack, &iCdRom, &iTrackIndex, TRUE, FALSE ) ) {
  4045. PTRACK_PLAY pt;
  4046. /*
  4047. ** If this is the first valid file given nuke the
  4048. ** existing play lists and prepare for a new list. Note that
  4049. ** things are complicated by the fact that we could be given
  4050. ** files from more than one CD-Rom drive.
  4051. */
  4052. if (! g_Devices[iCdRom]->fKilledPlayList)
  4053. {
  4054. /*
  4055. ** Kill the old play and save lists.
  4056. */
  4057. ErasePlayList( iCdRom );
  4058. EraseSaveList( iCdRom );
  4059. PLAYLIST( iCdRom ) = NULL;
  4060. SAVELIST( iCdRom ) = NULL;
  4061. fPlayListErased = TRUE;
  4062. g_Devices[iCdRom]->fKilledPlayList = TRUE;
  4063. *piCdRomIndex = iCdRom;
  4064. }
  4065. pt = AllocMemory( sizeof(TRACK_PLAY) );
  4066. pt->TocIndex = iTrackIndex;
  4067. pt->min = 0;
  4068. pt->sec = 0;
  4069. /*
  4070. ** Is this the first track on this devices play list ?
  4071. */
  4072. if ( PLAYLIST(iCdRom) == NULL ) {
  4073. PLAYLIST(iCdRom) = pt;
  4074. pt->nextplay = pt->prevplay = NULL;
  4075. }
  4076. else {
  4077. /*
  4078. ** append this track to the end of the current play list
  4079. */
  4080. AppendTrackToPlayList( PLAYLIST(iCdRom), pt );
  4081. }
  4082. }
  4083. else {
  4084. /*
  4085. ** Put up a message box warning the user that the given
  4086. ** track name is invalid and that we can't play it.
  4087. */
  4088. ;
  4089. }
  4090. /*
  4091. ** Remove any stray white space
  4092. */
  4093. szTrackList += _tcsspn( szTrackList, g_szBlank );
  4094. }
  4095. /*
  4096. ** If we have erased the play list we have to go off and reset the
  4097. ** saved play list.
  4098. */
  4099. if ( fPlayListErased ) {
  4100. SAVELIST( iCdRom ) = CopyPlayList( PLAYLIST(iCdRom) );
  4101. }
  4102. return szTrackList;
  4103. }
  4104. /*****************************Private*Routine******************************\
  4105. * CopyWord
  4106. *
  4107. * Copies one from szSource to szWord - assumes that words are delimited
  4108. * by ' ' characters. szSource MUST point to the begining of the word.
  4109. *
  4110. * Returns length of word copied.
  4111. *
  4112. * History:
  4113. * dd-mm-94 - StephenE - Created
  4114. *
  4115. \**************************************************************************/
  4116. int
  4117. CopyWord(
  4118. TCHAR *szWord,
  4119. TCHAR *szSource
  4120. )
  4121. {
  4122. int n, nReturn;
  4123. /*
  4124. ** Copy the track name
  4125. */
  4126. if ( (*szSource == TEXT('\'')) || (*szSource == TEXT('\"')) ) {
  4127. TCHAR ch = *szSource;
  4128. /*
  4129. ** Remember which quote character it was
  4130. ** According to the DOCS " is invalid in a filename...
  4131. */
  4132. n = 0;
  4133. /*
  4134. ** Move over the initial quote, then copy the filename
  4135. */
  4136. while ( *++szSource && *szSource != ch ) {
  4137. szWord[n++] = *szSource;
  4138. }
  4139. nReturn = n + (*szSource == ch ? 2 : 1);
  4140. }
  4141. else {
  4142. n = _tcscspn( szSource, g_szBlank );
  4143. _tcsncpy( szWord, szSource, n );
  4144. nReturn = n;
  4145. }
  4146. szWord[n] = g_chNULL;
  4147. return nReturn;
  4148. }
  4149. /*****************************Private*Routine******************************\
  4150. * IsTrackFileNameValid
  4151. *
  4152. * This function returns true if the specified filename is a valid CD track.
  4153. * On NT track filenames must be of the form:
  4154. * d:\track(n).cda where d: is the CD-Rom device and \track(n).cda
  4155. * is the index of the track to be played (starting from 1).
  4156. *
  4157. * On Chicago the track filename is actually a riff CDDA file which contains
  4158. * the track info that we require.
  4159. *
  4160. * If the filename is valid the function true and sets piCdromIndex and
  4161. * piTrackIndex to the correct values.
  4162. *
  4163. * History:
  4164. * 29-09-94 - StephenE - Created
  4165. *
  4166. \**************************************************************************/
  4167. BOOL
  4168. IsTrackFileNameValid(
  4169. LPTSTR lpstFileName,
  4170. int *piCdRomIndex,
  4171. int *piTrackIndex,
  4172. BOOL fScanningTracks,
  4173. BOOL fQuiet
  4174. )
  4175. {
  4176. #define RIFF_RIFF 0x46464952
  4177. #define RIFF_CDDA 0x41444443
  4178. RIFFCDA cda;
  4179. HANDLE hFile;
  4180. TCHAR chDriveLetter;
  4181. int i;
  4182. TCHAR szFileName[MAX_PATH];
  4183. TCHAR szPath[MAX_PATH];
  4184. SHFILEINFO shInfo;
  4185. DWORD cbRead;
  4186. //
  4187. // If we are not constructing a track play list it is valid to just specify
  4188. // a drive letter, in which case we select that drive and start playing
  4189. // at the first track on it. All the tracks are played in sequential
  4190. // order.
  4191. //
  4192. if ( !fScanningTracks) {
  4193. //
  4194. // Map the drive letter onto the internal CD-Rom index used by CDPlayer.
  4195. //
  4196. chDriveLetter = *lpstFileName;
  4197. for ( i = 0; i < g_NumCdDevices; i++ ) {
  4198. if (g_Devices[i]->drive == chDriveLetter) {
  4199. *piCdRomIndex = i;
  4200. break;
  4201. }
  4202. }
  4203. //
  4204. // If we mapped the drive OK check to see if we should play all
  4205. // the tracks or just the current play list for that drive. If we
  4206. // didn't map the drive OK assume that its the first part of a
  4207. // RIFF filename and fall through to the code below that opens the
  4208. // RIFF file and parses its contents.
  4209. //
  4210. if ( i != g_NumCdDevices ) {
  4211. //
  4212. // If next character is only a colon ':' then play the
  4213. // the entire disk starting from the first track.
  4214. //
  4215. if ( 0 == _tcscmp(lpstFileName + 1, g_szColon) ) {
  4216. *piTrackIndex = 0;
  4217. return TRUE;
  4218. }
  4219. //
  4220. // If the next two characters are colon backslash ":\" then
  4221. // we seek to the specified drive and play only those tracks that
  4222. // are in the default playlist for the current disk in that drive.
  4223. // All we need to do to achive this is return FALSE.
  4224. //
  4225. if ( 0 == _tcscmp(lpstFileName + 1, g_szColonBackSlash) ) {
  4226. return FALSE;
  4227. }
  4228. }
  4229. }
  4230. //
  4231. // Otherwise, open the file and read the CDA info. The file name may be a
  4232. // link to .cda in which case we need to get the shell to resolve the link for
  4233. // us. We take a copy of the file name because the ResolveLink function
  4234. // modifies the file name string in place.
  4235. //
  4236. _tcscpy(szFileName, lpstFileName);
  4237. if (0L == SHGetFileInfo( szFileName, 0L, &shInfo,
  4238. sizeof(shInfo), SHGFI_ATTRIBUTES)) {
  4239. return FALSE;
  4240. }
  4241. if ((shInfo.dwAttributes & SFGAO_LINK) == SFGAO_LINK) {
  4242. if (!g_fOleInitialized) {
  4243. g_fOleInitialized = SUCCEEDED(OleInitialize(NULL));
  4244. }
  4245. if (!ResolveLink(szFileName)) {
  4246. return FALSE;
  4247. }
  4248. }
  4249. // Make sure file exists
  4250. if (GetFileAttributes (szFileName) == ((DWORD)-1)) {
  4251. // Get Full path to file
  4252. if (0 == SearchPath (NULL, szFileName, NULL,
  4253. MAX_PATH, szPath, NULL)) {
  4254. return FALSE;
  4255. }
  4256. } else {
  4257. lstrcpy (szPath, szFileName);
  4258. }
  4259. // Open file and read in CDA info
  4260. hFile = CreateFile (szFileName, GENERIC_READ,
  4261. FILE_SHARE_READ, NULL,
  4262. OPEN_EXISTING, 0, NULL);
  4263. if (INVALID_HANDLE_VALUE == hFile) {
  4264. return FALSE;
  4265. }
  4266. ReadFile(hFile, &cda, sizeof(cda), &cbRead, NULL);
  4267. CloseHandle (hFile);
  4268. //
  4269. // Make sure its a RIFF CDDA file
  4270. //
  4271. if ( (cda.dwRIFF != RIFF_RIFF) || (cda.dwCDDA != RIFF_CDDA) ) {
  4272. return FALSE;
  4273. }
  4274. //
  4275. // Make sure that we have this disc loaded.
  4276. //
  4277. for ( i = 0; i < g_NumCdDevices; i++ ) {
  4278. if (g_Devices[i]->CdInfo.Id == cda.DiscID) {
  4279. *piCdRomIndex = i;
  4280. break;
  4281. }
  4282. }
  4283. //
  4284. // If we didn't map the drive OK return FALSE AND set the
  4285. // returned CD-ROM index to -1 but only if the caller asked us
  4286. // to complain about an incorrect CD being inserted in the drive.
  4287. //
  4288. if ( i == g_NumCdDevices ) {
  4289. if (!fQuiet) {
  4290. AskUserToInsertCorrectDisc(cda.DiscID);
  4291. *piCdRomIndex = -1;
  4292. }
  4293. return FALSE;
  4294. }
  4295. *piTrackIndex = cda.wTrack - 1;
  4296. return TRUE;
  4297. }
  4298. /*****************************Private*Routine******************************\
  4299. * AppendTrackToPlayList
  4300. *
  4301. * Appends the TRACK_PLAY record pointed to by pAppend to the end of the
  4302. * double linked list pointed to by pHead.
  4303. *
  4304. *
  4305. * History:
  4306. * dd-mm-94 - StephenE - Created
  4307. *
  4308. \**************************************************************************/
  4309. void
  4310. AppendTrackToPlayList(
  4311. PTRACK_PLAY pHead,
  4312. PTRACK_PLAY pAppend
  4313. )
  4314. {
  4315. PTRACK_PLAY pp = pHead;
  4316. while (pp->nextplay != NULL) {
  4317. pp = pp->nextplay;
  4318. }
  4319. pp->nextplay = pAppend;
  4320. pAppend->prevplay = pp;
  4321. pAppend->nextplay = NULL;
  4322. }
  4323. /*****************************Private*Routine******************************\
  4324. * FindMostSuitableDrive
  4325. *
  4326. * Tries to determine the best drive to make the current drive. Returns the
  4327. * drive.
  4328. *
  4329. * We should choose the first disc that is playing if any are playing.
  4330. *
  4331. * Else we should choose the first disc with a music disk in it if there
  4332. * any drives with music discs in them.
  4333. *
  4334. * Else we should chose the first drive that is available if any of the
  4335. * drives are available.
  4336. *
  4337. * Else just choose the first (ie. zeroth) drive.
  4338. *
  4339. * History:
  4340. * dd-mm-94 - StephenE - Created
  4341. *
  4342. \**************************************************************************/
  4343. int
  4344. FindMostSuitableDrive(
  4345. void
  4346. )
  4347. {
  4348. int iDisc;
  4349. /*
  4350. ** Check for a playing drive
  4351. */
  4352. for ( iDisc = 0; iDisc < g_NumCdDevices; iDisc++ ) {
  4353. if ( g_Devices[iDisc]->State & (CD_PLAYING | CD_PAUSED) ) {
  4354. return iDisc;
  4355. }
  4356. }
  4357. /*
  4358. ** Check for a drive with a music disk in it
  4359. */
  4360. for ( iDisc = 0; iDisc < g_NumCdDevices; iDisc++ ) {
  4361. if ( g_Devices[iDisc]->State & CD_LOADED ) {
  4362. return iDisc;
  4363. }
  4364. }
  4365. /*
  4366. ** Check for a drive that is not in use
  4367. */
  4368. for ( iDisc = 0; iDisc < g_NumCdDevices; iDisc++ ) {
  4369. if ( (g_Devices[iDisc]->State & (CD_BEING_SCANNED | CD_IN_USE)) == 0 ) {
  4370. return iDisc;
  4371. }
  4372. }
  4373. return 0;
  4374. }
  4375. /*****************************Private*Routine******************************\
  4376. * AskUserToInsertCorrectDisc
  4377. *
  4378. *
  4379. *
  4380. * History:
  4381. * dd-mm-94 - StephenE - Created
  4382. *
  4383. \**************************************************************************/
  4384. void
  4385. AskUserToInsertCorrectDisc(
  4386. DWORD dwID
  4387. )
  4388. {
  4389. TCHAR szSection[10];
  4390. TCHAR szMsgBoxTitle[32];
  4391. TCHAR szDiskTitle[TITLE_LENGTH];
  4392. TCHAR szArtistName[ARTIST_LENGTH];
  4393. TCHAR szFormat[STR_MAX_STRING_LEN];
  4394. TCHAR szText[STR_MAX_STRING_LEN + TITLE_LENGTH];
  4395. /*
  4396. ** Try to find the disk title in the cdplayer disk database.
  4397. */
  4398. wsprintf( szSection, g_szSectionF, dwID );
  4399. GetPrivateProfileString( szSection, g_szTitle, g_szNothingThere,
  4400. szDiskTitle, TITLE_LENGTH, g_IniFileName );
  4401. /*
  4402. ** If the disk title was found in the database display it.
  4403. */
  4404. if (_tcscmp(szDiskTitle, g_szNothingThere) != 0) {
  4405. TCHAR szUnknown[64];
  4406. _tcscpy( szUnknown, IdStr(STR_UNKNOWN_ARTIST) );
  4407. GetPrivateProfileString( szSection, g_szArtist, szUnknown,
  4408. szArtistName, ARTIST_LENGTH, g_IniFileName );
  4409. _tcscpy( szFormat, IdStr(STR_DISK_NOT_THERE_K) );
  4410. wsprintf(szText, szFormat, szDiskTitle, szArtistName);
  4411. }
  4412. else {
  4413. _tcscpy( szText, IdStr(STR_DISK_NOT_THERE) );
  4414. }
  4415. //
  4416. // If CD Player is minimized make sure it is restored
  4417. // before displaying the MessageBox
  4418. //
  4419. if (IsIconic(g_hwndApp)) {
  4420. WINDOWPLACEMENT wndpl;
  4421. wndpl.length = sizeof(WINDOWPLACEMENT);
  4422. GetWindowPlacement(g_hwndApp, &wndpl);
  4423. wndpl.showCmd = SW_RESTORE;
  4424. SetWindowPlacement(g_hwndApp, &wndpl);
  4425. }
  4426. _tcscpy( szMsgBoxTitle, IdStr(STR_CDPLAYER) );
  4427. MessageBox( g_hwndApp, szText, szMsgBoxTitle,
  4428. MB_SETFOREGROUND | MB_ICONINFORMATION | MB_APPLMODAL | MB_OK);
  4429. }
  4430. #ifndef USE_IOCTLS
  4431. BOOL CheckMCICDA (TCHAR chDrive)
  4432. {
  4433. DWORD cchLen;
  4434. DWORD dwResult;
  4435. DWORD dwErr;
  4436. CDHANDLE hCD;
  4437. TCHAR szPath[MAX_PATH];
  4438. TCHAR szText[512];
  4439. TCHAR szTitle[MAX_PATH];
  4440. // Make sure the mcicda.dll exists
  4441. cchLen = NUMELEMS(szPath);
  4442. dwResult = SearchPath (NULL, TEXT ("mcicda.dll"), NULL,
  4443. cchLen, szPath, NULL);
  4444. if ((! dwResult) ||
  4445. (0xFFFFFFFF == GetFileAttributes (szPath)))
  4446. {
  4447. // Give Missing MCICDA.DLL error message
  4448. GetSystemDirectory (szPath, cchLen);
  4449. _tcscpy( szTitle, IdStr( STR_MCICDA_MISSING ) );
  4450. wsprintf (szText, szTitle, szPath);
  4451. _tcscpy( szTitle, IdStr( STR_CDPLAYER ) );
  4452. MessageBox( NULL, szText, szTitle,
  4453. MB_APPLMODAL | MB_ICONINFORMATION |
  4454. MB_OK | MB_SETFOREGROUND );
  4455. return FALSE;
  4456. }
  4457. // Make sure mcicda.dll service is up and running
  4458. hCD = OpenCdRom (chDrive, &dwErr);
  4459. if (! hCD)
  4460. {
  4461. // Error loading media device driver.
  4462. _tcscpy( szText, IdStr( STR_MCICDA_NOT_WORKING ) );
  4463. _tcscpy( szTitle, IdStr( STR_CDPLAYER ) );
  4464. MessageBox( NULL, szText, szTitle,
  4465. MB_APPLMODAL | MB_ICONINFORMATION |
  4466. MB_OK | MB_SETFOREGROUND );
  4467. return FALSE;
  4468. }
  4469. // Close Device
  4470. CloseCdRom (hCD);
  4471. return TRUE;
  4472. }
  4473. #endif // ! USE_IOCTLS
  4474. #if DBG
  4475. /******************************Public*Routine******************************\
  4476. * CDAssert
  4477. *
  4478. *
  4479. * History:
  4480. * 18-11-93 - StephenE - Created
  4481. *
  4482. \**************************************************************************/
  4483. void
  4484. CDAssert(
  4485. LPSTR x,
  4486. LPSTR file,
  4487. int line
  4488. )
  4489. {
  4490. char buff[128];
  4491. wsprintfA( buff, "%s \nat line %d of %s", x, line, file );
  4492. MessageBoxA( NULL, buff, "Assertion Failure:", MB_APPLMODAL | MB_OK );
  4493. }
  4494. /******************************Public*Routine******************************\
  4495. * dprintf
  4496. *
  4497. *
  4498. *
  4499. * History:
  4500. * dd-mm-94 - StephenE - Created
  4501. *
  4502. \**************************************************************************/
  4503. void
  4504. dprintf(
  4505. char *lpszFormat,
  4506. ...
  4507. )
  4508. {
  4509. char buf[512];
  4510. UINT n;
  4511. va_list va;
  4512. static int iPrintOutput = -1;
  4513. if (iPrintOutput == -1) {
  4514. iPrintOutput = GetProfileInt( TEXT("MMDEBUG"), TEXT("CdPlayer"), 0);
  4515. }
  4516. if (iPrintOutput) {
  4517. n = wsprintfA(buf, "CdPlayer: <%d>", GetCurrentThreadId() );
  4518. va_start(va, lpszFormat);
  4519. n += wvsprintfA(buf+n, lpszFormat, va);
  4520. va_end(va);
  4521. buf[n++] = '\n';
  4522. buf[n] = 0;
  4523. OutputDebugStringA(buf);
  4524. }
  4525. }
  4526. #endif // End #ifdef DBG