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

5817 lines
134 KiB

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