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