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