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.

419 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 "playres.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] = (CDROM*)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 = (TOC_THREAD_PARMS*)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. {
  149. LocalFree( ptoc );
  150. return;
  151. }
  152. }
  153. CloseHandle( g_Devices[ cdrom ]->hThreadToc );
  154. }
  155. g_Devices[ cdrom ]->hThreadToc = CreateThread(
  156. NULL, 0L, (LPTHREAD_START_ROUTINE)TableOfContentsThread,
  157. (LPVOID)ptoc, 0L, &dwThreadId );
  158. /*
  159. ** For now I will kill the app if I cannot create the
  160. ** ReadTableOfContents thread. This is probably a bit
  161. ** harsh.
  162. */
  163. if (g_Devices[ cdrom ]->hThreadToc == NULL) {
  164. FatalApplicationError( STR_NO_RES, GetLastError() );
  165. }
  166. }
  167. /*****************************Private*Routine******************************\
  168. * TableOfContentsThread
  169. *
  170. * This is the worker thread that reads the table of contents for the
  171. * specified cdrom.
  172. *
  173. * Before the thread exits we post a message to the UI threads main window to
  174. * notify it that the TOC for this cdrom has been updated. It then examines the
  175. * database to determine if this cdrom is known and updates the screen ccordingly.
  176. *
  177. *
  178. * History:
  179. * 18-11-93 - StephenE - Created
  180. *
  181. \**************************************************************************/
  182. void
  183. TableOfContentsThread(
  184. TOC_THREAD_PARMS *ptoc
  185. )
  186. {
  187. DWORD status = 0;
  188. UCHAR num, numaudio;
  189. int cdrom;
  190. HWND hwndNotify;
  191. // This serializes access to this function
  192. // between multiple threads and the CDPlayer_OnTocRead
  193. // function on the main thread.
  194. // This prevents resource contention on CDROM Multi-changers
  195. EnterCriticalSection (&g_csTOCSerialize);
  196. cdrom = ptoc->cdrom;
  197. hwndNotify = ptoc->hwndNotify;
  198. LocalFree( ptoc );
  199. /*
  200. ** Try to read the TOC from the drive.
  201. */
  202. #ifdef USE_IOCTLS
  203. status = GetCdromTOC( g_Devices[cdrom]->hCd, &(g_Devices[cdrom]->toc) );
  204. num = g_Devices[cdrom]->toc.LastTrack - g_Devices[cdrom]->toc.FirstTrack+1;
  205. {
  206. int i;
  207. numaudio = 0;
  208. /*
  209. ** Look for audio tracks...
  210. */
  211. for( i = 0; i < num; i++ ) {
  212. if ( (g_Devices[cdrom]->toc.TrackData[i].Control &
  213. TRACK_TYPE_MASK ) == AUDIO_TRACK ) {
  214. numaudio++;
  215. }
  216. }
  217. }
  218. /*
  219. ** Need to check if we got data tracks or audio
  220. ** tracks back...if there is a mix, strip out
  221. ** the data tracks...
  222. */
  223. if (status == ERROR_SUCCESS) {
  224. /*
  225. ** If there aren't any audio tracks, then we (most likely)
  226. ** have a data CD loaded.
  227. */
  228. if (numaudio == 0) {
  229. status == ERROR_UNRECOGNIZED_MEDIA;
  230. g_Devices[cdrom]->State = CD_DATA_CD_LOADED | CD_STOPPED;
  231. }
  232. else {
  233. g_Devices[cdrom]->State = CD_LOADED | CD_STOPPED;
  234. }
  235. }
  236. else {
  237. g_Devices[cdrom]->State = CD_NO_CD | CD_STOPPED;
  238. }
  239. #else
  240. {
  241. MCIDEVICEID wDeviceID;
  242. DWORD dwCDPlayerMode = 0L;
  243. OSVERSIONINFO os;
  244. os.dwOSVersionInfoSize = sizeof(os);
  245. GetVersionEx(&os);
  246. if (os.dwPlatformId != VER_PLATFORM_WIN32_NT)
  247. {
  248. if (g_Devices[cdrom]->hCd == 0) {
  249. g_Devices[cdrom]->hCd = OpenCdRom( g_Devices[cdrom]->drive,
  250. &status );
  251. }
  252. wDeviceID = g_Devices[cdrom]->hCd;
  253. }
  254. else
  255. {
  256. wDeviceID = OpenCdRom( g_Devices[cdrom]->drive, &status );
  257. }
  258. if ( wDeviceID != 0 ) {
  259. int i;
  260. numaudio = 0;
  261. status = GetCdromTOC( wDeviceID, &(g_Devices[cdrom]->toc) );
  262. /*
  263. ** Need to check if we got data tracks or audio
  264. ** tracks back...if there is a mix, strip out
  265. ** the data tracks...
  266. */
  267. if ( status == ERROR_SUCCESS) {
  268. num = g_Devices[cdrom]->toc.LastTrack -
  269. g_Devices[cdrom]->toc.FirstTrack + 1;
  270. for( i = 0; i < num; i++ ) {
  271. if ( IsCdromTrackAudio(wDeviceID, i) ) {
  272. numaudio++;
  273. }
  274. }
  275. }
  276. dwCDPlayerMode = GetCdromMode( wDeviceID );
  277. OSVERSIONINFO os;
  278. os.dwOSVersionInfoSize = sizeof(os);
  279. GetVersionEx(&os);
  280. if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
  281. {
  282. CloseCdRom( wDeviceID );
  283. }
  284. }
  285. /*
  286. ** Need to check if we got data tracks or audio
  287. ** tracks back...if there is a mix, strip out
  288. ** the data tracks...
  289. */
  290. if (status == ERROR_SUCCESS) {
  291. /*
  292. ** If there aren't any audio tracks, then we (most likely)
  293. ** have a data CD loaded.
  294. */
  295. if (numaudio == 0) {
  296. g_Devices[cdrom]->State = CD_DATA_CD_LOADED | CD_STOPPED;
  297. }
  298. else {
  299. g_Devices[cdrom]->State = CD_LOADED;
  300. switch (dwCDPlayerMode) {
  301. case MCI_MODE_PAUSE:
  302. g_Devices[cdrom]->State |= CD_PAUSED;
  303. break;
  304. case MCI_MODE_PLAY:
  305. g_Devices[cdrom]->State |= CD_PLAYING;
  306. break;
  307. default:
  308. g_Devices[cdrom]->State |= CD_STOPPED;
  309. break;
  310. }
  311. }
  312. }
  313. else {
  314. if (status == (DWORD)MCIERR_MUST_USE_SHAREABLE) {
  315. g_Devices[cdrom]->State = CD_IN_USE;
  316. }
  317. if (g_Devices[cdrom]->State != CD_IN_USE) {
  318. g_Devices[cdrom]->State = CD_NO_CD | CD_STOPPED;
  319. }
  320. }
  321. }
  322. #endif
  323. /*
  324. ** Notify the UI thread that a TOC has been read and then terminate the
  325. ** thread.
  326. */
  327. PostMessage( hwndNotify, WM_NOTIFY_TOC_READ,
  328. (WPARAM)cdrom, (LPARAM)numaudio );
  329. LeaveCriticalSection (&g_csTOCSerialize);
  330. ExitThread( 1L );
  331. }