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