Modify ok("xxx") calls into ok("xxx\n") as is now expected.
[wine] / dlls / winmm / winmm.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * WINMM functions
5  *
6  * Copyright 1993      Martin Ayotte
7  *           1998-2002 Eric Pouech
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 /*
25  * Eric POUECH :
26  *      98/9    added Win32 MCI support
27  *      99/4    added midiStream support
28  *      99/9    added support for loadable low level drivers
29  */
30
31 #include <stdarg.h>
32 #include <string.h>
33
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "mmsystem.h"
39 #include "winuser.h"
40 #include "winreg.h"
41 #include "heap.h"
42 #include "winternl.h"
43 #include "winemm.h"
44
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
48
49 /******************************************************************
50  *              MyUserYield
51  *
52  * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32).
53  */
54 static void MyUserYield(void)
55 {
56     HMODULE mod = GetModuleHandleA( "user32.dll" );
57     if (mod)
58     {
59         FARPROC proc = GetProcAddress( mod, "UserYield16" );
60         if (proc) proc();
61     }
62 }
63
64 /* ========================================================================
65  *                   G L O B A L   S E T T I N G S
66  * ========================================================================*/
67
68 LPWINE_MM_IDATA         WINMM_IData /* = NULL */;
69
70 /**************************************************************************
71  *                      WINMM_CreateIData                       [internal]
72  */
73 static  BOOL    WINMM_CreateIData(HINSTANCE hInstDLL)
74 {
75     WINMM_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
76
77     if (!WINMM_IData)
78         return FALSE;
79     WINMM_IData->hWinMM32Instance = hInstDLL;
80     InitializeCriticalSection(&WINMM_IData->cs);
81     WINMM_IData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
82     WINMM_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
83     WINMM_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
84     TRACE("Created IData (%p)\n", WINMM_IData);
85     return TRUE;
86 }
87
88 /**************************************************************************
89  *                      WINMM_DeleteIData                       [internal]
90  */
91 static  void WINMM_DeleteIData(void)
92 {
93     if (WINMM_IData) {
94         TIME_MMTimeStop();
95
96         /* FIXME: should also free content and resources allocated
97          * inside WINMM_IData */
98         CloseHandle(WINMM_IData->psStopEvent);
99         CloseHandle(WINMM_IData->psLastEvent);
100         DeleteCriticalSection(&WINMM_IData->cs);
101         HeapFree(GetProcessHeap(), 0, WINMM_IData);
102         WINMM_IData = NULL;
103     }
104 }
105
106 /******************************************************************
107  *             WINMM_LoadMMSystem
108  *
109  */
110 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR);
111 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR);
112
113 BOOL WINMM_CheckForMMSystem(void)
114 {
115     /* 0 is not checked yet, -1 is not present, 1 is present */
116     static      int    loaded /* = 0 */;
117
118     if (loaded == 0)
119     {
120         HANDLE      h = GetModuleHandleA("kernel32");
121         loaded = -1;
122         if (h)
123         {
124             pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16");
125             pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16");
126             if (pGetModuleHandle16 && pLoadLibrary16 &&
127                 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
128                 loaded = 1;
129         }
130     }
131     return loaded > 0;
132 }
133
134 /**************************************************************************
135  *              DllMain (WINMM.init)
136  *
137  * WINMM DLL entry point
138  *
139  */
140 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
141 {
142     TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
143
144     switch (fdwReason) {
145     case DLL_PROCESS_ATTACH:
146         DisableThreadLibraryCalls(hInstDLL);
147
148         if (!WINMM_CreateIData(hInstDLL))
149             return FALSE;
150         if (!MCI_Init() || !MMDRV_Init()) {
151             WINMM_DeleteIData();
152             return FALSE;
153         }
154         break;
155     case DLL_PROCESS_DETACH:
156         /* close all opened MCI drivers */
157         MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE);
158         MMDRV_Exit();
159         /* now unload all remaining drivers... */
160         DRIVER_UnloadAll();
161
162         WINMM_DeleteIData();
163         break;
164     }
165     return TRUE;
166 }
167
168 /**************************************************************************
169  *      Mixer devices. New to Win95
170  */
171
172 /**************************************************************************
173  * find out the real mixer ID depending on hmix (depends on dwFlags)
174  */
175 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
176 {
177     LPWINE_MIXER        lpwm = NULL;
178
179     switch (dwFlags & 0xF0000000ul) {
180     case MIXER_OBJECTF_MIXER:
181         lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
182         break;
183     case MIXER_OBJECTF_HMIXER:
184         lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
185         break;
186     case MIXER_OBJECTF_WAVEOUT:
187         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE,  MMDRV_MIXER);
188         break;
189     case MIXER_OBJECTF_HWAVEOUT:
190         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
191         break;
192     case MIXER_OBJECTF_WAVEIN:
193         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN,  TRUE,  MMDRV_MIXER);
194         break;
195     case MIXER_OBJECTF_HWAVEIN:
196         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN,  FALSE, MMDRV_MIXER);
197         break;
198     case MIXER_OBJECTF_MIDIOUT:
199         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE,  MMDRV_MIXER);
200         break;
201     case MIXER_OBJECTF_HMIDIOUT:
202         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
203         break;
204     case MIXER_OBJECTF_MIDIIN:
205         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN,  TRUE,  MMDRV_MIXER);
206         break;
207     case MIXER_OBJECTF_HMIDIIN:
208         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN,  FALSE, MMDRV_MIXER);
209         break;
210     case MIXER_OBJECTF_AUX:
211         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX,     TRUE,  MMDRV_MIXER);
212         break;
213     default:
214         FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
215         break;
216     }
217     return lpwm;
218 }
219
220 /**************************************************************************
221  *                              mixerGetNumDevs                 [WINMM.@]
222  */
223 UINT WINAPI mixerGetNumDevs(void)
224 {
225     return MMDRV_GetNum(MMDRV_MIXER);
226 }
227
228 /**************************************************************************
229  *                              mixerGetDevCapsA                [WINMM.@]
230  */
231 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
232 {
233     LPWINE_MLD  wmld;
234
235     if ((wmld = MMDRV_Get((HANDLE)devid, MMDRV_MIXER, TRUE)) == NULL)
236         return MMSYSERR_BADDEVICEID;
237
238     return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
239 }
240
241 /**************************************************************************
242  *                              mixerGetDevCapsW                [WINMM.@]
243  */
244 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
245 {
246     MIXERCAPSA  micA;
247     UINT        ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
248
249     if (ret == MMSYSERR_NOERROR) {
250         mixcaps->wMid           = micA.wMid;
251         mixcaps->wPid           = micA.wPid;
252         mixcaps->vDriverVersion = micA.vDriverVersion;
253         MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
254                              sizeof(mixcaps->szPname)/sizeof(WCHAR) );
255         mixcaps->fdwSupport     = micA.fdwSupport;
256         mixcaps->cDestinations  = micA.cDestinations;
257     }
258     return ret;
259 }
260
261 UINT  MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
262                  DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
263 {
264     HANDLE              hMix;
265     LPWINE_MLD          wmld;
266     DWORD               dwRet = 0;
267     MIXEROPENDESC       mod;
268
269     TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
270           lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
271
272     wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
273                        &dwCallback, &dwInstance, bFrom32);
274
275     wmld->uDeviceID = uDeviceID;
276     mod.hmx = (HMIXEROBJ)hMix;
277     mod.dwCallback = dwCallback;
278     mod.dwInstance = dwInstance;
279
280     dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
281
282     if (dwRet != MMSYSERR_NOERROR) {
283         MMDRV_Free(hMix, wmld);
284         hMix = 0;
285     }
286     if (lphMix) *lphMix = hMix;
287     TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
288
289     return dwRet;
290 }
291
292 /**************************************************************************
293  *                              mixerOpen                       [WINMM.@]
294  */
295 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
296                       DWORD dwInstance, DWORD fdwOpen)
297 {
298     return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
299 }
300
301 /**************************************************************************
302  *                              mixerClose                      [WINMM.@]
303  */
304 UINT WINAPI mixerClose(HMIXER hMix)
305 {
306     LPWINE_MLD          wmld;
307     DWORD               dwRet;
308
309     TRACE("(%p)\n", hMix);
310
311     if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
312
313     dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
314     MMDRV_Free(hMix, wmld);
315
316     return dwRet;
317 }
318
319 /**************************************************************************
320  *                              mixerGetID                      [WINMM.@]
321  */
322 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
323 {
324     LPWINE_MIXER        lpwm;
325
326     TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID);
327
328     if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
329         return MMSYSERR_INVALHANDLE;
330     }
331
332     if (lpid)
333       *lpid = lpwm->mld.uDeviceID;
334
335     return MMSYSERR_NOERROR;
336 }
337
338 /**************************************************************************
339  *                              mixerGetControlDetailsA         [WINMM.@]
340  */
341 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
342                                     DWORD fdwDetails)
343 {
344     LPWINE_MIXER        lpwm;
345
346     TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
347
348     if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
349         return MMSYSERR_INVALHANDLE;
350
351     if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
352         return MMSYSERR_INVALPARAM;
353
354     return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
355                          fdwDetails, TRUE);
356 }
357
358 /**************************************************************************
359  *                              mixerGetControlDetailsW [WINMM.@]
360  */
361 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
362 {
363     DWORD                       ret = MMSYSERR_NOTENABLED;
364
365     TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
366
367     if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
368         return MMSYSERR_INVALPARAM;
369
370     switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
371     case MIXER_GETCONTROLDETAILSF_VALUE:
372         /* can savely use W structure as it is, no string inside */
373         ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
374         break;
375     case MIXER_GETCONTROLDETAILSF_LISTTEXT:
376         {
377             MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
378             MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
379             int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
380             int i;
381
382             if (lpmcd->u.cMultipleItems != 0) {
383                 size *= lpmcd->u.cMultipleItems;
384             }
385             pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
386             lpmcd->paDetails = pDetailsA;
387             lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
388             /* set up lpmcd->paDetails */
389             ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
390             /* copy from lpmcd->paDetails back to paDetailsW; */
391             if(ret == MMSYSERR_NOERROR) {
392                 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
393                     pDetailsW->dwParam1 = pDetailsA->dwParam1;
394                     pDetailsW->dwParam2 = pDetailsA->dwParam2;
395                     MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
396                                          pDetailsW->szName,
397                                          sizeof(pDetailsW->szName)/sizeof(WCHAR) );
398                     pDetailsA++;
399                     pDetailsW++;
400                 }
401                 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
402                 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
403             }
404             HeapFree(GetProcessHeap(), 0, pDetailsA);
405             lpmcd->paDetails = pDetailsW;
406             lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
407         }
408         break;
409     default:
410         ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
411     }
412
413     return ret;
414 }
415
416 /**************************************************************************
417  *                              mixerGetLineControlsA   [WINMM.@]
418  */
419 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
420                                   DWORD fdwControls)
421 {
422     LPWINE_MIXER        lpwm;
423
424     TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
425
426     if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
427         return MMSYSERR_INVALHANDLE;
428
429     if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
430         return MMSYSERR_INVALPARAM;
431
432     return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
433                          fdwControls, TRUE);
434 }
435
436 /**************************************************************************
437  *                              mixerGetLineControlsW           [WINMM.@]
438  */
439 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
440                                   DWORD fdwControls)
441 {
442     MIXERLINECONTROLSA  mlcA;
443     DWORD               ret;
444     int                 i;
445
446     TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
447
448     if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
449         lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
450         return MMSYSERR_INVALPARAM;
451
452     mlcA.cbStruct = sizeof(mlcA);
453     mlcA.dwLineID = lpmlcW->dwLineID;
454     mlcA.u.dwControlID = lpmlcW->u.dwControlID;
455     mlcA.u.dwControlType = lpmlcW->u.dwControlType;
456     mlcA.cControls = lpmlcW->cControls;
457     mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
458     mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
459                               mlcA.cControls * mlcA.cbmxctrl);
460
461     ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
462
463     if (ret == MMSYSERR_NOERROR) {
464         lpmlcW->dwLineID = mlcA.dwLineID;
465         lpmlcW->u.dwControlID = mlcA.u.dwControlID;
466         lpmlcW->u.dwControlType = mlcA.u.dwControlType;
467         lpmlcW->cControls = mlcA.cControls;
468
469         for (i = 0; i < mlcA.cControls; i++) {
470             lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
471             lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
472             lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
473             lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
474             lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
475             MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
476                                  lpmlcW->pamxctrl[i].szShortName,
477                                  sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
478             MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
479                                  lpmlcW->pamxctrl[i].szName,
480                                  sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
481             /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
482              * sizeof(mlcA.pamxctrl[i].Bounds) */
483             memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
484                    sizeof(mlcA.pamxctrl[i].Bounds));
485             /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
486              * sizeof(mlcA.pamxctrl[i].Metrics) */
487             memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
488                    sizeof(mlcA.pamxctrl[i].Metrics));
489         }
490     }
491
492     HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
493
494     return ret;
495 }
496
497 /**************************************************************************
498  *                              mixerGetLineInfoA               [WINMM.@]
499  */
500 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
501 {
502     LPWINE_MIXER        lpwm;
503
504     TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
505
506     if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
507         return MMSYSERR_INVALHANDLE;
508
509     return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
510                          fdwInfo, TRUE);
511 }
512
513 /**************************************************************************
514  *                              mixerGetLineInfoW               [WINMM.@]
515  */
516 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
517                               DWORD fdwInfo)
518 {
519     MIXERLINEA          mliA;
520     UINT                ret;
521
522     TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
523
524     if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
525         return MMSYSERR_INVALPARAM;
526
527     mliA.cbStruct = sizeof(mliA);
528     switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
529     case MIXER_GETLINEINFOF_COMPONENTTYPE:
530         mliA.dwComponentType = lpmliW->dwComponentType;
531         break;
532     case MIXER_GETLINEINFOF_DESTINATION:
533         mliA.dwDestination = lpmliW->dwDestination;
534         break;
535     case MIXER_GETLINEINFOF_LINEID:
536         mliA.dwLineID = lpmliW->dwLineID;
537         break;
538     case MIXER_GETLINEINFOF_SOURCE:
539         mliA.dwDestination = lpmliW->dwDestination;
540         mliA.dwSource = lpmliW->dwSource;
541         break;
542     case MIXER_GETLINEINFOF_TARGETTYPE:
543         mliA.Target.dwType = lpmliW->Target.dwType;
544         mliA.Target.wMid = lpmliW->Target.wMid;
545         mliA.Target.wPid = lpmliW->Target.wPid;
546         mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
547         WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
548         break;
549     default:
550         FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
551     }
552
553     ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
554
555     lpmliW->dwDestination = mliA.dwDestination;
556     lpmliW->dwSource = mliA.dwSource;
557     lpmliW->dwLineID = mliA.dwLineID;
558     lpmliW->fdwLine = mliA.fdwLine;
559     lpmliW->dwUser = mliA.dwUser;
560     lpmliW->dwComponentType = mliA.dwComponentType;
561     lpmliW->cChannels = mliA.cChannels;
562     lpmliW->cConnections = mliA.cConnections;
563     lpmliW->cControls = mliA.cControls;
564     MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
565                          sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
566     MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
567                          sizeof(lpmliW->szName)/sizeof(WCHAR) );
568     lpmliW->Target.dwType = mliA.Target.dwType;
569     lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
570     lpmliW->Target.wMid = mliA.Target.wMid;
571     lpmliW->Target.wPid = mliA.Target.wPid;
572     lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
573     MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
574                          sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
575
576     return ret;
577 }
578
579 /**************************************************************************
580  *                              mixerSetControlDetails  [WINMM.@]
581  */
582 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
583                                    DWORD fdwDetails)
584 {
585     LPWINE_MIXER        lpwm;
586
587     TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
588
589     if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
590         return MMSYSERR_INVALHANDLE;
591
592     return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
593                          fdwDetails, TRUE);
594 }
595
596 /**************************************************************************
597  *                              mixerMessage            [WINMM.@]
598  */
599 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
600 {
601     LPWINE_MLD          wmld;
602
603     TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
604           (DWORD)hmix, uMsg, dwParam1, dwParam2);
605
606     if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
607         return MMSYSERR_INVALHANDLE;
608
609     return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
610 }
611
612 /**************************************************************************
613  *                              auxGetNumDevs           [WINMM.@]
614  */
615 UINT WINAPI auxGetNumDevs(void)
616 {
617     return MMDRV_GetNum(MMDRV_AUX);
618 }
619
620 /**************************************************************************
621  *                              auxGetDevCapsW          [WINMM.@]
622  */
623 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
624 {
625     AUXCAPSA    acA;
626     UINT        ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
627
628     lpCaps->wMid = acA.wMid;
629     lpCaps->wPid = acA.wPid;
630     lpCaps->vDriverVersion = acA.vDriverVersion;
631     MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
632                          sizeof(lpCaps->szPname)/sizeof(WCHAR) );
633     lpCaps->wTechnology = acA.wTechnology;
634     lpCaps->dwSupport = acA.dwSupport;
635     return ret;
636 }
637
638 /**************************************************************************
639  *                              auxGetDevCapsA          [WINMM.@]
640  */
641 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
642 {
643     LPWINE_MLD          wmld;
644
645     TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
646
647     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
648         return MMSYSERR_INVALHANDLE;
649     return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
650 }
651
652 /**************************************************************************
653  *                              auxGetVolume            [WINMM.@]
654  */
655 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
656 {
657     LPWINE_MLD          wmld;
658
659     TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
660
661     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
662         return MMSYSERR_INVALHANDLE;
663     return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
664 }
665
666 /**************************************************************************
667  *                              auxSetVolume            [WINMM.@]
668  */
669 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
670 {
671     LPWINE_MLD          wmld;
672
673     TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
674
675     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
676         return MMSYSERR_INVALHANDLE;
677     return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
678 }
679
680 /**************************************************************************
681  *                              auxOutMessage           [WINMM.@]
682  */
683 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
684 {
685     LPWINE_MLD          wmld;
686
687     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
688         return MMSYSERR_INVALHANDLE;
689
690     return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
691 }
692
693 /**************************************************************************
694  *                              mciGetErrorStringW              [WINMM.@]
695  */
696 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
697 {
698     LPSTR       bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
699     BOOL        ret = mciGetErrorStringA(wError, bufstr, uLength);
700
701     MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
702     HeapFree(GetProcessHeap(), 0, bufstr);
703     return ret;
704 }
705
706 /**************************************************************************
707  *                              mciGetErrorStringA              [WINMM.@]
708  */
709 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
710 {
711     BOOL16              ret = FALSE;
712
713     if (lpstrBuffer != NULL && uLength > 0 &&
714         dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
715
716         if (LoadStringA(WINMM_IData->hWinMM32Instance,
717                         dwError, lpstrBuffer, uLength) > 0) {
718             ret = TRUE;
719         }
720     }
721     return ret;
722 }
723
724 /**************************************************************************
725  *                      mciDriverNotify                         [WINMM.@]
726  */
727 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
728 {
729
730     TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
731
732     return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
733 }
734
735 /**************************************************************************
736  *                      mciGetDriverData                        [WINMM.@]
737  */
738 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
739 {
740     LPWINE_MCIDRIVER    wmd;
741
742     TRACE("(%04x)\n", uDeviceID);
743
744     wmd = MCI_GetDriver(uDeviceID);
745
746     if (!wmd) {
747         WARN("Bad uDeviceID\n");
748         return 0L;
749     }
750
751     return wmd->dwPrivate;
752 }
753
754 /**************************************************************************
755  *                      mciSetDriverData                        [WINMM.@]
756  */
757 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
758 {
759     LPWINE_MCIDRIVER    wmd;
760
761     TRACE("(%04x, %08lx)\n", uDeviceID, data);
762
763     wmd = MCI_GetDriver(uDeviceID);
764
765     if (!wmd) {
766         WARN("Bad uDeviceID\n");
767         return FALSE;
768     }
769
770     wmd->dwPrivate = data;
771     return TRUE;
772 }
773
774 /**************************************************************************
775  *                              mciSendCommandA                 [WINMM.@]
776  */
777 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
778 {
779     DWORD       dwRet;
780
781     TRACE("(%08x, %s, %08lx, %08lx)\n",
782           wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
783
784     dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
785     dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
786     TRACE("=> %08lx\n", dwRet);
787     return dwRet;
788 }
789
790 /**************************************************************************
791  *                              mciSendCommandW                 [WINMM.@]
792  */
793 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
794 {
795     FIXME("(%08x, %s, %08lx, %08lx): stub\n",
796           wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
797     return MCIERR_UNSUPPORTED_FUNCTION;
798 }
799
800 /**************************************************************************
801  *                              mciGetDeviceIDA                 [WINMM.@]
802  */
803 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
804 {
805     return MCI_GetDriverFromString(lpstrName);
806 }
807
808 /**************************************************************************
809  *                              mciGetDeviceIDW                 [WINMM.@]
810  */
811 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
812 {
813     LPSTR       lpstrName;
814     UINT        ret;
815
816     lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
817     ret = MCI_GetDriverFromString(lpstrName);
818     HeapFree(GetProcessHeap(), 0, lpstrName);
819     return ret;
820 }
821
822 /**************************************************************************
823  *                              MCI_DefYieldProc                [internal]
824  */
825 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
826 {
827     INT16       ret;
828
829     TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
830
831     if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
832         (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
833         MyUserYield();
834         ret = 0;
835     } else {
836         MSG             msg;
837
838         msg.hwnd = HWND_32(HIWORD(data));
839         while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
840         ret = -1;
841     }
842     return ret;
843 }
844
845 /**************************************************************************
846  *                              mciSetYieldProc                 [WINMM.@]
847  */
848 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
849 {
850     LPWINE_MCIDRIVER    wmd;
851
852     TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
853
854     if (!(wmd = MCI_GetDriver(uDeviceID))) {
855         WARN("Bad uDeviceID\n");
856         return FALSE;
857     }
858
859     wmd->lpfnYieldProc = fpYieldProc;
860     wmd->dwYieldData   = dwYieldData;
861     wmd->bIs32         = TRUE;
862
863     return TRUE;
864 }
865
866 /**************************************************************************
867  *                              mciGetDeviceIDFromElementIDW    [WINMM.@]
868  */
869 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
870 {
871     /* FIXME: that's rather strange, there is no
872      * mciGetDeviceIDFromElementID32A in winmm.spec
873      */
874     FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
875     return 0;
876 }
877
878 /**************************************************************************
879  *                              mciGetYieldProc                 [WINMM.@]
880  */
881 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
882 {
883     LPWINE_MCIDRIVER    wmd;
884
885     TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
886
887     if (!(wmd = MCI_GetDriver(uDeviceID))) {
888         WARN("Bad uDeviceID\n");
889         return NULL;
890     }
891     if (!wmd->lpfnYieldProc) {
892         WARN("No proc set\n");
893         return NULL;
894     }
895     if (!wmd->bIs32) {
896         WARN("Proc is 32 bit\n");
897         return NULL;
898     }
899     return wmd->lpfnYieldProc;
900 }
901
902 /**************************************************************************
903  *                              mciGetCreatorTask               [WINMM.@]
904  */
905 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
906 {
907     LPWINE_MCIDRIVER    wmd;
908     HTASK ret = 0;
909
910     if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
911
912     TRACE("(%u) => %p\n", uDeviceID, ret);
913     return ret;
914 }
915
916 /**************************************************************************
917  *                      mciDriverYield                          [WINMM.@]
918  */
919 UINT WINAPI mciDriverYield(UINT uDeviceID)
920 {
921     LPWINE_MCIDRIVER    wmd;
922     UINT                ret = 0;
923
924     TRACE("(%04x)\n", uDeviceID);
925
926     if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
927         MyUserYield();
928     } else {
929         ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
930     }
931
932     return ret;
933 }
934
935 /**************************************************************************
936  *                              midiOutGetNumDevs       [WINMM.@]
937  */
938 UINT WINAPI midiOutGetNumDevs(void)
939 {
940     return MMDRV_GetNum(MMDRV_MIDIOUT);
941 }
942
943 /**************************************************************************
944  *                              midiOutGetDevCapsW      [WINMM.@]
945  */
946 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
947                                UINT uSize)
948 {
949     MIDIOUTCAPSA        mocA;
950     UINT                ret;
951
952     ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
953     lpCaps->wMid                = mocA.wMid;
954     lpCaps->wPid                = mocA.wPid;
955     lpCaps->vDriverVersion      = mocA.vDriverVersion;
956     MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
957                          sizeof(lpCaps->szPname)/sizeof(WCHAR) );
958     lpCaps->wTechnology         = mocA.wTechnology;
959     lpCaps->wVoices             = mocA.wVoices;
960     lpCaps->wNotes              = mocA.wNotes;
961     lpCaps->wChannelMask        = mocA.wChannelMask;
962     lpCaps->dwSupport           = mocA.dwSupport;
963     return ret;
964 }
965
966 /**************************************************************************
967  *                              midiOutGetDevCapsA      [WINMM.@]
968  */
969 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
970                                UINT uSize)
971 {
972     LPWINE_MLD  wmld;
973
974     TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
975
976     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
977
978     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
979         return MMSYSERR_INVALHANDLE;
980
981     return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
982 }
983
984 /**************************************************************************
985  *                              MIDI_GetErrorText               [internal]
986  */
987 static  UINT16  MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
988 {
989     UINT16              ret = MMSYSERR_BADERRNUM;
990
991     if (lpText == NULL) {
992         ret = MMSYSERR_INVALPARAM;
993     } else if (uSize == 0) {
994         ret = MMSYSERR_NOERROR;
995     } else if (
996                /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
997                 * a warning for the test was always true */
998                (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
999                (uError >= MIDIERR_BASE  && uError <= MIDIERR_LASTERROR)) {
1000
1001         if (LoadStringA(WINMM_IData->hWinMM32Instance,
1002                         uError, lpText, uSize) > 0) {
1003             ret = MMSYSERR_NOERROR;
1004         }
1005     }
1006     return ret;
1007 }
1008
1009 /**************************************************************************
1010  *                              midiOutGetErrorTextA    [WINMM.@]
1011  */
1012 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1013 {
1014     return MIDI_GetErrorText(uError, lpText, uSize);
1015 }
1016
1017 /**************************************************************************
1018  *                              midiOutGetErrorTextW    [WINMM.@]
1019  */
1020 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1021 {
1022     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1023     UINT        ret;
1024
1025     ret = MIDI_GetErrorText(uError, xstr, uSize);
1026     MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1027     HeapFree(GetProcessHeap(), 0, xstr);
1028     return ret;
1029 }
1030
1031 /**************************************************************************
1032  *                              MIDI_OutAlloc                   [internal]
1033  */
1034 static  LPWINE_MIDI     MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1035                                       LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1036                                       DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1037 {
1038     HANDLE              hMidiOut;
1039     LPWINE_MIDI         lpwm;
1040     UINT                size;
1041
1042     size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1043
1044     lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1045                                     lpdwCallback, lpdwInstance, bFrom32);
1046
1047     if (lphMidiOut != NULL)
1048         *lphMidiOut = hMidiOut;
1049
1050     if (lpwm) {
1051         lpwm->mod.hMidi = (HMIDI) hMidiOut;
1052         lpwm->mod.dwCallback = *lpdwCallback;
1053         lpwm->mod.dwInstance = *lpdwInstance;
1054         lpwm->mod.dnDevNode = 0;
1055         lpwm->mod.cIds = cIDs;
1056         if (cIDs)
1057             memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1058     }
1059     return lpwm;
1060 }
1061
1062 UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
1063                   DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1064 {
1065     HMIDIOUT            hMidiOut;
1066     LPWINE_MIDI         lpwm;
1067     UINT                dwRet = 0;
1068
1069     TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1070           lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1071
1072     if (lphMidiOut != NULL) *lphMidiOut = 0;
1073
1074     lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1075                          0, NULL, bFrom32);
1076
1077     if (lpwm == NULL)
1078         return MMSYSERR_NOMEM;
1079
1080     lpwm->mld.uDeviceID = uDeviceID;
1081
1082     dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1083
1084     if (dwRet != MMSYSERR_NOERROR) {
1085         MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1086         hMidiOut = 0;
1087     }
1088
1089     if (lphMidiOut) *lphMidiOut = hMidiOut;
1090     TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
1091
1092     return dwRet;
1093 }
1094
1095 /**************************************************************************
1096  *                              midiOutOpen             [WINMM.@]
1097  */
1098 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
1099                         DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1100 {
1101     return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1102 }
1103
1104 /**************************************************************************
1105  *                              midiOutClose            [WINMM.@]
1106  */
1107 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1108 {
1109     LPWINE_MLD          wmld;
1110     DWORD               dwRet;
1111
1112     TRACE("(%p)\n", hMidiOut);
1113
1114     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1115         return MMSYSERR_INVALHANDLE;
1116
1117     dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1118     MMDRV_Free(hMidiOut, wmld);
1119
1120     return dwRet;
1121 }
1122
1123 /**************************************************************************
1124  *                              midiOutPrepareHeader    [WINMM.@]
1125  */
1126 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1127                                  MIDIHDR* lpMidiOutHdr, UINT uSize)
1128 {
1129     LPWINE_MLD          wmld;
1130
1131     TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1132
1133     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1134         return MMSYSERR_INVALHANDLE;
1135
1136     return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1137 }
1138
1139 /**************************************************************************
1140  *                              midiOutUnprepareHeader  [WINMM.@]
1141  */
1142 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1143                                    MIDIHDR* lpMidiOutHdr, UINT uSize)
1144 {
1145     LPWINE_MLD          wmld;
1146
1147     TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1148
1149     if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1150         return MMSYSERR_NOERROR;
1151     }
1152
1153     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1154         return MMSYSERR_INVALHANDLE;
1155
1156     return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1157 }
1158
1159 /**************************************************************************
1160  *                              midiOutShortMsg         [WINMM.@]
1161  */
1162 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1163 {
1164     LPWINE_MLD          wmld;
1165
1166     TRACE("(%p, %08lX)\n", hMidiOut, dwMsg);
1167
1168     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1169         return MMSYSERR_INVALHANDLE;
1170
1171     return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE);
1172 }
1173
1174 /**************************************************************************
1175  *                              midiOutLongMsg          [WINMM.@]
1176  */
1177 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1178                            MIDIHDR* lpMidiOutHdr, UINT uSize)
1179 {
1180     LPWINE_MLD          wmld;
1181
1182     TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1183
1184     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1185         return MMSYSERR_INVALHANDLE;
1186
1187     return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
1188 }
1189
1190 /**************************************************************************
1191  *                              midiOutReset            [WINMM.@]
1192  */
1193 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1194 {
1195     LPWINE_MLD          wmld;
1196
1197     TRACE("(%p)\n", hMidiOut);
1198
1199     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1200         return MMSYSERR_INVALHANDLE;
1201
1202     return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1203 }
1204
1205 /**************************************************************************
1206  *                              midiOutGetVolume        [WINMM.@]
1207  */
1208 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
1209 {
1210     LPWINE_MLD          wmld;
1211
1212     TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
1213
1214     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1215         return MMSYSERR_INVALHANDLE;
1216
1217     return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1218 }
1219
1220 /**************************************************************************
1221  *                              midiOutSetVolume        [WINMM.@]
1222  */
1223 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
1224 {
1225     LPWINE_MLD          wmld;
1226
1227     TRACE("(%p, %ld);\n", hMidiOut, dwVolume);
1228
1229     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1230         return MMSYSERR_INVALHANDLE;
1231
1232     return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1233 }
1234
1235 /**************************************************************************
1236  *                              midiOutCachePatches             [WINMM.@]
1237  */
1238 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1239                                 WORD* lpwPatchArray, UINT uFlags)
1240 {
1241     /* not really necessary to support this */
1242     FIXME("not supported yet\n");
1243     return MMSYSERR_NOTSUPPORTED;
1244 }
1245
1246 /**************************************************************************
1247  *                              midiOutCacheDrumPatches [WINMM.@]
1248  */
1249 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1250                                     WORD* lpwKeyArray, UINT uFlags)
1251 {
1252     FIXME("not supported yet\n");
1253     return MMSYSERR_NOTSUPPORTED;
1254 }
1255
1256 /**************************************************************************
1257  *                              midiOutGetID            [WINMM.@]
1258  */
1259 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1260 {
1261     LPWINE_MLD          wmld;
1262
1263     TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
1264
1265     if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1266     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1267         return MMSYSERR_INVALHANDLE;
1268
1269     *lpuDeviceID = wmld->uDeviceID;
1270     return MMSYSERR_NOERROR;
1271 }
1272
1273 /**************************************************************************
1274  *                              midiOutMessage          [WINMM.@]
1275  */
1276 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1277                             DWORD dwParam1, DWORD dwParam2)
1278 {
1279     LPWINE_MLD          wmld;
1280
1281     TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1282
1283     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1284         /* HACK... */
1285         if (uMessage == 0x0001) {
1286             *(LPDWORD)dwParam1 = 1;
1287             return 0;
1288         }
1289         if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1290             return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1291         }
1292         return MMSYSERR_INVALHANDLE;
1293     }
1294
1295     switch (uMessage) {
1296     case MODM_OPEN:
1297     case MODM_CLOSE:
1298         FIXME("can't handle OPEN or CLOSE message!\n");
1299         return MMSYSERR_NOTSUPPORTED;
1300     }
1301     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1302 }
1303
1304 /**************************************************************************
1305  *                              midiInGetNumDevs        [WINMM.@]
1306  */
1307 UINT WINAPI midiInGetNumDevs(void)
1308 {
1309     return MMDRV_GetNum(MMDRV_MIDIIN);
1310 }
1311
1312 /**************************************************************************
1313  *                              midiInGetDevCapsW       [WINMM.@]
1314  */
1315 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1316 {
1317     MIDIINCAPSA         micA;
1318     UINT                ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
1319
1320     if (ret == MMSYSERR_NOERROR) {
1321         lpCaps->wMid = micA.wMid;
1322         lpCaps->wPid = micA.wPid;
1323         lpCaps->vDriverVersion = micA.vDriverVersion;
1324         MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
1325                              sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1326         lpCaps->dwSupport = micA.dwSupport;
1327     }
1328     return ret;
1329 }
1330
1331 /**************************************************************************
1332  *                              midiInGetDevCapsA       [WINMM.@]
1333  */
1334 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1335 {
1336     LPWINE_MLD  wmld;
1337
1338     TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1339
1340     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1341         return MMSYSERR_INVALHANDLE;
1342
1343    return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1344 }
1345
1346 /**************************************************************************
1347  *                              midiInGetErrorTextW             [WINMM.@]
1348  */
1349 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1350 {
1351     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1352     UINT        ret = MIDI_GetErrorText(uError, xstr, uSize);
1353
1354     MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1355     HeapFree(GetProcessHeap(), 0, xstr);
1356     return ret;
1357 }
1358
1359 /**************************************************************************
1360  *                              midiInGetErrorTextA             [WINMM.@]
1361  */
1362 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1363 {
1364     return MIDI_GetErrorText(uError, lpText, uSize);
1365 }
1366
1367 UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1368                  DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1369 {
1370     HANDLE              hMidiIn;
1371     LPWINE_MIDI         lpwm;
1372     DWORD               dwRet = 0;
1373
1374     TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1375           lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1376
1377     if (lphMidiIn != NULL) *lphMidiIn = 0;
1378
1379     lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1380                                     &dwFlags, &dwCallback, &dwInstance, bFrom32);
1381
1382     if (lpwm == NULL)
1383         return MMSYSERR_NOMEM;
1384
1385     lpwm->mod.hMidi = (HMIDI) hMidiIn;
1386     lpwm->mod.dwCallback = dwCallback;
1387     lpwm->mod.dwInstance = dwInstance;
1388
1389     lpwm->mld.uDeviceID = uDeviceID;
1390     dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1391
1392     if (dwRet != MMSYSERR_NOERROR) {
1393         MMDRV_Free(hMidiIn, &lpwm->mld);
1394         hMidiIn = 0;
1395     }
1396     if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1397     TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn);
1398
1399     return dwRet;
1400 }
1401
1402 /**************************************************************************
1403  *                              midiInOpen              [WINMM.@]
1404  */
1405 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1406                        DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1407 {
1408     return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1409 }
1410
1411 /**************************************************************************
1412  *                              midiInClose             [WINMM.@]
1413  */
1414 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1415 {
1416     LPWINE_MLD          wmld;
1417     DWORD               dwRet;
1418
1419     TRACE("(%p)\n", hMidiIn);
1420
1421     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1422         return MMSYSERR_INVALHANDLE;
1423
1424     dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1425     MMDRV_Free(hMidiIn, wmld);
1426     return dwRet;
1427 }
1428
1429 /**************************************************************************
1430  *                              midiInPrepareHeader     [WINMM.@]
1431  */
1432 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1433                                 MIDIHDR* lpMidiInHdr, UINT uSize)
1434 {
1435     LPWINE_MLD          wmld;
1436
1437     TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1438
1439     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1440         return MMSYSERR_INVALHANDLE;
1441
1442     return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1443 }
1444
1445 /**************************************************************************
1446  *                              midiInUnprepareHeader   [WINMM.@]
1447  */
1448 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1449                                   MIDIHDR* lpMidiInHdr, UINT uSize)
1450 {
1451     LPWINE_MLD          wmld;
1452
1453     TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1454
1455     if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1456         return MMSYSERR_NOERROR;
1457     }
1458
1459     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1460         return MMSYSERR_INVALHANDLE;
1461
1462     return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1463 }
1464
1465 /**************************************************************************
1466  *                              midiInAddBuffer         [WINMM.@]
1467  */
1468 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1469                             MIDIHDR* lpMidiInHdr, UINT uSize)
1470 {
1471     LPWINE_MLD          wmld;
1472
1473     TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1474
1475     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1476         return MMSYSERR_INVALHANDLE;
1477
1478     return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
1479 }
1480
1481 /**************************************************************************
1482  *                              midiInStart                     [WINMM.@]
1483  */
1484 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1485 {
1486     LPWINE_MLD          wmld;
1487
1488     TRACE("(%p)\n", hMidiIn);
1489
1490     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1491         return MMSYSERR_INVALHANDLE;
1492
1493     return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1494 }
1495
1496 /**************************************************************************
1497  *                              midiInStop                      [WINMM.@]
1498  */
1499 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1500 {
1501     LPWINE_MLD          wmld;
1502
1503     TRACE("(%p)\n", hMidiIn);
1504
1505     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1506         return MMSYSERR_INVALHANDLE;
1507
1508     return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1509 }
1510
1511 /**************************************************************************
1512  *                              midiInReset                     [WINMM.@]
1513  */
1514 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1515 {
1516     LPWINE_MLD          wmld;
1517
1518     TRACE("(%p)\n", hMidiIn);
1519
1520     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1521         return MMSYSERR_INVALHANDLE;
1522
1523     return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1524 }
1525
1526 /**************************************************************************
1527  *                              midiInGetID                     [WINMM.@]
1528  */
1529 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1530 {
1531     LPWINE_MLD          wmld;
1532
1533     TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
1534
1535     if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1536
1537     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1538         return MMSYSERR_INVALHANDLE;
1539
1540     *lpuDeviceID = wmld->uDeviceID;
1541
1542     return MMSYSERR_NOERROR;
1543 }
1544
1545 /**************************************************************************
1546  *                              midiInMessage           [WINMM.@]
1547  */
1548 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1549                            DWORD dwParam1, DWORD dwParam2)
1550 {
1551     LPWINE_MLD          wmld;
1552
1553     TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1554
1555     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1556         return MMSYSERR_INVALHANDLE;
1557
1558     switch (uMessage) {
1559     case MIDM_OPEN:
1560     case MIDM_CLOSE:
1561         FIXME("can't handle OPEN or CLOSE message!\n");
1562         return MMSYSERR_NOTSUPPORTED;
1563     }
1564     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1565 }
1566
1567 typedef struct WINE_MIDIStream {
1568     HMIDIOUT                    hDevice;
1569     HANDLE                      hThread;
1570     DWORD                       dwThreadID;
1571     DWORD                       dwTempo;
1572     DWORD                       dwTimeDiv;
1573     DWORD                       dwPositionMS;
1574     DWORD                       dwPulses;
1575     DWORD                       dwStartTicks;
1576     WORD                        wFlags;
1577     HANDLE                      hEvent;
1578     LPMIDIHDR                   lpMidiHdr;
1579 } WINE_MIDIStream;
1580
1581 #define WINE_MSM_HEADER         (WM_USER+0)
1582 #define WINE_MSM_STOP           (WM_USER+1)
1583
1584 /**************************************************************************
1585  *                              MMSYSTEM_GetMidiStream          [internal]
1586  */
1587 static  BOOL    MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1588 {
1589     WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1590
1591     if (lplpwm)
1592         *lplpwm = lpwm;
1593
1594     if (lpwm == NULL) {
1595         return FALSE;
1596     }
1597
1598     *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1599
1600     return *lpMidiStrm != NULL;
1601 }
1602
1603 /**************************************************************************
1604  *                              MMSYSTEM_MidiStream_Convert     [internal]
1605  */
1606 static  DWORD   MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1607 {
1608     DWORD       ret = 0;
1609
1610     if (lpMidiStrm->dwTimeDiv == 0) {
1611         FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1612     } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1613         int     nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv);      /* number of frames     */
1614         int     nsf = LOBYTE(lpMidiStrm->dwTimeDiv);            /* number of sub-frames */
1615         ret = (pulse * 1000) / (nf * nsf);
1616     } else {
1617         ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1618                       (double)lpMidiStrm->dwTimeDiv);
1619     }
1620
1621     return ret;
1622 }
1623
1624 /**************************************************************************
1625  *                      MMSYSTEM_MidiStream_MessageHandler      [internal]
1626  */
1627 static  BOOL    MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1628 {
1629     LPMIDIHDR   lpMidiHdr;
1630     LPMIDIHDR*  lpmh;
1631     LPBYTE      lpData;
1632
1633     switch (msg->message) {
1634     case WM_QUIT:
1635         SetEvent(lpMidiStrm->hEvent);
1636         return FALSE;
1637     case WINE_MSM_STOP:
1638         TRACE("STOP\n");
1639         /* this is not quite what MS doc says... */
1640         midiOutReset(lpMidiStrm->hDevice);
1641         /* empty list of already submitted buffers */
1642         for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1643             lpMidiHdr->dwFlags |= MHDR_DONE;
1644             lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1645
1646             DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1647                            (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1648                            lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1649         }
1650         lpMidiStrm->lpMidiHdr = 0;
1651         SetEvent(lpMidiStrm->hEvent);
1652         break;
1653     case WINE_MSM_HEADER:
1654         /* sets initial tick count for first MIDIHDR */
1655         if (!lpMidiStrm->dwStartTicks)
1656             lpMidiStrm->dwStartTicks = GetTickCount();
1657
1658         /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1659          * by native mcimidi, it doesn't look like a correct one".
1660          * this trick allows to throw it away... but I don't like it.
1661          * It looks like part of the file I'm trying to play and definitively looks
1662          * like raw midi content
1663          * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1664          * synchronization issue where native mcimidi is still processing raw MIDI
1665          * content before generating MIDIEVENTs ?
1666          *
1667          * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1668          * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1669          * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1670          * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1671          * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1672          * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1673          * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1674          * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1675          * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1676          * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1677          * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1678          * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1679          * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1680          * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1681          * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1682          * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1683          * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1684          */
1685         lpMidiHdr = (LPMIDIHDR)msg->lParam;
1686         lpData = lpMidiHdr->lpData;
1687         TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1688               (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1689               (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1690               lpMidiHdr->dwFlags, msg->wParam);
1691 #if 0
1692         /* dumps content of lpMidiHdr->lpData
1693          * FIXME: there should be a debug routine somewhere that already does this
1694          * I hate spreading this type of shit all around the code
1695          */
1696         for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
1697             DWORD       i;
1698             BYTE        ch;
1699
1700             for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1701                 printf("%02x ", lpData[dwToGo + i]);
1702             for (; i < 16; i++)
1703                 printf("   ");
1704             for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
1705                 ch = lpData[dwToGo + i];
1706                 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
1707             }
1708             printf("\n");
1709         }
1710 #endif
1711         if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
1712             ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
1713             ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
1714             FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1715                   (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
1716                   ((LPMIDIEVENT)lpData)->dwStreamID);
1717             lpMidiHdr->dwFlags |= MHDR_DONE;
1718             lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1719
1720             DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1721                            (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1722                            lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1723             break;
1724         }
1725
1726         for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
1727         *lpmh = lpMidiHdr;
1728         lpMidiHdr = (LPMIDIHDR)msg->lParam;
1729         lpMidiHdr->lpNext = 0;
1730         lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1731         lpMidiHdr->dwFlags &= MHDR_DONE;
1732         lpMidiHdr->dwOffset = 0;
1733
1734         break;
1735     default:
1736         FIXME("Unknown message %d\n", msg->message);
1737         break;
1738     }
1739     return TRUE;
1740 }
1741
1742 /**************************************************************************
1743  *                              MMSYSTEM_MidiStream_Player      [internal]
1744  */
1745 static  DWORD   CALLBACK        MMSYSTEM_MidiStream_Player(LPVOID pmt)
1746 {
1747     WINE_MIDIStream*    lpMidiStrm = pmt;
1748     WINE_MIDI*          lpwm;
1749     MSG                 msg;
1750     DWORD               dwToGo;
1751     DWORD               dwCurrTC;
1752     LPMIDIHDR           lpMidiHdr;
1753     LPMIDIEVENT         me;
1754     LPBYTE              lpData = 0;
1755
1756     TRACE("(%p)!\n", lpMidiStrm);
1757
1758     if (!lpMidiStrm ||
1759         (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
1760         goto the_end;
1761
1762     /* force thread's queue creation */
1763     /* Used to be InitThreadInput16(0, 5); */
1764     /* but following works also with hack in midiStreamOpen */
1765     PeekMessageA(&msg, 0, 0, 0, 0);
1766
1767     /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1768     SetEvent(lpMidiStrm->hEvent);
1769     TRACE("Ready to go 1\n");
1770     /* thread is started in paused mode */
1771     SuspendThread(lpMidiStrm->hThread);
1772     TRACE("Ready to go 2\n");
1773
1774     lpMidiStrm->dwStartTicks = 0;
1775     lpMidiStrm->dwPulses = 0;
1776
1777     lpMidiStrm->lpMidiHdr = 0;
1778
1779     for (;;) {
1780         lpMidiHdr = lpMidiStrm->lpMidiHdr;
1781         if (!lpMidiHdr) {
1782             /* for first message, block until one arrives, then process all that are available */
1783             GetMessageA(&msg, 0, 0, 0);
1784             do {
1785                 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1786                     goto the_end;
1787             } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
1788             lpData = 0;
1789             continue;
1790         }
1791
1792         if (!lpData)
1793             lpData = lpMidiHdr->lpData;
1794
1795         me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
1796
1797         /* do we have to wait ? */
1798         if (me->dwDeltaTime) {
1799             lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
1800             lpMidiStrm->dwPulses += me->dwDeltaTime;
1801
1802             dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
1803
1804             TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
1805             while ((dwCurrTC = GetTickCount()) < dwToGo) {
1806                 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
1807                     /* got a message, handle it */
1808                     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
1809                         if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1810                             goto the_end;
1811                     }
1812                     lpData = 0;
1813                 } else {
1814                     /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1815                     break;
1816                 }
1817             }
1818         }
1819         switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
1820         case MEVT_COMMENT:
1821             FIXME("NIY: MEVT_COMMENT\n");
1822             /* do nothing, skip bytes */
1823             break;
1824         case MEVT_LONGMSG:
1825             FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1826             break;
1827         case MEVT_NOP:
1828             break;
1829         case MEVT_SHORTMSG:
1830             midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
1831             break;
1832         case MEVT_TEMPO:
1833             lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
1834             break;
1835         case MEVT_VERSION:
1836             break;
1837         default:
1838             FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
1839             break;
1840         }
1841         if (me->dwEvent & MEVT_F_CALLBACK) {
1842             DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1843                            (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
1844                            lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
1845         }
1846         lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
1847         if (me->dwEvent & MEVT_F_LONG)
1848             lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
1849         if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
1850             /* done with this header */
1851             lpMidiHdr->dwFlags |= MHDR_DONE;
1852             lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1853
1854             lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
1855             DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1856                            (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1857                            lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1858             lpData = 0;
1859         }
1860     }
1861 the_end:
1862     TRACE("End of thread\n");
1863     ExitThread(0);
1864     return 0;   /* for removing the warning, never executed */
1865 }
1866
1867 /**************************************************************************
1868  *                              MMSYSTEM_MidiStream_PostMessage [internal]
1869  */
1870 static  BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
1871 {
1872     if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
1873         DWORD   count;
1874
1875         ReleaseThunkLock(&count);
1876         WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1877         RestoreThunkLock(count);
1878     } else {
1879         WARN("bad PostThreadMessageA\n");
1880         return FALSE;
1881     }
1882     return TRUE;
1883 }
1884
1885 /**************************************************************************
1886  *                              midiStreamClose                 [WINMM.@]
1887  */
1888 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
1889 {
1890     WINE_MIDIStream*    lpMidiStrm;
1891
1892     TRACE("(%p)!\n", hMidiStrm);
1893
1894     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
1895         return MMSYSERR_INVALHANDLE;
1896
1897     midiStreamStop(hMidiStrm);
1898     MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
1899     HeapFree(GetProcessHeap(), 0, lpMidiStrm);
1900     CloseHandle(lpMidiStrm->hEvent);
1901
1902     return midiOutClose((HMIDIOUT)hMidiStrm);
1903 }
1904
1905 /**************************************************************************
1906  *                              MMSYSTEM_MidiStream_Open        [internal]
1907  */
1908 MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi,
1909                          DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen, 
1910                          BOOL bFrom32)
1911 {
1912     WINE_MIDIStream*    lpMidiStrm;
1913     MMRESULT            ret;
1914     MIDIOPENSTRMID      mosm;
1915     LPWINE_MIDI         lpwm;
1916     HMIDIOUT            hMidiOut;
1917
1918     TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1919           lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
1920
1921     if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
1922         return MMSYSERR_INVALPARAM;
1923
1924     lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
1925     if (!lpMidiStrm)
1926         return MMSYSERR_NOMEM;
1927
1928     lpMidiStrm->dwTempo = 500000;
1929     lpMidiStrm->dwTimeDiv = 480;        /* 480 is 120 quater notes per minute *//* FIXME ??*/
1930     lpMidiStrm->dwPositionMS = 0;
1931
1932     mosm.dwStreamID = (DWORD)lpMidiStrm;
1933     /* FIXME: the correct value is not allocated yet for MAPPER */
1934     mosm.wDeviceID  = *lpuDeviceID;
1935     lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
1936     lpMidiStrm->hDevice = hMidiOut;
1937     if (lphMidiStrm)
1938         *lphMidiStrm = (HMIDISTRM)hMidiOut;
1939
1940     /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
1941     FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
1942     lpwm->mld.uDeviceID = *lpuDeviceID = 0;
1943
1944     ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
1945     lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1946     lpMidiStrm->wFlags = HIWORD(fdwOpen);
1947
1948     lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
1949                                        lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
1950
1951     if (!lpMidiStrm->hThread) {
1952         midiStreamClose((HMIDISTRM)hMidiOut);
1953         return MMSYSERR_NOMEM;
1954     }
1955
1956     /* wait for thread to have started, and for its queue to be created */
1957     {
1958         DWORD   count;
1959
1960         /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1961          * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1962          * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1963          */
1964         ReleaseThunkLock(&count);
1965         WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1966         RestoreThunkLock(count);
1967     }
1968
1969     TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
1970           *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
1971     return ret;
1972 }
1973
1974 /**************************************************************************
1975  *                              midiStreamOpen                  [WINMM.@]
1976  */
1977 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
1978                                DWORD cMidi, DWORD dwCallback,
1979                                DWORD dwInstance, DWORD fdwOpen)
1980 {
1981     return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
1982                            dwInstance, fdwOpen, TRUE);
1983 }
1984
1985 /**************************************************************************
1986  *                              midiStreamOut                   [WINMM.@]
1987  */
1988 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
1989                               UINT cbMidiHdr)
1990 {
1991     WINE_MIDIStream*    lpMidiStrm;
1992     DWORD               ret = MMSYSERR_NOERROR;
1993
1994     TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
1995
1996     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
1997         ret = MMSYSERR_INVALHANDLE;
1998     } else if (!lpMidiHdr) {
1999         ret = MMSYSERR_INVALPARAM;
2000     } else {
2001         if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
2002                                 WINE_MSM_HEADER, cbMidiHdr,
2003                                 (DWORD)lpMidiHdr)) {
2004             WARN("bad PostThreadMessageA\n");
2005             ret = MMSYSERR_ERROR;
2006         }
2007     }
2008     return ret;
2009 }
2010
2011 /**************************************************************************
2012  *                              midiStreamPause                 [WINMM.@]
2013  */
2014 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
2015 {
2016     WINE_MIDIStream*    lpMidiStrm;
2017     DWORD               ret = MMSYSERR_NOERROR;
2018
2019     TRACE("(%p)!\n", hMidiStrm);
2020
2021     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2022         ret = MMSYSERR_INVALHANDLE;
2023     } else {
2024         if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2025             WARN("bad Suspend (%ld)\n", GetLastError());
2026             ret = MMSYSERR_ERROR;
2027         }
2028     }
2029     return ret;
2030 }
2031
2032 /**************************************************************************
2033  *                              midiStreamPosition              [WINMM.@]
2034  */
2035 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2036 {
2037     WINE_MIDIStream*    lpMidiStrm;
2038     DWORD               ret = MMSYSERR_NOERROR;
2039
2040     TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2041
2042     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2043         ret = MMSYSERR_INVALHANDLE;
2044     } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2045         ret = MMSYSERR_INVALPARAM;
2046     } else {
2047         switch (lpMMT->wType) {
2048         case TIME_MS:
2049             lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2050             TRACE("=> %ld ms\n", lpMMT->u.ms);
2051             break;
2052         case TIME_TICKS:
2053             lpMMT->u.ticks = lpMidiStrm->dwPulses;
2054             TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2055             break;
2056         default:
2057             WARN("Unsupported time type %d\n", lpMMT->wType);
2058             lpMMT->wType = TIME_MS;
2059             ret = MMSYSERR_INVALPARAM;
2060             break;
2061         }
2062     }
2063     return ret;
2064 }
2065
2066 /**************************************************************************
2067  *                              midiStreamProperty              [WINMM.@]
2068  */
2069 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2070 {
2071     WINE_MIDIStream*    lpMidiStrm;
2072     MMRESULT            ret = MMSYSERR_NOERROR;
2073
2074     TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2075
2076     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2077         ret = MMSYSERR_INVALHANDLE;
2078     } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2079         ret = MMSYSERR_INVALPARAM;
2080     } else if (dwProperty & MIDIPROP_TEMPO) {
2081         MIDIPROPTEMPO*  mpt = (MIDIPROPTEMPO*)lpPropData;
2082
2083         if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2084             ret = MMSYSERR_INVALPARAM;
2085         } else if (dwProperty & MIDIPROP_SET) {
2086             lpMidiStrm->dwTempo = mpt->dwTempo;
2087             TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2088         } else if (dwProperty & MIDIPROP_GET) {
2089             mpt->dwTempo = lpMidiStrm->dwTempo;
2090             TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2091         }
2092     } else if (dwProperty & MIDIPROP_TIMEDIV) {
2093         MIDIPROPTIMEDIV*        mptd = (MIDIPROPTIMEDIV*)lpPropData;
2094
2095         if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2096             ret = MMSYSERR_INVALPARAM;
2097         } else if (dwProperty & MIDIPROP_SET) {
2098             lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2099             TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2100         } else if (dwProperty & MIDIPROP_GET) {
2101             mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2102             TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2103         }
2104     } else {
2105         ret = MMSYSERR_INVALPARAM;
2106     }
2107
2108     return ret;
2109 }
2110
2111 /**************************************************************************
2112  *                              midiStreamRestart               [WINMM.@]
2113  */
2114 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2115 {
2116     WINE_MIDIStream*    lpMidiStrm;
2117     MMRESULT            ret = MMSYSERR_NOERROR;
2118
2119     TRACE("(%p)!\n", hMidiStrm);
2120
2121     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2122         ret = MMSYSERR_INVALHANDLE;
2123     } else {
2124         DWORD   ret;
2125
2126         /* since we increase the thread suspend count on each midiStreamPause
2127          * there may be a need for several midiStreamResume
2128          */
2129         do {
2130             ret = ResumeThread(lpMidiStrm->hThread);
2131         } while (ret != 0xFFFFFFFF && ret != 0);
2132         if (ret == 0xFFFFFFFF) {
2133             WARN("bad Resume (%ld)\n", GetLastError());
2134             ret = MMSYSERR_ERROR;
2135         } else {
2136             lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2137         }
2138     }
2139     return ret;
2140 }
2141
2142 /**************************************************************************
2143  *                              midiStreamStop                  [WINMM.@]
2144  */
2145 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2146 {
2147     WINE_MIDIStream*    lpMidiStrm;
2148     MMRESULT            ret = MMSYSERR_NOERROR;
2149
2150     TRACE("(%p)!\n", hMidiStrm);
2151
2152     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2153         ret = MMSYSERR_INVALHANDLE;
2154     } else {
2155         /* in case stream has been paused... FIXME is the current state correct ? */
2156         midiStreamRestart(hMidiStrm);
2157         MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2158     }
2159     return ret;
2160 }
2161
2162 UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, 
2163                const LPWAVEFORMATEX lpFormat, DWORD dwCallback, 
2164                DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2165 {
2166     HANDLE              handle;
2167     LPWINE_MLD          wmld;
2168     DWORD               dwRet = MMSYSERR_NOERROR;
2169     WAVEOPENDESC        wod;
2170
2171     TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2172           lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2173           dwInstance, dwFlags, bFrom32?32:16);
2174
2175     if (dwFlags & WAVE_FORMAT_QUERY)    TRACE("WAVE_FORMAT_QUERY requested !\n");
2176
2177     if (lpFormat == NULL) return WAVERR_BADFORMAT;
2178     if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
2179         return MMSYSERR_INVALPARAM;
2180
2181     TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2182           lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2183           lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
2184
2185     if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2186                             &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
2187         return MMSYSERR_NOMEM;
2188
2189     wod.hWave = handle;
2190     wod.lpFormat = lpFormat;  /* should the struct be copied iso pointer? */
2191     wod.dwCallback = dwCallback;
2192     wod.dwInstance = dwInstance;
2193     wod.dnDevNode = 0L;
2194
2195     TRACE("cb=%08lx\n", wod.dwCallback);
2196
2197     for (;;) {
2198         if (dwFlags & WAVE_MAPPED) {
2199             wod.uMappedDeviceID = uDeviceID;
2200             uDeviceID = WAVE_MAPPER;
2201         } else {
2202             wod.uMappedDeviceID = -1;
2203         }
2204         wmld->uDeviceID = uDeviceID;
2205     
2206         dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, 
2207                            (DWORD)&wod, dwFlags);
2208
2209         if (dwRet != WAVERR_BADFORMAT ||
2210             (dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) break;
2211         /* if we ask for a format which isn't supported by the physical driver, 
2212          * let's try to map it through the wave mapper (except, if we already tried
2213          * or user didn't allow us to use acm codecs)
2214          */
2215         dwFlags |= WAVE_MAPPED;
2216         /* we shall loop only one */
2217     }
2218
2219     if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2220         MMDRV_Free(handle, wmld);
2221         handle = 0;
2222     }
2223
2224     if (lphndl != NULL) *lphndl = handle;
2225     TRACE("=> %ld hWave=%p\n", dwRet, handle);
2226
2227     return dwRet;
2228 }
2229
2230 /**************************************************************************
2231  *                              waveOutGetNumDevs               [WINMM.@]
2232  */
2233 UINT WINAPI waveOutGetNumDevs(void)
2234 {
2235     return MMDRV_GetNum(MMDRV_WAVEOUT);
2236 }
2237
2238 /**************************************************************************
2239  *                              waveOutGetDevCapsA              [WINMM.@]
2240  */
2241 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
2242                                UINT uSize)
2243 {
2244     LPWINE_MLD          wmld;
2245
2246     TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2247
2248     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2249
2250     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2251         return MMSYSERR_BADDEVICEID;
2252
2253     return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2254
2255 }
2256
2257 /**************************************************************************
2258  *                              waveOutGetDevCapsW              [WINMM.@]
2259  */
2260 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
2261                                UINT uSize)
2262 {
2263     WAVEOUTCAPSA        wocA;
2264     UINT                ret;
2265
2266     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2267
2268     ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2269
2270     if (ret == MMSYSERR_NOERROR) {
2271         lpCaps->wMid = wocA.wMid;
2272         lpCaps->wPid = wocA.wPid;
2273         lpCaps->vDriverVersion = wocA.vDriverVersion;
2274         MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
2275                              sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2276         lpCaps->dwFormats = wocA.dwFormats;
2277         lpCaps->wChannels = wocA.wChannels;
2278         lpCaps->dwSupport = wocA.dwSupport;
2279     }
2280     return ret;
2281 }
2282
2283 /**************************************************************************
2284  *                              WAVE_GetErrorText               [internal]
2285  */
2286 static  UINT16  WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2287 {
2288     UINT16              ret = MMSYSERR_BADERRNUM;
2289
2290     if (lpText == NULL) {
2291         ret = MMSYSERR_INVALPARAM;
2292     } else if (uSize == 0) {
2293         ret = MMSYSERR_NOERROR;
2294     } else if (
2295                /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2296                 * a warning for the test was always true */
2297                (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2298                (uError >= WAVERR_BASE  && uError <= WAVERR_LASTERROR)) {
2299
2300         if (LoadStringA(WINMM_IData->hWinMM32Instance,
2301                         uError, lpText, uSize) > 0) {
2302             ret = MMSYSERR_NOERROR;
2303         }
2304     }
2305     return ret;
2306 }
2307
2308 /**************************************************************************
2309  *                              waveOutGetErrorTextA    [WINMM.@]
2310  */
2311 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2312 {
2313     return WAVE_GetErrorText(uError, lpText, uSize);
2314 }
2315
2316 /**************************************************************************
2317  *                              waveOutGetErrorTextW    [WINMM.@]
2318  */
2319 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2320 {
2321     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2322     UINT        ret = WAVE_GetErrorText(uError, xstr, uSize);
2323
2324     MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2325     HeapFree(GetProcessHeap(), 0, xstr);
2326     return ret;
2327 }
2328
2329 /**************************************************************************
2330  *                      waveOutOpen                     [WINMM.@]
2331  * All the args/structs have the same layout as the win16 equivalents
2332  */
2333 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
2334                         const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2335                         DWORD dwInstance, DWORD dwFlags)
2336 {
2337     return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2338                      dwCallback, dwInstance, dwFlags, TRUE);
2339 }
2340
2341 /**************************************************************************
2342  *                              waveOutClose            [WINMM.@]
2343  */
2344 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2345 {
2346     LPWINE_MLD          wmld;
2347     DWORD               dwRet;
2348
2349     TRACE("(%p)\n", hWaveOut);
2350
2351     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2352         return MMSYSERR_INVALHANDLE;
2353
2354     dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2355     MMDRV_Free(hWaveOut, wmld);
2356
2357     return dwRet;
2358 }
2359
2360 /**************************************************************************
2361  *                              waveOutPrepareHeader    [WINMM.@]
2362  */
2363 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2364                                  WAVEHDR* lpWaveOutHdr, UINT uSize)
2365 {
2366     LPWINE_MLD          wmld;
2367
2368     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2369
2370     if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
2371
2372     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2373         return MMSYSERR_INVALHANDLE;
2374
2375     return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2376 }
2377
2378 /**************************************************************************
2379  *                              waveOutUnprepareHeader  [WINMM.@]
2380  */
2381 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2382                                    LPWAVEHDR lpWaveOutHdr, UINT uSize)
2383 {
2384     LPWINE_MLD          wmld;
2385
2386     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2387
2388     if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2389         return MMSYSERR_NOERROR;
2390     }
2391
2392     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2393         return MMSYSERR_INVALHANDLE;
2394
2395     return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2396 }
2397
2398 /**************************************************************************
2399  *                              waveOutWrite            [WINMM.@]
2400  */
2401 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2402                          UINT uSize)
2403 {
2404     LPWINE_MLD          wmld;
2405
2406     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2407
2408     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2409         return MMSYSERR_INVALHANDLE;
2410
2411     return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2412 }
2413
2414 /**************************************************************************
2415  *                              waveOutBreakLoop        [WINMM.@]
2416  */
2417 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2418 {
2419     LPWINE_MLD          wmld;
2420
2421     TRACE("(%p);\n", hWaveOut);
2422
2423     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2424         return MMSYSERR_INVALHANDLE;
2425     return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2426 }
2427
2428 /**************************************************************************
2429  *                              waveOutPause            [WINMM.@]
2430  */
2431 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2432 {
2433     LPWINE_MLD          wmld;
2434
2435     TRACE("(%p);\n", hWaveOut);
2436
2437     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2438         return MMSYSERR_INVALHANDLE;
2439     return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2440 }
2441
2442 /**************************************************************************
2443  *                              waveOutReset            [WINMM.@]
2444  */
2445 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2446 {
2447     LPWINE_MLD          wmld;
2448
2449     TRACE("(%p);\n", hWaveOut);
2450
2451     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2452         return MMSYSERR_INVALHANDLE;
2453     return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2454 }
2455
2456 /**************************************************************************
2457  *                              waveOutRestart          [WINMM.@]
2458  */
2459 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2460 {
2461     LPWINE_MLD          wmld;
2462
2463     TRACE("(%p);\n", hWaveOut);
2464
2465     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2466         return MMSYSERR_INVALHANDLE;
2467     return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2468 }
2469
2470 /**************************************************************************
2471  *                              waveOutGetPosition      [WINMM.@]
2472  */
2473 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2474                                UINT uSize)
2475 {
2476     LPWINE_MLD          wmld;
2477
2478     TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
2479
2480     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2481         return MMSYSERR_INVALHANDLE;
2482
2483     return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2484 }
2485
2486 /**************************************************************************
2487  *                              waveOutGetPitch         [WINMM.@]
2488  */
2489 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2490 {
2491     LPWINE_MLD          wmld;
2492
2493     TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2494
2495     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2496         return MMSYSERR_INVALHANDLE;
2497     return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
2498 }
2499
2500 /**************************************************************************
2501  *                              waveOutSetPitch         [WINMM.@]
2502  */
2503 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2504 {
2505     LPWINE_MLD          wmld;
2506
2507     TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2508
2509     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2510         return MMSYSERR_INVALHANDLE;
2511     return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2512 }
2513
2514 /**************************************************************************
2515  *                              waveOutGetPlaybackRate  [WINMM.@]
2516  */
2517 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2518 {
2519     LPWINE_MLD          wmld;
2520
2521     TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2522
2523     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2524         return MMSYSERR_INVALHANDLE;
2525     return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
2526 }
2527
2528 /**************************************************************************
2529  *                              waveOutSetPlaybackRate  [WINMM.@]
2530  */
2531 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2532 {
2533     LPWINE_MLD          wmld;
2534
2535     TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2536
2537     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2538         return MMSYSERR_INVALHANDLE;
2539     return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2540 }
2541
2542 /**************************************************************************
2543  *                              waveOutGetVolume        [WINMM.@]
2544  */
2545 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
2546 {
2547     LPWINE_MLD          wmld;
2548
2549     TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2550
2551      if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2552         return MMSYSERR_INVALHANDLE;
2553
2554     return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
2555 }
2556
2557 /**************************************************************************
2558  *                              waveOutSetVolume        [WINMM.@]
2559  */
2560 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
2561 {
2562     LPWINE_MLD          wmld;
2563
2564     TRACE("(%p, %08lx);\n", hWaveOut, dw);
2565
2566      if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2567         return MMSYSERR_INVALHANDLE;
2568
2569     return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2570 }
2571
2572 /**************************************************************************
2573  *                              waveOutGetID            [WINMM.@]
2574  */
2575 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2576 {
2577     LPWINE_MLD          wmld;
2578
2579     TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
2580
2581     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2582
2583     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2584         return MMSYSERR_INVALHANDLE;
2585
2586     *lpuDeviceID = wmld->uDeviceID;
2587     return 0;
2588 }
2589
2590 /**************************************************************************
2591  *                              waveOutMessage          [WINMM.@]
2592  */
2593 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2594                             DWORD dwParam1, DWORD dwParam2)
2595 {
2596     LPWINE_MLD          wmld;
2597
2598     TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2599
2600     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2601         if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2602             return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2603         }
2604         return MMSYSERR_INVALHANDLE;
2605     }
2606
2607     /* from M$ KB */
2608     if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2609         return MMSYSERR_INVALPARAM;
2610
2611     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2612 }
2613
2614 /**************************************************************************
2615  *                              waveInGetNumDevs                [WINMM.@]
2616  */
2617 UINT WINAPI waveInGetNumDevs(void)
2618 {
2619     return MMDRV_GetNum(MMDRV_WAVEIN);
2620 }
2621
2622 /**************************************************************************
2623  *                              waveInGetDevCapsW               [WINMM.@]
2624  */
2625 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2626 {
2627     WAVEINCAPSA         wicA;
2628     UINT                ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
2629
2630     if (ret == MMSYSERR_NOERROR) {
2631         lpCaps->wMid = wicA.wMid;
2632         lpCaps->wPid = wicA.wPid;
2633         lpCaps->vDriverVersion = wicA.vDriverVersion;
2634         MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
2635                              sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2636         lpCaps->dwFormats = wicA.dwFormats;
2637         lpCaps->wChannels = wicA.wChannels;
2638     }
2639
2640     return ret;
2641 }
2642
2643 /**************************************************************************
2644  *                              waveInGetDevCapsA               [WINMM.@]
2645  */
2646 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2647 {
2648     LPWINE_MLD          wmld;
2649
2650     TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2651
2652     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
2653         return MMSYSERR_BADDEVICEID;
2654
2655     return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2656 }
2657
2658 /**************************************************************************
2659  *                              waveInGetErrorTextA     [WINMM.@]
2660  */
2661 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2662 {
2663     return WAVE_GetErrorText(uError, lpText, uSize);
2664 }
2665
2666 /**************************************************************************
2667  *                              waveInGetErrorTextW     [WINMM.@]
2668  */
2669 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2670 {
2671     LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
2672     UINT        ret = WAVE_GetErrorText(uError, txt, uSize);
2673
2674     MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
2675     HeapFree(GetProcessHeap(), 0, txt);
2676     return ret;
2677 }
2678
2679 /**************************************************************************
2680  *                              waveInOpen                      [WINMM.@]
2681  */
2682 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
2683                        const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2684                        DWORD dwInstance, DWORD dwFlags)
2685 {
2686     return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
2687                      dwCallback, dwInstance, dwFlags, TRUE);
2688 }
2689
2690 /**************************************************************************
2691  *                              waveInClose                     [WINMM.@]
2692  */
2693 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
2694 {
2695     LPWINE_MLD          wmld;
2696     DWORD               dwRet;
2697
2698     TRACE("(%p)\n", hWaveIn);
2699
2700     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2701         return MMSYSERR_INVALHANDLE;
2702
2703     dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
2704     MMDRV_Free(hWaveIn, wmld);
2705     return dwRet;
2706 }
2707
2708 /**************************************************************************
2709  *                              waveInPrepareHeader             [WINMM.@]
2710  */
2711 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2712                                 UINT uSize)
2713 {
2714     LPWINE_MLD          wmld;
2715
2716     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2717
2718     if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2719     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2720         return MMSYSERR_INVALHANDLE;
2721
2722     lpWaveInHdr->dwBytesRecorded = 0;
2723
2724     return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2725 }
2726
2727 /**************************************************************************
2728  *                              waveInUnprepareHeader   [WINMM.@]
2729  */
2730 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2731                                   UINT uSize)
2732 {
2733     LPWINE_MLD          wmld;
2734
2735     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2736
2737     if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2738     if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
2739         return MMSYSERR_NOERROR;
2740     }
2741
2742     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2743         return MMSYSERR_INVALHANDLE;
2744
2745     return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2746 }
2747
2748 /**************************************************************************
2749  *                              waveInAddBuffer         [WINMM.@]
2750  */
2751 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
2752                             WAVEHDR* lpWaveInHdr, UINT uSize)
2753 {
2754     LPWINE_MLD          wmld;
2755
2756     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2757
2758     if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2759     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2760         return MMSYSERR_INVALHANDLE;
2761
2762     return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
2763 }
2764
2765 /**************************************************************************
2766  *                              waveInReset             [WINMM.@]
2767  */
2768 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
2769 {
2770     LPWINE_MLD          wmld;
2771
2772     TRACE("(%p);\n", hWaveIn);
2773
2774     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2775         return MMSYSERR_INVALHANDLE;
2776
2777     return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
2778 }
2779
2780 /**************************************************************************
2781  *                              waveInStart             [WINMM.@]
2782  */
2783 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
2784 {
2785     LPWINE_MLD          wmld;
2786
2787     TRACE("(%p);\n", hWaveIn);
2788
2789     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2790         return MMSYSERR_INVALHANDLE;
2791
2792     return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
2793 }
2794
2795 /**************************************************************************
2796  *                              waveInStop              [WINMM.@]
2797  */
2798 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
2799 {
2800     LPWINE_MLD          wmld;
2801
2802     TRACE("(%p);\n", hWaveIn);
2803
2804     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2805         return MMSYSERR_INVALHANDLE;
2806
2807     return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
2808 }
2809
2810 /**************************************************************************
2811  *                              waveInGetPosition       [WINMM.@]
2812  */
2813 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
2814                               UINT uSize)
2815 {
2816     LPWINE_MLD          wmld;
2817
2818     TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
2819
2820     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2821         return MMSYSERR_INVALHANDLE;
2822
2823     return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2824 }
2825
2826 /**************************************************************************
2827  *                              waveInGetID                     [WINMM.@]
2828  */
2829 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
2830 {
2831     LPWINE_MLD          wmld;
2832
2833     TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
2834
2835     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2836
2837     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2838         return MMSYSERR_INVALHANDLE;
2839
2840     *lpuDeviceID = wmld->uDeviceID;
2841     return MMSYSERR_NOERROR;
2842 }
2843
2844 /**************************************************************************
2845  *                              waveInMessage           [WINMM.@]
2846  */
2847 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
2848                            DWORD dwParam1, DWORD dwParam2)
2849 {
2850     LPWINE_MLD          wmld;
2851
2852     TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
2853
2854     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
2855         if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
2856             return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2857         }
2858         return MMSYSERR_INVALHANDLE;
2859     }
2860
2861     /* from M$ KB */
2862     if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2863         return MMSYSERR_INVALPARAM;
2864
2865
2866     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2867 }