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