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