2 * MCI driver for audio CD (MCICDA)
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1998-99 Eric Pouech
6 * Copyright 2000 Andreas Mohr
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #define WIN32_NO_STATUS
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(mcicda
);
45 #define CDFRAMES_PERSEC 75
46 #define CDFRAMES_PERMIN (CDFRAMES_PERSEC * 60)
47 #define FRAME_OF_ADDR(a) ((a)[1] * CDFRAMES_PERMIN + (a)[2] * CDFRAMES_PERSEC + (a)[3])
48 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
52 int nUseCount
; /* Incremented for each shared open */
53 BOOL fShareable
; /* TRUE if first open was shareable */
54 WORD wNotifyDeviceID
; /* MCI device ID with a pending notification */
55 HANDLE hCallback
; /* Callback handle for pending notification */
60 /*-----------------------------------------------------------------------*/
62 /**************************************************************************
63 * MCICDA_drvOpen [internal]
65 static DWORD
MCICDA_drvOpen(LPCWSTR str
, LPMCI_OPEN_DRIVER_PARMSW modp
)
67 WINE_MCICDAUDIO
* wmcda
;
69 if (!modp
) return 0xFFFFFFFF;
71 wmcda
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WINE_MCICDAUDIO
));
76 wmcda
->wDevID
= modp
->wDeviceID
;
77 mciSetDriverData(wmcda
->wDevID
, (DWORD
)wmcda
);
78 modp
->wCustomCommandTable
= MCI_NO_COMMAND_TABLE
;
79 modp
->wType
= MCI_DEVTYPE_CD_AUDIO
;
80 return modp
->wDeviceID
;
83 /**************************************************************************
84 * MCICDA_drvClose [internal]
86 static DWORD
MCICDA_drvClose(DWORD dwDevID
)
88 WINE_MCICDAUDIO
* wmcda
= (WINE_MCICDAUDIO
*)mciGetDriverData(dwDevID
);
91 HeapFree(GetProcessHeap(), 0, wmcda
);
92 mciSetDriverData(dwDevID
, 0);
94 return (dwDevID
== 0xFFFFFFFF) ? 1 : 0;
97 /**************************************************************************
98 * MCICDA_GetOpenDrv [internal]
100 static WINE_MCICDAUDIO
* MCICDA_GetOpenDrv(UINT wDevID
)
102 WINE_MCICDAUDIO
* wmcda
= (WINE_MCICDAUDIO
*)mciGetDriverData(wDevID
);
104 if (wmcda
== NULL
|| wmcda
->nUseCount
== 0) {
105 WARN("Invalid wDevID=%u\n", wDevID
);
111 /**************************************************************************
112 * MCICDA_GetStatus [internal]
114 static DWORD
MCICDA_GetStatus(WINE_MCICDAUDIO
* wmcda
)
116 CDROM_SUB_Q_DATA_FORMAT fmt
;
117 SUB_Q_CHANNEL_DATA data
;
119 DWORD mode
= MCI_MODE_NOT_READY
;
121 fmt
.Format
= IOCTL_CDROM_CURRENT_POSITION
;
122 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_Q_CHANNEL
, &fmt
, sizeof(fmt
),
123 &data
, sizeof(data
), &br
, NULL
)) {
124 if (GetLastError() == ERROR_NOT_READY
) mode
= MCI_MODE_OPEN
;
126 switch (data
.CurrentPosition
.Header
.AudioStatus
)
128 case AUDIO_STATUS_IN_PROGRESS
: mode
= MCI_MODE_PLAY
; break;
129 case AUDIO_STATUS_PAUSED
: mode
= MCI_MODE_PAUSE
; break;
130 case AUDIO_STATUS_NO_STATUS
:
131 case AUDIO_STATUS_PLAY_COMPLETE
: mode
= MCI_MODE_STOP
; break;
132 case AUDIO_STATUS_PLAY_ERROR
:
133 case AUDIO_STATUS_NOT_SUPPORTED
:
141 /**************************************************************************
142 * MCICDA_GetError [internal]
144 static int MCICDA_GetError(WINE_MCICDAUDIO
* wmcda
)
146 switch (GetLastError())
148 case ERROR_NOT_READY
: return MCIERR_DEVICE_NOT_READY
;
149 case ERROR_IO_DEVICE
: return MCIERR_HARDWARE
;
151 FIXME("Unknown mode %u\n", GetLastError());
153 return MCIERR_DRIVER_INTERNAL
;
156 /**************************************************************************
157 * MCICDA_CalcFrame [internal]
159 static DWORD
MCICDA_CalcFrame(WINE_MCICDAUDIO
* wmcda
, DWORD dwTime
)
167 TRACE("(%p, %08X, %u);\n", wmcda
, wmcda
->dwTimeFormat
, dwTime
);
169 switch (wmcda
->dwTimeFormat
) {
170 case MCI_FORMAT_MILLISECONDS
:
171 dwFrame
= ((dwTime
- 1) * CDFRAMES_PERSEC
+ 500) / 1000;
172 TRACE("MILLISECONDS %u\n", dwFrame
);
175 TRACE("MSF %02u:%02u:%02u\n",
176 MCI_MSF_MINUTE(dwTime
), MCI_MSF_SECOND(dwTime
), MCI_MSF_FRAME(dwTime
));
177 dwFrame
+= CDFRAMES_PERMIN
* MCI_MSF_MINUTE(dwTime
);
178 dwFrame
+= CDFRAMES_PERSEC
* MCI_MSF_SECOND(dwTime
);
179 dwFrame
+= MCI_MSF_FRAME(dwTime
);
181 case MCI_FORMAT_TMSF
:
182 default: /* unknown format ! force TMSF ! ... */
183 wTrack
= MCI_TMSF_TRACK(dwTime
);
184 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
185 &toc
, sizeof(toc
), &br
, NULL
))
187 if (wTrack
< toc
.FirstTrack
|| wTrack
> toc
.LastTrack
)
189 TRACE("MSF %02u-%02u:%02u:%02u\n",
190 MCI_TMSF_TRACK(dwTime
), MCI_TMSF_MINUTE(dwTime
),
191 MCI_TMSF_SECOND(dwTime
), MCI_TMSF_FRAME(dwTime
));
192 addr
= toc
.TrackData
[wTrack
- toc
.FirstTrack
].Address
;
193 TRACE("TMSF trackpos[%u]=%d:%d:%d\n",
194 wTrack
, addr
[1], addr
[2], addr
[3]);
195 dwFrame
= CDFRAMES_PERMIN
* (addr
[1] + MCI_TMSF_MINUTE(dwTime
)) +
196 CDFRAMES_PERSEC
* (addr
[2] + MCI_TMSF_SECOND(dwTime
)) +
197 addr
[3] + MCI_TMSF_FRAME(dwTime
);
203 /**************************************************************************
204 * MCICDA_CalcTime [internal]
206 static DWORD
MCICDA_CalcTime(WINE_MCICDAUDIO
* wmcda
, DWORD tf
, DWORD dwFrame
, LPDWORD lpRet
)
216 TRACE("(%p, %08X, %u);\n", wmcda
, tf
, dwFrame
);
219 case MCI_FORMAT_MILLISECONDS
:
220 dwTime
= (dwFrame
* 1000) / CDFRAMES_PERSEC
+ 1;
221 TRACE("MILLISECONDS %u\n", dwTime
);
225 wMinutes
= dwFrame
/ CDFRAMES_PERMIN
;
226 wSeconds
= (dwFrame
- CDFRAMES_PERMIN
* wMinutes
) / CDFRAMES_PERSEC
;
227 wFrames
= dwFrame
- CDFRAMES_PERMIN
* wMinutes
- CDFRAMES_PERSEC
* wSeconds
;
228 dwTime
= MCI_MAKE_MSF(wMinutes
, wSeconds
, wFrames
);
229 TRACE("MSF %02u:%02u:%02u -> dwTime=%u\n",
230 wMinutes
, wSeconds
, wFrames
, dwTime
);
231 *lpRet
= MCI_COLONIZED3_RETURN
;
233 case MCI_FORMAT_TMSF
:
234 default: /* unknown format ! force TMSF ! ... */
235 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
236 &toc
, sizeof(toc
), &br
, NULL
))
238 if (dwFrame
< FRAME_OF_TOC(toc
, toc
.FirstTrack
) ||
239 dwFrame
> FRAME_OF_TOC(toc
, toc
.LastTrack
+ 1)) {
240 ERR("Out of range value %u [%u,%u]\n",
241 dwFrame
, FRAME_OF_TOC(toc
, toc
.FirstTrack
),
242 FRAME_OF_TOC(toc
, toc
.LastTrack
+ 1));
246 for (wTrack
= toc
.FirstTrack
; wTrack
<= toc
.LastTrack
; wTrack
++) {
247 if (FRAME_OF_TOC(toc
, wTrack
) > dwFrame
)
251 dwFrame
-= FRAME_OF_TOC(toc
, wTrack
);
252 wMinutes
= dwFrame
/ CDFRAMES_PERMIN
;
253 wSeconds
= (dwFrame
- CDFRAMES_PERMIN
* wMinutes
) / CDFRAMES_PERSEC
;
254 wFrames
= dwFrame
- CDFRAMES_PERMIN
* wMinutes
- CDFRAMES_PERSEC
* wSeconds
;
255 dwTime
= MCI_MAKE_TMSF(wTrack
, wMinutes
, wSeconds
, wFrames
);
256 TRACE("%02u-%02u:%02u:%02u\n", wTrack
, wMinutes
, wSeconds
, wFrames
);
257 *lpRet
= MCI_COLONIZED4_RETURN
;
263 static DWORD
MCICDA_Seek(UINT wDevID
, DWORD dwFlags
, LPMCI_SEEK_PARMS lpParms
);
264 static DWORD
MCICDA_Stop(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
);
266 /**************************************************************************
267 * MCICDA_Open [internal]
269 static DWORD
MCICDA_Open(UINT wDevID
, DWORD dwFlags
, LPMCI_OPEN_PARMSW lpOpenParms
)
272 DWORD ret
= MCIERR_HARDWARE
;
273 WINE_MCICDAUDIO
* wmcda
= (WINE_MCICDAUDIO
*)mciGetDriverData(wDevID
);
274 WCHAR root
[7], drive
= 0;
277 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpOpenParms
);
279 if (lpOpenParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
280 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
282 dwDeviceID
= lpOpenParms
->wDeviceID
;
284 if (wmcda
->nUseCount
> 0) {
285 /* The driver is already open on this channel */
286 /* If the driver was opened shareable before and this open specifies */
287 /* shareable then increment the use count */
288 if (wmcda
->fShareable
&& (dwFlags
& MCI_OPEN_SHAREABLE
))
291 return MCIERR_MUST_USE_SHAREABLE
;
293 wmcda
->nUseCount
= 1;
294 wmcda
->fShareable
= dwFlags
& MCI_OPEN_SHAREABLE
;
296 if (dwFlags
& MCI_OPEN_ELEMENT
) {
297 if (dwFlags
& MCI_OPEN_ELEMENT_ID
) {
298 WARN("MCI_OPEN_ELEMENT_ID %8x ! Abort\n", (DWORD
)lpOpenParms
->lpstrElementName
);
299 return MCIERR_NO_ELEMENT_ALLOWED
;
301 TRACE("MCI_OPEN_ELEMENT element name: %s\n", debugstr_w(lpOpenParms
->lpstrElementName
));
302 if (!isalpha(lpOpenParms
->lpstrElementName
[0]) || lpOpenParms
->lpstrElementName
[1] != ':' ||
303 (lpOpenParms
->lpstrElementName
[2] && lpOpenParms
->lpstrElementName
[2] != '\\'))
305 WARN("MCI_OPEN_ELEMENT unsupported format: %s\n",
306 debugstr_w(lpOpenParms
->lpstrElementName
));
307 ret
= MCIERR_NO_ELEMENT_ALLOWED
;
310 drive
= toupper(lpOpenParms
->lpstrElementName
[0]);
311 root
[0] = drive
; root
[1] = ':'; root
[2] = '\\'; root
[3] = '\0';
312 if (GetDriveTypeW(root
) != DRIVE_CDROM
)
314 ret
= MCIERR_INVALID_DEVICE_NAME
;
320 /* drive letter isn't passed... get the dwDeviceID'th cdrom in the system */
321 root
[0] = 'A'; root
[1] = ':'; root
[2] = '\\'; root
[3] = '\0';
322 for (count
= 0; root
[0] <= 'Z'; root
[0]++)
324 if (GetDriveTypeW(root
) == DRIVE_CDROM
&& ++count
>= dwDeviceID
)
332 ret
= MCIERR_INVALID_DEVICE_ID
;
337 wmcda
->wNotifyDeviceID
= dwDeviceID
;
338 wmcda
->dwTimeFormat
= MCI_FORMAT_MSF
;
340 /* now, open the handle */
341 root
[0] = root
[1] = '\\'; root
[2] = '.'; root
[3] = '\\'; root
[4] = drive
; root
[5] = ':'; root
[6] = '\0';
342 wmcda
->handle
= CreateFileW(root
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
343 if (wmcda
->handle
!= INVALID_HANDLE_VALUE
)
351 /**************************************************************************
352 * MCICDA_Close [internal]
354 static DWORD
MCICDA_Close(UINT wDevID
, DWORD dwParam
, LPMCI_GENERIC_PARMS lpParms
)
356 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
358 TRACE("(%04X, %08X, %p);\n", wDevID
, dwParam
, lpParms
);
360 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
362 if (--wmcda
->nUseCount
== 0) {
363 CloseHandle(wmcda
->handle
);
368 /**************************************************************************
369 * MCICDA_GetDevCaps [internal]
371 static DWORD
MCICDA_GetDevCaps(UINT wDevID
, DWORD dwFlags
,
372 LPMCI_GETDEVCAPS_PARMS lpParms
)
376 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
378 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
380 if (dwFlags
& MCI_GETDEVCAPS_ITEM
) {
381 TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08X;\n", lpParms
->dwItem
);
383 switch (lpParms
->dwItem
) {
384 case MCI_GETDEVCAPS_CAN_RECORD
:
385 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
386 ret
= MCI_RESOURCE_RETURNED
;
388 case MCI_GETDEVCAPS_HAS_AUDIO
:
389 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
390 ret
= MCI_RESOURCE_RETURNED
;
392 case MCI_GETDEVCAPS_HAS_VIDEO
:
393 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
394 ret
= MCI_RESOURCE_RETURNED
;
396 case MCI_GETDEVCAPS_DEVICE_TYPE
:
397 lpParms
->dwReturn
= MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO
, MCI_DEVTYPE_CD_AUDIO
);
398 ret
= MCI_RESOURCE_RETURNED
;
400 case MCI_GETDEVCAPS_USES_FILES
:
401 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
402 ret
= MCI_RESOURCE_RETURNED
;
404 case MCI_GETDEVCAPS_COMPOUND_DEVICE
:
405 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
406 ret
= MCI_RESOURCE_RETURNED
;
408 case MCI_GETDEVCAPS_CAN_EJECT
:
409 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
410 ret
= MCI_RESOURCE_RETURNED
;
412 case MCI_GETDEVCAPS_CAN_PLAY
:
413 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
414 ret
= MCI_RESOURCE_RETURNED
;
416 case MCI_GETDEVCAPS_CAN_SAVE
:
417 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
418 ret
= MCI_RESOURCE_RETURNED
;
421 ERR("Unsupported %x devCaps item\n", lpParms
->dwItem
);
422 return MCIERR_UNRECOGNIZED_COMMAND
;
425 TRACE("No GetDevCaps-Item !\n");
426 return MCIERR_UNRECOGNIZED_COMMAND
;
428 TRACE("lpParms->dwReturn=%08X;\n", lpParms
->dwReturn
);
432 static DWORD
CDROM_Audio_GetSerial(CDROM_TOC
* toc
)
434 unsigned long serial
= 0;
437 DWORD dwStart
, dwEnd
;
440 * wMagic collects the wFrames from track 1
441 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
443 * There it is collected for correcting the serial when there are less than
446 wMagic
= toc
->TrackData
[0].Address
[3];
447 dwStart
= FRAME_OF_TOC(*toc
, toc
->FirstTrack
);
449 for (i
= 0; i
<= toc
->LastTrack
- toc
->FirstTrack
; i
++) {
450 serial
+= (toc
->TrackData
[i
].Address
[1] << 16) |
451 (toc
->TrackData
[i
].Address
[2] << 8) | toc
->TrackData
[i
].Address
[3];
453 dwEnd
= FRAME_OF_TOC(*toc
, toc
->LastTrack
+ 1);
455 if (toc
->LastTrack
- toc
->FirstTrack
+ 1 < 3)
456 serial
+= wMagic
+ (dwEnd
- dwStart
);
462 /**************************************************************************
463 * MCICDA_Info [internal]
465 static DWORD
MCICDA_Info(UINT wDevID
, DWORD dwFlags
, LPMCI_INFO_PARMSW lpParms
)
468 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
472 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
474 if (lpParms
== NULL
|| lpParms
->lpstrReturn
== NULL
)
475 return MCIERR_NULL_PARAMETER_BLOCK
;
476 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
478 TRACE("buf=%p, len=%u\n", lpParms
->lpstrReturn
, lpParms
->dwRetSize
);
480 if (dwFlags
& MCI_INFO_PRODUCT
) {
481 static const WCHAR wszAudioCd
[] = {'W','i','n','e','\'','s',' ','a','u','d','i','o',' ','C','D',0};
483 } else if (dwFlags
& MCI_INFO_MEDIA_UPC
) {
484 ret
= MCIERR_NO_IDENTITY
;
485 } else if (dwFlags
& MCI_INFO_MEDIA_IDENTITY
) {
489 static const WCHAR wszLu
[] = {'%','l','u',0};
491 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
492 &toc
, sizeof(toc
), &br
, NULL
)) {
493 return MCICDA_GetError(wmcda
);
496 res
= CDROM_Audio_GetSerial(&toc
);
497 sprintfW(buffer
, wszLu
, res
);
500 WARN("Don't know this info command (%u)\n", dwFlags
);
501 ret
= MCIERR_UNRECOGNIZED_COMMAND
;
504 if (lpParms
->dwRetSize
<= strlenW(str
)) {
505 lstrcpynW(lpParms
->lpstrReturn
, str
, lpParms
->dwRetSize
- 1);
506 ret
= MCIERR_PARAM_OVERFLOW
;
508 strcpyW(lpParms
->lpstrReturn
, str
);
511 *lpParms
->lpstrReturn
= 0;
513 TRACE("=> %s (%d)\n", debugstr_w(lpParms
->lpstrReturn
), ret
);
517 /**************************************************************************
518 * MCICDA_Status [internal]
520 static DWORD
MCICDA_Status(UINT wDevID
, DWORD dwFlags
, LPMCI_STATUS_PARMS lpParms
)
522 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
525 CDROM_SUB_Q_DATA_FORMAT fmt
;
526 SUB_Q_CHANNEL_DATA data
;
530 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
532 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
533 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
535 if (dwFlags
& MCI_NOTIFY
) {
536 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
537 mciDriverNotify(HWND_32(LOWORD(lpParms
->dwCallback
)),
538 wmcda
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
540 if (dwFlags
& MCI_STATUS_ITEM
) {
541 TRACE("dwItem = %x\n", lpParms
->dwItem
);
542 switch (lpParms
->dwItem
) {
543 case MCI_STATUS_CURRENT_TRACK
:
544 fmt
.Format
= IOCTL_CDROM_CURRENT_POSITION
;
545 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_Q_CHANNEL
, &fmt
, sizeof(fmt
),
546 &data
, sizeof(data
), &br
, NULL
))
548 return MCICDA_GetError(wmcda
);
550 lpParms
->dwReturn
= data
.CurrentPosition
.TrackNumber
;
551 TRACE("CURRENT_TRACK=%u!\n", lpParms
->dwReturn
);
553 case MCI_STATUS_LENGTH
:
554 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
555 &toc
, sizeof(toc
), &br
, NULL
)) {
556 WARN("error reading TOC !\n");
557 return MCICDA_GetError(wmcda
);
559 if (dwFlags
& MCI_TRACK
) {
560 TRACE("MCI_TRACK #%u LENGTH=??? !\n", lpParms
->dwTrack
);
561 if (lpParms
->dwTrack
< toc
.FirstTrack
|| lpParms
->dwTrack
> toc
.LastTrack
)
562 return MCIERR_OUTOFRANGE
;
563 idx
= lpParms
->dwTrack
- toc
.FirstTrack
;
564 lpParms
->dwReturn
= FRAME_OF_TOC(toc
, lpParms
->dwTrack
+ 1) -
565 FRAME_OF_TOC(toc
, lpParms
->dwTrack
);
566 /* Windows returns one frame less than the total track length for the
567 last track on the CD. See CDDB HOWTO. Verified on Win95OSR2. */
568 if (lpParms
->dwTrack
== toc
.LastTrack
)
571 /* Sum of the lengths of all of the tracks. Inherits the
572 'off by one frame' behavior from the length of the last track.
573 See above comment. */
574 lpParms
->dwReturn
= FRAME_OF_TOC(toc
, toc
.LastTrack
+ 1) -
575 FRAME_OF_TOC(toc
, toc
.FirstTrack
) - 1;
577 lpParms
->dwReturn
= MCICDA_CalcTime(wmcda
,
578 (wmcda
->dwTimeFormat
== MCI_FORMAT_TMSF
)
579 ? MCI_FORMAT_MSF
: wmcda
->dwTimeFormat
,
582 TRACE("LENGTH=%u !\n", lpParms
->dwReturn
);
584 case MCI_STATUS_MODE
:
585 lpParms
->dwReturn
= MCICDA_GetStatus(wmcda
);
586 TRACE("MCI_STATUS_MODE=%08X !\n", lpParms
->dwReturn
);
587 lpParms
->dwReturn
= MAKEMCIRESOURCE(lpParms
->dwReturn
, lpParms
->dwReturn
);
588 ret
= MCI_RESOURCE_RETURNED
;
590 case MCI_STATUS_MEDIA_PRESENT
:
591 lpParms
->dwReturn
= (MCICDA_GetStatus(wmcda
) == MCI_MODE_OPEN
) ?
592 MAKEMCIRESOURCE(FALSE
, MCI_FALSE
) : MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
593 TRACE("MCI_STATUS_MEDIA_PRESENT =%c!\n", LOWORD(lpParms
->dwReturn
) ? 'Y' : 'N');
594 ret
= MCI_RESOURCE_RETURNED
;
596 case MCI_STATUS_NUMBER_OF_TRACKS
:
597 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
598 &toc
, sizeof(toc
), &br
, NULL
)) {
599 WARN("error reading TOC !\n");
600 return MCICDA_GetError(wmcda
);
602 lpParms
->dwReturn
= toc
.LastTrack
- toc
.FirstTrack
+ 1;
603 TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %u !\n", lpParms
->dwReturn
);
604 if (lpParms
->dwReturn
== (WORD
)-1)
605 return MCICDA_GetError(wmcda
);
607 case MCI_STATUS_POSITION
:
608 if (dwFlags
& MCI_STATUS_START
) {
609 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
610 &toc
, sizeof(toc
), &br
, NULL
)) {
611 WARN("error reading TOC !\n");
612 return MCICDA_GetError(wmcda
);
614 lpParms
->dwReturn
= FRAME_OF_TOC(toc
, toc
.FirstTrack
);
615 TRACE("get MCI_STATUS_START !\n");
616 } else if (dwFlags
& MCI_TRACK
) {
617 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
618 &toc
, sizeof(toc
), &br
, NULL
)) {
619 WARN("error reading TOC !\n");
620 return MCICDA_GetError(wmcda
);
622 if (lpParms
->dwTrack
< toc
.FirstTrack
|| lpParms
->dwTrack
> toc
.LastTrack
)
623 return MCIERR_OUTOFRANGE
;
624 lpParms
->dwReturn
= FRAME_OF_TOC(toc
, lpParms
->dwTrack
);
625 TRACE("get MCI_TRACK #%u !\n", lpParms
->dwTrack
);
627 fmt
.Format
= IOCTL_CDROM_CURRENT_POSITION
;
628 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_Q_CHANNEL
, &fmt
, sizeof(fmt
),
629 &data
, sizeof(data
), &br
, NULL
)) {
630 return MCICDA_GetError(wmcda
);
632 lpParms
->dwReturn
= FRAME_OF_ADDR(data
.CurrentPosition
.AbsoluteAddress
);
634 lpParms
->dwReturn
= MCICDA_CalcTime(wmcda
, wmcda
->dwTimeFormat
, lpParms
->dwReturn
, &ret
);
635 TRACE("MCI_STATUS_POSITION=%08X !\n", lpParms
->dwReturn
);
637 case MCI_STATUS_READY
:
638 TRACE("MCI_STATUS_READY !\n");
639 switch (MCICDA_GetStatus(wmcda
))
641 case MCI_MODE_NOT_READY
:
643 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
646 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
649 TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms
->dwReturn
));
650 ret
= MCI_RESOURCE_RETURNED
;
652 case MCI_STATUS_TIME_FORMAT
:
653 lpParms
->dwReturn
= MAKEMCIRESOURCE(wmcda
->dwTimeFormat
, MCI_FORMAT_RETURN_BASE
+ wmcda
->dwTimeFormat
);
654 TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms
->dwReturn
));
655 ret
= MCI_RESOURCE_RETURNED
;
657 case 4001: /* FIXME: for bogus FullCD */
658 case MCI_CDA_STATUS_TYPE_TRACK
:
659 if (!(dwFlags
& MCI_TRACK
))
660 ret
= MCIERR_MISSING_PARAMETER
;
662 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
663 &toc
, sizeof(toc
), &br
, NULL
)) {
664 WARN("error reading TOC !\n");
665 return MCICDA_GetError(wmcda
);
667 if (lpParms
->dwTrack
< toc
.FirstTrack
|| lpParms
->dwTrack
> toc
.LastTrack
)
668 ret
= MCIERR_OUTOFRANGE
;
670 lpParms
->dwReturn
= (toc
.TrackData
[lpParms
->dwTrack
- toc
.FirstTrack
].Control
& 0x04) ?
671 MCI_CDA_TRACK_OTHER
: MCI_CDA_TRACK_AUDIO
;
673 TRACE("MCI_CDA_STATUS_TYPE_TRACK[%d]=%d\n", lpParms
->dwTrack
, lpParms
->dwReturn
);
676 FIXME("unknown command %08X !\n", lpParms
->dwItem
);
677 return MCIERR_UNRECOGNIZED_COMMAND
;
680 WARN("not MCI_STATUS_ITEM !\n");
685 /**************************************************************************
686 * MCICDA_SkipDataTracks [internal]
688 static DWORD
MCICDA_SkipDataTracks(WINE_MCICDAUDIO
* wmcda
,DWORD
*frame
)
693 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
694 &toc
, sizeof(toc
), &br
, NULL
)) {
695 WARN("error reading TOC !\n");
696 return MCICDA_GetError(wmcda
);
698 /* Locate first track whose starting frame is bigger than frame */
699 for(i
=toc
.FirstTrack
;i
<=toc
.LastTrack
+1;i
++)
700 if ( FRAME_OF_TOC(toc
, i
) > *frame
) break;
701 if (i
<= toc
.FirstTrack
&& i
>toc
.LastTrack
+1) {
702 i
= 0; /* requested address is out of range: go back to start */
703 *frame
= FRAME_OF_TOC(toc
,toc
.FirstTrack
);
707 /* i points to last track whose start address is not greater than frame.
708 * Now skip non-audio tracks */
709 for(;i
<=toc
.LastTrack
+1;i
++)
710 if ( ! (toc
.TrackData
[i
-toc
.FirstTrack
].Control
& 4) )
712 /* The frame will be an address in the next audio track or
713 * address of lead-out. */
714 if ( FRAME_OF_TOC(toc
, i
) > *frame
)
715 *frame
= FRAME_OF_TOC(toc
, i
);
719 /**************************************************************************
720 * MCICDA_Play [internal]
722 static DWORD
MCICDA_Play(UINT wDevID
, DWORD dwFlags
, LPMCI_PLAY_PARMS lpParms
)
724 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
725 DWORD ret
= 0, start
, end
;
727 CDROM_PLAY_AUDIO_MSF play
;
728 CDROM_SUB_Q_DATA_FORMAT fmt
;
729 SUB_Q_CHANNEL_DATA data
;
732 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
735 return MCIERR_NULL_PARAMETER_BLOCK
;
738 return MCIERR_INVALID_DEVICE_ID
;
740 if (dwFlags
& MCI_FROM
) {
741 start
= MCICDA_CalcFrame(wmcda
, lpParms
->dwFrom
);
742 if ( (ret
=MCICDA_SkipDataTracks(wmcda
, &start
)) )
744 TRACE("MCI_FROM=%08X -> %u\n", lpParms
->dwFrom
, start
);
746 fmt
.Format
= IOCTL_CDROM_CURRENT_POSITION
;
747 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_Q_CHANNEL
, &fmt
, sizeof(fmt
),
748 &data
, sizeof(data
), &br
, NULL
)) {
749 return MCICDA_GetError(wmcda
);
751 start
= FRAME_OF_ADDR(data
.CurrentPosition
.AbsoluteAddress
);
752 if ( (ret
=MCICDA_SkipDataTracks(wmcda
, &start
)) )
755 if (dwFlags
& MCI_TO
) {
756 end
= MCICDA_CalcFrame(wmcda
, lpParms
->dwTo
);
757 TRACE("MCI_TO=%08X -> %u\n", lpParms
->dwTo
, end
);
759 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
760 &toc
, sizeof(toc
), &br
, NULL
)) {
761 WARN("error reading TOC !\n");
762 return MCICDA_GetError(wmcda
);
764 end
= FRAME_OF_TOC(toc
, toc
.LastTrack
+ 1) - 1;
766 TRACE("Playing from %u to %u\n", start
, end
);
767 play
.StartingM
= start
/ CDFRAMES_PERMIN
;
768 play
.StartingS
= (start
/ CDFRAMES_PERSEC
) % 60;
769 play
.StartingF
= start
% CDFRAMES_PERSEC
;
770 play
.EndingM
= end
/ CDFRAMES_PERMIN
;
771 play
.EndingS
= (end
/ CDFRAMES_PERSEC
) % 60;
772 play
.EndingF
= end
% CDFRAMES_PERSEC
;
773 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_PLAY_AUDIO_MSF
, &play
, sizeof(play
),
774 NULL
, 0, &br
, NULL
)) {
775 ret
= MCIERR_HARDWARE
;
776 } else if (dwFlags
& MCI_NOTIFY
) {
777 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
779 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
780 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
786 /**************************************************************************
787 * MCICDA_Stop [internal]
789 static DWORD
MCICDA_Stop(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
791 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
794 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
796 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
798 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_STOP_AUDIO
, NULL
, 0, NULL
, 0, &br
, NULL
))
799 return MCIERR_HARDWARE
;
801 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
802 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
803 mciDriverNotify(HWND_32(LOWORD(lpParms
->dwCallback
)),
804 wmcda
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
809 /**************************************************************************
810 * MCICDA_Pause [internal]
812 static DWORD
MCICDA_Pause(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
814 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
817 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
819 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
821 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_PAUSE_AUDIO
, NULL
, 0, NULL
, 0, &br
, NULL
))
822 return MCIERR_HARDWARE
;
824 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
825 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
826 mciDriverNotify(HWND_32(LOWORD(lpParms
->dwCallback
)),
827 wmcda
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
832 /**************************************************************************
833 * MCICDA_Resume [internal]
835 static DWORD
MCICDA_Resume(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
837 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
840 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
842 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
844 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_RESUME_AUDIO
, NULL
, 0, NULL
, 0, &br
, NULL
))
845 return MCIERR_HARDWARE
;
847 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
848 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
849 mciDriverNotify(HWND_32(LOWORD(lpParms
->dwCallback
)),
850 wmcda
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
855 /**************************************************************************
856 * MCICDA_Seek [internal]
858 static DWORD
MCICDA_Seek(UINT wDevID
, DWORD dwFlags
, LPMCI_SEEK_PARMS lpParms
)
861 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
862 CDROM_SEEK_AUDIO_MSF seek
;
866 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
868 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
869 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
871 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_READ_TOC
, NULL
, 0,
872 &toc
, sizeof(toc
), &br
, NULL
)) {
873 WARN("error reading TOC !\n");
874 return MCICDA_GetError(wmcda
);
876 switch (dwFlags
& ~(MCI_NOTIFY
|MCI_WAIT
)) {
877 case MCI_SEEK_TO_START
:
878 TRACE("Seeking to start\n");
879 at
= FRAME_OF_TOC(toc
,toc
.FirstTrack
);
880 if ( (ret
=MCICDA_SkipDataTracks(wmcda
, &at
)) )
883 case MCI_SEEK_TO_END
:
884 TRACE("Seeking to end\n");
885 at
= FRAME_OF_TOC(toc
, toc
.LastTrack
+ 1) - 1;
886 if ( (ret
=MCICDA_SkipDataTracks(wmcda
, &at
)) )
890 TRACE("Seeking to %u\n", lpParms
->dwTo
);
891 at
= MCICDA_CalcFrame(wmcda
, lpParms
->dwTo
);
892 if ( (ret
=MCICDA_SkipDataTracks(wmcda
, &at
)) )
896 TRACE("Unknown seek action %08lX\n",
897 (dwFlags
& ~(MCI_NOTIFY
|MCI_WAIT
)));
898 return MCIERR_UNSUPPORTED_FUNCTION
;
900 seek
.M
= at
/ CDFRAMES_PERMIN
;
901 seek
.S
= (at
/ CDFRAMES_PERSEC
) % 60;
902 seek
.F
= at
% CDFRAMES_PERSEC
;
903 if (!DeviceIoControl(wmcda
->handle
, IOCTL_CDROM_SEEK_AUDIO_MSF
, &seek
, sizeof(seek
),
905 return MCIERR_HARDWARE
;
907 if (dwFlags
& MCI_NOTIFY
) {
908 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
909 mciDriverNotify(HWND_32(LOWORD(lpParms
->dwCallback
)),
910 wmcda
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
915 /**************************************************************************
916 * MCICDA_SetDoor [internal]
918 static DWORD
MCICDA_SetDoor(UINT wDevID
, BOOL open
)
920 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
923 TRACE("(%04x, %s) !\n", wDevID
, (open
) ? "OPEN" : "CLOSE");
925 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
927 if (!DeviceIoControl(wmcda
->handle
,
928 (open
) ? IOCTL_STORAGE_EJECT_MEDIA
: IOCTL_STORAGE_LOAD_MEDIA
,
929 NULL
, 0, NULL
, 0, &br
, NULL
))
930 return MCIERR_HARDWARE
;
935 /**************************************************************************
936 * MCICDA_Set [internal]
938 static DWORD
MCICDA_Set(UINT wDevID
, DWORD dwFlags
, LPMCI_SET_PARMS lpParms
)
940 WINE_MCICDAUDIO
* wmcda
= MCICDA_GetOpenDrv(wDevID
);
942 TRACE("(%04X, %08X, %p);\n", wDevID
, dwFlags
, lpParms
);
944 if (wmcda
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
946 if (dwFlags
& MCI_SET_DOOR_OPEN
) {
947 MCICDA_SetDoor(wDevID
, TRUE
);
949 if (dwFlags
& MCI_SET_DOOR_CLOSED
) {
950 MCICDA_SetDoor(wDevID
, FALSE
);
953 /* only functions which require valid lpParms below this line ! */
954 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
956 TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
957 TRACE("dwAudio=%08lX\n", lpParms->dwAudio);
959 if (dwFlags
& MCI_SET_TIME_FORMAT
) {
960 switch (lpParms
->dwTimeFormat
) {
961 case MCI_FORMAT_MILLISECONDS
:
962 TRACE("MCI_FORMAT_MILLISECONDS !\n");
965 TRACE("MCI_FORMAT_MSF !\n");
967 case MCI_FORMAT_TMSF
:
968 TRACE("MCI_FORMAT_TMSF !\n");
971 WARN("bad time format !\n");
972 return MCIERR_BAD_TIME_FORMAT
;
974 wmcda
->dwTimeFormat
= lpParms
->dwTimeFormat
;
976 if (dwFlags
& MCI_SET_VIDEO
) return MCIERR_UNSUPPORTED_FUNCTION
;
977 if (dwFlags
& MCI_SET_ON
) return MCIERR_UNSUPPORTED_FUNCTION
;
978 if (dwFlags
& MCI_SET_OFF
) return MCIERR_UNSUPPORTED_FUNCTION
;
979 if (dwFlags
& MCI_NOTIFY
) {
980 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n",
981 lpParms
->dwCallback
);
982 mciDriverNotify(HWND_32(LOWORD(lpParms
->dwCallback
)),
983 wmcda
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
988 /**************************************************************************
989 * DriverProc (MCICDA.@)
991 LRESULT CALLBACK
MCICDA_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
992 LPARAM dwParam1
, LPARAM dwParam2
)
995 case DRV_LOAD
: return 1;
996 case DRV_FREE
: return 1;
997 case DRV_OPEN
: return MCICDA_drvOpen((LPCWSTR
)dwParam1
, (LPMCI_OPEN_DRIVER_PARMSW
)dwParam2
);
998 case DRV_CLOSE
: return MCICDA_drvClose(dwDevID
);
999 case DRV_ENABLE
: return 1;
1000 case DRV_DISABLE
: return 1;
1001 case DRV_QUERYCONFIGURE
: return 1;
1002 case DRV_CONFIGURE
: MessageBoxA(0, "MCI audio CD driver !", "Wine Driver", MB_OK
); return 1;
1003 case DRV_INSTALL
: return DRVCNF_RESTART
;
1004 case DRV_REMOVE
: return DRVCNF_RESTART
;
1007 if (dwDevID
== 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION
;
1010 case MCI_OPEN_DRIVER
: return MCICDA_Open(dwDevID
, dwParam1
, (LPMCI_OPEN_PARMSW
)dwParam2
);
1011 case MCI_CLOSE_DRIVER
: return MCICDA_Close(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1012 case MCI_GETDEVCAPS
: return MCICDA_GetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
)dwParam2
);
1013 case MCI_INFO
: return MCICDA_Info(dwDevID
, dwParam1
, (LPMCI_INFO_PARMSW
)dwParam2
);
1014 case MCI_STATUS
: return MCICDA_Status(dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
)dwParam2
);
1015 case MCI_SET
: return MCICDA_Set(dwDevID
, dwParam1
, (LPMCI_SET_PARMS
)dwParam2
);
1016 case MCI_PLAY
: return MCICDA_Play(dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
)dwParam2
);
1017 case MCI_STOP
: return MCICDA_Stop(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1018 case MCI_PAUSE
: return MCICDA_Pause(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1019 case MCI_RESUME
: return MCICDA_Resume(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1020 case MCI_SEEK
: return MCICDA_Seek(dwDevID
, dwParam1
, (LPMCI_SEEK_PARMS
)dwParam2
);
1021 /* commands that should report an error as they are not supported in
1022 * the native version */
1023 case MCI_SET_DOOR_CLOSED
:
1024 case MCI_SET_DOOR_OPEN
:
1041 TRACE("Unsupported command [0x%x]\n", wMsg
);
1045 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1048 TRACE("Sending msg [0x%x] to default driver proc\n", wMsg
);
1049 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1051 return MCIERR_UNRECOGNIZED_COMMAND
;
1054 /*-----------------------------------------------------------------------*/