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