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