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