Windows hook proc thunk management simplified.
[wine/gsoc_dplay.git] / multimedia / mciwave.c
blob9e503ebf9ffeeed346c08a708e1a8da2ce74b14d
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Sample Wine Driver for MCI wave forms
5 * Copyright 1994 Martin Ayotte
6 * 1999 Eric Pouech
7 */
8 /*
9 * FIXME:
10 * - record/play should and must be done asynchronous
11 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
14 #include "winuser.h"
15 #include "driver.h"
16 #include "mmddk.h"
17 #include "heap.h"
18 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(mciwave)
22 typedef struct {
23 UINT wDevID;
24 HANDLE hWave;
25 int nUseCount; /* Incremented for each shared open */
26 BOOL fShareable; /* TRUE if first open was shareable */
27 WORD wNotifyDeviceID;/* MCI device ID with a pending notification */
28 HANDLE hCallback; /* Callback handle for pending notification */
29 HMMIO hFile; /* mmio file handle open as Element */
30 MCI_WAVE_OPEN_PARMSA openParms;
31 WAVEOPENDESC waveDesc;
32 PCMWAVEFORMAT WaveFormat;
33 WAVEHDR WaveHdr;
34 BOOL fInput; /* FALSE = Output, TRUE = Input */
35 WORD dwStatus; /* one from MCI_MODE_xxxx */
36 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
37 DWORD dwFileOffset; /* Offset of chunk in mmio file */
38 DWORD dwLength; /* number of bytes in chunk for playing */
39 DWORD dwPosition; /* position in bytes in chunk for playing */
40 } WINE_MCIWAVE;
42 /*======================================================================*
43 * MCI WAVE implemantation *
44 *======================================================================*/
46 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
48 /**************************************************************************
49 * MCIWAVE_drvOpen [internal]
51 static DWORD WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
53 WINE_MCIWAVE* wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
55 if (!wmw)
56 return 0;
58 wmw->wDevID = modp->wDeviceID;
59 mciSetDriverData(wmw->wDevID, (DWORD)wmw);
60 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
61 modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
62 return modp->wDeviceID;
65 /**************************************************************************
66 * MCIWAVE_drvClose [internal]
68 static DWORD WAVE_drvClose(DWORD dwDevID)
70 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
72 if (wmw) {
73 HeapFree(GetProcessHeap(), 0, wmw);
74 mciSetDriverData(dwDevID, 0);
75 return 1;
77 return 0;
80 /**************************************************************************
81 * WAVE_mciGetOpenDev [internal]
83 static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT wDevID)
85 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
87 if (wmw == NULL || wmw->nUseCount == 0) {
88 WARN("Invalid wDevID=%u\n", wDevID);
89 return 0;
91 return wmw;
94 /**************************************************************************
95 * WAVE_ConvertByteToTimeFormat [internal]
97 static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
99 DWORD ret = 0;
101 switch (wmw->dwMciTimeFormat) {
102 case MCI_FORMAT_MILLISECONDS:
103 ret = (val * 1000) / wmw->WaveFormat.wf.nAvgBytesPerSec;
104 break;
105 case MCI_FORMAT_BYTES:
106 ret = val;
107 break;
108 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
109 ret = (val * 8) / wmw->WaveFormat.wBitsPerSample;
110 break;
111 default:
112 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
114 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
115 *lpRet = 0;
116 return ret;
119 /**************************************************************************
120 * WAVE_ConvertTimeFormatToByte [internal]
122 static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
124 DWORD ret = 0;
126 switch (wmw->dwMciTimeFormat) {
127 case MCI_FORMAT_MILLISECONDS:
128 ret = (val * wmw->WaveFormat.wf.nAvgBytesPerSec) / 1000;
129 break;
130 case MCI_FORMAT_BYTES:
131 ret = val;
132 break;
133 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
134 ret = (val * wmw->WaveFormat.wBitsPerSample) / 8;
135 break;
136 default:
137 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
139 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
140 return ret;
143 /**************************************************************************
144 * WAVE_mciReadFmt [internal]
146 static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
148 MMCKINFO mmckInfo;
150 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
151 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
152 return MCIERR_INVALID_FILE;
153 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
154 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
155 if (mmioRead(wmw->hFile, (HPSTR)&wmw->WaveFormat,
156 (long)sizeof(PCMWAVEFORMAT)) != (long)sizeof(PCMWAVEFORMAT))
157 return MCIERR_INVALID_FILE;
159 TRACE("wFormatTag=%04X !\n", wmw->WaveFormat.wf.wFormatTag);
160 TRACE("nChannels=%d \n", wmw->WaveFormat.wf.nChannels);
161 TRACE("nSamplesPerSec=%ld\n", wmw->WaveFormat.wf.nSamplesPerSec);
162 TRACE("nAvgBytesPerSec=%ld\n", wmw->WaveFormat.wf.nAvgBytesPerSec);
163 TRACE("nBlockAlign=%d \n", wmw->WaveFormat.wf.nBlockAlign);
164 TRACE("wBitsPerSample=%u !\n", wmw->WaveFormat.wBitsPerSample);
166 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
167 mmioSeek(wmw->hFile, mmckInfo.dwDataOffset + ((mmckInfo.cksize + 1) & ~1), SEEK_SET);
168 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
169 TRACE("can't find data chunk\n");
170 return MCIERR_INVALID_FILE;
172 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
173 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
174 TRACE("nChannels=%d nSamplesPerSec=%ld\n",
175 wmw->WaveFormat.wf.nChannels, wmw->WaveFormat.wf.nSamplesPerSec);
176 wmw->dwLength = mmckInfo.cksize;
177 wmw->dwFileOffset = mmioSeek(wmw->hFile, 0, SEEK_CUR); /* >= 0 */
178 return 0;
181 /**************************************************************************
182 * WAVE_mciOpen [internal]
184 static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms)
186 DWORD dwRet = 0;
187 DWORD dwDeviceID;
188 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
190 TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
191 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
192 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
194 if (dwFlags & MCI_OPEN_SHAREABLE)
195 return MCIERR_HARDWARE;
197 if (wmw->nUseCount > 0) {
198 /* The driver is already opened on this channel
199 * Wave driver cannot be shared
201 return MCIERR_DEVICE_OPEN;
203 wmw->nUseCount++;
205 dwDeviceID = lpOpenParms->wDeviceID;
207 wmw->fInput = FALSE;
208 wmw->hWave = 0;
210 TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
212 if (dwFlags & MCI_OPEN_ELEMENT) {
213 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
214 /* could it be that (DWORD)lpOpenParms->lpstrElementName
215 * contains the hFile value ?
217 dwRet = MCIERR_UNRECOGNIZED_COMMAND;
218 } else {
219 LPCSTR lpstrElementName = lpOpenParms->lpstrElementName;
221 /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
222 TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
223 if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
224 wmw->hFile = mmioOpenA((LPSTR)lpstrElementName, NULL,
225 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
226 if (wmw->hFile == 0) {
227 WARN("can't find file='%s' !\n", lpstrElementName);
228 dwRet = MCIERR_FILE_NOT_FOUND;
230 } else {
231 wmw->hFile = 0;
235 TRACE("hFile=%u\n", wmw->hFile);
237 memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
238 wmw->wNotifyDeviceID = dwDeviceID;
239 wmw->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
241 wmw->waveDesc.hWave = 0;
243 if (dwRet == 0 && wmw->hFile != 0) {
244 MMCKINFO ckMainRIFF;
246 if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
247 dwRet = MCIERR_INVALID_FILE;
248 } else {
249 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
250 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
251 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
252 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
253 dwRet = MCIERR_INVALID_FILE;
254 } else {
255 dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
258 } else {
259 wmw->dwLength = 0;
261 if (dwRet == 0) {
262 wmw->WaveFormat.wf.nAvgBytesPerSec =
263 wmw->WaveFormat.wf.nSamplesPerSec * wmw->WaveFormat.wf.nBlockAlign;
264 wmw->waveDesc.lpFormat = (LPWAVEFORMAT)&wmw->WaveFormat;
265 wmw->dwPosition = 0;
267 wmw->dwStatus = MCI_MODE_STOP;
268 } else {
269 wmw->nUseCount--;
270 if (wmw->hFile != 0)
271 mmioClose(wmw->hFile, 0);
272 wmw->hFile = 0;
274 return dwRet;
277 /**************************************************************************
278 * WAVE_mciCue [internal]
280 static DWORD WAVE_mciCue(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
283 FIXME
285 This routine is far from complete. At the moment only a check is done on the
286 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
287 is the default.
289 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
290 are ignored
293 DWORD dwRet;
294 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
296 FIXME("(%u, %08lX, %p); likely to fail\n", wDevID, dwParam, lpParms);
298 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
300 /* always close elements ? */
301 if (wmw->hFile != 0) {
302 mmioClose(wmw->hFile, 0);
303 wmw->hFile = 0;
306 dwRet = MMSYSERR_NOERROR; /* assume success */
308 if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
309 dwRet = waveOutClose(wmw->hWave);
310 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
311 wmw->fInput = TRUE;
312 } else if (wmw->fInput) {
313 dwRet = waveInClose(wmw->hWave);
314 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
315 wmw->fInput = FALSE;
317 wmw->hWave = 0;
318 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
321 /**************************************************************************
322 * WAVE_mciStop [internal]
324 static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
326 DWORD dwRet;
327 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
329 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
331 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
332 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
334 wmw->dwStatus = MCI_MODE_STOP;
335 wmw->dwPosition = 0;
336 TRACE("wmw->dwStatus=%d\n", wmw->dwStatus);
338 if (wmw->fInput)
339 dwRet = waveInReset(wmw->hWave);
340 else
341 dwRet = waveOutReset(wmw->hWave);
343 if (dwFlags & MCI_NOTIFY) {
344 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
345 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
346 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
349 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
352 /**************************************************************************
353 * WAVE_mciClose [internal]
355 static DWORD WAVE_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
357 DWORD dwRet = 0;
358 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
360 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
362 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
364 if (wmw->dwStatus != MCI_MODE_STOP) {
365 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
368 wmw->nUseCount--;
370 if (wmw->nUseCount == 0) {
371 DWORD mmRet;
372 if (wmw->hFile != 0) {
373 mmioClose(wmw->hFile, 0);
374 wmw->hFile = 0;
376 mmRet = (wmw->fInput) ? waveInClose(wmw->hWave) : waveOutClose(wmw->hWave);
378 if (mmRet != MMSYSERR_NOERROR) dwRet = MCIERR_INTERNAL;
381 if ((dwFlags & MCI_NOTIFY) && lpParms) {
382 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
383 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
384 wmw->wNotifyDeviceID,
385 (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
387 return 0;
390 /**************************************************************************
391 * WAVE_mciPlay [internal]
393 static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
395 DWORD end;
396 LONG bufsize, count;
397 HGLOBAL16 hData;
398 DWORD dwRet;
399 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
401 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
403 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
404 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
406 if (wmw->fInput) {
407 WARN("cannot play on input device\n");
408 return MCIERR_NONAPPLICABLE_FUNCTION;
411 if (wmw->hFile == 0) {
412 WARN("Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
413 return MCIERR_FILE_NOT_FOUND;
416 if (!(dwFlags & MCI_WAIT)) {
417 return MCI_SendCommandAsync(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags,
418 (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
421 if (wmw->dwStatus != MCI_MODE_STOP) {
422 if (wmw->dwStatus == MCI_MODE_PAUSE) {
423 /* FIXME: parameters (start/end) in lpParams may not be used */
424 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
426 return MCIERR_INTERNAL;
429 end = 0xFFFFFFFF;
430 if (lpParms && (dwFlags & MCI_FROM)) {
431 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
433 if (lpParms && (dwFlags & MCI_TO)) {
434 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
437 TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
439 /* go back to begining of chunk */
440 mmioSeek(wmw->hFile, wmw->dwFileOffset, SEEK_SET); /* >= 0 */
442 /* By default the device will be opened for output, the MCI_CUE function is there to
443 * change from output to input and back
445 /* FIXME: how to choose between several output channels ? here 0 is forced */
446 /* I shall rather use WAVE_MAPPER */
447 dwRet = waveOutOpen(&wmw->hWave, 0, (LPWAVEFORMATEX)&wmw->WaveFormat, 0L, 0L, CALLBACK_NULL);
448 if (dwRet != 0) {
449 TRACE("Can't open low level audio device %ld\n", dwRet);
450 return MCIERR_DEVICE_OPEN;
453 /* at 22050 bytes per sec => 30 ms by block */
454 bufsize = 10240;
455 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
456 wmw->WaveHdr.lpData = (LPSTR)GlobalLock16(hData);
458 wmw->dwStatus = MCI_MODE_PLAY;
460 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
461 /* FIXME: use several WaveHdr for smoother playback */
462 /* FIXME: use only regular MMSYS functions, not calling directly the driver */
463 while (wmw->dwStatus != MCI_MODE_STOP) {
464 wmw->WaveHdr.dwUser = 0L;
465 wmw->WaveHdr.dwFlags = 0L;
466 wmw->WaveHdr.dwLoops = 0L;
467 count = mmioRead(wmw->hFile, wmw->WaveHdr.lpData, bufsize);
468 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
469 if (count < 1)
470 break;
471 dwRet = waveOutPrepareHeader(wmw->hWave, &wmw->WaveHdr, sizeof(WAVEHDR));
472 wmw->WaveHdr.dwBufferLength = count;
473 wmw->WaveHdr.dwBytesRecorded = 0;
474 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
475 &wmw->WaveHdr, wmw->WaveHdr.dwBufferLength, wmw->WaveHdr.dwBytesRecorded);
476 dwRet = waveOutWrite(wmw->hWave, &wmw->WaveHdr, sizeof(WAVEHDR));
477 /* FIXME: should use callback mechanisms from audio driver */
478 #if 1
479 while (!(wmw->WaveHdr.dwFlags & WHDR_DONE))
480 Sleep(1);
481 #endif
482 wmw->dwPosition += count;
483 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
484 dwRet = waveOutUnprepareHeader(wmw->hWave, &wmw->WaveHdr, sizeof(WAVEHDR));
487 if (wmw->WaveHdr.lpData != NULL) {
488 GlobalUnlock16(hData);
489 GlobalFree16(hData);
490 wmw->WaveHdr.lpData = NULL;
493 waveOutReset(wmw->hWave);
494 waveOutClose(wmw->hWave);
496 wmw->dwStatus = MCI_MODE_STOP;
497 if (lpParms && (dwFlags & MCI_NOTIFY)) {
498 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
499 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
500 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
502 return 0;
505 /**************************************************************************
506 * WAVE_mciRecord [internal]
508 static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
510 int start, end;
511 LONG bufsize;
512 HGLOBAL16 hData;
513 LPWAVEHDR lpWaveHdr;
514 DWORD dwRet;
515 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
517 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
519 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
520 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
522 if (!wmw->fInput) {
523 WARN("cannot record on output device\n");
524 return MCIERR_NONAPPLICABLE_FUNCTION;
527 if (wmw->hFile == 0) {
528 WARN("can't find file='%s' !\n",
529 wmw->openParms.lpstrElementName);
530 return MCIERR_FILE_NOT_FOUND;
532 start = 1; end = 99999;
533 if (dwFlags & MCI_FROM) {
534 start = lpParms->dwFrom;
535 TRACE("MCI_FROM=%d \n", start);
537 if (dwFlags & MCI_TO) {
538 end = lpParms->dwTo;
539 TRACE("MCI_TO=%d \n", end);
541 bufsize = 64000;
542 lpWaveHdr = &wmw->WaveHdr;
543 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
544 lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
545 lpWaveHdr->dwBufferLength = bufsize;
546 lpWaveHdr->dwUser = 0L;
547 lpWaveHdr->dwFlags = 0L;
548 lpWaveHdr->dwLoops = 0L;
549 dwRet = waveInPrepareHeader(wmw->hWave, lpWaveHdr, sizeof(WAVEHDR));
550 while (TRUE) { /* FIXME: I don't see any waveInAddBuffer ? */
551 lpWaveHdr->dwBytesRecorded = 0;
552 dwRet = waveInStart(wmw->hWave);
553 TRACE("after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
554 lpWaveHdr, lpWaveHdr->dwBytesRecorded);
555 if (lpWaveHdr->dwBytesRecorded == 0) break;
557 dwRet = waveInUnprepareHeader(wmw->hWave, lpWaveHdr, sizeof(WAVEHDR));
558 if (lpWaveHdr->lpData != NULL) {
559 GlobalUnlock16(hData);
560 GlobalFree16(hData);
561 lpWaveHdr->lpData = NULL;
563 if (dwFlags & MCI_NOTIFY) {
564 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
565 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
566 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
568 return 0;
571 /**************************************************************************
572 * WAVE_mciPause [internal]
574 static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
576 DWORD dwRet;
577 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
579 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
581 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
582 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
584 if (wmw->dwStatus == MCI_MODE_PLAY) {
585 wmw->dwStatus = MCI_MODE_PAUSE;
588 if (wmw->fInput) dwRet = waveInStop(wmw->hWave);
589 else dwRet = waveOutPause(wmw->hWave);
591 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
594 /**************************************************************************
595 * WAVE_mciResume [internal]
597 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
599 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
600 DWORD dwRet = 0;
602 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
604 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
605 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
607 if (wmw->dwStatus == MCI_MODE_PAUSE) {
608 wmw->dwStatus = MCI_MODE_PLAY;
611 /* FIXME: I doubt WIDM_START is correct */
612 if (wmw->fInput) dwRet = waveInStart(wmw->hWave);
613 else dwRet = waveOutRestart(wmw->hWave);
614 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
617 /**************************************************************************
618 * WAVE_mciSeek [internal]
620 static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
622 DWORD ret = 0;
623 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
625 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
627 if (lpParms == NULL) {
628 ret = MCIERR_NULL_PARAMETER_BLOCK;
629 } else if (wmw == NULL) {
630 ret = MCIERR_INVALID_DEVICE_ID;
631 } else {
632 WAVE_mciStop(wDevID, MCI_WAIT, 0);
634 if (dwFlags & MCI_SEEK_TO_START) {
635 wmw->dwPosition = 0;
636 } else if (dwFlags & MCI_SEEK_TO_END) {
637 wmw->dwPosition = 0xFFFFFFFF; /* fixme */
638 } else if (dwFlags & MCI_TO) {
639 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
640 } else {
641 WARN("dwFlag doesn't tell where to seek to...\n");
642 return MCIERR_MISSING_PARAMETER;
645 TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
647 if (dwFlags & MCI_NOTIFY) {
648 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
649 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
650 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
653 return ret;
656 /**************************************************************************
657 * WAVE_mciSet [internal]
659 static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
661 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
663 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
665 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
666 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
668 if (dwFlags & MCI_SET_TIME_FORMAT) {
669 switch (lpParms->dwTimeFormat) {
670 case MCI_FORMAT_MILLISECONDS:
671 TRACE("MCI_FORMAT_MILLISECONDS !\n");
672 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
673 break;
674 case MCI_FORMAT_BYTES:
675 TRACE("MCI_FORMAT_BYTES !\n");
676 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
677 break;
678 case MCI_FORMAT_SAMPLES:
679 TRACE("MCI_FORMAT_SAMPLES !\n");
680 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
681 break;
682 default:
683 WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
684 return MCIERR_BAD_TIME_FORMAT;
687 if (dwFlags & MCI_SET_VIDEO) {
688 TRACE("No support for video !\n");
689 return MCIERR_UNSUPPORTED_FUNCTION;
691 if (dwFlags & MCI_SET_DOOR_OPEN) {
692 TRACE("No support for door open !\n");
693 return MCIERR_UNSUPPORTED_FUNCTION;
695 if (dwFlags & MCI_SET_DOOR_CLOSED) {
696 TRACE("No support for door close !\n");
697 return MCIERR_UNSUPPORTED_FUNCTION;
699 if (dwFlags & MCI_SET_AUDIO) {
700 if (dwFlags & MCI_SET_ON) {
701 TRACE("MCI_SET_ON audio !\n");
702 } else if (dwFlags & MCI_SET_OFF) {
703 TRACE("MCI_SET_OFF audio !\n");
704 } else {
705 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
706 return MCIERR_BAD_INTEGER;
709 if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
710 TRACE("MCI_SET_AUDIO_ALL !\n");
711 if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
712 TRACE("MCI_SET_AUDIO_LEFT !\n");
713 if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
714 TRACE("MCI_SET_AUDIO_RIGHT !\n");
716 if (dwFlags & MCI_WAVE_INPUT)
717 TRACE("MCI_WAVE_INPUT !\n");
718 if (dwFlags & MCI_WAVE_OUTPUT)
719 TRACE("MCI_WAVE_OUTPUT !\n");
720 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
721 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
722 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
723 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
724 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
725 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
726 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
727 TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
728 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
729 TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
730 if (dwFlags & MCI_WAVE_SET_CHANNELS)
731 TRACE("MCI_WAVE_SET_CHANNELS !\n");
732 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
733 TRACE("MCI_WAVE_SET_FORMATTAG !\n");
734 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
735 TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
736 return 0;
739 /**************************************************************************
740 * WAVE_mciStatus [internal]
742 static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
744 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
745 DWORD ret;
747 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
748 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
749 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
751 if (dwFlags & MCI_STATUS_ITEM) {
752 switch (lpParms->dwItem) {
753 case MCI_STATUS_CURRENT_TRACK:
754 lpParms->dwReturn = 1;
755 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
756 break;
757 case MCI_STATUS_LENGTH:
758 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
759 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength, &ret);
760 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
761 break;
762 case MCI_STATUS_MODE:
763 TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
764 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
765 ret = MCI_RESOURCE_RETURNED;
766 break;
767 case MCI_STATUS_MEDIA_PRESENT:
768 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
769 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
770 ret = MCI_RESOURCE_RETURNED;
771 break;
772 case MCI_STATUS_NUMBER_OF_TRACKS:
773 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
774 lpParms->dwReturn = 1;
775 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
776 break;
777 case MCI_STATUS_POSITION:
778 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
779 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
780 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
781 &ret);
782 TRACE("MCI_STATUS_POSITION %s => %lu\n",
783 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
784 break;
785 case MCI_STATUS_READY:
786 lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
787 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
788 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
789 ret = MCI_RESOURCE_RETURNED;
790 break;
791 case MCI_STATUS_TIME_FORMAT:
792 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, wmw->dwMciTimeFormat);
793 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
794 ret = MCI_RESOURCE_RETURNED;
795 break;
796 case MCI_WAVE_INPUT:
797 TRACE("MCI_WAVE_INPUT !\n");
798 lpParms->dwReturn = 0;
799 break;
800 case MCI_WAVE_OUTPUT:
801 TRACE("MCI_WAVE_OUTPUT !\n");
802 lpParms->dwReturn = 0;
803 break;
804 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
805 lpParms->dwReturn = wmw->WaveFormat.wf.nAvgBytesPerSec;
806 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
807 break;
808 case MCI_WAVE_STATUS_BITSPERSAMPLE:
809 lpParms->dwReturn = wmw->WaveFormat.wBitsPerSample;
810 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
811 break;
812 case MCI_WAVE_STATUS_BLOCKALIGN:
813 lpParms->dwReturn = wmw->WaveFormat.wf.nBlockAlign;
814 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
815 break;
816 case MCI_WAVE_STATUS_CHANNELS:
817 lpParms->dwReturn = wmw->WaveFormat.wf.nChannels;
818 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
819 break;
820 case MCI_WAVE_STATUS_FORMATTAG:
821 lpParms->dwReturn = wmw->WaveFormat.wf.wFormatTag;
822 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
823 break;
824 case MCI_WAVE_STATUS_LEVEL:
825 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
826 lpParms->dwReturn = 0xAAAA5555;
827 break;
828 case MCI_WAVE_STATUS_SAMPLESPERSEC:
829 lpParms->dwReturn = wmw->WaveFormat.wf.nSamplesPerSec;
830 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
831 break;
832 default:
833 WARN("unknown command %08lX !\n", lpParms->dwItem);
834 return MCIERR_UNRECOGNIZED_COMMAND;
837 if (dwFlags & MCI_NOTIFY) {
838 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
839 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
840 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
842 return ret;
845 /**************************************************************************
846 * WAVE_mciGetDevCaps [internal]
848 static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags,
849 LPMCI_GETDEVCAPS_PARMS lpParms)
851 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
852 DWORD ret = 0;
854 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
856 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
857 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
859 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
860 switch(lpParms->dwItem) {
861 case MCI_GETDEVCAPS_DEVICE_TYPE:
862 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
863 ret = MCI_RESOURCE_RETURNED;
864 break;
865 case MCI_GETDEVCAPS_HAS_AUDIO:
866 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
867 ret = MCI_RESOURCE_RETURNED;
868 break;
869 case MCI_GETDEVCAPS_HAS_VIDEO:
870 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
871 ret = MCI_RESOURCE_RETURNED;
872 break;
873 case MCI_GETDEVCAPS_USES_FILES:
874 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
875 ret = MCI_RESOURCE_RETURNED;
876 break;
877 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
878 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
879 ret = MCI_RESOURCE_RETURNED;
880 break;
881 case MCI_GETDEVCAPS_CAN_RECORD:
882 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
883 ret = MCI_RESOURCE_RETURNED;
884 break;
885 case MCI_GETDEVCAPS_CAN_EJECT:
886 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
887 ret = MCI_RESOURCE_RETURNED;
888 break;
889 case MCI_GETDEVCAPS_CAN_PLAY:
890 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
891 ret = MCI_RESOURCE_RETURNED;
892 break;
893 case MCI_GETDEVCAPS_CAN_SAVE:
894 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
895 ret = MCI_RESOURCE_RETURNED;
896 break;
897 case MCI_WAVE_GETDEVCAPS_INPUTS:
898 lpParms->dwReturn = 1;
899 break;
900 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
901 lpParms->dwReturn = 1;
902 break;
903 default:
904 FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
905 return MCIERR_UNRECOGNIZED_COMMAND;
907 } else {
908 WARN("No GetDevCaps-Item !\n");
909 return MCIERR_UNRECOGNIZED_COMMAND;
911 return ret;
914 /**************************************************************************
915 * WAVE_mciInfo [internal]
917 static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
919 DWORD ret = 0;
920 LPCSTR str = 0;
921 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
923 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
925 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
926 ret = MCIERR_NULL_PARAMETER_BLOCK;
927 } else if (wmw == NULL) {
928 ret = MCIERR_INVALID_DEVICE_ID;
929 } else {
930 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
932 switch(dwFlags) {
933 case MCI_INFO_PRODUCT:
934 str = "Wine's audio player";
935 break;
936 case MCI_INFO_FILE:
937 str = wmw->openParms.lpstrElementName;
938 break;
939 case MCI_WAVE_INPUT:
940 str = "Wine Wave In";
941 break;
942 case MCI_WAVE_OUTPUT:
943 str = "Wine Wave Out";
944 break;
945 default:
946 WARN("Don't know this info command (%lu)\n", dwFlags);
947 ret = MCIERR_UNRECOGNIZED_COMMAND;
950 if (str) {
951 if (strlen(str) + 1 > lpParms->dwRetSize) {
952 ret = MCIERR_PARAM_OVERFLOW;
953 } else {
954 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
956 } else {
957 lpParms->lpstrReturn[0] = 0;
960 return ret;
963 /**************************************************************************
964 * MCIWAVE_DriverProc [sample driver]
966 LONG CALLBACK MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
967 DWORD dwParam1, DWORD dwParam2)
969 TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
970 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
972 switch(wMsg) {
973 case DRV_LOAD: return 1;
974 case DRV_FREE: return 1;
975 case DRV_OPEN: return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
976 case DRV_CLOSE: return WAVE_drvClose(dwDevID);
977 case DRV_ENABLE: return 1;
978 case DRV_DISABLE: return 1;
979 case DRV_QUERYCONFIGURE: return 1;
980 case DRV_CONFIGURE: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK); return 1;
981 case DRV_INSTALL: return DRVCNF_RESTART;
982 case DRV_REMOVE: return DRVCNF_RESTART;
983 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA) dwParam2);
984 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
985 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
986 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
987 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
988 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
989 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
990 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
991 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
992 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
993 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
994 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSA) dwParam2);
995 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
996 /* commands that should be supported */
997 case MCI_LOAD:
998 case MCI_SAVE:
999 case MCI_FREEZE:
1000 case MCI_PUT:
1001 case MCI_REALIZE:
1002 case MCI_UNFREEZE:
1003 case MCI_UPDATE:
1004 case MCI_WHERE:
1005 case MCI_STEP:
1006 case MCI_SPIN:
1007 case MCI_ESCAPE:
1008 case MCI_COPY:
1009 case MCI_CUT:
1010 case MCI_DELETE:
1011 case MCI_PASTE:
1012 FIXME("Unsupported yet command=%s\n", MCI_MessageToString(wMsg));
1013 break;
1014 case MCI_WINDOW:
1015 TRACE("Unsupported command=%s\n", MCI_MessageToString(wMsg));
1016 break;
1017 case MCI_OPEN:
1018 case MCI_CLOSE:
1019 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1020 break;
1021 default:
1022 FIXME("is probably wrong msg=%s\n", MCI_MessageToString(wMsg));
1023 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1025 return MCIERR_UNRECOGNIZED_COMMAND;