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