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