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