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