Moved all MCI internal functions/variables/macros to mci.c.
[wine] / multimedia / mmsystem.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * MMSYTEM functions
5  *
6  * Copyright 1993 Martin Ayotte
7  */
8
9 /* 
10  * Eric POUECH : 
11  * 98/9 added support for Win32 MCI
12  */
13
14 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses 
15  *        and long term pointers to 16 bit space in here
16  */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <sys/ioctl.h>
23
24 #include "winbase.h"
25 #include "windef.h"
26 #include "wine/winbase16.h"
27 #include "heap.h"
28 #include "user.h"
29 #include "driver.h"
30 #include "multimedia.h"
31 #include "callback.h"
32 #include "module.h"
33 #include "selectors.h"
34 #include "debugstr.h"
35 #include "debug.h"
36
37 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
38 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
39 LONG   WINAPI DrvDefDriverProc(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg, 
40                                DWORD dwParam1, DWORD dwParam2);
41
42 /**************************************************************************
43  *                              MMSYSTEM_WEP            [MMSYSTEM.1]
44  */
45 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
46                         WORD cbHeapSize, LPSTR lpCmdLine)
47 {
48     FIXME(mmsys, "STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
49     return(TRUE);
50 }
51
52 static void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, LPMMTIME mmt32) 
53 {
54     mmt16->wType = mmt32->wType;
55     /* layout of rest is the same for 32/16 */
56     memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
57 }
58
59 static void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, LPMMTIME16 mmt16) 
60 {
61     mmt32->wType = mmt16->wType;
62     /* layout of rest is the same for 32/16,
63      * Note: mmt16->u is 2 bytes smaller than mmt32->u
64      */
65     memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
66 }
67
68 static HANDLE           PlaySound_hThread = 0;
69 static HANDLE           PlaySound_hPlayEvent = 0;
70 static HANDLE           PlaySound_hReadyEvent = 0;
71 static HANDLE           PlaySound_hMiddleEvent = 0;
72 static BOOL             PlaySound_Result = FALSE;
73 static int              PlaySound_Stop = FALSE;
74 static int              PlaySound_Playing = FALSE;
75
76 static LPCSTR           PlaySound_pszSound = NULL;
77 static HMODULE          PlaySound_hmod = 0;
78 static DWORD            PlaySound_fdwSound = 0;
79 static int              PlaySound_Loop = FALSE;
80 static int              PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
81                                                      2 - PlaySound order */
82
83 static HMMIO16  get_mmioFromFile(LPCSTR lpszName)
84 {
85     return mmioOpen16((LPSTR)lpszName, NULL,
86                       MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
87 }
88
89 static HMMIO16 get_mmioFromProfile(UINT uFlags, LPCSTR lpszName) 
90 {
91     char        str[128];
92     LPSTR       ptr;
93     HMMIO16     hmmio;
94     
95     TRACE(mmsys, "searching in SystemSound List !\n");
96     GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
97     if (strlen(str) == 0) {
98         if (uFlags & SND_NODEFAULT) return 0;
99         GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
100         if (strlen(str) == 0) return 0;
101     }
102     if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
103     hmmio = get_mmioFromFile(str);
104     if (hmmio == 0) {
105         WARN(mmsys, "can't find SystemSound='%s' !\n", str);
106         return 0;
107     }
108     return hmmio;
109 }
110
111 static BOOL16 WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
112 {
113     BOOL16              bRet = FALSE;
114     HMMIO16             hmmio;
115     MMCKINFO            ckMainRIFF;
116     
117     TRACE(mmsys, "SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
118     if (lpszSoundName == NULL) {
119         TRACE(mmsys, "Stop !\n");
120         return FALSE;
121     }
122     if (uFlags & SND_MEMORY) {
123         MMIOINFO16 mminfo;
124         memset(&mminfo, 0, sizeof(mminfo));
125         mminfo.fccIOProc = FOURCC_MEM;
126         mminfo.pchBuffer = (LPSTR)lpszSoundName;
127         mminfo.cchBuffer = -1;
128         TRACE(mmsys, "Memory sound %p\n", lpszSoundName);
129         hmmio = mmioOpen16(NULL, &mminfo, MMIO_READ);
130     } else {
131         hmmio = 0;
132         if (uFlags & SND_ALIAS)
133             if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) 
134                 return FALSE;
135         
136         if (uFlags & SND_FILENAME)
137             if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
138         
139         if (PlaySound_SearchMode == 1) {
140             PlaySound_SearchMode = 0;
141             if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) 
142                 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) 
143                     return FALSE;
144         }
145         
146         if (PlaySound_SearchMode == 2) {
147             PlaySound_SearchMode = 0;
148             if ((hmmio=get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0) 
149                 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0)       
150                     if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) return FALSE;
151         }
152     }
153     
154     if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0) == 0) 
155         do {
156             TRACE(mmsys, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
157                   (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, 
158                   ckMainRIFF.cksize);
159             
160             if ((ckMainRIFF.ckid == FOURCC_RIFF) &&
161                 (ckMainRIFF.fccType == mmioFOURCC('W', 'A', 'V', 'E'))) {
162                 MMCKINFO        mmckInfo;
163                 
164                 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
165                 
166                 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
167                     PCMWAVEFORMAT           pcmWaveFormat;
168                     
169                     TRACE(mmsys, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
170                           (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
171                     
172                     if (mmioRead(hmmio, (HPSTR)&pcmWaveFormat,
173                                    (long) sizeof(PCMWAVEFORMAT)) == (long) sizeof(PCMWAVEFORMAT)) {
174                         TRACE(mmsys, "wFormatTag=%04X !\n", pcmWaveFormat.wf.wFormatTag);
175                         TRACE(mmsys, "nChannels=%d \n", pcmWaveFormat.wf.nChannels);
176                         TRACE(mmsys, "nSamplesPerSec=%ld\n", pcmWaveFormat.wf.nSamplesPerSec);
177                         TRACE(mmsys, "nAvgBytesPerSec=%ld\n", pcmWaveFormat.wf.nAvgBytesPerSec);
178                         TRACE(mmsys, "nBlockAlign=%d \n", pcmWaveFormat.wf.nBlockAlign);
179                         TRACE(mmsys, "wBitsPerSample=%u !\n", pcmWaveFormat.wBitsPerSample);
180                         
181                         mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
182                         if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
183                             WAVEOPENDESC        waveDesc;
184                             DWORD               dwRet;
185                             
186                             TRACE(mmsys, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n", 
187                                   (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
188                             
189                             pcmWaveFormat.wf.nAvgBytesPerSec = pcmWaveFormat.wf.nSamplesPerSec * 
190                                 pcmWaveFormat.wf.nBlockAlign;
191                             waveDesc.hWave    = 0;
192                             waveDesc.lpFormat = (LPWAVEFORMAT)&pcmWaveFormat;
193                             
194                             dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
195                             if (dwRet == MMSYSERR_NOERROR) {
196                                 WAVEHDR         waveHdr;
197                                 HGLOBAL16       hData;
198                                 INT             count, bufsize, left = mmckInfo.cksize;
199                                 
200                                 bufsize = 64000;
201                                 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
202                                 waveHdr.lpData = (LPSTR)GlobalLock16(hData);
203                                 waveHdr.dwBufferLength = bufsize;
204                                 waveHdr.dwUser = 0L;
205                                 waveHdr.dwFlags = 0L;
206                                 waveHdr.dwLoops = 0L;
207                                 
208                                 dwRet = wodMessage(0, WODM_PREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
209                                 if (dwRet == MMSYSERR_NOERROR) {
210                                     while (left) {
211                                         if (PlaySound_Stop) {
212                                             PlaySound_Stop = FALSE;
213                                             PlaySound_Loop = FALSE;
214                                             break;
215                                         }
216                                         if (bufsize > left) bufsize = left;
217                                         count = mmioRead(hmmio, waveHdr.lpData,bufsize);
218                                         if (count < 1) break;
219                                         left -= count;
220                                         waveHdr.dwBufferLength = count;
221                                 /*      waveHdr.dwBytesRecorded = count; */
222                                         /* FIXME: doesn't expect async ops */ 
223                                         wodMessage(0, WODM_WRITE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
224                                     }
225                                     wodMessage(0, WODM_UNPREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
226                                     wodMessage(0, WODM_CLOSE, 0, 0L, 0L);
227                                     
228                                     bRet = TRUE;
229                                 } else 
230                                     WARN(mmsys, "can't prepare WaveOut device !\n");
231                                 
232                                 GlobalUnlock16(hData);
233                                 GlobalFree16(hData);
234                             }
235                         }
236                     }
237                 }
238             }
239         } while (PlaySound_Loop);
240     
241     if (hmmio != 0) mmioClose(hmmio, 0);
242     return bRet;
243 }
244
245 static DWORD WINAPI PlaySound_Thread(LPVOID arg) 
246 {
247     DWORD     res;
248     
249     for (;;) {
250         PlaySound_Playing = FALSE;
251         SetEvent(PlaySound_hReadyEvent);
252         res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
253         ResetEvent(PlaySound_hReadyEvent);
254         SetEvent(PlaySound_hMiddleEvent);
255         if (res == WAIT_FAILED) ExitThread(2);
256         if (res != WAIT_OBJECT_0) continue;
257         PlaySound_Playing = TRUE;
258         
259         if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
260             HRSRC       hRES;
261             HGLOBAL     hGLOB;
262             void*       ptr;
263
264             if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
265                 PlaySound_Result = FALSE;
266                 continue;
267             }
268             if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
269                 PlaySound_Result = FALSE;
270                 continue;
271             }
272             if ((ptr = LockResource(hGLOB)) == NULL) {
273                 FreeResource(hGLOB);
274                 PlaySound_Result = FALSE;
275                 continue;
276             }
277             PlaySound_Result = proc_PlaySound(ptr, 
278                                               ((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
279             FreeResource(hGLOB);
280             continue;
281         }
282         PlaySound_Result=proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
283     }
284 }
285
286 /**************************************************************************
287  *                              PlaySoundA              [WINMM.1]
288  */
289 BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
290 {
291     static LPSTR StrDup = NULL;
292     
293     TRACE(mmsys, "pszSound='%p' hmod=%04X fdwSound=%08lX\n",
294           pszSound, hmod, fdwSound);
295     
296     if (PlaySound_hThread == 0) { /* This is the first time they called us */
297         DWORD   id;
298         if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
299             return FALSE;
300         if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
301             return FALSE;
302         if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
303             return FALSE;
304         if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0) 
305             return FALSE;
306     }
307     
308     /* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */ 
309     if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing) 
310         return FALSE;
311     
312     /* Trying to stop if playing */
313     if (PlaySound_Playing) PlaySound_Stop = TRUE;
314     
315     /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
316     if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
317         return FALSE;
318     
319     if (!pszSound || (fdwSound & SND_PURGE)) 
320         return FALSE; /* We stoped playing so leaving */
321     
322     if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
323     if (!(fdwSound & SND_ASYNC)) {
324         if (fdwSound & SND_LOOP) 
325             return FALSE;
326         PlaySound_pszSound = pszSound;
327         PlaySound_hmod = hmod;
328         PlaySound_fdwSound = fdwSound;
329         PlaySound_Result = FALSE;
330         SetEvent(PlaySound_hPlayEvent);
331         if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0) 
332             return FALSE;
333         if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0) 
334             return FALSE;
335         return PlaySound_Result;
336     } else {
337         PlaySound_hmod = hmod;
338         PlaySound_fdwSound = fdwSound;
339         PlaySound_Result = FALSE;
340         if (StrDup) {
341             HeapFree(GetProcessHeap(), 0, StrDup);
342             StrDup = NULL;
343         }
344         if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) && 
345                                           !((DWORD)pszSound >> 16)) || !pszSound)) {
346             StrDup = HEAP_strdupA(GetProcessHeap(), 0,pszSound);
347             PlaySound_pszSound = StrDup;
348         } else PlaySound_pszSound = pszSound;
349         PlaySound_Loop = fdwSound & SND_LOOP;
350         SetEvent(PlaySound_hPlayEvent);
351         ResetEvent(PlaySound_hMiddleEvent);
352         return TRUE;
353     }
354     return FALSE;
355 }
356
357 /**************************************************************************
358  *                              PlaySoundW              [WINMM.18]
359  */
360 BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
361 {
362     LPSTR       pszSoundA;
363     BOOL        bSound;
364     
365     if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) && 
366                                       !((DWORD)pszSound >> 16)) || !pszSound)) {
367         pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
368         bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
369         HeapFree(GetProcessHeap(), 0,pszSoundA);
370     } else  
371         bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
372     
373     return bSound;
374 }
375
376 /**************************************************************************
377  *                              sndPlaySoundA           [MMSYSTEM.2][WINMM135]
378  */
379 BOOL16 WINAPI sndPlaySoundA(LPCSTR lpszSoundName, UINT16 uFlags)
380 {
381     PlaySound_SearchMode = 1;
382     return PlaySoundA(lpszSoundName, 0, uFlags);
383 }
384
385 /**************************************************************************
386  *                              sndPlaySoundW           [WINMM.136]
387  */
388 BOOL16 WINAPI sndPlaySoundW(LPCWSTR lpszSoundName, UINT16 uFlags)
389 {
390     PlaySound_SearchMode = 1;
391     return PlaySoundW(lpszSoundName, 0, uFlags);
392 }
393
394 /**************************************************************************
395  *                              mmsystemGetVersion      [WINMM.134]
396  */
397 UINT WINAPI mmsystemGetVersion()
398 {
399     return mmsystemGetVersion16();
400 }
401
402 /**************************************************************************
403  *                              mmsystemGetVersion      [MMSYSTEM.5]
404  * return value borrowed from Win95 winmm.dll ;)
405  */
406 UINT16 WINAPI mmsystemGetVersion16()
407 {
408     TRACE(mmsys, "3.10 (Win95?)\n");
409     return 0x030a;
410 }
411
412 /**************************************************************************
413  *                              DriverProc      [MMSYSTEM.6]
414  */
415 LRESULT WINAPI DriverProc16(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg, 
416                             DWORD dwParam1, DWORD dwParam2)
417 {
418     return DrvDefDriverProc(dwDevID, hDrv, wMsg, dwParam1, dwParam2);
419 }
420
421 /**************************************************************************
422  *                              DriverCallback  [MMSYSTEM.31]
423  */
424 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HANDLE16 hDev, 
425                                WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
426 {
427     TRACE(mmsys, "(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
428           dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
429
430     switch (uFlags & DCB_TYPEMASK) {
431     case DCB_NULL:
432         TRACE(mmsys, "CALLBACK_NULL !\n");
433         break;
434     case DCB_WINDOW:
435         TRACE(mmsys, "CALLBACK_WINDOW = %04lX handle = %04X!\n",
436               dwCallBack, hDev);
437         if (!IsWindow(dwCallBack) || USER_HEAP_LIN_ADDR(hDev) == NULL)
438             return FALSE;
439         
440         PostMessageA((HWND16)dwCallBack, wMsg, hDev, dwParam1);
441         break;
442     case DCB_TASK:
443         TRACE(mmsys, "CALLBACK_TASK !\n");
444         return FALSE;
445     case DCB_FUNCTION:
446         TRACE(mmsys, "CALLBACK_FUNCTION !\n");
447         Callbacks->CallDriverCallback((FARPROC16)dwCallBack,
448                                        hDev, wMsg, dwUser,
449                                        dwParam1, dwParam2 );
450         break;
451     case DCB_FUNC32:
452         TRACE(mmsys, "CALLBACK_FUNCTION !\n");
453         ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser,
454                                        dwParam1, dwParam2 );
455         break;
456     default:
457         WARN(mmsys, "Unknown callback type\n");
458         break;
459     }
460     return TRUE;
461 }
462
463 /**************************************************************************
464  *      Mixer devices. New to Win95
465  */
466 /**************************************************************************
467  * find out the real mixer ID depending on hmix (depends on dwFlags)
468  * FIXME: also fix dwInstance passing to mixMessage 
469  */
470 static UINT _get_mixerID_from_handle(HMIXEROBJ hmix, DWORD dwFlags) 
471 {
472     /* FIXME: Check dwFlags for MIXER_OBJECTF_xxxx entries and modify hmix 
473      * accordingly. For now we always use mixerdevice 0. 
474      */
475     return 0;
476 }
477
478 /**************************************************************************
479  *                              mixerGetNumDevs         [WINMM.108]
480  */
481 UINT WINAPI mixerGetNumDevs() 
482 {
483     return mixerGetNumDevs16();
484 }
485
486 /**************************************************************************
487  *                              mixerGetNumDevs 
488  */
489 UINT16 WINAPI mixerGetNumDevs16() 
490 {
491     UINT16      count = mixMessage(0, MXDM_GETNUMDEVS, 0L, 0L, 0L);
492     
493     TRACE(mmaux,"mixerGetNumDevs returns %d\n",count);
494     return count;
495 }
496
497 /**************************************************************************
498  *                              mixerGetDevCapsW                [WINMM.102]
499  */
500 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size) 
501 {
502     MIXERCAPS16 mic16;
503     UINT        ret = mixerGetDevCaps16(devid, &mic16, sizeof(mic16));
504     
505     mixcaps->wMid = mic16.wMid;
506     mixcaps->wPid = mic16.wPid;
507     mixcaps->vDriverVersion = mic16.vDriverVersion;
508     lstrcpyAtoW(mixcaps->szPname, mic16.szPname);
509     mixcaps->fdwSupport = mic16.fdwSupport;
510     mixcaps->cDestinations = mic16.cDestinations;
511     return ret;
512 }
513
514 /**************************************************************************
515  *                              mixerGetDevCaps         [WINMM.101]
516  */
517 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size) 
518 {
519     MIXERCAPS16 mic16;
520     UINT        ret = mixerGetDevCaps16(devid, &mic16, sizeof(mic16));
521     
522     mixcaps->wMid = mic16.wMid;
523     mixcaps->wPid = mic16.wPid;
524     mixcaps->vDriverVersion = mic16.vDriverVersion;
525     strcpy(mixcaps->szPname, mic16.szPname);
526     mixcaps->fdwSupport = mic16.fdwSupport;
527     mixcaps->cDestinations = mic16.cDestinations;
528     return ret;
529 }
530
531 /**************************************************************************
532  *                              mixerGetDevCaps 
533  */
534 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps, UINT16 size) 
535 {
536     FIXME(mmsys,"should this be a fixme?\n");
537     return mixMessage(devid, MXDM_GETDEVCAPS, 0L, (DWORD)mixcaps, (DWORD)size);
538 }
539
540 /**************************************************************************
541  *                              mixerOpen               [WINMM.110]
542  */
543 UINT WINAPI mixerOpen(LPHMIXER lphmix, UINT uDeviceID, DWORD dwCallback,
544                           DWORD dwInstance, DWORD fdwOpen) 
545 {
546     HMIXER16    hmix16;
547     UINT        ret;
548     
549     FIXME(mmsys,"(%p,%d,%08lx,%08lx,%08lx): semi stub?\n",
550           lphmix,uDeviceID, dwCallback, dwInstance, fdwOpen);
551     ret = mixerOpen16(&hmix16,uDeviceID, dwCallback, dwInstance,fdwOpen);
552     if (lphmix) *lphmix = hmix16;
553     return ret;
554 }
555
556 /**************************************************************************
557  *                              mixerOpen
558  */
559 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
560                           DWORD dwInstance, DWORD fdwOpen) 
561 {
562     HMIXER16            hmix;
563     LPMIXEROPENDESC     lpmod;
564     BOOL                mapperflag = (uDeviceID==0);
565     DWORD               dwRet=0;
566     
567     TRACE(mmsys,"(%p,%d,%08lx,%08lx,%08lx)\n",
568           lphmix,uDeviceID, dwCallback, dwInstance, fdwOpen);
569     hmix = USER_HEAP_ALLOC(sizeof(MIXEROPENDESC));
570     if (lphmix) *lphmix = hmix;
571     lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
572     lpmod->hmx = hmix;
573     lpmod->dwCallback = dwCallback;
574     lpmod->dwInstance = dwInstance;
575     if (uDeviceID >= MAXMIXERDRIVERS)
576         uDeviceID = 0;
577     while (uDeviceID < MAXMIXERDRIVERS) {
578         dwRet=mixMessage(uDeviceID, MXDM_OPEN, dwInstance, (DWORD)lpmod, fdwOpen);
579         if (dwRet == MMSYSERR_NOERROR) break;
580         if (!mapperflag) break;
581         uDeviceID++;
582     }
583     lpmod->uDeviceID = uDeviceID;
584     return dwRet;
585 }
586
587 /**************************************************************************
588  *                              mixerClose              [WINMM.98]
589  */
590 UINT WINAPI mixerClose(HMIXER hmix) 
591 {
592     return mixerClose16(hmix);
593 }
594
595 /**************************************************************************
596  *                              mixerClose
597  */
598 UINT16 WINAPI mixerClose16(HMIXER16 hmix) 
599 {
600     LPMIXEROPENDESC     lpmod;
601     
602     FIXME(mmsys,"(%04x): semi-stub?\n", hmix);
603     lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
604     return mixMessage(lpmod->uDeviceID, MXDM_CLOSE, lpmod->dwInstance, 0L, 0L);
605 }
606
607 /**************************************************************************
608  *                              mixerGetID              [WINMM.103]
609  */
610 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID) 
611 {
612     UINT16      xid;    
613     UINT        ret = mixerGetID16(hmix, &xid, fdwID);
614
615     if (lpid) *lpid = xid;
616     return ret;
617 }
618
619 /**************************************************************************
620  *                              mixerGetID
621  */
622 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID) 
623 {
624     FIXME(mmsys,"(%04x): semi-stub\n",hmix);
625     if (lpid)
626       *lpid = _get_mixerID_from_handle(hmix,fdwID);
627     return MMSYSERR_NOERROR; /* FIXME: many error possibilities */
628 }
629
630 /**************************************************************************
631  *                              mixerGetControlDetailsA [WINMM.99]
632  */
633 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails) 
634 {
635     FIXME(mmsys,"(%04x,%p,%08lx): stub!\n", hmix, lpmcd, fdwDetails);
636     return MMSYSERR_NOTENABLED;
637 }
638
639 /**************************************************************************
640  *                              mixerGetControlDetailsW [WINMM.100]
641  */
642 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails) 
643 {
644     FIXME(mmsys,"(%04x,%p,%08lx): stub!\n",     hmix, lpmcd, fdwDetails);
645     return MMSYSERR_NOTENABLED;
646 }
647
648 /**************************************************************************
649  *                              mixerGetControlDetails  [MMSYSTEM.808]
650  */
651 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails) 
652 {
653     FIXME(mmsys,"(%04x,%p,%08lx): stub!\n", hmix, lpmcd, fdwDetails);
654     return MMSYSERR_NOTENABLED;
655 }
656
657 /**************************************************************************
658  *                              mixerGetLineControlsA   [WINMM.104]
659  */
660 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlc, DWORD fdwControls) 
661 {
662     FIXME(mmsys,"(%04x,%p,%08lx): stub!\n", hmix, lpmlc, fdwControls);
663     return MMSYSERR_NOTENABLED;
664 }
665
666 /**************************************************************************
667  *                              mixerGetLineControlsW   [WINMM.105]
668  */
669 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlc, DWORD fdwControls) 
670 {
671     FIXME(mmsys,"(%04x,%p,%08lx): stub!\n", hmix, lpmlc, fdwControls);
672     return MMSYSERR_NOTENABLED;
673 }
674
675 /**************************************************************************
676  *                              mixerGetLineControls    [MMSYSTEM.807]
677  */
678 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix, LPMIXERLINECONTROLS16 lpmlc, DWORD fdwControls) 
679 {
680     FIXME(mmsys,"(%04x,%p,%08lx): stub!\n", hmix, lpmlc, fdwControls);
681     return MMSYSERR_NOTENABLED;
682 }
683
684 /**************************************************************************
685  *                              mixerGetLineInfoA       [WINMM.106]
686  */
687 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpml, DWORD fdwInfo) 
688 {
689     MIXERLINE16         ml16;
690     UINT                ret;
691     
692     TRACE(mmsys, "(%04x,%p,%08lx)\n", hmix, lpml, fdwInfo);
693
694     if (lpml == NULL || lpml->cbStruct != sizeof(*lpml)) 
695         return MMSYSERR_INVALPARAM;
696
697     ml16.cbStruct = sizeof(ml16);
698     ml16.dwDestination = lpml->dwDestination;
699     ml16.dwSource = lpml->dwSource; 
700     ml16.dwLineID = lpml->dwLineID; 
701     ml16.dwUser = lpml->dwUser; 
702     ml16.dwComponentType = lpml->dwComponentType; 
703     ml16.cChannels = lpml->cChannels; 
704     ml16.cConnections = lpml->cConnections; 
705     ml16.cControls = lpml->cControls; 
706
707     ret = mixerGetLineInfo16(hmix, &ml16, fdwInfo);
708
709     lpml->dwSource = ml16.dwSource;
710     lpml->dwLineID = ml16.dwLineID;
711     lpml->fdwLine = ml16.fdwLine;
712     lpml->dwUser = ml16.dwUser;
713     lpml->dwComponentType = ml16.dwComponentType;
714     lpml->cChannels = ml16.cChannels;
715     lpml->cConnections = ml16.cConnections;
716     lpml->cControls = ml16.cControls;
717     strcpy(lpml->szShortName, ml16.szShortName);
718     strcpy(lpml->szName, ml16.szName);
719     lpml->Target.dwType = ml16.Target.dwType;
720     lpml->Target.dwDeviceID = ml16.Target.dwDeviceID;
721     lpml->Target.wMid = ml16.Target.wMid;
722     lpml->Target.wPid = ml16.Target.wPid;
723     lpml->Target.vDriverVersion = ml16.Target.vDriverVersion;
724     strcpy(lpml->Target.szPname, ml16.Target.szPname);
725     return ret;
726 }
727
728 /**************************************************************************
729  *                              mixerGetLineInfoW       [WINMM.107]
730  */
731 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpml, DWORD fdwInfo) 
732 {
733     MIXERLINE16         ml16;
734     UINT                ret;
735     
736     TRACE(mmsys,"(%04x,%p,%08lx)\n", hmix, lpml, fdwInfo);
737
738     if (lpml == NULL || lpml->cbStruct != sizeof(*lpml)) 
739         return MMSYSERR_INVALPARAM;
740
741     ml16.cbStruct = sizeof(ml16);
742     ml16.dwDestination = lpml->dwDestination;
743     ml16.dwSource = lpml->dwSource; 
744     ml16.dwLineID = lpml->dwLineID; 
745     ml16.dwUser = lpml->dwUser; 
746     ml16.dwComponentType = lpml->dwComponentType; 
747     ml16.cChannels = lpml->cChannels; 
748     ml16.cConnections = lpml->cConnections; 
749     ml16.cControls = lpml->cControls; 
750
751     ret = mixerGetLineInfo16(hmix, &ml16, fdwInfo);
752
753     lpml->dwSource = ml16.dwSource;
754     lpml->dwLineID = ml16.dwLineID;
755     lpml->fdwLine = ml16.fdwLine;
756     lpml->dwUser = ml16.dwUser;
757     lpml->dwComponentType = ml16.dwComponentType;
758     lpml->cChannels = ml16.cChannels;
759     lpml->cConnections = ml16.cConnections;
760     lpml->cControls = ml16.cControls;
761     lstrcpyAtoW(lpml->szShortName, ml16.szShortName);
762     lstrcpyAtoW(lpml->szName, ml16.szName);
763     lpml->Target.dwType = ml16.Target.dwType;
764     lpml->Target.dwDeviceID = ml16.Target.dwDeviceID;
765     lpml->Target.wMid = ml16.Target.wMid;
766     lpml->Target.wPid = ml16.Target.wPid;
767     lpml->Target.vDriverVersion = ml16.Target.vDriverVersion;
768     /*lstrcpyAtoW(lpml->Target.szPname, ml16.Target.szPname);*/
769     return ret;
770 }
771
772 /**************************************************************************
773  *                              mixerGetLineInfo        [MMSYSTEM.805]
774  */
775 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpml, DWORD fdwInfo) 
776 {
777     UINT16 devid = _get_mixerID_from_handle(hmix, fdwInfo);
778     
779     FIXME(mmsys, "(%04x, %p[line %08lx], %08lx)\n",
780           hmix, lpml, lpml->dwDestination, fdwInfo);
781     return mixMessage(devid, MXDM_GETLINEINFO, 0, (DWORD)lpml, fdwInfo);
782 }
783
784 /**************************************************************************
785  *                              mixerSetControlDetails  [WINMM.111]
786  */
787 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails) 
788 {
789     FIXME(mmsys,"(%04x,%p,%08lx): stub!\n", hmix, lpmcd, fdwDetails);
790     return MMSYSERR_NOTENABLED;
791 }
792
793 /**************************************************************************
794  *                              mixerSetControlDetails  [MMSYSTEM.809]
795  */
796 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails) 
797 {
798     FIXME(mmsys,"(%04x,%p,%08lx): stub!\n", hmix, lpmcd, fdwDetails);
799     return MMSYSERR_NOTENABLED;
800 }
801
802 /**************************************************************************
803  *                              mixerMessage            [WINMM.109]
804  */
805 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2) 
806 {
807     LPMIXEROPENDESC     lpmod;
808     UINT16              uDeviceID;
809     
810     lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
811     if (lpmod)
812         uDeviceID = lpmod->uDeviceID;
813     else
814         uDeviceID = 0;
815     FIXME(mmsys,"(%04lx,%d,%08lx,%08lx): semi-stub?\n",
816           (DWORD)hmix,uMsg, dwParam1, dwParam2);
817     return mixMessage(uDeviceID,uMsg, 0L, dwParam1, dwParam2);
818 }
819
820 /**************************************************************************
821  *                              mixerMessage            [MMSYSTEM.804]
822  */
823 UINT16 WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1, DWORD dwParam2) 
824 {
825     LPMIXEROPENDESC     lpmod;
826     UINT16              uDeviceID;
827     
828     lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
829     uDeviceID = (lpmod) ? lpmod->uDeviceID : 0;
830     FIXME(mmsys,"(%04x,%d,%08lx,%08lx) - semi-stub?\n",
831           hmix,uMsg, dwParam1, dwParam2);
832     return mixMessage(uDeviceID,uMsg, 0L, dwParam1, dwParam2);
833 }
834
835 /**************************************************************************
836  *                              auxGetNumDevs           [WINMM.22]
837  */
838 UINT WINAPI auxGetNumDevs()
839 {
840     return auxGetNumDevs16();
841 }
842
843 /**************************************************************************
844  *                              auxGetNumDevs           [MMSYSTEM.350]
845  */
846 UINT16 WINAPI auxGetNumDevs16()
847 {
848     UINT16      count;
849
850     TRACE(mmsys, "\n");
851     count = auxMessage(0, AUXDM_GETNUMDEVS, 0L, 0L, 0L);
852     TRACE(mmsys, "=> %u\n", count);
853     return count;
854 }
855
856 /**************************************************************************
857  *                              auxGetDevCaps           [WINMM.20]
858  */
859 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
860 {
861     AUXCAPS16   ac16;
862     UINT        ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
863     
864     lpCaps->wMid = ac16.wMid;
865     lpCaps->wPid = ac16.wPid;
866     lpCaps->vDriverVersion = ac16.vDriverVersion;
867     lstrcpyAtoW(lpCaps->szPname,ac16.szPname);
868     lpCaps->wTechnology = ac16.wTechnology;
869     lpCaps->dwSupport = ac16.dwSupport;
870     return ret;
871 }
872
873 /**************************************************************************
874  *                              auxGetDevCaps           [WINMM.21]
875  */
876 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
877 {
878     AUXCAPS16   ac16;
879     UINT        ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
880     
881     lpCaps->wMid = ac16.wMid;
882     lpCaps->wPid = ac16.wPid;
883     lpCaps->vDriverVersion = ac16.vDriverVersion;
884     strcpy(lpCaps->szPname,ac16.szPname);
885     lpCaps->wTechnology = ac16.wTechnology;
886     lpCaps->dwSupport = ac16.dwSupport;
887     return ret;
888 }
889
890 /**************************************************************************
891  *                              auxGetDevCaps           [MMSYSTEM.351]
892  */
893 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
894 {
895     TRACE(mmsys, "(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
896
897     return auxMessage(uDeviceID, AUXDM_GETDEVCAPS,
898                       0L, (DWORD)lpCaps, (DWORD)uSize);
899 }
900
901 /**************************************************************************
902  *                              auxGetVolume            [WINM.23]
903  */
904 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
905 {
906     return auxGetVolume16(uDeviceID, lpdwVolume);
907 }
908
909 /**************************************************************************
910  *                              auxGetVolume            [MMSYSTEM.352]
911  */
912 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
913 {
914     TRACE(mmsys, "(%04X, %p) !\n", uDeviceID, lpdwVolume);
915
916     return auxMessage(uDeviceID, AUXDM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
917 }
918
919 /**************************************************************************
920  *                              auxSetVolume            [WINMM.25]
921  */
922 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
923 {
924     return auxSetVolume16(uDeviceID, dwVolume);
925 }
926
927 /**************************************************************************
928  *                              auxSetVolume            [MMSYSTEM.353]
929  */
930 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
931 {
932     TRACE(mmsys, "(%04X, %08lX) !\n", uDeviceID, dwVolume);
933
934     return auxMessage(uDeviceID, AUXDM_SETVOLUME, 0L, dwVolume, 0L);
935 }
936
937 /**************************************************************************
938  *                              auxOutMessage           [MMSYSTEM.354]
939  */
940 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
941 {
942     switch (uMessage) {
943     case AUXDM_GETNUMDEVS:
944     case AUXDM_GETVOLUME:
945     case AUXDM_SETVOLUME:
946         /* no argument conversion needed */
947         break;
948     case AUXDM_GETDEVCAPS:
949         return auxGetDevCapsA(uDeviceID, (LPAUXCAPSA)dw1, dw2);
950     default:
951         ERR(mmsys,"(%04x,%04x,%08lx,%08lx): unhandled message\n",
952             uDeviceID,uMessage, dw1, dw2);
953         break;
954     }
955     return auxMessage(uDeviceID,uMessage, 0L, dw1, dw2);
956 }
957
958 /**************************************************************************
959  *                              auxOutMessage           [MMSYSTEM.354]
960  */
961 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
962 {
963     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
964
965     switch (uMessage) {
966     case AUXDM_GETNUMDEVS:
967     case AUXDM_SETVOLUME:
968         /* no argument conversion needed */
969         break;
970     case AUXDM_GETVOLUME:
971         return auxGetVolume16(uDeviceID, (LPDWORD)PTR_SEG_TO_LIN(dw1));
972     case AUXDM_GETDEVCAPS:
973         return auxGetDevCaps16(uDeviceID, (LPAUXCAPS16)PTR_SEG_TO_LIN(dw1), dw2);
974     default:
975         ERR(mmsys,"(%04x,%04x,%08lx,%08lx): unhandled message\n",
976             uDeviceID,uMessage, dw1, dw2);
977         break;
978     }
979     return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
980 }
981
982 /**************************************************************************
983  *                              mciGetErrorStringW              [WINMM.46]
984  */
985 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
986 {
987     LPSTR       bufstr = HeapAlloc(GetProcessHeap(), 0,uLength);
988     BOOL        ret = mciGetErrorStringA(wError, bufstr, uLength);
989     
990     lstrcpyAtoW(lpstrBuffer, bufstr);
991     HeapFree(GetProcessHeap(), 0, bufstr);
992     return ret;
993 }
994
995 /**************************************************************************
996  *                              mciGetErrorStringA              [WINMM.45]
997  */
998 BOOL WINAPI mciGetErrorStringA(DWORD wError, LPSTR lpstrBuffer, UINT uLength)
999 {
1000     return mciGetErrorString16(wError, lpstrBuffer,uLength);
1001 }
1002
1003 /**************************************************************************
1004  *                              mciGetErrorString               [MMSYSTEM.706]
1005  */
1006 BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength)
1007 {
1008     LPSTR       msgptr;
1009
1010     TRACE(mmsys, "(%08lX, %p, %d);\n", wError, lpstrBuffer, uLength);
1011
1012     if ((lpstrBuffer == NULL) || (uLength < 1)) 
1013         return(FALSE);
1014     lpstrBuffer[0] = '\0';
1015
1016     switch (wError) {
1017     case 0:
1018         msgptr = "The specified command has been executed.";
1019         break;
1020     case MCIERR_INVALID_DEVICE_ID:
1021         msgptr = "Invalid MCI device ID. Use the ID returned when opening the MCI device.";
1022         break;
1023     case MCIERR_UNRECOGNIZED_KEYWORD:
1024         msgptr = "The driver cannot recognize the specified command parameter.";
1025         break;
1026     case MCIERR_UNRECOGNIZED_COMMAND:
1027         msgptr = "The driver cannot recognize the specified command.";
1028         break;
1029     case MCIERR_HARDWARE:
1030         msgptr = "There is a problem with your media device. Make sure it is working correctly or contact the device manufacturer.";
1031         break;
1032     case MCIERR_INVALID_DEVICE_NAME:
1033         msgptr = "The specified device is not open or is not recognized by MCI.";
1034         break;
1035     case MCIERR_OUT_OF_MEMORY:
1036         msgptr = "Not enough memory available for this task. \nQuit one or more applications to increase available memory, and then try again.";
1037         break;
1038     case MCIERR_DEVICE_OPEN:
1039         msgptr = "The device name is already being used as an alias by this application. Use a unique alias.";
1040         break;
1041     case MCIERR_CANNOT_LOAD_DRIVER:
1042         msgptr = "There is an undetectable problem in loading the specified device driver.";
1043         break;
1044     case MCIERR_MISSING_COMMAND_STRING:
1045         msgptr = "No command was specified.";
1046         break;
1047     case MCIERR_PARAM_OVERFLOW:
1048         msgptr = "The output string was to large to fit in the return buffer. Increase the size of the buffer.";
1049         break;
1050     case MCIERR_MISSING_STRING_ARGUMENT:
1051         msgptr = "The specified command requires a character-string parameter. Please provide one.";
1052         break;
1053     case MCIERR_BAD_INTEGER:
1054         msgptr = "The specified integer is invalid for this command.";
1055         break;
1056     case MCIERR_PARSER_INTERNAL:
1057         msgptr = "The device driver returned an invalid return type. Check with the device manufacturer about obtaining a new driver.";
1058         break;
1059     case MCIERR_DRIVER_INTERNAL:
1060         msgptr = "There is a problem with the device driver. Check with the device manufacturer about obtaining a new driver.";
1061         break;
1062     case MCIERR_MISSING_PARAMETER:
1063         msgptr = "The specified command requires a parameter. Please supply one.";
1064         break;
1065     case MCIERR_UNSUPPORTED_FUNCTION:
1066         msgptr = "The MCI device you are using does not support the specified command.";
1067         break;
1068     case MCIERR_FILE_NOT_FOUND:
1069         msgptr = "Cannot find the specified file. Make sure the path and filename are correct.";
1070         break;
1071     case MCIERR_DEVICE_NOT_READY:
1072         msgptr = "The device driver is not ready.";
1073         break;
1074     case MCIERR_INTERNAL:
1075         msgptr = "A problem occurred in initializing MCI. Try restarting Windows.";
1076         break;
1077     case MCIERR_DRIVER:
1078         msgptr = "There is a problem with the device driver. The driver has closed. Cannot access error.";
1079         break;
1080     case MCIERR_CANNOT_USE_ALL:
1081         msgptr = "Cannot use 'all' as the device name with the specified command.";
1082         break;
1083     case MCIERR_MULTIPLE:
1084         msgptr = "Errors occurred in more than one device. Specify each command and device separately to determine which devices caused the error";
1085         break;
1086     case MCIERR_EXTENSION_NOT_FOUND:
1087         msgptr = "Cannot determine the device type from the given filename extension.";
1088         break;
1089     case MCIERR_OUTOFRANGE:
1090         msgptr = "The specified parameter is out of range for the specified command.";
1091         break;
1092     case MCIERR_FLAGS_NOT_COMPATIBLE:
1093         msgptr = "The specified parameters cannot be used together.";
1094         break;
1095     case MCIERR_FILE_NOT_SAVED:
1096         msgptr = "Cannot save the specified file. Make sure you have enough disk space or are still connected to the network.";
1097         break;
1098     case MCIERR_DEVICE_TYPE_REQUIRED:
1099         msgptr = "Cannot find the specified device. Make sure it is installed or that the device name is spelled correctly.";
1100         break;
1101     case MCIERR_DEVICE_LOCKED:
1102         msgptr = "The specified device is now being closed. Wait a few seconds, and then try again.";
1103         break;
1104     case MCIERR_DUPLICATE_ALIAS:
1105         msgptr = "The specified alias is already being used in this application. Use a unique alias.";
1106         break;
1107     case MCIERR_BAD_CONSTANT:
1108         msgptr = "The specified parameter is invalid for this command.";
1109         break;
1110     case MCIERR_MUST_USE_SHAREABLE:
1111         msgptr = "The device driver is already in use. To share it, use the 'shareable' parameter with each 'open' command.";
1112         break;
1113     case MCIERR_MISSING_DEVICE_NAME:
1114         msgptr = "The specified command requires an alias, file, driver, or device name. Please supply one.";
1115         break;
1116     case MCIERR_BAD_TIME_FORMAT:
1117         msgptr = "The specified value for the time format is invalid. Refer to the MCI documentation for valid formats.";
1118         break;
1119     case MCIERR_NO_CLOSING_QUOTE:
1120         msgptr = "A closing double-quotation mark is missing from the parameter value. Please supply one.";
1121         break;
1122     case MCIERR_DUPLICATE_FLAGS:
1123         msgptr = "A parameter or value was specified twice. Only specify it once.";
1124         break;
1125     case MCIERR_INVALID_FILE:
1126         msgptr = "The specified file cannot be played on the specified MCI device. The file may be corrupt, or not in the correct format.";
1127         break;
1128     case MCIERR_NULL_PARAMETER_BLOCK:
1129         msgptr = "A null parameter block was passed to MCI.";
1130         break;
1131     case MCIERR_UNNAMED_RESOURCE:
1132         msgptr = "Cannot save an unnamed file. Supply a filename.";
1133         break;
1134     case MCIERR_NEW_REQUIRES_ALIAS:
1135         msgptr = "You must specify an alias when using the 'new' parameter.";
1136         break;
1137     case MCIERR_NOTIFY_ON_AUTO_OPEN:
1138         msgptr = "Cannot use the 'notify' flag with auto-opened devices.";
1139         break;
1140     case MCIERR_NO_ELEMENT_ALLOWED:
1141         msgptr = "Cannot use a filename with the specified device.";
1142         break;
1143     case MCIERR_NONAPPLICABLE_FUNCTION:
1144         msgptr = "Cannot carry out the commands in the order specified. Correct the command sequence, and then try again.";
1145         break;
1146     case MCIERR_ILLEGAL_FOR_AUTO_OPEN:
1147         msgptr = "Cannot carry out the specified command on an auto-opened device. Wait until the device is closed, and then try again.";
1148         break;
1149     case MCIERR_FILENAME_REQUIRED:
1150         msgptr = "The filename is invalid. Make sure the filename is not longer than 8 characters, followed by a period and an extension.";
1151         break;
1152     case MCIERR_EXTRA_CHARACTERS:
1153         msgptr = "Cannot specify extra characters after a string enclosed in quotation marks.";
1154         break;
1155     case MCIERR_DEVICE_NOT_INSTALLED:
1156         msgptr = "The specified device is not installed on the system. Use the Drivers option in Control Panel to install the device.";
1157         break;
1158     case MCIERR_GET_CD:
1159         msgptr = "Cannot access the specified file or MCI device. Try changing directories or restarting your computer.";
1160         break;
1161     case MCIERR_SET_CD:
1162         msgptr = "Cannot access the specified file or MCI device because the application cannot change directories.";
1163         break;
1164     case MCIERR_SET_DRIVE:
1165         msgptr = "Cannot access specified file or MCI device because the application cannot change drives.";
1166         break;
1167     case MCIERR_DEVICE_LENGTH:
1168         msgptr = "Specify a device or driver name that is less than 79 characters.";
1169         break;
1170     case MCIERR_DEVICE_ORD_LENGTH:
1171         msgptr = "Specify a device or driver name that is less than 69 characters.";
1172         break;
1173     case MCIERR_NO_INTEGER:
1174         msgptr = "The specified command requires an integer parameter. Please provide one.";
1175         break;
1176     case MCIERR_WAVE_OUTPUTSINUSE:
1177         msgptr = "All wave devices that can play files in the current format are in use. Wait until a wave device is free, and then try again.";
1178         break;
1179     case MCIERR_WAVE_SETOUTPUTINUSE:
1180         msgptr = "Cannot set the current wave device for play back because it is in use. Wait until the device is free, and then try again.";
1181         break;
1182     case MCIERR_WAVE_INPUTSINUSE:
1183         msgptr = "All wave devices that can record files in the current format are in use. Wait until a wave device is free, and then try again.";
1184         break;
1185     case MCIERR_WAVE_SETINPUTINUSE:
1186         msgptr = "Cannot set the current wave device for recording because it is in use. Wait until the device is free, and then try again.";
1187         break;
1188     case MCIERR_WAVE_OUTPUTUNSPECIFIED:
1189         msgptr = "Any compatible waveform playback device may be used.";
1190         break;
1191     case MCIERR_WAVE_INPUTUNSPECIFIED:
1192         msgptr = "Any compatible waveform recording device may be used.";
1193         break;
1194     case MCIERR_WAVE_OUTPUTSUNSUITABLE:
1195         msgptr = "No wave device that can play files in the current format is installed. Use the Drivers option to install the wave device.";
1196         break;
1197     case MCIERR_WAVE_SETOUTPUTUNSUITABLE:
1198         msgptr = "The device you are trying to play to cannot recognize the current file format.";
1199         break;
1200     case MCIERR_WAVE_INPUTSUNSUITABLE:
1201         msgptr = "No wave device that can record files in the current format is installed. Use the Drivers option to install the wave device.";
1202         break;
1203     case MCIERR_WAVE_SETINPUTUNSUITABLE:
1204         msgptr = "The device you are trying to record from cannot recognize the current file format.";
1205         break;
1206     case MCIERR_NO_WINDOW:
1207         msgptr = "There is no display window.";
1208         break;
1209     case MCIERR_CREATEWINDOW:
1210         msgptr = "Could not create or use window.";
1211         break;
1212     case MCIERR_FILE_READ:
1213         msgptr = "Cannot read the specified file. Make sure the file is still present, or check your disk or network connection.";
1214         break;
1215     case MCIERR_FILE_WRITE:
1216         msgptr = "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network.";
1217         break;
1218     case MCIERR_SEQ_DIV_INCOMPATIBLE:
1219         msgptr = "The time formats of the \"song pointer\" and SMPTE are mutually exclusive. You can't use them together.";
1220         break;
1221     case MCIERR_SEQ_NOMIDIPRESENT:
1222         msgptr = "The system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver.";
1223         break;
1224     case MCIERR_SEQ_PORT_INUSE:
1225         msgptr = "The specified MIDI port is already in use. Wait until it is free; the try again.";
1226         break;
1227     case MCIERR_SEQ_PORT_MAPNODEVICE:
1228         msgptr = "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use the MIDI Mapper option from the Control Panel to edit the setup.";
1229         break;
1230     case MCIERR_SEQ_PORT_MISCERROR:
1231         msgptr = "An error occurred with the specified port.";
1232         break;
1233     case MCIERR_SEQ_PORT_NONEXISTENT:
1234         msgptr = "The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device.";
1235         break;
1236     case MCIERR_SEQ_PORTUNSPECIFIED:
1237         msgptr = "The system doesnot have a current MIDI port specified.";
1238         break;
1239     case MCIERR_SEQ_TIMER:
1240         msgptr = "All multimedia timers are being used by other applications. Quit one of these applications; then, try again.";
1241         break;
1242         
1243         /* 
1244            msg# 513 : vcr
1245            msg# 514 : videodisc
1246            msg# 515 : overlay
1247            msg# 516 : cdaudio
1248            msg# 517 : dat
1249            msg# 518 : scanner
1250            msg# 519 : animation
1251            msg# 520 : digitalvideo
1252            msg# 521 : other
1253            msg# 522 : waveaudio
1254            msg# 523 : sequencer
1255            msg# 524 : not ready
1256            msg# 525 : stopped
1257            msg# 526 : playing
1258            msg# 527 : recording
1259            msg# 528 : seeking
1260            msg# 529 : paused
1261            msg# 530 : open
1262            msg# 531 : false
1263            msg# 532 : true
1264            msg# 533 : milliseconds
1265            msg# 534 : hms
1266            msg# 535 : msf
1267            msg# 536 : frames
1268            msg# 537 : smpte 24
1269            msg# 538 : smpte 25
1270            msg# 539 : smpte 30
1271            msg# 540 : smpte 30 drop
1272            msg# 541 : bytes
1273            msg# 542 : samples
1274            msg# 543 : tmsf
1275         */
1276     default:
1277         msgptr = "Unknown MCI Error !\n";
1278         break;
1279     }
1280     lstrcpynA(lpstrBuffer, msgptr, uLength);
1281     TRACE(mmsys, "msg = %s;\n", msgptr);
1282     return TRUE;
1283 }
1284
1285 /**************************************************************************
1286  *                              mciDriverNotify                 [MMSYSTEM.711]
1287  */
1288 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1289 {
1290     TRACE(mmsys, "(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1291
1292     if (!IsWindow(hWndCallBack)) {
1293         WARN(mmsys, "bad hWnd for call back\n");
1294         return FALSE;
1295     }
1296     TRACE(mmsys, "before PostMessage\n");
1297     PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1298     return TRUE;
1299 }
1300
1301 /**************************************************************************
1302  *                      mciDriverNotify                         [WINMM.36]
1303  */
1304 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1305 {
1306     FIXME(mmsys, "(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1307
1308     if (!IsWindow(hWndCallBack)) {
1309         WARN(mmsys, "bad hWnd for call back\n");
1310         return FALSE;
1311     }
1312     TRACE(mmsys, "before PostMessage\n");
1313     PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1314     return TRUE;
1315 }
1316
1317 /**************************************************************************
1318  *                      mciGetDriverData                        [MMSYSTEM.708]
1319  */
1320 DWORD WINAPI mciGetDriverData16(HDRVR16 hDrv) 
1321 {
1322     return mciGetDriverData(hDrv);
1323 }
1324
1325 /**************************************************************************
1326  *                      mciGetDriverData                        [WINMM.44]
1327  */
1328 DWORD WINAPI mciGetDriverData(HDRVR hDrv) 
1329 {
1330     TRACE(mmsys,"(%04x)\n", hDrv);
1331     if (!MCI_DevIDValid(hDrv) || MCI_GetDrv(hDrv)->modp.wType == 0) {
1332         WARN(mmsys, "Bad hDrv\n");
1333         return 0L;
1334     }
1335     
1336     return MCI_GetDrv(hDrv)->dwPrivate;
1337 }
1338
1339 /**************************************************************************
1340  *                      mciSetDriverData                        [MMSYSTEM.707]
1341  */
1342 BOOL16 WINAPI mciSetDriverData16(HDRVR16 hDrv, DWORD data) 
1343 {
1344     return mciSetDriverData(hDrv, data);
1345 }
1346
1347 /**************************************************************************
1348  *                      mciSetDriverData                        [WINMM.53]
1349  */
1350 BOOL WINAPI mciSetDriverData(HDRVR hDrv, DWORD data) 
1351 {
1352     TRACE(mmsys,"(%04x,%08lx)\n", hDrv, data);
1353     if (!MCI_DevIDValid(hDrv) || MCI_GetDrv(hDrv)->modp.wType == 0) {
1354         WARN(mmsys, "Bad hDrv\n");
1355         return FALSE;
1356     }
1357     
1358     MCI_GetDrv(hDrv)->dwPrivate = data;
1359     return TRUE;
1360 }
1361
1362 /**************************************************************************
1363  *                      mciLoadCommandResource                  [MMSYSTEM.705]
1364  */
1365 UINT16 WINAPI mciLoadCommandResource16(HANDLE16 hinst, LPCSTR resname, UINT16 type)
1366 {
1367     char            buf[200];
1368     OFSTRUCT        ofs;
1369     HANDLE16        xhinst;
1370     HRSRC16         hrsrc;
1371     HGLOBAL16       hmem;
1372     LPSTR           segstr;
1373     SEGPTR          xmem;
1374     LPBYTE          lmem;
1375     static UINT16   mcidevtype = 0;
1376     
1377     FIXME(mmsys,"(%04x,%s,%d): stub!\n", hinst, resname, type);
1378     if (!lstrcmpiA(resname,"core")) {
1379         FIXME(mmsys, "(...,\"core\",...), have to use internal tables... (not there yet)\n");
1380         return 0;
1381     }
1382     /* if file exists "resname.mci", then load resource "resname" from it
1383      * otherwise directly from driver
1384      */
1385     strcpy(buf,resname);
1386     strcat(buf,".mci");
1387     if (OpenFile(buf, &ofs,OF_EXIST) != HFILE_ERROR) {
1388         xhinst = LoadLibrary16(buf);
1389         if (xhinst > 32)
1390             hinst = xhinst;
1391     } /* else use passed hinst */
1392     segstr = SEGPTR_STRDUP(resname);
1393     hrsrc = FindResource16(hinst, SEGPTR_GET(segstr), type);
1394     SEGPTR_FREE(segstr);
1395     if (!hrsrc) {
1396         WARN(mmsys,"no special commandlist found in resource\n");
1397         return MCI_NO_COMMAND_TABLE;
1398     }
1399     hmem = LoadResource16(hinst, hrsrc);
1400     if (!hmem) {
1401         WARN(mmsys,"couldn't load resource??\n");
1402         return MCI_NO_COMMAND_TABLE;
1403     }
1404     xmem = WIN16_LockResource16(hmem);
1405     if (!xmem) {
1406         WARN(mmsys,"couldn't lock resource??\n");
1407         FreeResource16(hmem);
1408         return MCI_NO_COMMAND_TABLE;
1409     }
1410     lmem = PTR_SEG_TO_LIN(xmem);
1411     TRACE(mmsys, "first resource entry is %s\n", (char*)lmem);
1412     /* parse resource, register stuff, return unique id */
1413     return ++mcidevtype;
1414 }
1415
1416 /**************************************************************************
1417  *                      mciFreeCommandResource                  [MMSYSTEM.713]
1418  */
1419 BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable)
1420 {
1421     FIXME(mci, "(%04x) stub\n", uTable);
1422     return 0;
1423 }
1424  
1425 /**************************************************************************
1426  *                      mciFreeCommandResource                  [WINMM.39]
1427  */
1428 BOOL WINAPI mciFreeCommandResource(UINT uTable)
1429 {
1430     FIXME(mci, "(%08x) stub\n", uTable);
1431     return 0;
1432 }
1433
1434 /**************************************************************************
1435  *                      mciLoadCommandResource                  [WINMM.48]
1436  */
1437 UINT WINAPI mciLoadCommandResource(HANDLE hinst, LPCWSTR resname, UINT type)
1438 {
1439     FIXME(mci, "(%04x,%s,%d): stub!\n", hinst, debugstr_w(resname), type);
1440     return 0;
1441 }
1442
1443 /**************************************************************************
1444  *                              mciSendCommandA                 [WINMM.49]
1445  */
1446 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1447 {
1448     DWORD       dwRet;
1449
1450     TRACE(mci, "(%08x,%s,%08lx,%08lx)\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1451
1452     switch (wMsg) {
1453     case MCI_OPEN:
1454         dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1455         break;
1456     case MCI_CLOSE:
1457         dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1458         break;
1459     case MCI_SYSINFO:
1460         dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1461         break;
1462     default:
1463         if (wDevID == MCI_ALL_DEVICE_ID) {
1464             FIXME(mci, "unhandled MCI_ALL_DEVICE_ID\n");
1465             dwRet = MCIERR_CANNOT_USE_ALL;
1466         } else {
1467             dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2);
1468         }
1469         break;
1470     }
1471     dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1472     TRACE(mci, "=> %08ld\n", dwRet);
1473     return dwRet;
1474 }
1475
1476 /**************************************************************************
1477  *                              mciSendCommandW                 [WINMM.50]
1478  */
1479 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1480 {
1481     return 0x1; /* !ok */
1482 }
1483
1484 /**************************************************************************
1485  *                              mciSendCommand                  [MMSYSTEM.701]
1486  */
1487 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1488 {
1489     DWORD       dwRet = MCIERR_UNRECOGNIZED_COMMAND;
1490
1491     TRACE(mmsys, "(%04X, %s, %08lX, %08lX)\n", 
1492           wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1493
1494     switch (wMsg) {
1495     case MCI_OPEN:
1496         if (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2) >= 0) {
1497             dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1498             MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1499         }
1500         break;
1501     case MCI_CLOSE:
1502         if (wDevID == MCI_ALL_DEVICE_ID) {
1503             FIXME(mci, "unhandled MCI_ALL_DEVICE_ID\n");
1504             dwRet = MCIERR_CANNOT_USE_ALL;
1505         } else if (!MCI_DevIDValid(wDevID)) {
1506             dwRet = MCIERR_INVALID_DEVICE_ID;
1507         } else if (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2) >= 0) {
1508             dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1509             MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1510         }
1511         break;
1512     case MCI_SYSINFO:
1513         if (MCI_MapMsg16To32A(0, wDevID, &dwParam2) >= 0) {
1514             dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1515             MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
1516         }
1517         break;
1518     /* FIXME: it seems that MCI_BREAK and MCI_SOUND need the same handling */
1519     default:
1520         if (wDevID == MCI_ALL_DEVICE_ID) {
1521             FIXME(mci, "unhandled MCI_ALL_DEVICE_ID\n");
1522             dwRet = MCIERR_CANNOT_USE_ALL;
1523         } else if (!MCI_DevIDValid(wDevID)) {
1524             dwRet = MCIERR_INVALID_DEVICE_ID;
1525         } else {
1526             int                 res;
1527                     
1528             switch (DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv)) {
1529             case WINE_DI_TYPE_16:               
1530                 dwRet = SendDriverMessage16(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
1531                 break;
1532             case WINE_DI_TYPE_32:
1533                 switch (res = MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1534                 case -1:
1535                     TRACE(mci, "Not handled yet (%s)\n", MCI_CommandToString(wMsg));
1536                     dwRet = MCIERR_DRIVER_INTERNAL;
1537                     break;
1538                 case -2:
1539                     TRACE(mci, "Problem mapping msg=%s from 16 to 32a\n", MCI_CommandToString(wMsg));
1540                     dwRet = MCIERR_OUT_OF_MEMORY;
1541                     break;
1542                 case 0:
1543                 case 1:
1544                     dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2);
1545                     if (res)
1546                         MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1547                     break;
1548                 }
1549                 break;
1550             default:
1551                 WARN(mmsys, "Unknown driver type=%u\n", DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv));
1552                 dwRet = MCIERR_DRIVER_INTERNAL;
1553             }
1554         }
1555     }
1556     dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1557     TRACE(mmsys, "=> %ld\n", dwRet);
1558     return dwRet;
1559 }
1560     
1561 /**************************************************************************
1562  *                              mciGetDeviceID                  [MMSYSTEM.703]
1563  */
1564 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1565 {
1566     UINT16      wDevID;
1567     TRACE(mmsys, "(\"%s\")\n", lpstrName);
1568
1569     if (!lpstrName)
1570         return 0;
1571     
1572     if (!lstrcmpiA(lpstrName, "ALL"))
1573         return MCI_ALL_DEVICE_ID;
1574     
1575     for (wDevID = MCI_FirstDevID(); MCI_DevIDValid(wDevID); wDevID = MCI_NextDevID(wDevID)) {
1576         if (MCI_GetDrv(wDevID)->modp.wType) {
1577             FIXME(mmsys, "This is wrong for compound devices\n");
1578             /* FIXME: for compound devices, lpstrName is matched against 
1579              * the name of the file, not the name of the device... 
1580              */
1581             if (MCI_GetOpenDrv(wDevID)->lpstrDeviceType && 
1582                 strcmp(MCI_GetOpenDrv(wDevID)->lpstrDeviceType, lpstrName) == 0)
1583                 return wDevID;
1584     
1585             if (MCI_GetOpenDrv(wDevID)->lpstrAlias && 
1586                 strcmp(MCI_GetOpenDrv(wDevID)->lpstrAlias, lpstrName) == 0)
1587                 return wDevID;
1588         }
1589     }
1590     
1591     return 0;
1592 }
1593
1594 /**************************************************************************
1595  *                              mciGetDeviceIDA                 [WINMM.41]
1596  */
1597 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1598 {
1599     return mciGetDeviceID16(lpstrName);
1600 }
1601
1602 /**************************************************************************
1603  *                              mciGetDeviceIDW                 [WINMM.43]
1604  */
1605 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1606 {
1607     LPSTR       lpstrName;
1608     UINT        ret;
1609
1610     lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1611     ret = mciGetDeviceID16(lpstrName);
1612     HeapFree(GetProcessHeap(), 0, lpstrName);
1613     return ret;
1614 }
1615
1616 /**************************************************************************
1617  *                              mciSetYieldProc                 [MMSYSTEM.714]
1618  */
1619 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, 
1620                                 YIELDPROC fpYieldProc, DWORD dwYieldData)
1621 {
1622     FIXME(mci, "(%u, %p, %08lx) stub\n", uDeviceID, fpYieldProc, dwYieldData);
1623     return FALSE;
1624 }
1625
1626 /**************************************************************************
1627  *                              mciSetYieldProc                 [WINMM.54]
1628  */
1629 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, 
1630                                 YIELDPROC fpYieldProc, DWORD dwYieldData)
1631 {
1632     FIXME(mci, "(%u, %p, %08lx) stub\n", uDeviceID, fpYieldProc, dwYieldData);
1633     return FALSE;
1634 }
1635
1636 /**************************************************************************
1637  *                              mciGetDeviceIDFromElementID     [MMSYSTEM.715]
1638  */
1639 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1640 {
1641     FIXME(mci, "(%lu, %s) stub\n", dwElementID, lpstrType);
1642     return 0;
1643 }
1644         
1645 /**************************************************************************
1646  *                              mciGetDeviceIDFromElementIDW    [WINMM.42]
1647  */
1648 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1649 {
1650     /* FIXME: that's rather strange, there is no 
1651      * mciGetDeviceIDFromElementID32A in winmm.spec
1652      */
1653     FIXME(mci, "(%lu, %p) stub\n", dwElementID, lpstrType);
1654     return 0;
1655 }
1656         
1657 /**************************************************************************
1658  *                              mciGetYieldProc                 [MMSYSTEM.716]
1659  */
1660 YIELDPROC WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1661 {
1662     FIXME(mci, "(%u, %p) stub\n", uDeviceID, lpdwYieldData);
1663     return NULL;
1664 }
1665     
1666 /**************************************************************************
1667  *                              mciGetYieldProc                 [WINMM.47]
1668  */
1669 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1670 {
1671     FIXME(mci, "(%u, %p) stub\n", uDeviceID, lpdwYieldData);
1672     return NULL;
1673 }
1674
1675 /**************************************************************************
1676  *                              mciGetCreatorTask               [MMSYSTEM.717]
1677  */
1678 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1679 {
1680     FIXME(mci, "(%u) stub\n", uDeviceID);
1681     return 0;
1682 }
1683
1684 /**************************************************************************
1685  *                              mciGetCreatorTask               [WINMM.40]
1686  */
1687 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1688 {
1689     FIXME(mci, "(%u) stub\n", uDeviceID);
1690     return 0;
1691 }
1692
1693 /**************************************************************************
1694  *                              mciDriverYield                  [MMSYSTEM.710]
1695  */
1696 UINT16 WINAPI mciDriverYield16(HANDLE16 hnd) 
1697 {
1698     FIXME(mmsys,"(%04x): stub!\n", hnd);
1699     return 0;
1700 }
1701
1702 /**************************************************************************
1703  *                      mciDriverYield                          [WINMM.37]
1704  */
1705 UINT WINAPI mciDriverYield(HANDLE hnd) 
1706 {
1707     FIXME(mmsys,"(%04x): stub!\n", hnd);
1708     return 0;
1709 }
1710
1711 /**************************************************************************
1712  *                              midiOutGetNumDevs       [WINMM.80]
1713  */
1714 UINT WINAPI midiOutGetNumDevs(void)
1715 {
1716     return midiOutGetNumDevs16();
1717 }
1718
1719 /**************************************************************************
1720  *                              midiOutGetNumDevs       [MMSYSTEM.201]
1721  */
1722 UINT16 WINAPI midiOutGetNumDevs16(void)
1723 {
1724     UINT16      count = modMessage(0, MODM_GETNUMDEVS, 0L, 0L, 0L);
1725
1726     TRACE(mmsys, "returns %u\n", count);
1727     return count;
1728 }
1729
1730 /**************************************************************************
1731  *                              midiOutGetDevCapsW      [WINMM.76]
1732  */
1733 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps, UINT uSize)
1734 {
1735     MIDIOUTCAPS16       moc16;
1736     UINT                ret;
1737     
1738     ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
1739     lpCaps->wMid                = moc16.wMid;
1740     lpCaps->wPid                = moc16.wPid;
1741     lpCaps->vDriverVersion      = moc16.vDriverVersion;
1742     lstrcpyAtoW(lpCaps->szPname, moc16.szPname);
1743     lpCaps->wTechnology = moc16.wTechnology;
1744     lpCaps->wVoices             = moc16.wVoices;
1745     lpCaps->wNotes              = moc16.wNotes;
1746     lpCaps->wChannelMask        = moc16.wChannelMask;
1747     lpCaps->dwSupport   = moc16.dwSupport;
1748     return ret;
1749 }
1750
1751 /**************************************************************************
1752  *                              midiOutGetDevCapsA      [WINMM.75]
1753  */
1754 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps, UINT uSize)
1755 {
1756     MIDIOUTCAPS16       moc16;
1757     UINT                ret;
1758     
1759     ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
1760     lpCaps->wMid                = moc16.wMid;
1761     lpCaps->wPid                = moc16.wPid;
1762     lpCaps->vDriverVersion      = moc16.vDriverVersion;
1763     strcpy(lpCaps->szPname, moc16.szPname);
1764     lpCaps->wTechnology = moc16.wTechnology;
1765     lpCaps->wVoices             = moc16.wVoices;
1766     lpCaps->wNotes              = moc16.wNotes;
1767     lpCaps->wChannelMask        = moc16.wChannelMask;
1768     lpCaps->dwSupport   = moc16.dwSupport;
1769     return ret;
1770 }
1771
1772 /**************************************************************************
1773  *                              midiOutGetDevCaps       [MMSYSTEM.202]
1774  */
1775 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps, UINT16 uSize)
1776 {
1777     TRACE(mmsys, "midiOutGetDevCaps\n");
1778     return modMessage(uDeviceID, MODM_GETDEVCAPS, 0, (DWORD)lpCaps,uSize);
1779 }
1780
1781 /**************************************************************************
1782  *                              midiOutGetErrorTextA    [WINMM.77]
1783  */
1784 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1785 {
1786     TRACE(mmsys, "midiOutGetErrorText\n");
1787     return midiGetErrorText(uError, lpText, uSize);
1788 }
1789
1790 /**************************************************************************
1791  *                              midiOutGetErrorTextW    [WINMM.78]
1792  */
1793 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1794 {
1795     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0,uSize);
1796     UINT        ret;
1797     
1798     TRACE(mmsys, "midiOutGetErrorText\n");
1799     ret = midiGetErrorText(uError, xstr, uSize);
1800     lstrcpyAtoW(lpText,xstr);
1801     HeapFree(GetProcessHeap(), 0,xstr);
1802     return ret;
1803 }
1804
1805 /**************************************************************************
1806  *                              midiOutGetErrorText     [MMSYSTEM.203]
1807  */
1808 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
1809 {
1810     TRACE(mmsys, "midiOutGetErrorText\n");
1811     return midiGetErrorText(uError, lpText, uSize);
1812 }
1813
1814 /**************************************************************************
1815  *                              midiGetErrorText        [internal]
1816  */
1817 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1818 {
1819     LPSTR       msgptr;
1820     if ((lpText == NULL) || (uSize < 1)) return(FALSE);
1821     lpText[0] = '\0';
1822     switch (uError) {
1823     case MIDIERR_UNPREPARED:
1824         msgptr = "The MIDI header was not prepared. Use the Prepare function to prepare the header, and then try again.";
1825         break;
1826     case MIDIERR_STILLPLAYING:
1827         msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
1828         break;
1829     case MIDIERR_NOMAP:
1830         msgptr = "A MIDI map was not found. There may be a problem with the driver, or the MIDIMAP.CFG file may be corrupt or missing.";
1831         break;
1832     case MIDIERR_NOTREADY:
1833         msgptr = "The port is transmitting data to the device. Wait until the data has been transmitted, and then try again.";
1834         break;
1835     case MIDIERR_NODEVICE:
1836         msgptr = "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup.";
1837         break;
1838     case MIDIERR_INVALIDSETUP:
1839         msgptr = "The current MIDI setup is damaged. Copy the original MIDIMAP.CFG file to the Windows SYSTEM directory, and then try again.";
1840         break;
1841         /*
1842           msg# 336 : Cannot use the song-pointer time format and the SMPTE time-format together.
1843           msg# 337 : The specified MIDI device is already in use. Wait until it is free, and then try again.
1844           msg# 338 : The specified MIDI device is not installed on the system. Use the Drivers option in Control Panel to install the driver.
1845           msg# 339 : The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup.
1846           msg# 340 : An error occurred using the specified port.
1847           msg# 341 : All multimedia timers are being used by other applications. Quit one of these applications, and then try again.
1848           msg# 342 : There is no current MIDI port.
1849           msg# 343 : There are no MIDI devices installed on the system. Use the Drivers option in Control Panel to install the driver.
1850         */
1851     default:
1852         msgptr = "Unknown MIDI Error !\n";
1853         break;
1854     }
1855     lstrcpynA(lpText, msgptr, uSize);
1856     return TRUE;
1857 }
1858
1859 /**************************************************************************
1860  *                              midiOutOpen             [WINM.84]
1861  */
1862 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
1863                         DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1864 {
1865     HMIDIOUT16  hmo16;
1866     UINT        ret;
1867     
1868     ret = midiOutOpen16(&hmo16,uDeviceID, dwCallback, dwInstance,
1869                         CALLBACK32CONV(dwFlags));
1870     if (lphMidiOut) *lphMidiOut = hmo16;
1871     return ret;
1872 }
1873
1874 /**************************************************************************
1875  *                              midiOutOpen             [MMSYSTEM.204]
1876  */
1877 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
1878                             DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1879 {
1880     HMIDI16                     hMidiOut;
1881     LPMIDIOPENDESC              lpDesc;
1882     DWORD                       dwRet = 0;
1883     BOOL                        bMapperFlg = FALSE;
1884     
1885     if (lphMidiOut != NULL) *lphMidiOut = 0;
1886     TRACE(mmsys, "(%p, %d, %08lX, %08lX, %08lX);\n", 
1887           lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1888     if (uDeviceID == (UINT16)MIDI_MAPPER) {
1889         TRACE(mmsys, "MIDI_MAPPER mode requested !\n");
1890         bMapperFlg = TRUE;
1891         uDeviceID = 0;
1892     }
1893     hMidiOut = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC));
1894     if (lphMidiOut != NULL) 
1895         *lphMidiOut = hMidiOut;
1896     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
1897     if (lpDesc == NULL)
1898         return MMSYSERR_NOMEM;
1899     lpDesc->hMidi = hMidiOut;
1900     lpDesc->dwCallback = dwCallback;
1901     lpDesc->dwInstance = dwInstance;
1902     
1903     while (uDeviceID < MAXMIDIDRIVERS) {
1904         dwRet = modMessage(uDeviceID, MODM_OPEN, 
1905                            lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
1906         if (dwRet == MMSYSERR_NOERROR) break;
1907         if (!bMapperFlg) break;
1908         uDeviceID++;
1909         TRACE(mmsys, "MIDI_MAPPER mode ! try next driver...\n");
1910     }
1911     lpDesc->wDevID = uDeviceID;
1912     return dwRet;
1913 }
1914
1915 /**************************************************************************
1916  *                              midiOutClose            [WINMM.74]
1917  */
1918 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1919 {
1920     return midiOutClose16(hMidiOut);
1921 }
1922
1923 /**************************************************************************
1924  *                              midiOutClose            [MMSYSTEM.205]
1925  */
1926 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
1927 {
1928     LPMIDIOPENDESC      lpDesc;
1929
1930     TRACE(mmsys, "(%04X)\n", hMidiOut);
1931
1932     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
1933     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
1934     return modMessage(lpDesc->wDevID, MODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
1935 }
1936
1937 /**************************************************************************
1938  *                              midiOutPrepareHeader    [WINMM.85]
1939  */
1940 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1941                                  MIDIHDR16* lpMidiOutHdr, UINT uSize)
1942 {
1943     LPMIDIOPENDESC      lpDesc;
1944
1945     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1946
1947     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
1948     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
1949     lpMidiOutHdr->reserved = (DWORD)lpMidiOutHdr->lpData;
1950     return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance, 
1951                       (DWORD)lpMidiOutHdr, (DWORD)uSize);
1952 }
1953
1954 /**************************************************************************
1955  *                              midiOutPrepareHeader    [MMSYSTEM.206]
1956  */
1957 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut,
1958                                      MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
1959 {
1960     LPMIDIOPENDESC      lpDesc;
1961
1962     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1963
1964     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
1965     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
1966     lpMidiOutHdr->reserved = (DWORD)PTR_SEG_TO_LIN(lpMidiOutHdr->lpData);
1967     return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance, 
1968                       (DWORD)lpMidiOutHdr, (DWORD)uSize);
1969 }
1970
1971 /**************************************************************************
1972  *                              midiOutUnprepareHeader  [WINMM.89]
1973  */
1974 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1975                                    MIDIHDR16* lpMidiOutHdr, UINT uSize)
1976 {
1977     return midiOutUnprepareHeader16(hMidiOut, lpMidiOutHdr,uSize);
1978 }
1979
1980 /**************************************************************************
1981  *                              midiOutUnprepareHeader  [MMSYSTEM.207]
1982  */
1983 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut,
1984                                        MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
1985 {
1986     LPMIDIOPENDESC      lpDesc;
1987
1988     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1989
1990     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
1991     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
1992     return modMessage(lpDesc->wDevID, MODM_UNPREPARE, lpDesc->dwInstance, 
1993                       (DWORD)lpMidiOutHdr, (DWORD)uSize);
1994 }
1995
1996 /**************************************************************************
1997  *                              midiOutShortMsg         [WINMM.88]
1998  */
1999 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2000 {
2001     return midiOutShortMsg16(hMidiOut, dwMsg);
2002 }
2003
2004 /**************************************************************************
2005  *                              midiOutShortMsg         [MMSYSTEM.208]
2006  */
2007 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2008 {
2009     LPMIDIOPENDESC      lpDesc;
2010
2011     TRACE(mmsys, "(%04X, %08lX)\n", hMidiOut, dwMsg);
2012
2013     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2014     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2015     return modMessage(lpDesc->wDevID, MODM_DATA, lpDesc->dwInstance, dwMsg, 0L);
2016 }
2017
2018 /**************************************************************************
2019  *                              midiOutLongMsg          [WINMM.82]
2020  */
2021 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2022                            MIDIHDR16* lpMidiOutHdr, UINT uSize)
2023 {
2024     return midiOutLongMsg16(hMidiOut, lpMidiOutHdr,uSize);
2025 }
2026
2027 /**************************************************************************
2028  *                              midiOutLongMsg          [MMSYSTEM.209]
2029  */
2030 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut,
2031                                MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2032 {
2033     LPMIDIOPENDESC      lpDesc;
2034
2035     TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2036
2037     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2038     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2039     return modMessage(lpDesc->wDevID, MODM_LONGDATA, lpDesc->dwInstance, 
2040                       (DWORD)lpMidiOutHdr, (DWORD)uSize);
2041 }
2042
2043 /**************************************************************************
2044  *                              midiOutReset            [WINMM.86]
2045  */
2046 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2047 {
2048     return midiOutReset16(hMidiOut);
2049 }
2050
2051 /**************************************************************************
2052  *                              midiOutReset            [MMSYSTEM.210]
2053  */
2054 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2055 {
2056     LPMIDIOPENDESC      lpDesc;
2057
2058     TRACE(mmsys, "(%04X)\n", hMidiOut);
2059
2060     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2061     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2062     return modMessage(lpDesc->wDevID, MODM_RESET, lpDesc->dwInstance, 0L, 0L);
2063 }
2064
2065 /**************************************************************************
2066  *                              midiOutGetVolume        [WINM.81]
2067  */
2068 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2069 {
2070     return midiOutGetVolume16(uDeviceID, lpdwVolume);
2071 }
2072
2073 /**************************************************************************
2074  *                              midiOutGetVolume        [MMSYSTEM.211]
2075  */
2076 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2077 {
2078     TRACE(mmsys, "(%04X, %p);\n", uDeviceID, lpdwVolume);
2079     return modMessage(uDeviceID, MODM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
2080 }
2081
2082 /**************************************************************************
2083  *                              midiOutSetVolume        [WINMM.87]
2084  */
2085 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2086 {
2087     return midiOutSetVolume16(uDeviceID, dwVolume);
2088 }
2089
2090 /**************************************************************************
2091  *                              midiOutSetVolume        [MMSYSTEM.212]
2092  */
2093 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2094 {
2095     TRACE(mmsys, "(%04X, %08lX);\n", uDeviceID, dwVolume);
2096     return modMessage(uDeviceID, MODM_SETVOLUME, 0L, dwVolume, 0L);
2097 }
2098
2099 /**************************************************************************
2100  *                              midiOutCachePatches             [WINMM.73]
2101  */
2102 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2103                                 WORD* lpwPatchArray, UINT uFlags)
2104 {
2105     return midiOutCachePatches16(hMidiOut,uBank, lpwPatchArray,uFlags);
2106 }
2107
2108 /**************************************************************************
2109  *                              midiOutCachePatches             [MMSYSTEM.213]
2110  */
2111 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2112                                     WORD* lpwPatchArray, UINT16 uFlags)
2113 {
2114     /* not really necessary to support this */
2115     FIXME(mmsys, "not supported yet\n");
2116     return MMSYSERR_NOTSUPPORTED;
2117 }
2118
2119 /**************************************************************************
2120  *                              midiOutCacheDrumPatches [WINMM.72]
2121  */
2122 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2123                                     WORD* lpwKeyArray, UINT uFlags)
2124 {
2125     return midiOutCacheDrumPatches16(hMidiOut,uPatch, lpwKeyArray,uFlags);
2126 }
2127
2128 /**************************************************************************
2129  *                              midiOutCacheDrumPatches [MMSYSTEM.214]
2130  */
2131 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2132                                         WORD* lpwKeyArray, UINT16 uFlags)
2133 {
2134     FIXME(mmsys, "not supported yet\n");
2135     return MMSYSERR_NOTSUPPORTED;
2136 }
2137
2138 /**************************************************************************
2139  *                              midiOutGetID            [WINMM.79]
2140  */
2141 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2142 {
2143     UINT16      xid;
2144     UINT        ret;
2145     
2146     ret = midiOutGetID16(hMidiOut, &xid);
2147     *lpuDeviceID = xid;
2148     return ret;
2149 }
2150
2151 /**************************************************************************
2152  *                              midiOutGetID            [MMSYSTEM.215]
2153  */
2154 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2155 {
2156     TRACE(mmsys, "midiOutGetID\n");
2157     return 0;
2158 }
2159
2160 /**************************************************************************
2161  *                              midiOutMessage          [WINMM.83]
2162  */
2163 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, 
2164                             DWORD dwParam1, DWORD dwParam2)
2165 {
2166     LPMIDIOPENDESC      lpDesc;
2167     
2168     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
2169           hMidiOut, uMessage, dwParam1, dwParam2);
2170     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2171     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2172     switch (uMessage) {
2173     case MODM_OPEN:
2174         FIXME(mmsys,"can't handle MODM_OPEN!\n");
2175         return 0;
2176     case MODM_GETDEVCAPS:
2177         return midiOutGetDevCapsA(hMidiOut, (LPMIDIOUTCAPSA)dwParam1, dwParam2);
2178     case MODM_GETNUMDEVS:
2179     case MODM_RESET:
2180     case MODM_CLOSE:
2181     case MODM_GETVOLUME:
2182     case MODM_SETVOLUME:
2183     case MODM_LONGDATA:
2184     case MODM_PREPARE:
2185     case MODM_UNPREPARE:
2186         /* no argument conversion needed */
2187         break;
2188     default:
2189         ERR(mmsys,"(%04x,%04x,%08lx,%08lx): unhandled message\n",
2190             hMidiOut,uMessage, dwParam1, dwParam2);
2191         break;
2192     }
2193     return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2194 }
2195
2196 /**************************************************************************
2197  *                              midiOutMessage          [MMSYSTEM.216]
2198  */
2199 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage, 
2200                               DWORD dwParam1, DWORD dwParam2)
2201 {
2202     LPMIDIOPENDESC      lpDesc;
2203     
2204     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
2205           hMidiOut, uMessage, dwParam1, dwParam2);
2206     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2207     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2208     switch (uMessage) {
2209     case MODM_OPEN:
2210         FIXME(mmsys,"can't handle MODM_OPEN!\n");
2211         return 0;
2212     case MODM_GETNUMDEVS:
2213     case MODM_RESET:
2214     case MODM_CLOSE:
2215     case MODM_SETVOLUME:
2216         /* no argument conversion needed */
2217         break;
2218     case MODM_GETVOLUME:
2219         return midiOutGetVolume16(hMidiOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
2220     case MODM_LONGDATA:
2221         return midiOutLongMsg16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2222     case MODM_PREPARE:
2223         return midiOutPrepareHeader16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2224     case MODM_UNPREPARE:
2225         return midiOutUnprepareHeader16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2226     default:
2227         ERR(mmsys,"(%04x,%04x,%08lx,%08lx): unhandled message\n",
2228             hMidiOut,uMessage, dwParam1, dwParam2);
2229         break;
2230     }
2231     return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2232 }
2233
2234 /**************************************************************************
2235  *                              midiInGetNumDevs        [WINMM.64]
2236  */
2237 UINT WINAPI midiInGetNumDevs(void)
2238 {
2239     return midiInGetNumDevs16();
2240 }
2241
2242 /**************************************************************************
2243  *                              midiInGetNumDevs        [MMSYSTEM.301]
2244  */
2245 UINT16 WINAPI midiInGetNumDevs16(void)
2246 {
2247     UINT16      count = 0;
2248     TRACE(mmsys, "midiInGetNumDevs\n");
2249     count += midMessage(0, MIDM_GETNUMDEVS, 0L, 0L, 0L);
2250     TRACE(mmsys, "midiInGetNumDevs return %u \n", count);
2251     return count;
2252 }
2253
2254 /**************************************************************************
2255  *                              midiInGetDevCaps        [WINMM.60]
2256  */
2257 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2258 {
2259     MIDIINCAPS16        mic16;
2260     UINT                ret = midiInGetDevCaps16(uDeviceID, &mic16,uSize);
2261     
2262     lpCaps->wMid = mic16.wMid;
2263     lpCaps->wPid = mic16.wPid;
2264     lpCaps->vDriverVersion = mic16.vDriverVersion;
2265     lstrcpyAtoW(lpCaps->szPname, mic16.szPname);
2266     lpCaps->dwSupport = mic16.dwSupport;
2267     return ret;
2268 }
2269
2270 /**************************************************************************
2271  *                              midiInGetDevCaps        [WINMM.59]
2272  */
2273 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2274 {
2275     MIDIINCAPS16        mic16;
2276     UINT                ret = midiInGetDevCaps16(uDeviceID, &mic16,uSize);
2277     
2278     lpCaps->wMid = mic16.wMid;
2279     lpCaps->wPid = mic16.wPid;
2280     lpCaps->vDriverVersion = mic16.vDriverVersion;
2281     strcpy(lpCaps->szPname, mic16.szPname);
2282     lpCaps->dwSupport = mic16.dwSupport;
2283     return ret;
2284 }
2285
2286 /**************************************************************************
2287  *                              midiInGetDevCaps        [MMSYSTEM.302]
2288  */
2289 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID,
2290                                  LPMIDIINCAPS16 lpCaps, UINT16 uSize)
2291 {
2292     TRACE(mmsys, "midiInGetDevCaps\n");
2293     return midMessage(uDeviceID, MIDM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
2294 }
2295
2296 /**************************************************************************
2297  *                              midiInGetErrorText              [WINMM.62]
2298  */
2299 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2300 {
2301     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0,uSize);
2302     UINT        ret = midiInGetErrorText16(uError,xstr,uSize);
2303     lstrcpyAtoW(lpText,xstr);
2304     HeapFree(GetProcessHeap(), 0,xstr);
2305     return ret;
2306 }
2307
2308 /**************************************************************************
2309  *                              midiInGetErrorText              [WINMM.61]
2310  */
2311 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2312 {
2313     return midiInGetErrorText16(uError, lpText,uSize);
2314 }
2315
2316 /**************************************************************************
2317  *                              midiInGetErrorText              [MMSYSTEM.303]
2318  */
2319 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2320 {
2321     TRACE(mmsys, "midiInGetErrorText\n");
2322     return (midiGetErrorText(uError, lpText, uSize));
2323 }
2324
2325 /**************************************************************************
2326  *                              midiInOpen              [WINMM.66]
2327  */
2328 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2329                        DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2330 {
2331     HMIDIIN16   xhmid16;
2332     UINT                ret = midiInOpen16(&xhmid16,uDeviceID, dwCallback, dwInstance,
2333                                            CALLBACK32CONV(dwFlags));
2334     if (lphMidiIn) 
2335         *lphMidiIn = xhmid16;
2336     return ret;
2337 }
2338
2339 /**************************************************************************
2340  *                              midiInOpen              [MMSYSTEM.304]
2341  */
2342 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2343                            DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2344 {
2345     HMIDI16                     hMidiIn;
2346     LPMIDIOPENDESC              lpDesc;
2347     DWORD                       dwRet = 0;
2348     BOOL                        bMapperFlg = FALSE;
2349     
2350     if (lphMidiIn != NULL) 
2351         *lphMidiIn = 0;
2352     TRACE(mmsys, "(%p, %d, %08lX, %08lX, %08lX);\n", 
2353           lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2354     if (uDeviceID == (UINT16)MIDI_MAPPER) {
2355         TRACE(mmsys, "MIDI_MAPPER mode requested !\n");
2356         bMapperFlg = TRUE;
2357         uDeviceID = 0;
2358     }
2359     hMidiIn = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC));
2360     if (lphMidiIn != NULL) 
2361         *lphMidiIn = hMidiIn;
2362     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2363     if (lpDesc == NULL) 
2364         return MMSYSERR_NOMEM;
2365     lpDesc->hMidi = hMidiIn;
2366     lpDesc->dwCallback = dwCallback;
2367     lpDesc->dwInstance = dwInstance;
2368     
2369     while (uDeviceID < MAXMIDIDRIVERS) {
2370         dwRet = midMessage(uDeviceID, MIDM_OPEN, 
2371                            lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2372         if (dwRet == MMSYSERR_NOERROR) 
2373             break;
2374         if (!bMapperFlg) 
2375             break;
2376         uDeviceID++;
2377         TRACE(mmsys, "MIDI_MAPPER mode ! try next driver...\n");
2378     }
2379     lpDesc->wDevID = uDeviceID;
2380     return dwRet;
2381 }
2382
2383 /**************************************************************************
2384  *                              midiInClose             [WINMM.58]
2385  */
2386 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2387 {
2388     return midiInClose16(hMidiIn);
2389 }
2390
2391 /**************************************************************************
2392  *                              midiInClose             [MMSYSTEM.305]
2393  */
2394 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2395 {
2396     LPMIDIOPENDESC      lpDesc;
2397     TRACE(mmsys, "(%04X)\n", hMidiIn);
2398     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2399     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2400     return midMessage(lpDesc->wDevID, MIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2401 }
2402
2403 /**************************************************************************
2404  *                              midiInPrepareHeader     [WINMM.67]
2405  */
2406 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2407                                 MIDIHDR16* lpMidiInHdr, UINT uSize)
2408 {
2409     LPMIDIOPENDESC      lpDesc;
2410     
2411     TRACE(mmsys, "(%04X, %p, %d)\n", 
2412           hMidiIn, lpMidiInHdr, uSize);
2413     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2414     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2415     lpMidiInHdr->reserved = (DWORD)lpMidiInHdr->lpData;
2416     return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance, 
2417                       (DWORD)lpMidiInHdr, (DWORD)uSize);
2418 }
2419
2420 /**************************************************************************
2421  *                              midiInPrepareHeader     [MMSYSTEM.306]
2422  */
2423 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn,
2424                                     MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2425 {
2426     LPMIDIOPENDESC      lpDesc;
2427     
2428     TRACE(mmsys, "(%04X, %p, %d)\n", 
2429           hMidiIn, lpMidiInHdr, uSize);
2430     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2431     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2432     lpMidiInHdr->reserved = (DWORD)PTR_SEG_TO_LIN(lpMidiInHdr->lpData);
2433     return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance, 
2434                       (DWORD)lpMidiInHdr, (DWORD)uSize);
2435 }
2436
2437 /**************************************************************************
2438  *                              midiInUnprepareHeader   [WINMM.71]
2439  */
2440 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2441                                   MIDIHDR16* lpMidiInHdr, UINT uSize)
2442 {
2443     return midiInUnprepareHeader16(hMidiIn, lpMidiInHdr,uSize);
2444 }
2445
2446 /**************************************************************************
2447  *                              midiInUnprepareHeader   [MMSYSTEM.307]
2448  */
2449 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn,
2450                                       MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2451 {
2452     LPMIDIOPENDESC      lpDesc;
2453     TRACE(mmsys, "(%04X, %p, %d)\n", 
2454           hMidiIn, lpMidiInHdr, uSize);
2455     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2456     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2457     return midMessage(lpDesc->wDevID, MIDM_UNPREPARE, lpDesc->dwInstance, 
2458                       (DWORD)lpMidiInHdr, (DWORD)uSize);
2459 }
2460
2461 /**************************************************************************
2462  *                              midiInAddBuffer         [WINMM.57]
2463  */
2464 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2465                             MIDIHDR16* lpMidiInHdr, UINT uSize)
2466 {
2467     return midiInAddBuffer16(hMidiIn, lpMidiInHdr,uSize);
2468 }
2469
2470 /**************************************************************************
2471  *                              midiInAddBuffer         [MMSYSTEM.308]
2472  */
2473 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn,
2474                                 MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2475 {
2476     TRACE(mmsys, "midiInAddBuffer\n");
2477     return 0;
2478 }
2479
2480 /**************************************************************************
2481  *                              midiInStart                     [WINMM.69]
2482  */
2483 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2484 {
2485     return midiInStart16(hMidiIn);
2486 }
2487
2488 /**************************************************************************
2489  *                              midiInStart                     [MMSYSTEM.309]
2490  */
2491 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2492 {
2493     LPMIDIOPENDESC      lpDesc;
2494     
2495     TRACE(mmsys, "(%04X)\n", hMidiIn);
2496     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2497     if (lpDesc == NULL) 
2498         return MMSYSERR_INVALHANDLE;
2499     return midMessage(lpDesc->wDevID, MIDM_START, lpDesc->dwInstance, 0L, 0L);
2500 }
2501
2502 /**************************************************************************
2503  *                              midiInStop                      [WINMM.70]
2504  */
2505 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2506 {
2507     return midiInStop16(hMidiIn);
2508 }
2509
2510 /**************************************************************************
2511  *                              midiInStop                      [MMSYSTEM.310]
2512  */
2513 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2514 {
2515     LPMIDIOPENDESC      lpDesc;
2516     
2517     TRACE(mmsys, "(%04X)\n", hMidiIn);
2518     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2519     if (lpDesc == NULL) 
2520         return MMSYSERR_INVALHANDLE;
2521     return midMessage(lpDesc->wDevID, MIDM_STOP, lpDesc->dwInstance, 0L, 0L);
2522 }
2523
2524 /**************************************************************************
2525  *                              midiInReset                     [WINMM.68]
2526  */
2527 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2528 {
2529     return midiInReset16(hMidiIn);
2530 }
2531
2532 /**************************************************************************
2533  *                              midiInReset                     [MMSYSTEM.311]
2534  */
2535 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2536 {
2537     LPMIDIOPENDESC      lpDesc;
2538     
2539     TRACE(mmsys, "(%04X)\n", hMidiIn);
2540     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2541     if (lpDesc == NULL) 
2542         return MMSYSERR_INVALHANDLE;
2543     return midMessage(lpDesc->wDevID, MIDM_RESET, lpDesc->dwInstance, 0L, 0L);
2544 }
2545
2546 /**************************************************************************
2547  *                              midiInGetID                     [WINMM.63]
2548  */
2549 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2550 {
2551     LPMIDIOPENDESC      lpDesc;
2552     
2553     TRACE(mmsys, "(%04X, %p)\n", hMidiIn, lpuDeviceID);
2554     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2555     if (lpDesc == NULL) 
2556         return MMSYSERR_INVALHANDLE;
2557     if (lpuDeviceID == NULL) 
2558         return MMSYSERR_INVALPARAM;
2559     *lpuDeviceID = lpDesc->wDevID;
2560     
2561     return MMSYSERR_NOERROR;
2562 }
2563
2564 /**************************************************************************
2565  *                              midiInGetID                     [MMSYSTEM.312]
2566  */
2567 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
2568 {
2569     LPMIDIOPENDESC      lpDesc;
2570     
2571     TRACE(mmsys, "(%04X, %p)\n", hMidiIn, lpuDeviceID);
2572     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2573     if (lpDesc == NULL) 
2574         return MMSYSERR_INVALHANDLE;
2575     if (lpuDeviceID == NULL) 
2576         return MMSYSERR_INVALPARAM;
2577     *lpuDeviceID = lpDesc->wDevID;
2578     
2579     return MMSYSERR_NOERROR;
2580 }
2581
2582 /**************************************************************************
2583  *                              midiInMessage           [WINMM.65]
2584  */
2585 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, 
2586                            DWORD dwParam1, DWORD dwParam2)
2587 {
2588     LPMIDIOPENDESC      lpDesc;
2589     
2590     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
2591           hMidiIn, uMessage, dwParam1, dwParam2);
2592     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2593     if (lpDesc == NULL) 
2594         return MMSYSERR_INVALHANDLE;
2595     
2596     switch (uMessage) {
2597     case MIDM_OPEN:
2598         FIXME(mmsys,"can't handle MIDM_OPEN!\n");
2599         return 0;
2600     case MIDM_GETDEVCAPS:
2601         return midiInGetDevCapsA(hMidiIn, (LPMIDIINCAPSA)dwParam1, dwParam2);
2602     case MIDM_GETNUMDEVS:
2603     case MIDM_RESET:
2604     case MIDM_STOP:
2605     case MIDM_START:
2606     case MIDM_CLOSE:
2607         /* no argument conversion needed */
2608         break;
2609     case MIDM_PREPARE:
2610         return midiInPrepareHeader(hMidiIn, (LPMIDIHDR16)dwParam1, dwParam2);
2611     case MIDM_UNPREPARE:
2612         return midiInUnprepareHeader(hMidiIn, (LPMIDIHDR16)dwParam1, dwParam2);
2613     case MIDM_ADDBUFFER:
2614         return midiInAddBuffer(hMidiIn, (LPMIDIHDR16)dwParam1, dwParam2);
2615     default:
2616         ERR(mmsys,"(%04x,%04x,%08lx,%08lx): unhandled message\n",
2617             hMidiIn,uMessage, dwParam1, dwParam2);
2618         break;
2619     }
2620     return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2621 }
2622
2623 /**************************************************************************
2624  *                              midiInMessage           [MMSYSTEM.313]
2625  */
2626 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage, 
2627                              DWORD dwParam1, DWORD dwParam2)
2628 {
2629     LPMIDIOPENDESC      lpDesc;
2630
2631     TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
2632
2633     lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2634     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2635     switch (uMessage) {
2636     case MIDM_OPEN:
2637         WARN(mmsys,"can't handle MIDM_OPEN!\n");
2638         return 0;
2639     case MIDM_GETDEVCAPS:
2640         return midiInGetDevCaps16(hMidiIn, (LPMIDIINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2641     case MIDM_GETNUMDEVS:
2642     case MIDM_RESET:
2643     case MIDM_STOP:
2644     case MIDM_START:
2645     case MIDM_CLOSE:
2646         /* no argument conversion needed */
2647         break;
2648     case MIDM_PREPARE:
2649         return midiInPrepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2650     case MIDM_UNPREPARE:
2651         return midiInUnprepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2652     case MIDM_ADDBUFFER:
2653         return midiInAddBuffer16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2654     default:
2655         ERR(mmsys,"(%04x,%04x,%08lx,%08lx): unhandled message\n",
2656             hMidiIn,uMessage, dwParam1, dwParam2);
2657         break;
2658     }
2659     return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2660 }
2661
2662 #define MIDI_STREAM_MAGIC       0xC9080F17
2663
2664 typedef struct {
2665     DWORD               dwMagic;
2666     HMIDIOUT            hDevice;
2667     /*     thread ID */
2668     DWORD               dwTempo;
2669     DWORD               dwTimeDiv;
2670     DWORD               dwMS;
2671     DWORD               dwStatus; 
2672     LPMIDIHDR   lpMidiHdr;
2673 } WINE_MIDIStream;
2674
2675 /**************************************************************************
2676  *                              MMSYSTEM_MidiStreamPlayer       [internal]
2677  */
2678 static  void    WINE_UNUSED MMSYSTEM_MidiStreamPlayer(WINE_MIDIStream* ms)
2679 {
2680     /* FIXME: should I sleep a bit when there is no pending lpMidiHdr ? 
2681      * => provide a better synchronization system
2682      * midiStreamPause/midiStreamRestart should freeze/thaw this thread
2683      * global resource should guard access to ms->lpMidiHdr list, or 
2684      * use a MB to send new LPMIDIHDR
2685      * an empty ms->lpMidiHdr list should freeze this thread 
2686      */
2687     for (;;) {
2688         if (ms->dwStatus && ms->lpMidiHdr) {
2689             LPMIDIEVENT         me = (LPMIDIEVENT)(ms->lpMidiHdr->lpData + ms->lpMidiHdr->dwOffset);
2690
2691             FIXME(mmsys, "Should wait for current time to be in sync with me->dwDeltaTime\n");
2692
2693             if (me->dwEvent & MEVT_F_CALLBACK) {
2694                 WARN(mmsys, "Should generate callback when encountering F_CALLBACK flagged midi events...\n");
2695             }
2696             switch (MEVT_EVENTTYPE(me->dwEvent)) {
2697             case MEVT_COMMENT:
2698                 /* do nothing, skip bytes */
2699                 break;
2700             case MEVT_LONGMSG:
2701                 WARN(mmsys, "NIY: sending Sysex Event");
2702                 break;
2703             case MEVT_NOP:
2704                 break;
2705             case MEVT_SHORTMSG:
2706                 midiOutShortMsg(ms->hDevice, MEVT_EVENTPARM(me->dwEvent));
2707                 break;
2708             case MEVT_TEMPO:
2709                 ms->dwTempo = MEVT_EVENTPARM(me->dwEvent);
2710                 break;
2711             case MEVT_VERSION:
2712                 break;    
2713             }
2714             ms->lpMidiHdr->dwOffset += sizeof(MIDIEVENT);
2715             if (me->dwEvent & MEVT_F_LONG) {
2716                 ms->lpMidiHdr->dwOffset += MEVT_EVENTPARM(me->dwEvent);
2717             }
2718             if (ms->lpMidiHdr->dwOffset >= ms->lpMidiHdr->dwBufferLength) {
2719                 ms->lpMidiHdr->dwFlags |= MHDR_DONE;
2720                 ms->lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2721                 ms->lpMidiHdr = (LPMIDIHDR)ms->lpMidiHdr->lpNext; 
2722                 WARN(mmsys, "Should generate callback when done with MIDIHDR...\n");
2723             }
2724             FIXME(mmsys, "Should accordingly update ms->dwMS with me->dwDeltaTime\n");
2725         }
2726     }
2727 }
2728
2729 /**************************************************************************
2730  *                              midiStreamClose                 [WINMM.90]
2731  */
2732 MMRESULT WINAPI midiStreamClose(HMIDISTRM hms)
2733 {
2734     WINE_MIDIStream*    ms;
2735
2736     TRACE(midi, "(%08x)!\n", hms);
2737
2738     ms = (WINE_MIDIStream*)hms;
2739     if (!ms || ms->dwMagic != MIDI_STREAM_MAGIC)        
2740         return MMSYSERR_INVALHANDLE;
2741
2742     free(ms);
2743
2744     return MMSYSERR_NOTSUPPORTED;
2745 }
2746
2747 /**************************************************************************
2748  *                              midiStreamOpen                  [WINMM.91]
2749  */
2750 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* phms, LPUINT lpuDeviceID, 
2751                                DWORD cMidi, DWORD dwCallback, 
2752                                DWORD dwInstance, DWORD fdwOpen) 
2753 {
2754     WINE_MIDIStream*    ms;
2755
2756     TRACE(midi, "(%p,%p,%ld, 0x%08lx, 0x%08lx, 0x%08lx), stub!\n",
2757           phms, lpuDeviceID,cMidi, dwCallback, dwInstance, fdwOpen);
2758
2759     if (cMidi != 1 || phms == NULL || lpuDeviceID == NULL)
2760         return MMSYSERR_INVALPARAM;
2761     
2762     ms = malloc(sizeof(WINE_MIDIStream));
2763     *phms = (HMIDISTRM)ms;
2764     ms->dwMagic = MIDI_STREAM_MAGIC;
2765     ms->dwTempo = 50000;        /* FIXME */
2766     ms->dwTimeDiv = 1;          /* FIXME */
2767     ms->dwMS = 0;
2768     ms->dwStatus = 0;
2769
2770     /* FIXME is this correct ? */
2771     *lpuDeviceID = 0;
2772     /* FIXME is this correct ? */
2773     return midiOutOpen(&(ms->hDevice), *lpuDeviceID, dwCallback, dwInstance, fdwOpen);
2774 }
2775
2776 /**************************************************************************
2777  *                              midiStreamOut                   [WINMM.92]
2778  */
2779 MMRESULT WINAPI midiStreamOut(HMIDISTRM hms, LPMIDIHDR16 lpMidiHdr, UINT cbMidiHdr) 
2780 {
2781     FIXME(midi, "(%08x, %p, %u) stub!\n", hms, lpMidiHdr, cbMidiHdr);
2782     return MMSYSERR_NOTSUPPORTED;
2783 }
2784
2785 /**************************************************************************
2786  *                              midiStreamPause                 [WINMM.93]
2787  */
2788 MMRESULT WINAPI midiStreamPause(HMIDISTRM hms) 
2789 {
2790     WINE_MIDIStream*    ms;
2791
2792     TRACE(midi, "(%08x)!\n", hms);
2793
2794     ms = (WINE_MIDIStream*)hms;
2795     if (!ms || ms->dwMagic != MIDI_STREAM_MAGIC)        
2796         return MMSYSERR_INVALHANDLE;
2797
2798     ms->dwStatus = 0;
2799     return MMSYSERR_NOERROR;
2800 }
2801
2802 /**************************************************************************
2803  *                              midiStreamPosition              [WINMM.94]
2804  */
2805 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hms, LPMMTIME lpMMT, UINT cbmmt) 
2806 {
2807     WINE_MIDIStream*    ms;
2808     DWORD               ret = MMSYSERR_NOERROR;
2809
2810     FIXME(midi, "(%08x, %p, %u) stub!\n", hms, lpMMT, cbmmt);
2811
2812     ms = (WINE_MIDIStream*)hms;
2813
2814     if (!ms || ms->dwMagic != MIDI_STREAM_MAGIC) {
2815         ret = MMSYSERR_INVALHANDLE;
2816     } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2817         ret = MMSYSERR_INVALPARAM;
2818     } else {
2819         switch (lpMMT->wType) {
2820         case TIME_MS:   
2821             lpMMT->u.ms = ms->dwMS;     
2822             break;
2823         default:                
2824             lpMMT->wType = TIME_MS;
2825             ret = MMSYSERR_INVALPARAM;
2826         }
2827     }
2828     return ret;
2829 }
2830
2831 /**************************************************************************
2832  *                              midiStreamProperty              [WINMM.95]
2833  */
2834 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hms, LPBYTE lpPropData, DWORD dwProperty) 
2835 {
2836     WINE_MIDIStream*    ms = (WINE_MIDIStream*)hms;
2837     MMRESULT            ret = MMSYSERR_NOERROR;
2838
2839     TRACE(midi, "(%08x, %p, %lx)\n", hms, lpPropData, dwProperty);
2840
2841     if (!ms || ms->dwMagic != MIDI_STREAM_MAGIC) {      
2842         ret = MMSYSERR_INVALHANDLE;
2843     } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2844         return MMSYSERR_INVALPARAM;
2845     } else if (dwProperty & MIDIPROP_TEMPO) {
2846         MIDIPROPTEMPO*  mpt = (MIDIPROPTEMPO*)lpPropData;
2847         
2848         if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2849             ret = MMSYSERR_INVALPARAM;
2850         } else if (dwProperty & MIDIPROP_GET) {
2851             ms->dwTempo = mpt->dwTempo;
2852         } else if (dwProperty & MIDIPROP_SET) {
2853             mpt->dwTempo = ms->dwTempo;
2854         }
2855     } else if (dwProperty & MIDIPROP_TIMEDIV) {
2856         MIDIPROPTIMEDIV*        mptd = (MIDIPROPTIMEDIV*)lpPropData;
2857         
2858         if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2859             ret = MMSYSERR_INVALPARAM;
2860         } else if (dwProperty & MIDIPROP_GET) {
2861             ms->dwTimeDiv = mptd->dwTimeDiv;
2862         } else if (dwProperty & MIDIPROP_SET) {
2863             mptd->dwTimeDiv = ms->dwTimeDiv;
2864         }    
2865     } else {
2866         ret = MMSYSERR_INVALPARAM;
2867     }
2868
2869     return ret;
2870 }
2871
2872 /**************************************************************************
2873  *                              midiStreamRestart               [WINMM.96]
2874  */
2875 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hms) 
2876 {
2877     WINE_MIDIStream*    ms;
2878
2879     TRACE(midi, "(%08x)!\n", hms);
2880
2881     ms = (WINE_MIDIStream*)hms;
2882     if (!ms || ms->dwMagic != MIDI_STREAM_MAGIC)        
2883         return MMSYSERR_INVALHANDLE;
2884
2885     ms->dwStatus = 1;
2886     return MMSYSERR_NOERROR;
2887 }
2888
2889 /**************************************************************************
2890  *                              midiStreamStop                  [WINMM.97]
2891  */
2892 MMRESULT WINAPI midiStreamStop(HMIDISTRM hms) 
2893 {
2894     FIXME(midi, "(%08x stub!)\n", hms);
2895         return MMSYSERR_NOTSUPPORTED;
2896 }
2897
2898 /**************************************************************************
2899  *                              midiStreamClose                 [MMSYSTEM.252]
2900  */
2901 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hms)
2902 {
2903     return midiStreamClose(hms);
2904 }
2905
2906 /**************************************************************************
2907  *                              midiStreamOpen                  [MMSYSTEM.251]
2908  */
2909 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phms, LPUINT16 devid, 
2910                                    DWORD cMidi, DWORD dwCallback, 
2911                                    DWORD dwInstance, DWORD fdwOpen) 
2912 {
2913     HMIDISTRM   hms32;
2914     MMRESULT    ret;
2915     UINT        devid32;
2916
2917     if (!phms || !devid)
2918         return MMSYSERR_INVALPARAM;
2919     devid32 = *devid;
2920     ret = midiStreamOpen(&hms32, &devid32, cMidi, dwCallback, dwInstance, fdwOpen);
2921     *phms = hms32;
2922     *devid = devid32;
2923     return ret;
2924 }
2925
2926 /**************************************************************************
2927  *                              midiStreamOut                   [MMSYSTEM.254]
2928  */
2929 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hms, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr) 
2930 {
2931     return midiStreamOut(hms, lpMidiHdr, cbMidiHdr);
2932 }
2933
2934 /**************************************************************************
2935  *                              midiStreamPause                 [MMSYSTEM.255]
2936  */
2937 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hms) 
2938 {
2939     return midiStreamPause(hms);
2940 }
2941
2942 /**************************************************************************
2943  *                              midiStreamPosition              [MMSYSTEM.253]
2944  */
2945 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hms, LPMMTIME16 lpmmt, UINT16 cbmmt) 
2946 {
2947     MMTIME      mmt32;
2948     MMRESULT    ret;
2949
2950     if (!lpmmt)
2951         return MMSYSERR_INVALPARAM;
2952     MMSYSTEM_MMTIME16to32(&mmt32, lpmmt);
2953     ret = midiStreamPosition(hms, &mmt32, cbmmt);
2954     MMSYSTEM_MMTIME32to16(lpmmt, &mmt32);
2955     return ret;
2956 }
2957
2958 /**************************************************************************
2959  *                              midiStreamProperty              [MMSYSTEM.250]
2960  */
2961 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hms, LPBYTE lpPropData, DWORD dwProperty) 
2962 {
2963     return midiStreamProperty(hms, lpPropData, dwProperty);
2964 }
2965
2966 /**************************************************************************
2967  *                              midiStreamRestart               [MMSYSTEM.256]
2968  */
2969 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hms) 
2970 {
2971     return midiStreamRestart(hms);
2972 }
2973
2974 /**************************************************************************
2975  *                              midiStreamStop                  [MMSYSTEM.257]
2976  */
2977 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hms) 
2978 {
2979     return midiStreamStop(hms);
2980 }
2981
2982 /**************************************************************************
2983  *                              waveOutGetNumDevs               [MMSYSTEM.401]
2984  */
2985 UINT WINAPI waveOutGetNumDevs() 
2986 {
2987     return waveOutGetNumDevs16();
2988 }
2989
2990 /**************************************************************************
2991  *                              waveOutGetNumDevs               [WINMM.167]
2992  */
2993 UINT16 WINAPI waveOutGetNumDevs16()
2994 {
2995     UINT16      count = 0;
2996     TRACE(mmsys, "waveOutGetNumDevs\n");
2997     /* FIXME: I'm not sure MCI_FirstDevID() is correct */
2998     count += wodMessage(MCI_FirstDevID(), WODM_GETNUMDEVS, 0L, 0L, 0L);
2999     TRACE(mmsys, "waveOutGetNumDevs return %u \n", count);
3000     return count;
3001 }
3002
3003 /**************************************************************************
3004  *                              waveOutGetDevCaps               [MMSYSTEM.402]
3005  */
3006 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID, LPWAVEOUTCAPS16 lpCaps,
3007                                   UINT16 uSize)
3008 {
3009     if (uDeviceID > waveOutGetNumDevs16() - 1) return MMSYSERR_BADDEVICEID;
3010     if (uDeviceID == (UINT16)WAVE_MAPPER) return MMSYSERR_BADDEVICEID; /* FIXME: do we have a wave mapper ? */
3011     TRACE(mmsys, "waveOutGetDevCaps\n");
3012     return wodMessage(uDeviceID, WODM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
3013 }
3014
3015 /**************************************************************************
3016  *                              waveOutGetDevCapsA              [WINMM.162]
3017  */
3018 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3019                                UINT uSize)
3020 {
3021     WAVEOUTCAPS16       woc16;
3022     UINT16 ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3023     
3024     lpCaps->wMid = woc16.wMid;
3025     lpCaps->wPid = woc16.wPid;
3026     lpCaps->vDriverVersion = woc16.vDriverVersion;
3027     strcpy(lpCaps->szPname, woc16.szPname);
3028     lpCaps->dwFormats = woc16.dwFormats;
3029     lpCaps->wChannels = woc16.wChannels;
3030     lpCaps->dwSupport = woc16.dwSupport;
3031     return ret;
3032 }
3033
3034 /**************************************************************************
3035  *                              waveOutGetDevCapsW              [WINMM.163]
3036  */
3037 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3038                                    UINT uSize)
3039 {
3040     WAVEOUTCAPS16       woc16;
3041     UINT ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3042     
3043     lpCaps->wMid = woc16.wMid;
3044     lpCaps->wPid = woc16.wPid;
3045     lpCaps->vDriverVersion = woc16.vDriverVersion;
3046     lstrcpyAtoW(lpCaps->szPname, woc16.szPname);
3047     lpCaps->dwFormats = woc16.dwFormats;
3048     lpCaps->wChannels = woc16.wChannels;
3049     lpCaps->dwSupport = woc16.dwSupport;
3050     return ret;
3051 }
3052
3053 /**************************************************************************
3054  *                              waveOutGetErrorText     [MMSYSTEM.403]
3055  */
3056 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3057 {
3058     TRACE(mmsys, "waveOutGetErrorText\n");
3059     return(waveGetErrorText(uError, lpText, uSize));
3060 }
3061
3062 /**************************************************************************
3063  *                              waveOutGetErrorTextA    [WINMM.164]
3064  */
3065 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3066 {
3067     return(waveOutGetErrorText16(uError, lpText, uSize));
3068 }
3069
3070 /**************************************************************************
3071  *                              waveOutGetErrorTextW    [WINMM.165]
3072  */
3073 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3074 {
3075     LPSTR       xstr = HeapAlloc(GetProcessHeap(), 0,uSize);
3076     UINT        ret = waveOutGetErrorTextA(uError, xstr, uSize);
3077     
3078     lstrcpyAtoW(lpText,xstr);
3079     HeapFree(GetProcessHeap(), 0,xstr);
3080     return ret;
3081 }
3082
3083 /**************************************************************************
3084  *                              waveGetErrorText                [internal]
3085  */
3086 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3087 {
3088     LPSTR       msgptr;
3089     TRACE(mmsys, "(%04X, %p, %d);\n", 
3090           uError, lpText, uSize);
3091     if ((lpText == NULL) || (uSize < 1)) return(FALSE);
3092     lpText[0] = '\0';
3093     switch (uError) {
3094     case MMSYSERR_NOERROR:
3095         msgptr = "The specified command was carried out.";
3096         break;
3097     case MMSYSERR_ERROR:
3098         msgptr = "Undefined external error.";
3099         break;
3100     case MMSYSERR_BADDEVICEID:
3101         msgptr = "A device ID has been used that is out of range for your system.";
3102         break;
3103     case MMSYSERR_NOTENABLED:
3104         msgptr = "The driver was not enabled.";
3105         break;
3106     case MMSYSERR_ALLOCATED:
3107         msgptr = "The specified device is already in use. Wait until it is free, and then try again.";
3108         break;
3109     case MMSYSERR_INVALHANDLE:
3110         msgptr = "The specified device handle is invalid.";
3111         break;
3112     case MMSYSERR_NODRIVER:
3113         msgptr = "There is no driver installed on your system !\n";
3114         break;
3115     case MMSYSERR_NOMEM:
3116         msgptr = "Not enough memory available for this task. Quit one or more applications to increase available memory, and then try again.";
3117         break;
3118     case MMSYSERR_NOTSUPPORTED:
3119         msgptr = "This function is not supported. Use the Capabilities function to determine which functions and messages the driver supports.";
3120         break;
3121     case MMSYSERR_BADERRNUM:
3122         msgptr = "An error number was specified that is not defined in the system.";
3123         break;
3124     case MMSYSERR_INVALFLAG:
3125         msgptr = "An invalid flag was passed to a system function.";
3126         break;
3127     case MMSYSERR_INVALPARAM:
3128         msgptr = "An invalid parameter was passed to a system function.";
3129         break;
3130     case WAVERR_BADFORMAT:
3131         msgptr = "The specified format is not supported or cannot be translated. Use the Capabilities function to determine the supported formats";
3132         break;
3133     case WAVERR_STILLPLAYING:
3134         msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
3135         break;
3136     case WAVERR_UNPREPARED:
3137         msgptr = "The wave header was not prepared. Use the Prepare function to prepare the header, and then try again.";
3138         break;
3139     case WAVERR_SYNC:
3140         msgptr = "Cannot open the device without using the WAVE_ALLOWSYNC flag. Use the flag, and then try again.";
3141         break;
3142     default:
3143         msgptr = "Unknown MMSYSTEM Error !\n";
3144         break;
3145     }
3146     lstrcpynA(lpText, msgptr, uSize);
3147     return TRUE;
3148 }
3149
3150 /**************************************************************************
3151  *                      waveOutOpen                     [WINMM.173]
3152  * All the args/structs have the same layout as the win16 equivalents
3153  */
3154 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3155                         const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3156                         DWORD dwInstance, DWORD dwFlags)
3157 {
3158     HWAVEOUT16  hwo16;
3159     UINT        ret = waveOutOpen16(&hwo16,uDeviceID, lpFormat, dwCallback, dwInstance,
3160                                     CALLBACK32CONV(dwFlags));
3161
3162     if (lphWaveOut) *lphWaveOut=hwo16;
3163     return ret;
3164 }
3165
3166 /**************************************************************************
3167  *                      waveOutOpen                     [MMSYSTEM.404]
3168  */
3169 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3170                             const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3171                             DWORD dwInstance, DWORD dwFlags)
3172 {
3173     HWAVEOUT16  hWaveOut;
3174     LPWAVEOPENDESC      lpDesc;
3175     DWORD               dwRet = 0;
3176     BOOL                bMapperFlg = FALSE;
3177     
3178     TRACE(mmsys, "(%p, %d, %p, %08lX, %08lX, %08lX);\n", 
3179           lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
3180     if (dwFlags & WAVE_FORMAT_QUERY)
3181         TRACE(mmsys, "WAVE_FORMAT_QUERY requested !\n");
3182     if (uDeviceID == (UINT16)WAVE_MAPPER) {
3183         TRACE(mmsys, "WAVE_MAPPER mode requested !\n");
3184         bMapperFlg = TRUE;
3185         uDeviceID = 0;
3186     }
3187     if (lpFormat == NULL) return WAVERR_BADFORMAT;
3188     
3189     hWaveOut = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
3190     if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
3191     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3192     if (lpDesc == NULL) return MMSYSERR_NOMEM;
3193     lpDesc->hWave = hWaveOut;
3194     lpDesc->lpFormat = (LPWAVEFORMAT)lpFormat;  /* should the struct be copied iso pointer? */
3195     lpDesc->dwCallBack = dwCallback;
3196     lpDesc->dwInstance = dwInstance;
3197     if (uDeviceID >= MAXWAVEDRIVERS)
3198         uDeviceID = 0;
3199     while (uDeviceID < MAXWAVEDRIVERS) {
3200         dwRet = wodMessage(uDeviceID, WODM_OPEN, 
3201                            lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
3202         if (dwRet == MMSYSERR_NOERROR) break;
3203         if (!bMapperFlg) break;
3204         uDeviceID++;
3205         TRACE(mmsys, "WAVE_MAPPER mode ! try next driver...\n");
3206     }
3207     lpDesc->uDeviceID = uDeviceID;  /* save physical Device ID */
3208     if (dwFlags & WAVE_FORMAT_QUERY) {
3209         TRACE(mmsys, "End of WAVE_FORMAT_QUERY !\n");
3210         dwRet = waveOutClose(hWaveOut);
3211     }
3212     return dwRet;
3213 }
3214
3215 /**************************************************************************
3216  *                              waveOutClose            [WINMM.161]
3217  */
3218 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3219 {
3220     return waveOutClose16(hWaveOut);
3221 }
3222
3223 /**************************************************************************
3224  *                              waveOutClose            [MMSYSTEM.405]
3225  */
3226 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
3227 {
3228     LPWAVEOPENDESC      lpDesc;
3229     
3230     TRACE(mmsys, "(%04X)\n", hWaveOut);
3231
3232     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3233     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3234     return wodMessage(lpDesc->uDeviceID, WODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
3235 }
3236
3237 /**************************************************************************
3238  *                              waveOutPrepareHeader    [WINMM.175]
3239  */
3240 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
3241                                  WAVEHDR* lpWaveOutHdr, UINT uSize)
3242 {
3243     LPWAVEOPENDESC      lpDesc;
3244     
3245     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3246
3247     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3248     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3249     lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr->lpData;
3250     return wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance, 
3251                        (DWORD)lpWaveOutHdr,uSize);
3252 }
3253
3254 /**************************************************************************
3255  *                              waveOutPrepareHeader    [MMSYSTEM.406]
3256  */
3257 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut,
3258                                      WAVEHDR* lpWaveOutHdr, UINT16 uSize)
3259 {
3260     LPWAVEOPENDESC      lpDesc;
3261     UINT16              ret;
3262     
3263     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3264
3265     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3266     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3267     lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr->lpData;
3268     lpWaveOutHdr->lpData = PTR_SEG_TO_LIN(lpWaveOutHdr->lpData);
3269     ret = wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance, 
3270                       (DWORD)lpWaveOutHdr,uSize);
3271     lpWaveOutHdr->lpData = lpWaveOutHdr->lpData;
3272     return ret;
3273 }
3274
3275 /**************************************************************************
3276  *                              waveOutUnprepareHeader  [WINMM.181]
3277  */
3278 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
3279                                    WAVEHDR* lpWaveOutHdr, UINT uSize)
3280 {
3281     LPWAVEOPENDESC      lpDesc;
3282     
3283     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3284
3285     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3286     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3287     lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr->lpData;
3288     return wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance, 
3289                       (DWORD)lpWaveOutHdr, uSize);
3290 }
3291
3292 /**************************************************************************
3293  *                              waveOutUnprepareHeader  [MMSYSTEM.407]
3294  */
3295 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut,
3296                                        WAVEHDR* lpWaveOutHdr, UINT16 uSize)
3297 {
3298     LPWAVEOPENDESC      lpDesc;
3299     UINT16              ret;
3300     
3301     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3302
3303     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3304     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3305     lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr->lpData;
3306     lpWaveOutHdr->lpData = PTR_SEG_TO_LIN(lpWaveOutHdr->lpData);
3307     ret = wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance, 
3308                      (DWORD)lpWaveOutHdr, uSize);
3309     lpWaveOutHdr->lpData = (LPBYTE)lpWaveOutHdr->reserved;
3310     return ret;
3311 }
3312
3313 /**************************************************************************
3314  *                              waveOutWrite            [MMSYSTEM.408]
3315  */
3316 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, WAVEHDR* lpWaveOutHdr,
3317                          UINT uSize)
3318 {
3319     LPWAVEOPENDESC      lpDesc;
3320
3321     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3322
3323     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3324     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3325     lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr->lpData;
3326     return wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance, (DWORD)lpWaveOutHdr, uSize);
3327 }
3328
3329 /**************************************************************************
3330  *                              waveOutWrite            [MMSYSTEM.408]
3331  */
3332 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, WAVEHDR * lpWaveOutHdr,
3333                              UINT16 uSize)
3334 {
3335     LPWAVEOPENDESC      lpDesc;
3336     UINT16              ret;
3337     
3338     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3339
3340     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3341     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3342     lpWaveOutHdr->reserved =(DWORD)lpWaveOutHdr->lpData;/*save original ptr*/
3343     lpWaveOutHdr->lpData = PTR_SEG_TO_LIN(lpWaveOutHdr->lpData);
3344     ret = wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance, (DWORD)lpWaveOutHdr, uSize);
3345     lpWaveOutHdr->lpData = (LPBYTE)lpWaveOutHdr->reserved;
3346     return ret;
3347 }
3348
3349 /**************************************************************************
3350  *                              waveOutPause            [WINMM.174]
3351  */
3352 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
3353 {
3354     return waveOutPause16(hWaveOut);
3355 }
3356
3357 /**************************************************************************
3358  *                              waveOutPause            [MMSYSTEM.409]
3359  */
3360 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut)
3361 {
3362     LPWAVEOPENDESC      lpDesc;
3363     
3364     TRACE(mmsys, "(%04X)\n", hWaveOut);
3365
3366     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3367     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3368     return wodMessage(lpDesc->uDeviceID, WODM_PAUSE, lpDesc->dwInstance, 0L, 0L);
3369 }
3370
3371 /**************************************************************************
3372  *                              waveOutRestart          [WINMM.177]
3373  */
3374 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
3375 {
3376     return waveOutRestart16(hWaveOut);
3377 }
3378
3379 /**************************************************************************
3380  *                              waveOutRestart          [MMSYSTEM.410]
3381  */
3382 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut)
3383 {
3384     LPWAVEOPENDESC      lpDesc;
3385     
3386     TRACE(mmsys, "(%04X)\n", hWaveOut);
3387
3388     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3389     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3390     return wodMessage(lpDesc->uDeviceID, WODM_RESTART, lpDesc->dwInstance, 0L, 0L);
3391 }
3392
3393 /**************************************************************************
3394  *                              waveOutReset            [WINMM.176]
3395  */
3396 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
3397 {
3398     return waveOutReset16(hWaveOut);
3399 }
3400
3401 /**************************************************************************
3402  *                              waveOutReset            [MMSYSTEM.411]
3403  */
3404 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut)
3405 {
3406     LPWAVEOPENDESC      lpDesc;
3407
3408     TRACE(mmsys, "(%04X)\n", hWaveOut);
3409
3410     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3411     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3412     return wodMessage(lpDesc->uDeviceID, WODM_RESET, lpDesc->dwInstance, 0L, 0L);
3413 }
3414
3415 /**************************************************************************
3416  *                              waveOutGetPosition      [WINMM.170]
3417  */
3418 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
3419                                UINT uSize)
3420 {
3421     MMTIME16    mmt16;
3422     UINT ret;
3423     
3424     mmt16.wType = lpTime->wType;
3425     ret = waveOutGetPosition16(hWaveOut, &mmt16, sizeof(mmt16));
3426     MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
3427     return ret;
3428 }
3429
3430 /**************************************************************************
3431  *                              waveOutGetPosition      [MMSYSTEM.412]
3432  */
3433 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
3434                                    UINT16 uSize)
3435 {
3436     LPWAVEOPENDESC      lpDesc;
3437     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
3438     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3439     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3440     return wodMessage(lpDesc->uDeviceID, WODM_GETPOS, lpDesc->dwInstance, 
3441                        (DWORD)lpTime, (DWORD)uSize);
3442 }
3443
3444 #define WAVEOUT_SHORTCUT_1(xx,XX,atype) \
3445         UINT WINAPI waveOut##xx(HWAVEOUT hWaveOut, atype x)     \
3446 {                                                                       \
3447         return waveOut##xx##16(hWaveOut,x);                             \
3448 }                                                                       \
3449 UINT16 WINAPI waveOut##xx##16(HWAVEOUT16 hWaveOut, atype x)             \
3450 {                                                                       \
3451         LPWAVEOPENDESC  lpDesc;                                         \
3452         TRACE(mmsys, "(%04X, %08lx);\n", hWaveOut, (DWORD)x);           \
3453         lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);         \
3454         if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;                \
3455         return wodMessage(lpDesc->uDeviceID, WODM_##XX,                 \
3456                           lpDesc->dwInstance, (DWORD)x, 0L);            \
3457 }
3458
3459 WAVEOUT_SHORTCUT_1(GetPitch,GETPITCH, DWORD*)
3460 WAVEOUT_SHORTCUT_1(SetPitch,SETPITCH, DWORD)
3461 WAVEOUT_SHORTCUT_1(GetPlaybackRate,GETPLAYBACKRATE, DWORD*)
3462 WAVEOUT_SHORTCUT_1(SetPlaybackRate,SETPLAYBACKRATE, DWORD)
3463     
3464 #define WAVEOUT_SHORTCUT_2(xx,XX,atype) \
3465         UINT WINAPI waveOut##xx(UINT devid, atype x)            \
3466 {                                                                       \
3467         return waveOut##xx##16(devid,x);                                \
3468 }                                                                       \
3469 UINT16 WINAPI waveOut##xx##16(UINT16 devid, atype x)                    \
3470 {                                                                       \
3471         TRACE(mmsys, "(%04X, %08lx);\n", devid, (DWORD)x);              \
3472         return wodMessage(devid, WODM_##XX, 0L, (DWORD)x, 0L);          \
3473 }
3474     
3475 WAVEOUT_SHORTCUT_2(GetVolume,GETVOLUME, DWORD*)
3476 WAVEOUT_SHORTCUT_2(SetVolume,SETVOLUME, DWORD)
3477     
3478 /**************************************************************************
3479  *                              waveOutBreakLoop        [MMSYSTEM.419]
3480  */
3481 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
3482 {
3483     return waveOutBreakLoop16(hWaveOut);
3484 }
3485
3486 /**************************************************************************
3487  *                              waveOutBreakLoop        [MMSYSTEM.419]
3488  */
3489 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut)
3490 {
3491     TRACE(mmsys, "(%04X)\n", hWaveOut);
3492     return MMSYSERR_INVALHANDLE;
3493 }
3494
3495 /**************************************************************************
3496  *                              waveOutGetID            [MMSYSTEM.420]
3497  */
3498 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
3499 {
3500     LPWAVEOPENDESC      lpDesc;
3501
3502     TRACE(mmsys, "(%04X, %p);\n", hWaveOut, lpuDeviceID);
3503
3504     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3505     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3506     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3507     *lpuDeviceID = lpDesc->uDeviceID;
3508     return 0;
3509 }
3510
3511 /**************************************************************************
3512  *                              waveOutGetID            [MMSYSTEM.420]
3513  */
3514 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
3515 {
3516     LPWAVEOPENDESC      lpDesc;
3517
3518     TRACE(mmsys, "(%04X, %p);\n", hWaveOut, lpuDeviceID);
3519
3520     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3521     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3522     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3523     *lpuDeviceID = lpDesc->uDeviceID;
3524     return 0;
3525 }
3526
3527 /**************************************************************************
3528  *                              waveOutMessage          [MMSYSTEM.421]
3529  */
3530 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, 
3531                               DWORD dwParam1, DWORD dwParam2)
3532 {
3533     LPWAVEOPENDESC      lpDesc;
3534     
3535     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3536     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3537     switch (uMessage) {
3538     case WODM_GETNUMDEVS:
3539     case WODM_GETPOS:
3540     case WODM_GETVOLUME:
3541     case WODM_GETPITCH:
3542     case WODM_GETPLAYBACKRATE:
3543     case WODM_SETVOLUME:
3544     case WODM_SETPITCH:
3545     case WODM_SETPLAYBACKRATE:
3546     case WODM_RESET:
3547     case WODM_PAUSE:
3548     case WODM_PREPARE:
3549     case WODM_UNPREPARE:
3550     case WODM_STOP:
3551     case WODM_CLOSE:
3552         /* no argument conversion needed */
3553         break;
3554     case WODM_WRITE:
3555         return waveOutWrite(hWaveOut, (LPWAVEHDR)dwParam1, dwParam2);
3556     case WODM_GETDEVCAPS:
3557         /* FIXME: UNICODE/ANSI? */
3558         return waveOutGetDevCapsA(hWaveOut, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
3559     case WODM_OPEN:
3560         FIXME(mmsys,"can't handle WODM_OPEN, please report.\n");
3561         break;
3562     default:
3563         ERR(mmsys,"(0x%04x, 0x%04x,%08lx,%08lx): unhandled message\n",
3564             hWaveOut,uMessage, dwParam1, dwParam2);
3565         break;
3566     }
3567     return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
3568 }
3569
3570 /**************************************************************************
3571  *                              waveOutMessage          [MMSYSTEM.421]
3572  */
3573 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage, 
3574                               DWORD dwParam1, DWORD dwParam2)
3575 {
3576     LPWAVEOPENDESC      lpDesc;
3577     
3578     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3579     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3580     switch (uMessage) {
3581     case WODM_GETNUMDEVS:
3582     case WODM_SETVOLUME:
3583     case WODM_SETPITCH:
3584     case WODM_SETPLAYBACKRATE:
3585     case WODM_RESET:
3586     case WODM_PAUSE:
3587     case WODM_STOP:
3588     case WODM_CLOSE:
3589         /* no argument conversion needed */
3590         break;
3591     case WODM_GETPOS:
3592         return waveOutGetPosition16(hWaveOut, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3593     case WODM_GETVOLUME:
3594         return waveOutGetVolume16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
3595     case WODM_GETPITCH:
3596         return waveOutGetPitch16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
3597     case WODM_GETPLAYBACKRATE:
3598         return waveOutGetPlaybackRate16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
3599     case WODM_GETDEVCAPS:
3600         return waveOutGetDevCaps16(hWaveOut, (LPWAVEOUTCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3601     case WODM_PREPARE:
3602         return waveOutPrepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3603     case WODM_UNPREPARE:
3604         return waveOutUnprepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3605     case WODM_WRITE:
3606         return waveOutWrite16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3607     case WODM_OPEN:
3608         FIXME(mmsys,"can't handle WODM_OPEN, please report.\n");
3609         break;
3610     default:
3611         ERR(mmsys,"(0x%04x, 0x%04x,%08lx,%08lx): unhandled message\n",
3612             hWaveOut,uMessage, dwParam1, dwParam2);
3613     }
3614     return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
3615 }
3616
3617 /**************************************************************************
3618  *                              waveInGetNumDevs                [WINMM.151]
3619  */
3620 UINT WINAPI waveInGetNumDevs()
3621 {
3622     return waveInGetNumDevs16();
3623 }
3624
3625 /**************************************************************************
3626  *                              waveInGetNumDevs                [MMSYSTEM.501]
3627  */
3628 UINT16 WINAPI waveInGetNumDevs16()
3629 {
3630     UINT16      count = 0;
3631
3632     TRACE(mmsys, "waveInGetNumDevs\n");
3633     count += widMessage(0, WIDM_GETNUMDEVS, 0L, 0L, 0L);
3634     TRACE(mmsys, "waveInGetNumDevs return %u \n", count);
3635     return count;
3636 }
3637
3638 /**************************************************************************
3639  *                              waveInGetDevCapsA               [WINMM.147]
3640  */
3641 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
3642 {
3643     WAVEINCAPS16        wic16;
3644     UINT                ret = waveInGetDevCaps16(uDeviceID, &wic16,uSize);
3645     
3646     lpCaps->wMid = wic16.wMid;
3647     lpCaps->wPid = wic16.wPid;
3648     lpCaps->vDriverVersion = wic16.vDriverVersion;
3649     lstrcpyAtoW(lpCaps->szPname, wic16.szPname);
3650     lpCaps->dwFormats = wic16.dwFormats;
3651     lpCaps->wChannels = wic16.wChannels;
3652     
3653     return ret;
3654 }
3655
3656 /**************************************************************************
3657  *                              waveInGetDevCapsA               [WINMM.146]
3658  */
3659 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
3660 {
3661     WAVEINCAPS16        wic16;
3662     UINT                ret = waveInGetDevCaps16(uDeviceID, &wic16,uSize);
3663     
3664     lpCaps->wMid = wic16.wMid;
3665     lpCaps->wPid = wic16.wPid;
3666     lpCaps->vDriverVersion = wic16.vDriverVersion;
3667     strcpy(lpCaps->szPname, wic16.szPname);
3668     lpCaps->dwFormats = wic16.dwFormats;
3669     lpCaps->wChannels = wic16.wChannels;
3670     return ret;
3671 }
3672
3673 /**************************************************************************
3674  *                              waveInGetDevCaps                [MMSYSTEM.502]
3675  */
3676 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps, UINT16 uSize)
3677 {
3678     TRACE(mmsys, "waveInGetDevCaps\n");
3679
3680     return widMessage(uDeviceID, WIDM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
3681 }
3682
3683 /**************************************************************************
3684  *                              waveInGetErrorTextA     [WINMM.148]
3685  */
3686 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3687 {
3688     TRACE(mmsys, "waveInGetErrorText\n");
3689     return(waveGetErrorText(uError, lpText, uSize));
3690 }
3691
3692 /**************************************************************************
3693  *                              waveInGetErrorTextW     [WINMM.149]
3694  */
3695 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3696 {
3697     LPSTR txt = HeapAlloc(GetProcessHeap(), 0,uSize);
3698     UINT        ret = waveGetErrorText(uError, txt, uSize);
3699     
3700     lstrcpyAtoW(lpText, txt);
3701     HeapFree(GetProcessHeap(), 0, txt);
3702     return ret;
3703 }
3704
3705 /**************************************************************************
3706  *                              waveInGetErrorText      [MMSYSTEM.503]
3707  */
3708 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3709 {
3710     TRACE(mmsys, "waveInGetErrorText\n");
3711     return(waveGetErrorText(uError, lpText, uSize));
3712 }
3713
3714 /**************************************************************************
3715  *                              waveInOpen                      [WINMM.154]
3716  */
3717 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
3718                        const LPWAVEFORMAT lpFormat, DWORD dwCallback,
3719                        DWORD dwInstance, DWORD dwFlags)
3720 {
3721     HWAVEIN16   hwin16;
3722     UINT        ret = waveInOpen16(&hwin16,uDeviceID, lpFormat, dwCallback, dwInstance,
3723                                  CALLBACK32CONV(dwFlags));
3724     if (lphWaveIn) *lphWaveIn = hwin16;
3725     return ret;
3726 }
3727
3728 /**************************************************************************
3729  *                              waveInOpen                      [MMSYSTEM.504]
3730  */
3731 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
3732                            const LPWAVEFORMAT lpFormat, DWORD dwCallback,
3733                            DWORD dwInstance, DWORD dwFlags)
3734 {
3735     HWAVEIN16 hWaveIn;
3736     LPWAVEOPENDESC      lpDesc;
3737     DWORD       dwRet = 0;
3738     BOOL        bMapperFlg = FALSE;
3739
3740     TRACE(mmsys, "(%p, %d, %p, %08lX, %08lX, %08lX);\n", 
3741           lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
3742     if (dwFlags & WAVE_FORMAT_QUERY)
3743         TRACE(mmsys, "WAVE_FORMAT_QUERY requested !\n");
3744     if (uDeviceID == (UINT16)WAVE_MAPPER) {
3745         TRACE(mmsys, "WAVE_MAPPER mode requested !\n");
3746         bMapperFlg = TRUE;
3747         uDeviceID = 0;
3748     }
3749     if (lpFormat == NULL) return WAVERR_BADFORMAT;
3750     hWaveIn = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
3751     if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
3752     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3753     if (lpDesc == NULL) return MMSYSERR_NOMEM;
3754     lpDesc->hWave = hWaveIn;
3755     lpDesc->lpFormat = lpFormat;
3756     lpDesc->dwCallBack = dwCallback;
3757     lpDesc->dwInstance = dwInstance;
3758     while (uDeviceID < MAXWAVEDRIVERS) {
3759         dwRet = widMessage(uDeviceID, WIDM_OPEN, 
3760                            lpDesc->dwInstance, (DWORD)lpDesc, 0L);
3761         if (dwRet == MMSYSERR_NOERROR) break;
3762         if (!bMapperFlg) break;
3763         uDeviceID++;
3764         TRACE(mmsys, "WAVE_MAPPER mode ! try next driver...\n");
3765     }
3766     lpDesc->uDeviceID = uDeviceID;
3767     if (dwFlags & WAVE_FORMAT_QUERY) {
3768         TRACE(mmsys, "End of WAVE_FORMAT_QUERY !\n");
3769         dwRet = waveInClose16(hWaveIn);
3770     }
3771     return dwRet;
3772 }
3773
3774 /**************************************************************************
3775  *                              waveInClose                     [WINMM.145]
3776  */
3777 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
3778 {
3779     return waveInClose16(hWaveIn);
3780 }
3781
3782 /**************************************************************************
3783  *                              waveInClose                     [MMSYSTEM.505]
3784  */
3785 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
3786 {
3787     LPWAVEOPENDESC      lpDesc;
3788     
3789     TRACE(mmsys, "(%04X)\n", hWaveIn);
3790     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3791     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3792     return widMessage(lpDesc->uDeviceID, WIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
3793 }
3794
3795 /**************************************************************************
3796  *                              waveInPrepareHeader             [WINMM.155]
3797  */
3798 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn,
3799                                 WAVEHDR* lpWaveInHdr, UINT uSize)
3800 {
3801     LPWAVEOPENDESC      lpDesc;
3802     
3803     TRACE(mmsys, "(%04X, %p, %u);\n", 
3804           hWaveIn, lpWaveInHdr, uSize);
3805     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3806     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3807     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
3808     lpWaveInHdr = lpWaveInHdr;
3809     lpWaveInHdr->lpNext = NULL;
3810     lpWaveInHdr->dwBytesRecorded = 0;
3811     TRACE(mmsys, "lpData=%p size=%lu \n", 
3812           lpWaveInHdr->lpData, lpWaveInHdr->dwBufferLength);
3813     return widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance, 
3814                       (DWORD)lpWaveInHdr, uSize);
3815 }
3816
3817 /**************************************************************************
3818  *                              waveInPrepareHeader             [MMSYSTEM.506]
3819  */
3820 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn,
3821                                     WAVEHDR* lpWaveInHdr, UINT16 uSize)
3822 {
3823     LPWAVEOPENDESC      lpDesc;
3824     LPBYTE              saveddata = lpWaveInHdr->lpData;
3825     UINT16              ret;
3826     
3827     TRACE(mmsys, "(%04X, %p, %u);\n", 
3828           hWaveIn, lpWaveInHdr, uSize);
3829     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3830     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3831     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
3832     lpWaveInHdr = lpWaveInHdr;
3833     lpWaveInHdr->lpNext = NULL;
3834     lpWaveInHdr->dwBytesRecorded = 0;
3835     
3836     TRACE(mmsys, "lpData=%p size=%lu \n", 
3837           lpWaveInHdr->lpData, lpWaveInHdr->dwBufferLength);
3838     lpWaveInHdr->lpData = PTR_SEG_TO_LIN(lpWaveInHdr->lpData);
3839     ret = widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance, 
3840                      (DWORD)lpWaveInHdr,uSize);
3841     lpWaveInHdr->lpData = saveddata;
3842     return ret;
3843 }
3844
3845 /**************************************************************************
3846  *                              waveInUnprepareHeader   [WINMM.159]
3847  */
3848 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn,
3849                                   WAVEHDR* lpWaveInHdr, UINT uSize)
3850 {
3851     LPWAVEOPENDESC      lpDesc;
3852     
3853     TRACE(mmsys, "(%04X, %p, %u);\n", 
3854           hWaveIn, lpWaveInHdr, uSize);
3855     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3856     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3857     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
3858     /*USER_HEAP_FREE(HIWORD((DWORD)lpWaveInHdr->lpData)); FIXME */
3859     lpWaveInHdr->lpData = NULL;
3860     lpWaveInHdr->lpNext = NULL;
3861     return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance, 
3862                       (DWORD)lpWaveInHdr, uSize);
3863 }
3864
3865 /**************************************************************************
3866  *                              waveInUnprepareHeader   [MMSYSTEM.507]
3867  */
3868 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn,
3869                                       WAVEHDR* lpWaveInHdr, UINT16 uSize)
3870 {
3871     LPWAVEOPENDESC      lpDesc;
3872     
3873     TRACE(mmsys, "(%04X, %p, %u);\n", 
3874           hWaveIn, lpWaveInHdr, uSize);
3875     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3876     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3877     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
3878     /*USER_HEAP_FREE(HIWORD((DWORD)lpWaveInHdr->lpData)); FIXME */
3879     lpWaveInHdr->lpData = NULL;
3880     lpWaveInHdr->lpNext = NULL;
3881     return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance, 
3882                       (DWORD)lpWaveInHdr, uSize);
3883 }
3884
3885 /**************************************************************************
3886  *                              waveInAddBuffer         [WINMM.144]
3887  */
3888 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
3889                             WAVEHDR* lpWaveInHdr, UINT uSize)
3890 {
3891     LPWAVEOPENDESC      lpDesc;
3892     
3893     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3894     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3895     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3896     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
3897     lpWaveInHdr->lpNext = NULL;
3898     lpWaveInHdr->dwBytesRecorded = 0;
3899     TRACE(mmsys, "lpData=%p size=%lu \n", 
3900           lpWaveInHdr->lpData, lpWaveInHdr->dwBufferLength);
3901     return widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
3902                       (DWORD)lpWaveInHdr, uSize);
3903     
3904 }
3905
3906 /**************************************************************************
3907  *                              waveInAddBuffer         [MMSYSTEM.508]
3908  */
3909 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn,
3910                                 WAVEHDR* lpWaveInHdr, UINT16 uSize)
3911 {
3912     LPWAVEOPENDESC      lpDesc;
3913     UINT16              ret;
3914     
3915     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3916     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3917     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3918     if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
3919     lpWaveInHdr->lpNext = NULL;
3920     lpWaveInHdr->dwBytesRecorded = 0;
3921     lpWaveInHdr->lpData = PTR_SEG_TO_LIN(lpWaveInHdr->lpData);
3922     TRACE(mmsys, "lpData=%p size=%lu \n", 
3923           lpWaveInHdr->lpData, lpWaveInHdr->dwBufferLength);
3924     ret = widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
3925                      (DWORD)lpWaveInHdr, uSize);
3926     /*lpWaveInHdr->lpData = saveddata;*/
3927     return ret;
3928 }
3929
3930 /**************************************************************************
3931  *                              waveInStart                     [WINMM.157]
3932  */
3933 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
3934 {
3935     return waveInStart16(hWaveIn);
3936 }
3937
3938 /**************************************************************************
3939  *                              waveInStart                     [MMSYSTEM.509]
3940  */
3941 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn)
3942 {
3943     LPWAVEOPENDESC      lpDesc;
3944     
3945     TRACE(mmsys, "(%04X)\n", hWaveIn);
3946     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3947     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3948     return widMessage(lpDesc->uDeviceID, WIDM_START, lpDesc->dwInstance, 0, 0);
3949 }
3950
3951 /**************************************************************************
3952  *                              waveInStop                      [WINMM.158]
3953  */
3954 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
3955 {
3956     return waveInStop16(hWaveIn);
3957 }
3958
3959 /**************************************************************************
3960  *                              waveInStop                      [MMSYSTEM.510]
3961  */
3962 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn)
3963 {
3964     LPWAVEOPENDESC      lpDesc;
3965     
3966     TRACE(mmsys, "(%04X)\n", hWaveIn);
3967     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3968     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3969     return widMessage(lpDesc->uDeviceID, WIDM_STOP, lpDesc->dwInstance, 0L, 0L);
3970 }
3971
3972 /**************************************************************************
3973  *                              waveInReset                     [WINMM.156]
3974  */
3975 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
3976 {
3977     return waveInReset16(hWaveIn);
3978 }
3979
3980 /**************************************************************************
3981  *                              waveInReset                     [MMSYSTEM.511]
3982  */
3983 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn)
3984 {
3985     LPWAVEOPENDESC      lpDesc;
3986     
3987     TRACE(mmsys, "(%04X)\n", hWaveIn);
3988     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
3989     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3990     return widMessage(lpDesc->uDeviceID, WIDM_RESET, lpDesc->dwInstance, 0, 0);
3991 }
3992
3993 /**************************************************************************
3994  *                              waveInGetPosition       [WINMM.152]
3995  */
3996 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
3997                               UINT uSize)
3998 {
3999     MMTIME16    mmt16;
4000     UINT        ret;
4001     
4002     mmt16.wType = lpTime->wType;
4003     ret = waveInGetPosition16(hWaveIn, &mmt16,uSize);
4004     
4005     MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
4006     return ret;
4007 }
4008
4009 /**************************************************************************
4010  *                              waveInGetPosition       [MMSYSTEM.512]
4011  */
4012 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4013                                   UINT16 uSize)
4014 {
4015     LPWAVEOPENDESC      lpDesc;
4016     
4017     TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4018     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4019     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4020     return widMessage(lpDesc->uDeviceID, WIDM_GETPOS, lpDesc->dwInstance,
4021                       (DWORD)lpTime, (DWORD)uSize);
4022 }
4023
4024 /**************************************************************************
4025  *                              waveInGetID                     [WINMM.150]
4026  */
4027 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4028 {
4029     LPWAVEOPENDESC      lpDesc;
4030     
4031     TRACE(mmsys, "waveInGetID\n");
4032     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4033     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4034     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4035     *lpuDeviceID = lpDesc->uDeviceID;
4036     return 0;
4037 }
4038
4039 /**************************************************************************
4040  *                              waveInGetID                     [MMSYSTEM.513]
4041  */
4042 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4043 {
4044     LPWAVEOPENDESC      lpDesc;
4045     
4046     TRACE(mmsys, "waveInGetID\n");
4047     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4048     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4049     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4050     *lpuDeviceID = lpDesc->uDeviceID;
4051     return 0;
4052 }
4053
4054 /**************************************************************************
4055  *                              waveInMessage           [WINMM.153]
4056  */
4057 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4058                            DWORD dwParam1, DWORD dwParam2)
4059 {
4060     LPWAVEOPENDESC      lpDesc;
4061     
4062     FIXME(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
4063           hWaveIn, uMessage, dwParam1, dwParam2);
4064     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4065     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4066     switch (uMessage) {
4067     case WIDM_OPEN:
4068         FIXME(mmsys, "cannot handle WIDM_OPEN, please report.\n");
4069         break;
4070     case WIDM_GETNUMDEVS:
4071     case WIDM_GETPOS:
4072     case WIDM_CLOSE:
4073     case WIDM_STOP:
4074     case WIDM_RESET:
4075     case WIDM_START:
4076     case WIDM_PREPARE:
4077     case WIDM_UNPREPARE:
4078     case WIDM_ADDBUFFER:
4079     case WIDM_PAUSE:
4080         /* no argument conversion needed */
4081         break;
4082     case WIDM_GETDEVCAPS:
4083         /*FIXME: ANSI/UNICODE */
4084         return waveInGetDevCapsA(hWaveIn, (LPWAVEINCAPSA)dwParam1, dwParam2);
4085     default:
4086         ERR(mmsys,"(%04x,%04x,%08lx,%08lx): unhandled message\n",
4087             hWaveIn,uMessage, dwParam1, dwParam2);
4088         break;
4089     }
4090     return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4091 }
4092
4093 /**************************************************************************
4094  *                              waveInMessage           [MMSYSTEM.514]
4095  */
4096 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4097                              DWORD dwParam1, DWORD dwParam2)
4098 {
4099     LPWAVEOPENDESC      lpDesc;
4100     
4101     FIXME(mmsys, "(%04X, %04X, %08lX, %08lX)\n", 
4102           hWaveIn, uMessage, dwParam1, dwParam2);
4103     lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4104     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4105     switch (uMessage) {
4106     case WIDM_OPEN:
4107         FIXME(mmsys,"cannot handle WIDM_OPEN, please report.\n");
4108         break;
4109     case WIDM_GETNUMDEVS:
4110     case WIDM_CLOSE:
4111     case WIDM_STOP:
4112     case WIDM_RESET:
4113     case WIDM_START:
4114     case WIDM_PAUSE:
4115         /* no argument conversion needed */
4116         break;
4117     case WIDM_GETDEVCAPS:
4118         return waveInGetDevCaps16(hWaveIn, (LPWAVEINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4119     case WIDM_GETPOS:
4120         return waveInGetPosition16(hWaveIn, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4121     case WIDM_PREPARE:
4122         return waveInPrepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4123     case WIDM_UNPREPARE:
4124         return waveInUnprepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4125     case WIDM_ADDBUFFER:
4126         return waveInAddBuffer16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4127     default:
4128         ERR(mmsys,"(%04x,%04x,%08lx,%08lx): unhandled message\n",
4129             hWaveIn,uMessage, dwParam1, dwParam2);
4130         break;
4131     }
4132     return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4133 }
4134
4135 /**************************************************************************
4136  *                              DrvOpen                 [MMSYSTEM.1100]
4137  */
4138 HDRVR16 WINAPI DrvOpen(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam)
4139 {
4140     TRACE(mmsys,"('%s','%s',%08lX);\n", lpDriverName, lpSectionName, lParam);
4141
4142     return OpenDriver16(lpDriverName, lpSectionName, lParam);
4143 }
4144
4145 /**************************************************************************
4146  *                              DrvClose                [MMSYSTEM.1101]
4147  */
4148 LRESULT WINAPI DrvClose(HDRVR16 hDrv, LPARAM lParam1, LPARAM lParam2)
4149 {
4150     TRACE(mmsys, "(%04X, %08lX, %08lX);\n", hDrv, lParam1, lParam2);
4151
4152     return CloseDriver16(hDrv, lParam1, lParam2);
4153 }
4154
4155 /**************************************************************************
4156  *                              DrvSendMessage          [MMSYSTEM.1102]
4157  */
4158 LRESULT WINAPI DrvSendMessage(HDRVR16 hDrv, WORD msg, LPARAM lParam1,
4159                               LPARAM lParam2)
4160 {
4161     /* DWORD    dwDriverID = 0; */
4162
4163     FIXME(mmsys, "(%04X, %04X, %08lX, %08lX);\n", hDrv, msg, lParam1, lParam2);
4164     return MMSYSERR_NOTENABLED;
4165     /* FIXME: wrong ... */
4166     /* should known the mapping between hDrv and wDevIDs */
4167     /* MCICDAUDIO_DriverProc16(dwDriverID, hDrv, msg, lParam1, lParam2); */
4168 }
4169
4170 /**************************************************************************
4171  *                              DrvGetModuleHandle      [MMSYSTEM.1103]
4172  */
4173 HANDLE16 WINAPI DrvGetModuleHandle16(HDRVR16 hDrv)
4174 {
4175     return GetDriverModuleHandle16(hDrv);
4176 }
4177
4178 /**************************************************************************
4179  *                              DrvDefDriverProc        [MMSYSTEM.1104]
4180  */
4181 LRESULT WINAPI DrvDefDriverProc(DWORD dwDriverID, HDRVR16 hDrv, WORD wMsg, 
4182                                 DWORD dwParam1, DWORD dwParam2)
4183 {
4184     /* FIXME : any mapping from 32 to 16 bit structure ? */
4185     return DefDriverProc16(dwDriverID, hDrv, wMsg, dwParam1, dwParam2);
4186 }
4187
4188 /**************************************************************************
4189  *                              DefDriverProc                     [WINMM.5]
4190  */
4191 LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR hDrv,
4192                              UINT Msg, LPARAM lParam1, LPARAM lParam2)
4193 {
4194     switch (Msg) {
4195     case DRV_LOAD:
4196     case DRV_DISABLE:
4197     case DRV_INSTALL:
4198         return 0;
4199     case DRV_ENABLE:
4200     case DRV_FREE:
4201     case DRV_REMOVE:
4202         return 1;
4203     default:
4204         return 0;
4205     }
4206 }
4207
4208 /**************************************************************************
4209  *                              mmThreadCreate          [MMSYSTEM.1120]
4210  */
4211 LRESULT WINAPI mmThreadCreate16(LPVOID x1, LPWORD x2, DWORD x3, DWORD x4) 
4212 {
4213     FIXME(mmsys,"(%p,%p,%08lx,%08lx): stub!\n",x1,x2,x3,x4);
4214     *x2 = 0xbabe;
4215     return 0;
4216 }
4217
4218 /**************************************************************************
4219  *                              mmThreadGetTask         [MMSYSTEM.1125]
4220  */
4221 LRESULT WINAPI mmThreadGetTask16(WORD hnd) 
4222 {
4223     FIXME(mmsys,"(%04x): stub!\n", hnd);
4224     return GetCurrentTask();
4225 }
4226
4227 /**************************************************************************
4228  *                              mmThreadSignal          [MMSYSTEM.1121]
4229  */
4230 LRESULT WINAPI mmThreadSignal16(WORD hnd) 
4231 {
4232     FIXME(mmsys,"(%04x): stub!\n", hnd);
4233     return 0;
4234 }
4235
4236 /**************************************************************************
4237  *                              mmTaskCreate            [MMSYSTEM.900]
4238  */
4239 HINSTANCE16 WINAPI mmTaskCreate16(LPWORD lphnd,HINSTANCE16 *hMmTask, DWORD x2)
4240 {
4241     DWORD showCmd = 0x40002;
4242     LPSTR cmdline;
4243     WORD sel1, sel2;
4244     LOADPARAMS16 *lp;
4245     HINSTANCE16 ret, handle;
4246     
4247     TRACE(mmsys,"(%p,%p,%08lx);\n", lphnd, hMmTask,x2);
4248     cmdline = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 0x0d);
4249     cmdline[0] = 0x0d;
4250     (DWORD)cmdline[1] = (DWORD)lphnd;
4251     (DWORD)cmdline[5] = x2;
4252     (DWORD)cmdline[9] = 0;
4253     
4254     sel1 = SELECTOR_AllocBlock(cmdline, 0x0d, SEGMENT_DATA, FALSE, FALSE);
4255     sel2 = SELECTOR_AllocBlock(&showCmd, sizeof(showCmd),
4256                                SEGMENT_DATA, FALSE, FALSE);
4257     
4258     lp = (LOADPARAMS16 *)HeapAlloc(GetProcessHeap(), 0, sizeof(LOADPARAMS16));
4259     lp->hEnvironment = 0;
4260     lp->cmdLine = PTR_SEG_OFF_TO_SEGPTR(sel1, 0);
4261     lp->showCmd = PTR_SEG_OFF_TO_SEGPTR(sel2, 0);
4262     lp->reserved = 0;
4263     
4264     ret = LoadModule16("c:\\windows\\mmtask.tsk", lp);
4265     if (ret < 32) {
4266         if (ret)
4267             ret = 1;
4268         else
4269             ret = 2;
4270         handle = 0;
4271     }
4272     else {
4273         handle = ret;
4274         ret = 0;
4275     }
4276     if (hMmTask)
4277         *(HINSTANCE16 *)PTR_SEG_TO_LIN(hMmTask) = handle;
4278     
4279     UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel2, 0));
4280     UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel1, 0));
4281     
4282     HeapFree(GetProcessHeap(), 0, lp);
4283     HeapFree(GetProcessHeap(), 0, cmdline);
4284     
4285     return ret;
4286 }
4287
4288 /**************************************************************************
4289  *                              mmTaskSignal            [MMSYSTEM.903]
4290  */
4291 LRESULT WINAPI mmTaskSignal16(HTASK16 ht) 
4292 {
4293     TRACE(mmsys,"(%04x);\n", ht);
4294     return PostAppMessageA(ht, WM_USER, 0, 0);
4295 }