advapi32/tests: Test SystemFunction036.
[wine] / dlls / mmsystem.dll16 / mmsystem.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * MMSYSTEM functions
5  *
6  * Copyright 1993      Martin Ayotte
7  *           1998-2003 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 /*
25  * Eric POUECH :
26  *      99/4    added mmTask and mmThread functions support
27  */
28
29 #include <stdarg.h>
30 #include <string.h>
31
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "winbase.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "wownt32.h"
39 #include "winnls.h"
40
41 #include "wine/list.h"
42 #include "wine/winuser16.h"
43 #include "winemm16.h"
44
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(mmsys);
48
49
50 static CRITICAL_SECTION_DEBUG mmdrv_critsect_debug =
51 {
52     0, 0, &mmdrv_cs,
53     { &mmdrv_critsect_debug.ProcessLocksList, &mmdrv_critsect_debug.ProcessLocksList },
54       0, 0, { (DWORD_PTR)(__FILE__ ": mmsystem_mmdrv_cs") }
55 };
56 CRITICAL_SECTION mmdrv_cs = { &mmdrv_critsect_debug, -1, 0, 0, 0, 0 };
57
58 /* ###################################################
59  * #                  LIBRARY                        #
60  * ###################################################
61  */
62
63 /**************************************************************************
64  *                      DllEntryPoint (MMSYSTEM.4)
65  *
66  * MMSYSTEM DLL entry point
67  *
68  */
69 BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds,
70                              WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
71 {
72     static int done;
73
74     if (!done++) LoadLibrary16( "sound.drv" );
75     return TRUE;
76 }
77
78 /**************************************************************************
79  *                              WEP                     [MMSYSTEM.1]
80  */
81 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
82                         WORD cbHeapSize, LPSTR lpCmdLine)
83 {
84     TRACE("STUB: Unloading MMSystem DLL ... hInst=%04X\n", hInstance);
85     return TRUE;
86 }
87
88 /* ###################################################
89  * #                     TIME                        #
90  * ###################################################
91  */
92
93 /******************************************************************
94  *              MMSYSTEM_MMTIME32to16
95  *
96  *
97  */
98 void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
99 {
100     mmt16->wType = mmt32->wType;
101     /* layout of rest is the same for 32/16,
102      * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
103      */
104     memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
105 }
106
107 /******************************************************************
108  *              MMSYSTEM_MMTIME16to32
109  *
110  *
111  */
112 static void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
113 {
114     mmt32->wType = mmt16->wType;
115     /* layout of rest is the same for 32/16,
116      * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
117      */
118     memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
119 }
120
121 /**************************************************************************
122  *                              timeGetSystemTime       [MMSYSTEM.601]
123  */
124 MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize)
125 {
126     if (wSize >= sizeof(*lpTime)) {
127         lpTime->wType = TIME_MS;
128         lpTime->u.ms = GetTickCount();
129
130         TRACE("=> %u\n", lpTime->u.ms);
131     }
132
133     return 0;
134 }
135
136 struct timer_entry {
137     struct list         entry;
138     UINT                id;
139     LPTIMECALLBACK16    func16;
140     DWORD               user;
141 };
142
143 static struct list timer_list = LIST_INIT(timer_list);
144
145 static void CALLBACK timeCB3216(UINT id, UINT uMsg, DWORD_PTR user, DWORD_PTR dw1, DWORD_PTR dw2)
146 {
147     struct timer_entry* te = (void*)user;
148     WORD                args[8];
149     DWORD               ret;
150
151     args[7] = LOWORD(id);
152     args[6] = LOWORD(uMsg);
153     args[5] = HIWORD(te->user);
154     args[4] = LOWORD(te->user);
155     args[3] = HIWORD(dw1);
156     args[2] = LOWORD(dw2);
157     args[1] = HIWORD(dw2);
158     args[0] = LOWORD(dw2);
159     WOWCallback16Ex((DWORD)te->func16, WCB16_PASCAL, sizeof(args), args, &ret);
160 }
161
162 /**************************************************************************
163  *                              timeSetEvent            [MMSYSTEM.602]
164  */
165 MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, LPTIMECALLBACK16 lpFunc,
166                                  DWORD dwUser, UINT16 wFlags)
167 {
168     MMRESULT16          id;
169     struct timer_entry* te;
170
171     switch (wFlags & (TIME_CALLBACK_EVENT_SET|TIME_CALLBACK_EVENT_PULSE))
172     {
173     case TIME_CALLBACK_EVENT_SET:
174     case TIME_CALLBACK_EVENT_PULSE:
175         id = timeSetEvent(wDelay, wResol, (LPTIMECALLBACK)lpFunc, dwUser, wFlags);
176         break;
177     case TIME_CALLBACK_FUNCTION:
178         te = HeapAlloc(GetProcessHeap(), 0, sizeof(*te));
179         if (!te) return 0;
180         te->func16 = lpFunc;
181         te->user = dwUser;
182         id = te->id = timeSetEvent(wDelay, wResol, timeCB3216, (DWORD_PTR)te, wFlags);
183         if (id)
184         {
185             EnterCriticalSection(&mmdrv_cs);
186             list_add_tail(&timer_list, &te->entry);
187             LeaveCriticalSection(&mmdrv_cs);
188         }
189         else HeapFree(GetProcessHeap(), 0, te);
190         break;
191     default:
192         id = 0;
193         break;
194     }
195     return id;
196 }
197
198 /**************************************************************************
199  *                              timeKillEvent           [MMSYSTEM.603]
200  */
201 MMRESULT16 WINAPI timeKillEvent16(UINT16 wID)
202 {
203     MMRESULT16  ret = timeKillEvent(wID);
204     struct timer_entry* te;
205
206     if (ret == TIMERR_NOERROR)
207     {
208         EnterCriticalSection(&mmdrv_cs);
209         LIST_FOR_EACH_ENTRY(te, &timer_list, struct timer_entry, entry)
210         {
211             if (wID == te->id)
212             {
213                 list_remove(&te->entry);
214                 HeapFree(GetProcessHeap(), 0, te);
215                 break;
216             }
217         }
218         LeaveCriticalSection(&mmdrv_cs);
219     }
220     return ret;
221 }
222
223 /**************************************************************************
224  *                              timeGetDevCaps          [MMSYSTEM.604]
225  */
226 MMRESULT16 WINAPI timeGetDevCaps16(LPTIMECAPS16 lpCaps, UINT16 wSize)
227 {
228     TIMECAPS    caps;
229     MMRESULT    ret;
230     TRACE("(%p, %u) !\n", lpCaps, wSize);
231
232     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
233
234     ret = timeGetDevCaps(&caps, sizeof(caps));
235     if (ret == MMSYSERR_NOERROR) {
236         TIMECAPS16 tc16;
237         tc16.wPeriodMin = caps.wPeriodMin;
238         tc16.wPeriodMax = caps.wPeriodMax;
239         memcpy(lpCaps, &tc16, min(wSize, sizeof(tc16)));
240     }
241     return ret;
242 }
243
244 /**************************************************************************
245  *                              timeBeginPeriod [MMSYSTEM.605]
246  */
247 MMRESULT16 WINAPI timeBeginPeriod16(UINT16 wPeriod)
248 {
249     TRACE("(%u) !\n", wPeriod);
250
251     return timeBeginPeriod(wPeriod);
252 }
253
254 /**************************************************************************
255  *                              timeEndPeriod           [MMSYSTEM.606]
256  */
257 MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod)
258 {
259     TRACE("(%u) !\n", wPeriod);
260
261     return timeEndPeriod(wPeriod);
262 }
263
264 /**************************************************************************
265  *                              timeGetTime    [MMSYSTEM.607]
266  */
267 DWORD WINAPI timeGetTime16(void)
268 {
269     return timeGetTime();
270 }
271
272 /* ###################################################
273  * #                  PlaySound                      #
274  * ###################################################
275  */
276
277 /**************************************************************************
278  *                              PlaySound               [MMSYSTEM.3]
279  */
280 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
281 {
282     BOOL16      retv;
283     DWORD       lc;
284
285     if ((fdwSound & SND_RESOURCE) == SND_RESOURCE)
286     {
287         HGLOBAL16 handle;
288         HRSRC16 res;
289
290         if (!(res = FindResource16( hmod, pszSound, "WAVE" ))) return FALSE;
291         if (!(handle = LoadResource16( hmod, res ))) return FALSE;
292         pszSound = LockResource16(handle);
293         fdwSound = (fdwSound & ~SND_RESOURCE) | SND_MEMORY;
294         /* FIXME: FreeResource16 */
295     }
296
297     ReleaseThunkLock(&lc);
298     retv = PlaySoundA(pszSound, 0, fdwSound);
299     RestoreThunkLock(lc);
300
301     return retv;
302 }
303
304 /**************************************************************************
305  *                              sndPlaySound            [MMSYSTEM.2]
306  */
307 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
308 {
309     BOOL16      retv;
310     DWORD       lc;
311
312     ReleaseThunkLock(&lc);
313     retv = sndPlaySoundA(lpszSoundName, uFlags);
314     RestoreThunkLock(lc);
315
316     return retv;
317 }
318
319 /* ###################################################
320  * #                    MISC                         #
321  * ###################################################
322  */
323
324 /**************************************************************************
325  *                              mmsystemGetVersion      [MMSYSTEM.5]
326  *
327  */
328 UINT16 WINAPI mmsystemGetVersion16(void)
329 {
330     return mmsystemGetVersion();
331 }
332
333 /**************************************************************************
334  *                              DriverCallback                  [MMSYSTEM.31]
335  */
336 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev,
337                                WORD wMsg, DWORD dwUser, DWORD dwParam1,
338                                DWORD dwParam2)
339 {
340     return DriverCallback(dwCallBack, uFlags, HDRVR_32(hDev), wMsg, dwUser, dwParam1, dwParam2);
341 }
342
343 /**************************************************************************
344  *                      OutputDebugStr          [MMSYSTEM.30]
345  */
346 void WINAPI OutputDebugStr16(LPCSTR str)
347 {
348     OutputDebugStringA( str );
349 }
350
351 /* ###################################################
352  * #                    MIXER                        #
353  * ###################################################
354  */
355
356 /**************************************************************************
357  *      Mixer devices. New to Win95
358  */
359
360 /**************************************************************************
361  *                              mixerGetNumDevs                 [MMSYSTEM.800]
362  */
363 UINT16 WINAPI mixerGetNumDevs16(void)
364 {
365     return mixerGetNumDevs();
366 }
367
368 /**************************************************************************
369  *                              mixerGetDevCaps                 [MMSYSTEM.801]
370  */
371 UINT16 WINAPI mixerGetDevCaps16(UINT16 uDeviceID, LPMIXERCAPS16 lpCaps,
372                                 UINT16 uSize)
373 {
374     MIXERCAPSA  micA;
375     UINT        ret;
376
377     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
378
379     ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA));
380     if (ret == MMSYSERR_NOERROR) {
381         MIXERCAPS16 mic16;
382         mic16.wMid           = micA.wMid;
383         mic16.wPid           = micA.wPid;
384         mic16.vDriverVersion = micA.vDriverVersion;
385         strcpy(mic16.szPname, micA.szPname);
386         mic16.fdwSupport     = micA.fdwSupport;
387         mic16.cDestinations  = micA.cDestinations;
388         memcpy(lpCaps, &mic16, min(uSize, sizeof(mic16)));
389     }
390     return ret;
391 }
392
393 /**************************************************************************
394  *                              mixerOpen                       [MMSYSTEM.802]
395  */
396 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
397                           DWORD dwInstance, DWORD fdwOpen)
398 {
399     HMIXER                      hmix;
400     UINT                        ret;
401     struct mmsystdrv_thunk*     thunk;
402
403     if (!(thunk = MMSYSTDRV_AddThunk(dwCallback, MMSYSTDRV_MIXER)))
404     {
405         return MMSYSERR_NOMEM;
406     }
407     if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
408     {
409         dwCallback = (DWORD)thunk;
410     }
411
412     ret = mixerOpen(&hmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
413     if (ret == MMSYSERR_NOERROR)
414     {
415         if (lphmix) *lphmix = HMIXER_16(hmix);
416         if (thunk) MMSYSTDRV_SetHandle(thunk, hmix);
417     }
418     else MMSYSTDRV_DeleteThunk(thunk);
419     return ret;
420 }
421
422 /**************************************************************************
423  *                              mixerClose                      [MMSYSTEM.803]
424  */
425 UINT16 WINAPI mixerClose16(HMIXER16 hMix)
426 {
427     UINT        ret = mixerClose(HMIXER_32(hMix));
428
429     if (ret == MMSYSERR_NOERROR)
430         MMSYSTDRV_CloseHandle((void*)HMIXER_32(hMix));
431     return ret;
432 }
433
434 /**************************************************************************
435  *                              mixerGetID (MMSYSTEM.806)
436  */
437 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
438 {
439     UINT        xid;
440     UINT        ret = mixerGetID(HMIXEROBJ_32(hmix), &xid, fdwID);
441
442     if (lpid)
443         *lpid = xid;
444     return ret;
445 }
446
447 /**************************************************************************
448  *                              mixerGetControlDetails  [MMSYSTEM.808]
449  */
450 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix,
451                                        LPMIXERCONTROLDETAILS16 lpmcd,
452                                        DWORD fdwDetails)
453 {
454     DWORD       ret = MMSYSERR_NOTENABLED;
455     SEGPTR      sppaDetails;
456
457     TRACE("(%04x, %p, %08x)\n", hmix, lpmcd, fdwDetails);
458
459     if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
460         return MMSYSERR_INVALPARAM;
461
462     sppaDetails = (SEGPTR)lpmcd->paDetails;
463     lpmcd->paDetails = MapSL(sppaDetails);
464     ret = mixerGetControlDetailsA(HMIXEROBJ_32(hmix),
465                                  (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails);
466     lpmcd->paDetails = (LPVOID)sppaDetails;
467
468     return ret;
469 }
470
471 /**************************************************************************
472  *                              mixerGetLineControls            [MMSYSTEM.807]
473  */
474 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix,
475                                      LPMIXERLINECONTROLS16 lpmlc16,
476                                      DWORD fdwControls)
477 {
478     MIXERLINECONTROLSA  mlcA;
479     DWORD               ret;
480     unsigned int        i;
481     LPMIXERCONTROL16    lpmc16;
482
483     TRACE("(%04x, %p, %08x)\n", hmix, lpmlc16, fdwControls);
484
485     if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) ||
486         lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16))
487         return MMSYSERR_INVALPARAM;
488
489     mlcA.cbStruct = sizeof(mlcA);
490     mlcA.dwLineID = lpmlc16->dwLineID;
491     mlcA.u.dwControlID = lpmlc16->u.dwControlID;
492     mlcA.u.dwControlType = lpmlc16->u.dwControlType;
493     mlcA.cControls = lpmlc16->cControls;
494     mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
495     mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
496                               mlcA.cControls * mlcA.cbmxctrl);
497
498     ret = mixerGetLineControlsA(HMIXEROBJ_32(hmix), &mlcA, fdwControls);
499
500     if (ret == MMSYSERR_NOERROR) {
501         lpmlc16->dwLineID = mlcA.dwLineID;
502         lpmlc16->u.dwControlID = mlcA.u.dwControlID;
503         lpmlc16->u.dwControlType = mlcA.u.dwControlType;
504         lpmlc16->cControls = mlcA.cControls;
505
506         lpmc16 = MapSL(lpmlc16->pamxctrl);
507
508         for (i = 0; i < mlcA.cControls; i++) {
509             lpmc16[i].cbStruct = sizeof(MIXERCONTROL16);
510             lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
511             lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
512             lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
513             lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
514             strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName);
515             strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName);
516             /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
517             memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds,
518                    sizeof(mlcA.pamxctrl[i].Bounds));
519             /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
520             memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics,
521                    sizeof(mlcA.pamxctrl[i].Metrics));
522         }
523     }
524
525     HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
526
527     return ret;
528 }
529
530 /**************************************************************************
531  *                              mixerGetLineInfo        [MMSYSTEM.805]
532  */
533 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16,
534                                  DWORD fdwInfo)
535 {
536     MIXERLINEA          mliA;
537     UINT                ret;
538
539     TRACE("(%04x, %p, %08x)\n", hmix, lpmli16, fdwInfo);
540
541     if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16))
542         return MMSYSERR_INVALPARAM;
543
544     mliA.cbStruct = sizeof(mliA);
545     switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
546     case MIXER_GETLINEINFOF_COMPONENTTYPE:
547         mliA.dwComponentType = lpmli16->dwComponentType;
548         break;
549     case MIXER_GETLINEINFOF_DESTINATION:
550         mliA.dwDestination = lpmli16->dwDestination;
551         break;
552     case MIXER_GETLINEINFOF_LINEID:
553         mliA.dwLineID = lpmli16->dwLineID;
554         break;
555     case MIXER_GETLINEINFOF_SOURCE:
556         mliA.dwDestination = lpmli16->dwDestination;
557         mliA.dwSource = lpmli16->dwSource;
558         break;
559     case MIXER_GETLINEINFOF_TARGETTYPE:
560         mliA.Target.dwType = lpmli16->Target.dwType;
561         mliA.Target.wMid = lpmli16->Target.wMid;
562         mliA.Target.wPid = lpmli16->Target.wPid;
563         mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion;
564         strcpy(mliA.Target.szPname, lpmli16->Target.szPname);
565         break;
566     default:
567         FIXME("Unsupported fdwControls=0x%08x\n", fdwInfo);
568     }
569
570     ret = mixerGetLineInfoA(HMIXEROBJ_32(hmix), &mliA, fdwInfo);
571
572     lpmli16->dwDestination      = mliA.dwDestination;
573     lpmli16->dwSource           = mliA.dwSource;
574     lpmli16->dwLineID           = mliA.dwLineID;
575     lpmli16->fdwLine            = mliA.fdwLine;
576     lpmli16->dwUser             = mliA.dwUser;
577     lpmli16->dwComponentType    = mliA.dwComponentType;
578     lpmli16->cChannels          = mliA.cChannels;
579     lpmli16->cConnections       = mliA.cConnections;
580     lpmli16->cControls          = mliA.cControls;
581     strcpy(lpmli16->szShortName, mliA.szShortName);
582     strcpy(lpmli16->szName, mliA.szName);
583     lpmli16->Target.dwType      = mliA.Target.dwType;
584     lpmli16->Target.dwDeviceID  = mliA.Target.dwDeviceID;
585     lpmli16->Target.wMid        = mliA.Target.wMid;
586     lpmli16->Target.wPid        = mliA.Target.wPid;
587     lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion;
588     strcpy(lpmli16->Target.szPname, mliA.Target.szPname);
589
590     return ret;
591 }
592
593 /**************************************************************************
594  *                              mixerSetControlDetails  [MMSYSTEM.809]
595  */
596 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix,
597                                        LPMIXERCONTROLDETAILS16 lpmcd,
598                                        DWORD fdwDetails)
599 {
600     TRACE("(%04x, %p, %08x)\n", hmix, lpmcd, fdwDetails);
601     return MMSYSERR_NOTENABLED;
602 }
603
604 /**************************************************************************
605  *                              mixerMessage            [MMSYSTEM.804]
606  */
607 DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1,
608                              DWORD dwParam2)
609 {
610     return mixerMessage(HMIXER_32(hmix), uMsg, dwParam1, dwParam2);
611 }
612
613 /* ###################################################
614  * #                     AUX                         #
615  * ###################################################
616  */
617
618 /**************************************************************************
619  *                              auxGetNumDevs           [MMSYSTEM.350]
620  */
621 UINT16 WINAPI auxGetNumDevs16(void)
622 {
623     return auxGetNumDevs();
624 }
625
626 /**************************************************************************
627  *                              auxGetDevCaps           [MMSYSTEM.351]
628  */
629 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
630 {
631     AUXCAPSA  acA;
632     UINT      ret;
633
634     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
635
636     ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
637     if (ret == MMSYSERR_NOERROR) {
638         AUXCAPS16 ac16;
639         ac16.wMid           = acA.wMid;
640         ac16.wPid           = acA.wPid;
641         ac16.vDriverVersion = acA.vDriverVersion;
642         strcpy(ac16.szPname, acA.szPname);
643         ac16.wTechnology    = acA.wTechnology;
644         ac16.dwSupport      = acA.dwSupport;
645         memcpy(lpCaps, &ac16, min(uSize, sizeof(ac16)));
646     }
647     return ret;
648 }
649
650 /**************************************************************************
651  *                              auxGetVolume            [MMSYSTEM.352]
652  */
653 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume)
654 {
655     return auxGetVolume(uDeviceID, lpdwVolume);
656 }
657
658 /**************************************************************************
659  *                              auxSetVolume            [MMSYSTEM.353]
660  */
661 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
662 {
663     return auxSetVolume(uDeviceID, dwVolume);
664 }
665
666 /**************************************************************************
667  *                              auxOutMessage           [MMSYSTEM.354]
668  */
669 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
670 {
671     TRACE("(%04X, %04X, %08X, %08X)\n", uDeviceID, uMessage, dw1, dw2);
672
673     switch (uMessage) {
674     case AUXDM_GETNUMDEVS:
675     case AUXDM_SETVOLUME:
676         /* no argument conversion needed */
677         break;
678     case AUXDM_GETVOLUME:
679         return auxGetVolume(uDeviceID, MapSL(dw1));
680     case AUXDM_GETDEVCAPS:
681         return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2);
682     default:
683         TRACE("(%04x, %04x, %08x, %08x): unhandled message\n",
684               uDeviceID, uMessage, dw1, dw2);
685         break;
686     }
687     return auxOutMessage(uDeviceID, uMessage, dw1, dw2);
688 }
689
690 /* ###################################################
691  * #                     MIDI                        #
692  * ###################################################
693  */
694
695 /**************************************************************************
696  *                              midiOutGetNumDevs       [MMSYSTEM.201]
697  */
698 UINT16 WINAPI midiOutGetNumDevs16(void)
699 {
700     return midiOutGetNumDevs();
701 }
702
703 /**************************************************************************
704  *                              midiOutGetDevCaps       [MMSYSTEM.202]
705  */
706 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps,
707                                   UINT16 uSize)
708 {
709     MIDIOUTCAPSA        mocA;
710     UINT                ret;
711
712     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
713
714     ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
715     if (ret == MMSYSERR_NOERROR) {
716         MIDIOUTCAPS16 moc16;
717         moc16.wMid            = mocA.wMid;
718         moc16.wPid            = mocA.wPid;
719         moc16.vDriverVersion  = mocA.vDriverVersion;
720         strcpy(moc16.szPname, mocA.szPname);
721         moc16.wTechnology     = mocA.wTechnology;
722         moc16.wVoices         = mocA.wVoices;
723         moc16.wNotes          = mocA.wNotes;
724         moc16.wChannelMask    = mocA.wChannelMask;
725         moc16.dwSupport       = mocA.dwSupport;
726         memcpy(lpCaps, &moc16, min(uSize, sizeof(moc16)));
727     }
728     return ret;
729  }
730
731 /**************************************************************************
732  *                              midiOutGetErrorText     [MMSYSTEM.203]
733  *                              midiInGetErrorText      [MMSYSTEM.303]
734  */
735 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
736 {
737     return midiOutGetErrorTextA(uError, lpText, uSize);
738 }
739
740 /**************************************************************************
741  *                              midiOutOpen             [MMSYSTEM.204]
742  */
743 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
744                             DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
745 {
746     HMIDIOUT                    hmo;
747     UINT                        ret;
748     struct mmsystdrv_thunk*     thunk;
749
750     if (!(thunk = MMSYSTDRV_AddThunk(dwCallback, MMSYSTDRV_MIDIOUT)))
751     {
752         return MMSYSERR_NOMEM;
753     }
754     if ((dwFlags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
755     {
756         dwCallback = (DWORD)thunk;
757     }
758     ret = midiOutOpen(&hmo, uDeviceID, dwCallback, dwInstance, dwFlags);
759     if (ret == MMSYSERR_NOERROR)
760     {
761         if (lphMidiOut != NULL) *lphMidiOut = HMIDIOUT_16(hmo);
762         MMSYSTDRV_SetHandle(thunk, (void*)hmo);
763     }
764     else MMSYSTDRV_DeleteThunk(thunk);
765     return ret;
766 }
767
768 /**************************************************************************
769  *                              midiOutClose            [MMSYSTEM.205]
770  */
771 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
772 {
773     UINT        ret = midiOutClose(HMIDIOUT_32(hMidiOut));
774
775     if (ret == MMSYSERR_NOERROR)
776         MMSYSTDRV_CloseHandle((void*)HMIDIOUT_32(hMidiOut));
777     return ret;
778 }
779
780 /**************************************************************************
781  *                              midiOutPrepareHeader    [MMSYSTEM.206]
782  */
783 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut,         /* [in] */
784                                      SEGPTR lpsegMidiOutHdr,      /* [???] */
785                                      UINT16 uSize)                /* [in] */
786 {
787     TRACE("(%04X, %08x, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
788
789     return MMSYSTDRV_Message(HMIDIOUT_32(hMidiOut), MODM_PREPARE, lpsegMidiOutHdr, uSize);
790 }
791
792 /**************************************************************************
793  *                              midiOutUnprepareHeader  [MMSYSTEM.207]
794  */
795 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut,         /* [in] */
796                                        SEGPTR lpsegMidiOutHdr,      /* [???] */
797                                        UINT16 uSize)                /* [in] */
798 {
799     LPMIDIHDR16         lpMidiOutHdr = MapSL(lpsegMidiOutHdr);
800
801     TRACE("(%04X, %08x, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
802
803     if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
804         return MMSYSERR_NOERROR;
805     }
806
807     return MMSYSTDRV_Message(HMIDIOUT_32(hMidiOut), MODM_UNPREPARE, lpsegMidiOutHdr, uSize);
808 }
809
810 /**************************************************************************
811  *                              midiOutShortMsg         [MMSYSTEM.208]
812  */
813 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
814 {
815     return midiOutShortMsg(HMIDIOUT_32(hMidiOut), dwMsg);
816 }
817
818 /**************************************************************************
819  *                              midiOutLongMsg          [MMSYSTEM.209]
820  */
821 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut,          /* [in] */
822                                LPMIDIHDR16 lpsegMidiOutHdr,  /* [???] NOTE: SEGPTR */
823                                UINT16 uSize)                 /* [in] */
824 {
825     TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
826
827     return MMSYSTDRV_Message(HMIDIOUT_32(hMidiOut), MODM_LONGDATA, (DWORD_PTR)lpsegMidiOutHdr, uSize);
828 }
829
830 /**************************************************************************
831  *                              midiOutReset            [MMSYSTEM.210]
832  */
833 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
834 {
835     return midiOutReset(HMIDIOUT_32(hMidiOut));
836 }
837
838 /**************************************************************************
839  *                              midiOutGetVolume        [MMSYSTEM.211]
840  */
841 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
842 {
843     return midiOutGetVolume(HMIDIOUT_32(uDeviceID), lpdwVolume);
844 }
845
846 /**************************************************************************
847  *                              midiOutSetVolume        [MMSYSTEM.212]
848  */
849 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
850 {
851     return midiOutSetVolume(HMIDIOUT_32(uDeviceID), dwVolume);
852 }
853
854 /**************************************************************************
855  *                              midiOutCachePatches             [MMSYSTEM.213]
856  */
857 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
858                                     WORD* lpwPatchArray, UINT16 uFlags)
859 {
860     return midiOutCachePatches(HMIDIOUT_32(hMidiOut), uBank, lpwPatchArray,
861                                uFlags);
862 }
863
864 /**************************************************************************
865  *                              midiOutCacheDrumPatches [MMSYSTEM.214]
866  */
867 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
868                                         WORD* lpwKeyArray, UINT16 uFlags)
869 {
870     return midiOutCacheDrumPatches(HMIDIOUT_32(hMidiOut), uPatch, lpwKeyArray, uFlags);
871 }
872
873 /**************************************************************************
874  *                              midiOutGetID            [MMSYSTEM.215]
875  */
876 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
877 {
878     UINT        devid;
879     UINT16      ret;
880
881     ret = midiOutGetID(HMIDIOUT_32(hMidiOut), &devid);
882     if (ret != MMSYSERR_NOERROR) return ret;
883     *lpuDeviceID = devid;
884     return ret;
885 }
886
887 /**************************************************************************
888  *                              midiOutMessage          [MMSYSTEM.216]
889  */
890 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
891                               DWORD dwParam1, DWORD dwParam2)
892 {
893     TRACE("(%04X, %04X, %08X, %08X)\n", hMidiOut, uMessage, dwParam1, dwParam2);
894
895     switch (uMessage) {
896     case MODM_OPEN:
897     case MODM_CLOSE:
898         FIXME("can't handle OPEN or CLOSE message!\n");
899         return MMSYSERR_NOTSUPPORTED;
900
901     case MODM_GETVOLUME:
902         return midiOutGetVolume16(hMidiOut, MapSL(dwParam1));
903     case MODM_LONGDATA:
904         return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2);
905     case MODM_PREPARE:
906         /* lpMidiOutHdr is still a segmented pointer for this function */
907         return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2);
908     case MODM_UNPREPARE:
909         return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2);
910     }
911     return MMSYSTDRV_Message(HMIDIOUT_32(hMidiOut), uMessage, dwParam1, dwParam2);
912 }
913
914 /**************************************************************************
915  *                              midiInGetNumDevs        [MMSYSTEM.301]
916  */
917 UINT16 WINAPI midiInGetNumDevs16(void)
918 {
919     return midiInGetNumDevs();
920 }
921
922 /**************************************************************************
923  *                              midiInGetDevCaps        [MMSYSTEM.302]
924  */
925 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps,
926                                  UINT16 uSize)
927 {
928     MIDIINCAPSA         micA;
929     UINT                ret;
930
931     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
932
933     ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
934     if (ret == MMSYSERR_NOERROR) {
935         MIDIINCAPS16 mic16;
936         mic16.wMid           = micA.wMid;
937         mic16.wPid           = micA.wPid;
938         mic16.vDriverVersion = micA.vDriverVersion;
939         strcpy(mic16.szPname, micA.szPname);
940         mic16.dwSupport      = micA.dwSupport;
941         memcpy(lpCaps, &mic16, min(uSize, sizeof(mic16)));
942     }
943     return ret;
944 }
945
946 /**************************************************************************
947  *                              midiInOpen              [MMSYSTEM.304]
948  */
949 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
950                            DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
951 {
952     HMIDIIN     hmid;
953     UINT        ret;
954     struct mmsystdrv_thunk*     thunk;
955
956     if (!(thunk = MMSYSTDRV_AddThunk(dwCallback, MMSYSTDRV_MIDIIN)))
957     {
958         return MMSYSERR_NOMEM;
959     }
960     if ((dwFlags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
961     {
962         dwCallback = (DWORD)thunk;
963     }
964     ret = midiInOpen(&hmid, uDeviceID, dwCallback, dwInstance, dwFlags);
965     if (ret == MMSYSERR_NOERROR)
966     {
967         if (lphMidiIn) *lphMidiIn = HMIDIIN_16(hmid);
968         MMSYSTDRV_SetHandle(thunk, (void*)hmid);
969     }
970     else MMSYSTDRV_DeleteThunk(thunk);
971     return ret;
972 }
973
974 /**************************************************************************
975  *                              midiInClose             [MMSYSTEM.305]
976  */
977 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
978 {
979     UINT        ret = midiInClose(HMIDIIN_32(hMidiIn));
980
981     if (ret == MMSYSERR_NOERROR)
982         MMSYSTDRV_CloseHandle((void*)HMIDIIN_32(hMidiIn));
983     return ret;
984 }
985
986 /**************************************************************************
987  *                              midiInPrepareHeader     [MMSYSTEM.306]
988  */
989 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn,         /* [in] */
990                                     SEGPTR lpsegMidiInHdr,     /* [???] */
991                                     UINT16 uSize)              /* [in] */
992 {
993     TRACE("(%04X, %08x, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
994
995     return MMSYSTDRV_Message(HMIDIIN_32(hMidiIn), MIDM_PREPARE, lpsegMidiInHdr, uSize);
996 }
997
998 /**************************************************************************
999  *                              midiInUnprepareHeader   [MMSYSTEM.307]
1000  */
1001 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn,         /* [in] */
1002                                       SEGPTR lpsegMidiInHdr,     /* [???] */
1003                                       UINT16 uSize)              /* [in] */
1004 {
1005     LPMIDIHDR16         lpMidiInHdr = MapSL(lpsegMidiInHdr);
1006
1007     TRACE("(%04X, %08x, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
1008
1009     if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1010         return MMSYSERR_NOERROR;
1011     }
1012
1013     return MMSYSTDRV_Message(HMIDIIN_32(hMidiIn), MIDM_UNPREPARE, lpsegMidiInHdr, uSize);
1014 }
1015
1016 /**************************************************************************
1017  *                              midiInAddBuffer         [MMSYSTEM.308]
1018  */
1019 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn,         /* [in] */
1020                                 MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */
1021                                 UINT16 uSize)              /* [in] */
1022 {
1023     TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
1024
1025     return MMSYSTDRV_Message(HMIDIIN_32(hMidiIn), MIDM_ADDBUFFER, (DWORD_PTR)lpsegMidiInHdr, uSize);
1026 }
1027
1028 /**************************************************************************
1029  *                              midiInStart                     [MMSYSTEM.309]
1030  */
1031 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
1032 {
1033     return midiInStart(HMIDIIN_32(hMidiIn));
1034 }
1035
1036 /**************************************************************************
1037  *                              midiInStop                      [MMSYSTEM.310]
1038  */
1039 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
1040 {
1041     return midiInStop(HMIDIIN_32(hMidiIn));
1042 }
1043
1044 /**************************************************************************
1045  *                              midiInReset                     [MMSYSTEM.311]
1046  */
1047 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
1048 {
1049     return midiInReset(HMIDIIN_32(hMidiIn));
1050 }
1051
1052 /**************************************************************************
1053  *                              midiInGetID                     [MMSYSTEM.312]
1054  */
1055 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
1056 {
1057     UINT        devid;
1058     UINT16      ret;
1059
1060     ret = midiInGetID(HMIDIIN_32(hMidiIn), &devid);
1061     if (ret != MMSYSERR_NOERROR) return ret;
1062     *lpuDeviceID = devid;
1063     return ret;
1064 }
1065
1066 /**************************************************************************
1067  *                              midiInMessage           [MMSYSTEM.313]
1068  */
1069 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
1070                              DWORD dwParam1, DWORD dwParam2)
1071 {
1072     TRACE("(%04X, %04X, %08X, %08X)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1073
1074     switch (uMessage) {
1075     case MIDM_OPEN:
1076     case MIDM_CLOSE:
1077         FIXME("can't handle OPEN or CLOSE message!\n");
1078         return MMSYSERR_NOTSUPPORTED;
1079
1080     case MIDM_GETDEVCAPS:
1081         return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2);
1082     case MIDM_PREPARE:
1083         return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2);
1084     case MIDM_UNPREPARE:
1085         return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2);
1086     case MIDM_ADDBUFFER:
1087         return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2);
1088     }
1089     return MMSYSTDRV_Message(HMIDIIN_32(hMidiIn), uMessage, dwParam1, dwParam2);
1090 }
1091
1092 /**************************************************************************
1093  *                              midiStreamClose                 [MMSYSTEM.252]
1094  */
1095 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
1096 {
1097     UINT        ret = midiStreamClose(HMIDISTRM_32(hMidiStrm));
1098     if (ret == MMSYSERR_NOERROR)
1099         MMSYSTDRV_CloseHandle((void*)HMIDISTRM_32(hMidiStrm));
1100     return ret;
1101 }
1102
1103 /**************************************************************************
1104  *                              midiStreamOpen                  [MMSYSTEM.251]
1105  */
1106 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
1107                                    DWORD cMidi, DWORD dwCallback,
1108                                    DWORD dwInstance, DWORD fdwOpen)
1109 {
1110     HMIDISTRM                   hMidiStrm32;
1111     MMRESULT                    ret;
1112     UINT                        devid32;
1113     struct mmsystdrv_thunk*     thunk;
1114
1115     if (!phMidiStrm || !devid)
1116         return MMSYSERR_INVALPARAM;
1117     devid32 = *devid;
1118
1119     if (!(thunk = MMSYSTDRV_AddThunk(dwCallback, MMSYSTDRV_MIDIOUT)))
1120     {
1121         return MMSYSERR_NOMEM;
1122     }
1123     if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
1124     {
1125         dwCallback = (DWORD)thunk;
1126     }
1127     ret = midiStreamOpen(&hMidiStrm32, &devid32, cMidi, dwCallback, dwInstance, fdwOpen);
1128     if (ret == MMSYSERR_NOERROR)
1129     {
1130         *phMidiStrm = HMIDISTRM_16(hMidiStrm32);
1131         *devid = devid32;
1132         MMSYSTDRV_SetHandle(thunk, hMidiStrm32);
1133     }
1134     else MMSYSTDRV_DeleteThunk(thunk);
1135     return ret;
1136 }
1137
1138 /**************************************************************************
1139  *                              midiStreamOut                   [MMSYSTEM.254]
1140  */
1141 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
1142 {
1143     return midiStreamOut(HMIDISTRM_32(hMidiStrm), (LPMIDIHDR)lpMidiHdr,
1144                          cbMidiHdr);
1145 }
1146
1147 /**************************************************************************
1148  *                              midiStreamPause                 [MMSYSTEM.255]
1149  */
1150 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
1151 {
1152     return midiStreamPause(HMIDISTRM_32(hMidiStrm));
1153 }
1154
1155 /**************************************************************************
1156  *                              midiStreamPosition              [MMSYSTEM.253]
1157  */
1158 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
1159 {
1160     MMTIME      mmt32;
1161     MMRESULT    ret;
1162
1163     if (!lpmmt16)
1164         return MMSYSERR_INVALPARAM;
1165     MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
1166     ret = midiStreamPosition(HMIDISTRM_32(hMidiStrm), &mmt32, sizeof(MMTIME));
1167     MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
1168     return ret;
1169 }
1170
1171 /**************************************************************************
1172  *                              midiStreamProperty              [MMSYSTEM.250]
1173  */
1174 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
1175 {
1176     return midiStreamProperty(HMIDISTRM_32(hMidiStrm), lpPropData, dwProperty);
1177 }
1178
1179 /**************************************************************************
1180  *                              midiStreamRestart               [MMSYSTEM.256]
1181  */
1182 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
1183 {
1184     return midiStreamRestart(HMIDISTRM_32(hMidiStrm));
1185 }
1186
1187 /**************************************************************************
1188  *                              midiStreamStop                  [MMSYSTEM.257]
1189  */
1190 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
1191 {
1192     return midiStreamStop(HMIDISTRM_32(hMidiStrm));
1193 }
1194
1195 /* ###################################################
1196  * #                     WAVE                        #
1197  * ###################################################
1198  */
1199
1200 /**************************************************************************
1201  *                              waveOutGetNumDevs               [MMSYSTEM.401]
1202  */
1203 UINT16 WINAPI waveOutGetNumDevs16(void)
1204 {
1205     return waveOutGetNumDevs();
1206 }
1207
1208 /**************************************************************************
1209  *                              waveOutGetDevCaps               [MMSYSTEM.402]
1210  */
1211 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID,
1212                                   LPWAVEOUTCAPS16 lpCaps, UINT16 uSize)
1213 {
1214     WAVEOUTCAPSA        wocA;
1215     UINT                ret;
1216     TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
1217
1218     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1219
1220     ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
1221     if (ret == MMSYSERR_NOERROR) {
1222         WAVEOUTCAPS16 woc16;
1223         woc16.wMid           = wocA.wMid;
1224         woc16.wPid           = wocA.wPid;
1225         woc16.vDriverVersion = wocA.vDriverVersion;
1226         strcpy(woc16.szPname, wocA.szPname);
1227         woc16.dwFormats      = wocA.dwFormats;
1228         woc16.wChannels      = wocA.wChannels;
1229         woc16.dwSupport      = wocA.dwSupport;
1230         memcpy(lpCaps, &woc16, min(uSize, sizeof(woc16)));
1231     }
1232     return ret;
1233 }
1234
1235 /**************************************************************************
1236  *                              waveOutGetErrorText     [MMSYSTEM.403]
1237  *                              waveInGetErrorText      [MMSYSTEM.503]
1238  */
1239 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
1240 {
1241     return waveOutGetErrorTextA(uError, lpText, uSize);
1242 }
1243
1244 /**************************************************************************
1245  *                      waveOutOpen                     [MMSYSTEM.404]
1246  */
1247 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
1248                             LPCWAVEFORMATEX lpFormat, DWORD dwCallback,
1249                             DWORD dwInstance, DWORD dwFlags)
1250 {
1251     HWAVEOUT                    hWaveOut;
1252     UINT                        ret;
1253     struct mmsystdrv_thunk*     thunk;
1254
1255     if (!(thunk = MMSYSTDRV_AddThunk(dwCallback, MMSYSTDRV_WAVEOUT)))
1256     {
1257         return MMSYSERR_NOMEM;
1258     }
1259     if ((dwFlags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
1260     {
1261         dwCallback = (DWORD)thunk;
1262     }
1263     /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
1264      * call the 32 bit version
1265      * however, we need to promote correctly the wave mapper id
1266      * (0xFFFFFFFF and not 0x0000FFFF)
1267      */
1268     ret = waveOutOpen(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
1269                       lpFormat, dwCallback, dwInstance, dwFlags);
1270
1271     if (ret == MMSYSERR_NOERROR)
1272     {
1273         if (lphWaveOut != NULL) *lphWaveOut = HWAVEOUT_16(hWaveOut);
1274         MMSYSTDRV_SetHandle(thunk, (void*)hWaveOut);
1275     }
1276     else MMSYSTDRV_DeleteThunk(thunk);
1277     return ret;
1278 }
1279
1280 /**************************************************************************
1281  *                              waveOutClose            [MMSYSTEM.405]
1282  */
1283 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
1284 {
1285     DWORD       level;
1286     UINT16      ret;
1287
1288     ReleaseThunkLock(&level);
1289     ret = waveOutClose(HWAVEOUT_32(hWaveOut));
1290     RestoreThunkLock(level);
1291     if (ret == MMSYSERR_NOERROR)
1292         MMSYSTDRV_CloseHandle((void*)HWAVEOUT_32(hWaveOut));
1293     return ret;
1294 }
1295
1296 /**************************************************************************
1297  *                              waveOutPrepareHeader    [MMSYSTEM.406]
1298  */
1299 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut,      /* [in] */
1300                                      SEGPTR lpsegWaveOutHdr,   /* [???] */
1301                                      UINT16 uSize)             /* [in] */
1302 {
1303     LPWAVEHDR           lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
1304     UINT16              result;
1305
1306     TRACE("(%04X, %08x, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
1307
1308     if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
1309
1310     if ((result = MMSYSTDRV_Message(HWAVEOUT_32(hWaveOut), WODM_PREPARE, lpsegWaveOutHdr,
1311                                     uSize)) != MMSYSERR_NOTSUPPORTED)
1312         return result;
1313
1314     if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
1315         return WAVERR_STILLPLAYING;
1316
1317     lpWaveOutHdr->dwFlags |= WHDR_PREPARED;
1318     lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
1319
1320     return MMSYSERR_NOERROR;
1321 }
1322
1323 /**************************************************************************
1324  *                              waveOutUnprepareHeader  [MMSYSTEM.407]
1325  */
1326 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut,       /* [in] */
1327                                        SEGPTR lpsegWaveOutHdr,    /* [???] */
1328                                        UINT16 uSize)              /* [in] */
1329 {
1330     LPWAVEHDR           lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
1331
1332     TRACE("(%04X, %08x, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
1333
1334     if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
1335         return MMSYSERR_NOERROR;
1336     }
1337
1338     return MMSYSTDRV_Message(HWAVEOUT_32(hWaveOut), WODM_UNPREPARE, lpsegWaveOutHdr, uSize);
1339 }
1340
1341 /**************************************************************************
1342  *                              waveOutWrite            [MMSYSTEM.408]
1343  */
1344 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut,       /* [in] */
1345                              LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */
1346                              UINT16 uSize)              /* [in] */
1347 {
1348     TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
1349
1350     return MMSYSTDRV_Message(HWAVEOUT_32(hWaveOut), WODM_WRITE, (DWORD_PTR)lpsegWaveOutHdr, uSize);
1351 }
1352
1353 /**************************************************************************
1354  *                              waveOutBreakLoop        [MMSYSTEM.419]
1355  */
1356 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16)
1357 {
1358     DWORD       level;
1359     UINT16      ret;
1360
1361     ReleaseThunkLock(&level);
1362     ret = waveOutBreakLoop(HWAVEOUT_32(hWaveOut16));
1363     RestoreThunkLock(level);
1364     return ret;
1365 }
1366
1367 /**************************************************************************
1368  *                              waveOutPause            [MMSYSTEM.409]
1369  */
1370 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16)
1371 {
1372     DWORD       level;
1373     UINT16      ret;
1374
1375     ReleaseThunkLock(&level);
1376     ret = waveOutPause(HWAVEOUT_32(hWaveOut16));
1377     RestoreThunkLock(level);
1378     return ret;
1379 }
1380
1381 /**************************************************************************
1382  *                              waveOutReset            [MMSYSTEM.411]
1383  */
1384 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16)
1385 {
1386     DWORD       level;
1387     UINT16      ret;
1388
1389     ReleaseThunkLock(&level);
1390     ret = waveOutReset(HWAVEOUT_32(hWaveOut16));
1391     RestoreThunkLock(level);
1392     return ret;
1393 }
1394
1395 /**************************************************************************
1396  *                              waveOutRestart  [MMSYSTEM.410]
1397  */
1398 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16)
1399 {
1400     DWORD       level;
1401     UINT16      ret;
1402
1403     ReleaseThunkLock(&level);
1404     ret = waveOutRestart(HWAVEOUT_32(hWaveOut16));
1405     RestoreThunkLock(level);
1406     return ret;
1407 }
1408
1409 /**************************************************************************
1410  *                              waveOutGetPosition      [MMSYSTEM.412]
1411  */
1412 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
1413                                    UINT16 uSize)
1414 {
1415     UINT        ret;
1416     MMTIME      mmt;
1417
1418     mmt.wType = lpTime->wType;
1419     ret = waveOutGetPosition(HWAVEOUT_32(hWaveOut), &mmt, sizeof(mmt));
1420     MMSYSTEM_MMTIME32to16(lpTime, &mmt);
1421     return ret;
1422 }
1423
1424 /**************************************************************************
1425  *                              waveOutGetPitch         [MMSYSTEM.413]
1426  */
1427 UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
1428 {
1429     return waveOutGetPitch(HWAVEOUT_32(hWaveOut16), lpdw);
1430 }
1431
1432 /**************************************************************************
1433  *                              waveOutSetPitch         [MMSYSTEM.414]
1434  */
1435 UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw)
1436 {
1437     return waveOutSetPitch(HWAVEOUT_32(hWaveOut16), dw);
1438 }
1439
1440 /**************************************************************************
1441  *                              waveOutGetPlaybackRate  [MMSYSTEM.417]
1442  */
1443 UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
1444 {
1445     return waveOutGetPlaybackRate(HWAVEOUT_32(hWaveOut16), lpdw);
1446 }
1447
1448 /**************************************************************************
1449  *                              waveOutSetPlaybackRate  [MMSYSTEM.418]
1450  */
1451 UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw)
1452 {
1453     return waveOutSetPlaybackRate(HWAVEOUT_32(hWaveOut16), dw);
1454 }
1455
1456 /**************************************************************************
1457  *                              waveOutGetVolume        [MMSYSTEM.415]
1458  */
1459 UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw)
1460 {
1461     return waveOutGetVolume(HWAVEOUT_32(devid), lpdw);
1462 }
1463
1464 /**************************************************************************
1465  *                              waveOutSetVolume        [MMSYSTEM.416]
1466  */
1467 UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw)
1468 {
1469     return waveOutSetVolume(HWAVEOUT_32(devid), dw);
1470 }
1471
1472 /**************************************************************************
1473  *                              waveOutGetID            [MMSYSTEM.420]
1474  */
1475 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
1476 {
1477     UINT        devid;
1478     UINT16      ret;
1479
1480     ret = waveOutGetID(HWAVEOUT_32(hWaveOut), &devid);
1481     if (ret != MMSYSERR_NOERROR) return ret;
1482     *lpuDeviceID = devid;
1483     return ret;
1484 }
1485
1486 /**************************************************************************
1487  *                              waveOutMessage          [MMSYSTEM.421]
1488  */
1489 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
1490                               DWORD dwParam1, DWORD dwParam2)
1491 {
1492     TRACE("(%04x, %u, %d, %d)\n", hWaveOut, uMessage, dwParam1, dwParam2);
1493
1494     if ((DWORD_PTR)hWaveOut < waveOutGetNumDevs())
1495     {
1496         if (uMessage == DRV_QUERYDRVENTRY || uMessage == DRV_QUERYDEVNODE)
1497             dwParam1 = (DWORD)MapSL(dwParam1);
1498     }
1499     else if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
1500         /* from M$ KB */
1501         return MMSYSERR_INVALPARAM;
1502
1503     return MMSYSTDRV_Message(HWAVEOUT_32(hWaveOut), uMessage, dwParam1, dwParam2);
1504 }
1505
1506 /**************************************************************************
1507  *                              waveInGetNumDevs                [MMSYSTEM.501]
1508  */
1509 UINT16 WINAPI waveInGetNumDevs16(void)
1510 {
1511     return waveInGetNumDevs();
1512 }
1513
1514 /**************************************************************************
1515  *                              waveInGetDevCaps                [MMSYSTEM.502]
1516  */
1517 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps,
1518                                  UINT16 uSize)
1519 {
1520     WAVEINCAPSA wicA;
1521     UINT        ret;
1522
1523     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1524
1525     ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
1526     if (ret == MMSYSERR_NOERROR) {
1527         WAVEINCAPS16 wic16;
1528         wic16.wMid           = wicA.wMid;
1529         wic16.wPid           = wicA.wPid;
1530         wic16.vDriverVersion = wicA.vDriverVersion;
1531         strcpy(wic16.szPname, wicA.szPname);
1532         wic16.dwFormats      = wicA.dwFormats;
1533         wic16.wChannels      = wicA.wChannels;
1534         memcpy(lpCaps, &wic16, min(uSize, sizeof(wic16)));
1535     }
1536     return ret;
1537 }
1538
1539 /**************************************************************************
1540  *                              waveInOpen                      [MMSYSTEM.504]
1541  */
1542 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
1543                            LPCWAVEFORMATEX lpFormat, DWORD dwCallback,
1544                            DWORD dwInstance, DWORD dwFlags)
1545 {
1546     HWAVEIN                     hWaveIn;
1547     UINT                        ret;
1548     struct mmsystdrv_thunk*     thunk;
1549
1550     if (!(thunk = MMSYSTDRV_AddThunk(dwCallback, MMSYSTDRV_WAVEIN)))
1551     {
1552         return MMSYSERR_NOMEM;
1553     }
1554     if ((dwFlags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
1555     {
1556         dwCallback = (DWORD)thunk;
1557     }
1558     /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
1559      * call the 32 bit version
1560      * however, we need to promote correctly the wave mapper id
1561      * (0xFFFFFFFF and not 0x0000FFFF)
1562      */
1563     ret = waveInOpen(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
1564                      lpFormat, dwCallback, dwInstance, dwFlags);
1565
1566     if (ret == MMSYSERR_NOERROR)
1567     {
1568         if (lphWaveIn != NULL) *lphWaveIn = HWAVEIN_16(hWaveIn);
1569         MMSYSTDRV_SetHandle(thunk, (void*)hWaveIn);
1570     }
1571     else MMSYSTDRV_DeleteThunk(thunk);
1572     return ret;
1573 }
1574
1575 /**************************************************************************
1576  *                              waveInClose                     [MMSYSTEM.505]
1577  */
1578 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
1579 {
1580     DWORD       level;
1581     UINT16      ret;
1582
1583     ReleaseThunkLock(&level);
1584     ret = waveInClose(HWAVEIN_32(hWaveIn));
1585     RestoreThunkLock(level);
1586     if (ret == MMSYSERR_NOERROR)
1587         MMSYSTDRV_CloseHandle((void*)HWAVEIN_32(hWaveIn));
1588     return ret;
1589 }
1590
1591 /**************************************************************************
1592  *                              waveInPrepareHeader             [MMSYSTEM.506]
1593  */
1594 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn,       /* [in] */
1595                                     SEGPTR lpsegWaveInHdr,   /* [???] */
1596                                     UINT16 uSize)            /* [in] */
1597 {
1598     LPWAVEHDR           lpWaveInHdr = MapSL(lpsegWaveInHdr);
1599     UINT16              ret;
1600
1601     TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
1602
1603     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
1604     lpWaveInHdr->dwBytesRecorded = 0;
1605
1606     ret = MMSYSTDRV_Message(HWAVEIN_32(hWaveIn), WIDM_PREPARE, lpsegWaveInHdr, uSize);
1607     return ret;
1608 }
1609
1610 /**************************************************************************
1611  *                              waveInUnprepareHeader   [MMSYSTEM.507]
1612  */
1613 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn,       /* [in] */
1614                                       SEGPTR lpsegWaveInHdr,   /* [???] */
1615                                       UINT16 uSize)            /* [in] */
1616 {
1617     LPWAVEHDR           lpWaveInHdr = MapSL(lpsegWaveInHdr);
1618
1619     TRACE("(%04X, %08x, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
1620
1621     if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
1622
1623     if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
1624         return MMSYSERR_NOERROR;
1625     }
1626
1627     return MMSYSTDRV_Message(HWAVEIN_32(hWaveIn), WIDM_UNPREPARE, lpsegWaveInHdr, uSize);
1628 }
1629
1630 /**************************************************************************
1631  *                              waveInAddBuffer         [MMSYSTEM.508]
1632  */
1633 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn,       /* [in] */
1634                                 WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */
1635                                 UINT16 uSize)            /* [in] */
1636 {
1637     TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
1638
1639     if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
1640
1641     return MMSYSTDRV_Message(HWAVEIN_32(hWaveIn), WIDM_ADDBUFFER, (DWORD_PTR)lpsegWaveInHdr, uSize);
1642 }
1643
1644 /**************************************************************************
1645  *                              waveInReset             [MMSYSTEM.511]
1646  */
1647 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16)
1648 {
1649     DWORD       level;
1650     UINT16      ret;
1651
1652     ReleaseThunkLock(&level);
1653     ret = waveInReset(HWAVEIN_32(hWaveIn16));
1654     RestoreThunkLock(level);
1655     return ret;
1656 }
1657
1658 /**************************************************************************
1659  *                              waveInStart             [MMSYSTEM.509]
1660  */
1661 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16)
1662 {
1663     DWORD       level;
1664     UINT16      ret;
1665
1666     ReleaseThunkLock(&level);
1667     ret = waveInStart(HWAVEIN_32(hWaveIn16));
1668     RestoreThunkLock(level);
1669     return ret;
1670 }
1671
1672 /**************************************************************************
1673  *                              waveInStop              [MMSYSTEM.510]
1674  */
1675 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16)
1676 {
1677     DWORD       level;
1678     UINT16      ret;
1679
1680     ReleaseThunkLock(&level);
1681     ret = waveInStop(HWAVEIN_32(hWaveIn16));
1682     RestoreThunkLock(level);
1683     return ret;
1684 }
1685
1686 /**************************************************************************
1687  *                              waveInGetPosition       [MMSYSTEM.512]
1688  */
1689 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
1690                                   UINT16 uSize)
1691 {
1692     UINT        ret;
1693     MMTIME      mmt;
1694
1695     mmt.wType = lpTime->wType;
1696     ret = waveInGetPosition(HWAVEIN_32(hWaveIn), &mmt, sizeof(mmt));
1697     MMSYSTEM_MMTIME32to16(lpTime, &mmt);
1698     return ret;
1699 }
1700
1701 /**************************************************************************
1702  *                              waveInGetID                     [MMSYSTEM.513]
1703  */
1704 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
1705 {
1706     UINT        devid;
1707     UINT16      ret;
1708
1709     ret = waveInGetID(HWAVEIN_32(hWaveIn), &devid);
1710     if (ret != MMSYSERR_NOERROR) return ret;
1711     *lpuDeviceID = devid;
1712     return ret;
1713 }
1714
1715 /**************************************************************************
1716  *                              waveInMessage           [MMSYSTEM.514]
1717  */
1718 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
1719                              DWORD dwParam1, DWORD dwParam2)
1720 {
1721     TRACE("(%04x, %u, %d, %d)\n", hWaveIn, uMessage, dwParam1, dwParam2);
1722
1723     if ((DWORD_PTR)hWaveIn < waveInGetNumDevs())
1724     {
1725         if (uMessage == DRV_QUERYDRVENTRY || uMessage == DRV_QUERYDEVNODE)
1726             dwParam1 = (DWORD)MapSL(dwParam1);
1727     }
1728     else if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
1729         /* from M$ KB */
1730         return MMSYSERR_INVALPARAM;
1731
1732     return MMSYSTDRV_Message(HWAVEIN_32(hWaveIn), uMessage, dwParam1, dwParam2);
1733 }
1734
1735 /* ###################################################
1736  * #                     TASK                        #
1737  * ###################################################
1738  */
1739
1740 /*#define USE_MM_TSK_WINE*/
1741
1742 /**************************************************************************
1743  *                              mmTaskCreate            [MMSYSTEM.900]
1744  *
1745  * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
1746  * called upon creation with dwPmt as parameter.
1747  */
1748 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
1749 {
1750     HINSTANCE16         ret;
1751     HINSTANCE16         handle;
1752     char cmdline[16];
1753     DWORD showCmd = 0x40002;
1754     LOADPARAMS16 lp;
1755
1756     TRACE("(%08x, %p, %08x);\n", spProc, lphMmTask, dwPmt);
1757     /* This to work requires NE modules to be started with a binary command line
1758      * which is not currently the case. A patch exists but has never been committed.
1759      * A workaround would be to integrate code for mmtask.tsk into Wine, but
1760      * this requires tremendous work (starting with patching tools/build to
1761      * create NE executables (and not only DLLs) for builtins modules.
1762      * EP 99/04/25
1763      */
1764     FIXME("This is currently broken. It will fail\n");
1765
1766     cmdline[0] = 0x0d;
1767     *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
1768     *(LPDWORD)(cmdline + 5) = dwPmt;
1769     *(LPDWORD)(cmdline + 9) = 0;
1770
1771     lp.hEnvironment = 0;
1772     lp.cmdLine = MapLS(cmdline);
1773     lp.showCmd = MapLS(&showCmd);
1774     lp.reserved = 0;
1775
1776 #ifndef USE_MM_TSK_WINE
1777     handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp);
1778 #else
1779     handle = LoadModule16("mmtask.tsk", &lp);
1780 #endif
1781     if (handle < 32) {
1782         ret = (handle) ? 1 : 2;
1783         handle = 0;
1784     } else {
1785         ret = 0;
1786     }
1787     if (lphMmTask)
1788         *lphMmTask = handle;
1789
1790     UnMapLS( lp.cmdLine );
1791     UnMapLS( lp.showCmd );
1792     TRACE("=> 0x%04x/%d\n", handle, ret);
1793     return ret;
1794 }
1795
1796 #ifdef USE_MM_TSK_WINE
1797 /* C equivalent to mmtask.tsk binary content */
1798 void    mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
1799 {
1800     int len = cmdLine[0x80];
1801
1802     if (len / 2 == 6) {
1803         void    (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1)));
1804         DWORD   dwPmt  = *((DWORD*)(cmdLine + 5));
1805
1806 #if 0
1807         InitTask16(); /* FIXME: pmts / from context ? */
1808         InitApp(di);
1809 #endif
1810         if (SetMessageQueue16(0x40)) {
1811             WaitEvent16(0);
1812             if (HIWORD(fpProc)) {
1813                 OldYield16();
1814 /* EPP          StackEnter16(); */
1815                 (fpProc)(dwPmt);
1816             }
1817         }
1818     }
1819     OldYield16();
1820     OldYield16();
1821     OldYield16();
1822     ExitProcess(0);
1823 }
1824 #endif
1825
1826 /**************************************************************************
1827  *                              mmTaskBlock             [MMSYSTEM.902]
1828  */
1829 void WINAPI mmTaskBlock16(HINSTANCE16 hInst)
1830 {
1831     MSG         msg;
1832
1833     do {
1834         GetMessageA(&msg, 0, 0, 0);
1835         if (msg.hwnd) {
1836             TranslateMessage(&msg);
1837             DispatchMessageA(&msg);
1838         }
1839     } while (msg.message < 0x3A0);
1840 }
1841
1842 /**************************************************************************
1843  *                              mmTaskSignal            [MMSYSTEM.903]
1844  */
1845 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
1846 {
1847     TRACE("(%04x);\n", ht);
1848     return PostThreadMessageW( HTASK_32(ht), WM_USER, 0, 0 );
1849 }
1850
1851 /**************************************************************************
1852  *                              mmGetCurrentTask        [MMSYSTEM.904]
1853  */
1854 HTASK16 WINAPI mmGetCurrentTask16(void)
1855 {
1856     return GetCurrentTask();
1857 }
1858
1859 /**************************************************************************
1860  *                              mmTaskYield             [MMSYSTEM.905]
1861  */
1862 void    WINAPI  mmTaskYield16(void)
1863 {
1864     MSG         msg;
1865
1866     if (PeekMessageA(&msg, 0, 0, 0, 0)) {
1867         WOWYield16();
1868     }
1869 }
1870
1871 /******************************************************************
1872  *              WINMM_GetmmThread
1873  *
1874  *
1875  */
1876 static  WINE_MMTHREAD*  WINMM_GetmmThread(HANDLE16 h)
1877 {
1878     return MapSL(MAKESEGPTR(h, 0));
1879 }
1880
1881 static  void    MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
1882 {
1883     MSG         msg;
1884     DWORD       ret;
1885
1886     if (lpMMThd->dwThreadID != GetCurrentThreadId())
1887         ERR("Not called by thread itself\n");
1888
1889     for (;;) {
1890         ResetEvent(lpMMThd->hEvent);
1891         if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
1892             break;
1893         InterlockedIncrement(&lpMMThd->dwSignalCount);
1894
1895         TRACE("S1\n");
1896
1897         ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
1898         switch (ret) {
1899         case WAIT_OBJECT_0:     /* Event */
1900             TRACE("S2.1\n");
1901             break;
1902         case WAIT_OBJECT_0 + 1: /* Msg */
1903             TRACE("S2.2\n");
1904             if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
1905                 TranslateMessage(&msg);
1906                 DispatchMessageA(&msg);
1907             }
1908             break;
1909         default:
1910             WARN("S2.x unsupported ret val 0x%08x\n", ret);
1911         }
1912         TRACE("S3\n");
1913     }
1914 }
1915
1916 /**************************************************************************
1917  *                              mmThreadBlock           [MMSYSTEM.1122]
1918  */
1919 void    WINAPI mmThreadBlock16(HANDLE16 hndl)
1920 {
1921     TRACE("(%04x)!\n", hndl);
1922
1923     if (hndl) {
1924         WINE_MMTHREAD*  lpMMThd = WINMM_GetmmThread(hndl);
1925
1926         if (lpMMThd->hThread != 0) {
1927             DWORD       lc;
1928
1929             ReleaseThunkLock(&lc);
1930             MMSYSTEM_ThreadBlock(lpMMThd);
1931             RestoreThunkLock(lc);
1932         } else {
1933             mmTaskBlock16(lpMMThd->hTask);
1934         }
1935     }
1936     TRACE("done\n");
1937 }
1938
1939 /**************************************************************************
1940  *                              __wine_mmThreadEntryPoint (MMSYSTEM.2047)
1941  */
1942 DWORD WINAPI WINE_mmThreadEntryPoint(LPVOID p)
1943 {
1944     HANDLE16            hndl = (HANDLE16)(DWORD_PTR)p;
1945     WINE_MMTHREAD*      lpMMThd = WINMM_GetmmThread(hndl);
1946
1947     TRACE("(%04x %p)\n", hndl, lpMMThd);
1948
1949     lpMMThd->hTask = LOWORD(GetCurrentTask());
1950     TRACE("[10-%p] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
1951     lpMMThd->dwStatus = 0x10;
1952     MMSYSTEM_ThreadBlock(lpMMThd);
1953     TRACE("[20-%p]\n", lpMMThd->hThread);
1954     lpMMThd->dwStatus = 0x20;
1955     if (lpMMThd->fpThread) {
1956         WOWCallback16(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
1957     }
1958     lpMMThd->dwStatus = 0x30;
1959     TRACE("[30-%p]\n", lpMMThd->hThread);
1960     while (lpMMThd->dwCounter) {
1961         Sleep(1);
1962         /* WOWYield16();*/
1963     }
1964     TRACE("[XX-%p]\n", lpMMThd->hThread);
1965     /* paranoia */
1966     lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
1967     /* close lpMMThread->hVxD directIO */
1968     if (lpMMThd->hEvent)
1969         CloseHandle(lpMMThd->hEvent);
1970     GlobalFree16(hndl);
1971     TRACE("done\n");
1972
1973     return 0;
1974 }
1975
1976 extern DWORD    WINAPI  GetProcessFlags(DWORD);
1977
1978 /**************************************************************************
1979  *                              mmThreadCreate          [MMSYSTEM.1120]
1980  *
1981  * undocumented
1982  * Creates a MM thread, calling fpThreadAddr(dwPmt).
1983  * dwFlags:
1984  *      bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
1985  *      bit.1 set means to open a VxD for this thread (unsupported)
1986  */
1987 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE16 lpHndl, DWORD dwPmt, DWORD dwFlags)
1988 {
1989     HANDLE16            hndl;
1990     LRESULT             ret;
1991
1992     TRACE("(%p, %p, %08x, %08x)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
1993
1994     hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
1995
1996     if (hndl == 0) {
1997         ret = 2;
1998     } else {
1999         WINE_MMTHREAD*  lpMMThd = WINMM_GetmmThread(hndl);
2000
2001 #if 0
2002         /* force mmtask routines even if mmthread is required */
2003         /* this will work only if the patch about binary cmd line and NE tasks
2004          * is committed
2005          */
2006         dwFlags |= 1;
2007 #endif
2008
2009         lpMMThd->dwSignature    = WINE_MMTHREAD_CREATED;
2010         lpMMThd->dwCounter      = 0;
2011         lpMMThd->hThread        = 0;
2012         lpMMThd->dwThreadID     = 0;
2013         lpMMThd->fpThread       = (DWORD)fpThreadAddr;
2014         lpMMThd->dwThreadPmt    = dwPmt;
2015         lpMMThd->dwSignalCount  = 0;
2016         lpMMThd->hEvent         = 0;
2017         lpMMThd->hVxD           = 0;
2018         lpMMThd->dwStatus       = 0;
2019         lpMMThd->dwFlags        = dwFlags;
2020         lpMMThd->hTask          = 0;
2021
2022         if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
2023             lpMMThd->hEvent = CreateEventW(NULL, FALSE, TRUE, NULL);
2024
2025             TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
2026             if (lpMMThd->dwFlags & 2) {
2027                 /* as long as we don't support MM VxD in wine, we don't need
2028                  * to care about this flag
2029                  */
2030                 /* FIXME("Don't know how to properly open VxD handles\n"); */
2031                 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
2032             }
2033
2034             lpMMThd->hThread = CreateThread(0, 0, WINE_mmThreadEntryPoint,
2035                                             (LPVOID)(DWORD_PTR)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
2036             if (lpMMThd->hThread == 0) {
2037                 WARN("Couldn't create thread\n");
2038                 /* clean-up(VxDhandle...); devicedirectio... */
2039                 if (lpMMThd->hEvent != 0)
2040                     CloseHandle(lpMMThd->hEvent);
2041                 ret = 2;
2042             } else {
2043                 SetThreadPriority(lpMMThd->hThread, THREAD_PRIORITY_TIME_CRITICAL);
2044                 TRACE("Got a nice thread hndl=%p id=0x%08x\n", lpMMThd->hThread, lpMMThd->dwThreadID);
2045                 ret = 0;
2046             }
2047         } else {
2048             /* get WINE_mmThreadEntryPoint()
2049              * 2047 is its ordinal in mmsystem.spec
2050              */
2051             FARPROC16   fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047);
2052
2053             TRACE("farproc seg=0x%p lin=%p\n", fp, MapSL((SEGPTR)fp));
2054
2055             ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
2056         }
2057
2058         if (ret == 0) {
2059             if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
2060                 WARN("Couldn't resume thread\n");
2061
2062             while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
2063                 MSG msg;
2064                 PeekMessageW( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
2065             }
2066         }
2067     }
2068
2069     if (ret != 0) {
2070         GlobalFree16(hndl);
2071         hndl = 0;
2072     }
2073
2074     if (lpHndl)
2075         *lpHndl = hndl;
2076
2077     TRACE("ok => %ld\n", ret);
2078     return ret;
2079 }
2080
2081 /**************************************************************************
2082  *                              mmThreadSignal          [MMSYSTEM.1121]
2083  */
2084 void WINAPI mmThreadSignal16(HANDLE16 hndl)
2085 {
2086     TRACE("(%04x)!\n", hndl);
2087
2088     if (hndl) {
2089         WINE_MMTHREAD*  lpMMThd = WINMM_GetmmThread(hndl);
2090
2091         lpMMThd->dwCounter++;
2092         if (lpMMThd->hThread != 0) {
2093             InterlockedIncrement(&lpMMThd->dwSignalCount);
2094             SetEvent(lpMMThd->hEvent);
2095         } else {
2096             mmTaskSignal16(lpMMThd->hTask);
2097         }
2098         lpMMThd->dwCounter--;
2099     }
2100 }
2101
2102 /**************************************************************************
2103  *                              mmThreadIsCurrent       [MMSYSTEM.1123]
2104  */
2105 BOOL16  WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
2106 {
2107     BOOL16              ret = FALSE;
2108
2109     TRACE("(%04x)!\n", hndl);
2110
2111     if (hndl && mmThreadIsValid16(hndl)) {
2112         WINE_MMTHREAD*  lpMMThd = WINMM_GetmmThread(hndl);
2113         ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
2114     }
2115     TRACE("=> %d\n", ret);
2116     return ret;
2117 }
2118
2119 /**************************************************************************
2120  *                              mmThreadIsValid         [MMSYSTEM.1124]
2121  */
2122 BOOL16  WINAPI  mmThreadIsValid16(HANDLE16 hndl)
2123 {
2124     BOOL16              ret = FALSE;
2125
2126     TRACE("(%04x)!\n", hndl);
2127
2128     if (hndl) {
2129         WINE_MMTHREAD*  lpMMThd = WINMM_GetmmThread(hndl);
2130
2131         if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
2132             lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
2133             IsTask16(lpMMThd->hTask)) {
2134             lpMMThd->dwCounter++;
2135             if (lpMMThd->hThread != 0) {
2136                 DWORD   dwThreadRet;
2137                 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
2138                     dwThreadRet == STATUS_PENDING) {
2139                     ret = TRUE;
2140                 }
2141             } else {
2142                 ret = TRUE;
2143             }
2144             lpMMThd->dwCounter--;
2145         }
2146     }
2147     TRACE("=> %d\n", ret);
2148     return ret;
2149 }
2150
2151 /**************************************************************************
2152  *                              mmThreadGetTask         [MMSYSTEM.1125]
2153  */
2154 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
2155 {
2156     HANDLE16    ret = 0;
2157
2158     TRACE("(%04x)\n", hndl);
2159
2160     if (mmThreadIsValid16(hndl)) {
2161         WINE_MMTHREAD*  lpMMThd = WINMM_GetmmThread(hndl);
2162         ret = lpMMThd->hTask;
2163     }
2164     return ret;
2165 }
2166
2167 typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR);
2168
2169 /**************************************************************************
2170  *                      mmShowMMCPLPropertySheet        [MMSYSTEM.1150]
2171  */
2172 BOOL16  WINAPI  mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice,
2173                                            LPCSTR lpStrTab, LPCSTR lpStrTitle)
2174 {
2175     HANDLE      hndl;
2176     BOOL16      ret = FALSE;
2177
2178     TRACE("(%p \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
2179
2180     hndl = LoadLibraryA("MMSYS.CPL");
2181     if (hndl != 0) {
2182         MMCPLCALLBACK   fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
2183         if (fp != NULL) {
2184             DWORD       lc;
2185             ReleaseThunkLock(&lc);
2186             ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
2187             RestoreThunkLock(lc);
2188         }
2189         FreeLibrary(hndl);
2190     }
2191
2192     return ret;
2193 }
2194
2195 /**************************************************************************
2196  *                      StackEnter              [MMSYSTEM.32]
2197  */
2198 void WINAPI StackEnter16(void)
2199 {
2200 #ifdef __i386__
2201     /* mmsystem.dll from Win 95 does only this: so does Wine */
2202     __asm__("stc");
2203 #endif
2204 }
2205
2206 /**************************************************************************
2207  *                      StackLeave              [MMSYSTEM.33]
2208  */
2209 void WINAPI StackLeave16(void)
2210 {
2211 #ifdef __i386__
2212     /* mmsystem.dll from Win 95 does only this: so does Wine */
2213     __asm__("stc");
2214 #endif
2215 }
2216
2217 /**************************************************************************
2218  *                      WMMMidiRunOnce          [MMSYSTEM.8]
2219  */
2220 void WINAPI WMMMidiRunOnce16(void)
2221 {
2222     FIXME("(), stub!\n");
2223 }
2224
2225
2226
2227 /* ###################################################
2228  * #                     JOYSTICK                    #
2229  * ###################################################
2230  */
2231
2232 /**************************************************************************
2233  *                              joyGetNumDevs           [MMSYSTEM.101]
2234  */
2235 UINT16 WINAPI joyGetNumDevs16(void)
2236 {
2237     return joyGetNumDevs();
2238 }
2239
2240 /**************************************************************************
2241  *                              joyGetDevCaps           [MMSYSTEM.102]
2242  */
2243 MMRESULT16 WINAPI joyGetDevCaps16(UINT16 wID, LPJOYCAPS16 lpCaps, UINT16 wSize)
2244 {
2245     JOYCAPSA    jca;
2246     MMRESULT    ret;
2247
2248     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2249
2250     ret = joyGetDevCapsA(wID, &jca, sizeof(jca));
2251
2252     if (ret != JOYERR_NOERROR) return ret;
2253     lpCaps->wMid = jca.wMid;
2254     lpCaps->wPid = jca.wPid;
2255     strcpy(lpCaps->szPname, jca.szPname);
2256     lpCaps->wXmin = jca.wXmin;
2257     lpCaps->wXmax = jca.wXmax;
2258     lpCaps->wYmin = jca.wYmin;
2259     lpCaps->wYmax = jca.wYmax;
2260     lpCaps->wZmin = jca.wZmin;
2261     lpCaps->wZmax = jca.wZmax;
2262     lpCaps->wNumButtons = jca.wNumButtons;
2263     lpCaps->wPeriodMin = jca.wPeriodMin;
2264     lpCaps->wPeriodMax = jca.wPeriodMax;
2265
2266     if (wSize >= sizeof(JOYCAPS16)) { /* Win95 extensions ? */
2267         lpCaps->wRmin = jca.wRmin;
2268         lpCaps->wRmax = jca.wRmax;
2269         lpCaps->wUmin = jca.wUmin;
2270         lpCaps->wUmax = jca.wUmax;
2271         lpCaps->wVmin = jca.wVmin;
2272         lpCaps->wVmax = jca.wVmax;
2273         lpCaps->wCaps = jca.wCaps;
2274         lpCaps->wMaxAxes = jca.wMaxAxes;
2275         lpCaps->wNumAxes = jca.wNumAxes;
2276         lpCaps->wMaxButtons = jca.wMaxButtons;
2277         strcpy(lpCaps->szRegKey, jca.szRegKey);
2278         strcpy(lpCaps->szOEMVxD, jca.szOEMVxD);
2279     }
2280
2281     return ret;
2282 }
2283
2284 /**************************************************************************
2285  *                              joyGetPosEx           [MMSYSTEM.110]
2286  */
2287 MMRESULT16 WINAPI joyGetPosEx16(UINT16 wID, LPJOYINFOEX lpInfo)
2288 {
2289     return joyGetPosEx(wID, lpInfo);
2290 }
2291
2292 /**************************************************************************
2293  *                              joyGetPos               [MMSYSTEM.103]
2294  */
2295 MMRESULT16 WINAPI joyGetPos16(UINT16 wID, LPJOYINFO16 lpInfo)
2296 {
2297     JOYINFO     ji;
2298     MMRESULT    ret;
2299
2300     TRACE("(%d, %p);\n", wID, lpInfo);
2301
2302     if ((ret = joyGetPos(wID, &ji)) == JOYERR_NOERROR) {
2303         lpInfo->wXpos = ji.wXpos;
2304         lpInfo->wYpos = ji.wYpos;
2305         lpInfo->wZpos = ji.wZpos;
2306         lpInfo->wButtons = ji.wButtons;
2307     }
2308     return ret;
2309 }
2310
2311 /**************************************************************************
2312  *                              joyGetThreshold         [MMSYSTEM.104]
2313  */
2314 MMRESULT16 WINAPI joyGetThreshold16(UINT16 wID, LPUINT16 lpThreshold)
2315 {
2316     UINT        t;
2317     MMRESULT    ret;
2318
2319     ret = joyGetThreshold(wID, &t);
2320     if (ret == JOYERR_NOERROR)
2321         *lpThreshold = t;
2322     return ret;
2323 }
2324
2325 /**************************************************************************
2326  *                              joyReleaseCapture       [MMSYSTEM.105]
2327  */
2328 MMRESULT16 WINAPI joyReleaseCapture16(UINT16 wID)
2329 {
2330     return joyReleaseCapture(wID);
2331 }
2332
2333 /**************************************************************************
2334  *                              joySetCapture           [MMSYSTEM.106]
2335  */
2336 MMRESULT16 WINAPI joySetCapture16(HWND16 hWnd, UINT16 wID, UINT16 wPeriod, BOOL16 bChanged)
2337 {
2338     return joySetCapture(HWND_32(hWnd), wID, wPeriod, bChanged);
2339 }
2340
2341 /**************************************************************************
2342  *                              joySetThreshold         [MMSYSTEM.107]
2343  */
2344 MMRESULT16 WINAPI joySetThreshold16(UINT16 wID, UINT16 wThreshold)
2345 {
2346     return joySetThreshold(wID,wThreshold);
2347 }
2348
2349 /**************************************************************************
2350  *                              joySetCalibration       [MMSYSTEM.109]
2351  */
2352 MMRESULT16 WINAPI joySetCalibration16(UINT16 wID)
2353 {
2354     FIXME("(%04X): stub.\n", wID);
2355     return JOYERR_NOCANDO;
2356 }