Added stubs for AccessCheckByType, AddAuditAccessAce,
[wine] / dlls / winmm / mciwave / mciwave.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Sample Wine Driver for MCI wave forms
4  *
5  * Copyright    1994 Martin Ayotte
6  *              1999,2000 Eric Pouech
7  *              2000 Francois Jacques
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include <stdarg.h>
25
26 #include "winerror.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "mmddk.h"
32 #include "wownt32.h"
33 #include "digitalv.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mciwave);
37
38 typedef struct {
39     UINT                        wDevID;
40     HANDLE                      hWave;
41     int                         nUseCount;      /* Incremented for each shared open */
42     BOOL                        fShareable;     /* TRUE if first open was shareable */
43     HMMIO                       hFile;          /* mmio file handle open as Element */
44     MCI_WAVE_OPEN_PARMSA        openParms;
45     WAVEFORMATEX                wfxRef;
46     LPWAVEFORMATEX              lpWaveFormat;
47     BOOL                        fInput;         /* FALSE = Output, TRUE = Input */
48     volatile WORD               dwStatus;       /* one from MCI_MODE_xxxx */
49     DWORD                       dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
50     DWORD                       dwPosition;     /* position in bytes in chunk */
51     HANDLE                      hEvent;         /* for synchronization */
52     DWORD                       dwEventCount;   /* for synchronization */
53     BOOL                        bTemporaryFile; /* temporary file (MCI_RECORD) */
54     MMCKINFO                    ckMainRIFF;     /* main RIFF chunk */
55     MMCKINFO                    ckWaveData;     /* data chunk */
56 } WINE_MCIWAVE;
57
58 /* ===================================================================
59  * ===================================================================
60  * FIXME: should be using the new mmThreadXXXX functions from WINMM
61  * instead of those
62  * it would require to add a wine internal flag to mmThreadCreate
63  * in order to pass a 32 bit function instead of a 16 bit one
64  * ===================================================================
65  * =================================================================== */
66
67 struct SCA {
68     UINT        wDevID;
69     UINT        wMsg;
70     DWORD       dwParam1;
71     DWORD       dwParam2;
72 };
73
74 /**************************************************************************
75  *                              MCI_SCAStarter                  [internal]
76  */
77 static DWORD CALLBACK   MCI_SCAStarter(LPVOID arg)
78 {
79     struct SCA* sca = (struct SCA*)arg;
80     DWORD               ret;
81
82     TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
83           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
84     ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
85     TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
86           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
87     HeapFree(GetProcessHeap(), 0, sca);
88     ExitThread(ret);
89     WARN("Should not happen ? what's wrong \n");
90     /* should not go after this point */
91     return ret;
92 }
93
94 /**************************************************************************
95  *                              MCI_SendCommandAsync            [internal]
96  */
97 static  DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
98                                    DWORD dwParam2, UINT size)
99 {
100     struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
101
102     if (sca == 0)
103         return MCIERR_OUT_OF_MEMORY;
104
105     sca->wDevID   = wDevID;
106     sca->wMsg     = wMsg;
107     sca->dwParam1 = dwParam1;
108
109     if (size && dwParam2) {
110         sca->dwParam2 = (DWORD)sca + sizeof(struct SCA);
111         /* copy structure passed by program in dwParam2 to be sure
112          * we can still use it whatever the program does
113          */
114         memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
115     } else {
116         sca->dwParam2 = dwParam2;
117     }
118
119     if (CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL) == 0) {
120         WARN("Couldn't allocate thread for async command handling, sending synchonously\n");
121         return MCI_SCAStarter(&sca);
122     }
123     return 0;
124 }
125
126 /*======================================================================*
127  *                          MCI WAVE implemantation                     *
128  *======================================================================*/
129
130 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
131
132 /**************************************************************************
133  *                              MCIWAVE_drvOpen                 [internal]
134  */
135 static  DWORD   WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
136 {
137     WINE_MCIWAVE*       wmw;
138
139     if (modp == NULL) return 0xFFFFFFFF;
140
141     wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
142
143     if (!wmw)
144         return 0;
145
146     wmw->wDevID = modp->wDeviceID;
147     mciSetDriverData(wmw->wDevID, (DWORD)wmw);
148     modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
149     modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
150
151     wmw->wfxRef.wFormatTag      = WAVE_FORMAT_PCM;
152     wmw->wfxRef.nChannels       = 1;      /* MONO */
153     wmw->wfxRef.nSamplesPerSec  = 11025;
154     wmw->wfxRef.nAvgBytesPerSec = 11025;
155     wmw->wfxRef.nBlockAlign     = 1;
156     wmw->wfxRef.wBitsPerSample  = 8;
157     wmw->wfxRef.cbSize          = 0;      /* don't care */
158
159     return modp->wDeviceID;
160 }
161
162 /**************************************************************************
163  *                              MCIWAVE_drvClose                [internal]
164  */
165 static  DWORD   WAVE_drvClose(DWORD dwDevID)
166 {
167     WINE_MCIWAVE*  wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
168
169     if (wmw) {
170         HeapFree(GetProcessHeap(), 0, wmw);
171         mciSetDriverData(dwDevID, 0);
172         return 1;
173     }
174     return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
175 }
176
177 /**************************************************************************
178  *                              WAVE_mciGetOpenDev              [internal]
179  */
180 static WINE_MCIWAVE*  WAVE_mciGetOpenDev(UINT wDevID)
181 {
182     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
183
184     if (wmw == NULL || wmw->nUseCount == 0) {
185         WARN("Invalid wDevID=%u\n", wDevID);
186         return 0;
187     }
188     return wmw;
189 }
190
191 /**************************************************************************
192  *                              WAVE_ConvertByteToTimeFormat    [internal]
193  */
194 static  DWORD   WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
195 {
196     DWORD          ret = 0;
197
198     switch (wmw->dwMciTimeFormat) {
199     case MCI_FORMAT_MILLISECONDS:
200         ret = MulDiv(val,1000,wmw->lpWaveFormat->nAvgBytesPerSec);
201         break;
202     case MCI_FORMAT_BYTES:
203         ret = val;
204         break;
205     case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
206         ret = (val * 8) / wmw->lpWaveFormat->wBitsPerSample;
207         break;
208     default:
209         WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
210     }
211     TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
212     *lpRet = 0;
213     return ret;
214 }
215
216 /**************************************************************************
217  *                              WAVE_ConvertTimeFormatToByte    [internal]
218  */
219 static  DWORD   WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
220 {
221     DWORD       ret = 0;
222
223     switch (wmw->dwMciTimeFormat) {
224     case MCI_FORMAT_MILLISECONDS:
225         ret = (val * wmw->lpWaveFormat->nAvgBytesPerSec) / 1000;
226         break;
227     case MCI_FORMAT_BYTES:
228         ret = val;
229         break;
230     case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
231         ret = (val * wmw->lpWaveFormat->wBitsPerSample) / 8;
232         break;
233     default:
234         WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
235     }
236     TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
237     return ret;
238 }
239
240 /**************************************************************************
241  *                      WAVE_mciReadFmt                         [internal]
242  */
243 static  DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
244 {
245     MMCKINFO    mmckInfo;
246     long        r;
247
248     mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
249     if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
250         return MCIERR_INVALID_FILE;
251     TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
252           (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
253
254     wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
255     if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
256     r = mmioRead(wmw->hFile, (HPSTR)wmw->lpWaveFormat, mmckInfo.cksize);
257     if (r < sizeof(WAVEFORMAT))
258         return MCIERR_INVALID_FILE;
259
260     TRACE("wFormatTag=%04X !\n",   wmw->lpWaveFormat->wFormatTag);
261     TRACE("nChannels=%d \n",       wmw->lpWaveFormat->nChannels);
262     TRACE("nSamplesPerSec=%ld\n",  wmw->lpWaveFormat->nSamplesPerSec);
263     TRACE("nAvgBytesPerSec=%ld\n", wmw->lpWaveFormat->nAvgBytesPerSec);
264     TRACE("nBlockAlign=%d \n",     wmw->lpWaveFormat->nBlockAlign);
265     TRACE("wBitsPerSample=%u !\n", wmw->lpWaveFormat->wBitsPerSample);
266     if (r >= (long)sizeof(WAVEFORMATEX))
267         TRACE("cbSize=%u !\n", wmw->lpWaveFormat->cbSize);
268
269     mmioAscend(wmw->hFile, &mmckInfo, 0);
270     wmw->ckWaveData.ckid = mmioFOURCC('d', 'a', 't', 'a');
271     if (mmioDescend(wmw->hFile, &wmw->ckWaveData, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
272         TRACE("can't find data chunk\n");
273         return MCIERR_INVALID_FILE;
274     }
275     TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
276           (LPSTR)&wmw->ckWaveData.ckid, (LPSTR)&wmw->ckWaveData.fccType, wmw->ckWaveData.cksize);
277     TRACE("nChannels=%d nSamplesPerSec=%ld\n",
278           wmw->lpWaveFormat->nChannels, wmw->lpWaveFormat->nSamplesPerSec);
279
280     return 0;
281 }
282
283 /**************************************************************************
284  *                      WAVE_mciCreateRIFFSkeleton              [internal]
285  */
286 static DWORD WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE* wmw)
287 {
288    MMCKINFO     ckWaveFormat;
289    LPMMCKINFO   lpckRIFF     = &(wmw->ckMainRIFF);
290    LPMMCKINFO   lpckWaveData = &(wmw->ckWaveData);
291
292    lpckRIFF->ckid    = FOURCC_RIFF;
293    lpckRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E');
294    lpckRIFF->cksize  = 0;
295
296    if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckRIFF, MMIO_CREATERIFF))
297         goto err;
298
299    ckWaveFormat.fccType = 0;
300    ckWaveFormat.ckid    = mmioFOURCC('f', 'm', 't', ' ');
301    ckWaveFormat.cksize  = sizeof(PCMWAVEFORMAT);
302
303    if (!wmw->lpWaveFormat)
304    {
305        wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmw->lpWaveFormat));
306        if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
307        memcpy(wmw->lpWaveFormat, &wmw->wfxRef, sizeof(wmw->wfxRef));
308    }
309
310    /* we can only record PCM files... there is no way in the MCI API to specify
311     * the necessary data to initialize the extra bytes of the WAVEFORMATEX
312     * structure
313     */
314    if (wmw->lpWaveFormat->wFormatTag != WAVE_FORMAT_PCM)
315        goto err;
316
317    if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, &ckWaveFormat, 0))
318         goto err;
319
320    if (-1 == mmioWrite(wmw->hFile, (HPCSTR)wmw->lpWaveFormat, sizeof(PCMWAVEFORMAT)))
321         goto err;
322
323    if (MMSYSERR_NOERROR != mmioAscend(wmw->hFile, &ckWaveFormat, 0))
324         goto err;
325
326    lpckWaveData->cksize  = 0;
327    lpckWaveData->fccType = 0;
328    lpckWaveData->ckid    = mmioFOURCC('d', 'a', 't', 'a');
329
330    /* create data chunk */
331    if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckWaveData, 0))
332         goto err;
333
334    return 0;
335
336 err:
337    if (wmw->lpWaveFormat)
338        HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
339    wmw->lpWaveFormat = NULL;
340    return MCIERR_INVALID_FILE;
341 }
342
343 /**************************************************************************
344  *                      WAVE_mciOpen                            [internal]
345  */
346 static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms)
347 {
348     DWORD               dwRet = 0;
349     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
350     CHAR*               pszTmpFileName = 0;
351
352     TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
353     if (lpOpenParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
354     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
355
356     if (dwFlags & MCI_OPEN_SHAREABLE)
357         return MCIERR_HARDWARE;
358
359     if (wmw->nUseCount > 0) {
360         /* The driver is already opened on this channel
361          * Wave driver cannot be shared
362          */
363         return MCIERR_DEVICE_OPEN;
364     }
365
366     wmw->nUseCount++;
367
368     wmw->fInput = FALSE;
369     wmw->hWave = 0;
370     wmw->dwStatus = MCI_MODE_NOT_READY;
371
372     TRACE("wDevID=%04X (lpParams->wDeviceID=%08X)\n", wDevID, lpOpenParms->wDeviceID);
373
374     if (dwFlags & MCI_OPEN_ELEMENT) {
375         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
376             /* could it be that (DWORD)lpOpenParms->lpstrElementName
377              * contains the hFile value ?
378              */
379             dwRet = MCIERR_UNRECOGNIZED_COMMAND;
380         } else {
381             if (strlen(lpOpenParms->lpstrElementName) > 0) {
382                 lpOpenParms->lpstrElementName = lpOpenParms->lpstrElementName;
383
384                 /* FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
385                 TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpOpenParms->lpstrElementName);
386
387                 if (lpOpenParms->lpstrElementName && (strlen(lpOpenParms->lpstrElementName) > 0)) {
388                     wmw->hFile = mmioOpenA((LPSTR)lpOpenParms->lpstrElementName, NULL,
389                                     MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READWRITE);
390
391                     if (wmw->hFile == 0) {
392                         WARN("can't find file='%s' !\n", lpOpenParms->lpstrElementName);
393                         dwRet = MCIERR_FILE_NOT_FOUND;
394                     }
395                     else
396                     {
397                         LPMMCKINFO          lpckMainRIFF = &wmw->ckMainRIFF;
398
399                         /* make sure we're are the beginning of the file */
400                         mmioSeek(wmw->hFile, 0, SEEK_SET);
401
402                         /* first reading of this file. read the waveformat chunk */
403                         if (mmioDescend(wmw->hFile, lpckMainRIFF, NULL, 0) != 0) {
404                             dwRet = MCIERR_INVALID_FILE;
405                         } else {
406                             TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
407                                 (LPSTR)&(lpckMainRIFF->ckid),
408                                 (LPSTR) &(lpckMainRIFF->fccType),
409                                 (lpckMainRIFF->cksize));
410
411                             if ((lpckMainRIFF->ckid    != FOURCC_RIFF) ||
412                                  lpckMainRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')) {
413                                 dwRet = MCIERR_INVALID_FILE;
414                             } else {
415                                 dwRet = WAVE_mciReadFmt(wmw, lpckMainRIFF);
416                             }
417                         }
418                     }
419                 }
420                 else {
421                     wmw->hFile = 0;
422                 }
423             }
424             else {
425                 CHAR  szTmpPath[MAX_PATH];
426                 CHAR  szPrefix[4]    = "TMP\0";
427
428                 pszTmpFileName = HeapAlloc(GetProcessHeap(),
429                                            HEAP_ZERO_MEMORY,
430                                            MAX_PATH * sizeof(*pszTmpFileName));
431
432                 if (!GetTempPathA(sizeof(szTmpPath), szTmpPath)) {
433                     WARN("can't retrieve temp path!\n");
434                     HeapFree(GetProcessHeap(), 0, pszTmpFileName);
435                     return MCIERR_FILE_NOT_FOUND;
436                 }
437
438                 if (!GetTempFileNameA(szTmpPath, szPrefix, 0, pszTmpFileName)) {
439                         WARN("can't retrieve temp file name!\n");
440                         HeapFree(GetProcessHeap(), 0, pszTmpFileName);
441                         return MCIERR_FILE_NOT_FOUND;
442                 }
443
444                 wmw->bTemporaryFile = TRUE;
445
446                 TRACE("MCI_OPEN_ELEMENT '%s' !\n", pszTmpFileName);
447
448                 if (pszTmpFileName && (strlen(pszTmpFileName) > 0)) {
449
450                     wmw->hFile = mmioOpenA(pszTmpFileName, NULL,
451                                            MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE);
452
453                     if (wmw->hFile == 0) {
454                         /* temporary file could not be created. clean filename. */
455                         HeapFree(GetProcessHeap(), 0, pszTmpFileName);
456                         WARN("can't create file='%s' !\n", pszTmpFileName);
457                         dwRet = MCIERR_FILE_NOT_FOUND;
458                     }
459                 }
460             }
461         }
462     }
463
464     TRACE("hFile=%p\n", wmw->hFile);
465
466     memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
467
468     if (wmw->bTemporaryFile == TRUE)
469     {
470             /* Additional openParms is temporary file's name */
471             wmw->openParms.lpstrElementName = pszTmpFileName;
472     }
473
474     if (dwRet == 0) {
475         if (wmw->lpWaveFormat) {
476             switch (wmw->lpWaveFormat->wFormatTag) {
477             case WAVE_FORMAT_PCM:
478                 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
479                     wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
480                     WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
481                         wmw->lpWaveFormat->nAvgBytesPerSec,
482                         wmw->lpWaveFormat->nSamplesPerSec *
483                          wmw->lpWaveFormat->nBlockAlign);
484                     wmw->lpWaveFormat->nAvgBytesPerSec =
485                         wmw->lpWaveFormat->nSamplesPerSec *
486                         wmw->lpWaveFormat->nBlockAlign;
487                 }
488                 break;
489             }
490         }
491         wmw->dwPosition = 0;
492
493         wmw->dwStatus = MCI_MODE_STOP;
494     } else {
495         wmw->nUseCount--;
496         if (wmw->hFile != 0)
497             mmioClose(wmw->hFile, 0);
498         wmw->hFile = 0;
499     }
500     return dwRet;
501 }
502
503 /**************************************************************************
504  *                               WAVE_mciCue             [internal]
505  */
506 static DWORD WAVE_mciCue(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
507 {
508     /*
509       FIXME
510
511       This routine is far from complete. At the moment only a check is done on the
512       MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
513       is the default.
514
515       The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
516       are ignored
517     */
518
519     DWORD               dwRet;
520     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
521
522     FIXME("(%u, %08lX, %p); likely to fail\n", wDevID, dwParam, lpParms);
523
524     if (wmw == NULL)    return MCIERR_INVALID_DEVICE_ID;
525
526     /* always close elements ? */
527     if (wmw->hFile != 0) {
528         mmioClose(wmw->hFile, 0);
529         wmw->hFile = 0;
530     }
531
532     dwRet = MMSYSERR_NOERROR;  /* assume success */
533
534     if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
535         dwRet = waveOutClose(wmw->hWave);
536         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
537         wmw->fInput = TRUE;
538     } else if (wmw->fInput) {
539         dwRet = waveInClose(wmw->hWave);
540         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
541         wmw->fInput = FALSE;
542     }
543     wmw->hWave = 0;
544     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
545 }
546
547 /**************************************************************************
548  *                              WAVE_mciStop                    [internal]
549  */
550 static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
551 {
552     DWORD               dwRet = 0;
553     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
554
555     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
556
557     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
558
559     /* wait for playback thread (if any) to exit before processing further */
560     switch (wmw->dwStatus) {
561     case MCI_MODE_PAUSE:
562     case MCI_MODE_PLAY:
563     case MCI_MODE_RECORD:
564         {
565             int oldStat = wmw->dwStatus;
566             wmw->dwStatus = MCI_MODE_NOT_READY;
567             if (oldStat == MCI_MODE_PAUSE)
568                 dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
569         }
570         while (wmw->dwStatus != MCI_MODE_STOP)
571             Sleep(10);
572         break;
573     }
574
575     wmw->dwPosition = 0;
576
577     /* sanity resets */
578     wmw->dwStatus = MCI_MODE_STOP;
579
580     if ((dwFlags & MCI_NOTIFY) && lpParms) {
581         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
582                         wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
583     }
584
585     return dwRet;
586 }
587
588 /**************************************************************************
589  *                              WAVE_mciClose           [internal]
590  */
591 static DWORD WAVE_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
592 {
593     DWORD               dwRet = 0;
594     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
595
596     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
597
598     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
599
600     if (wmw->dwStatus != MCI_MODE_STOP) {
601         dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
602     }
603
604     wmw->nUseCount--;
605
606     if (wmw->nUseCount == 0) {
607         if (wmw->hFile != 0) {
608             mmioClose(wmw->hFile, 0);
609             wmw->hFile = 0;
610         }
611     }
612
613     /* That string got allocated in mciOpen because no filename was specified
614      * in MCI_OPEN_PARMS stucture. Cast-away const from string since it was
615      * allocated by mciOpen, *NOT* the application.
616      */
617     if (wmw->bTemporaryFile)
618     {
619         HeapFree(GetProcessHeap(), 0, (char*)wmw->openParms.lpstrElementName);
620         wmw->openParms.lpstrElementName = NULL;
621     }
622
623     HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
624     wmw->lpWaveFormat = NULL;
625
626     if ((dwFlags & MCI_NOTIFY) && lpParms) {
627         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
628                         wmw->openParms.wDeviceID,
629                         (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
630     }
631
632     return 0;
633 }
634
635 /**************************************************************************
636  *                              WAVE_mciPlayCallback            [internal]
637  */
638 static  void    CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
639                                               DWORD dwInstance,
640                                               DWORD dwParam1, DWORD dwParam2)
641 {
642     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)dwInstance;
643
644     switch (uMsg) {
645     case WOM_OPEN:
646     case WOM_CLOSE:
647         break;
648     case WOM_DONE:
649         InterlockedIncrement(&wmw->dwEventCount);
650         TRACE("Returning waveHdr=%lx\n", dwParam1);
651         SetEvent(wmw->hEvent);
652         break;
653     default:
654         ERR("Unknown uMsg=%d\n", uMsg);
655     }
656 }
657
658 /******************************************************************
659  *              WAVE_mciPlayWaitDone
660  *
661  *
662  */
663 static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
664 {
665     for (;;) {
666         ResetEvent(wmw->hEvent);
667         if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
668             break;
669         }
670         InterlockedIncrement(&wmw->dwEventCount);
671
672         WaitForSingleObject(wmw->hEvent, INFINITE);
673     }
674 }
675
676 /**************************************************************************
677  *                              WAVE_mciPlay            [internal]
678  */
679 static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
680 {
681     DWORD               end;
682     LONG                bufsize, count, left;
683     DWORD               dwRet = 0;
684     LPWAVEHDR           waveHdr = NULL;
685     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
686     int                 whidx;
687
688     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
689
690     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
691     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
692
693     /* FIXME : since there is no way to determine in which mode the device is
694      * open (recording/playback) automatically switch from a mode to another
695      */
696     wmw->fInput = FALSE;
697
698     if (wmw->fInput) {
699         WARN("cannot play on input device\n");
700         return MCIERR_NONAPPLICABLE_FUNCTION;
701     }
702
703     if (wmw->hFile == 0) {
704         WARN("Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
705         return MCIERR_FILE_NOT_FOUND;
706     }
707
708     if (wmw->dwStatus == MCI_MODE_PAUSE) {
709         /* FIXME: parameters (start/end) in lpParams may not be used */
710         return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
711     }
712
713     /** This function will be called again by a thread when async is used.
714      * We have to set MCI_MODE_PLAY before we do this so that the app can spin
715      * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
716      */
717     if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_PLAY) && (dwFlags & MCI_WAIT))) {
718         return MCIERR_INTERNAL;
719     }
720
721     wmw->dwStatus = MCI_MODE_PLAY;
722
723     if (!(dwFlags & MCI_WAIT)) {
724         return MCI_SendCommandAsync(wmw->openParms.wDeviceID, MCI_PLAY, dwFlags,
725                                     (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
726     }
727
728     end = 0xFFFFFFFF;
729     if (lpParms && (dwFlags & MCI_FROM)) {
730         wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
731     }
732     if (lpParms && (dwFlags & MCI_TO)) {
733         end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
734     }
735
736     TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
737
738     if (end <= wmw->dwPosition)
739         return TRUE;
740
741
742 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
743 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
744
745     wmw->dwPosition        = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
746     wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
747
748     if (dwRet == 0) {
749         if (wmw->lpWaveFormat) {
750             switch (wmw->lpWaveFormat->wFormatTag) {
751             case WAVE_FORMAT_PCM:
752                 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
753                     wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
754                     WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
755                         wmw->lpWaveFormat->nAvgBytesPerSec,
756                         wmw->lpWaveFormat->nSamplesPerSec *
757                          wmw->lpWaveFormat->nBlockAlign);
758                     wmw->lpWaveFormat->nAvgBytesPerSec =
759                         wmw->lpWaveFormat->nSamplesPerSec *
760                         wmw->lpWaveFormat->nBlockAlign;
761                 }
762                 break;
763             }
764         }
765     } else {
766         TRACE("can't retrieve wave format %ld\n", dwRet);
767         goto cleanUp;
768     }
769
770
771     /* go back to beginning of chunk plus the requested position */
772     /* FIXME: I'm not sure this is correct, notably because some data linked to
773      * the decompression state machine will not be correcly initialized.
774      * try it this way (other way would be to decompress from 0 up to dwPosition
775      * and to start sending to hWave when dwPosition is reached)
776      */
777     mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
778
779     /* By default the device will be opened for output, the MCI_CUE function is there to
780      * change from output to input and back
781      */
782     /* FIXME: how to choose between several output channels ? here mapper is forced */
783     dwRet = waveOutOpen((HWAVEOUT *)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
784                         (DWORD)WAVE_mciPlayCallback, (DWORD)wmw, CALLBACK_FUNCTION);
785
786     if (dwRet != 0) {
787         TRACE("Can't open low level audio device %ld\n", dwRet);
788         dwRet = MCIERR_DEVICE_OPEN;
789         wmw->hWave = 0;
790         goto cleanUp;
791     }
792
793     /* make it so that 3 buffers per second are needed */
794     bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
795
796     waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
797     waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
798     waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
799     waveHdr[0].dwUser         = waveHdr[1].dwUser         = 0L;
800     waveHdr[0].dwLoops        = waveHdr[1].dwLoops        = 0L;
801     waveHdr[0].dwFlags        = waveHdr[1].dwFlags        = 0L;
802     waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
803     if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
804         waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
805         dwRet = MCIERR_INTERNAL;
806         goto cleanUp;
807     }
808
809     whidx = 0;
810     left = min(wmw->ckWaveData.cksize, end - wmw->dwPosition);
811     wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
812     wmw->dwEventCount = 1L; /* for first buffer */
813
814     TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
815
816     /* FIXME: this doesn't work if wmw->dwPosition != 0 */
817     while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
818         count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, min(bufsize, left));
819         TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
820         if (count < 1)
821             break;
822         /* count is always <= bufsize, so this is correct regarding the
823          * waveOutPrepareHeader function
824          */
825         waveHdr[whidx].dwBufferLength = count;
826         waveHdr[whidx].dwFlags &= ~WHDR_DONE;
827         TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
828               &waveHdr[whidx], waveHdr[whidx].dwBufferLength,
829               waveHdr[whidx].dwBytesRecorded);
830         dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
831         left -= count;
832         wmw->dwPosition += count;
833         TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
834
835         WAVE_mciPlayWaitDone(wmw);
836         whidx ^= 1;
837     }
838
839     WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
840
841     /* just to get rid of some race conditions between play, stop and pause */
842     waveOutReset(wmw->hWave);
843
844     waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
845     waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
846
847     dwRet = 0;
848
849 cleanUp:
850     HeapFree(GetProcessHeap(), 0, waveHdr);
851
852     if (wmw->hWave) {
853         waveOutClose(wmw->hWave);
854         wmw->hWave = 0;
855     }
856     CloseHandle(wmw->hEvent);
857
858     if (lpParms && (dwFlags & MCI_NOTIFY)) {
859         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
860                         wmw->openParms.wDeviceID,
861                         dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
862     }
863
864     wmw->dwStatus = MCI_MODE_STOP;
865
866     return dwRet;
867 }
868
869 /**************************************************************************
870  *                              WAVE_mciPlayCallback            [internal]
871  */
872 static  void    CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg,
873                                                 DWORD dwInstance,
874                                                 DWORD dwParam1, DWORD dwParam2)
875 {
876     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)dwInstance;
877     LPWAVEHDR           lpWaveHdr;
878     LONG                count = 0;
879
880     switch (uMsg) {
881     case WIM_OPEN:
882     case WIM_CLOSE:
883         break;
884     case WIM_DATA:
885         lpWaveHdr = (LPWAVEHDR) dwParam1;
886
887         InterlockedIncrement(&wmw->dwEventCount);
888
889         count = mmioWrite(wmw->hFile, lpWaveHdr->lpData, lpWaveHdr->dwBytesRecorded);
890
891         lpWaveHdr->dwFlags &= ~WHDR_DONE;
892         if (count > 0)
893             wmw->dwPosition  += count;
894         /* else error reporting ?? */
895         if (wmw->dwStatus == MCI_MODE_RECORD)
896         {
897            /* Only queue up another buffer if we are recording.  We could receive this
898               message also when waveInReset() is called, since it notifies on all wave
899               buffers that are outstanding.  Queueing up more sometimes causes waveInClose
900               to fail. */
901            waveInAddBuffer(wmw->hWave, lpWaveHdr, sizeof(*lpWaveHdr));
902            TRACE("after mmioWrite dwPosition=%lu\n", wmw->dwPosition);
903         }
904
905         SetEvent(wmw->hEvent);
906         break;
907     default:
908         ERR("Unknown uMsg=%d\n", uMsg);
909     }
910 }
911
912 /******************************************************************
913  *              bWAVE_mciRecordWaitDone
914  *
915  */
916 static void WAVE_mciRecordWaitDone(WINE_MCIWAVE* wmw)
917 {
918     for (;;) {
919         ResetEvent(wmw->hEvent);
920         if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
921             break;
922         }
923         InterlockedIncrement(&wmw->dwEventCount);
924
925         WaitForSingleObject(wmw->hEvent, INFINITE);
926     }
927 }
928
929 /**************************************************************************
930  *                              WAVE_mciRecord                  [internal]
931  */
932 static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
933 {
934     DWORD               end;
935     DWORD               dwRet = MMSYSERR_NOERROR;
936     LONG                bufsize;
937     LPWAVEHDR           waveHdr = NULL;
938     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
939
940
941     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
942
943     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
944     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
945
946     /* FIXME : since there is no way to determine in which mode the device is
947      * open (recording/playback) automatically switch from a mode to another
948      */
949     wmw->fInput = TRUE;
950
951     if (!wmw->fInput) {
952         WARN("cannot record on output device\n");
953         return MCIERR_NONAPPLICABLE_FUNCTION;
954     }
955
956     if (wmw->dwStatus == MCI_MODE_PAUSE) {
957         /* FIXME: parameters (start/end) in lpParams may not be used */
958         return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
959     }
960
961     /** This function will be called again by a thread when async is used.
962      * We have to set MCI_MODE_PLAY before we do this so that the app can spin
963      * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
964      */
965     if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_RECORD) && (dwFlags & MCI_WAIT))) {
966         return MCIERR_INTERNAL;
967     }
968
969     wmw->dwStatus = MCI_MODE_RECORD;
970
971     if (!(dwFlags & MCI_WAIT)) {
972         return MCI_SendCommandAsync(wmw->openParms.wDeviceID, MCI_RECORD, dwFlags,
973                                     (DWORD)lpParms, sizeof(MCI_RECORD_PARMS));
974     }
975
976     if (!wmw->lpWaveFormat) {
977         /* new RIFF file */
978         dwRet = WAVE_mciCreateRIFFSkeleton(wmw);
979     } else {
980         FIXME("Should descend into data chunk. Please report.\n");
981     }
982
983     end = 0xFFFFFFFF;
984     if (lpParms && (dwFlags & MCI_FROM)) {
985         wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
986     }
987
988     if (lpParms && (dwFlags & MCI_TO)) {
989         end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
990     }
991
992     TRACE("Recording from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
993
994     if (end <= wmw->dwPosition)
995     {
996         return TRUE;
997     }
998
999 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
1000 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
1001
1002     wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
1003     wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
1004
1005     /* go back to beginning of chunk plus the requested position */
1006     /* FIXME: I'm not sure this is correct, notably because some data linked to
1007      * the decompression state machine will not be correcly initialized.
1008      * try it this way (other way would be to decompress from 0 up to dwPosition
1009      * and to start sending to hWave when dwPosition is reached)
1010      */
1011     mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
1012
1013     /* By default the device will be opened for output, the MCI_CUE function is there to
1014      * change from output to input and back
1015      */
1016     /* FIXME: how to choose between several output channels ? here mapper is forced */
1017     dwRet = waveInOpen((HWAVEIN*)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
1018                         (DWORD)WAVE_mciRecordCallback, (DWORD)wmw, CALLBACK_FUNCTION);
1019
1020     if (dwRet != MMSYSERR_NOERROR) {
1021         TRACE("Can't open low level audio device %ld\n", dwRet);
1022         dwRet = MCIERR_DEVICE_OPEN;
1023         wmw->hWave = 0;
1024         goto cleanUp;
1025     }
1026
1027     /* make it so that 3 buffers per second are needed */
1028     bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
1029
1030     waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
1031     waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
1032     waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
1033     waveHdr[0].dwUser         = waveHdr[1].dwUser         = 0L;
1034     waveHdr[0].dwLoops        = waveHdr[1].dwLoops        = 0L;
1035     waveHdr[0].dwFlags        = waveHdr[1].dwFlags        = 0L;
1036     waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
1037
1038     if (waveInPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1039         waveInPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1040         dwRet = MCIERR_INTERNAL;
1041         goto cleanUp;
1042     }
1043
1044     if (waveInAddBuffer(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1045         waveInAddBuffer(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1046         dwRet = MCIERR_INTERNAL;
1047         goto cleanUp;
1048     }
1049
1050     wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1051     wmw->dwEventCount = 1L; /* for first buffer */
1052
1053     TRACE("Recording (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, end - wmw->dwPosition);
1054
1055     dwRet = waveInStart(wmw->hWave);
1056
1057     while (wmw->dwPosition < end && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
1058         WAVE_mciRecordWaitDone(wmw);
1059     }
1060
1061     /* needed so that the callback above won't add again the buffers returned by the reset */
1062     wmw->dwStatus = MCI_MODE_STOP;
1063
1064     waveInReset(wmw->hWave);
1065
1066     waveInUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
1067     waveInUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
1068
1069     dwRet = 0;
1070
1071 cleanUp:
1072     HeapFree(GetProcessHeap(), 0, waveHdr);
1073
1074     if (wmw->hWave) {
1075         waveInClose(wmw->hWave);
1076         wmw->hWave = 0;
1077     }
1078     CloseHandle(wmw->hEvent);
1079
1080     /* need to update the size of the data chunk */
1081     if (mmioAscend(wmw->hFile, &wmw->ckWaveData, 0) != MMSYSERR_NOERROR) {
1082         TRACE("failed on ascend\n");
1083     }
1084
1085     if (lpParms && (dwFlags & MCI_NOTIFY)) {
1086         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1087                         wmw->openParms.wDeviceID,
1088                         dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
1089     }
1090
1091     wmw->dwStatus = MCI_MODE_STOP;
1092
1093     return dwRet;
1094
1095 }
1096
1097 /**************************************************************************
1098  *                              WAVE_mciPause                   [internal]
1099  */
1100 static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1101 {
1102     DWORD               dwRet;
1103     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1104
1105     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1106
1107     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1108     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1109
1110     if (wmw->dwStatus == MCI_MODE_PLAY) {
1111         wmw->dwStatus = MCI_MODE_PAUSE;
1112     }
1113
1114     if (wmw->fInput)    dwRet = waveInStop(wmw->hWave);
1115     else                dwRet = waveOutPause(wmw->hWave);
1116
1117     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
1118 }
1119
1120 /**************************************************************************
1121  *                              WAVE_mciResume                  [internal]
1122  */
1123 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1124 {
1125     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1126     DWORD               dwRet = 0;
1127
1128     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1129
1130     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1131
1132     if (wmw->dwStatus == MCI_MODE_PAUSE) {
1133         wmw->dwStatus = MCI_MODE_PLAY;
1134     }
1135
1136     if (wmw->fInput)    dwRet = waveInStart(wmw->hWave);
1137     else                dwRet = waveOutRestart(wmw->hWave);
1138     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
1139 }
1140
1141 /**************************************************************************
1142  *                              WAVE_mciSeek                    [internal]
1143  */
1144 static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
1145 {
1146     DWORD               ret = 0;
1147     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1148
1149     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1150
1151     if (lpParms == NULL) {
1152         ret = MCIERR_NULL_PARAMETER_BLOCK;
1153     } else if (wmw == NULL) {
1154         ret = MCIERR_INVALID_DEVICE_ID;
1155     } else {
1156         WAVE_mciStop(wDevID, MCI_WAIT, 0);
1157
1158         if (dwFlags & MCI_SEEK_TO_START) {
1159             wmw->dwPosition = 0;
1160         } else if (dwFlags & MCI_SEEK_TO_END) {
1161             wmw->dwPosition = wmw->ckWaveData.cksize;
1162         } else if (dwFlags & MCI_TO) {
1163             wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1164         } else {
1165             WARN("dwFlag doesn't tell where to seek to...\n");
1166             return MCIERR_MISSING_PARAMETER;
1167         }
1168
1169         TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
1170
1171         if (dwFlags & MCI_NOTIFY) {
1172             mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1173                             wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
1174         }
1175     }
1176     return ret;
1177 }
1178
1179 /**************************************************************************
1180  *                              WAVE_mciSet                     [internal]
1181  */
1182 static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
1183 {
1184     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1185
1186     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1187
1188     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1189     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1190
1191     if (dwFlags & MCI_SET_TIME_FORMAT) {
1192         switch (lpParms->dwTimeFormat) {
1193         case MCI_FORMAT_MILLISECONDS:
1194             TRACE("MCI_FORMAT_MILLISECONDS !\n");
1195             wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
1196             break;
1197         case MCI_FORMAT_BYTES:
1198             TRACE("MCI_FORMAT_BYTES !\n");
1199             wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
1200             break;
1201         case MCI_FORMAT_SAMPLES:
1202             TRACE("MCI_FORMAT_SAMPLES !\n");
1203             wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
1204             break;
1205         default:
1206             WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
1207             return MCIERR_BAD_TIME_FORMAT;
1208         }
1209     }
1210     if (dwFlags & MCI_SET_VIDEO) {
1211         TRACE("No support for video !\n");
1212         return MCIERR_UNSUPPORTED_FUNCTION;
1213     }
1214     if (dwFlags & MCI_SET_DOOR_OPEN) {
1215         TRACE("No support for door open !\n");
1216         return MCIERR_UNSUPPORTED_FUNCTION;
1217     }
1218     if (dwFlags & MCI_SET_DOOR_CLOSED) {
1219         TRACE("No support for door close !\n");
1220         return MCIERR_UNSUPPORTED_FUNCTION;
1221     }
1222     if (dwFlags & MCI_SET_AUDIO) {
1223         if (dwFlags & MCI_SET_ON) {
1224             TRACE("MCI_SET_ON audio !\n");
1225         } else if (dwFlags & MCI_SET_OFF) {
1226             TRACE("MCI_SET_OFF audio !\n");
1227         } else {
1228             WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
1229             return MCIERR_BAD_INTEGER;
1230         }
1231
1232         if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
1233             TRACE("MCI_SET_AUDIO_ALL !\n");
1234         if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
1235             TRACE("MCI_SET_AUDIO_LEFT !\n");
1236         if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
1237             TRACE("MCI_SET_AUDIO_RIGHT !\n");
1238     }
1239     if (dwFlags & MCI_WAVE_INPUT)
1240         TRACE("MCI_WAVE_INPUT !\n");
1241     if (dwFlags & MCI_WAVE_OUTPUT)
1242         TRACE("MCI_WAVE_OUTPUT !\n");
1243     if (dwFlags & MCI_WAVE_SET_ANYINPUT)
1244         TRACE("MCI_WAVE_SET_ANYINPUT !\n");
1245     if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
1246         TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
1247     if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) {
1248         wmw->wfxRef.nAvgBytesPerSec = ((LPMCI_WAVE_SET_PARMS)lpParms)->nAvgBytesPerSec;
1249         TRACE("MCI_WAVE_SET_AVGBYTESPERSEC = %ld\n", wmw->wfxRef.nAvgBytesPerSec);
1250     }
1251     if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) {
1252         wmw->wfxRef.wBitsPerSample = ((LPMCI_WAVE_SET_PARMS)lpParms)->wBitsPerSample;
1253         TRACE("MCI_WAVE_SET_BITSPERSAMPLE = %d\n", wmw->wfxRef.wBitsPerSample);
1254     }
1255     if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) {
1256         wmw->wfxRef.nBlockAlign = ((LPMCI_WAVE_SET_PARMS)lpParms)->nBlockAlign;
1257         TRACE("MCI_WAVE_SET_BLOCKALIGN = %d\n", wmw->wfxRef.nBlockAlign);
1258     }
1259     if (dwFlags & MCI_WAVE_SET_CHANNELS) {
1260         wmw->wfxRef.nChannels = ((LPMCI_WAVE_SET_PARMS)lpParms)->nChannels;
1261         TRACE("MCI_WAVE_SET_CHANNELS = %d\n", wmw->wfxRef.nChannels);
1262     }
1263     if (dwFlags & MCI_WAVE_SET_FORMATTAG) {
1264         wmw->wfxRef.wFormatTag = ((LPMCI_WAVE_SET_PARMS)lpParms)->wFormatTag;
1265         TRACE("MCI_WAVE_SET_FORMATTAG = %d\n", wmw->wfxRef.wFormatTag);
1266     }
1267     if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) {
1268         wmw->wfxRef.nSamplesPerSec = ((LPMCI_WAVE_SET_PARMS)lpParms)->nSamplesPerSec;
1269         TRACE("MCI_WAVE_SET_SAMPLESPERSEC = %ld\n", wmw->wfxRef.nSamplesPerSec);
1270     }
1271     return 0;
1272 }
1273
1274 /**************************************************************************
1275  *                              WAVE_mciSave            [internal]
1276  */
1277 static DWORD WAVE_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_SAVE_PARMS lpParms)
1278 {
1279     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1280     DWORD               ret = MCIERR_FILE_NOT_SAVED, tmpRet;
1281     WPARAM              wparam = MCI_NOTIFY_FAILURE;
1282
1283     TRACE("%d, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1284     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1285     if (wmw     == NULL)        return MCIERR_INVALID_DEVICE_ID;
1286
1287     if (dwFlags & MCI_WAIT)
1288     {
1289         FIXME("MCI_WAIT not implemented\n");
1290     }
1291
1292     ret = mmioAscend(wmw->hFile, &wmw->ckWaveData, 0);
1293     ret = mmioAscend(wmw->hFile, &wmw->ckMainRIFF, 0);
1294
1295
1296     ret = mmioClose(wmw->hFile, 0);
1297
1298     /*
1299       If the destination file already exists, it has to be overwritten.  (Behaviour
1300       verified in Windows (2000)).  If it doesn't overwrite, it is breaking one of
1301       my applications.  We are making use of mmioRename, which WILL NOT overwrite
1302       the destination file (which is what Windows does, also verified in Win2K)
1303       So, lets delete the destination file before calling mmioRename.  If the
1304       destination file DOESN'T exist, the delete will fail silently.  Let's also be
1305       careful not to lose our previous error code.
1306     */
1307     tmpRet = GetLastError();
1308     DeleteFileA (lpParms->lpfilename);
1309     SetLastError(tmpRet);
1310
1311     if (0 == mmioRenameA(wmw->openParms.lpstrElementName, lpParms->lpfilename, 0, 0 )) {
1312         ret = ERROR_SUCCESS;
1313     }
1314
1315     if (dwFlags & MCI_NOTIFY) {
1316         if (ret == ERROR_SUCCESS) wparam = MCI_NOTIFY_SUCCESSFUL;
1317
1318         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1319                          wmw->openParms.wDeviceID, wparam);
1320     }
1321
1322     return ret;
1323 }
1324
1325 /**************************************************************************
1326  *                              WAVE_mciStatus          [internal]
1327  */
1328 static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
1329 {
1330     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1331     DWORD               ret = 0;
1332
1333     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1334     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1335     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1336
1337     if (dwFlags & MCI_STATUS_ITEM) {
1338         switch (lpParms->dwItem) {
1339         case MCI_STATUS_CURRENT_TRACK:
1340             lpParms->dwReturn = 1;
1341             TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
1342             break;
1343         case MCI_STATUS_LENGTH:
1344             if (!wmw->hFile) {
1345                 lpParms->dwReturn = 0;
1346                 return MCIERR_UNSUPPORTED_FUNCTION;
1347             }
1348             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1349             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->ckWaveData.cksize, &ret);
1350             TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
1351             break;
1352         case MCI_STATUS_MODE:
1353             TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
1354             lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
1355             ret = MCI_RESOURCE_RETURNED;
1356             break;
1357         case MCI_STATUS_MEDIA_PRESENT:
1358             TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
1359             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1360             ret = MCI_RESOURCE_RETURNED;
1361             break;
1362         case MCI_STATUS_NUMBER_OF_TRACKS:
1363             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1364             lpParms->dwReturn = 1;
1365             TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
1366             break;
1367         case MCI_STATUS_POSITION:
1368             if (!wmw->hFile) {
1369                 lpParms->dwReturn = 0;
1370                 return MCIERR_UNSUPPORTED_FUNCTION;
1371             }
1372             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1373             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
1374                                                              (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
1375                                                              &ret);
1376             TRACE("MCI_STATUS_POSITION %s => %lu\n",
1377                   (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
1378             break;
1379         case MCI_STATUS_READY:
1380             lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
1381                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1382             TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
1383             ret = MCI_RESOURCE_RETURNED;
1384             break;
1385         case MCI_STATUS_TIME_FORMAT:
1386             lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, wmw->dwMciTimeFormat);
1387             TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
1388             ret = MCI_RESOURCE_RETURNED;
1389             break;
1390         case MCI_WAVE_INPUT:
1391             TRACE("MCI_WAVE_INPUT !\n");
1392             lpParms->dwReturn = 0;
1393             ret = MCIERR_WAVE_INPUTUNSPECIFIED;
1394             break;
1395         case MCI_WAVE_OUTPUT:
1396             TRACE("MCI_WAVE_OUTPUT !\n");
1397             {
1398                 UINT    id;
1399                 if (waveOutGetID(wmw->hWave, &id) == MMSYSERR_NOERROR) {
1400                     lpParms->dwReturn = id;
1401                 } else {
1402                     lpParms->dwReturn = 0;
1403                     ret = MCIERR_WAVE_INPUTUNSPECIFIED;
1404                 }
1405             }
1406             break;
1407         case MCI_WAVE_STATUS_AVGBYTESPERSEC:
1408             if (!wmw->hFile) {
1409                 lpParms->dwReturn = 0;
1410                 return MCIERR_UNSUPPORTED_FUNCTION;
1411             }
1412             lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1413             TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
1414             break;
1415         case MCI_WAVE_STATUS_BITSPERSAMPLE:
1416             if (!wmw->hFile) {
1417                 lpParms->dwReturn = 0;
1418                 return MCIERR_UNSUPPORTED_FUNCTION;
1419             }
1420             lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1421             TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
1422             break;
1423         case MCI_WAVE_STATUS_BLOCKALIGN:
1424             if (!wmw->hFile) {
1425                 lpParms->dwReturn = 0;
1426                 return MCIERR_UNSUPPORTED_FUNCTION;
1427             }
1428             lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1429             TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
1430             break;
1431         case MCI_WAVE_STATUS_CHANNELS:
1432             if (!wmw->hFile) {
1433                 lpParms->dwReturn = 0;
1434                 return MCIERR_UNSUPPORTED_FUNCTION;
1435             }
1436             lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1437             TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
1438             break;
1439         case MCI_WAVE_STATUS_FORMATTAG:
1440             if (!wmw->hFile) {
1441                 lpParms->dwReturn = 0;
1442                 return MCIERR_UNSUPPORTED_FUNCTION;
1443             }
1444             lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1445             TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
1446             break;
1447         case MCI_WAVE_STATUS_LEVEL:
1448             TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1449             lpParms->dwReturn = 0xAAAA5555;
1450             break;
1451         case MCI_WAVE_STATUS_SAMPLESPERSEC:
1452             if (!wmw->hFile) {
1453                 lpParms->dwReturn = 0;
1454                 return MCIERR_UNSUPPORTED_FUNCTION;
1455             }
1456             lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1457             TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
1458             break;
1459         default:
1460             WARN("unknown command %08lX !\n", lpParms->dwItem);
1461             return MCIERR_UNRECOGNIZED_COMMAND;
1462         }
1463     }
1464     if (dwFlags & MCI_NOTIFY) {
1465         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1466                         wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
1467     }
1468     return ret;
1469 }
1470
1471 /**************************************************************************
1472  *                              WAVE_mciGetDevCaps              [internal]
1473  */
1474 static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags,
1475                                 LPMCI_GETDEVCAPS_PARMS lpParms)
1476 {
1477     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1478     DWORD               ret = 0;
1479
1480     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1481
1482     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1483     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1484
1485     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1486         switch(lpParms->dwItem) {
1487         case MCI_GETDEVCAPS_DEVICE_TYPE:
1488             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1489             ret = MCI_RESOURCE_RETURNED;
1490             break;
1491         case MCI_GETDEVCAPS_HAS_AUDIO:
1492             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1493             ret = MCI_RESOURCE_RETURNED;
1494             break;
1495         case MCI_GETDEVCAPS_HAS_VIDEO:
1496             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1497             ret = MCI_RESOURCE_RETURNED;
1498             break;
1499         case MCI_GETDEVCAPS_USES_FILES:
1500             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1501             ret = MCI_RESOURCE_RETURNED;
1502             break;
1503         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1504             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1505             ret = MCI_RESOURCE_RETURNED;
1506             break;
1507         case MCI_GETDEVCAPS_CAN_RECORD:
1508             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1509             ret = MCI_RESOURCE_RETURNED;
1510             break;
1511         case MCI_GETDEVCAPS_CAN_EJECT:
1512             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1513             ret = MCI_RESOURCE_RETURNED;
1514             break;
1515         case MCI_GETDEVCAPS_CAN_PLAY:
1516             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1517             ret = MCI_RESOURCE_RETURNED;
1518             break;
1519         case MCI_GETDEVCAPS_CAN_SAVE:
1520             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1521             ret = MCI_RESOURCE_RETURNED;
1522             break;
1523         case MCI_WAVE_GETDEVCAPS_INPUTS:
1524             lpParms->dwReturn = 1;
1525             break;
1526         case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1527             lpParms->dwReturn = 1;
1528             break;
1529         default:
1530             FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1531             return MCIERR_UNRECOGNIZED_COMMAND;
1532         }
1533     } else {
1534         WARN("No GetDevCaps-Item !\n");
1535         return MCIERR_UNRECOGNIZED_COMMAND;
1536     }
1537     return ret;
1538 }
1539
1540 /**************************************************************************
1541  *                              WAVE_mciInfo                    [internal]
1542  */
1543 static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
1544 {
1545     DWORD               ret = 0;
1546     LPCSTR              str = 0;
1547     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1548
1549     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1550
1551     if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
1552         ret = MCIERR_NULL_PARAMETER_BLOCK;
1553     } else if (wmw == NULL) {
1554         ret = MCIERR_INVALID_DEVICE_ID;
1555     } else {
1556         TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1557
1558         switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1559         case MCI_INFO_PRODUCT:
1560             str = "Wine's audio player";
1561             break;
1562         case MCI_INFO_FILE:
1563             str = wmw->openParms.lpstrElementName;
1564             break;
1565         case MCI_WAVE_INPUT:
1566             str = "Wine Wave In";
1567             break;
1568         case MCI_WAVE_OUTPUT:
1569             str = "Wine Wave Out";
1570             break;
1571         default:
1572             WARN("Don't know this info command (%lu)\n", dwFlags);
1573             ret = MCIERR_UNRECOGNIZED_COMMAND;
1574         }
1575     }
1576     if (str) {
1577         if (strlen(str) + 1 > lpParms->dwRetSize) {
1578             ret = MCIERR_PARAM_OVERFLOW;
1579         } else {
1580             lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1581         }
1582     } else {
1583         lpParms->lpstrReturn[0] = 0;
1584     }
1585
1586     return ret;
1587 }
1588
1589 /**************************************************************************
1590  *                              DriverProc (MCIWAVE.@)
1591  */
1592 LONG CALLBACK   MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1593                                    DWORD dwParam1, DWORD dwParam2)
1594 {
1595     TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1596           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1597
1598     switch (wMsg) {
1599     case DRV_LOAD:              return 1;
1600     case DRV_FREE:              return 1;
1601     case DRV_OPEN:              return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
1602     case DRV_CLOSE:             return WAVE_drvClose(dwDevID);
1603     case DRV_ENABLE:            return 1;
1604     case DRV_DISABLE:           return 1;
1605     case DRV_QUERYCONFIGURE:    return 1;
1606     case DRV_CONFIGURE:         MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK);      return 1;
1607     case DRV_INSTALL:           return DRVCNF_RESTART;
1608     case DRV_REMOVE:            return DRVCNF_RESTART;
1609     }
1610
1611     if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1612
1613     switch (wMsg) {
1614     case MCI_OPEN_DRIVER:       return WAVE_mciOpen      (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA)  dwParam2);
1615     case MCI_CLOSE_DRIVER:      return WAVE_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1616     case MCI_CUE:               return WAVE_mciCue       (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1617     case MCI_PLAY:              return WAVE_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)        dwParam2);
1618     case MCI_RECORD:            return WAVE_mciRecord    (dwDevID, dwParam1, (LPMCI_RECORD_PARMS)      dwParam2);
1619     case MCI_STOP:              return WAVE_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1620     case MCI_SET:               return WAVE_mciSet       (dwDevID, dwParam1, (LPMCI_SET_PARMS)         dwParam2);
1621     case MCI_PAUSE:             return WAVE_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1622     case MCI_RESUME:            return WAVE_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1623     case MCI_STATUS:            return WAVE_mciStatus    (dwDevID, dwParam1, (LPMCI_STATUS_PARMS)      dwParam2);
1624     case MCI_GETDEVCAPS:        return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)  dwParam2);
1625     case MCI_INFO:              return WAVE_mciInfo      (dwDevID, dwParam1, (LPMCI_INFO_PARMSA)       dwParam2);
1626     case MCI_SEEK:              return WAVE_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)        dwParam2);
1627     case MCI_SAVE:              return WAVE_mciSave      (dwDevID, dwParam1, (LPMCI_SAVE_PARMS)        dwParam2);
1628         /* commands that should be supported */
1629     case MCI_LOAD:
1630     case MCI_FREEZE:
1631     case MCI_PUT:
1632     case MCI_REALIZE:
1633     case MCI_UNFREEZE:
1634     case MCI_UPDATE:
1635     case MCI_WHERE:
1636     case MCI_STEP:
1637     case MCI_SPIN:
1638     case MCI_ESCAPE:
1639     case MCI_COPY:
1640     case MCI_CUT:
1641     case MCI_DELETE:
1642     case MCI_PASTE:
1643         FIXME("Unsupported yet command [%lu]\n", wMsg);
1644         break;
1645     case MCI_WINDOW:
1646         TRACE("Unsupported command [%lu]\n", wMsg);
1647         break;
1648         /* option which can be silenced */
1649     case MCI_CONFIGURE:
1650         return 0;
1651     case MCI_OPEN:
1652     case MCI_CLOSE:
1653         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1654         break;
1655     default:
1656         FIXME("is probably wrong msg [%lu]\n", wMsg);
1657         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1658     }
1659     return MCIERR_UNRECOGNIZED_COMMAND;
1660 }