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.

406 lines
10 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: scan.c
  3. *
  4. * Code for scanning the available CD Rom devices.
  5. *
  6. *
  7. * Created: 02-11-93
  8. * Author: Stephen Estrop [StephenE]
  9. *
  10. * Copyright (c) 1993 Microsoft Corporation
  11. \**************************************************************************/
  12. #pragma warning( once : 4201 4214 )
  13. #define NOOLE
  14. #include <windows.h> /* required for all Windows applications */
  15. #include <windowsx.h>
  16. #include <string.h>
  17. #include <tchar.h> /* contains portable ascii/unicode macros */
  18. #include "resource.h"
  19. #include "cdplayer.h"
  20. #include "cdapi.h"
  21. #include "scan.h"
  22. #include "trklst.h"
  23. #include "database.h"
  24. /*****************************Private*Routine******************************\
  25. * ScanForCdromDevices
  26. *
  27. * Returns the number of CD-ROM devices installed in the system.
  28. *
  29. * History:
  30. * 18-11-93 - StephenE - Created
  31. *
  32. \**************************************************************************/
  33. int
  34. ScanForCdromDevices(
  35. void
  36. )
  37. {
  38. DWORD dwDrives;
  39. TCHAR chDrive[] = TEXT("A:\\");
  40. int iNumDrives;
  41. iNumDrives = 0;
  42. for (dwDrives = GetLogicalDrives(); dwDrives != 0; dwDrives >>= 1 ) {
  43. /*
  44. ** Is there a logical drive ??
  45. */
  46. if (dwDrives & 1) {
  47. if ( GetDriveType(chDrive) == DRIVE_CDROM ) {
  48. g_Devices[iNumDrives] = AllocMemory( sizeof(CDROM) );
  49. g_Devices[iNumDrives]->drive = chDrive[0];
  50. g_Devices[iNumDrives]->State = CD_BEING_SCANNED;
  51. iNumDrives++;
  52. }
  53. }
  54. /*
  55. ** Go look at the next drive
  56. */
  57. chDrive[0] = chDrive[0] + 1;
  58. }
  59. return iNumDrives;
  60. }
  61. /******************************Public*Routine******************************\
  62. * RescanDevice
  63. *
  64. *
  65. * This routine is called to scan the disc in a given cdrom by
  66. * reading its table of contents. If the cdrom is playing the user is
  67. * notified that the music will stop.
  68. *
  69. * History:
  70. * 18-11-93 - StephenE - Created
  71. *
  72. \**************************************************************************/
  73. void RescanDevice(
  74. HWND hwndNotify,
  75. int cdrom
  76. )
  77. {
  78. TOC_THREAD_PARMS *ptoc;
  79. HWND hwndButton;
  80. int iMsgBoxRtn;
  81. if ( g_Devices[cdrom]->State & CD_PLAYING ) {
  82. TCHAR s1[256];
  83. TCHAR s2[256];
  84. _tcscpy( s1, IdStr( STR_CANCEL_PLAY ) );
  85. _tcscpy( s2, IdStr( STR_RESCAN ) );
  86. iMsgBoxRtn = MessageBox( g_hwndApp, s1, s2,
  87. MB_APPLMODAL | MB_DEFBUTTON1 |
  88. MB_ICONQUESTION | MB_YESNO);
  89. if ( iMsgBoxRtn == IDYES ) {
  90. hwndButton = g_hwndControls[INDEX(IDM_PLAYBAR_STOP)];
  91. SendMessage( hwndButton, WM_LBUTTONDOWN, 0, 0L );
  92. SendMessage( hwndButton, WM_LBUTTONUP, 0, 0L );
  93. }
  94. else {
  95. return;
  96. }
  97. }
  98. /*
  99. ** Attempt to read table of contents of disc in this drive. We
  100. ** now spawn off a separate thread to do this. Note that the child
  101. ** thread frees the storage allocated below.
  102. */
  103. ptoc = AllocMemory( sizeof(TOC_THREAD_PARMS) );
  104. ptoc->hwndNotify = hwndNotify;
  105. ptoc->cdrom = cdrom;
  106. ReadTableOfContents( ptoc );
  107. }
  108. /*****************************Private*Routine******************************\
  109. * ReadTableofContents
  110. *
  111. * This function reads in the table of contents (TOC) for the specified cdrom.
  112. * All TOC's are read on a worker thread. The hi-word of thread_info variable
  113. * is a boolean that states if the display should been updated after the TOC
  114. * has been reads. The lo-word of thread_info is the id of the cdrom device
  115. * to be read.
  116. *
  117. * History:
  118. * 18-11-93 - StephenE - Created
  119. *
  120. \**************************************************************************/
  121. void
  122. ReadTableOfContents(
  123. TOC_THREAD_PARMS *ptoc
  124. )
  125. {
  126. DWORD dwThreadId;
  127. int cdrom;
  128. cdrom = ptoc->cdrom;
  129. g_Devices[ cdrom ]->fIsTocValid = FALSE;
  130. g_Devices[cdrom]->fShowLeadIn = FALSE;
  131. g_Devices[cdrom]->fProcessingLeadIn = FALSE;
  132. if (g_Devices[ cdrom ]->hThreadToc != NULL) {
  133. /*
  134. ** We have a thread TOC handle see if the thread is
  135. ** still running. If so just return, otherwise
  136. */
  137. switch ( WaitForSingleObject(g_Devices[ cdrom ]->hThreadToc, 0L) ) {
  138. /*
  139. ** Thread has finished to continue
  140. */
  141. case WAIT_OBJECT_0:
  142. break;
  143. /*
  144. ** The thread is still running so just return
  145. */
  146. case WAIT_TIMEOUT:
  147. default:
  148. return;
  149. }
  150. CloseHandle( g_Devices[ cdrom ]->hThreadToc );
  151. }
  152. g_Devices[ cdrom ]->hThreadToc = CreateThread(
  153. NULL, 0L, (LPTHREAD_START_ROUTINE)TableOfContentsThread,
  154. (LPVOID)ptoc, 0L, &dwThreadId );
  155. /*
  156. ** For now I will kill the app if I cannot create the
  157. ** ReadTableOfContents thread. This is probably a bit
  158. ** harsh.
  159. */
  160. if (g_Devices[ cdrom ]->hThreadToc == NULL) {
  161. FatalApplicationError( STR_NO_RES, GetLastError() );
  162. }
  163. }
  164. /*****************************Private*Routine******************************\
  165. * TableOfContentsThread
  166. *
  167. * This is the worker thread that reads the table of contents for the
  168. * specified cdrom.
  169. *
  170. * Before the thread exits we post a message to the UI threads main window to
  171. * notify it that the TOC for this cdrom has been updated. It then examines the
  172. * database to determine if this cdrom is known and updates the screen ccordingly.
  173. *
  174. *
  175. * History:
  176. * 18-11-93 - StephenE - Created
  177. *
  178. \**************************************************************************/
  179. void
  180. TableOfContentsThread(
  181. TOC_THREAD_PARMS *ptoc
  182. )
  183. {
  184. DWORD status;
  185. UCHAR num, numaudio;
  186. int cdrom;
  187. HWND hwndNotify;
  188. // This serializes access to this function
  189. // between multiple threads and the CDPlayer_OnTocRead
  190. // function on the main thread.
  191. // This prevents resource contention on CDROM Multi-changers
  192. EnterCriticalSection (&g_csTOCSerialize);
  193. cdrom = ptoc->cdrom;
  194. hwndNotify = ptoc->hwndNotify;
  195. LocalFree( ptoc );
  196. /*
  197. ** Try to read the TOC from the drive.
  198. */
  199. #ifdef USE_IOCTLS
  200. status = GetCdromTOC( g_Devices[cdrom]->hCd, &(g_Devices[cdrom]->toc) );
  201. num = g_Devices[cdrom]->toc.LastTrack - g_Devices[cdrom]->toc.FirstTrack+1;
  202. {
  203. int i;
  204. numaudio = 0;
  205. /*
  206. ** Look for audio tracks...
  207. */
  208. for( i = 0; i < num; i++ ) {
  209. if ( (g_Devices[cdrom]->toc.TrackData[i].Control &
  210. TRACK_TYPE_MASK ) == AUDIO_TRACK ) {
  211. numaudio++;
  212. }
  213. }
  214. }
  215. /*
  216. ** Need to check if we got data tracks or audio
  217. ** tracks back...if there is a mix, strip out
  218. ** the data tracks...
  219. */
  220. if (status == ERROR_SUCCESS) {
  221. /*
  222. ** If there aren't any audio tracks, then we (most likely)
  223. ** have a data CD loaded.
  224. */
  225. if (numaudio == 0) {
  226. status == ERROR_UNRECOGNIZED_MEDIA;
  227. g_Devices[cdrom]->State = CD_DATA_CD_LOADED | CD_STOPPED;
  228. }
  229. else {
  230. g_Devices[cdrom]->State = CD_LOADED | CD_STOPPED;
  231. }
  232. }
  233. else {
  234. g_Devices[cdrom]->State = CD_NO_CD | CD_STOPPED;
  235. }
  236. #else
  237. {
  238. MCIDEVICEID wDeviceID;
  239. DWORD dwCDPlayerMode = 0L;
  240. #ifdef CHICAGO
  241. if (g_Devices[cdrom]->hCd == 0) {
  242. g_Devices[cdrom]->hCd = OpenCdRom( g_Devices[cdrom]->drive,
  243. &status );
  244. }
  245. wDeviceID = g_Devices[cdrom]->hCd;
  246. #else
  247. wDeviceID = OpenCdRom( g_Devices[cdrom]->drive, &status );
  248. #endif
  249. if ( wDeviceID != 0 ) {
  250. int i;
  251. numaudio = 0;
  252. status = GetCdromTOC( wDeviceID, &(g_Devices[cdrom]->toc) );
  253. /*
  254. ** Need to check if we got data tracks or audio
  255. ** tracks back...if there is a mix, strip out
  256. ** the data tracks...
  257. */
  258. if ( status == ERROR_SUCCESS) {
  259. num = g_Devices[cdrom]->toc.LastTrack -
  260. g_Devices[cdrom]->toc.FirstTrack + 1;
  261. for( i = 0; i < num; i++ ) {
  262. if ( IsCdromTrackAudio(wDeviceID, i) ) {
  263. numaudio++;
  264. }
  265. }
  266. }
  267. dwCDPlayerMode = GetCdromMode( wDeviceID );
  268. #ifdef DAYTONA
  269. CloseCdRom( wDeviceID );
  270. #endif
  271. }
  272. /*
  273. ** Need to check if we got data tracks or audio
  274. ** tracks back...if there is a mix, strip out
  275. ** the data tracks...
  276. */
  277. if (status == ERROR_SUCCESS) {
  278. /*
  279. ** If there aren't any audio tracks, then we (most likely)
  280. ** have a data CD loaded.
  281. */
  282. if (numaudio == 0) {
  283. g_Devices[cdrom]->State = CD_DATA_CD_LOADED | CD_STOPPED;
  284. }
  285. else {
  286. g_Devices[cdrom]->State = CD_LOADED;
  287. switch (dwCDPlayerMode) {
  288. case MCI_MODE_PAUSE:
  289. g_Devices[cdrom]->State |= CD_PAUSED;
  290. break;
  291. case MCI_MODE_PLAY:
  292. g_Devices[cdrom]->State |= CD_PLAYING;
  293. break;
  294. default:
  295. g_Devices[cdrom]->State |= CD_STOPPED;
  296. break;
  297. }
  298. }
  299. }
  300. else {
  301. if (status == MCIERR_MUST_USE_SHAREABLE) {
  302. g_Devices[cdrom]->State = CD_IN_USE;
  303. }
  304. if (g_Devices[cdrom]->State != CD_IN_USE) {
  305. g_Devices[cdrom]->State = CD_NO_CD | CD_STOPPED;
  306. }
  307. }
  308. }
  309. #endif
  310. /*
  311. ** Notify the UI thread that a TOC has been read and then terminate the
  312. ** thread.
  313. */
  314. PostMessage( hwndNotify, WM_NOTIFY_TOC_READ,
  315. (WPARAM)cdrom, (LPARAM)numaudio );
  316. LeaveCriticalSection (&g_csTOCSerialize);
  317. ExitThread( 1L );
  318. }