- got rid of all the internal MM tweaks to load builtin MCI
[wine] / multimedia / mmsystem.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * MMSYTEM functions
5  *
6  * Copyright 1993 Martin Ayotte
7  */
8
9 /* 
10  * Eric POUECH : 
11  *      98/9    added Win32 MCI support
12  *      99/4    added mmTask and mmThread functions support
13  *              added midiStream support
14  */
15
16 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses 
17  *        and long term pointers to 16 bit space in here
18  */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <sys/ioctl.h>
25
26 #include "winbase.h"
27 #include "windef.h"
28 #include "wine/winbase16.h"
29 #include "heap.h"
30 #include "user.h"
31 #include "driver.h"
32 #include "multimedia.h"
33 #include "callback.h"
34 #include "module.h"
35 #include "selectors.h"
36 #include "debugstr.h"
37 #include "debug.h"
38
39 DECLARE_DEBUG_CHANNEL(mmaux)
40 DECLARE_DEBUG_CHANNEL(mmsys)
41
42 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
43 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
44 LONG   WINAPI DrvDefDriverProc(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg, 
45                                DWORD dwParam1, DWORD dwParam2);
46
47 /**************************************************************************
48  *                              MMSYSTEM_WEP            [MMSYSTEM.1]
49  */
50 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
51                         WORD cbHeapSize, LPSTR lpCmdLine)
52 {
53     FIXME(mmsys, "STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
54     return(TRUE);
55 }
56
57 static void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32) 
58 {
59     mmt16->wType = mmt32->wType;
60     /* layout of rest is the same for 32/16,
61      * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
62      */
63     memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
64 }
65
66 static void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16) 
67 {
68     mmt32->wType = mmt16->wType;
69     /* layout of rest is the same for 32/16,
70      * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
71      */
72     memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
73 }
74
75 static HANDLE           PlaySound_hThread = 0;
76 static HANDLE           PlaySound_hPlayEvent = 0;
77 static HANDLE           PlaySound_hReadyEvent = 0;
78 static HANDLE           PlaySound_hMiddleEvent = 0;
79 static BOOL             PlaySound_Result = FALSE;
80 static int              PlaySound_Stop = FALSE;
81 static int              PlaySound_Playing = FALSE;
82
83 static LPCSTR           PlaySound_pszSound = NULL;
84 static HMODULE          PlaySound_hmod = 0;
85 static DWORD            PlaySound_fdwSound = 0;
86 static int              PlaySound_Loop = FALSE;
87 static int              PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
88                                                      2 - PlaySound order */
89
90 static HMMIO16  get_mmioFromFile(LPCSTR lpszName)
91 {
92     return mmioOpen16((LPSTR)lpszName, NULL,
93                       MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
94 }
95
96 static HMMIO16 get_mmioFromProfile(UINT uFlags, LPCSTR lpszName) 
97 {
98     char        str[128];
99     LPSTR       ptr;
100     HMMIO16     hmmio;
101     
102     TRACE(mmsys, "searching in SystemSound List !\n");
103     GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
104     if (strlen(str) == 0) {
105         if (uFlags & SND_NODEFAULT) return 0;
106         GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
107         if (strlen(str) == 0) return 0;
108     }
109     if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
110     hmmio = get_mmioFromFile(str);
111     if (hmmio == 0) {
112         WARN(mmsys, "can't find SystemSound='%s' !\n", str);
113         return 0;
114     }
115     return hmmio;
116 }
117
118 static BOOL16 WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
119 {
120     BOOL16              bRet = FALSE;
121     HMMIO16             hmmio;
122     MMCKINFO            ckMainRIFF;
123     
124     TRACE(mmsys, "SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
125     if (lpszSoundName == NULL) {
126         TRACE(mmsys, "Stop !\n");
127         return FALSE;
128     }
129     if (uFlags & SND_MEMORY) {
130         MMIOINFO16 mminfo;
131         memset(&mminfo, 0, sizeof(mminfo));
132         mminfo.fccIOProc = FOURCC_MEM;
133         mminfo.pchBuffer = (LPSTR)lpszSoundName;
134         mminfo.cchBuffer = -1;
135         TRACE(mmsys, "Memory sound %p\n", lpszSoundName);
136         hmmio = mmioOpen16(NULL, &mminfo, MMIO_READ);
137     } else {
138         hmmio = 0;
139         if (uFlags & SND_ALIAS)
140             if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) 
141                 return FALSE;
142         
143         if (uFlags & SND_FILENAME)
144             if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
145         
146         if (PlaySound_SearchMode == 1) {
147             PlaySound_SearchMode = 0;
148             if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) 
149                 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) 
150                     return FALSE;
151         }
152         
153         if (PlaySound_SearchMode == 2) {
154             PlaySound_SearchMode = 0;
155             if ((hmmio=get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0) 
156                 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0)       
157                     if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) return FALSE;
158         }
159     }
160     
161     if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0) == 0) 
162         do {
163             TRACE(mmsys, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
164                   (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, 
165                   ckMainRIFF.cksize);
166             
167             if ((ckMainRIFF.ckid == FOURCC_RIFF) &&
168                 (ckMainRIFF.fccType == mmioFOURCC('W', 'A', 'V', 'E'))) {
169                 MMCKINFO        mmckInfo;
170                 
171                 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
172                 
173                 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
174                     PCMWAVEFORMAT           pcmWaveFormat;
175                     
176                     TRACE(mmsys, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
177                           (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
178                     
179                     if (mmioRead(hmmio, (HPSTR)&pcmWaveFormat,
180                                  (long) sizeof(PCMWAVEFORMAT)) == (long) sizeof(PCMWAVEFORMAT)) {
181                         TRACE(mmsys, "wFormatTag=%04X !\n", pcmWaveFormat.wf.wFormatTag);
182                         TRACE(mmsys, "nChannels=%d \n", pcmWaveFormat.wf.nChannels);
183                         TRACE(mmsys, "nSamplesPerSec=%ld\n", pcmWaveFormat.wf.nSamplesPerSec);
184                         TRACE(mmsys, "nAvgBytesPerSec=%ld\n", pcmWaveFormat.wf.nAvgBytesPerSec);
185                         TRACE(mmsys, "nBlockAlign=%d \n", pcmWaveFormat.wf.nBlockAlign);
186                         TRACE(mmsys, "wBitsPerSample=%u !\n", pcmWaveFormat.wBitsPerSample);
187                         
188                         mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
189                         if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
190                             WAVEOPENDESC        waveDesc;
191                             DWORD               dwRet;
192                             
193                             TRACE(mmsys, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n", 
194                                   (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
195                             
196                             pcmWaveFormat.wf.nAvgBytesPerSec = pcmWaveFormat.wf.nSamplesPerSec * 
197                                 pcmWaveFormat.wf.nBlockAlign;
198                             waveDesc.hWave    = 0;
199                             waveDesc.lpFormat = (LPWAVEFORMAT)&pcmWaveFormat;
200                             
201                             dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
202                             if (dwRet == MMSYSERR_NOERROR) {
203                                 WAVEHDR         waveHdr;
204                                 HGLOBAL16       hData;
205                                 INT             count, bufsize, left = mmckInfo.cksize;
206                                 
207                                 bufsize = 64000;
208                                 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
209                                 waveHdr.lpData = (LPSTR)GlobalLock16(hData);
210                                 waveHdr.dwBufferLength = bufsize;
211                                 waveHdr.dwUser = 0L;
212                                 waveHdr.dwFlags = 0L;
213                                 waveHdr.dwLoops = 0L;
214                                 
215                                 dwRet = wodMessage(0, WODM_PREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
216                                 if (dwRet == MMSYSERR_NOERROR) {
217                                     while (left) {
218                                         if (PlaySound_Stop) {
219                                             PlaySound_Stop = FALSE;
220                                             PlaySound_Loop = FALSE;
221                                             break;
222                                         }
223                                         if (bufsize > left) bufsize = left;
224                                         count = mmioRead(hmmio, waveHdr.lpData,bufsize);
225                                         if (count < 1) break;
226                                         left -= count;
227                                         waveHdr.dwBufferLength = count;
228                                         /* FIXME */
229                                         waveHdr.reserved = (DWORD)&waveHdr;
230                                         /* waveHdr.dwBytesRecorded = count; */
231                                         /* FIXME: doesn't expect async ops */ 
232                                         wodMessage(0, WODM_WRITE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
233                                     }
234                                     wodMessage(0, WODM_UNPREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
235                                     wodMessage(0, WODM_CLOSE, 0, 0L, 0L);
236                                     
237                                     bRet = TRUE;
238                                 } else 
239                                     WARN(mmsys, "can't prepare WaveOut device !\n");
240                                 
241                                 GlobalUnlock16(hData);
242                                 GlobalFree16(hData);
243                             }
244                         }
245                     }
246                 }
247             }
248         } while (PlaySound_Loop);
249     
250     if (hmmio != 0) mmioClose(hmmio, 0);
251     return bRet;
252 }
253
254 static DWORD WINAPI PlaySound_Thread(LPVOID arg) 
255 {
256     DWORD     res;
257     
258     for (;;) {
259         PlaySound_Playing = FALSE;
260         SetEvent(PlaySound_hReadyEvent);
261         res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
262         ResetEvent(PlaySound_hReadyEvent);
263         SetEvent(PlaySound_hMiddleEvent);
264         if (res == WAIT_FAILED) ExitThread(2);
265         if (res != WAIT_OBJECT_0) continue;
266         PlaySound_Playing = TRUE;
267         
268         if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
269             HRSRC       hRES;
270             HGLOBAL     hGLOB;
271             void*       ptr;
272
273             if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
274                 PlaySound_Result = FALSE;
275                 continue;
276             }
277             if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
278                 PlaySound_Result = FALSE;
279                 continue;
280             }
281             if ((ptr = LockResource(hGLOB)) == NULL) {
282                 FreeResource(hGLOB);
283                 PlaySound_Result = FALSE;
284                 continue;
285             }
286             PlaySound_Result = proc_PlaySound(ptr, 
287                                               ((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
288             FreeResource(hGLOB);
289             continue;
290         }
291         PlaySound_Result=proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
292     }
293 }
294
295 /**************************************************************************
296  *                              PlaySoundA              [WINMM.1]
297  */
298 BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
299 {
300     static LPSTR StrDup = NULL;
301     
302     TRACE(mmsys, "pszSound='%p' hmod=%04X fdwSound=%08lX\n",
303           pszSound, hmod, fdwSound);
304     
305     if (PlaySound_hThread == 0) { /* This is the first time they called us */
306         DWORD   id;
307         if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
308             return FALSE;
309         if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
310             return FALSE;
311         if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
312             return FALSE;
313         if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0) 
314             return FALSE;
315     }
316     
317     /* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */ 
318     if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing) 
319         return FALSE;
320     
321     /* Trying to stop if playing */
322     if (PlaySound_Playing) PlaySound_Stop = TRUE;
323     
324     /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
325     if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
326         return FALSE;
327     
328     if (!pszSound || (fdwSound & SND_PURGE)) 
329         return FALSE; /* We stoped playing so leaving */
330     
331     if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
332     if (!(fdwSound & SND_ASYNC)) {
333         if (fdwSound & SND_LOOP) 
334             return FALSE;
335         PlaySound_pszSound = pszSound;
336         PlaySound_hmod = hmod;
337         PlaySound_fdwSound = fdwSound;
338         PlaySound_Result = FALSE;
339         SetEvent(PlaySound_hPlayEvent);
340         if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0) 
341             return FALSE;
342         if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0) 
343             return FALSE;
344         return PlaySound_Result;
345     } else {
346         PlaySound_hmod = hmod;
347         PlaySound_fdwSound = fdwSound;
348         PlaySound_Result = FALSE;
349         if (StrDup) {
350             HeapFree(GetProcessHeap(), 0, StrDup);
351             StrDup = NULL;
352         }
353         if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) && 
354                                           !((DWORD)pszSound >> 16)) || !pszSound)) {
355             StrDup = HEAP_strdupA(GetProcessHeap(), 0,pszSound);
356             PlaySound_pszSound = StrDup;
357         } else PlaySound_pszSound = pszSound;
358         PlaySound_Loop = fdwSound & SND_LOOP;
359         SetEvent(PlaySound_hPlayEvent);
360         ResetEvent(PlaySound_hMiddleEvent);
361         return TRUE;
362     }
363     return FALSE;
364 }
365
366 /**************************************************************************
367  *                              PlaySoundW              [WINMM.18]
368  */
369 BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
370 {
371     LPSTR       pszSoundA;
372     BOOL        bSound;
373     
374     if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) && 
375                                       !((DWORD)pszSound >> 16)) || !pszSound)) {
376         pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
377         bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
378         HeapFree(GetProcessHeap(), 0,pszSoundA);
379     } else  
380         bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
381     
382     return bSound;
383 }
384
385 /**************************************************************************
386  *                              sndPlaySoundA           [MMSYSTEM.2][WINMM135]
387  */
388 BOOL16 WINAPI sndPlaySoundA(LPCSTR lpszSoundName, UINT16 uFlags)
389 {
390     PlaySound_SearchMode = 1;
391     return PlaySoundA(lpszSoundName, 0, uFlags);
392 }
393
394 /**************************************************************************
395  *                              sndPlaySoundW           [WINMM.136]
396  */
397 BOOL16 WINAPI sndPlaySoundW(LPCWSTR lpszSoundName, UINT16 uFlags)
398 {
399     PlaySound_SearchMode = 1;
400     return PlaySoundW(lpszSoundName, 0, uFlags);
401 }
402
403 /**************************************************************************
404  *                              mmsystemGetVersion      [WINMM.134]
405  */
406 UINT WINAPI mmsystemGetVersion()
407 {
408     return mmsystemGetVersion16();
409 }
410
411 /**************************************************************************
412  *                              mmsystemGetVersion      [MMSYSTEM.5]
413  * return value borrowed from Win95 winmm.dll ;)
414  */
415 UINT16 WINAPI mmsystemGetVersion16()
416 {
417     TRACE(mmsys, "3.10 (Win95?)\n");
418     return 0x030a;
419 }
420
421 /**************************************************************************
422  *                              DriverProc                      [MMSYSTEM.6]
423  */
424 LRESULT WINAPI DriverProc16(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg, 
425                             DWORD dwParam1, DWORD dwParam2)
426 {
427     return DrvDefDriverProc(dwDevID, hDrv, wMsg, dwParam1, dwParam2);
428 }
429
430 /**************************************************************************
431  *                              DriverCallback                  [MMSYSTEM.31]
432  */
433 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HANDLE16 hDev, 
434                                WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
435 {
436     TRACE(mmsys, "(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
437           dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
438
439     switch (uFlags & DCB_TYPEMASK) {
440     case DCB_NULL:
441         TRACE(mmsys, "Null !\n");
442         break;
443     case DCB_WINDOW:
444         TRACE(mmsys, "Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
445         if (!IsWindow(dwCallBack) || USER_HEAP_LIN_ADDR(hDev) == NULL)
446             return FALSE;
447         Callout.PostMessageA((HWND16)dwCallBack, wMsg, hDev, dwParam1);
448         break;
449     case DCB_TASK: /* aka DCB_THREAD */
450         TRACE(mmsys, "Task(%04lx) !\n", dwCallBack);
451         Callout.PostThreadMessageA(dwCallBack, wMsg, hDev, dwParam1);
452         break;
453     case DCB_FUNCTION:
454         TRACE(mmsys, "Function (16bit) !\n");
455         Callbacks->CallDriverCallback((FARPROC16)dwCallBack, hDev, wMsg, dwUser,
456                                        dwParam1, dwParam2);
457         break;
458     case DCB_FUNC32: /* This is a Wine only value - AKAIF not used yet by MS */
459         TRACE(mmsys, "Function (32bit) !\n");
460         ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
461         break;
462     case DCB_EVENT:
463         TRACE(mmsys, "Event(%08lx) !\n", dwCallBack);
464         SetEvent((HANDLE)dwCallBack);
465         break;
466     case 6: /* I would dub it DCB_MMTHREADSIGNAL */
467         /* this is an undocumented DCB_ value used for mmThreads
468          * loword of dwCallBack contains the handle of the lpMMThd block
469          * which dwSignalCount has to be incremented
470          */
471         {
472             WINE_MMTHREAD*      lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(LOWORD(dwCallBack), 0);
473
474             TRACE(mmsys, "mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
475             /* same as mmThreadSignal16 */
476             InterlockedIncrement(&lpMMThd->dwSignalCount);
477             SetEvent(lpMMThd->hEvent);
478             /* some other stuff on lpMMThd->hVxD */
479         }
480         break;  
481 #if 0
482     case 4:
483         /* this is an undocumented DCB_ value for... I don't know */
484         break;
485 #endif
486     default:
487         WARN(mmsys, "Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
488         return FALSE;
489     }
490     TRACE(mmsys, "Done\n");
491     return TRUE;
492 }
493
494 /**************************************************************************
495  *      Mixer devices. New to Win95
496  */
497
498 /**************************************************************************
499  * find out the real mixer ID depending on hmix (depends on dwFlags)
500  * FIXME: also fix dwInstance passing to mixMessage 
501  */
502 static UINT MIXER_GetDevID(HMIXEROBJ hmix, DWORD dwFlags) 
503 {
504     /* FIXME: Check dwFlags for MIXER_OBJSECTF_xxxx entries and modify hmix 
505      * accordingly. For now we always use mixerdevice 0. 
506      */
507     return 0;
508 }
509
510 /**************************************************************************
511  *                              mixerGetNumDevs                 [WINMM.108]
512  */
513 UINT WINAPI mixerGetNumDevs(void) 
514 {
515     UINT16      count = mixMessage(0, MXDM_GETNUMDEVS, 0L, 0L, 0L);
516     
517     TRACE(mmaux,"mixerGetNumDevs returns %d\n", count);
518     return count;
519 }
520
521 /**************************************************************************
522  *                              mixerGetNumDevs                 [MMSYSTEM.800]
523  */
524 UINT16 WINAPI mixerGetNumDevs16() 
525 {
526     return mixerGetNumDevs();
527 }
528
529 /**************************************************************************
530  *                              mixerGetDevCapsA                [WINMM.101]
531  */
532 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size) 
533 {
534     return mixMessage(devid, MXDM_GETDEVCAPS, 0L, (DWORD)mixcaps, (DWORD)size);
535 }
536
537 /**************************************************************************
538  *                              mixerGetDevCapsW                [WINMM.102]
539  */
540 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size) 
541 {
542     MIXERCAPSA  micA;
543     UINT        ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
544
545     if (ret == MMSYSERR_NOERROR) {
546         mixcaps->wMid           = micA.wMid;
547         mixcaps->wPid           = micA.wPid;
548         mixcaps->vDriverVersion = micA.vDriverVersion;
549         lstrcpyAtoW(mixcaps->szPname, micA.szPname);
550         mixcaps->fdwSupport     = micA.fdwSupport;
551         mixcaps->cDestinations  = micA.cDestinations;
552     }
553     return ret;
554 }
555
556 /**************************************************************************
557  *                              mixerGetDevCaps                 [MMSYSTEM.801]
558  */
559 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps, UINT16 size) 
560 {
561     MIXERCAPSA  micA;
562     UINT        ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
563     
564     if (ret == MMSYSERR_NOERROR) {
565         mixcaps->wMid           = micA.wMid;
566         mixcaps->wPid           = micA.wPid;
567         mixcaps->vDriverVersion = micA.vDriverVersion;
568         strcpy(PTR_SEG_TO_LIN(mixcaps->szPname), micA.szPname);
569         mixcaps->fdwSupport     = micA.fdwSupport;
570         mixcaps->cDestinations  = micA.cDestinations;
571     }
572     return ret;
573 }
574
575 /**************************************************************************
576  *                              mixerOpen                       [WINMM.110]
577  */
578 UINT WINAPI mixerOpen(LPHMIXER lphmix, UINT uDeviceID, DWORD dwCallback,
579                       DWORD dwInstance, DWORD fdwOpen) 
580 {
581     HMIXER16    hmix16;
582     UINT        ret;
583     
584     FIXME(mmsys,"(%p, %d, %08lx, %08lx, %08lx): semi stub?\n",
585           lphmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
586     ret = mixerOpen16(&hmix16, uDeviceID, dwCallback, dwInstance,fdwOpen);
587     if (lphmix) *lphmix = hmix16;
588     return ret;
589 }
590
591 /**************************************************************************
592  *                              mixerOpen                       [MMSYSTEM.803]
593  */
594 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
595                           DWORD dwInstance, DWORD fdwOpen) 
596 {
597     HMIXER16            hmix;
598     LPMIXEROPENDESC     lpmod;
599     BOOL                mapperflag = (uDeviceID == 0);
600     DWORD               dwRet = 0;
601     
602     TRACE(mmsys,"(%p, %d, %08lx, %08lx, %08lx)\n",
603           lphmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
604     hmix = USER_HEAP_ALLOC(sizeof(MIXEROPENDESC));
605     if (lphmix) *lphmix = hmix;
606     lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
607     lpmod->hmx = hmix;
608     lpmod->dwCallback = dwCallback;
609     lpmod->dwInstance = dwInstance;
610     if (uDeviceID >= MAXMIXERDRIVERS)
611         uDeviceID = 0;
612     while (uDeviceID < MAXMIXERDRIVERS) {
613         dwRet = mixMessage(uDeviceID, MXDM_OPEN, dwInstance, (DWORD)lpmod, fdwOpen);
614         if (dwRet == MMSYSERR_NOERROR) break;
615         if (!mapperflag) break;
616         uDeviceID++;
617     }
618     lpmod->uDeviceID = uDeviceID;
619     
620     if (dwRet != MMSYSERR_NOERROR) {
621         USER_HEAP_FREE(hmix);
622         if (lphmix) *lphmix = 0;
623     }
624
625     return dwRet;
626 }
627
628 /**************************************************************************
629  *                              mixerClose                      [WINMM.98]
630  */
631 UINT WINAPI mixerClose(HMIXER hmix) 
632 {
633     LPMIXEROPENDESC     lpmod;
634     DWORD               dwRet;    
635
636     FIXME(mmsys,"(%04x): semi-stub?\n", hmix);
637
638     lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
639     if (lpmod == NULL) return MMSYSERR_INVALHANDLE;
640     dwRet = mixMessage(lpmod->uDeviceID, MXDM_CLOSE, lpmod->dwInstance, 0L, 0L);
641     USER_HEAP_FREE(hmix);
642     return dwRet;
643 }
644
645 /**************************************************************************
646  *                              mixerClose                      [MMSYSTEM.803]
647  */
648 UINT16 WINAPI mixerClose16(HMIXER16 hmix) 
649 {
650     return mixerClose(hmix);
651 }
652
653 /**************************************************************************
654  *                              mixerGetID                      [WINMM.103]
655  */
656 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID) 
657 {
658     FIXME(mmsys,"(%04x %p %08lx): semi-stub\n", hmix, lpid, fdwID);
659
660     if (lpid)
661       *lpid = MIXER_GetDevID(hmix, fdwID);
662
663     return MMSYSERR_NOERROR; /* FIXME: many error possibilities */
664 }
665
666 /**************************************************************************
667  *                              mixerGetID
668  */
669 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID) 
670 {
671     UINT        xid;    
672     UINT        ret = mixerGetID(hmix, &xid, fdwID);
673
674     if (lpid) 
675         *lpid = xid;
676     return ret;
677 }
678
679 /**************************************************************************
680  *                              mixerGetControlDetailsA [WINMM.99]
681  */
682 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails) 
683 {
684     FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
685     return MMSYSERR_NOTENABLED;
686 }
687
688 /**************************************************************************
689  *                              mixerGetControlDetailsW [WINMM.100]
690  */
691 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails) 
692 {
693     FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
694     return MMSYSERR_NOTENABLED;
695 }
696
697 /**************************************************************************
698  *                              mixerGetControlDetails  [MMSYSTEM.808]
699  */
700 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails) 
701 {
702     FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
703     return MMSYSERR_NOTENABLED;
704 }
705
706 /**************************************************************************
707  *                              mixerGetLineControlsA   [WINMM.104]
708  */
709 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlc, DWORD fdwControls) 
710 {
711     UINT        uDevID;
712
713     FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmlc, fdwControls);
714
715     uDevID = MIXER_GetDevID(hmix, 0);
716
717     return mixMessage(uDevID, MXDM_GETLINECONTROLS, 0, (DWORD)lpmlc, fdwControls);
718 }
719
720 /**************************************************************************
721  *                              mixerGetLineControlsW           [WINMM.105]
722  */
723 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlc, DWORD fdwControls) 
724 {
725     FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmlc, fdwControls);
726     return MMSYSERR_NOTENABLED;
727 }
728
729 /**************************************************************************
730  *                              mixerGetLineControls            [MMSYSTEM.807]
731  */
732 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix, LPMIXERLINECONTROLS16 lpmlc, DWORD fdwControls) 
733 {
734     FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmlc, fdwControls);
735     return MMSYSERR_NOTENABLED;
736 }
737
738 /**************************************************************************
739  *                              mixerGetLineInfoA               [WINMM.106]
740  */
741 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpml, DWORD fdwInfo) 
742 {
743     UINT16 devid;
744     
745     TRACE(mmsys, "(%04x, %p, %08lx)\n", hmix, lpml, fdwInfo);
746     
747     /* FIXME: I'm not sure of the flags */
748     devid = MIXER_GetDevID(hmix, fdwInfo);
749     return mixMessage(devid, MXDM_GETLINEINFO, 0, (DWORD)lpml, fdwInfo);
750 }
751
752 /**************************************************************************
753  *                              mixerGetLineInfoW               [WINMM.107]
754  */
755 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpml, DWORD fdwInfo) 
756 {
757     MIXERLINEA          mlA;
758     UINT                ret;
759     
760     TRACE(mmsys,"(%04x, %p, %08lx)\n", hmix, lpml, fdwInfo);
761
762     if (lpml == NULL || lpml->cbStruct != sizeof(*lpml)) 
763         return MMSYSERR_INVALPARAM;
764
765     mlA.cbStruct = sizeof(mlA);
766     mlA.dwDestination = lpml->dwDestination;
767     mlA.dwSource = lpml->dwSource; 
768     mlA.dwLineID = lpml->dwLineID; 
769     mlA.dwUser = lpml->dwUser; 
770     mlA.dwComponentType = lpml->dwComponentType; 
771     mlA.cChannels = lpml->cChannels; 
772     mlA.cConnections = lpml->cConnections; 
773     mlA.cControls = lpml->cControls; 
774
775     ret = mixerGetLineInfoA(hmix, &mlA, fdwInfo);
776
777     lpml->dwDestination = mlA.dwDestination;
778     lpml->dwSource = mlA.dwSource;
779     lpml->dwLineID = mlA.dwLineID;
780     lpml->fdwLine = mlA.fdwLine;
781     lpml->dwUser = mlA.dwUser;
782     lpml->dwComponentType = mlA.dwComponentType;
783     lpml->cChannels = mlA.cChannels;
784     lpml->cConnections = mlA.cConnections;
785     lpml->cControls = mlA.cControls;
786     lstrcpyAtoW(lpml->szShortName, mlA.szShortName);
787     lstrcpyAtoW(lpml->szName, mlA.szName);
788     lpml->Target.dwType = mlA.Target.dwType;
789     lpml->Target.dwDeviceID = mlA.Target.dwDeviceID;
790     lpml->Target.wMid = mlA.Target.wMid;
791     lpml->Target.wPid = mlA.Target.wPid;
792     lpml->Target.vDriverVersion = mlA.Target.vDriverVersion;
793     lstrcpyAtoW(lpml->Target.szPname, mlA.Target.szPname);
794
795     return ret;
796 }
797
798 /**************************************************************************
799  *                              mixerGetLineInfo        [MMSYSTEM.805]
800  */
801 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpml, DWORD fdwInfo) 
802 {
803     MIXERLINEA          mlA;
804     UINT                ret;
805     
806     TRACE(mmsys, "(%04x, %p, %08lx)\n", hmix, lpml, fdwInfo);
807
808     if (lpml == NULL || lpml->cbStruct != sizeof(*lpml)) 
809         return MMSYSERR_INVALPARAM;
810
811     mlA.cbStruct                = sizeof(mlA);
812     mlA.dwDestination           = lpml->dwDestination;
813     mlA.dwSource                = lpml->dwSource; 
814     mlA.dwLineID                = lpml->dwLineID; 
815     mlA.dwUser                  = lpml->dwUser; 
816     mlA.dwComponentType         = lpml->dwComponentType; 
817     mlA.cChannels               = lpml->cChannels; 
818     mlA.cConnections            = lpml->cConnections; 
819     mlA.cControls               = lpml->cControls; 
820
821     ret = mixerGetLineInfoA(hmix, &mlA, fdwInfo);
822
823     lpml->dwDestination         = mlA.dwDestination;
824     lpml->dwSource              = mlA.dwSource;
825     lpml->dwLineID              = mlA.dwLineID;
826     lpml->fdwLine               = mlA.fdwLine;
827     lpml->dwUser                = mlA.dwUser;
828     lpml->dwComponentType       = mlA.dwComponentType;
829     lpml->cChannels             = mlA.cChannels;
830     lpml->cConnections          = mlA.cConnections;
831     lpml->cControls             = mlA.cControls;
832     strcpy(PTR_SEG_TO_LIN(lpml->szShortName), mlA.szShortName);
833     strcpy(PTR_SEG_TO_LIN(lpml->szName), mlA.szName);
834     lpml->Target.dwType         = mlA.Target.dwType;
835     lpml->Target.dwDeviceID     = mlA.Target.dwDeviceID;
836     lpml->Target.wMid           = mlA.Target.wMid;
837     lpml->Target.wPid           = mlA.Target.wPid;
838     lpml->Target.vDriverVersion = mlA.Target.vDriverVersion;
839     strcpy(PTR_SEG_TO_LIN(lpml->Target.szPname), mlA.Target.szPname);
840     return ret;
841 }
842
843 /**************************************************************************
844  *                              mixerSetControlDetails  [WINMM.111]
845  */
846 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails) 
847 {
848     FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
849     return MMSYSERR_NOTENABLED;
850 }
851
852 /**************************************************************************
853  *                              mixerSetControlDetails  [MMSYSTEM.809]
854  */
855 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails) 
856 {
857     FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
858     return MMSYSERR_NOTENABLED;
859 }
860
861 /**************************************************************************
862  *                              mixerMessage            [WINMM.109]
863  */
864 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2) 
865 {
866     LPMIXEROPENDESC     lpmod;
867     UINT16              uDeviceID;
868     
869     lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
870     if (lpmod)
871         uDeviceID = lpmod->uDeviceID;
872     else
873         uDeviceID = 0;
874     FIXME(mmsys,"(%04lx, %d, %08lx, %08lx): semi-stub?\n",
875           (DWORD)hmix, uMsg, dwParam1, dwParam2);
876     return mixMessage(uDeviceID, uMsg, 0L, dwParam1, dwParam2);
877 }
878
879 /**************************************************************************
880  *                              mixerMessage            [MMSYSTEM.804]
881  */
882 UINT16 WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1, DWORD dwParam2) 
883 {
884     LPMIXEROPENDESC     lpmod;
885     UINT16              uDeviceID;
886     
887     lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
888     uDeviceID = (lpmod) ? lpmod->uDeviceID : 0;
889     FIXME(mmsys,"(%04x, %d, %08lx, %08lx) - semi-stub?\n",
890           hmix, uMsg, dwParam1, dwParam2);
891     return mixMessage(uDeviceID, uMsg, 0L, dwParam1, dwParam2);
892 }
893
894 /**************************************************************************
895  *                              auxGetNumDevs           [WINMM.22]
896  */
897 UINT WINAPI auxGetNumDevs()
898 {
899     return auxGetNumDevs16();
900 }
901
902 /**************************************************************************
903  *                              auxGetNumDevs           [MMSYSTEM.350]
904  */
905 UINT16 WINAPI auxGetNumDevs16()
906 {
907     UINT16      count;
908
909     TRACE(mmsys, "\n");
910     count = auxMessage(0, AUXDM_GETNUMDEVS, 0L, 0L, 0L);
911     TRACE(mmsys, "=> %u\n", count);
912     return count;
913 }
914
915 /**************************************************************************
916  *                              auxGetDevCaps           [WINMM.20]
917  */
918 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
919 {
920     AUXCAPS16   ac16;
921     UINT        ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
922     
923     lpCaps->wMid = ac16.wMid;
924     lpCaps->wPid = ac16.wPid;
925     lpCaps->vDriverVersion = ac16.vDriverVersion;
926     lstrcpyAtoW(lpCaps->szPname, ac16.szPname);
927     lpCaps->wTechnology = ac16.wTechnology;
928     lpCaps->dwSupport = ac16.dwSupport;
929     return ret;
930 }
931
932 /**************************************************************************
933  *                              auxGetDevCaps           [WINMM.21]
934  */
935 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
936 {
937     AUXCAPS16   ac16;
938     UINT        ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
939     
940     lpCaps->wMid = ac16.wMid;
941     lpCaps->wPid = ac16.wPid;
942     lpCaps->vDriverVersion = ac16.vDriverVersion;
943     strcpy(lpCaps->szPname, ac16.szPname);
944     lpCaps->wTechnology = ac16.wTechnology;
945     lpCaps->dwSupport = ac16.dwSupport;
946     return ret;
947 }
948
949 /**************************************************************************
950  *                              auxGetDevCaps           [MMSYSTEM.351]
951  */
952 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
953 {
954     TRACE(mmsys, "(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
955
956     return auxMessage(uDeviceID, AUXDM_GETDEVCAPS,
957                       0L, (DWORD)lpCaps, (DWORD)uSize);
958 }
959
960 /**************************************************************************
961  *                              auxGetVolume            [WINM.23]
962  */
963 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
964 {
965     return auxGetVolume16(uDeviceID, lpdwVolume);
966 }
967
968 /**************************************************************************
969  *                              auxGetVolume            [MMSYSTEM.352]
970  */
971 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
972 {
973     TRACE(mmsys, "(%04X, %p) !\n", uDeviceID, lpdwVolume);
974
975     return auxMessage(uDeviceID, AUXDM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
976 }
977
978 /**************************************************************************
979  *                              auxSetVolume            [WINMM.25]
980  */
981 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
982 {
983     return auxSetVolume16(uDeviceID, dwVolume);
984 }
985
986 /**************************************************************************
987  *                              auxSetVolume            [MMSYSTEM.353]
988  */
989 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
990 {
991     TRACE(mmsys, "(%04X, %08lX) !\n", uDeviceID, dwVolume);
992
993     return auxMessage(uDeviceID, AUXDM_SETVOLUME, 0L, dwVolume, 0L);
994 }
995
996 /**************************************************************************
997  *                              auxOutMessage           [MMSYSTEM.354]
998  */
999 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1000 {
1001     switch (uMessage) {
1002     case AUXDM_GETNUMDEVS:
1003     case AUXDM_GETVOLUME:
1004     case AUXDM_SETVOLUME:
1005         /* no argument conversion needed */
1006         break;
1007     case AUXDM_GETDEVCAPS:
1008         return auxGetDevCapsA(uDeviceID, (LPAUXCAPSA)dw1, dw2);
1009     default:
1010         ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
1011             uDeviceID, uMessage, dw1, dw2);
1012         break;
1013     }
1014     return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
1015 }
1016
1017 /**************************************************************************
1018  *                              auxOutMessage           [MMSYSTEM.354]
1019  */
1020 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1021 {
1022     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1023
1024     switch (uMessage) {
1025     case AUXDM_GETNUMDEVS:
1026     case AUXDM_SETVOLUME:
1027         /* no argument conversion needed */
1028         break;
1029     case AUXDM_GETVOLUME:
1030         return auxGetVolume16(uDeviceID, (LPDWORD)PTR_SEG_TO_LIN(dw1));
1031     case AUXDM_GETDEVCAPS:
1032         return auxGetDevCaps16(uDeviceID, (LPAUXCAPS16)PTR_SEG_TO_LIN(dw1), dw2);
1033     default:
1034         ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
1035             uDeviceID, uMessage, dw1, dw2);
1036         break;
1037     }
1038     return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
1039 }
1040
1041 /**************************************************************************
1042  *                              mciGetErrorStringW              [WINMM.46]
1043  */
1044 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1045 {
1046     LPSTR       bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1047     BOOL        ret = mciGetErrorStringA(wError, bufstr, uLength);
1048     
1049     lstrcpyAtoW(lpstrBuffer, bufstr);
1050     HeapFree(GetProcessHeap(), 0, bufstr);
1051     return ret;
1052 }
1053
1054 /**************************************************************************
1055  *                              mciGetErrorStringA              [WINMM.45]
1056  */
1057 BOOL WINAPI mciGetErrorStringA(DWORD wError, LPSTR lpstrBuffer, UINT uLength)
1058 {
1059     return mciGetErrorString16(wError, lpstrBuffer, uLength);
1060 }
1061
1062 /**************************************************************************
1063  *                              mciGetErrorString               [MMSYSTEM.706]
1064  */
1065 BOOL16 WINAPI mciGetErrorString16(DWORD dwError, LPSTR lpstrBuffer, UINT16 uLength)
1066 {
1067     LPSTR       msgptr = NULL;
1068
1069     TRACE(mmsys, "(%08lX, %p, %d);\n", dwError, lpstrBuffer, uLength);
1070
1071     if ((lpstrBuffer == NULL) || (uLength < 1)) 
1072         return FALSE;
1073
1074     lpstrBuffer[0] = '\0';
1075
1076     switch (dwError) {
1077     case 0:
1078         msgptr = "The specified command has been executed.";
1079         break;
1080     case MCIERR_INVALID_DEVICE_ID:
1081         msgptr = "Invalid MCI device ID. Use the ID returned when opening the MCI device.";
1082         break;
1083     case MCIERR_UNRECOGNIZED_KEYWORD:
1084         msgptr = "The driver cannot recognize the specified command parameter.";
1085         break;
1086     case MCIERR_UNRECOGNIZED_COMMAND:
1087         msgptr = "The driver cannot recognize the specified command.";
1088         break;
1089     case MCIERR_HARDWARE:
1090         msgptr = "There is a problem with your media device. Make sure it is working correctly or contact the device manufacturer.";
1091         break;
1092     case MCIERR_INVALID_DEVICE_NAME:
1093         msgptr = "The specified device is not open or is not recognized by MCI.";
1094         break;
1095     case MCIERR_OUT_OF_MEMORY:
1096         msgptr = "Not enough memory available for this task. \nQuit one or more applications to increase available memory, and then try again.";
1097         break;
1098     case MCIERR_DEVICE_OPEN:
1099         msgptr = "The device name is already being used as an alias by this application. Use a unique alias.";
1100         break;
1101     case MCIERR_CANNOT_LOAD_DRIVER:
1102         msgptr = "There is an undetectable problem in loading the specified device driver.";
1103         break;
1104     case MCIERR_MISSING_COMMAND_STRING:
1105         msgptr = "No command was specified.";
1106         break;
1107     case MCIERR_PARAM_OVERFLOW:
1108         msgptr = "The output string was to large to fit in the return buffer. Increase the size of the buffer.";
1109         break;
1110     case MCIERR_MISSING_STRING_ARGUMENT:
1111         msgptr = "The specified command requires a character-string parameter. Please provide one.";
1112         break;
1113     case MCIERR_BAD_INTEGER:
1114         msgptr = "The specified integer is invalid for this command.";
1115         break;
1116     case MCIERR_PARSER_INTERNAL:
1117         msgptr = "The device driver returned an invalid return type. Check with the device manufacturer about obtaining a new driver.";
1118         break;
1119     case MCIERR_DRIVER_INTERNAL:
1120         msgptr = "There is a problem with the device driver. Check with the device manufacturer about obtaining a new driver.";
1121         break;
1122     case MCIERR_MISSING_PARAMETER:
1123         msgptr = "The specified command requires a parameter. Please supply one.";
1124         break;
1125     case MCIERR_UNSUPPORTED_FUNCTION:
1126         msgptr = "The MCI device you are using does not support the specified command.";
1127         break;
1128     case MCIERR_FILE_NOT_FOUND:
1129         msgptr = "Cannot find the specified file. Make sure the path and filename are correct.";
1130         break;
1131     case MCIERR_DEVICE_NOT_READY:
1132         msgptr = "The device driver is not ready.";
1133         break;
1134     case MCIERR_INTERNAL:
1135         msgptr = "A problem occurred in initializing MCI. Try restarting Windows.";
1136         break;
1137     case MCIERR_DRIVER:
1138         msgptr = "There is a problem with the device driver. The driver has closed. Cannot access error.";
1139         break;
1140     case MCIERR_CANNOT_USE_ALL:
1141         msgptr = "Cannot use 'all' as the device name with the specified command.";
1142         break;
1143     case MCIERR_MULTIPLE:
1144         msgptr = "Errors occurred in more than one device. Specify each command and device separately to determine which devices caused the error";
1145         break;
1146     case MCIERR_EXTENSION_NOT_FOUND:
1147         msgptr = "Cannot determine the device type from the given filename extension.";
1148         break;
1149     case MCIERR_OUTOFRANGE:
1150         msgptr = "The specified parameter is out of range for the specified command.";
1151         break;
1152     case MCIERR_FLAGS_NOT_COMPATIBLE:
1153         msgptr = "The specified parameters cannot be used together.";
1154         break;
1155     case MCIERR_FILE_NOT_SAVED:
1156         msgptr = "Cannot save the specified file. Make sure you have enough disk space or are still connected to the network.";
1157         break;
1158     case MCIERR_DEVICE_TYPE_REQUIRED:
1159         msgptr = "Cannot find the specified device. Make sure it is installed or that the device name is spelled correctly.";
1160         break;
1161     case MCIERR_DEVICE_LOCKED:
1162         msgptr = "The specified device is now being closed. Wait a few seconds, and then try again.";
1163         break;
1164     case MCIERR_DUPLICATE_ALIAS:
1165         msgptr = "The specified alias is already being used in this application. Use a unique alias.";
1166         break;
1167     case MCIERR_BAD_CONSTANT:
1168         msgptr = "The specified parameter is invalid for this command.";
1169         break;
1170     case MCIERR_MUST_USE_SHAREABLE:
1171         msgptr = "The device driver is already in use. To share it, use the 'shareable' parameter with each 'open' command.";
1172         break;
1173     case MCIERR_MISSING_DEVICE_NAME:
1174         msgptr = "The specified command requires an alias, file, driver, or device name. Please supply one.";
1175         break;
1176     case MCIERR_BAD_TIME_FORMAT:
1177         msgptr = "The specified value for the time format is invalid. Refer to the MCI documentation for valid formats.";
1178         break;
1179     case MCIERR_NO_CLOSING_QUOTE:
1180         msgptr = "A closing double-quotation mark is missing from the parameter value. Please supply one.";
1181         break;
1182     case MCIERR_DUPLICATE_FLAGS:
1183         msgptr = "A parameter or value was specified twice. Only specify it once.";
1184         break;
1185     case MCIERR_INVALID_FILE:
1186         msgptr = "The specified file cannot be played on the specified MCI device. The file may be corrupt, or not in the correct format.";
1187         break;
1188     case MCIERR_NULL_PARAMETER_BLOCK:
1189         msgptr = "A null parameter block was passed to MCI.";
1190         break;
1191     case MCIERR_UNNAMED_RESOURCE:
1192         msgptr = "Cannot save an unnamed file. Supply a filename.";
1193         break;
1194     case MCIERR_NEW_REQUIRES_ALIAS:
1195         msgptr = "You must specify an alias when using the 'new' parameter.";
1196         break;
1197     case MCIERR_NOTIFY_ON_AUTO_OPEN:
1198         msgptr = "Cannot use the 'notify' flag with auto-opened devices.";
1199         break;
1200     case MCIERR_NO_ELEMENT_ALLOWED:
1201         msgptr = "Cannot use a filename with the specified device.";
1202         break;
1203     case MCIERR_NONAPPLICABLE_FUNCTION:
1204         msgptr = "Cannot carry out the commands in the order specified. Correct the command sequence, and then try again.";
1205         break;
1206     case MCIERR_ILLEGAL_FOR_AUTO_OPEN:
1207         msgptr = "Cannot carry out the specified command on an auto-opened device. Wait until the device is closed, and then try again.";
1208         break;
1209     case MCIERR_FILENAME_REQUIRED:
1210         msgptr = "The filename is invalid. Make sure the filename is not longer than 8 characters, followed by a period and an extension.";
1211         break;
1212     case MCIERR_EXTRA_CHARACTERS:
1213         msgptr = "Cannot specify extra characters after a string enclosed in quotation marks.";
1214         break;
1215     case MCIERR_DEVICE_NOT_INSTALLED:
1216         msgptr = "The specified device is not installed on the system. Use the Drivers option in Control Panel to install the device.";
1217         break;
1218     case MCIERR_GET_CD:
1219         msgptr = "Cannot access the specified file or MCI device. Try changing directories or restarting your computer.";
1220         break;
1221     case MCIERR_SET_CD:
1222         msgptr = "Cannot access the specified file or MCI device because the application cannot change directories.";
1223         break;
1224     case MCIERR_SET_DRIVE:
1225         msgptr = "Cannot access specified file or MCI device because the application cannot change drives.";
1226         break;
1227     case MCIERR_DEVICE_LENGTH:
1228         msgptr = "Specify a device or driver name that is less than 79 characters.";
1229         break;
1230     case MCIERR_DEVICE_ORD_LENGTH:
1231         msgptr = "Specify a device or driver name that is less than 69 characters.";
1232         break;
1233     case MCIERR_NO_INTEGER:
1234         msgptr = "The specified command requires an integer parameter. Please provide one.";
1235         break;
1236     case MCIERR_WAVE_OUTPUTSINUSE:
1237         msgptr = "All wave devices that can play files in the current format are in use. Wait until a wave device is free, and then try again.";
1238         break;
1239     case MCIERR_WAVE_SETOUTPUTINUSE:
1240         msgptr = "Cannot set the current wave device for play back because it is in use. Wait until the device is free, and then try again.";
1241         break;
1242     case MCIERR_WAVE_INPUTSINUSE:
1243         msgptr = "All wave devices that can record files in the current format are in use. Wait until a wave device is free, and then try again.";
1244         break;
1245     case MCIERR_WAVE_SETINPUTINUSE:
1246         msgptr = "Cannot set the current wave device for recording because it is in use. Wait until the device is free, and then try again.";
1247         break;
1248     case MCIERR_WAVE_OUTPUTUNSPECIFIED:
1249         msgptr = "Any compatible waveform playback device may be used.";
1250         break;
1251     case MCIERR_WAVE_INPUTUNSPECIFIED:
1252         msgptr = "Any compatible waveform recording device may be used.";
1253         break;
1254     case MCIERR_WAVE_OUTPUTSUNSUITABLE:
1255         msgptr = "No wave device that can play files in the current format is installed. Use the Drivers option to install the wave device.";
1256         break;
1257     case MCIERR_WAVE_SETOUTPUTUNSUITABLE:
1258         msgptr = "The device you are trying to play to cannot recognize the current file format.";
1259         break;
1260     case MCIERR_WAVE_INPUTSUNSUITABLE:
1261         msgptr = "No wave device that can record files in the current format is installed. Use the Drivers option to install the wave device.";
1262         break;
1263     case MCIERR_WAVE_SETINPUTUNSUITABLE:
1264         msgptr = "The device you are trying to record from cannot recognize the current file format.";
1265         break;
1266     case MCIERR_NO_WINDOW:
1267         msgptr = "There is no display window.";
1268         break;
1269     case MCIERR_CREATEWINDOW:
1270         msgptr = "Could not create or use window.";
1271         break;
1272     case MCIERR_FILE_READ:
1273         msgptr = "Cannot read the specified file. Make sure the file is still present, or check your disk or network connection.";
1274         break;
1275     case MCIERR_FILE_WRITE:
1276         msgptr = "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network.";
1277         break;
1278     case MCIERR_SEQ_DIV_INCOMPATIBLE:
1279         msgptr = "The time formats of the \"song pointer\" and SMPTE are mutually exclusive. You can't use them together.";
1280         break;
1281     case MCIERR_SEQ_NOMIDIPRESENT:
1282         msgptr = "The system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver.";
1283         break;
1284     case MCIERR_SEQ_PORT_INUSE:
1285         msgptr = "The specified MIDI port is already in use. Wait until it is free; the try again.";
1286         break;
1287     case MCIERR_SEQ_PORT_MAPNODEVICE:
1288         msgptr = "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use the MIDI Mapper option from the Control Panel to edit the setup.";
1289         break;
1290     case MCIERR_SEQ_PORT_MISCERROR:
1291         msgptr = "An error occurred with the specified port.";
1292         break;
1293     case MCIERR_SEQ_PORT_NONEXISTENT:
1294         msgptr = "The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device.";
1295         break;
1296     case MCIERR_SEQ_PORTUNSPECIFIED:
1297         msgptr = "The system doesnot have a current MIDI port specified.";
1298         break;
1299     case MCIERR_SEQ_TIMER:
1300         msgptr = "All multimedia timers are being used by other applications. Quit one of these applications; then, try again.";
1301         break;
1302         
1303         /* 
1304            msg# 513 : vcr
1305            msg# 514 : videodisc
1306            msg# 515 : overlay
1307            msg# 516 : cdaudio
1308            msg# 517 : dat
1309            msg# 518 : scanner
1310            msg# 519 : animation
1311            msg# 520 : digitalvideo
1312            msg# 521 : other
1313            msg# 522 : waveaudio
1314            msg# 523 : sequencer
1315            msg# 524 : not ready
1316            msg# 525 : stopped
1317            msg# 526 : playing
1318            msg# 527 : recording
1319            msg# 528 : seeking
1320            msg# 529 : paused
1321            msg# 530 : open
1322            msg# 531 : false
1323            msg# 532 : true
1324            msg# 533 : milliseconds
1325            msg# 534 : hms
1326            msg# 535 : msf
1327            msg# 536 : frames
1328            msg# 537 : smpte 24
1329            msg# 538 : smpte 25
1330            msg# 539 : smpte 30
1331            msg# 540 : smpte 30 drop
1332            msg# 541 : bytes
1333            msg# 542 : samples
1334            msg# 543 : tmsf
1335         */
1336     default:
1337         TRACE(mmsys, "Unknown MCI Error %ld!\n", dwError);
1338         return FALSE;
1339     }
1340     lstrcpynA(lpstrBuffer, msgptr, uLength);
1341     TRACE(mmsys, "msg = \"%s\";\n", lpstrBuffer);
1342     return TRUE;
1343 }
1344
1345 /**************************************************************************
1346  *                              mciDriverNotify                 [MMSYSTEM.711]
1347  */
1348 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1349 {
1350     TRACE(mmsys, "(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1351
1352     if (!IsWindow(hWndCallBack)) {
1353         WARN(mmsys, "bad hWnd for call back (0x%04x)\n", hWndCallBack);
1354         return FALSE;
1355     }
1356     TRACE(mmsys, "before PostMessage\n");
1357     Callout.PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1358     return TRUE;
1359 }
1360
1361 /**************************************************************************
1362  *                      mciDriverNotify                         [WINMM.36]
1363  */
1364 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1365 {
1366     FIXME(mmsys, "(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1367
1368     if (!IsWindow(hWndCallBack)) {
1369         WARN(mmsys, "bad hWnd for call back (0x%04x)\n", hWndCallBack);
1370         return FALSE;
1371     }
1372     TRACE(mmsys, "before PostMessage\n");
1373     Callout.PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1374     return TRUE;
1375 }
1376
1377 /**************************************************************************
1378  *                      mciGetDriverData                        [MMSYSTEM.708]
1379  */
1380 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID) 
1381 {
1382     return mciGetDriverData(uDeviceID);
1383 }
1384
1385 /**************************************************************************
1386  *                      mciGetDriverData                        [WINMM.44]
1387  */
1388 DWORD WINAPI mciGetDriverData(UINT uDeviceID) 
1389 {
1390     TRACE(mmsys, "(%04x)\n", uDeviceID);
1391     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1392         WARN(mmsys, "Bad uDeviceID\n");
1393         return 0L;
1394     }
1395     
1396     return MCI_GetDrv(uDeviceID)->dwPrivate;
1397 }
1398
1399 /**************************************************************************
1400  *                      mciSetDriverData                        [MMSYSTEM.707]
1401  */
1402 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data) 
1403 {
1404     return mciSetDriverData(uDeviceID, data);
1405 }
1406
1407 /**************************************************************************
1408  *                      mciSetDriverData                        [WINMM.53]
1409  */
1410 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data) 
1411 {
1412     TRACE(mmsys, "(%04x, %08lx)\n", uDeviceID, data);
1413     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1414         WARN(mmsys, "Bad uDeviceID\n");
1415         return FALSE;
1416     }
1417     
1418     MCI_GetDrv(uDeviceID)->dwPrivate = data;
1419     return TRUE;
1420 }
1421
1422 /**************************************************************************
1423  *                      mciLoadCommandResource                  [MMSYSTEM.705]
1424  */
1425 UINT16 WINAPI mciLoadCommandResource16(HANDLE16 hinst, LPCSTR resname, UINT16 type)
1426 {
1427     char            buf[200];
1428     OFSTRUCT        ofs;
1429     HANDLE16        xhinst;
1430     HRSRC16         hrsrc;
1431     HGLOBAL16       hmem;
1432     LPSTR           segstr;
1433     SEGPTR          xmem;
1434     LPBYTE          lmem;
1435     static UINT16   mcidevtype = 0;
1436     
1437     FIXME(mmsys, "(%04x, %s, %d): stub!\n", hinst, resname, type);
1438     if (!lstrcmpiA(resname, "core")) {
1439         FIXME(mmsys, "(...,\"core\",...), have to use internal tables... (not there yet)\n");
1440         return 0;
1441     }
1442     return ++mcidevtype;
1443     /* if file exists "resname.mci", then load resource "resname" from it
1444      * otherwise directly from driver
1445      */
1446     strcpy(buf,resname);
1447     strcat(buf, ".mci");
1448     if (OpenFile(buf, &ofs,OF_EXIST) != HFILE_ERROR) {
1449         xhinst = LoadLibrary16(buf);
1450         if (xhinst > 32)
1451             hinst = xhinst;
1452     } /* else use passed hinst */
1453     segstr = SEGPTR_STRDUP(resname);
1454     hrsrc = FindResource16(hinst, SEGPTR_GET(segstr), type);
1455     SEGPTR_FREE(segstr);
1456     if (!hrsrc) {
1457         WARN(mmsys, "no special commandlist found in resource\n");
1458         return MCI_NO_COMMAND_TABLE;
1459     }
1460     hmem = LoadResource16(hinst, hrsrc);
1461     if (!hmem) {
1462         WARN(mmsys, "couldn't load resource??\n");
1463         return MCI_NO_COMMAND_TABLE;
1464     }
1465     xmem = WIN16_LockResource16(hmem);
1466     if (!xmem) {
1467         WARN(mmsys, "couldn't lock resource??\n");
1468         FreeResource16(hmem);
1469         return MCI_NO_COMMAND_TABLE;
1470     }
1471     lmem = PTR_SEG_TO_LIN(xmem);
1472     TRACE(mmsys, "first resource entry is %s\n", (char*)lmem);
1473     /* parse resource, register stuff, return unique id */
1474     return ++mcidevtype;
1475 }
1476
1477 /**************************************************************************
1478  *                      mciFreeCommandResource                  [MMSYSTEM.713]
1479  */
1480 BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable)
1481 {
1482     FIXME(mmsys, "(%04x) stub\n", uTable);
1483     return 0;
1484 }
1485  
1486 /**************************************************************************
1487  *                      mciFreeCommandResource                  [WINMM.39]
1488  */
1489 BOOL WINAPI mciFreeCommandResource(UINT uTable)
1490 {
1491     FIXME(mmsys, "(%08x) stub\n", uTable);
1492     return 0;
1493 }
1494
1495 /**************************************************************************
1496  *                      mciLoadCommandResource                  [WINMM.48]
1497  */
1498 UINT WINAPI mciLoadCommandResource(HANDLE hinst, LPCWSTR resname, UINT type)
1499 {
1500     FIXME(mmsys, "(%04x, %s, %d): stub!\n", hinst, debugstr_w(resname), type);
1501     return 0;
1502 }
1503
1504 /**************************************************************************
1505  *                              mciSendCommandA                 [WINMM.49]
1506  */
1507 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1508 {
1509     DWORD       dwRet;
1510
1511     TRACE(mmsys, "(%08x, %s, %08lx, %08lx)\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1512
1513     switch (wMsg) {
1514     case MCI_OPEN:
1515         dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1516         break;
1517     case MCI_CLOSE:
1518         dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1519         break;
1520     case MCI_SYSINFO:
1521         dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1522         break;
1523     default:
1524         if (wDevID == MCI_ALL_DEVICE_ID) {
1525             FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
1526             dwRet = MCIERR_CANNOT_USE_ALL;
1527         } else {
1528             dwRet = MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2);
1529         }
1530         break;
1531     }
1532     dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1533     TRACE(mmsys, "=> %08lx\n", dwRet);
1534     return dwRet;
1535 }
1536
1537 /**************************************************************************
1538  *                              mciSendCommandW                 [WINMM.50]
1539  */
1540 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1541 {
1542     FIXME(mmsys, "(%08x, %s, %08lx, %08lx): stub\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1543     return MCIERR_UNSUPPORTED_FUNCTION;
1544 }
1545
1546 /**************************************************************************
1547  *                              mciSendCommand                  [MMSYSTEM.701]
1548  */
1549 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1550 {
1551     DWORD       dwRet = MCIERR_UNRECOGNIZED_COMMAND;
1552
1553     TRACE(mmsys, "(%04X, %s, %08lX, %08lX)\n", 
1554           wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1555
1556     switch (wMsg) {
1557     case MCI_OPEN:
1558         switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1559         case MCI_MAP_OK:
1560         case MCI_MAP_OKMEM:
1561             dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1562             MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1563             break;
1564         default: break; /* so that gcc does bark */
1565         }
1566         break;
1567     case MCI_CLOSE:
1568         if (wDevID == MCI_ALL_DEVICE_ID) {
1569             FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
1570             dwRet = MCIERR_CANNOT_USE_ALL;
1571         } else if (!MCI_DevIDValid(wDevID)) {
1572             dwRet = MCIERR_INVALID_DEVICE_ID;
1573         } else {
1574             switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1575             case MCI_MAP_OK:
1576             case MCI_MAP_OKMEM:
1577                 dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1578                 MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1579                 break;
1580             default: break; /* so that gcc does bark */
1581             }
1582         }
1583         break;
1584     case MCI_SYSINFO:
1585         switch (MCI_MapMsg16To32A(0, wDevID, &dwParam2)) {
1586         case MCI_MAP_OK:
1587         case MCI_MAP_OKMEM:
1588             dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1589             MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
1590             break;
1591         default: break; /* so that gcc does bark */
1592         }
1593         break;
1594     /* FIXME: it seems that MCI_BREAK and MCI_SOUND need the same handling */
1595     default:
1596         if (wDevID == MCI_ALL_DEVICE_ID) {
1597             FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
1598             dwRet = MCIERR_CANNOT_USE_ALL;
1599         } else {
1600             dwRet = MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2);
1601         }
1602         break;
1603     }
1604     dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1605     TRACE(mmsys, "=> %ld\n", dwRet);
1606     return dwRet;
1607 }
1608     
1609 /**************************************************************************
1610  *                              mciGetDeviceID                  [MMSYSTEM.703]
1611  */
1612 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1613 {
1614     UINT16      wDevID;
1615     TRACE(mmsys, "(\"%s\")\n", lpstrName);
1616
1617     if (!lpstrName)
1618         return 0;
1619     
1620     if (!lstrcmpiA(lpstrName, "ALL"))
1621         return MCI_ALL_DEVICE_ID;
1622     
1623     for (wDevID = MCI_FirstDevID(); MCI_DevIDValid(wDevID); wDevID = MCI_NextDevID(wDevID)) {
1624         if (MCI_GetDrv(wDevID)->modp.wType) {
1625             FIXME(mmsys, "This is wrong for compound devices\n");
1626             /* FIXME: for compound devices, lpstrName is matched against 
1627              * the name of the file, not the name of the device... 
1628              */
1629             if (MCI_GetOpenDrv(wDevID)->lpstrDeviceType && 
1630                 strcmp(MCI_GetOpenDrv(wDevID)->lpstrDeviceType, lpstrName) == 0)
1631                 return wDevID;
1632     
1633             if (MCI_GetOpenDrv(wDevID)->lpstrAlias && 
1634                 strcmp(MCI_GetOpenDrv(wDevID)->lpstrAlias, lpstrName) == 0)
1635                 return wDevID;
1636         }
1637     }
1638     
1639     return 0;
1640 }
1641
1642 /**************************************************************************
1643  *                              mciGetDeviceIDA                 [WINMM.41]
1644  */
1645 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1646 {
1647     return mciGetDeviceID16(lpstrName);
1648 }
1649
1650 /**************************************************************************
1651  *                              mciGetDeviceIDW                 [WINMM.43]
1652  */
1653 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1654 {
1655     LPSTR       lpstrName;
1656     UINT        ret;
1657
1658     lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1659     ret = mciGetDeviceID16(lpstrName);
1660     HeapFree(GetProcessHeap(), 0, lpstrName);
1661     return ret;
1662 }
1663
1664 /**************************************************************************
1665  *                              MCI_DefYieldProc                [internal]
1666  */
1667 UINT16  WINAPI MCI_DefYieldProc(UINT16 wDevID, DWORD data)
1668 {
1669     INT16       ret;
1670     
1671     TRACE(mmsys, "(0x%04x, 0x%08lx)\n", wDevID, data);
1672
1673     if ((HIWORD(data) != 0 && GetActiveWindow16() != HIWORD(data)) ||
1674         (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1675         UserYield16();
1676         ret = 0;
1677     } else {
1678         MSG             msg;
1679
1680         msg.hwnd = HIWORD(data);
1681         while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1682         ret = 0xFFFF;
1683     }
1684     return ret;
1685 }
1686
1687 /**************************************************************************
1688  *                              mciSetYieldProc                 [MMSYSTEM.714]
1689  */
1690 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1691 {
1692     TRACE(mmsys, "(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1693
1694     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1695         WARN(mmsys, "Bad uDeviceID\n");
1696         return FALSE;
1697     }
1698     
1699     MCI_GetDrv(uDeviceID)->lpfnYieldProc = fpYieldProc;
1700     MCI_GetDrv(uDeviceID)->dwYieldData   = dwYieldData;
1701     MCI_GetDrv(uDeviceID)->bIs32         = FALSE;
1702
1703     return TRUE;
1704 }
1705
1706 /**************************************************************************
1707  *                              mciSetYieldProc                 [WINMM.54]
1708  */
1709 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1710 {
1711     TRACE(mmsys, "(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1712
1713     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1714         WARN(mmsys, "Bad uDeviceID\n");
1715         return FALSE;
1716     }
1717     
1718     MCI_GetDrv(uDeviceID)->lpfnYieldProc = fpYieldProc;
1719     MCI_GetDrv(uDeviceID)->dwYieldData   = dwYieldData;
1720     MCI_GetDrv(uDeviceID)->bIs32         = TRUE;
1721
1722     return TRUE;
1723 }
1724
1725 /**************************************************************************
1726  *                              mciGetDeviceIDFromElementID     [MMSYSTEM.715]
1727  */
1728 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1729 {
1730     FIXME(mmsys, "(%lu, %s) stub\n", dwElementID, lpstrType);
1731     return 0;
1732 }
1733         
1734 /**************************************************************************
1735  *                              mciGetDeviceIDFromElementIDW    [WINMM.42]
1736  */
1737 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1738 {
1739     /* FIXME: that's rather strange, there is no 
1740      * mciGetDeviceIDFromElementID32A in winmm.spec
1741      */
1742     FIXME(mmsys, "(%lu, %p) stub\n", dwElementID, lpstrType);
1743     return 0;
1744 }
1745         
1746 /**************************************************************************
1747  *                              mciGetYieldProc                 [MMSYSTEM.716]
1748  */
1749 YIELDPROC WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1750 {
1751     TRACE(mmsys, "(%u, %p)\n", uDeviceID, lpdwYieldData);
1752
1753     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1754         WARN(mmsys, "Bad uDeviceID\n");
1755         return NULL;
1756     }
1757     if (!MCI_GetDrv(uDeviceID)->lpfnYieldProc) {
1758         WARN(mmsys, "No proc set\n");
1759         return NULL;
1760     }
1761     if (MCI_GetDrv(uDeviceID)->bIs32) {
1762         WARN(mmsys, "Proc is 32 bit\n");
1763         return NULL;
1764     }
1765     return MCI_GetDrv(uDeviceID)->lpfnYieldProc;
1766 }
1767     
1768 /**************************************************************************
1769  *                              mciGetYieldProc                 [WINMM.47]
1770  */
1771 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1772 {
1773     TRACE(mmsys, "(%u, %p)\n", uDeviceID, lpdwYieldData);
1774
1775     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1776         WARN(mmsys, "Bad uDeviceID\n");
1777         return NULL;
1778     }
1779     if (!MCI_GetDrv(uDeviceID)->lpfnYieldProc) {
1780         WARN(mmsys, "No proc set\n");
1781         return NULL;
1782     }
1783     if (!MCI_GetDrv(uDeviceID)->bIs32) {
1784         WARN(mmsys, "Proc is 32 bit\n");
1785         return NULL;
1786     }
1787     return MCI_GetDrv(uDeviceID)->lpfnYieldProc;
1788 }
1789
1790 /**************************************************************************
1791  *                              mciGetCreatorTask               [MMSYSTEM.717]
1792  */
1793 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1794 {
1795     return mciGetCreatorTask(uDeviceID);
1796 }
1797
1798 /**************************************************************************
1799  *                              mciGetCreatorTask               [WINMM.40]
1800  */
1801 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1802 {
1803     HTASK       ret;
1804
1805     TRACE(mmsys, "(%u)\n", uDeviceID);
1806
1807     ret = (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) ?
1808         0 : MCI_GetDrv(uDeviceID)->hCreatorTask;
1809
1810     TRACE(mmsys, "=> %04x\n", ret);
1811     return ret;
1812 }
1813
1814 /**************************************************************************
1815  *                              mciDriverYield                  [MMSYSTEM.710]
1816  */
1817 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID) 
1818 {
1819     UINT16      ret = 0;
1820
1821     /*    TRACE(mmsys, "(%04x)\n", uDeviceID); */
1822
1823     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
1824         !MCI_GetDrv(uDeviceID)->lpfnYieldProc || MCI_GetDrv(uDeviceID)->bIs32) {
1825         UserYield16();
1826     } else {
1827         ret = MCI_GetDrv(uDeviceID)->lpfnYieldProc(uDeviceID, MCI_GetDrv(uDeviceID)->dwYieldData);
1828     }
1829
1830     return ret;
1831 }
1832
1833 /**************************************************************************
1834  *                      mciDriverYield                          [WINMM.37]
1835  */
1836 UINT WINAPI mciDriverYield(UINT uDeviceID) 
1837 {
1838     UINT        ret = 0;
1839
1840     TRACE(mmsys, "(%04x)\n", uDeviceID);
1841     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
1842         !MCI_GetDrv(uDeviceID)->lpfnYieldProc || !MCI_GetDrv(uDeviceID)->bIs32) {
1843         UserYield16();
1844     } else {
1845         ret = MCI_GetDrv(uDeviceID)->lpfnYieldProc(uDeviceID, MCI_GetDrv(uDeviceID)->dwYieldData);
1846     }
1847
1848     return ret;
1849 }
1850
1851 /**************************************************************************
1852  *                              midiOutGetNumDevs       [WINMM.80]
1853  */
1854 UINT WINAPI midiOutGetNumDevs(void)
1855 {
1856     return midiOutGetNumDevs16();
1857 }
1858
1859 /**************************************************************************
1860  *                              midiOutGetNumDevs       [MMSYSTEM.201]
1861  */
1862 UINT16 WINAPI midiOutGetNumDevs16(void)
1863 {
1864     UINT16      count = modMessage(0, MODM_GETNUMDEVS, 0L, 0L, 0L);
1865
1866     TRACE(mmsys, "returns %u\n", count);
1867     return count;
1868 }
1869
1870 /**************************************************************************
1871  *                              midiOutGetDevCapsW      [WINMM.76]
1872  */
1873 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps, UINT uSize)
1874 {
1875     MIDIOUTCAPS16       moc16;
1876     UINT                ret;
1877     
1878     ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
1879     lpCaps->wMid                = moc16.wMid;
1880     lpCaps->wPid                = moc16.wPid;
1881     lpCaps->vDriverVersion      = moc16.vDriverVersion;
1882     lstrcpyAtoW(lpCaps->szPname, moc16.szPname);
1883     lpCaps->wTechnology = moc16.wTechnology;
1884     lpCaps->wVoices             = moc16.wVoices;
1885     lpCaps->wNotes              = moc16.wNotes;
1886     lpCaps->wChannelMask        = moc16.wChannelMask;
1887     lpCaps->dwSupport   = moc16.dwSupport;
1888     return ret;
1889 }
1890
1891 /**************************************************************************
1892  *                              midiOutGetDevCapsA      [WINMM.75]
1893  */
1894 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps, UINT uSize)
1895 {
1896     MIDIOUTCAPS16       moc16;
1897     UINT                ret;
1898     
1899     ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
1900     lpCaps->wMid                = moc16.wMid;
1901     lpCaps->wPid                = moc16.wPid;
1902     lpCaps->vDriverVersion      = moc16.vDriverVersion;
1903     strcpy(lpCaps->szPname, moc16.szPname);
1904     lpCaps->wTechnology = moc16.wTechnology;
1905     lpCaps->wVoices             = moc16.wVoices;
1906     lpCaps->wNotes              = moc16.wNotes;
1907     lpCaps->wChannelMask        = moc16.wChannelMask;
1908     lpCaps->dwSupport   = moc16.dwSupport;
1909     return ret;
1910 }
1911
1912 /**************************************************************************
1913  *                              midiOutGetDevCaps       [MMSYSTEM.202]
1914  */
1915 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps, UINT16 uSize)
1916 {
1917     TRACE(mmsys, "midiOutGetDevCaps\n");
1918     return modMessage(uDeviceID, MODM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
1919 }
1920
1921 /**************************************************************************
1922  *                              midiOutGetErrorTextA    [WINMM.77]
1923  */
1924 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1925 {
1926     TRACE(mmsys, "midiOutGetErrorText\n");
1927     return midiGetErrorText(uError, lpText, uSize);
1928 }
1929
1930 /**************************************************************************
1931  *                              midiOutGetErrorTextW    [WINMM.78]
1932  */
1933 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1934 {
1935     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1936     UINT        ret;
1937     
1938     TRACE(mmsys, "midiOutGetErrorText\n");
1939     ret = midiGetErrorText(uError, xstr, uSize);
1940     lstrcpyAtoW(lpText, xstr);
1941     HeapFree(GetProcessHeap(), 0, xstr);
1942     return ret;
1943 }
1944
1945 /**************************************************************************
1946  *                              midiOutGetErrorText     [MMSYSTEM.203]
1947  */
1948 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
1949 {
1950     TRACE(mmsys, "midiOutGetErrorText\n");
1951     return midiGetErrorText(uError, lpText, uSize);
1952 }
1953
1954 /**************************************************************************
1955  *                              midiGetErrorText        [internal]
1956  */
1957 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1958 {
1959     LPSTR       msgptr;
1960     if ((lpText == NULL) || (uSize < 1)) return(FALSE);
1961     lpText[0] = '\0';
1962     switch (uError) {
1963     case MIDIERR_UNPREPARED:
1964         msgptr = "The MIDI header was not prepared. Use the Prepare function to prepare the header, and then try again.";
1965         break;
1966     case MIDIERR_STILLPLAYING:
1967         msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
1968         break;
1969     case MIDIERR_NOMAP:
1970         msgptr = "A MIDI map was not found. There may be a problem with the driver, or the MIDIMAP.CFG file may be corrupt or missing.";
1971         break;
1972     case MIDIERR_NOTREADY:
1973         msgptr = "The port is transmitting data to the device. Wait until the data has been transmitted, and then try again.";
1974         break;
1975     case MIDIERR_NODEVICE:
1976         msgptr = "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup.";
1977         break;
1978     case MIDIERR_INVALIDSETUP:
1979         msgptr = "The current MIDI setup is damaged. Copy the original MIDIMAP.CFG file to the Windows SYSTEM directory, and then try again.";
1980         break;
1981         /*
1982           msg# 336 : Cannot use the song-pointer time format and the SMPTE time-format together.
1983           msg# 337 : The specified MIDI device is already in use. Wait until it is free, and then try again.
1984           msg# 338 : The specified MIDI device is not installed on the system. Use the Drivers option in Control Panel to install the driver.
1985           msg# 339 : The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup.
1986           msg# 340 : An error occurred using the specified port.
1987           msg# 341 : All multimedia timers are being used by other applications. Quit one of these applications, and then try again.
1988           msg# 342 : There is no current MIDI port.
1989           msg# 343 : There are no MIDI devices installed on the system. Use the Drivers option in Control Panel to install the driver.
1990         */
1991     default:
1992         msgptr = "Unknown MIDI Error !\n";
1993         break;
1994     }
1995     lstrcpynA(lpText, msgptr, uSize);
1996     return TRUE;
1997 }
1998
1999 static  LPMIDIOPENDESC  MIDI_OutAlloc(HMIDIOUT16* lphMidiOut, DWORD dwCallback, 
2000                                       DWORD dwInstance, DWORD cIDs, MIDIOPENSTRMID* lpIDs)
2001 {
2002     HMIDI16                     hMidiOut;
2003     LPMIDIOPENDESC              lpDesc;
2004
2005     hMidiOut = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC) + (cIDs ? (cIDs - 1) : 0) * sizeof(MIDIOPENSTRMID));
2006
2007     if (lphMidiOut != NULL) 
2008         *lphMidiOut = hMidiOut;
2009     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2010
2011     if (lpDesc) {
2012         lpDesc->hMidi = hMidiOut;
2013         lpDesc->dwCallback = dwCallback;
2014         lpDesc->dwInstance = dwInstance;
2015         lpDesc->dnDevNode = 0;
2016         lpDesc->cIds = cIDs;
2017         if (cIDs)
2018             memcpy(&(lpDesc->rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2019     }
2020     return lpDesc;
2021 }
2022
2023 /**************************************************************************
2024  *                              midiOutOpen             [WINM.84]
2025  */
2026 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2027                         DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2028 {
2029     HMIDIOUT16  hmo16;
2030     UINT        ret;
2031     
2032     ret = midiOutOpen16(&hmo16, uDeviceID, dwCallback, dwInstance,
2033                         CALLBACK32CONV(dwFlags));
2034     if (lphMidiOut) *lphMidiOut = hmo16;
2035     return ret;
2036 }
2037
2038 /**************************************************************************
2039  *                              midiOutOpen             [MMSYSTEM.204]
2040  */
2041 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2042                             DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2043 {
2044     HMIDIOUT16                  hMidiOut;
2045     LPMIDIOPENDESC              lpDesc;
2046     UINT16                      ret = 0;
2047     BOOL                        bMapperFlg = FALSE;
2048     
2049     TRACE(mmsys, "(%p, %d, %08lX, %08lX, %08lX);\n", 
2050           lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2051
2052     if (lphMidiOut != NULL) *lphMidiOut = 0;
2053
2054     if (uDeviceID == (UINT16)MIDI_MAPPER) {
2055         TRACE(mmsys, "MIDI_MAPPER mode requested !\n");
2056         bMapperFlg = TRUE;
2057         uDeviceID = 0;
2058     }
2059
2060     lpDesc = MIDI_OutAlloc(&hMidiOut, dwCallback, dwInstance, 0, NULL);
2061
2062     if (lpDesc == NULL)
2063         return MMSYSERR_NOMEM;
2064     
2065     while (uDeviceID < MAXMIDIDRIVERS) {
2066         ret = modMessage(uDeviceID, MODM_OPEN, 
2067                          lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2068         if (ret == MMSYSERR_NOERROR) break;
2069         if (!bMapperFlg) break;
2070         uDeviceID++;
2071         TRACE(mmsys, "MIDI_MAPPER mode ! try next driver...\n");
2072     }
2073     TRACE(mmsys, "=> wDevID=%u (%d)\n", uDeviceID, ret);
2074     if (ret != MMSYSERR_NOERROR) {
2075         USER_HEAP_FREE(hMidiOut);
2076         if (lphMidiOut) *lphMidiOut = 0;
2077     } else {
2078         lpDesc->wDevID = uDeviceID;
2079         if (lphMidiOut) *lphMidiOut = hMidiOut;
2080     }
2081
2082     return ret;
2083 }
2084
2085 /**************************************************************************
2086  *                              midiOutClose            [WINMM.74]
2087  */
2088 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2089 {
2090     return midiOutClose16(hMidiOut);
2091 }
2092
2093 /**************************************************************************
2094  *                              midiOutClose            [MMSYSTEM.205]
2095  */
2096 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2097 {
2098     LPMIDIOPENDESC      lpDesc;
2099     DWORD               dwRet;
2100
2101     TRACE(mmsys, "(%04X)\n", hMidiOut);
2102
2103     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2104
2105     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2106     dwRet = modMessage(lpDesc->wDevID, MODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2107     USER_HEAP_FREE(hMidiOut);
2108     return dwRet;
2109 }
2110
2111 /**************************************************************************
2112  *                              midiOutPrepareHeader    [WINMM.85]
2113  */
2114 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2115                                  MIDIHDR* lpMidiOutHdr, UINT uSize)
2116 {
2117     LPMIDIOPENDESC      lpDesc;
2118
2119     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2120
2121     lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiOut);
2122     if (lpDesc == NULL) 
2123         return MMSYSERR_INVALHANDLE;
2124     lpMidiOutHdr->reserved = (DWORD)lpMidiOutHdr;
2125     return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance, 
2126                       (DWORD)lpMidiOutHdr, (DWORD)uSize);
2127 }
2128
2129 /**************************************************************************
2130  *                              midiOutPrepareHeader    [MMSYSTEM.206]
2131  */
2132 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut,
2133                                      LPMIDIHDR16 /*SEGPTR*/ _lpMidiOutHdr, UINT16 uSize)
2134 {
2135     LPMIDIOPENDESC      lpDesc;
2136     LPMIDIHDR16         lpMidiOutHdr = (LPMIDIHDR16)PTR_SEG_TO_LIN(_lpMidiOutHdr);
2137
2138     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2139
2140     lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiOut);
2141     if (lpDesc == NULL) 
2142         return MMSYSERR_INVALHANDLE;
2143     lpMidiOutHdr->reserved = (DWORD)_lpMidiOutHdr;
2144     return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance, 
2145                       (DWORD)lpMidiOutHdr, (DWORD)uSize);
2146 }
2147
2148 /**************************************************************************
2149  *                              midiOutUnprepareHeader  [WINMM.89]
2150  */
2151 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2152                                    MIDIHDR* lpMidiOutHdr, UINT uSize)
2153 {
2154     return midiOutUnprepareHeader16(hMidiOut, (MIDIHDR16*)lpMidiOutHdr, uSize);
2155 }
2156
2157 /**************************************************************************
2158  *                              midiOutUnprepareHeader  [MMSYSTEM.207]
2159  */
2160 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut,
2161                                        MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2162 {
2163     LPMIDIOPENDESC      lpDesc;
2164
2165     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2166
2167     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2168     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2169     return modMessage(lpDesc->wDevID, MODM_UNPREPARE, lpDesc->dwInstance, 
2170                       (DWORD)lpMidiOutHdr, (DWORD)uSize);
2171 }
2172
2173 /**************************************************************************
2174  *                              midiOutShortMsg         [WINMM.88]
2175  */
2176 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2177 {
2178     return midiOutShortMsg16(hMidiOut, dwMsg);
2179 }
2180
2181 /**************************************************************************
2182  *                              midiOutShortMsg         [MMSYSTEM.208]
2183  */
2184 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2185 {
2186     LPMIDIOPENDESC      lpDesc;
2187
2188     TRACE(mmsys, "(%04X, %08lX)\n", hMidiOut, dwMsg);
2189
2190     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2191     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2192     return modMessage(lpDesc->wDevID, MODM_DATA, lpDesc->dwInstance, dwMsg, 0L);
2193 }
2194
2195 /**************************************************************************
2196  *                              midiOutLongMsg          [WINMM.82]
2197  */
2198 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2199                            MIDIHDR* lpMidiOutHdr, UINT uSize)
2200 {
2201     return midiOutLongMsg16(hMidiOut, (MIDIHDR16*)lpMidiOutHdr, uSize);
2202 }
2203
2204 /**************************************************************************
2205  *                              midiOutLongMsg          [MMSYSTEM.209]
2206  */
2207 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut,
2208                                MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2209 {
2210     LPMIDIOPENDESC      lpDesc;
2211
2212     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2213
2214     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2215     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2216     return modMessage(lpDesc->wDevID, MODM_LONGDATA, lpDesc->dwInstance, 
2217                       (DWORD)lpMidiOutHdr, (DWORD)uSize);
2218 }
2219
2220 /**************************************************************************
2221  *                              midiOutReset            [WINMM.86]
2222  */
2223 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2224 {
2225     return midiOutReset16(hMidiOut);
2226 }
2227
2228 /**************************************************************************
2229  *                              midiOutReset            [MMSYSTEM.210]
2230  */
2231 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2232 {
2233     LPMIDIOPENDESC      lpDesc;
2234
2235     TRACE(mmsys, "(%04X)\n", hMidiOut);
2236
2237     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2238     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2239     return modMessage(lpDesc->wDevID, MODM_RESET, lpDesc->dwInstance, 0L, 0L);
2240 }
2241
2242 /**************************************************************************
2243  *                              midiOutGetVolume        [WINM.81]
2244  */
2245 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2246 {
2247     return midiOutGetVolume16(uDeviceID, lpdwVolume);
2248 }
2249
2250 /**************************************************************************
2251  *                              midiOutGetVolume        [MMSYSTEM.211]
2252  */
2253 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2254 {
2255     TRACE(mmsys, "(%04X, %p);\n", uDeviceID, lpdwVolume);
2256     return modMessage(uDeviceID, MODM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
2257 }
2258
2259 /**************************************************************************
2260  *                              midiOutSetVolume        [WINMM.87]
2261  */
2262 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2263 {
2264     return midiOutSetVolume16(uDeviceID, dwVolume);
2265 }
2266
2267 /**************************************************************************
2268  *                              midiOutSetVolume        [MMSYSTEM.212]
2269  */
2270 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2271 {
2272     TRACE(mmsys, "(%04X, %08lX);\n", uDeviceID, dwVolume);
2273     return modMessage(uDeviceID, MODM_SETVOLUME, 0L, dwVolume, 0L);
2274 }
2275
2276 /**************************************************************************
2277  *                              midiOutCachePatches             [WINMM.73]
2278  */
2279 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2280                                 WORD* lpwPatchArray, UINT uFlags)
2281 {
2282     return midiOutCachePatches16(hMidiOut, uBank, lpwPatchArray, uFlags);
2283 }
2284
2285 /**************************************************************************
2286  *                              midiOutCachePatches             [MMSYSTEM.213]
2287  */
2288 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2289                                     WORD* lpwPatchArray, UINT16 uFlags)
2290 {
2291     /* not really necessary to support this */
2292     FIXME(mmsys, "not supported yet\n");
2293     return MMSYSERR_NOTSUPPORTED;
2294 }
2295
2296 /**************************************************************************
2297  *                              midiOutCacheDrumPatches [WINMM.72]
2298  */
2299 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2300                                     WORD* lpwKeyArray, UINT uFlags)
2301 {
2302     return midiOutCacheDrumPatches16(hMidiOut, uPatch, lpwKeyArray, uFlags);
2303 }
2304
2305 /**************************************************************************
2306  *                              midiOutCacheDrumPatches [MMSYSTEM.214]
2307  */
2308 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2309                                         WORD* lpwKeyArray, UINT16 uFlags)
2310 {
2311     FIXME(mmsys, "not supported yet\n");
2312     return MMSYSERR_NOTSUPPORTED;
2313 }
2314
2315 /**************************************************************************
2316  *                              midiOutGetID            [WINMM.79]
2317  */
2318 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2319 {
2320     UINT16      xid;
2321     UINT        ret;
2322     
2323     ret = midiOutGetID16(hMidiOut, &xid);
2324     *lpuDeviceID = xid;
2325     return ret;
2326 }
2327
2328 /**************************************************************************
2329  *                              midiOutGetID            [MMSYSTEM.215]
2330  */
2331 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2332 {
2333     TRACE(mmsys, "midiOutGetID\n");
2334     return 0;
2335 }
2336
2337 /**************************************************************************
2338  *                              midiOutMessage          [WINMM.83]
2339  */
2340 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, 
2341                             DWORD dwParam1, DWORD dwParam2)
2342 {
2343     LPMIDIOPENDESC      lpDesc;
2344
2345     /* Shouldn't we anyway use the functions midiOutXXX ?
2346      * M$ doc says: This function is used only for driver-specific 
2347      * messages that are not supported by the MIDI API. 
2348      * Clearly not what we are currently doing
2349      */
2350
2351     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
2352           hMidiOut, uMessage, dwParam1, dwParam2);
2353
2354     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2355     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2356     switch (uMessage) {
2357     case MODM_OPEN:
2358         FIXME(mmsys, "can't handle MODM_OPEN!\n");
2359         return 0;
2360     case MODM_GETDEVCAPS:
2361         return midiOutGetDevCapsA(hMidiOut, (LPMIDIOUTCAPSA)dwParam1, dwParam2);
2362     case MODM_GETNUMDEVS:
2363     case MODM_RESET:
2364     case MODM_CLOSE:
2365     case MODM_GETVOLUME:
2366     case MODM_SETVOLUME:
2367     case MODM_LONGDATA:
2368     case MODM_PREPARE:
2369     case MODM_UNPREPARE:
2370         /* no argument conversion needed */
2371         break;
2372     default:
2373         ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
2374             hMidiOut, uMessage, dwParam1, dwParam2);
2375         break;
2376     }
2377     return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2378 }
2379
2380 /**************************************************************************
2381  *                              midiOutMessage          [MMSYSTEM.216]
2382  */
2383 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage, 
2384                               DWORD dwParam1, DWORD dwParam2)
2385 {
2386     LPMIDIOPENDESC      lpDesc;
2387     
2388     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
2389           hMidiOut, uMessage, dwParam1, dwParam2);
2390     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2391     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2392     switch (uMessage) {
2393     case MODM_OPEN:
2394         FIXME(mmsys, "can't handle MODM_OPEN!\n");
2395         return 0;
2396     case MODM_GETNUMDEVS:
2397     case MODM_RESET:
2398     case MODM_CLOSE:
2399     case MODM_SETVOLUME:
2400         /* no argument conversion needed */
2401         break;
2402     case MODM_GETVOLUME:
2403         return midiOutGetVolume16(hMidiOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
2404     case MODM_LONGDATA:
2405         return midiOutLongMsg16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2406     case MODM_PREPARE:
2407         /* lpMidiOutHdr is still a segmented pointer for this function */
2408         return midiOutPrepareHeader16(hMidiOut, (LPMIDIHDR16)dwParam1, dwParam2);
2409     case MODM_UNPREPARE:
2410         return midiOutUnprepareHeader16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2411     default:
2412         ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
2413             hMidiOut, uMessage, dwParam1, dwParam2);
2414         break;
2415     }
2416     return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2417 }
2418
2419 /**************************************************************************
2420  *                              midiInGetNumDevs        [WINMM.64]
2421  */
2422 UINT WINAPI midiInGetNumDevs(void)
2423 {
2424     return midiInGetNumDevs16();
2425 }
2426
2427 /**************************************************************************
2428  *                              midiInGetNumDevs        [MMSYSTEM.301]
2429  */
2430 UINT16 WINAPI midiInGetNumDevs16(void)
2431 {
2432     UINT16      count = 0;
2433     TRACE(mmsys, "midiInGetNumDevs\n");
2434     count += midMessage(0, MIDM_GETNUMDEVS, 0L, 0L, 0L);
2435     TRACE(mmsys, "midiInGetNumDevs return %u \n", count);
2436     return count;
2437 }
2438
2439 /**************************************************************************
2440  *                              midiInGetDevCaps        [WINMM.60]
2441  */
2442 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2443 {
2444     MIDIINCAPS16        mic16;
2445     UINT                ret = midiInGetDevCaps16(uDeviceID, &mic16, uSize);
2446     
2447     lpCaps->wMid = mic16.wMid;
2448     lpCaps->wPid = mic16.wPid;
2449     lpCaps->vDriverVersion = mic16.vDriverVersion;
2450     lstrcpyAtoW(lpCaps->szPname, mic16.szPname);
2451     lpCaps->dwSupport = mic16.dwSupport;
2452     return ret;
2453 }
2454
2455 /**************************************************************************
2456  *                              midiInGetDevCaps        [WINMM.59]
2457  */
2458 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2459 {
2460     MIDIINCAPS16        mic16;
2461     UINT                ret = midiInGetDevCaps16(uDeviceID, &mic16, uSize);
2462     
2463     lpCaps->wMid = mic16.wMid;
2464     lpCaps->wPid = mic16.wPid;
2465     lpCaps->vDriverVersion = mic16.vDriverVersion;
2466     strcpy(lpCaps->szPname, mic16.szPname);
2467     lpCaps->dwSupport = mic16.dwSupport;
2468     return ret;
2469 }
2470
2471 /**************************************************************************
2472  *                              midiInGetDevCaps        [MMSYSTEM.302]
2473  */
2474 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID,
2475                                  LPMIDIINCAPS16 lpCaps, UINT16 uSize)
2476 {
2477     TRACE(mmsys, "midiInGetDevCaps\n");
2478     return midMessage(uDeviceID, MIDM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
2479 }
2480
2481 /**************************************************************************
2482  *                              midiInGetErrorText              [WINMM.62]
2483  */
2484 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2485 {
2486     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2487     UINT        ret = midiInGetErrorText16(uError, xstr, uSize);
2488     lstrcpyAtoW(lpText, xstr);
2489     HeapFree(GetProcessHeap(), 0, xstr);
2490     return ret;
2491 }
2492
2493 /**************************************************************************
2494  *                              midiInGetErrorText              [WINMM.61]
2495  */
2496 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2497 {
2498     return midiInGetErrorText16(uError, lpText, uSize);
2499 }
2500
2501 /**************************************************************************
2502  *                              midiInGetErrorText              [MMSYSTEM.303]
2503  */
2504 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2505 {
2506     TRACE(mmsys, "midiInGetErrorText\n");
2507     return (midiGetErrorText(uError, lpText, uSize));
2508 }
2509
2510 /**************************************************************************
2511  *                              midiInOpen              [WINMM.66]
2512  */
2513 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2514                        DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2515 {
2516     HMIDIIN16   xhmid16;
2517     UINT                ret = midiInOpen16(&xhmid16, uDeviceID, dwCallback, dwInstance,
2518                                            CALLBACK32CONV(dwFlags));
2519     if (lphMidiIn) 
2520         *lphMidiIn = xhmid16;
2521     return ret;
2522 }
2523
2524 /**************************************************************************
2525  *                              midiInOpen              [MMSYSTEM.304]
2526  */
2527 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2528                            DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2529 {
2530     HMIDI16                     hMidiIn;
2531     LPMIDIOPENDESC              lpDesc;
2532     DWORD                       dwRet = 0;
2533     BOOL                        bMapperFlg = FALSE;
2534     
2535     if (lphMidiIn != NULL) 
2536         *lphMidiIn = 0;
2537     TRACE(mmsys, "(%p, %d, %08lX, %08lX, %08lX);\n", 
2538           lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2539     if (uDeviceID == (UINT16)MIDI_MAPPER) {
2540         TRACE(mmsys, "MIDI_MAPPER mode requested !\n");
2541         bMapperFlg = TRUE;
2542         uDeviceID = 0;
2543     }
2544     hMidiIn = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC));
2545     if (lphMidiIn != NULL) 
2546         *lphMidiIn = hMidiIn;
2547     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2548     if (lpDesc == NULL) 
2549         return MMSYSERR_NOMEM;
2550     lpDesc->hMidi = hMidiIn;
2551     lpDesc->dwCallback = dwCallback;
2552     lpDesc->dwInstance = dwInstance;
2553     
2554     while (uDeviceID < MAXMIDIDRIVERS) {
2555         dwRet = midMessage(uDeviceID, MIDM_OPEN, 
2556                            lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2557         if (dwRet == MMSYSERR_NOERROR) 
2558             break;
2559         if (!bMapperFlg) 
2560             break;
2561         uDeviceID++;
2562         TRACE(mmsys, "MIDI_MAPPER mode ! try next driver...\n");
2563     }
2564     lpDesc->wDevID = uDeviceID;
2565     
2566     if (dwRet != MMSYSERR_NOERROR) {
2567         USER_HEAP_FREE(hMidiIn);
2568         if (lphMidiIn) *lphMidiIn = 0;
2569     }
2570
2571     return dwRet;
2572 }
2573
2574 /**************************************************************************
2575  *                              midiInClose             [WINMM.58]
2576  */
2577 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2578 {
2579     return midiInClose16(hMidiIn);
2580 }
2581
2582 /**************************************************************************
2583  *                              midiInClose             [MMSYSTEM.305]
2584  */
2585 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2586 {
2587     LPMIDIOPENDESC      lpDesc;
2588     DWORD               dwRet;    
2589
2590     TRACE(mmsys, "(%04X)\n", hMidiIn);
2591     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2592
2593     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2594     dwRet = midMessage(lpDesc->wDevID, MIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2595     USER_HEAP_FREE(hMidiIn);
2596     return dwRet;
2597 }
2598
2599 /**************************************************************************
2600  *                              midiInPrepareHeader     [WINMM.67]
2601  */
2602 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn, 
2603                                 MIDIHDR* lpMidiInHdr, UINT uSize)
2604 {
2605     LPMIDIOPENDESC      lpDesc;
2606     
2607     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2608
2609     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2610     if (lpDesc == NULL) 
2611         return MMSYSERR_INVALHANDLE;
2612     lpMidiInHdr->reserved = (DWORD)lpMidiInHdr;
2613     return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance, 
2614                       (DWORD)lpMidiInHdr, (DWORD)uSize);
2615 }
2616
2617 /**************************************************************************
2618  *                              midiInPrepareHeader     [MMSYSTEM.306]
2619  */
2620 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn,
2621                                     MIDIHDR16* /*SEGPTR*/ _lpMidiInHdr, UINT16 uSize)
2622 {
2623     LPMIDIOPENDESC      lpDesc;
2624     LPMIDIHDR16         lpMidiInHdr = (LPMIDIHDR16)PTR_SEG_TO_LIN(_lpMidiInHdr);
2625
2626     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2627
2628     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2629     if (lpDesc == NULL) 
2630         return MMSYSERR_INVALHANDLE;
2631     lpMidiInHdr->reserved = (DWORD)_lpMidiInHdr;
2632     return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance, 
2633                       (DWORD)lpMidiInHdr, (DWORD)uSize);
2634 }
2635
2636 /**************************************************************************
2637  *                              midiInUnprepareHeader   [WINMM.71]
2638  */
2639 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2640                                   MIDIHDR* lpMidiInHdr, UINT uSize)
2641 {
2642     return midiInUnprepareHeader16(hMidiIn, (MIDIHDR16*)lpMidiInHdr, uSize);
2643 }
2644
2645 /**************************************************************************
2646  *                              midiInUnprepareHeader   [MMSYSTEM.307]
2647  */
2648 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn,
2649                                       MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2650 {
2651     LPMIDIOPENDESC      lpDesc;
2652
2653     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2654
2655     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2656     if (lpDesc == NULL) 
2657         return MMSYSERR_INVALHANDLE;
2658     return midMessage(lpDesc->wDevID, MIDM_UNPREPARE, lpDesc->dwInstance, 
2659                       (DWORD)lpMidiInHdr, (DWORD)uSize);
2660 }
2661
2662 /**************************************************************************
2663  *                              midiInAddBuffer         [WINMM.57]
2664  */
2665 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2666                             MIDIHDR* lpMidiInHdr, UINT uSize)
2667 {
2668     return midiInAddBuffer16(hMidiIn, (MIDIHDR16*)lpMidiInHdr, uSize);
2669 }
2670
2671 /**************************************************************************
2672  *                              midiInAddBuffer         [MMSYSTEM.308]
2673  */
2674 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn,
2675                                 MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2676 {
2677     TRACE(mmsys, "midiInAddBuffer\n");
2678     return 0;
2679 }
2680
2681 /**************************************************************************
2682  *                              midiInStart                     [WINMM.69]
2683  */
2684 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2685 {
2686     return midiInStart16(hMidiIn);
2687 }
2688
2689 /**************************************************************************
2690  *                              midiInStart                     [MMSYSTEM.309]
2691  */
2692 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2693 {
2694     LPMIDIOPENDESC      lpDesc;
2695     
2696     TRACE(mmsys, "(%04X)\n", hMidiIn);
2697     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2698     if (lpDesc == NULL) 
2699         return MMSYSERR_INVALHANDLE;
2700     return midMessage(lpDesc->wDevID, MIDM_START, lpDesc->dwInstance, 0L, 0L);
2701 }
2702
2703 /**************************************************************************
2704  *                              midiInStop                      [WINMM.70]
2705  */
2706 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2707 {
2708     return midiInStop16(hMidiIn);
2709 }
2710
2711 /**************************************************************************
2712  *                              midiInStop                      [MMSYSTEM.310]
2713  */
2714 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2715 {
2716     LPMIDIOPENDESC      lpDesc;
2717     
2718     TRACE(mmsys, "(%04X)\n", hMidiIn);
2719     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2720     if (lpDesc == NULL) 
2721         return MMSYSERR_INVALHANDLE;
2722     return midMessage(lpDesc->wDevID, MIDM_STOP, lpDesc->dwInstance, 0L, 0L);
2723 }
2724
2725 /**************************************************************************
2726  *                              midiInReset                     [WINMM.68]
2727  */
2728 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2729 {
2730     return midiInReset16(hMidiIn);
2731 }
2732
2733 /**************************************************************************
2734  *                              midiInReset                     [MMSYSTEM.311]
2735  */
2736 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2737 {
2738     LPMIDIOPENDESC      lpDesc;
2739     
2740     TRACE(mmsys, "(%04X)\n", hMidiIn);
2741     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2742     if (lpDesc == NULL) 
2743         return MMSYSERR_INVALHANDLE;
2744     return midMessage(lpDesc->wDevID, MIDM_RESET, lpDesc->dwInstance, 0L, 0L);
2745 }
2746
2747 /**************************************************************************
2748  *                              midiInGetID                     [WINMM.63]
2749  */
2750 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2751 {
2752     LPMIDIOPENDESC      lpDesc;
2753     
2754     TRACE(mmsys, "(%04X, %p)\n", hMidiIn, lpuDeviceID);
2755     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2756     if (lpDesc == NULL) 
2757         return MMSYSERR_INVALHANDLE;
2758     if (lpuDeviceID == NULL) 
2759         return MMSYSERR_INVALPARAM;
2760     *lpuDeviceID = lpDesc->wDevID;
2761     
2762     return MMSYSERR_NOERROR;
2763 }
2764
2765 /**************************************************************************
2766  *                              midiInGetID                     [MMSYSTEM.312]
2767  */
2768 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
2769 {
2770     LPMIDIOPENDESC      lpDesc;
2771     
2772     TRACE(mmsys, "(%04X, %p)\n", hMidiIn, lpuDeviceID);
2773     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2774     if (lpDesc == NULL) 
2775         return MMSYSERR_INVALHANDLE;
2776     if (lpuDeviceID == NULL) 
2777         return MMSYSERR_INVALPARAM;
2778     *lpuDeviceID = lpDesc->wDevID;
2779     
2780     return MMSYSERR_NOERROR;
2781 }
2782
2783 /**************************************************************************
2784  *                              midiInMessage           [WINMM.65]
2785  */
2786 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, 
2787                            DWORD dwParam1, DWORD dwParam2)
2788 {
2789     LPMIDIOPENDESC      lpDesc;
2790     
2791     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
2792           hMidiIn, uMessage, dwParam1, dwParam2);
2793     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2794     if (lpDesc == NULL) 
2795         return MMSYSERR_INVALHANDLE;
2796     
2797     switch (uMessage) {
2798     case MIDM_OPEN:
2799         FIXME(mmsys, "can't handle MIDM_OPEN!\n");
2800         return 0;
2801     case MIDM_GETDEVCAPS:
2802         return midiInGetDevCapsA(hMidiIn, (LPMIDIINCAPSA)dwParam1, dwParam2);
2803     case MIDM_GETNUMDEVS:
2804     case MIDM_RESET:
2805     case MIDM_STOP:
2806     case MIDM_START:
2807     case MIDM_CLOSE:
2808         /* no argument conversion needed */
2809         break;
2810     case MIDM_PREPARE:
2811         return midiInPrepareHeader(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
2812     case MIDM_UNPREPARE:
2813         return midiInUnprepareHeader(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
2814     case MIDM_ADDBUFFER:
2815         return midiInAddBuffer(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
2816     default:
2817         ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
2818             hMidiIn, uMessage, dwParam1, dwParam2);
2819         break;
2820     }
2821     return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2822 }
2823
2824 /**************************************************************************
2825  *                              midiInMessage           [MMSYSTEM.313]
2826  */
2827 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage, 
2828                              DWORD dwParam1, DWORD dwParam2)
2829 {
2830     LPMIDIOPENDESC      lpDesc;
2831
2832     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
2833
2834     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2835     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2836     switch (uMessage) {
2837     case MIDM_OPEN:
2838         WARN(mmsys, "can't handle MIDM_OPEN!\n");
2839         return 0;
2840     case MIDM_GETDEVCAPS:
2841         return midiInGetDevCaps16(hMidiIn, (LPMIDIINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2842     case MIDM_GETNUMDEVS:
2843     case MIDM_RESET:
2844     case MIDM_STOP:
2845     case MIDM_START:
2846     case MIDM_CLOSE:
2847         /* no argument conversion needed */
2848         break;
2849     case MIDM_PREPARE:
2850         return midiInPrepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2851     case MIDM_UNPREPARE:
2852         return midiInUnprepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2853     case MIDM_ADDBUFFER:
2854         return midiInAddBuffer16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2855     default:
2856         ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
2857             hMidiIn, uMessage, dwParam1, dwParam2);
2858         break;
2859     }
2860     return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2861 }
2862
2863 typedef struct WINE_MIDIStream{
2864     HMIDIOUT                    hDevice;
2865     HANDLE                      hThread;
2866     DWORD                       dwThreadID;
2867     DWORD                       dwTempo;
2868     DWORD                       dwTimeDiv;
2869     DWORD                       dwPositionMS;
2870     DWORD                       dwPulses;
2871     DWORD                       dwStartTicks;
2872     WORD                        wFlags;
2873     BOOL                        bFlag;
2874 } WINE_MIDIStream;
2875
2876 /**************************************************************************
2877  *                              MMSYSTEM_GetMidiStream          [internal]
2878  */
2879 static  BOOL    MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, MIDIOPENDESC** lplpDesc)
2880 {
2881     MIDIOPENDESC* lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiStrm);
2882
2883     if (lplpDesc)
2884         *lplpDesc = lpDesc;
2885
2886     if (lpDesc == NULL) {
2887         return FALSE;
2888     }
2889
2890     *lpMidiStrm = (WINE_MIDIStream*)lpDesc->rgIds.dwStreamID;
2891
2892     return *lpMidiStrm != NULL;
2893 }
2894
2895 /**************************************************************************
2896  *                              MMSYSTEM_MidiStreamConvert      [internal]
2897  */
2898 static  DWORD   MMSYSTEM_MidiStreamConvert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
2899 {
2900     DWORD       ret = 0;
2901     
2902     if (lpMidiStrm->dwTimeDiv == 0) {
2903         FIXME(mmsys, "Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
2904     } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
2905         int     nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv);      /* number of frames     */
2906         int     nsf = LOBYTE(lpMidiStrm->dwTimeDiv);            /* number of sub-frames */
2907         ret = (pulse * 1000) / (nf * nsf);
2908     } else {
2909         ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /    
2910                       (double)lpMidiStrm->dwTimeDiv);
2911     }
2912     
2913     return ret;
2914 }
2915
2916 /**************************************************************************
2917  *                              MMSYSTEM_MidiStreamPlayer       [internal]
2918  */
2919 static  DWORD   WINAPI  MMSYSTEM_MidiStreamPlayer(LPVOID pmt)
2920 {
2921     WINE_MIDIStream*    lpMidiStrm = pmt;
2922     MIDIOPENDESC*       lpDesc = USER_HEAP_LIN_ADDR(lpMidiStrm->hDevice);
2923     MSG                 msg;
2924     DWORD               dwToGo;
2925     DWORD               dwCurrTC;
2926
2927     TRACE(mmsys, "(%p)!\n", lpMidiStrm);
2928
2929     /* force thread's queue creation */
2930     /* Used to be InitThreadInput16(0, 5); */
2931     /* but following works also with hack in midiStreamOpen */
2932     Callout.PeekMessageA(&msg, 0, 0, 0, 0);
2933
2934     /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
2935     lpMidiStrm->bFlag = TRUE;
2936     TRACE(mmsys, "Ready to go 1\n");
2937     SuspendThread(lpMidiStrm->hThread);
2938     TRACE(mmsys, "Ready to go 2\n");
2939
2940     lpMidiStrm->dwStartTicks = 0;    
2941     lpMidiStrm->dwPulses = 0;
2942
2943     while (Callout.GetMessageA(&msg, 0, 0, 0)) {
2944         LPMIDIHDR       lpMidiHdr = (LPMIDIHDR)msg.lParam;
2945         LPMIDIEVENT     me;
2946         LPBYTE          lpData;
2947
2948         switch (msg.message) {
2949         case WM_USER:
2950             TRACE(mmsys, "%s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx]\n", 
2951                   (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr, 
2952                   lpMidiHdr->reserved, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded, lpMidiHdr->dwFlags);
2953
2954             /* <HACK>
2955              * midiOutPrepareHeader(), in Wine, sets the 'reserved' field of MIDIHDR to the
2956              * 16 or 32 bit address of lpMidiHdr (depending if called from 16 to 32 bit code)
2957              */
2958             lpData = ((DWORD)lpMidiHdr == lpMidiHdr->reserved) ?
2959                 (LPBYTE)lpMidiHdr->lpData : (LPBYTE)PTR_SEG_TO_LIN(lpMidiHdr->lpData);
2960
2961 #if 0
2962             /* dumps content of lpMidiHdr->lpData
2963              * FIXME: there should be a debug routine somewhere that already does this
2964              * I hate spreading this type of shit all around the code 
2965              */ 
2966             for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
2967                 DWORD   i;
2968                 BYTE    ch;
2969
2970                 for (i = 0; i < MIN(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
2971                     printf("%02x ", lpData[dwToGo + i]);
2972                 for (; i < 16; i++)
2973                     printf("   ");
2974                 for (i = 0; i < MIN(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
2975                     ch = lpData[dwToGo + i];
2976                     printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
2977                 }
2978                 printf("\n");
2979             }
2980 #endif
2981             /* FIXME: EPP says "I don't understand the content of the first MIDIHDR sent
2982              * by native mcimidi, it doesn't look like a correct one".
2983              * this trick allows to throw it away... but I don't like it. 
2984              * It looks like part of the file I'm trying to play and definitively looks 
2985              * like raw midi content
2986              * I'd really like to understand why native mcimidi sends it. Perhaps a bad
2987              * synchronization issue where native mcimidi is still processing raw MIDI 
2988              * content before generating MIDIEVENTs ?
2989              *
2990              * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
2991              * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
2992              * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
2993              * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
2994              * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
2995              * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
2996              * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
2997              * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
2998              * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
2999              * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3000              * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3001              * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3002              * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3003              * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3004              * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3005              * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3006              * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3007              */
3008             if (((LPMIDIEVENT)lpData)->dwStreamID != 0 && 
3009                 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3010                 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3011                 FIXME(mmsys, "Dropping bad lpMidiHdr (streamID=%08lx)\n", ((LPMIDIEVENT)lpData)->dwStreamID);
3012             } else {
3013                 /* sets initial tick count for first MIDIHDR */
3014                 if (!lpMidiStrm->dwStartTicks)
3015                     lpMidiStrm->dwStartTicks = GetTickCount();
3016                 
3017                 for (lpMidiHdr->dwOffset = 0; lpMidiHdr->dwOffset < lpMidiHdr->dwBufferLength; ) {
3018                     me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3019                     
3020                     if (me->dwDeltaTime) {
3021                         lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStreamConvert(lpMidiStrm, me->dwDeltaTime);
3022                         dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3023                         dwCurrTC = GetTickCount();
3024                         
3025                         lpMidiStrm->dwPulses += me->dwDeltaTime;
3026                         
3027                         TRACE(mmsys, "%ld/%ld/%ld\n", dwToGo, dwCurrTC, me->dwDeltaTime);
3028                         if (dwCurrTC < dwToGo)  
3029                             Sleep(dwToGo - dwCurrTC);
3030                     }
3031                     switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3032                     case MEVT_COMMENT:
3033                         FIXME(mmsys, "NIY: MEVT_COMMENT\n");
3034                         /* do nothing, skip bytes */
3035                         break;
3036                     case MEVT_LONGMSG:
3037                         FIXME(mmsys, "NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3038                         break;
3039                     case MEVT_NOP:
3040                         break;
3041                     case MEVT_SHORTMSG:
3042                         midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3043                         break;
3044                     case MEVT_TEMPO:
3045                         lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3046                         break;
3047                     case MEVT_VERSION:
3048                         break;
3049                     default:
3050                         FIXME(mmsys, "Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3051                         break;
3052                     }
3053                     lpMidiHdr->dwOffset += sizeof(MIDIEVENT) + ((me->dwEvent & MEVT_F_LONG) ? ((MEVT_EVENTPARM(me->dwEvent) + 3) & ~3): 0);
3054                     if (me->dwEvent & MEVT_F_CALLBACK) {
3055                         DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice, 
3056                                          MM_MOM_POSITIONCB, lpDesc->dwInstance, (LPARAM)lpMidiHdr, 0L);
3057                     }
3058                 }
3059             }
3060             lpMidiHdr->dwFlags |= MHDR_DONE;
3061             lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3062             
3063             DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice, 
3064                              MM_MOM_DONE, lpDesc->dwInstance, lpMidiHdr->reserved, 0L);
3065             break;
3066         default:
3067             WARN(mmsys, "Unknown message %d\n", msg.message);
3068             break;
3069         }
3070     }
3071     return msg.wParam;
3072 }
3073
3074 /**************************************************************************
3075  *                              midiStreamClose                 [WINMM.90]
3076  */
3077 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3078 {
3079     WINE_MIDIStream*    lpMidiStrm;
3080
3081     TRACE(mmsys, "(%08x)!\n", hMidiStrm);
3082
3083     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3084         return MMSYSERR_INVALHANDLE;
3085
3086     midiStreamStop(hMidiStrm);
3087
3088     USER_HEAP_FREE(hMidiStrm);
3089
3090     return midiOutClose(hMidiStrm);
3091 }
3092
3093 /**************************************************************************
3094  *                              midiStreamOpen                  [WINMM.91]
3095  */
3096 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, 
3097                                DWORD cMidi, DWORD dwCallback, 
3098                                DWORD dwInstance, DWORD fdwOpen) 
3099 {
3100     WINE_MIDIStream*    lpMidiStrm;
3101     MMRESULT            ret;
3102     MIDIOPENSTRMID      mosm;
3103     MIDIOPENDESC*       lpDesc;
3104     HMIDIOUT16          hMidiOut16;
3105
3106     TRACE(mmsys, "(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3107           lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3108
3109     if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3110         return MMSYSERR_INVALPARAM;
3111
3112     if (*lpuDeviceID == (UINT16)MIDI_MAPPER) {
3113         FIXME(mmsys, "MIDI_MAPPER mode requested ! => forcing devID to 0\n");
3114         *lpuDeviceID = 0;
3115     }
3116
3117     lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3118     lpMidiStrm->dwTempo = 500000;
3119     lpMidiStrm->dwTimeDiv = 480;        /* 480 is 120 quater notes per minute *//* FIXME ??*/
3120     lpMidiStrm->dwPositionMS = 0;
3121
3122     mosm.dwStreamID = (DWORD)lpMidiStrm;
3123     /* FIXME: the correct value is not allocated yet for MAPPER */
3124     mosm.wDeviceID  = *lpuDeviceID;
3125     lpDesc = MIDI_OutAlloc(&hMidiOut16, dwCallback, dwInstance, 1, &mosm);
3126     lpMidiStrm->hDevice = hMidiOut16;
3127     if (lphMidiStrm)
3128         *lphMidiStrm = hMidiOut16;
3129
3130     lpDesc->wDevID = *lpuDeviceID;
3131     ret = modMessage(lpDesc->wDevID, MODM_OPEN, 
3132                      lpDesc->dwInstance, (DWORD)lpDesc, fdwOpen);
3133     lpMidiStrm->bFlag = FALSE;
3134     lpMidiStrm->wFlags = HIWORD(fdwOpen);
3135
3136     lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStreamPlayer, 
3137                                        lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3138
3139     if (!lpMidiStrm->hThread) {
3140         midiStreamClose((HMIDISTRM)hMidiOut16);
3141         return MMSYSERR_NOMEM;  
3142     }
3143
3144     /* wait for thread to have started, and for it's queue to be created */
3145     while (!((volatile WINE_MIDIStream*)lpMidiStrm)->bFlag) {
3146         DWORD   count;
3147        
3148         /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code, 
3149          * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running 
3150          * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3151          */
3152         ReleaseThunkLock(&count);
3153         Sleep(1);
3154         RestoreThunkLock(count);
3155     }
3156
3157     TRACE(mmsys, "=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n", *lpuDeviceID, lpDesc->wDevID, *lphMidiStrm, ret, lpMidiStrm);        
3158     return ret;
3159 }
3160
3161 /**************************************************************************
3162  *                              midiStreamOut                   [WINMM.92]
3163  */
3164 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, UINT cbMidiHdr) 
3165 {
3166     WINE_MIDIStream*    lpMidiStrm;
3167     DWORD               ret = MMSYSERR_NOERROR;
3168
3169     TRACE(mmsys, "(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3170
3171     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3172         ret = MMSYSERR_INVALHANDLE;
3173     } else {
3174         if (!Callout.PostThreadMessageA(lpMidiStrm->dwThreadID, WM_USER, 0, (DWORD)lpMidiHdr)) {
3175             WARN(mmsys, "bad PostThreadMessageA\n");
3176         }
3177     }
3178     return ret;
3179 }
3180
3181 /**************************************************************************
3182  *                              midiStreamPause                 [WINMM.93]
3183  */
3184 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm) 
3185 {
3186     WINE_MIDIStream*    lpMidiStrm;
3187     DWORD               ret = MMSYSERR_NOERROR;
3188
3189     TRACE(mmsys, "(%08x)!\n", hMidiStrm);
3190
3191     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3192         ret = MMSYSERR_INVALHANDLE;
3193     } else {
3194         if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3195             WARN(mmsys, "bad Suspend (%ld)\n", GetLastError());
3196         }
3197     }
3198     return ret;
3199 }
3200
3201 /**************************************************************************
3202  *                              midiStreamPosition              [WINMM.94]
3203  */
3204 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt) 
3205 {
3206     WINE_MIDIStream*    lpMidiStrm;
3207     DWORD               ret = MMSYSERR_NOERROR;
3208
3209     TRACE(mmsys, "(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3210
3211     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3212         ret = MMSYSERR_INVALHANDLE;
3213     } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3214         ret = MMSYSERR_INVALPARAM;
3215     } else {
3216         switch (lpMMT->wType) {
3217         case TIME_MS:   
3218             lpMMT->u.ms = lpMidiStrm->dwPositionMS;     
3219             TRACE(mmsys, "=> %ld ms\n", lpMMT->u.ms);
3220             break;
3221         case TIME_TICKS:
3222             lpMMT->u.ticks = lpMidiStrm->dwPulses;      
3223             TRACE(mmsys, "=> %ld ticks\n", lpMMT->u.ticks);
3224             break;
3225         default:
3226             WARN(mmsys, "Unsupported time type %d\n", lpMMT->wType);
3227             lpMMT->wType = TIME_MS;
3228             ret = MMSYSERR_INVALPARAM;
3229             break;
3230         }
3231     }
3232     return ret;
3233 }
3234
3235 /**************************************************************************
3236  *                              midiStreamProperty              [WINMM.95]
3237  */
3238 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) 
3239 {
3240     WINE_MIDIStream*    lpMidiStrm;
3241     MMRESULT            ret = MMSYSERR_NOERROR;
3242
3243     TRACE(mmsys, "(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3244
3245     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3246         ret = MMSYSERR_INVALHANDLE;
3247     } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3248         ret = MMSYSERR_INVALPARAM;
3249     } else if (dwProperty & MIDIPROP_TEMPO) {
3250         MIDIPROPTEMPO*  mpt = (MIDIPROPTEMPO*)lpPropData;
3251         
3252         if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3253             ret = MMSYSERR_INVALPARAM;
3254         } else if (dwProperty & MIDIPROP_SET) {
3255             lpMidiStrm->dwTempo = mpt->dwTempo;
3256             TRACE(mmsys, "Setting tempo to %ld\n", mpt->dwTempo);
3257         } else if (dwProperty & MIDIPROP_GET) {
3258             mpt->dwTempo = lpMidiStrm->dwTempo;
3259             TRACE(mmsys, "Getting tempo <= %ld\n", mpt->dwTempo);
3260         }
3261     } else if (dwProperty & MIDIPROP_TIMEDIV) {
3262         MIDIPROPTIMEDIV*        mptd = (MIDIPROPTIMEDIV*)lpPropData;
3263         
3264         if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3265             ret = MMSYSERR_INVALPARAM;
3266         } else if (dwProperty & MIDIPROP_SET) {
3267             lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3268             TRACE(mmsys, "Setting time div to %ld\n", mptd->dwTimeDiv);
3269         } else if (dwProperty & MIDIPROP_GET) {
3270             mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3271             TRACE(mmsys, "Getting time div <= %ld\n", mptd->dwTimeDiv);
3272         }    
3273     } else {
3274         ret = MMSYSERR_INVALPARAM;
3275     }
3276
3277     return ret;
3278 }
3279
3280 /**************************************************************************
3281  *                              midiStreamRestart               [WINMM.96]
3282  */
3283 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm) 
3284 {
3285     WINE_MIDIStream*    lpMidiStrm;
3286     MMRESULT            ret = MMSYSERR_NOERROR;
3287
3288     TRACE(mmsys, "(%08x)!\n", hMidiStrm);
3289
3290     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3291         ret = MMSYSERR_INVALHANDLE;
3292     } else {
3293         if (ResumeThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3294             WARN(mmsys, "bad Resume (%ld)\n", GetLastError());
3295         }
3296     }
3297     return ret;
3298 }
3299
3300 /**************************************************************************
3301  *                              midiStreamStop                  [WINMM.97]
3302  */
3303 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm) 
3304 {
3305     WINE_MIDIStream*    lpMidiStrm;
3306     MMRESULT            ret = MMSYSERR_NOERROR;
3307
3308     FIXME(mmsys, "(%08x) stub!\n", hMidiStrm);
3309
3310     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3311         ret = MMSYSERR_INVALHANDLE;
3312     } else {
3313         /* FIXME: should turn off all notes, and return all buffers to
3314          * calling application
3315          */
3316     }
3317     return ret;
3318 }
3319
3320 /**************************************************************************
3321  *                              midiStreamClose                 [MMSYSTEM.252]
3322  */
3323 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3324 {
3325     return midiStreamClose(hMidiStrm);
3326 }
3327
3328 /**************************************************************************
3329  *                              midiStreamOpen                  [MMSYSTEM.251]
3330  */
3331 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid, 
3332                                    DWORD cMidi, DWORD dwCallback, 
3333                                    DWORD dwInstance, DWORD fdwOpen) 
3334 {
3335     HMIDISTRM   hMidiStrm32;
3336     MMRESULT    ret;
3337     UINT        devid32;
3338
3339     if (!phMidiStrm || !devid)
3340         return MMSYSERR_INVALPARAM;
3341     devid32 = *devid;
3342     ret = midiStreamOpen(&hMidiStrm32, &devid32, cMidi, dwCallback, dwInstance, fdwOpen);
3343     *phMidiStrm = hMidiStrm32;
3344     *devid = devid32;
3345     return ret;
3346 }
3347
3348 /**************************************************************************
3349  *                              midiStreamOut                   [MMSYSTEM.254]
3350  */
3351 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr) 
3352 {
3353     return midiStreamOut(hMidiStrm, (LPMIDIHDR)lpMidiHdr, cbMidiHdr);
3354 }
3355
3356 /**************************************************************************
3357  *                              midiStreamPause                 [MMSYSTEM.255]
3358  */
3359 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm) 
3360 {
3361     return midiStreamPause(hMidiStrm);
3362 }
3363
3364 /**************************************************************************
3365  *                              midiStreamPosition              [MMSYSTEM.253]
3366  */
3367 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt) 
3368 {
3369     MMTIME      mmt32;
3370     MMRESULT    ret;
3371
3372     if (!lpmmt16)
3373         return MMSYSERR_INVALPARAM;
3374     MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3375     ret = midiStreamPosition(hMidiStrm, &mmt32, sizeof(MMTIME));
3376     MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3377     return ret;
3378 }
3379
3380 /**************************************************************************
3381  *                              midiStreamProperty              [MMSYSTEM.250]
3382  */
3383 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) 
3384 {
3385     return midiStreamProperty(hMidiStrm, lpPropData, dwProperty);
3386 }
3387
3388 /**************************************************************************
3389  *                              midiStreamRestart               [MMSYSTEM.256]
3390  */
3391 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm) 
3392 {
3393     return midiStreamRestart(hMidiStrm);
3394 }
3395
3396 /**************************************************************************
3397  *                              midiStreamStop                  [MMSYSTEM.257]
3398  */
3399 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm) 
3400 {
3401     return midiStreamStop(hMidiStrm);
3402 }
3403
3404 /**************************************************************************
3405  *                              waveOutGetNumDevs               [MMSYSTEM.401]
3406  */
3407 UINT WINAPI waveOutGetNumDevs() 
3408 {
3409     return waveOutGetNumDevs16();
3410 }
3411
3412 /**************************************************************************
3413  *                              waveOutGetNumDevs               [WINMM.167]
3414  */
3415 UINT16 WINAPI waveOutGetNumDevs16()
3416 {
3417     UINT16      count = 0;
3418     TRACE(mmsys, "waveOutGetNumDevs\n");
3419     /* FIXME: I'm not sure MCI_FirstDevID() is correct */
3420     count += wodMessage(MCI_FirstDevID(), WODM_GETNUMDEVS, 0L, 0L, 0L);
3421     TRACE(mmsys, "waveOutGetNumDevs return %u \n", count);
3422     return count;
3423 }
3424
3425 /**************************************************************************
3426  *                              waveOutGetDevCaps               [MMSYSTEM.402]
3427  */
3428 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID, LPWAVEOUTCAPS16 lpCaps,
3429                                   UINT16 uSize)
3430 {
3431     if (uDeviceID > waveOutGetNumDevs16() - 1) return MMSYSERR_BADDEVICEID;
3432     if (uDeviceID == (UINT16)WAVE_MAPPER) return MMSYSERR_BADDEVICEID; /* FIXME: do we have a wave mapper ? */
3433     TRACE(mmsys, "waveOutGetDevCaps\n");
3434     return wodMessage(uDeviceID, WODM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
3435 }
3436
3437 /**************************************************************************
3438  *                              waveOutGetDevCapsA              [WINMM.162]
3439  */
3440 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3441                                UINT uSize)
3442 {
3443     WAVEOUTCAPS16       woc16;
3444     UINT16 ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3445     
3446     lpCaps->wMid = woc16.wMid;
3447     lpCaps->wPid = woc16.wPid;
3448     lpCaps->vDriverVersion = woc16.vDriverVersion;
3449     strcpy(lpCaps->szPname, woc16.szPname);
3450     lpCaps->dwFormats = woc16.dwFormats;
3451     lpCaps->wChannels = woc16.wChannels;
3452     lpCaps->dwSupport = woc16.dwSupport;
3453     return ret;
3454 }
3455
3456 /**************************************************************************
3457  *                              waveOutGetDevCapsW              [WINMM.163]
3458  */
3459 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3460                                    UINT uSize)
3461 {
3462     WAVEOUTCAPS16       woc16;
3463     UINT ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3464     
3465     lpCaps->wMid = woc16.wMid;
3466     lpCaps->wPid = woc16.wPid;
3467     lpCaps->vDriverVersion = woc16.vDriverVersion;
3468     lstrcpyAtoW(lpCaps->szPname, woc16.szPname);
3469     lpCaps->dwFormats = woc16.dwFormats;
3470     lpCaps->wChannels = woc16.wChannels;
3471     lpCaps->dwSupport = woc16.dwSupport;
3472     return ret;
3473 }
3474
3475 /**************************************************************************
3476  *                              waveOutGetErrorText     [MMSYSTEM.403]
3477  */
3478 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3479 {
3480     TRACE(mmsys, "waveOutGetErrorText\n");
3481     return waveGetErrorText(uError, lpText, uSize);
3482 }
3483
3484 /**************************************************************************
3485  *                              waveOutGetErrorTextA    [WINMM.164]
3486  */
3487 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3488 {
3489     return waveOutGetErrorText16(uError, lpText, uSize);
3490 }
3491
3492 /**************************************************************************
3493  *                              waveOutGetErrorTextW    [WINMM.165]
3494  */
3495 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3496 {
3497     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3498     UINT        ret = waveOutGetErrorTextA(uError, xstr, uSize);
3499     
3500     lstrcpyAtoW(lpText, xstr);
3501     HeapFree(GetProcessHeap(), 0, xstr);
3502     return ret;
3503 }
3504
3505 /**************************************************************************
3506  *                              waveGetErrorText                [internal]
3507  */
3508 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3509 {
3510     LPSTR       msgptr;
3511     TRACE(mmsys, "(%04X, %p, %d);\n", 
3512           uError, lpText, uSize);
3513     if ((lpText == NULL) || (uSize < 1)) return(FALSE);
3514     lpText[0] = '\0';
3515     switch (uError) {
3516     case MMSYSERR_NOERROR:
3517         msgptr = "The specified command was carried out.";
3518         break;
3519     case MMSYSERR_ERROR:
3520         msgptr = "Undefined external error.";
3521         break;
3522     case MMSYSERR_BADDEVICEID:
3523         msgptr = "A device ID has been used that is out of range for your system.";
3524         break;
3525     case MMSYSERR_NOTENABLED:
3526         msgptr = "The driver was not enabled.";
3527         break;
3528     case MMSYSERR_ALLOCATED:
3529         msgptr = "The specified device is already in use. Wait until it is free, and then try again.";
3530         break;
3531     case MMSYSERR_INVALHANDLE:
3532         msgptr = "The specified device handle is invalid.";
3533         break;
3534     case MMSYSERR_NODRIVER:
3535         msgptr = "There is no driver installed on your system !\n";
3536         break;
3537     case MMSYSERR_NOMEM:
3538         msgptr = "Not enough memory available for this task. Quit one or more applications to increase available memory, and then try again.";
3539         break;
3540     case MMSYSERR_NOTSUPPORTED:
3541         msgptr = "This function is not supported. Use the Capabilities function to determine which functions and messages the driver supports.";
3542         break;
3543     case MMSYSERR_BADERRNUM:
3544         msgptr = "An error number was specified that is not defined in the system.";
3545         break;
3546     case MMSYSERR_INVALFLAG:
3547         msgptr = "An invalid flag was passed to a system function.";
3548         break;
3549     case MMSYSERR_INVALPARAM:
3550         msgptr = "An invalid parameter was passed to a system function.";
3551         break;
3552     case WAVERR_BADFORMAT:
3553         msgptr = "The specified format is not supported or cannot be translated. Use the Capabilities function to determine the supported formats";
3554         break;
3555     case WAVERR_STILLPLAYING:
3556         msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
3557         break;
3558     case WAVERR_UNPREPARED:
3559         msgptr = "The wave header was not prepared. Use the Prepare function to prepare the header, and then try again.";
3560         break;
3561     case WAVERR_SYNC:
3562         msgptr = "Cannot open the device without using the WAVE_ALLOWSYNC flag. Use the flag, and then try again.";
3563         break;
3564     default:
3565         msgptr = "Unknown MMSYSTEM Error !\n";
3566         break;
3567     }
3568     lstrcpynA(lpText, msgptr, uSize);
3569     return TRUE;
3570 }
3571
3572 /**************************************************************************
3573  *                      waveOutOpen                     [WINMM.173]
3574  * All the args/structs have the same layout as the win16 equivalents
3575  */
3576 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3577                         const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3578                         DWORD dwInstance, DWORD dwFlags)
3579 {
3580     HWAVEOUT16  hwo16;
3581     UINT        ret = waveOutOpen16(&hwo16, uDeviceID, lpFormat, dwCallback, dwInstance,
3582                                     CALLBACK32CONV(dwFlags));
3583
3584     if (lphWaveOut) *lphWaveOut=hwo16;
3585     return ret;
3586 }
3587
3588 /**************************************************************************
3589  *                      waveOutOpen                     [MMSYSTEM.404]
3590  */
3591 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3592                             const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3593                             DWORD dwInstance, DWORD dwFlags)
3594 {
3595     HWAVEOUT16  hWaveOut;
3596     LPWAVEOPENDESC      lpDesc;
3597     DWORD               dwRet = 0;
3598     BOOL                bMapperFlg = FALSE;
3599     
3600     TRACE(mmsys, "(%p, %d, %p, %08lX, %08lX, %08lX);\n", 
3601           lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
3602     if (dwFlags & WAVE_FORMAT_QUERY)
3603         TRACE(mmsys, "WAVE_FORMAT_QUERY requested !\n");
3604     if (uDeviceID == (UINT16)WAVE_MAPPER) {
3605         TRACE(mmsys, "WAVE_MAPPER mode requested !\n");
3606         bMapperFlg = TRUE;
3607         uDeviceID = 0;
3608     }
3609     if (lpFormat == NULL) return WAVERR_BADFORMAT;
3610     
3611     hWaveOut = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
3612     if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
3613     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3614     if (lpDesc == NULL) return MMSYSERR_NOMEM;
3615     lpDesc->hWave = hWaveOut;
3616     lpDesc->lpFormat = (LPWAVEFORMAT)lpFormat;  /* should the struct be copied iso pointer? */
3617     lpDesc->dwCallBack = dwCallback;
3618     lpDesc->dwInstance = dwInstance;
3619     if (uDeviceID >= MAXWAVEDRIVERS)
3620         uDeviceID = 0;
3621     while (uDeviceID < MAXWAVEDRIVERS) {
3622         dwRet = wodMessage(uDeviceID, WODM_OPEN, 
3623                            lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
3624         if (dwRet == MMSYSERR_NOERROR) break;
3625         if (!bMapperFlg) break;
3626         uDeviceID++;
3627         TRACE(mmsys, "WAVE_MAPPER mode ! try next driver...\n");
3628     }
3629     lpDesc->uDeviceID = uDeviceID;  /* save physical Device ID */
3630     if (dwFlags & WAVE_FORMAT_QUERY) {
3631         TRACE(mmsys, "End of WAVE_FORMAT_QUERY !\n");
3632         dwRet = waveOutClose(hWaveOut);
3633         if (lphWaveOut) *lphWaveOut = 0;
3634     }
3635     else if (dwRet != MMSYSERR_NOERROR)
3636     {
3637         USER_HEAP_FREE(hWaveOut);
3638         if (lphWaveOut) *lphWaveOut = 0;
3639     }
3640     return dwRet;
3641 }
3642
3643 /**************************************************************************
3644  *                              waveOutClose            [WINMM.161]
3645  */
3646 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3647 {
3648     return waveOutClose16(hWaveOut);
3649 }
3650
3651 /**************************************************************************
3652  *                              waveOutClose            [MMSYSTEM.405]
3653  */
3654 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
3655 {
3656     LPWAVEOPENDESC      lpDesc;
3657     DWORD               dwRet;
3658     
3659     TRACE(mmsys, "(%04X)\n", hWaveOut);
3660
3661     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3662     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3663     dwRet = wodMessage(lpDesc->uDeviceID, WODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
3664     USER_HEAP_FREE(hWaveOut);
3665     return dwRet;
3666 }
3667
3668 /**************************************************************************
3669  *                              waveOutPrepareHeader    [WINMM.175]
3670  */
3671 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
3672                                  WAVEHDR* lpWaveOutHdr, UINT uSize)
3673 {
3674     LPWAVEOPENDESC      lpDesc;
3675     
3676     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3677
3678     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3679     if (lpDesc == NULL) 
3680         return MMSYSERR_INVALHANDLE;
3681     lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr;
3682     return wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance, 
3683                       (DWORD)lpWaveOutHdr, uSize);
3684 }
3685
3686 /**************************************************************************
3687  *                              waveOutPrepareHeader    [MMSYSTEM.406]
3688  */
3689 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut,
3690                                      WAVEHDR* /*SEGPTR*/ _lpWaveOutHdr, UINT16 uSize)
3691 {
3692     LPWAVEOPENDESC      lpDesc;
3693     LPWAVEHDR           lpWaveOutHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(_lpWaveOutHdr);
3694     UINT16              ret;
3695     
3696     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3697
3698     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3699     if (lpDesc == NULL) 
3700         return MMSYSERR_INVALHANDLE;
3701     lpWaveOutHdr->reserved = (DWORD)_lpWaveOutHdr;
3702     ret = wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance, 
3703                      (DWORD)lpWaveOutHdr, uSize);
3704     return ret;
3705 }
3706
3707 /**************************************************************************
3708  *                              waveOutUnprepareHeader  [WINMM.181]
3709  */
3710 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
3711                                    WAVEHDR* lpWaveOutHdr, UINT uSize)
3712 {
3713     LPWAVEOPENDESC      lpDesc;
3714     
3715     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3716
3717     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3718     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3719     lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr;
3720     return wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance, 
3721                       (DWORD)lpWaveOutHdr, uSize);
3722 }
3723
3724 /**************************************************************************
3725  *                              waveOutUnprepareHeader  [MMSYSTEM.407]
3726  */
3727 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut,
3728                                        WAVEHDR* lpWaveOutHdr, UINT16 uSize)
3729 {
3730     LPWAVEOPENDESC      lpDesc;
3731     UINT16              ret;
3732     
3733     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3734
3735     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3736     if (lpDesc == NULL) 
3737         return MMSYSERR_INVALHANDLE;
3738     ret = wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance, 
3739                      (DWORD)lpWaveOutHdr, uSize);
3740     return ret;
3741 }
3742
3743 /**************************************************************************
3744  *                              waveOutWrite            [MMSYSTEM.408]
3745  */
3746 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, WAVEHDR* lpWaveOutHdr,
3747                          UINT uSize)
3748 {
3749     LPWAVEOPENDESC      lpDesc;
3750
3751     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3752
3753     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3754     if (lpDesc == NULL) 
3755         return MMSYSERR_INVALHANDLE;
3756     return wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance, 
3757                       (DWORD)lpWaveOutHdr, uSize);
3758 }
3759
3760 /**************************************************************************
3761  *                              waveOutWrite            [MMSYSTEM.408]
3762  */
3763 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, WAVEHDR* lpWaveOutHdr,
3764                              UINT16 uSize)
3765 {
3766     LPWAVEOPENDESC      lpDesc;
3767     UINT16              ret;
3768     
3769     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3770
3771     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3772     if (lpDesc == NULL) 
3773         return MMSYSERR_INVALHANDLE;
3774     ret = wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance, (DWORD)lpWaveOutHdr, uSize);
3775     return ret;
3776 }
3777
3778 /**************************************************************************
3779  *                              waveOutPause            [WINMM.174]
3780  */
3781 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
3782 {
3783     return waveOutPause16(hWaveOut);
3784 }
3785
3786 /**************************************************************************
3787  *                              waveOutPause            [MMSYSTEM.409]
3788  */
3789 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut)
3790 {
3791     LPWAVEOPENDESC      lpDesc;
3792     
3793     TRACE(mmsys, "(%04X)\n", hWaveOut);
3794
3795     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3796     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3797     return wodMessage(lpDesc->uDeviceID, WODM_PAUSE, lpDesc->dwInstance, 0L, 0L);
3798 }
3799
3800 /**************************************************************************
3801  *                              waveOutRestart          [WINMM.177]
3802  */
3803 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
3804 {
3805     return waveOutRestart16(hWaveOut);
3806 }
3807
3808 /**************************************************************************
3809  *                              waveOutRestart          [MMSYSTEM.410]
3810  */
3811 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut)
3812 {
3813     LPWAVEOPENDESC      lpDesc;
3814     
3815     TRACE(mmsys, "(%04X)\n", hWaveOut);
3816
3817     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3818     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3819     return wodMessage(lpDesc->uDeviceID, WODM_RESTART, lpDesc->dwInstance, 0L, 0L);
3820 }
3821
3822 /**************************************************************************
3823  *                              waveOutReset            [WINMM.176]
3824  */
3825 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
3826 {
3827     return waveOutReset16(hWaveOut);
3828 }
3829
3830 /**************************************************************************
3831  *                              waveOutReset            [MMSYSTEM.411]
3832  */
3833 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut)
3834 {
3835     LPWAVEOPENDESC      lpDesc;
3836
3837     TRACE(mmsys, "(%04X)\n", hWaveOut);
3838
3839     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3840     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3841     return wodMessage(lpDesc->uDeviceID, WODM_RESET, lpDesc->dwInstance, 0L, 0L);
3842 }
3843
3844 /**************************************************************************
3845  *                              waveOutGetPosition      [WINMM.170]
3846  */
3847 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
3848                                UINT uSize)
3849 {
3850     MMTIME16    mmt16;
3851     UINT ret;
3852     
3853     mmt16.wType = lpTime->wType;
3854     ret = waveOutGetPosition16(hWaveOut, &mmt16, sizeof(mmt16));
3855     MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
3856     return ret;
3857 }
3858
3859 /**************************************************************************
3860  *                              waveOutGetPosition      [MMSYSTEM.412]
3861  */
3862 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
3863                                    UINT16 uSize)
3864 {
3865     LPWAVEOPENDESC      lpDesc;
3866     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
3867     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3868     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3869     return wodMessage(lpDesc->uDeviceID, WODM_GETPOS, lpDesc->dwInstance, 
3870                        (DWORD)lpTime, (DWORD)uSize);
3871 }
3872
3873 #define WAVEOUT_SHORTCUT_1(xx, XX, atype)                               \
3874         UINT WINAPI waveOut##xx(HWAVEOUT hWaveOut, atype x)             \
3875 {                                                                       \
3876         return waveOut##xx##16(hWaveOut, x);                            \
3877 }                                                                       \
3878 UINT16 WINAPI waveOut##xx##16(HWAVEOUT16 hWaveOut, atype x)             \
3879 {                                                                       \
3880         LPWAVEOPENDESC  lpDesc;                                         \
3881         TRACE(mmsys, "(%04X, %08lx);\n", hWaveOut, (DWORD)x);           \
3882         lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);         \
3883         if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;                \
3884         return wodMessage(lpDesc->uDeviceID, WODM_##XX,                 \
3885                           lpDesc->dwInstance, (DWORD)x, 0L);            \
3886 }
3887
3888 WAVEOUT_SHORTCUT_1(GetPitch, GETPITCH, DWORD*)
3889 WAVEOUT_SHORTCUT_1(SetPitch, SETPITCH, DWORD)
3890 WAVEOUT_SHORTCUT_1(GetPlaybackRate, GETPLAYBACKRATE, DWORD*)
3891 WAVEOUT_SHORTCUT_1(SetPlaybackRate, SETPLAYBACKRATE, DWORD)
3892     
3893 #define WAVEOUT_SHORTCUT_2(xx, XX, atype)                               \
3894         UINT WINAPI waveOut##xx(UINT devid, atype x)                    \
3895 {                                                                       \
3896         return waveOut##xx##16(devid, x);                               \
3897 }                                                                       \
3898 UINT16 WINAPI waveOut##xx##16(UINT16 devid, atype x)                    \
3899 {                                                                       \
3900         TRACE(mmsys, "(%04X, %08lx);\n", devid, (DWORD)x);              \
3901         return wodMessage(devid, WODM_##XX, 0L, (DWORD)x, 0L);          \
3902 }
3903     
3904 WAVEOUT_SHORTCUT_2(GetVolume, GETVOLUME, DWORD*)
3905 WAVEOUT_SHORTCUT_2(SetVolume, SETVOLUME, DWORD)
3906     
3907 /**************************************************************************
3908  *                              waveOutBreakLoop        [MMSYSTEM.419]
3909  */
3910 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
3911 {
3912     return waveOutBreakLoop16(hWaveOut);
3913 }
3914
3915 /**************************************************************************
3916  *                              waveOutBreakLoop        [MMSYSTEM.419]
3917  */
3918 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut)
3919 {
3920     TRACE(mmsys, "(%04X)\n", hWaveOut);
3921     return MMSYSERR_INVALHANDLE;
3922 }
3923
3924 /**************************************************************************
3925  *                              waveOutGetID            [MMSYSTEM.420]
3926  */
3927 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
3928 {
3929     LPWAVEOPENDESC      lpDesc;
3930
3931     TRACE(mmsys, "(%04X, %p);\n", hWaveOut, lpuDeviceID);
3932
3933     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3934     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3935     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3936     *lpuDeviceID = lpDesc->uDeviceID;
3937     return 0;
3938 }
3939
3940 /**************************************************************************
3941  *                              waveOutGetID            [MMSYSTEM.420]
3942  */
3943 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
3944 {
3945     LPWAVEOPENDESC      lpDesc;
3946
3947     TRACE(mmsys, "(%04X, %p);\n", hWaveOut, lpuDeviceID);
3948
3949     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3950     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3951     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3952     *lpuDeviceID = lpDesc->uDeviceID;
3953     return 0;
3954 }
3955
3956 /**************************************************************************
3957  *                              waveOutMessage          [MMSYSTEM.421]
3958  */
3959 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, 
3960                               DWORD dwParam1, DWORD dwParam2)
3961 {
3962     LPWAVEOPENDESC      lpDesc;
3963     
3964     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3965     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3966     switch (uMessage) {
3967     case WODM_GETNUMDEVS:
3968     case WODM_GETPOS:
3969     case WODM_GETVOLUME:
3970     case WODM_GETPITCH:
3971     case WODM_GETPLAYBACKRATE:
3972     case WODM_SETVOLUME:
3973     case WODM_SETPITCH:
3974     case WODM_SETPLAYBACKRATE:
3975     case WODM_RESET:
3976     case WODM_PAUSE:
3977     case WODM_PREPARE:
3978     case WODM_UNPREPARE:
3979     case WODM_STOP:
3980     case WODM_CLOSE:
3981         /* no argument conversion needed */
3982         break;
3983     case WODM_WRITE:
3984         return waveOutWrite(hWaveOut, (LPWAVEHDR)dwParam1, dwParam2);
3985     case WODM_GETDEVCAPS:
3986         /* FIXME: UNICODE/ANSI? */
3987         return waveOutGetDevCapsA(hWaveOut, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
3988     case WODM_OPEN:
3989         FIXME(mmsys, "can't handle WODM_OPEN, please report.\n");
3990         break;
3991     default:
3992         ERR(mmsys, "(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
3993             hWaveOut, uMessage, dwParam1, dwParam2);
3994         break;
3995     }
3996     return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
3997 }
3998
3999 /**************************************************************************
4000  *                              waveOutMessage          [MMSYSTEM.421]
4001  */
4002 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage, 
4003                               DWORD dwParam1, DWORD dwParam2)
4004 {
4005     LPWAVEOPENDESC      lpDesc;
4006     
4007     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4008     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4009     switch (uMessage) {
4010     case WODM_GETNUMDEVS:
4011     case WODM_SETVOLUME:
4012     case WODM_SETPITCH:
4013     case WODM_SETPLAYBACKRATE:
4014     case WODM_RESET:
4015     case WODM_PAUSE:
4016     case WODM_STOP:
4017     case WODM_CLOSE:
4018         /* no argument conversion needed */
4019         break;
4020     case WODM_GETPOS:
4021         return waveOutGetPosition16(hWaveOut, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4022     case WODM_GETVOLUME:
4023         return waveOutGetVolume16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4024     case WODM_GETPITCH:
4025         return waveOutGetPitch16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4026     case WODM_GETPLAYBACKRATE:
4027         return waveOutGetPlaybackRate16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4028     case WODM_GETDEVCAPS:
4029         return waveOutGetDevCaps16(hWaveOut, (LPWAVEOUTCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4030     case WODM_PREPARE:
4031         return waveOutPrepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4032     case WODM_UNPREPARE:
4033         return waveOutUnprepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4034     case WODM_WRITE:
4035         return waveOutWrite16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4036     case WODM_OPEN:
4037         FIXME(mmsys, "can't handle WODM_OPEN, please report.\n");
4038         break;
4039     default:
4040         ERR(mmsys, "(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
4041             hWaveOut, uMessage, dwParam1, dwParam2);
4042     }
4043     return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4044 }
4045
4046 /**************************************************************************
4047  *                              waveInGetNumDevs                [WINMM.151]
4048  */
4049 UINT WINAPI waveInGetNumDevs()
4050 {
4051     return waveInGetNumDevs16();
4052 }
4053
4054 /**************************************************************************
4055  *                              waveInGetNumDevs                [MMSYSTEM.501]
4056  */
4057 UINT16 WINAPI waveInGetNumDevs16()
4058 {
4059     UINT16      count = 0;
4060
4061     TRACE(mmsys, "waveInGetNumDevs\n");
4062     count += widMessage(0, WIDM_GETNUMDEVS, 0L, 0L, 0L);
4063     TRACE(mmsys, "waveInGetNumDevs return %u \n", count);
4064     return count;
4065 }
4066
4067 /**************************************************************************
4068  *                              waveInGetDevCapsA               [WINMM.147]
4069  */
4070 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4071 {
4072     WAVEINCAPS16        wic16;
4073     UINT                ret = waveInGetDevCaps16(uDeviceID, &wic16, uSize);
4074     
4075     lpCaps->wMid = wic16.wMid;
4076     lpCaps->wPid = wic16.wPid;
4077     lpCaps->vDriverVersion = wic16.vDriverVersion;
4078     lstrcpyAtoW(lpCaps->szPname, wic16.szPname);
4079     lpCaps->dwFormats = wic16.dwFormats;
4080     lpCaps->wChannels = wic16.wChannels;
4081     
4082     return ret;
4083 }
4084
4085 /**************************************************************************
4086  *                              waveInGetDevCapsA               [WINMM.146]
4087  */
4088 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4089 {
4090     WAVEINCAPS16        wic16;
4091     UINT                ret = waveInGetDevCaps16(uDeviceID, &wic16, uSize);
4092     
4093     lpCaps->wMid = wic16.wMid;
4094     lpCaps->wPid = wic16.wPid;
4095     lpCaps->vDriverVersion = wic16.vDriverVersion;
4096     strcpy(lpCaps->szPname, wic16.szPname);
4097     lpCaps->dwFormats = wic16.dwFormats;
4098     lpCaps->wChannels = wic16.wChannels;
4099     return ret;
4100 }
4101
4102 /**************************************************************************
4103  *                              waveInGetDevCaps                [MMSYSTEM.502]
4104  */
4105 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps, UINT16 uSize)
4106 {
4107     TRACE(mmsys, "waveInGetDevCaps\n");
4108
4109     return widMessage(uDeviceID, WIDM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
4110 }
4111
4112 /**************************************************************************
4113  *                              waveInGetErrorTextA     [WINMM.148]
4114  */
4115 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4116 {
4117     TRACE(mmsys, "waveInGetErrorText\n");
4118     return waveGetErrorText(uError, lpText, uSize);
4119 }
4120
4121 /**************************************************************************
4122  *                              waveInGetErrorTextW     [WINMM.149]
4123  */
4124 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4125 {
4126     LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4127     UINT        ret = waveGetErrorText(uError, txt, uSize);
4128     
4129     lstrcpyAtoW(lpText, txt);
4130     HeapFree(GetProcessHeap(), 0, txt);
4131     return ret;
4132 }
4133
4134 /**************************************************************************
4135  *                              waveInGetErrorText      [MMSYSTEM.503]
4136  */
4137 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4138 {
4139     TRACE(mmsys, "waveInGetErrorText\n");
4140     return waveGetErrorText(uError, lpText, uSize);
4141 }
4142
4143 /**************************************************************************
4144  *                              waveInOpen                      [WINMM.154]
4145  */
4146 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4147                        const LPWAVEFORMAT lpFormat, DWORD dwCallback,
4148                        DWORD dwInstance, DWORD dwFlags)
4149 {
4150     HWAVEIN16   hwin16;
4151     UINT        ret = waveInOpen16(&hwin16, uDeviceID, lpFormat, dwCallback, dwInstance,
4152                                  CALLBACK32CONV(dwFlags));
4153     if (lphWaveIn) *lphWaveIn = hwin16;
4154     return ret;
4155 }
4156
4157 /**************************************************************************
4158  *                              waveInOpen                      [MMSYSTEM.504]
4159  */
4160 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4161                            const LPWAVEFORMAT lpFormat, DWORD dwCallback,
4162                            DWORD dwInstance, DWORD dwFlags)
4163 {
4164     HWAVEIN16 hWaveIn;
4165     LPWAVEOPENDESC      lpDesc;
4166     DWORD       dwRet = 0;
4167     BOOL        bMapperFlg = FALSE;
4168
4169     TRACE(mmsys, "(%p, %d, %p, %08lX, %08lX, %08lX);\n", 
4170           lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
4171     if (dwFlags & WAVE_FORMAT_QUERY)
4172         TRACE(mmsys, "WAVE_FORMAT_QUERY requested !\n");
4173     if (uDeviceID == (UINT16)WAVE_MAPPER) {
4174         TRACE(mmsys, "WAVE_MAPPER mode requested !\n");
4175         bMapperFlg = TRUE;
4176         uDeviceID = 0;
4177     }
4178     if (lpFormat == NULL) return WAVERR_BADFORMAT;
4179     hWaveIn = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
4180     if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
4181     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4182     if (lpDesc == NULL) return MMSYSERR_NOMEM;
4183     lpDesc->hWave = hWaveIn;
4184     lpDesc->lpFormat = lpFormat;
4185     lpDesc->dwCallBack = dwCallback;
4186     lpDesc->dwInstance = dwInstance;
4187     while (uDeviceID < MAXWAVEDRIVERS) {
4188         dwRet = widMessage(uDeviceID, WIDM_OPEN, 
4189                            lpDesc->dwInstance, (DWORD)lpDesc, 0L);
4190         if (dwRet == MMSYSERR_NOERROR) break;
4191         if (!bMapperFlg) break;
4192         uDeviceID++;
4193         TRACE(mmsys, "WAVE_MAPPER mode ! try next driver...\n");
4194     }
4195     lpDesc->uDeviceID = uDeviceID;
4196     if (dwFlags & WAVE_FORMAT_QUERY) {
4197         TRACE(mmsys, "End of WAVE_FORMAT_QUERY !\n");
4198         dwRet = waveInClose16(hWaveIn);
4199     } else if (dwRet != MMSYSERR_NOERROR) {
4200         USER_HEAP_FREE(hWaveIn);
4201         if (lphWaveIn) *lphWaveIn = 0;
4202     }
4203
4204     return dwRet;
4205 }
4206
4207 /**************************************************************************
4208  *                              waveInClose                     [WINMM.145]
4209  */
4210 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4211 {
4212     return waveInClose16(hWaveIn);
4213 }
4214
4215 /**************************************************************************
4216  *                              waveInClose                     [MMSYSTEM.505]
4217  */
4218 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4219 {
4220     LPWAVEOPENDESC      lpDesc;
4221     DWORD               dwRet;    
4222
4223     TRACE(mmsys, "(%04X)\n", hWaveIn);
4224     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4225     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4226     dwRet = widMessage(lpDesc->uDeviceID, WIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
4227     USER_HEAP_FREE(hWaveIn);
4228     return dwRet;
4229 }
4230
4231 /**************************************************************************
4232  *                              waveInPrepareHeader             [WINMM.155]
4233  */
4234 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn,
4235                                 WAVEHDR* lpWaveInHdr, UINT uSize)
4236 {
4237     LPWAVEOPENDESC      lpDesc;
4238     
4239     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4240     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4241     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4242     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4243     lpWaveInHdr->lpNext = NULL;
4244     lpWaveInHdr->dwBytesRecorded = 0;
4245     lpWaveInHdr->reserved = (DWORD)lpWaveInHdr;
4246
4247     return widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance, 
4248                       (DWORD)lpWaveInHdr, uSize);
4249 }
4250
4251 /**************************************************************************
4252  *                              waveInPrepareHeader             [MMSYSTEM.506]
4253  */
4254 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn,
4255                                     WAVEHDR* /* SEGPTR */ _lpWaveInHdr, UINT16 uSize)
4256 {
4257     LPWAVEOPENDESC      lpDesc;
4258     LPWAVEHDR           lpWaveInHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(_lpWaveInHdr);
4259     UINT16              ret;
4260     
4261     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4262
4263     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4264     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4265     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4266
4267     lpWaveInHdr->lpNext = NULL;
4268     lpWaveInHdr->dwBytesRecorded = 0;
4269     
4270     lpWaveInHdr->reserved = (DWORD)_lpWaveInHdr;
4271
4272     ret = widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance, 
4273                      (DWORD)lpWaveInHdr, uSize);
4274     return ret;
4275 }
4276
4277 /**************************************************************************
4278  *                              waveInUnprepareHeader   [WINMM.159]
4279  */
4280 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn,
4281                                   WAVEHDR* lpWaveInHdr, UINT uSize)
4282 {
4283     LPWAVEOPENDESC      lpDesc;
4284     
4285     TRACE(mmsys, "(%04X, %p, %u);\n", 
4286           hWaveIn, lpWaveInHdr, uSize);
4287     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4288     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4289     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4290
4291     lpWaveInHdr->lpNext = NULL;
4292     return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance, 
4293                       (DWORD)lpWaveInHdr, uSize);
4294 }
4295
4296 /**************************************************************************
4297  *                              waveInUnprepareHeader   [MMSYSTEM.507]
4298  */
4299 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn,
4300                                       WAVEHDR* lpWaveInHdr, UINT16 uSize)
4301 {
4302     LPWAVEOPENDESC      lpDesc;
4303     
4304     TRACE(mmsys, "(%04X, %p, %u);\n", 
4305           hWaveIn, lpWaveInHdr, uSize);
4306     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4307     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4308     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4309
4310     return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance, 
4311                       (DWORD)lpWaveInHdr, uSize);
4312 }
4313
4314 /**************************************************************************
4315  *                              waveInAddBuffer         [WINMM.144]
4316  */
4317 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4318                             WAVEHDR* lpWaveInHdr, UINT uSize)
4319 {
4320     LPWAVEOPENDESC      lpDesc;
4321     
4322     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4323
4324     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4325     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4326     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4327
4328     lpWaveInHdr->lpNext = NULL;
4329     lpWaveInHdr->dwBytesRecorded = 0;
4330
4331     return widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
4332                       (DWORD)lpWaveInHdr, uSize);
4333     
4334 }
4335
4336 /**************************************************************************
4337  *                              waveInAddBuffer         [MMSYSTEM.508]
4338  */
4339 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn,
4340                                 WAVEHDR* lpWaveInHdr, UINT16 uSize)
4341 {
4342     LPWAVEOPENDESC      lpDesc;
4343     UINT16              ret;
4344     
4345     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4346
4347     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4348     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4349     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4350     lpWaveInHdr->lpNext = NULL;
4351     lpWaveInHdr->dwBytesRecorded = 0;
4352
4353     ret = widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
4354                      (DWORD)lpWaveInHdr, uSize);
4355     return ret;
4356 }
4357
4358 /**************************************************************************
4359  *                              waveInStart                     [WINMM.157]
4360  */
4361 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4362 {
4363     return waveInStart16(hWaveIn);
4364 }
4365
4366 /**************************************************************************
4367  *                              waveInStart                     [MMSYSTEM.509]
4368  */
4369 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn)
4370 {
4371     LPWAVEOPENDESC      lpDesc;
4372     
4373     TRACE(mmsys, "(%04X)\n", hWaveIn);
4374     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4375     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4376     return widMessage(lpDesc->uDeviceID, WIDM_START, lpDesc->dwInstance, 0, 0);
4377 }
4378
4379 /**************************************************************************
4380  *                              waveInStop                      [WINMM.158]
4381  */
4382 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4383 {
4384     return waveInStop16(hWaveIn);
4385 }
4386
4387 /**************************************************************************
4388  *                              waveInStop                      [MMSYSTEM.510]
4389  */
4390 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn)
4391 {
4392     LPWAVEOPENDESC      lpDesc;
4393     
4394     TRACE(mmsys, "(%04X)\n", hWaveIn);
4395     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4396     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4397     return widMessage(lpDesc->uDeviceID, WIDM_STOP, lpDesc->dwInstance, 0L, 0L);
4398 }
4399
4400 /**************************************************************************
4401  *                              waveInReset                     [WINMM.156]
4402  */
4403 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4404 {
4405     return waveInReset16(hWaveIn);
4406 }
4407
4408 /**************************************************************************
4409  *                              waveInReset                     [MMSYSTEM.511]
4410  */
4411 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn)
4412 {
4413     LPWAVEOPENDESC      lpDesc;
4414     
4415     TRACE(mmsys, "(%04X)\n", hWaveIn);
4416     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4417     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4418     return widMessage(lpDesc->uDeviceID, WIDM_RESET, lpDesc->dwInstance, 0, 0);
4419 }
4420
4421 /**************************************************************************
4422  *                              waveInGetPosition       [WINMM.152]
4423  */
4424 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4425                               UINT uSize)
4426 {
4427     MMTIME16    mmt16;
4428     UINT        ret;
4429     
4430     mmt16.wType = lpTime->wType;
4431     ret = waveInGetPosition16(hWaveIn, &mmt16, uSize);
4432     
4433     MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
4434     return ret;
4435 }
4436
4437 /**************************************************************************
4438  *                              waveInGetPosition       [MMSYSTEM.512]
4439  */
4440 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4441                                   UINT16 uSize)
4442 {
4443     LPWAVEOPENDESC      lpDesc;
4444     
4445     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4446     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4447     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4448     return widMessage(lpDesc->uDeviceID, WIDM_GETPOS, lpDesc->dwInstance,
4449                       (DWORD)lpTime, (DWORD)uSize);
4450 }
4451
4452 /**************************************************************************
4453  *                              waveInGetID                     [WINMM.150]
4454  */
4455 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4456 {
4457     LPWAVEOPENDESC      lpDesc;
4458     
4459     TRACE(mmsys, "waveInGetID\n");
4460     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4461     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4462     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4463     *lpuDeviceID = lpDesc->uDeviceID;
4464     return 0;
4465 }
4466
4467 /**************************************************************************
4468  *                              waveInGetID                     [MMSYSTEM.513]
4469  */
4470 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4471 {
4472     LPWAVEOPENDESC      lpDesc;
4473     
4474     TRACE(mmsys, "waveInGetID\n");
4475     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4476     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4477     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4478     *lpuDeviceID = lpDesc->uDeviceID;
4479     return 0;
4480 }
4481
4482 /**************************************************************************
4483  *                              waveInMessage           [WINMM.153]
4484  */
4485 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4486                            DWORD dwParam1, DWORD dwParam2)
4487 {
4488     LPWAVEOPENDESC      lpDesc;
4489     
4490     FIXME(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
4491           hWaveIn, uMessage, dwParam1, dwParam2);
4492     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4493     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4494     switch (uMessage) {
4495     case WIDM_OPEN:
4496         FIXME(mmsys, "cannot handle WIDM_OPEN, please report.\n");
4497         break;
4498     case WIDM_GETNUMDEVS:
4499     case WIDM_GETPOS:
4500     case WIDM_CLOSE:
4501     case WIDM_STOP:
4502     case WIDM_RESET:
4503     case WIDM_START:
4504     case WIDM_PREPARE:
4505     case WIDM_UNPREPARE:
4506     case WIDM_ADDBUFFER:
4507     case WIDM_PAUSE:
4508         /* no argument conversion needed */
4509         break;
4510     case WIDM_GETDEVCAPS:
4511         /*FIXME: ANSI/UNICODE */
4512         return waveInGetDevCapsA(hWaveIn, (LPWAVEINCAPSA)dwParam1, dwParam2);
4513     default:
4514         ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
4515             hWaveIn, uMessage, dwParam1, dwParam2);
4516         break;
4517     }
4518     return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4519 }
4520
4521 /**************************************************************************
4522  *                              waveInMessage           [MMSYSTEM.514]
4523  */
4524 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4525                              DWORD dwParam1, DWORD dwParam2)
4526 {
4527     LPWAVEOPENDESC      lpDesc;
4528     
4529     FIXME(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
4530           hWaveIn, uMessage, dwParam1, dwParam2);
4531     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4532     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4533     switch (uMessage) {
4534     case WIDM_OPEN:
4535         FIXME(mmsys, "cannot handle WIDM_OPEN, please report.\n");
4536         break;
4537     case WIDM_GETNUMDEVS:
4538     case WIDM_CLOSE:
4539     case WIDM_STOP:
4540     case WIDM_RESET:
4541     case WIDM_START:
4542     case WIDM_PAUSE:
4543         /* no argument conversion needed */
4544         break;
4545     case WIDM_GETDEVCAPS:
4546         return waveInGetDevCaps16(hWaveIn, (LPWAVEINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4547     case WIDM_GETPOS:
4548         return waveInGetPosition16(hWaveIn, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4549     case WIDM_PREPARE:
4550         return waveInPrepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4551     case WIDM_UNPREPARE:
4552         return waveInUnprepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4553     case WIDM_ADDBUFFER:
4554         return waveInAddBuffer16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4555     default:
4556         ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
4557             hWaveIn, uMessage, dwParam1, dwParam2);
4558         break;
4559     }
4560     return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4561 }
4562
4563 /**************************************************************************
4564  *                              DrvOpen                 [MMSYSTEM.1100]
4565  */
4566 HDRVR16 WINAPI DrvOpen(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam)
4567 {
4568     TRACE(mmsys, "('%s','%s', %08lX);\n", lpDriverName, lpSectionName, lParam);
4569
4570     return OpenDriver16(lpDriverName, lpSectionName, lParam);
4571 }
4572
4573 /**************************************************************************
4574  *                              DrvClose                [MMSYSTEM.1101]
4575  */
4576 LRESULT WINAPI DrvClose(HDRVR16 hDrv, LPARAM lParam1, LPARAM lParam2)
4577 {
4578     TRACE(mmsys, "(%04X, %08lX, %08lX);\n", hDrv, lParam1, lParam2);
4579
4580     return CloseDriver16(hDrv, lParam1, lParam2);
4581 }
4582
4583 /**************************************************************************
4584  *                              DrvSendMessage          [MMSYSTEM.1102]
4585  */
4586 LRESULT WINAPI DrvSendMessage(HDRVR16 hDrv, WORD msg, LPARAM lParam1,
4587                               LPARAM lParam2)
4588 {
4589     return SendDriverMessage(hDrv, msg, lParam1, lParam2);
4590 }
4591
4592 /**************************************************************************
4593  *                              DrvGetModuleHandle      [MMSYSTEM.1103]
4594  */
4595 HANDLE16 WINAPI DrvGetModuleHandle16(HDRVR16 hDrv)
4596 {
4597     return GetDriverModuleHandle16(hDrv);
4598 }
4599
4600 /**************************************************************************
4601  *                              DrvDefDriverProc        [MMSYSTEM.1104]
4602  */
4603 LRESULT WINAPI DrvDefDriverProc(DWORD dwDriverID, HDRVR16 hDrv, WORD wMsg, 
4604                                 DWORD dwParam1, DWORD dwParam2)
4605 {
4606     /* FIXME : any mapping from 32 to 16 bit structure ? */
4607     return DefDriverProc16(dwDriverID, hDrv, wMsg, dwParam1, dwParam2);
4608 }
4609
4610 /**************************************************************************
4611  *                              DefDriverProc                     [WINMM.5]
4612  */
4613 LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR hDrv,
4614                              UINT Msg, LPARAM lParam1, LPARAM lParam2)
4615 {
4616     switch (Msg) {
4617     case DRV_LOAD:
4618     case DRV_FREE:
4619     case DRV_ENABLE:
4620     case DRV_DISABLE:
4621         return 1;
4622     case DRV_INSTALL:
4623     case DRV_REMOVE:
4624         return DRV_SUCCESS;
4625     default:
4626         return 0;
4627     }
4628 }
4629
4630 /*#define USE_MM_TSK_WINE*/
4631
4632 /**************************************************************************
4633  *                              mmTaskCreate            [MMSYSTEM.900]
4634  *
4635  * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4636  * called upon creation with dwPmt as parameter.
4637  */
4638 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4639 {
4640     DWORD               showCmd = 0x40002;
4641     LPSTR               cmdline;
4642     WORD                sel1, sel2;
4643     LOADPARAMS16*       lp;
4644     HINSTANCE16         ret;
4645     HINSTANCE16         handle;
4646     
4647     TRACE(mmsys, "(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
4648     /* This to work requires NE modules to be started with a binary command line
4649      * which is not currently the case. A patch exists but has never been committed.
4650      * A workaround would be to integrate code for mmtask.tsk into Wine, but
4651      * this requires tremendous work (starting with patching tools/build to
4652      * create NE executables (and not only DLLs) for builtins modules.
4653      * EP 99/04/25
4654      */
4655     FIXME(mmsys, "This is currently broken. It will fail\n");
4656
4657     cmdline = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 0x0d);
4658     cmdline[0] = 0x0d;
4659     *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
4660     *(LPDWORD)(cmdline + 5) = dwPmt;
4661     *(LPDWORD)(cmdline + 9) = 0;
4662
4663     sel1 = SELECTOR_AllocBlock(cmdline, 0x0d, SEGMENT_DATA, FALSE, FALSE);
4664     sel2 = SELECTOR_AllocBlock(&showCmd, sizeof(showCmd),
4665                                SEGMENT_DATA, FALSE, FALSE);
4666     
4667     lp = (LOADPARAMS16*)HeapAlloc(GetProcessHeap(), 0, sizeof(LOADPARAMS16));
4668     lp->hEnvironment = 0;
4669     lp->cmdLine = PTR_SEG_OFF_TO_SEGPTR(sel1, 0);
4670     lp->showCmd = PTR_SEG_OFF_TO_SEGPTR(sel2, 0);
4671     lp->reserved = 0;
4672     
4673 #ifndef USE_MM_TSK_WINE
4674     handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", lp);
4675 #else
4676     handle = LoadModule16("mmtask.tsk", lp);
4677 #endif
4678     if (handle < 32) {
4679         ret = (handle) ? 1 : 2;
4680         handle = 0;
4681     } else {
4682         ret = 0;
4683     }
4684     if (lphMmTask)
4685         *lphMmTask = handle;
4686     
4687     UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel2, 0));
4688     UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel1, 0));
4689     
4690     HeapFree(GetProcessHeap(), 0, lp);
4691     HeapFree(GetProcessHeap(), 0, cmdline);
4692
4693     TRACE(mmsys, "=> 0x%04x/%d\n", handle, ret);
4694     return ret;
4695 }
4696
4697 #ifdef USE_MM_TSK_WINE
4698 /* C equivalent to mmtask.tsk binary content */
4699 void    mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
4700 {
4701     int len = cmdLine[0x80];
4702
4703     if (len/2 == 6) {
4704         void    (*fpProc)(DWORD) = (void (*)(DWORD))PTR_SEG_TO_LIN(*((DWORD*)(cmdLine + 1)));
4705         DWORD   dwPmt  = *((DWORD*)(cmdLine + 5));
4706
4707 #if 0
4708         InitTask16(); /* fixme: pmts / from context ? */
4709         InitApp(di);
4710 #endif
4711         if (SetMessageQueue16(0x40)) {
4712             WaitEvent16(0);
4713             if (HIWORD(fpProc)) {
4714                 OldYield16();
4715 /* EPP          StackEnter16(); */
4716                 (fpProc)(dwPmt);
4717             }
4718         }
4719     }
4720     OldYield16();
4721     OldYield16();
4722     OldYield16();
4723     ExitProcess(0);
4724 }
4725 #endif
4726
4727 /**************************************************************************
4728  *                              mmTaskBlock             [MMSYSTEM.902]
4729  */
4730 void    WINAPI  mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
4731 {
4732     MSG         msg;
4733
4734     do {
4735         GetMessageA(&msg, 0, 0, 0);
4736         if (msg.hwnd) {
4737             TranslateMessage(&msg);
4738             DispatchMessageA(&msg);
4739         }
4740     } while (msg.message < 0x3A0);
4741 }
4742
4743 /**************************************************************************
4744  *                              mmTaskSignal            [MMSYSTEM.903]
4745  */
4746 LRESULT WINAPI mmTaskSignal16(HTASK16 ht) 
4747 {
4748     TRACE(mmsys, "(%04x);\n", ht);
4749     return Callout.PostAppMessage16(ht, WM_USER, 0, 0);
4750 }
4751
4752 /**************************************************************************
4753  *                              mmTaskYield16           [MMSYSTEM.905]
4754  */
4755 void    WINAPI  mmTaskYield16(void)
4756 {
4757     MSG         msg;
4758
4759     if (PeekMessageA(&msg, 0, 0, 0, 0)) {
4760         Yield16();
4761     }
4762 }
4763
4764 DWORD   WINAPI  GetProcessFlags(DWORD);
4765
4766 /**************************************************************************
4767  *                              mmThreadCreate          [MMSYSTEM.1120]
4768  *
4769  * undocumented
4770  * Creates a MM thread, calling fpThreadAddr(dwPmt). 
4771  * dwFlags: 
4772  *      bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
4773  *      bit.1 set means to open a VxD for this thread (unsupported) 
4774  */
4775 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags) 
4776 {
4777     HANDLE16            hndl;
4778     LRESULT             ret;
4779
4780     TRACE(mmsys, "(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
4781
4782     hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
4783
4784     if (hndl == 0) {
4785         ret = 2;
4786     } else {
4787         WINE_MMTHREAD*  lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4788
4789 #if 0
4790         /* force mmtask routines even if mmthread is required */
4791         /* this will work only if the patch about binary cmd line and NE tasks 
4792          * is committed
4793          */
4794         dwFlags |= 1;
4795 #endif
4796
4797         lpMMThd->dwSignature    = WINE_MMTHREAD_CREATED;
4798         lpMMThd->dwCounter      = 0;
4799         lpMMThd->hThread        = 0;
4800         lpMMThd->dwThreadID     = 0;
4801         lpMMThd->fpThread       = fpThreadAddr;
4802         lpMMThd->dwThreadPmt    = dwPmt;
4803         lpMMThd->dwSignalCount  = 0;
4804         lpMMThd->hEvent         = 0;
4805         lpMMThd->hVxD           = 0;
4806         lpMMThd->dwStatus       = 0;
4807         lpMMThd->dwFlags        = dwFlags;
4808         lpMMThd->hTask          = 0;
4809         
4810         if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
4811             lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
4812
4813             TRACE(mmsys, "Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
4814             if (lpMMThd->dwFlags & 2) {
4815                 /* as long as we don't support MM VxD in wine, we don't need 
4816                  * to care about this flag
4817                  */
4818                 /* FIXME(mmsys, "Don't know how to properly open VxD handles\n"); */
4819                 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
4820             }
4821
4822             lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint, 
4823                                             (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
4824             if (lpMMThd->hThread == 0) {
4825                 WARN(mmsys, "Couldn't create thread\n");
4826                 /* clean-up(VxDhandle...); devicedirectio... */
4827                 if (lpMMThd->hEvent != 0)
4828                     CloseHandle(lpMMThd->hEvent);
4829                 ret = 2;
4830             } else {
4831                 TRACE(mmsys, "Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
4832                 ret = 0;
4833             }
4834         } else {
4835             /* get WINE_mmThreadEntryPoint() 
4836              * 2047 is its ordinal in mmsystem.spec
4837              */
4838             FARPROC16   fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (SEGPTR)2047);
4839
4840             TRACE(mmsys, "farproc seg=0x%08lx lin=%p\n", (DWORD)fp, PTR_SEG_TO_LIN(fp));
4841
4842             ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
4843         }
4844
4845         if (ret == 0) {
4846             if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
4847                 WARN(mmsys, "Couldn't resume thread\n");
4848
4849             while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
4850                 UserYield16();
4851             }
4852         }
4853     }
4854
4855     if (ret != 0) {
4856         GlobalFree16(hndl);
4857         hndl = 0;
4858     }
4859
4860     if (lpHndl)
4861         *lpHndl = hndl;
4862
4863     TRACE(mmsys, "ok => %ld\n", ret);
4864     return ret;
4865 }
4866
4867 /**************************************************************************
4868  *                              mmThreadSignal          [MMSYSTEM.1121]
4869  */
4870 void WINAPI mmThreadSignal16(HANDLE16 hndl) 
4871 {
4872     TRACE(mmsys, "(%04x)!\n", hndl);
4873
4874     if (hndl) {
4875         WINE_MMTHREAD*  lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4876
4877         lpMMThd->dwCounter++;
4878         if (lpMMThd->hThread != 0) {
4879             InterlockedIncrement(&lpMMThd->dwSignalCount);
4880             SetEvent(lpMMThd->hEvent);
4881         } else {
4882             mmTaskSignal16(lpMMThd->hTask);
4883         }
4884         lpMMThd->dwCounter--;
4885     }
4886 }
4887
4888 /**************************************************************************
4889  *                              MMSYSTEM_ThreadBlock            [internal]
4890  */
4891 static  void    MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
4892 {
4893     MSG         msg;
4894     DWORD       ret;
4895
4896     if (lpMMThd->dwThreadID != GetCurrentThreadId())
4897         ERR(mmsys, "Not called by thread itself\n");
4898
4899     for (;;) {
4900         ResetEvent(lpMMThd->hEvent);
4901         if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
4902             break;
4903         InterlockedIncrement(&lpMMThd->dwSignalCount);
4904         
4905         TRACE(mmsys, "S1\n");
4906         
4907         ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
4908         switch (ret) {
4909         case WAIT_OBJECT_0:     /* Event */
4910             TRACE(mmsys, "S2.1\n");
4911             break;
4912         case WAIT_OBJECT_0 + 1: /* Msg */
4913             TRACE(mmsys, "S2.2\n");
4914             if (Callout.PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
4915                 Callout.TranslateMessage(&msg);
4916                 Callout.DispatchMessageA(&msg);
4917             }
4918             break;
4919         default:
4920             WARN(mmsys, "S2.x unsupported ret val 0x%08lx\n", ret);
4921         }
4922         TRACE(mmsys, "S3\n");
4923     }
4924 }
4925
4926 /**************************************************************************
4927  *                              mmThreadBlock           [MMSYSTEM.1122]
4928  */
4929 void    WINAPI mmThreadBlock16(HANDLE16 hndl) 
4930 {
4931     TRACE(mmsys, "(%04x)!\n", hndl);
4932
4933     if (hndl) {
4934         WINE_MMTHREAD*  lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4935         
4936         if (lpMMThd->hThread != 0) {
4937             SYSLEVEL_ReleaseWin16Lock();
4938             MMSYSTEM_ThreadBlock(lpMMThd);
4939             SYSLEVEL_RestoreWin16Lock();
4940         } else {
4941             mmTaskBlock16(lpMMThd->hTask);
4942         }
4943     }
4944     TRACE(mmsys, "done\n");
4945 }
4946
4947 /**************************************************************************
4948  *                              mmThreadIsCurrent       [MMSYSTEM.1123]
4949  */
4950 BOOL16  WINAPI mmThreadIsCurrent16(HANDLE16 hndl) 
4951 {
4952     BOOL16              ret = FALSE;
4953
4954     TRACE(mmsys, "(%04x)!\n", hndl);
4955
4956     if (hndl && mmThreadIsValid16(hndl)) {
4957         WINE_MMTHREAD*  lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4958         ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
4959         /* FIXME: just a test */
4960         SYSLEVEL_ReleaseWin16Lock();
4961         SYSLEVEL_RestoreWin16Lock();
4962     }
4963     TRACE(mmsys, "=> %d\n", ret);
4964     return ret;
4965 }
4966
4967 /**************************************************************************
4968  *                              mmThreadIsValid         [MMSYSTEM.1124]
4969  */
4970 BOOL16  WINAPI  mmThreadIsValid16(HANDLE16 hndl)
4971 {
4972     BOOL16              ret = FALSE;
4973
4974     TRACE(mmsys, "(%04x)!\n", hndl);
4975
4976     if (hndl) {
4977         WINE_MMTHREAD*  lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4978
4979         if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
4980             lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
4981             IsTask16(lpMMThd->hTask)) {
4982             lpMMThd->dwCounter++;
4983             if (lpMMThd->hThread != 0) {
4984                 DWORD   dwThreadRet;
4985                 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
4986                     dwThreadRet == STATUS_PENDING) {
4987                     ret = TRUE;
4988                 }
4989             } else {
4990                 ret = TRUE;
4991             }
4992             lpMMThd->dwCounter--;
4993         }
4994     }
4995     TRACE(mmsys, "=> %d\n", ret);
4996     return ret;
4997 }
4998
4999 /**************************************************************************
5000  *                              mmThreadGetTask         [MMSYSTEM.1125]
5001  */
5002 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl) 
5003 {
5004     HANDLE16    ret = 0;
5005
5006     TRACE(mmsys, "(%04x)\n", hndl);
5007
5008     if (mmThreadIsValid16(hndl)) {
5009         WINE_MMTHREAD*  lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5010         ret = lpMMThd->hTask;
5011     }
5012     return ret;
5013 }
5014
5015 /**************************************************************************
5016  *                              mmThreadGetTask                 [internal]
5017  */
5018 void    WINAPI  WINE_mmThreadEntryPoint(DWORD _pmt)
5019 {
5020     HANDLE16            hndl = (HANDLE16)_pmt;
5021     WINE_MMTHREAD*      lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5022     CRITICAL_SECTION*   cs;
5023
5024     TRACE(mmsys, "(%04x %p)\n", hndl, lpMMThd);
5025
5026     GetpWin16Lock(&cs);
5027
5028     TRACE(mmsys, "lc=%ld rc=%ld ot=%08lx\n", cs->LockCount, cs->RecursionCount, (DWORD)cs->OwningThread);
5029
5030     lpMMThd->hTask = LOWORD(GetCurrentTask());
5031     TRACE(mmsys, "[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5032     lpMMThd->dwStatus = 0x10;
5033     MMSYSTEM_ThreadBlock(lpMMThd);
5034     TRACE(mmsys, "[20-%08x]\n", lpMMThd->hThread);
5035     lpMMThd->dwStatus = 0x20;
5036     if (lpMMThd->fpThread) {
5037 #if 0
5038         extern  DWORD   CALLBACK        CallTo16_long_l_x(FARPROC16, DWORD);
5039         TRACE(mmsys, "Calling %08lx(%08lx)\n", (DWORD)lpMMThd->fpThread, lpMMThd->dwThreadPmt);$
5040         CallTo16_long_l_x(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5041 #else
5042         Callbacks->CallWOWCallbackProc(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5043 #endif
5044     }
5045     lpMMThd->dwStatus = 0x30;
5046     TRACE(mmsys, "[30-%08x]\n", lpMMThd->hThread);
5047     while (lpMMThd->dwCounter) {
5048         Sleep(1);
5049         /* Yield16();*/
5050     }
5051     TRACE(mmsys, "[XX-%08x]\n", lpMMThd->hThread);
5052     /* paranoia */
5053     lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5054     /* close lpMMThread->hVxD directio */
5055     if (lpMMThd->hEvent)
5056         CloseHandle(lpMMThd->hEvent);
5057     GlobalFree16(hndl);
5058     TRACE(mmsys, "lc=%ld rc=%ld ot=%08lx\n", cs->LockCount, cs->RecursionCount, (DWORD)cs->OwningThread);
5059     TRACE(mmsys, "done\n");
5060 }
5061
5062 /**************************************************************************
5063  *                      mmShowMMCPLPropertySheet        [MMSYSTEM.1150]
5064  */
5065 BOOL16  WINAPI  mmShowMMCPLPropertySheet16(HWND hWnd, char* lpStrDevice, 
5066                                            char* lpStrTab, char* lpStrTitle)
5067 {
5068     HANDLE      hndl;
5069     BOOL16      ret = FALSE;
5070
5071     TRACE(mmsys, "(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5072
5073     hndl = LoadLibraryA("MMSYS.CPL");
5074     if (hndl != 0) {
5075         BOOL16 (WINAPI *fp)(HWND, LPSTR, LPSTR, LPSTR);
5076
5077         fp = (BOOL16 (WINAPI *)(HWND, LPSTR, LPSTR, LPSTR))GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5078         if (fp != NULL) {           
5079             /* FIXME: wine hangs and/or seg faults in this call, 
5080              * after the window is correctly displayed 
5081              */
5082             TRACE(mmsys, "Ready to go ThreadID=%08lx\n", GetCurrentThreadId());
5083             SYSLEVEL_ReleaseWin16Lock();
5084             ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5085             SYSLEVEL_RestoreWin16Lock();
5086         }
5087         FreeLibrary(hndl);
5088     }
5089     
5090     return ret;
5091 }
5092
5093 /**************************************************************************
5094  *                      StackEnter & StackLeave         [MMSYSTEM.32][MMSYSTEM.33]
5095  */
5096 void    WINAPI  StackEnterLeave16(void)
5097 {
5098 #ifdef __i386__
5099     /* mmsystem.dll from Win 95 does only this: so does Wine */
5100     __asm__("stc");
5101 #endif
5102 }