Replaced WIN_GetWindowInstance by GetWindowLongA(GWL_HINSTANCE),
[wine/wine64.git] / multimedia / mmsystem.c
bloba9d066fa4cc8d2e1e44b1e8188450b92058caad3
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MMSYTEM functions
6 * Copyright 1993 Martin Ayotte
7 */
9 /*
10 * Eric POUECH :
11 * 98/9 added Win32 MCI support
12 * 99/4 added mmTask and mmThread functions support
13 * added midiStream support
16 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses
17 * and long term pointers to 16 bit space in here
20 #include <stdlib.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <sys/ioctl.h>
26 #include "winbase.h"
27 #include "windef.h"
28 #include "wine/winbase16.h"
29 #include "heap.h"
30 #include "user.h"
31 #include "driver.h"
32 #include "multimedia.h"
33 #include "syslevel.h"
34 #include "callback.h"
35 #include "module.h"
36 #include "selectors.h"
37 #include "debugtools.h"
39 DEFAULT_DEBUG_CHANNEL(mmsys)
41 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
42 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
43 LONG WINAPI DrvDefDriverProc(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg,
44 DWORD dwParam1, DWORD dwParam2);
46 /**************************************************************************
47 * MMSYSTEM_WEP [MMSYSTEM.1]
49 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
50 WORD cbHeapSize, LPSTR lpCmdLine)
52 FIXME("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
53 return(TRUE);
56 static void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
58 mmt16->wType = mmt32->wType;
59 /* layout of rest is the same for 32/16,
60 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
62 memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
65 static void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
67 mmt32->wType = mmt16->wType;
68 /* layout of rest is the same for 32/16,
69 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
71 memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
74 static HANDLE PlaySound_hThread = 0;
75 static HANDLE PlaySound_hPlayEvent = 0;
76 static HANDLE PlaySound_hReadyEvent = 0;
77 static HANDLE PlaySound_hMiddleEvent = 0;
78 static BOOL PlaySound_Result = FALSE;
79 static int PlaySound_Stop = FALSE;
80 static int PlaySound_Playing = FALSE;
82 static LPCSTR PlaySound_pszSound = NULL;
83 static HMODULE PlaySound_hmod = 0;
84 static DWORD PlaySound_fdwSound = 0;
85 static int PlaySound_Loop = FALSE;
86 static int PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
87 2 - PlaySound order */
89 static HMMIO16 get_mmioFromFile(LPCSTR lpszName)
91 return mmioOpen16((LPSTR)lpszName, NULL,
92 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
95 static HMMIO16 get_mmioFromProfile(UINT uFlags, LPCSTR lpszName)
97 char str[128];
98 LPSTR ptr;
99 HMMIO16 hmmio;
101 TRACE("searching in SystemSound List !\n");
102 GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
103 if (strlen(str) == 0) {
104 if (uFlags & SND_NODEFAULT) return 0;
105 GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
106 if (strlen(str) == 0) return 0;
108 if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
109 hmmio = get_mmioFromFile(str);
110 if (hmmio == 0) {
111 WARN("can't find SystemSound='%s' !\n", str);
112 return 0;
114 return hmmio;
117 static BOOL16 WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
119 BOOL16 bRet = FALSE;
120 HMMIO16 hmmio;
121 MMCKINFO ckMainRIFF;
123 TRACE("SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
124 if (lpszSoundName == NULL) {
125 TRACE("Stop !\n");
126 return FALSE;
128 if (uFlags & SND_MEMORY) {
129 MMIOINFO16 mminfo;
130 memset(&mminfo, 0, sizeof(mminfo));
131 mminfo.fccIOProc = FOURCC_MEM;
132 mminfo.pchBuffer = (LPSTR)lpszSoundName;
133 mminfo.cchBuffer = -1;
134 TRACE("Memory sound %p\n", lpszSoundName);
135 hmmio = mmioOpen16(NULL, &mminfo, MMIO_READ);
136 } else {
137 hmmio = 0;
138 if (uFlags & SND_ALIAS)
139 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
140 return FALSE;
142 if (uFlags & SND_FILENAME)
143 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
145 if (PlaySound_SearchMode == 1) {
146 PlaySound_SearchMode = 0;
147 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0)
148 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
149 return FALSE;
152 if (PlaySound_SearchMode == 2) {
153 PlaySound_SearchMode = 0;
154 if ((hmmio=get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0)
155 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0)
156 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) return FALSE;
160 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0) == 0)
161 do {
162 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
163 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
164 ckMainRIFF.cksize);
166 if ((ckMainRIFF.ckid == FOURCC_RIFF) &&
167 (ckMainRIFF.fccType == mmioFOURCC('W', 'A', 'V', 'E'))) {
168 MMCKINFO mmckInfo;
170 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
172 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
173 PCMWAVEFORMAT pcmWaveFormat;
175 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
176 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
178 if (mmioRead(hmmio, (HPSTR)&pcmWaveFormat,
179 (long) sizeof(PCMWAVEFORMAT)) == (long) sizeof(PCMWAVEFORMAT)) {
180 TRACE("wFormatTag=%04X !\n", pcmWaveFormat.wf.wFormatTag);
181 TRACE("nChannels=%d \n", pcmWaveFormat.wf.nChannels);
182 TRACE("nSamplesPerSec=%ld\n", pcmWaveFormat.wf.nSamplesPerSec);
183 TRACE("nAvgBytesPerSec=%ld\n", pcmWaveFormat.wf.nAvgBytesPerSec);
184 TRACE("nBlockAlign=%d \n", pcmWaveFormat.wf.nBlockAlign);
185 TRACE("wBitsPerSample=%u !\n", pcmWaveFormat.wBitsPerSample);
187 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
188 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
189 WAVEOPENDESC waveDesc;
190 DWORD dwRet;
192 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
193 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
195 pcmWaveFormat.wf.nAvgBytesPerSec = pcmWaveFormat.wf.nSamplesPerSec *
196 pcmWaveFormat.wf.nBlockAlign;
197 waveDesc.hWave = 0;
198 waveDesc.lpFormat = (LPWAVEFORMAT)&pcmWaveFormat;
200 dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
201 if (dwRet == MMSYSERR_NOERROR) {
202 WAVEHDR waveHdr;
203 HGLOBAL16 hData;
204 INT count, bufsize, left = mmckInfo.cksize;
206 bufsize = 64000;
207 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
208 waveHdr.lpData = (LPSTR)GlobalLock16(hData);
209 waveHdr.dwBufferLength = bufsize;
210 waveHdr.dwUser = 0L;
211 waveHdr.dwFlags = 0L;
212 waveHdr.dwLoops = 0L;
214 dwRet = wodMessage(0, WODM_PREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
215 if (dwRet == MMSYSERR_NOERROR) {
216 while (left) {
217 if (PlaySound_Stop) {
218 PlaySound_Stop = FALSE;
219 PlaySound_Loop = FALSE;
220 break;
222 if (bufsize > left) bufsize = left;
223 count = mmioRead(hmmio, waveHdr.lpData,bufsize);
224 if (count < 1) break;
225 left -= count;
226 waveHdr.dwBufferLength = count;
227 /* FIXME */
228 waveHdr.reserved = (DWORD)&waveHdr;
229 /* waveHdr.dwBytesRecorded = count; */
230 /* FIXME: doesn't expect async ops */
231 wodMessage(0, WODM_WRITE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
233 wodMessage(0, WODM_UNPREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
234 wodMessage(0, WODM_CLOSE, 0, 0L, 0L);
236 bRet = TRUE;
237 } else
238 WARN("can't prepare WaveOut device !\n");
240 GlobalUnlock16(hData);
241 GlobalFree16(hData);
247 } while (PlaySound_Loop);
249 if (hmmio != 0) mmioClose(hmmio, 0);
250 return bRet;
253 static DWORD WINAPI PlaySound_Thread(LPVOID arg)
255 DWORD res;
257 for (;;) {
258 PlaySound_Playing = FALSE;
259 SetEvent(PlaySound_hReadyEvent);
260 res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
261 ResetEvent(PlaySound_hReadyEvent);
262 SetEvent(PlaySound_hMiddleEvent);
263 if (res == WAIT_FAILED) ExitThread(2);
264 if (res != WAIT_OBJECT_0) continue;
265 PlaySound_Playing = TRUE;
267 if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
268 HRSRC hRES;
269 HGLOBAL hGLOB;
270 void* ptr;
272 if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
273 PlaySound_Result = FALSE;
274 continue;
276 if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
277 PlaySound_Result = FALSE;
278 continue;
280 if ((ptr = LockResource(hGLOB)) == NULL) {
281 FreeResource(hGLOB);
282 PlaySound_Result = FALSE;
283 continue;
285 PlaySound_Result = proc_PlaySound(ptr,
286 ((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
287 FreeResource(hGLOB);
288 continue;
290 PlaySound_Result=proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
294 /**************************************************************************
295 * PlaySoundA [WINMM.1]
297 BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
299 static LPSTR StrDup = NULL;
301 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
302 pszSound, hmod, fdwSound);
304 if (PlaySound_hThread == 0) { /* This is the first time they called us */
305 DWORD id;
306 if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
307 return FALSE;
308 if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
309 return FALSE;
310 if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
311 return FALSE;
312 if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0)
313 return FALSE;
316 /* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */
317 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing)
318 return FALSE;
320 /* Trying to stop if playing */
321 if (PlaySound_Playing) PlaySound_Stop = TRUE;
323 /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
324 if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
325 return FALSE;
327 if (!pszSound || (fdwSound & SND_PURGE))
328 return FALSE; /* We stoped playing so leaving */
330 if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
331 if (!(fdwSound & SND_ASYNC)) {
332 if (fdwSound & SND_LOOP)
333 return FALSE;
334 PlaySound_pszSound = pszSound;
335 PlaySound_hmod = hmod;
336 PlaySound_fdwSound = fdwSound;
337 PlaySound_Result = FALSE;
338 SetEvent(PlaySound_hPlayEvent);
339 if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0)
340 return FALSE;
341 if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0)
342 return FALSE;
343 return PlaySound_Result;
344 } else {
345 PlaySound_hmod = hmod;
346 PlaySound_fdwSound = fdwSound;
347 PlaySound_Result = FALSE;
348 if (StrDup) {
349 HeapFree(GetProcessHeap(), 0, StrDup);
350 StrDup = NULL;
352 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
353 !((DWORD)pszSound >> 16)) || !pszSound)) {
354 StrDup = HEAP_strdupA(GetProcessHeap(), 0,pszSound);
355 PlaySound_pszSound = StrDup;
356 } else PlaySound_pszSound = pszSound;
357 PlaySound_Loop = fdwSound & SND_LOOP;
358 SetEvent(PlaySound_hPlayEvent);
359 ResetEvent(PlaySound_hMiddleEvent);
360 return TRUE;
362 return FALSE;
365 /**************************************************************************
366 * PlaySoundW [WINMM.18]
368 BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
370 LPSTR pszSoundA;
371 BOOL bSound;
373 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
374 !((DWORD)pszSound >> 16)) || !pszSound)) {
375 pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
376 bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
377 HeapFree(GetProcessHeap(), 0,pszSoundA);
378 } else
379 bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
381 return bSound;
384 /**************************************************************************
385 * PlaySound16 [MMSYSTEM.3]
387 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
389 BOOL16 retv;
391 SYSLEVEL_ReleaseWin16Lock();
392 retv = PlaySoundA( pszSound, hmod, fdwSound );
393 SYSLEVEL_RestoreWin16Lock();
395 return retv;
398 /**************************************************************************
399 * sndPlaySoundA [WINMM135]
401 BOOL WINAPI sndPlaySoundA(LPCSTR lpszSoundName, UINT uFlags)
403 PlaySound_SearchMode = 1;
404 return PlaySoundA(lpszSoundName, 0, uFlags);
407 /**************************************************************************
408 * sndPlaySoundW [WINMM.136]
410 BOOL WINAPI sndPlaySoundW(LPCWSTR lpszSoundName, UINT uFlags)
412 PlaySound_SearchMode = 1;
413 return PlaySoundW(lpszSoundName, 0, uFlags);
416 /**************************************************************************
417 * sndPlaySound16 [MMSYSTEM.2]
419 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
421 BOOL16 retv;
423 SYSLEVEL_ReleaseWin16Lock();
424 retv = sndPlaySoundA( lpszSoundName, uFlags );
425 SYSLEVEL_RestoreWin16Lock();
427 return retv;
431 /**************************************************************************
432 * mmsystemGetVersion [WINMM.134]
434 UINT WINAPI mmsystemGetVersion()
436 return mmsystemGetVersion16();
439 /**************************************************************************
440 * mmsystemGetVersion [MMSYSTEM.5]
441 * return value borrowed from Win95 winmm.dll ;)
443 UINT16 WINAPI mmsystemGetVersion16()
445 TRACE("3.10 (Win95?)\n");
446 return 0x030a;
449 /**************************************************************************
450 * DriverProc [MMSYSTEM.6]
452 LRESULT WINAPI DriverProc16(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg,
453 DWORD dwParam1, DWORD dwParam2)
455 return DrvDefDriverProc(dwDevID, hDrv, wMsg, dwParam1, dwParam2);
458 /**************************************************************************
459 * DriverCallback [MMSYSTEM.31]
461 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HANDLE16 hDev,
462 WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
464 TRACE("(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
465 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
467 switch (uFlags & DCB_TYPEMASK) {
468 case DCB_NULL:
469 TRACE("Null !\n");
470 break;
471 case DCB_WINDOW:
472 TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
473 if (!IsWindow(dwCallBack) || USER_HEAP_LIN_ADDR(hDev) == NULL)
474 return FALSE;
475 Callout.PostMessageA((HWND16)dwCallBack, wMsg, hDev, dwParam1);
476 break;
477 case DCB_TASK: /* aka DCB_THREAD */
478 TRACE("Task(%04lx) !\n", dwCallBack);
479 Callout.PostThreadMessageA(dwCallBack, wMsg, hDev, dwParam1);
480 break;
481 case DCB_FUNCTION:
482 TRACE("Function (16bit) !\n");
483 Callbacks->CallDriverCallback((FARPROC16)dwCallBack, hDev, wMsg, dwUser,
484 dwParam1, dwParam2);
485 break;
486 case DCB_FUNC32: /* This is a Wine only value - AKAIF not used yet by MS */
487 TRACE("Function (32bit) !\n");
488 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
489 break;
490 case DCB_EVENT:
491 TRACE("Event(%08lx) !\n", dwCallBack);
492 SetEvent((HANDLE)dwCallBack);
493 break;
494 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
495 /* this is an undocumented DCB_ value used for mmThreads
496 * loword of dwCallBack contains the handle of the lpMMThd block
497 * which dwSignalCount has to be incremented
500 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(LOWORD(dwCallBack), 0);
502 TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
503 /* same as mmThreadSignal16 */
504 InterlockedIncrement(&lpMMThd->dwSignalCount);
505 SetEvent(lpMMThd->hEvent);
506 /* some other stuff on lpMMThd->hVxD */
508 break;
509 #if 0
510 case 4:
511 /* this is an undocumented DCB_ value for... I don't know */
512 break;
513 #endif
514 default:
515 WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
516 return FALSE;
518 TRACE("Done\n");
519 return TRUE;
522 /**************************************************************************
523 * Mixer devices. New to Win95
526 /**************************************************************************
527 * find out the real mixer ID depending on hmix (depends on dwFlags)
528 * FIXME: also fix dwInstance passing to mixMessage
530 static UINT MIXER_GetDevID(HMIXEROBJ hmix, DWORD dwFlags)
532 /* FIXME: Check dwFlags for MIXER_OBJSECTF_xxxx entries and modify hmix
533 * accordingly. For now we always use mixerdevice 0.
535 return 0;
538 /**************************************************************************
539 * mixerGetNumDevs [WINMM.108]
541 UINT WINAPI mixerGetNumDevs(void)
543 UINT16 count = mixMessage(0, MXDM_GETNUMDEVS, 0L, 0L, 0L);
545 TRACE("mixerGetNumDevs returns %d\n", count);
546 return count;
549 /**************************************************************************
550 * mixerGetNumDevs [MMSYSTEM.800]
552 UINT16 WINAPI mixerGetNumDevs16()
554 return mixerGetNumDevs();
557 /**************************************************************************
558 * mixerGetDevCapsA [WINMM.101]
560 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
562 return mixMessage(devid, MXDM_GETDEVCAPS, 0L, (DWORD)mixcaps, (DWORD)size);
565 /**************************************************************************
566 * mixerGetDevCapsW [WINMM.102]
568 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
570 MIXERCAPSA micA;
571 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
573 if (ret == MMSYSERR_NOERROR) {
574 mixcaps->wMid = micA.wMid;
575 mixcaps->wPid = micA.wPid;
576 mixcaps->vDriverVersion = micA.vDriverVersion;
577 lstrcpyAtoW(mixcaps->szPname, micA.szPname);
578 mixcaps->fdwSupport = micA.fdwSupport;
579 mixcaps->cDestinations = micA.cDestinations;
581 return ret;
584 /**************************************************************************
585 * mixerGetDevCaps [MMSYSTEM.801]
587 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps, UINT16 size)
589 MIXERCAPSA micA;
590 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
592 if (ret == MMSYSERR_NOERROR) {
593 mixcaps->wMid = micA.wMid;
594 mixcaps->wPid = micA.wPid;
595 mixcaps->vDriverVersion = micA.vDriverVersion;
596 strcpy(PTR_SEG_TO_LIN(mixcaps->szPname), micA.szPname);
597 mixcaps->fdwSupport = micA.fdwSupport;
598 mixcaps->cDestinations = micA.cDestinations;
600 return ret;
603 /**************************************************************************
604 * mixerOpen [WINMM.110]
606 UINT WINAPI mixerOpen(LPHMIXER lphmix, UINT uDeviceID, DWORD dwCallback,
607 DWORD dwInstance, DWORD fdwOpen)
609 HMIXER16 hmix16;
610 UINT ret;
612 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
613 lphmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
614 ret = mixerOpen16(&hmix16, uDeviceID, dwCallback, dwInstance,fdwOpen);
615 if (lphmix) *lphmix = hmix16;
616 return ret;
619 /**************************************************************************
620 * mixerOpen [MMSYSTEM.803]
622 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
623 DWORD dwInstance, DWORD fdwOpen)
625 HMIXER16 hmix;
626 LPMIXEROPENDESC lpmod;
627 BOOL mapperflag = (uDeviceID == 0);
628 DWORD dwRet = 0;
630 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
631 lphmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
632 hmix = USER_HEAP_ALLOC(sizeof(MIXEROPENDESC));
633 if (lphmix) *lphmix = hmix;
634 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
635 lpmod->hmx = hmix;
636 lpmod->dwCallback = dwCallback;
637 lpmod->dwInstance = dwInstance;
638 if (uDeviceID >= MAXMIXERDRIVERS)
639 uDeviceID = 0;
640 while (uDeviceID < MAXMIXERDRIVERS) {
641 dwRet = mixMessage(uDeviceID, MXDM_OPEN, dwInstance, (DWORD)lpmod, fdwOpen);
642 if (dwRet == MMSYSERR_NOERROR) break;
643 if (!mapperflag) break;
644 uDeviceID++;
646 lpmod->uDeviceID = uDeviceID;
648 if (dwRet != MMSYSERR_NOERROR) {
649 USER_HEAP_FREE(hmix);
650 if (lphmix) *lphmix = 0;
653 return dwRet;
656 /**************************************************************************
657 * mixerClose [WINMM.98]
659 UINT WINAPI mixerClose(HMIXER hmix)
661 LPMIXEROPENDESC lpmod;
662 DWORD dwRet;
664 TRACE("(%04x)\n", hmix);
666 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
667 if (lpmod == NULL) return MMSYSERR_INVALHANDLE;
668 dwRet = mixMessage(lpmod->uDeviceID, MXDM_CLOSE, lpmod->dwInstance, 0L, 0L);
669 USER_HEAP_FREE(hmix);
670 return dwRet;
673 /**************************************************************************
674 * mixerClose [MMSYSTEM.803]
676 UINT16 WINAPI mixerClose16(HMIXER16 hmix)
678 return mixerClose(hmix);
681 /**************************************************************************
682 * mixerGetID [WINMM.103]
684 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
686 FIXME("(%04x %p %08lx): semi-stub\n", hmix, lpid, fdwID);
688 if (lpid)
689 *lpid = MIXER_GetDevID(hmix, fdwID);
691 return MMSYSERR_NOERROR; /* FIXME: many error possibilities */
694 /**************************************************************************
695 * mixerGetID
697 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
699 UINT xid;
700 UINT ret = mixerGetID(hmix, &xid, fdwID);
702 if (lpid)
703 *lpid = xid;
704 return ret;
707 /**************************************************************************
708 * mixerGetControlDetailsA [WINMM.99]
710 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, DWORD fdwDetails)
712 UINT uDevID;
714 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
716 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
717 return MMSYSERR_INVALPARAM;
719 uDevID = MIXER_GetDevID(hmix, fdwDetails);
721 return mixMessage(uDevID, MXDM_GETCONTROLDETAILS, 0, (DWORD)lpmcdA, fdwDetails);
724 /**************************************************************************
725 * mixerGetControlDetailsW [WINMM.100]
727 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
729 DWORD ret = MMSYSERR_NOTENABLED;
731 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
733 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
734 return MMSYSERR_INVALPARAM;
736 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
737 case MIXER_GETCONTROLDETAILSF_VALUE:
738 /* can savely use W structure as it is, no string inside */
739 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
740 break;
741 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
743 LPVOID paDetailsW = lpmcd->paDetails;
744 int size = MAX(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
746 if (lpmcd->u.cMultipleItems != 0 && lpmcd->u.cMultipleItems != lpmcd->u.hwndOwner) {
747 size *= lpmcd->u.cMultipleItems;
749 lpmcd->paDetails = HeapAlloc(GetProcessHeap(), 0, size);
750 /* set up lpmcd->paDetails */
751 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
752 /* copy from lpmcd->paDetails back to paDetailsW; */
753 HeapFree(GetProcessHeap(), 0, lpmcd->paDetails);
754 lpmcd->paDetails = paDetailsW;
756 break;
757 default:
758 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
761 return ret;
764 /**************************************************************************
765 * mixerGetControlDetails [MMSYSTEM.808]
767 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails)
769 DWORD ret = MMSYSERR_NOTENABLED;
770 SEGPTR sppaDetails;
772 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
774 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
775 return MMSYSERR_INVALPARAM;
777 sppaDetails = (SEGPTR)lpmcd->paDetails;
778 lpmcd->paDetails = PTR_SEG_TO_LIN(sppaDetails);
779 ret = mixerGetControlDetailsA(hmix, (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails);
780 lpmcd->paDetails = (LPVOID)sppaDetails;
782 return ret;
785 /**************************************************************************
786 * mixerGetLineControlsA [WINMM.104]
788 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA, DWORD fdwControls)
790 UINT uDevID;
792 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
794 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
795 return MMSYSERR_INVALPARAM;
797 uDevID = MIXER_GetDevID(hmix, 0);
799 return mixMessage(uDevID, MXDM_GETLINECONTROLS, 0, (DWORD)lpmlcA, fdwControls);
802 /**************************************************************************
803 * mixerGetLineControlsW [WINMM.105]
805 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, DWORD fdwControls)
807 MIXERLINECONTROLSA mlcA;
808 DWORD ret;
809 int i;
811 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
813 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) || lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
814 return MMSYSERR_INVALPARAM;
816 mlcA.cbStruct = sizeof(mlcA);
817 mlcA.dwLineID = lpmlcW->dwLineID;
818 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
819 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
820 mlcA.cControls = lpmlcW->cControls;
821 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
822 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0, mlcA.cControls * mlcA.cbmxctrl);
824 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
826 if (ret == MMSYSERR_NOERROR) {
827 lpmlcW->dwLineID = mlcA.dwLineID;
828 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
829 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
830 lpmlcW->cControls = mlcA.cControls;
832 for (i = 0; i < mlcA.cControls; i++) {
833 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
834 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
835 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
836 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
837 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
838 lstrcpyAtoW(lpmlcW->pamxctrl[i].szShortName, mlcA.pamxctrl[i].szShortName);
839 lstrcpyAtoW(lpmlcW->pamxctrl[i].szName, mlcA.pamxctrl[i].szName);
840 /* sizeof(lpmlcW->pamxctrl[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
841 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds, sizeof(mlcA.pamxctrl[i].Bounds));
842 /* sizeof(lpmlcW->pamxctrl[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
843 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics, sizeof(mlcA.pamxctrl[i].Metrics));
847 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
849 return ret;
852 /**************************************************************************
853 * mixerGetLineControls [MMSYSTEM.807]
855 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix, LPMIXERLINECONTROLS16 lpmlc16, DWORD fdwControls)
857 MIXERLINECONTROLSA mlcA;
858 DWORD ret;
859 int i;
860 LPMIXERCONTROL16 lpmc16;
862 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls);
864 if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) || lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16))
865 return MMSYSERR_INVALPARAM;
867 mlcA.cbStruct = sizeof(mlcA);
868 mlcA.dwLineID = lpmlc16->dwLineID;
869 mlcA.u.dwControlID = lpmlc16->u.dwControlID;
870 mlcA.u.dwControlType = lpmlc16->u.dwControlType;
871 mlcA.cControls = lpmlc16->cControls;
872 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
873 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0, mlcA.cControls * mlcA.cbmxctrl);
875 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
877 if (ret == MMSYSERR_NOERROR) {
878 lpmlc16->dwLineID = mlcA.dwLineID;
879 lpmlc16->u.dwControlID = mlcA.u.dwControlID;
880 lpmlc16->u.dwControlType = mlcA.u.dwControlType;
881 lpmlc16->cControls = mlcA.cControls;
883 lpmc16 = PTR_SEG_TO_LIN(lpmlc16->pamxctrl);
885 for (i = 0; i < mlcA.cControls; i++) {
886 lpmc16[i].cbStruct = sizeof(MIXERCONTROL16);
887 lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
888 lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
889 lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
890 lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
891 strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName);
892 strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName);
893 /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
894 memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds, sizeof(mlcA.pamxctrl[i].Bounds));
895 /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
896 memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics, sizeof(mlcA.pamxctrl[i].Metrics));
900 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
902 return ret;
905 /**************************************************************************
906 * mixerGetLineInfoA [WINMM.106]
908 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
910 UINT16 devid;
912 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
914 /* FIXME: I'm not sure of the flags */
915 devid = MIXER_GetDevID(hmix, fdwInfo);
916 return mixMessage(devid, MXDM_GETLINEINFO, 0, (DWORD)lpmliW, fdwInfo);
919 /**************************************************************************
920 * mixerGetLineInfoW [WINMM.107]
922 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo)
924 MIXERLINEA mliA;
925 UINT ret;
927 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
929 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
930 return MMSYSERR_INVALPARAM;
932 mliA.cbStruct = sizeof(mliA);
933 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
934 case MIXER_GETLINEINFOF_COMPONENTTYPE:
935 mliA.dwComponentType = lpmliW->dwComponentType;
936 break;
937 case MIXER_GETLINEINFOF_DESTINATION:
938 mliA.dwDestination = lpmliW->dwDestination;
939 break;
940 case MIXER_GETLINEINFOF_LINEID:
941 mliA.dwLineID = lpmliW->dwLineID;
942 break;
943 case MIXER_GETLINEINFOF_SOURCE:
944 mliA.dwDestination = lpmliW->dwDestination;
945 mliA.dwSource = lpmliW->dwSource;
946 break;
947 case MIXER_GETLINEINFOF_TARGETTYPE:
948 mliA.Target.dwType = lpmliW->Target.dwType;
949 mliA.Target.wMid = lpmliW->Target.wMid;
950 mliA.Target.wPid = lpmliW->Target.wPid;
951 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
952 lstrcpyWtoA(mliA.Target.szPname, lpmliW->Target.szPname);
953 break;
954 default:
955 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
958 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
960 lpmliW->dwDestination = mliA.dwDestination;
961 lpmliW->dwSource = mliA.dwSource;
962 lpmliW->dwLineID = mliA.dwLineID;
963 lpmliW->fdwLine = mliA.fdwLine;
964 lpmliW->dwUser = mliA.dwUser;
965 lpmliW->dwComponentType = mliA.dwComponentType;
966 lpmliW->cChannels = mliA.cChannels;
967 lpmliW->cConnections = mliA.cConnections;
968 lpmliW->cControls = mliA.cControls;
969 lstrcpyAtoW(lpmliW->szShortName, mliA.szShortName);
970 lstrcpyAtoW(lpmliW->szName, mliA.szName);
971 lpmliW->Target.dwType = mliA.Target.dwType;
972 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
973 lpmliW->Target.wMid = mliA.Target.wMid;
974 lpmliW->Target.wPid = mliA.Target.wPid;
975 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
976 lstrcpyAtoW(lpmliW->Target.szPname, mliA.Target.szPname);
978 return ret;
981 /**************************************************************************
982 * mixerGetLineInfo [MMSYSTEM.805]
984 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16, DWORD fdwInfo)
986 MIXERLINEA mliA;
987 UINT ret;
989 TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo);
991 if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16))
992 return MMSYSERR_INVALPARAM;
994 mliA.cbStruct = sizeof(mliA);
995 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
996 case MIXER_GETLINEINFOF_COMPONENTTYPE:
997 mliA.dwComponentType = lpmli16->dwComponentType;
998 break;
999 case MIXER_GETLINEINFOF_DESTINATION:
1000 mliA.dwDestination = lpmli16->dwDestination;
1001 break;
1002 case MIXER_GETLINEINFOF_LINEID:
1003 mliA.dwLineID = lpmli16->dwLineID;
1004 break;
1005 case MIXER_GETLINEINFOF_SOURCE:
1006 mliA.dwDestination = lpmli16->dwDestination;
1007 mliA.dwSource = lpmli16->dwSource;
1008 break;
1009 case MIXER_GETLINEINFOF_TARGETTYPE:
1010 mliA.Target.dwType = lpmli16->Target.dwType;
1011 mliA.Target.wMid = lpmli16->Target.wMid;
1012 mliA.Target.wPid = lpmli16->Target.wPid;
1013 mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion;
1014 strcpy(mliA.Target.szPname, lpmli16->Target.szPname);
1015 break;
1016 default:
1017 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1020 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1022 lpmli16->dwDestination = mliA.dwDestination;
1023 lpmli16->dwSource = mliA.dwSource;
1024 lpmli16->dwLineID = mliA.dwLineID;
1025 lpmli16->fdwLine = mliA.fdwLine;
1026 lpmli16->dwUser = mliA.dwUser;
1027 lpmli16->dwComponentType = mliA.dwComponentType;
1028 lpmli16->cChannels = mliA.cChannels;
1029 lpmli16->cConnections = mliA.cConnections;
1030 lpmli16->cControls = mliA.cControls;
1031 strcpy(lpmli16->szShortName, mliA.szShortName);
1032 strcpy(lpmli16->szName, mliA.szName);
1033 lpmli16->Target.dwType = mliA.Target.dwType;
1034 lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID;
1035 lpmli16->Target.wMid = mliA.Target.wMid;
1036 lpmli16->Target.wPid = mliA.Target.wPid;
1037 lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion;
1038 strcpy(lpmli16->Target.szPname, mliA.Target.szPname);
1040 return ret;
1043 /**************************************************************************
1044 * mixerSetControlDetails [WINMM.111]
1046 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, DWORD fdwDetails)
1048 UINT uDevID;
1050 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1052 uDevID = MIXER_GetDevID(hmix, fdwDetails);
1054 return mixMessage(uDevID, MXDM_SETCONTROLDETAILS, 0, (DWORD)lpmcdA, fdwDetails);
1057 /**************************************************************************
1058 * mixerSetControlDetails [MMSYSTEM.809]
1060 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails)
1062 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1063 return MMSYSERR_NOTENABLED;
1066 /**************************************************************************
1067 * mixerMessage [WINMM.109]
1069 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
1071 LPMIXEROPENDESC lpmod;
1072 UINT16 uDeviceID;
1074 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
1075 if (lpmod)
1076 uDeviceID = lpmod->uDeviceID;
1077 else
1078 uDeviceID = 0;
1079 FIXME("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
1080 (DWORD)hmix, uMsg, dwParam1, dwParam2);
1081 return mixMessage(uDeviceID, uMsg, 0L, dwParam1, dwParam2);
1084 /**************************************************************************
1085 * mixerMessage [MMSYSTEM.804]
1087 UINT16 WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1, DWORD dwParam2)
1089 LPMIXEROPENDESC lpmod;
1090 UINT16 uDeviceID;
1092 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
1093 uDeviceID = (lpmod) ? lpmod->uDeviceID : 0;
1094 FIXME("(%04x, %d, %08lx, %08lx) - semi-stub?\n",
1095 hmix, uMsg, dwParam1, dwParam2);
1096 return mixMessage(uDeviceID, uMsg, 0L, dwParam1, dwParam2);
1099 /**************************************************************************
1100 * auxGetNumDevs [WINMM.22]
1102 UINT WINAPI auxGetNumDevs()
1104 return auxGetNumDevs16();
1107 /**************************************************************************
1108 * auxGetNumDevs [MMSYSTEM.350]
1110 UINT16 WINAPI auxGetNumDevs16()
1112 UINT16 count;
1114 TRACE("\n");
1115 count = auxMessage(0, AUXDM_GETNUMDEVS, 0L, 0L, 0L);
1116 TRACE("=> %u\n", count);
1117 return count;
1120 /**************************************************************************
1121 * auxGetDevCaps [WINMM.20]
1123 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
1125 AUXCAPS16 ac16;
1126 UINT ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
1128 lpCaps->wMid = ac16.wMid;
1129 lpCaps->wPid = ac16.wPid;
1130 lpCaps->vDriverVersion = ac16.vDriverVersion;
1131 lstrcpyAtoW(lpCaps->szPname, ac16.szPname);
1132 lpCaps->wTechnology = ac16.wTechnology;
1133 lpCaps->dwSupport = ac16.dwSupport;
1134 return ret;
1137 /**************************************************************************
1138 * auxGetDevCaps [WINMM.21]
1140 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
1142 AUXCAPS16 ac16;
1143 UINT ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
1145 lpCaps->wMid = ac16.wMid;
1146 lpCaps->wPid = ac16.wPid;
1147 lpCaps->vDriverVersion = ac16.vDriverVersion;
1148 strcpy(lpCaps->szPname, ac16.szPname);
1149 lpCaps->wTechnology = ac16.wTechnology;
1150 lpCaps->dwSupport = ac16.dwSupport;
1151 return ret;
1154 /**************************************************************************
1155 * auxGetDevCaps [MMSYSTEM.351]
1157 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
1159 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1161 return auxMessage(uDeviceID, AUXDM_GETDEVCAPS,
1162 0L, (DWORD)lpCaps, (DWORD)uSize);
1165 /**************************************************************************
1166 * auxGetVolume [WINM.23]
1168 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1170 return auxGetVolume16(uDeviceID, lpdwVolume);
1173 /**************************************************************************
1174 * auxGetVolume [MMSYSTEM.352]
1176 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
1178 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1180 return auxMessage(uDeviceID, AUXDM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
1183 /**************************************************************************
1184 * auxSetVolume [WINMM.25]
1186 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
1188 return auxSetVolume16(uDeviceID, dwVolume);
1191 /**************************************************************************
1192 * auxSetVolume [MMSYSTEM.353]
1194 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
1196 TRACE("(%04X, %08lX) !\n", uDeviceID, dwVolume);
1198 return auxMessage(uDeviceID, AUXDM_SETVOLUME, 0L, dwVolume, 0L);
1201 /**************************************************************************
1202 * auxOutMessage [MMSYSTEM.354]
1204 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1206 switch (uMessage) {
1207 case AUXDM_GETNUMDEVS:
1208 case AUXDM_GETVOLUME:
1209 case AUXDM_SETVOLUME:
1210 /* no argument conversion needed */
1211 break;
1212 case AUXDM_GETDEVCAPS:
1213 return auxGetDevCapsA(uDeviceID, (LPAUXCAPSA)dw1, dw2);
1214 default:
1215 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1216 uDeviceID, uMessage, dw1, dw2);
1217 break;
1219 return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
1222 /**************************************************************************
1223 * auxOutMessage [MMSYSTEM.354]
1225 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1227 TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1229 switch (uMessage) {
1230 case AUXDM_GETNUMDEVS:
1231 case AUXDM_SETVOLUME:
1232 /* no argument conversion needed */
1233 break;
1234 case AUXDM_GETVOLUME:
1235 return auxGetVolume16(uDeviceID, (LPDWORD)PTR_SEG_TO_LIN(dw1));
1236 case AUXDM_GETDEVCAPS:
1237 return auxGetDevCaps16(uDeviceID, (LPAUXCAPS16)PTR_SEG_TO_LIN(dw1), dw2);
1238 default:
1239 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1240 uDeviceID, uMessage, dw1, dw2);
1241 break;
1243 return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
1246 /**************************************************************************
1247 * mciGetErrorStringW [WINMM.46]
1249 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1251 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1252 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
1254 lstrcpyAtoW(lpstrBuffer, bufstr);
1255 HeapFree(GetProcessHeap(), 0, bufstr);
1256 return ret;
1259 /**************************************************************************
1260 * mciGetErrorStringA [WINMM.45]
1262 BOOL WINAPI mciGetErrorStringA(DWORD wError, LPSTR lpstrBuffer, UINT uLength)
1264 return mciGetErrorString16(wError, lpstrBuffer, uLength);
1267 /**************************************************************************
1268 * mciGetErrorString [MMSYSTEM.706]
1270 BOOL16 WINAPI mciGetErrorString16(DWORD dwError, LPSTR lpstrBuffer, UINT16 uLength)
1272 LPSTR msgptr = NULL;
1274 TRACE("(%08lX, %p, %d);\n", dwError, lpstrBuffer, uLength);
1276 if ((lpstrBuffer == NULL) || (uLength < 1))
1277 return FALSE;
1279 lpstrBuffer[0] = '\0';
1281 switch (dwError) {
1282 case 0:
1283 msgptr = "The specified command has been executed.";
1284 break;
1285 case MCIERR_INVALID_DEVICE_ID:
1286 msgptr = "Invalid MCI device ID. Use the ID returned when opening the MCI device.";
1287 break;
1288 case MCIERR_UNRECOGNIZED_KEYWORD:
1289 msgptr = "The driver cannot recognize the specified command parameter.";
1290 break;
1291 case MCIERR_UNRECOGNIZED_COMMAND:
1292 msgptr = "The driver cannot recognize the specified command.";
1293 break;
1294 case MCIERR_HARDWARE:
1295 msgptr = "There is a problem with your media device. Make sure it is working correctly or contact the device manufacturer.";
1296 break;
1297 case MCIERR_INVALID_DEVICE_NAME:
1298 msgptr = "The specified device is not open or is not recognized by MCI.";
1299 break;
1300 case MCIERR_OUT_OF_MEMORY:
1301 msgptr = "Not enough memory available for this task. \nQuit one or more applications to increase available memory, and then try again.";
1302 break;
1303 case MCIERR_DEVICE_OPEN:
1304 msgptr = "The device name is already being used as an alias by this application. Use a unique alias.";
1305 break;
1306 case MCIERR_CANNOT_LOAD_DRIVER:
1307 msgptr = "There is an undetectable problem in loading the specified device driver.";
1308 break;
1309 case MCIERR_MISSING_COMMAND_STRING:
1310 msgptr = "No command was specified.";
1311 break;
1312 case MCIERR_PARAM_OVERFLOW:
1313 msgptr = "The output string was to large to fit in the return buffer. Increase the size of the buffer.";
1314 break;
1315 case MCIERR_MISSING_STRING_ARGUMENT:
1316 msgptr = "The specified command requires a character-string parameter. Please provide one.";
1317 break;
1318 case MCIERR_BAD_INTEGER:
1319 msgptr = "The specified integer is invalid for this command.";
1320 break;
1321 case MCIERR_PARSER_INTERNAL:
1322 msgptr = "The device driver returned an invalid return type. Check with the device manufacturer about obtaining a new driver.";
1323 break;
1324 case MCIERR_DRIVER_INTERNAL:
1325 msgptr = "There is a problem with the device driver. Check with the device manufacturer about obtaining a new driver.";
1326 break;
1327 case MCIERR_MISSING_PARAMETER:
1328 msgptr = "The specified command requires a parameter. Please supply one.";
1329 break;
1330 case MCIERR_UNSUPPORTED_FUNCTION:
1331 msgptr = "The MCI device you are using does not support the specified command.";
1332 break;
1333 case MCIERR_FILE_NOT_FOUND:
1334 msgptr = "Cannot find the specified file. Make sure the path and filename are correct.";
1335 break;
1336 case MCIERR_DEVICE_NOT_READY:
1337 msgptr = "The device driver is not ready.";
1338 break;
1339 case MCIERR_INTERNAL:
1340 msgptr = "A problem occurred in initializing MCI. Try restarting Windows.";
1341 break;
1342 case MCIERR_DRIVER:
1343 msgptr = "There is a problem with the device driver. The driver has closed. Cannot access error.";
1344 break;
1345 case MCIERR_CANNOT_USE_ALL:
1346 msgptr = "Cannot use 'all' as the device name with the specified command.";
1347 break;
1348 case MCIERR_MULTIPLE:
1349 msgptr = "Errors occurred in more than one device. Specify each command and device separately to determine which devices caused the error";
1350 break;
1351 case MCIERR_EXTENSION_NOT_FOUND:
1352 msgptr = "Cannot determine the device type from the given filename extension.";
1353 break;
1354 case MCIERR_OUTOFRANGE:
1355 msgptr = "The specified parameter is out of range for the specified command.";
1356 break;
1357 case MCIERR_FLAGS_NOT_COMPATIBLE:
1358 msgptr = "The specified parameters cannot be used together.";
1359 break;
1360 case MCIERR_FILE_NOT_SAVED:
1361 msgptr = "Cannot save the specified file. Make sure you have enough disk space or are still connected to the network.";
1362 break;
1363 case MCIERR_DEVICE_TYPE_REQUIRED:
1364 msgptr = "Cannot find the specified device. Make sure it is installed or that the device name is spelled correctly.";
1365 break;
1366 case MCIERR_DEVICE_LOCKED:
1367 msgptr = "The specified device is now being closed. Wait a few seconds, and then try again.";
1368 break;
1369 case MCIERR_DUPLICATE_ALIAS:
1370 msgptr = "The specified alias is already being used in this application. Use a unique alias.";
1371 break;
1372 case MCIERR_BAD_CONSTANT:
1373 msgptr = "The specified parameter is invalid for this command.";
1374 break;
1375 case MCIERR_MUST_USE_SHAREABLE:
1376 msgptr = "The device driver is already in use. To share it, use the 'shareable' parameter with each 'open' command.";
1377 break;
1378 case MCIERR_MISSING_DEVICE_NAME:
1379 msgptr = "The specified command requires an alias, file, driver, or device name. Please supply one.";
1380 break;
1381 case MCIERR_BAD_TIME_FORMAT:
1382 msgptr = "The specified value for the time format is invalid. Refer to the MCI documentation for valid formats.";
1383 break;
1384 case MCIERR_NO_CLOSING_QUOTE:
1385 msgptr = "A closing double-quotation mark is missing from the parameter value. Please supply one.";
1386 break;
1387 case MCIERR_DUPLICATE_FLAGS:
1388 msgptr = "A parameter or value was specified twice. Only specify it once.";
1389 break;
1390 case MCIERR_INVALID_FILE:
1391 msgptr = "The specified file cannot be played on the specified MCI device. The file may be corrupt, or not in the correct format.";
1392 break;
1393 case MCIERR_NULL_PARAMETER_BLOCK:
1394 msgptr = "A null parameter block was passed to MCI.";
1395 break;
1396 case MCIERR_UNNAMED_RESOURCE:
1397 msgptr = "Cannot save an unnamed file. Supply a filename.";
1398 break;
1399 case MCIERR_NEW_REQUIRES_ALIAS:
1400 msgptr = "You must specify an alias when using the 'new' parameter.";
1401 break;
1402 case MCIERR_NOTIFY_ON_AUTO_OPEN:
1403 msgptr = "Cannot use the 'notify' flag with auto-opened devices.";
1404 break;
1405 case MCIERR_NO_ELEMENT_ALLOWED:
1406 msgptr = "Cannot use a filename with the specified device.";
1407 break;
1408 case MCIERR_NONAPPLICABLE_FUNCTION:
1409 msgptr = "Cannot carry out the commands in the order specified. Correct the command sequence, and then try again.";
1410 break;
1411 case MCIERR_ILLEGAL_FOR_AUTO_OPEN:
1412 msgptr = "Cannot carry out the specified command on an auto-opened device. Wait until the device is closed, and then try again.";
1413 break;
1414 case MCIERR_FILENAME_REQUIRED:
1415 msgptr = "The filename is invalid. Make sure the filename is not longer than 8 characters, followed by a period and an extension.";
1416 break;
1417 case MCIERR_EXTRA_CHARACTERS:
1418 msgptr = "Cannot specify extra characters after a string enclosed in quotation marks.";
1419 break;
1420 case MCIERR_DEVICE_NOT_INSTALLED:
1421 msgptr = "The specified device is not installed on the system. Use the Drivers option in Control Panel to install the device.";
1422 break;
1423 case MCIERR_GET_CD:
1424 msgptr = "Cannot access the specified file or MCI device. Try changing directories or restarting your computer.";
1425 break;
1426 case MCIERR_SET_CD:
1427 msgptr = "Cannot access the specified file or MCI device because the application cannot change directories.";
1428 break;
1429 case MCIERR_SET_DRIVE:
1430 msgptr = "Cannot access specified file or MCI device because the application cannot change drives.";
1431 break;
1432 case MCIERR_DEVICE_LENGTH:
1433 msgptr = "Specify a device or driver name that is less than 79 characters.";
1434 break;
1435 case MCIERR_DEVICE_ORD_LENGTH:
1436 msgptr = "Specify a device or driver name that is less than 69 characters.";
1437 break;
1438 case MCIERR_NO_INTEGER:
1439 msgptr = "The specified command requires an integer parameter. Please provide one.";
1440 break;
1441 case MCIERR_WAVE_OUTPUTSINUSE:
1442 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.";
1443 break;
1444 case MCIERR_WAVE_SETOUTPUTINUSE:
1445 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.";
1446 break;
1447 case MCIERR_WAVE_INPUTSINUSE:
1448 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.";
1449 break;
1450 case MCIERR_WAVE_SETINPUTINUSE:
1451 msgptr = "Cannot set the current wave device for recording because it is in use. Wait until the device is free, and then try again.";
1452 break;
1453 case MCIERR_WAVE_OUTPUTUNSPECIFIED:
1454 msgptr = "Any compatible waveform playback device may be used.";
1455 break;
1456 case MCIERR_WAVE_INPUTUNSPECIFIED:
1457 msgptr = "Any compatible waveform recording device may be used.";
1458 break;
1459 case MCIERR_WAVE_OUTPUTSUNSUITABLE:
1460 msgptr = "No wave device that can play files in the current format is installed. Use the Drivers option to install the wave device.";
1461 break;
1462 case MCIERR_WAVE_SETOUTPUTUNSUITABLE:
1463 msgptr = "The device you are trying to play to cannot recognize the current file format.";
1464 break;
1465 case MCIERR_WAVE_INPUTSUNSUITABLE:
1466 msgptr = "No wave device that can record files in the current format is installed. Use the Drivers option to install the wave device.";
1467 break;
1468 case MCIERR_WAVE_SETINPUTUNSUITABLE:
1469 msgptr = "The device you are trying to record from cannot recognize the current file format.";
1470 break;
1471 case MCIERR_NO_WINDOW:
1472 msgptr = "There is no display window.";
1473 break;
1474 case MCIERR_CREATEWINDOW:
1475 msgptr = "Could not create or use window.";
1476 break;
1477 case MCIERR_FILE_READ:
1478 msgptr = "Cannot read the specified file. Make sure the file is still present, or check your disk or network connection.";
1479 break;
1480 case MCIERR_FILE_WRITE:
1481 msgptr = "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network.";
1482 break;
1483 case MCIERR_SEQ_DIV_INCOMPATIBLE:
1484 msgptr = "The time formats of the \"song pointer\" and SMPTE are mutually exclusive. You can't use them together.";
1485 break;
1486 case MCIERR_SEQ_NOMIDIPRESENT:
1487 msgptr = "The system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver.";
1488 break;
1489 case MCIERR_SEQ_PORT_INUSE:
1490 msgptr = "The specified MIDI port is already in use. Wait until it is free; the try again.";
1491 break;
1492 case MCIERR_SEQ_PORT_MAPNODEVICE:
1493 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.";
1494 break;
1495 case MCIERR_SEQ_PORT_MISCERROR:
1496 msgptr = "An error occurred with the specified port.";
1497 break;
1498 case MCIERR_SEQ_PORT_NONEXISTENT:
1499 msgptr = "The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device.";
1500 break;
1501 case MCIERR_SEQ_PORTUNSPECIFIED:
1502 msgptr = "The system doesnot have a current MIDI port specified.";
1503 break;
1504 case MCIERR_SEQ_TIMER:
1505 msgptr = "All multimedia timers are being used by other applications. Quit one of these applications; then, try again.";
1506 break;
1509 msg# 513 : vcr
1510 msg# 514 : videodisc
1511 msg# 515 : overlay
1512 msg# 516 : cdaudio
1513 msg# 517 : dat
1514 msg# 518 : scanner
1515 msg# 519 : animation
1516 msg# 520 : digitalvideo
1517 msg# 521 : other
1518 msg# 522 : waveaudio
1519 msg# 523 : sequencer
1520 msg# 524 : not ready
1521 msg# 525 : stopped
1522 msg# 526 : playing
1523 msg# 527 : recording
1524 msg# 528 : seeking
1525 msg# 529 : paused
1526 msg# 530 : open
1527 msg# 531 : false
1528 msg# 532 : true
1529 msg# 533 : milliseconds
1530 msg# 534 : hms
1531 msg# 535 : msf
1532 msg# 536 : frames
1533 msg# 537 : smpte 24
1534 msg# 538 : smpte 25
1535 msg# 539 : smpte 30
1536 msg# 540 : smpte 30 drop
1537 msg# 541 : bytes
1538 msg# 542 : samples
1539 msg# 543 : tmsf
1541 default:
1542 TRACE("Unknown MCI Error %ld!\n", dwError);
1543 return FALSE;
1545 lstrcpynA(lpstrBuffer, msgptr, uLength);
1546 TRACE("msg = \"%s\";\n", lpstrBuffer);
1547 return TRUE;
1550 /**************************************************************************
1551 * mciDriverNotify [MMSYSTEM.711]
1553 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1555 TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1557 if (!IsWindow(hWndCallBack)) {
1558 WARN("bad hWnd for call back (0x%04x)\n", hWndCallBack);
1559 return FALSE;
1561 TRACE("before PostMessage\n");
1562 Callout.PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1563 return TRUE;
1566 /**************************************************************************
1567 * mciDriverNotify [WINMM.36]
1569 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1572 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1574 if (!IsWindow(hWndCallBack)) {
1575 WARN("bad hWnd for call back (0x%04x)\n", hWndCallBack);
1576 return FALSE;
1578 TRACE("before PostMessage\n");
1579 Callout.PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1580 return TRUE;
1583 /**************************************************************************
1584 * mciGetDriverData [MMSYSTEM.708]
1586 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1588 return mciGetDriverData(uDeviceID);
1591 /**************************************************************************
1592 * mciGetDriverData [WINMM.44]
1594 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1596 TRACE("(%04x)\n", uDeviceID);
1597 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1598 WARN("Bad uDeviceID\n");
1599 return 0L;
1602 return MCI_GetDrv(uDeviceID)->dwPrivate;
1605 /**************************************************************************
1606 * mciSetDriverData [MMSYSTEM.707]
1608 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1610 return mciSetDriverData(uDeviceID, data);
1613 /**************************************************************************
1614 * mciSetDriverData [WINMM.53]
1616 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1618 TRACE("(%04x, %08lx)\n", uDeviceID, data);
1619 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1620 WARN("Bad uDeviceID\n");
1621 return FALSE;
1624 MCI_GetDrv(uDeviceID)->dwPrivate = data;
1625 return TRUE;
1628 /**************************************************************************
1629 * mciLoadCommandResource [MMSYSTEM.705]
1631 UINT16 WINAPI mciLoadCommandResource16(HANDLE16 hinst, LPCSTR resname, UINT16 type)
1633 char buf[200];
1634 OFSTRUCT ofs;
1635 HANDLE16 xhinst;
1636 HRSRC16 hrsrc;
1637 HGLOBAL16 hmem;
1638 LPSTR segstr;
1639 SEGPTR xmem;
1640 LPBYTE lmem;
1641 static UINT16 mcidevtype = 0;
1643 FIXME("(%04x, %s, %d): stub!\n", hinst, resname, type);
1644 if (!lstrcmpiA(resname, "core")) {
1645 FIXME("(...,\"core\",...), have to use internal tables... (not there yet)\n");
1646 return 0;
1648 return ++mcidevtype;
1649 /* if file exists "resname.mci", then load resource "resname" from it
1650 * otherwise directly from driver
1652 strcpy(buf,resname);
1653 strcat(buf, ".mci");
1654 if (OpenFile(buf, &ofs,OF_EXIST) != HFILE_ERROR) {
1655 xhinst = LoadLibrary16(buf);
1656 if (xhinst > 32)
1657 hinst = xhinst;
1658 } /* else use passed hinst */
1659 segstr = SEGPTR_STRDUP(resname);
1660 hrsrc = FindResource16(hinst, SEGPTR_GET(segstr), type);
1661 SEGPTR_FREE(segstr);
1662 if (!hrsrc) {
1663 WARN("no special commandlist found in resource\n");
1664 return MCI_NO_COMMAND_TABLE;
1666 hmem = LoadResource16(hinst, hrsrc);
1667 if (!hmem) {
1668 WARN("couldn't load resource??\n");
1669 return MCI_NO_COMMAND_TABLE;
1671 xmem = WIN16_LockResource16(hmem);
1672 if (!xmem) {
1673 WARN("couldn't lock resource??\n");
1674 FreeResource16(hmem);
1675 return MCI_NO_COMMAND_TABLE;
1677 lmem = PTR_SEG_TO_LIN(xmem);
1678 TRACE("first resource entry is %s\n", (char*)lmem);
1679 /* parse resource, register stuff, return unique id */
1680 return ++mcidevtype;
1683 /**************************************************************************
1684 * mciFreeCommandResource [MMSYSTEM.713]
1686 BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable)
1688 FIXME("(%04x) stub\n", uTable);
1689 return 0;
1692 /**************************************************************************
1693 * mciFreeCommandResource [WINMM.39]
1695 BOOL WINAPI mciFreeCommandResource(UINT uTable)
1697 FIXME("(%08x) stub\n", uTable);
1698 return 0;
1701 /**************************************************************************
1702 * mciLoadCommandResource [WINMM.48]
1704 UINT WINAPI mciLoadCommandResource(HANDLE hinst, LPCWSTR resname, UINT type)
1706 FIXME("(%04x, %s, %d): stub!\n", hinst, debugstr_w(resname), type);
1707 return 0;
1710 /**************************************************************************
1711 * mciSendCommandA [WINMM.49]
1713 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1715 DWORD dwRet;
1717 TRACE("(%08x, %s, %08lx, %08lx)\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1719 switch (wMsg) {
1720 case MCI_OPEN:
1721 dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1722 break;
1723 case MCI_CLOSE:
1724 dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1725 break;
1726 case MCI_SYSINFO:
1727 dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1728 break;
1729 default:
1730 if (wDevID == MCI_ALL_DEVICE_ID) {
1731 FIXME("unhandled MCI_ALL_DEVICE_ID\n");
1732 dwRet = MCIERR_CANNOT_USE_ALL;
1733 } else {
1734 dwRet = MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2);
1736 break;
1738 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1739 TRACE("=> %08lx\n", dwRet);
1740 return dwRet;
1743 /**************************************************************************
1744 * mciSendCommandW [WINMM.50]
1746 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1748 FIXME("(%08x, %s, %08lx, %08lx): stub\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1749 return MCIERR_UNSUPPORTED_FUNCTION;
1752 /**************************************************************************
1753 * mciSendCommand [MMSYSTEM.701]
1755 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1757 DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND;
1759 TRACE("(%04X, %s, %08lX, %08lX)\n",
1760 wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1762 switch (wMsg) {
1763 case MCI_OPEN:
1764 switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1765 case MCI_MAP_OK:
1766 case MCI_MAP_OKMEM:
1767 dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1768 MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1769 break;
1770 default: break; /* so that gcc does bark */
1772 break;
1773 case MCI_CLOSE:
1774 if (wDevID == MCI_ALL_DEVICE_ID) {
1775 FIXME("unhandled MCI_ALL_DEVICE_ID\n");
1776 dwRet = MCIERR_CANNOT_USE_ALL;
1777 } else if (!MCI_DevIDValid(wDevID)) {
1778 dwRet = MCIERR_INVALID_DEVICE_ID;
1779 } else {
1780 switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1781 case MCI_MAP_OK:
1782 case MCI_MAP_OKMEM:
1783 dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1784 MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1785 break;
1786 default: break; /* so that gcc does bark */
1789 break;
1790 case MCI_SYSINFO:
1791 switch (MCI_MapMsg16To32A(0, wDevID, &dwParam2)) {
1792 case MCI_MAP_OK:
1793 case MCI_MAP_OKMEM:
1794 dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1795 MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
1796 break;
1797 default: break; /* so that gcc does bark */
1799 break;
1800 /* FIXME: it seems that MCI_BREAK and MCI_SOUND need the same handling */
1801 default:
1802 if (wDevID == MCI_ALL_DEVICE_ID) {
1803 FIXME("unhandled MCI_ALL_DEVICE_ID\n");
1804 dwRet = MCIERR_CANNOT_USE_ALL;
1805 } else {
1806 dwRet = MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2);
1808 break;
1810 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1811 TRACE("=> %ld\n", dwRet);
1812 return dwRet;
1815 /**************************************************************************
1816 * mciGetDeviceID [MMSYSTEM.703]
1818 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1820 UINT16 wDevID;
1821 TRACE("(\"%s\")\n", lpstrName);
1823 if (!lpstrName)
1824 return 0;
1826 if (!lstrcmpiA(lpstrName, "ALL"))
1827 return MCI_ALL_DEVICE_ID;
1829 for (wDevID = MCI_FirstDevID(); MCI_DevIDValid(wDevID); wDevID = MCI_NextDevID(wDevID)) {
1830 if (MCI_GetDrv(wDevID)->modp.wType) {
1831 FIXME("This is wrong for compound devices\n");
1832 /* FIXME: for compound devices, lpstrName is matched against
1833 * the name of the file, not the name of the device...
1835 if (MCI_GetOpenDrv(wDevID)->lpstrDeviceType &&
1836 strcmp(MCI_GetOpenDrv(wDevID)->lpstrDeviceType, lpstrName) == 0)
1837 return wDevID;
1839 if (MCI_GetOpenDrv(wDevID)->lpstrAlias &&
1840 strcmp(MCI_GetOpenDrv(wDevID)->lpstrAlias, lpstrName) == 0)
1841 return wDevID;
1845 return 0;
1848 /**************************************************************************
1849 * mciGetDeviceIDA [WINMM.41]
1851 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1853 return mciGetDeviceID16(lpstrName);
1856 /**************************************************************************
1857 * mciGetDeviceIDW [WINMM.43]
1859 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1861 LPSTR lpstrName;
1862 UINT ret;
1864 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1865 ret = mciGetDeviceID16(lpstrName);
1866 HeapFree(GetProcessHeap(), 0, lpstrName);
1867 return ret;
1870 /**************************************************************************
1871 * MCI_DefYieldProc [internal]
1873 UINT16 WINAPI MCI_DefYieldProc(UINT16 wDevID, DWORD data)
1875 INT16 ret;
1877 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1879 if ((HIWORD(data) != 0 && GetActiveWindow16() != HIWORD(data)) ||
1880 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1881 UserYield16();
1882 ret = 0;
1883 } else {
1884 MSG msg;
1886 msg.hwnd = HIWORD(data);
1887 while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1888 ret = 0xFFFF;
1890 return ret;
1893 /**************************************************************************
1894 * mciSetYieldProc [MMSYSTEM.714]
1896 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1898 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1900 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1901 WARN("Bad uDeviceID\n");
1902 return FALSE;
1905 MCI_GetDrv(uDeviceID)->lpfnYieldProc = fpYieldProc;
1906 MCI_GetDrv(uDeviceID)->dwYieldData = dwYieldData;
1907 MCI_GetDrv(uDeviceID)->bIs32 = FALSE;
1909 return TRUE;
1912 /**************************************************************************
1913 * mciSetYieldProc [WINMM.54]
1915 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1917 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1919 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1920 WARN("Bad uDeviceID\n");
1921 return FALSE;
1924 MCI_GetDrv(uDeviceID)->lpfnYieldProc = fpYieldProc;
1925 MCI_GetDrv(uDeviceID)->dwYieldData = dwYieldData;
1926 MCI_GetDrv(uDeviceID)->bIs32 = TRUE;
1928 return TRUE;
1931 /**************************************************************************
1932 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
1934 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1936 FIXME("(%lu, %s) stub\n", dwElementID, lpstrType);
1937 return 0;
1940 /**************************************************************************
1941 * mciGetDeviceIDFromElementIDW [WINMM.42]
1943 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1945 /* FIXME: that's rather strange, there is no
1946 * mciGetDeviceIDFromElementID32A in winmm.spec
1948 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1949 return 0;
1952 /**************************************************************************
1953 * mciGetYieldProc [MMSYSTEM.716]
1955 YIELDPROC WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1957 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1959 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1960 WARN("Bad uDeviceID\n");
1961 return NULL;
1963 if (!MCI_GetDrv(uDeviceID)->lpfnYieldProc) {
1964 WARN("No proc set\n");
1965 return NULL;
1967 if (MCI_GetDrv(uDeviceID)->bIs32) {
1968 WARN("Proc is 32 bit\n");
1969 return NULL;
1971 return MCI_GetDrv(uDeviceID)->lpfnYieldProc;
1974 /**************************************************************************
1975 * mciGetYieldProc [WINMM.47]
1977 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1979 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1981 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1982 WARN("Bad uDeviceID\n");
1983 return NULL;
1985 if (!MCI_GetDrv(uDeviceID)->lpfnYieldProc) {
1986 WARN("No proc set\n");
1987 return NULL;
1989 if (!MCI_GetDrv(uDeviceID)->bIs32) {
1990 WARN("Proc is 32 bit\n");
1991 return NULL;
1993 return MCI_GetDrv(uDeviceID)->lpfnYieldProc;
1996 /**************************************************************************
1997 * mciGetCreatorTask [MMSYSTEM.717]
1999 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
2001 return mciGetCreatorTask(uDeviceID);
2004 /**************************************************************************
2005 * mciGetCreatorTask [WINMM.40]
2007 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
2009 HTASK ret;
2011 TRACE("(%u)\n", uDeviceID);
2013 ret = (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) ?
2014 0 : MCI_GetDrv(uDeviceID)->hCreatorTask;
2016 TRACE("=> %04x\n", ret);
2017 return ret;
2020 /**************************************************************************
2021 * mciDriverYield [MMSYSTEM.710]
2023 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
2025 UINT16 ret = 0;
2027 /* TRACE("(%04x)\n", uDeviceID); */
2029 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
2030 !MCI_GetDrv(uDeviceID)->lpfnYieldProc || MCI_GetDrv(uDeviceID)->bIs32) {
2031 UserYield16();
2032 } else {
2033 ret = MCI_GetDrv(uDeviceID)->lpfnYieldProc(uDeviceID, MCI_GetDrv(uDeviceID)->dwYieldData);
2036 return ret;
2039 /**************************************************************************
2040 * mciDriverYield [WINMM.37]
2042 UINT WINAPI mciDriverYield(UINT uDeviceID)
2044 UINT ret = 0;
2046 TRACE("(%04x)\n", uDeviceID);
2047 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
2048 !MCI_GetDrv(uDeviceID)->lpfnYieldProc || !MCI_GetDrv(uDeviceID)->bIs32) {
2049 UserYield16();
2050 } else {
2051 ret = MCI_GetDrv(uDeviceID)->lpfnYieldProc(uDeviceID, MCI_GetDrv(uDeviceID)->dwYieldData);
2054 return ret;
2057 /**************************************************************************
2058 * midiOutGetNumDevs [WINMM.80]
2060 UINT WINAPI midiOutGetNumDevs(void)
2062 return midiOutGetNumDevs16();
2065 /**************************************************************************
2066 * midiOutGetNumDevs [MMSYSTEM.201]
2068 UINT16 WINAPI midiOutGetNumDevs16(void)
2070 UINT16 count = modMessage(0, MODM_GETNUMDEVS, 0L, 0L, 0L);
2072 TRACE("returns %u\n", count);
2073 return count;
2076 /**************************************************************************
2077 * midiOutGetDevCapsW [WINMM.76]
2079 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps, UINT uSize)
2081 MIDIOUTCAPS16 moc16;
2082 UINT ret;
2084 ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
2085 lpCaps->wMid = moc16.wMid;
2086 lpCaps->wPid = moc16.wPid;
2087 lpCaps->vDriverVersion = moc16.vDriverVersion;
2088 lstrcpyAtoW(lpCaps->szPname, moc16.szPname);
2089 lpCaps->wTechnology = moc16.wTechnology;
2090 lpCaps->wVoices = moc16.wVoices;
2091 lpCaps->wNotes = moc16.wNotes;
2092 lpCaps->wChannelMask = moc16.wChannelMask;
2093 lpCaps->dwSupport = moc16.dwSupport;
2094 return ret;
2097 /**************************************************************************
2098 * midiOutGetDevCapsA [WINMM.75]
2100 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps, UINT uSize)
2102 MIDIOUTCAPS16 moc16;
2103 UINT ret;
2105 ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
2106 lpCaps->wMid = moc16.wMid;
2107 lpCaps->wPid = moc16.wPid;
2108 lpCaps->vDriverVersion = moc16.vDriverVersion;
2109 strcpy(lpCaps->szPname, moc16.szPname);
2110 lpCaps->wTechnology = moc16.wTechnology;
2111 lpCaps->wVoices = moc16.wVoices;
2112 lpCaps->wNotes = moc16.wNotes;
2113 lpCaps->wChannelMask = moc16.wChannelMask;
2114 lpCaps->dwSupport = moc16.dwSupport;
2115 return ret;
2118 /**************************************************************************
2119 * midiOutGetDevCaps [MMSYSTEM.202]
2121 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps, UINT16 uSize)
2123 TRACE("midiOutGetDevCaps\n");
2124 return modMessage(uDeviceID, MODM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
2127 /**************************************************************************
2128 * midiOutGetErrorTextA [WINMM.77]
2130 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2132 TRACE("midiOutGetErrorText\n");
2133 return midiGetErrorText(uError, lpText, uSize);
2136 /**************************************************************************
2137 * midiOutGetErrorTextW [WINMM.78]
2139 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2141 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2142 UINT ret;
2144 TRACE("midiOutGetErrorText\n");
2145 ret = midiGetErrorText(uError, xstr, uSize);
2146 lstrcpyAtoW(lpText, xstr);
2147 HeapFree(GetProcessHeap(), 0, xstr);
2148 return ret;
2151 /**************************************************************************
2152 * midiOutGetErrorText [MMSYSTEM.203]
2154 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2156 TRACE("midiOutGetErrorText\n");
2157 return midiGetErrorText(uError, lpText, uSize);
2160 /**************************************************************************
2161 * midiGetErrorText [internal]
2163 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2165 LPSTR msgptr;
2166 if ((lpText == NULL) || (uSize < 1)) return(FALSE);
2167 lpText[0] = '\0';
2168 switch (uError) {
2169 case MIDIERR_UNPREPARED:
2170 msgptr = "The MIDI header was not prepared. Use the Prepare function to prepare the header, and then try again.";
2171 break;
2172 case MIDIERR_STILLPLAYING:
2173 msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
2174 break;
2175 case MIDIERR_NOMAP:
2176 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.";
2177 break;
2178 case MIDIERR_NOTREADY:
2179 msgptr = "The port is transmitting data to the device. Wait until the data has been transmitted, and then try again.";
2180 break;
2181 case MIDIERR_NODEVICE:
2182 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.";
2183 break;
2184 case MIDIERR_INVALIDSETUP:
2185 msgptr = "The current MIDI setup is damaged. Copy the original MIDIMAP.CFG file to the Windows SYSTEM directory, and then try again.";
2186 break;
2188 msg# 336 : Cannot use the song-pointer time format and the SMPTE time-format together.
2189 msg# 337 : The specified MIDI device is already in use. Wait until it is free, and then try again.
2190 msg# 338 : The specified MIDI device is not installed on the system. Use the Drivers option in Control Panel to install the driver.
2191 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.
2192 msg# 340 : An error occurred using the specified port.
2193 msg# 341 : All multimedia timers are being used by other applications. Quit one of these applications, and then try again.
2194 msg# 342 : There is no current MIDI port.
2195 msg# 343 : There are no MIDI devices installed on the system. Use the Drivers option in Control Panel to install the driver.
2197 default:
2198 msgptr = "Unknown MIDI Error !\n";
2199 break;
2201 lstrcpynA(lpText, msgptr, uSize);
2202 return TRUE;
2205 static LPMIDIOPENDESC MIDI_OutAlloc(HMIDIOUT16* lphMidiOut, DWORD dwCallback,
2206 DWORD dwInstance, DWORD cIDs, MIDIOPENSTRMID* lpIDs)
2208 HMIDI16 hMidiOut;
2209 LPMIDIOPENDESC lpDesc;
2211 hMidiOut = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC) + (cIDs ? (cIDs - 1) : 0) * sizeof(MIDIOPENSTRMID));
2213 if (lphMidiOut != NULL)
2214 *lphMidiOut = hMidiOut;
2215 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2217 if (lpDesc) {
2218 lpDesc->hMidi = hMidiOut;
2219 lpDesc->dwCallback = dwCallback;
2220 lpDesc->dwInstance = dwInstance;
2221 lpDesc->dnDevNode = 0;
2222 lpDesc->cIds = cIDs;
2223 if (cIDs)
2224 memcpy(&(lpDesc->rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2226 return lpDesc;
2229 /**************************************************************************
2230 * midiOutOpen [WINM.84]
2232 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2233 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2235 HMIDIOUT16 hmo16;
2236 UINT ret;
2238 ret = midiOutOpen16(&hmo16, uDeviceID, dwCallback, dwInstance,
2239 CALLBACK32CONV(dwFlags));
2240 if (lphMidiOut) *lphMidiOut = hmo16;
2241 return ret;
2244 /**************************************************************************
2245 * midiOutOpen [MMSYSTEM.204]
2247 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2248 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2250 HMIDIOUT16 hMidiOut;
2251 LPMIDIOPENDESC lpDesc;
2252 UINT16 ret = 0;
2253 BOOL bMapperFlg = FALSE;
2255 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2256 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2258 if (lphMidiOut != NULL) *lphMidiOut = 0;
2260 if (uDeviceID == (UINT16)MIDI_MAPPER) {
2261 TRACE("MIDI_MAPPER mode requested !\n");
2262 bMapperFlg = TRUE;
2263 uDeviceID = 0;
2266 lpDesc = MIDI_OutAlloc(&hMidiOut, dwCallback, dwInstance, 0, NULL);
2268 if (lpDesc == NULL)
2269 return MMSYSERR_NOMEM;
2271 while (uDeviceID < MAXMIDIDRIVERS) {
2272 ret = modMessage(uDeviceID, MODM_OPEN,
2273 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2274 if (ret == MMSYSERR_NOERROR) break;
2275 if (!bMapperFlg) break;
2276 uDeviceID++;
2277 TRACE("MIDI_MAPPER mode ! try next driver...\n");
2279 TRACE("=> wDevID=%u (%d)\n", uDeviceID, ret);
2280 if (ret != MMSYSERR_NOERROR) {
2281 USER_HEAP_FREE(hMidiOut);
2282 if (lphMidiOut) *lphMidiOut = 0;
2283 } else {
2284 lpDesc->wDevID = uDeviceID;
2285 if (lphMidiOut) *lphMidiOut = hMidiOut;
2288 return ret;
2291 /**************************************************************************
2292 * midiOutClose [WINMM.74]
2294 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2296 return midiOutClose16(hMidiOut);
2299 /**************************************************************************
2300 * midiOutClose [MMSYSTEM.205]
2302 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2304 LPMIDIOPENDESC lpDesc;
2305 DWORD dwRet;
2307 TRACE("(%04X)\n", hMidiOut);
2309 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2311 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2312 dwRet = modMessage(lpDesc->wDevID, MODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2313 USER_HEAP_FREE(hMidiOut);
2314 return dwRet;
2317 /**************************************************************************
2318 * midiOutPrepareHeader [WINMM.85]
2320 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2321 MIDIHDR* lpMidiOutHdr, UINT uSize)
2323 LPMIDIOPENDESC lpDesc;
2325 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2327 lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiOut);
2328 if (lpDesc == NULL)
2329 return MMSYSERR_INVALHANDLE;
2330 lpMidiOutHdr->reserved = (DWORD)lpMidiOutHdr;
2331 return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance,
2332 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2335 /**************************************************************************
2336 * midiOutPrepareHeader [MMSYSTEM.206]
2338 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut,
2339 LPMIDIHDR16 /*SEGPTR*/ _lpMidiOutHdr, UINT16 uSize)
2341 LPMIDIOPENDESC lpDesc;
2342 LPMIDIHDR16 lpMidiOutHdr = (LPMIDIHDR16)PTR_SEG_TO_LIN(_lpMidiOutHdr);
2344 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2346 lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiOut);
2347 if (lpDesc == NULL)
2348 return MMSYSERR_INVALHANDLE;
2349 lpMidiOutHdr->reserved = (DWORD)_lpMidiOutHdr;
2350 return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance,
2351 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2354 /**************************************************************************
2355 * midiOutUnprepareHeader [WINMM.89]
2357 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2358 MIDIHDR* lpMidiOutHdr, UINT uSize)
2360 return midiOutUnprepareHeader16(hMidiOut, (MIDIHDR16*)lpMidiOutHdr, uSize);
2363 /**************************************************************************
2364 * midiOutUnprepareHeader [MMSYSTEM.207]
2366 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut,
2367 MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2369 LPMIDIOPENDESC lpDesc;
2371 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2373 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2374 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2375 return modMessage(lpDesc->wDevID, MODM_UNPREPARE, lpDesc->dwInstance,
2376 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2379 /**************************************************************************
2380 * midiOutShortMsg [WINMM.88]
2382 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2384 return midiOutShortMsg16(hMidiOut, dwMsg);
2387 /**************************************************************************
2388 * midiOutShortMsg [MMSYSTEM.208]
2390 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2392 LPMIDIOPENDESC lpDesc;
2394 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
2396 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2397 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2398 return modMessage(lpDesc->wDevID, MODM_DATA, lpDesc->dwInstance, dwMsg, 0L);
2401 /**************************************************************************
2402 * midiOutLongMsg [WINMM.82]
2404 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2405 MIDIHDR* lpMidiOutHdr, UINT uSize)
2407 return midiOutLongMsg16(hMidiOut, (MIDIHDR16*)lpMidiOutHdr, uSize);
2410 /**************************************************************************
2411 * midiOutLongMsg [MMSYSTEM.209]
2413 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut,
2414 MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2416 LPMIDIOPENDESC lpDesc;
2418 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2420 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2421 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2422 return modMessage(lpDesc->wDevID, MODM_LONGDATA, lpDesc->dwInstance,
2423 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2426 /**************************************************************************
2427 * midiOutReset [WINMM.86]
2429 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2431 return midiOutReset16(hMidiOut);
2434 /**************************************************************************
2435 * midiOutReset [MMSYSTEM.210]
2437 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2439 LPMIDIOPENDESC lpDesc;
2441 TRACE("(%04X)\n", hMidiOut);
2443 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2444 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2445 return modMessage(lpDesc->wDevID, MODM_RESET, lpDesc->dwInstance, 0L, 0L);
2448 /**************************************************************************
2449 * midiOutGetVolume [WINM.81]
2451 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2453 return midiOutGetVolume16(uDeviceID, lpdwVolume);
2456 /**************************************************************************
2457 * midiOutGetVolume [MMSYSTEM.211]
2459 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2461 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
2462 return modMessage(uDeviceID, MODM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
2465 /**************************************************************************
2466 * midiOutSetVolume [WINMM.87]
2468 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2470 return midiOutSetVolume16(uDeviceID, dwVolume);
2473 /**************************************************************************
2474 * midiOutSetVolume [MMSYSTEM.212]
2476 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2478 TRACE("(%04X, %08lX);\n", uDeviceID, dwVolume);
2479 return modMessage(uDeviceID, MODM_SETVOLUME, 0L, dwVolume, 0L);
2482 /**************************************************************************
2483 * midiOutCachePatches [WINMM.73]
2485 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2486 WORD* lpwPatchArray, UINT uFlags)
2488 return midiOutCachePatches16(hMidiOut, uBank, lpwPatchArray, uFlags);
2491 /**************************************************************************
2492 * midiOutCachePatches [MMSYSTEM.213]
2494 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2495 WORD* lpwPatchArray, UINT16 uFlags)
2497 /* not really necessary to support this */
2498 FIXME("not supported yet\n");
2499 return MMSYSERR_NOTSUPPORTED;
2502 /**************************************************************************
2503 * midiOutCacheDrumPatches [WINMM.72]
2505 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2506 WORD* lpwKeyArray, UINT uFlags)
2508 return midiOutCacheDrumPatches16(hMidiOut, uPatch, lpwKeyArray, uFlags);
2511 /**************************************************************************
2512 * midiOutCacheDrumPatches [MMSYSTEM.214]
2514 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2515 WORD* lpwKeyArray, UINT16 uFlags)
2517 FIXME("not supported yet\n");
2518 return MMSYSERR_NOTSUPPORTED;
2521 /**************************************************************************
2522 * midiOutGetID [WINMM.79]
2524 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2526 UINT16 xid;
2527 UINT ret;
2529 ret = midiOutGetID16(hMidiOut, &xid);
2530 *lpuDeviceID = xid;
2531 return ret;
2534 /**************************************************************************
2535 * midiOutGetID [MMSYSTEM.215]
2537 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2539 TRACE("midiOutGetID\n");
2540 return 0;
2543 /**************************************************************************
2544 * midiOutMessage [WINMM.83]
2546 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2547 DWORD dwParam1, DWORD dwParam2)
2549 LPMIDIOPENDESC lpDesc;
2551 /* Shouldn't we anyway use the functions midiOutXXX ?
2552 * M$ doc says: This function is used only for driver-specific
2553 * messages that are not supported by the MIDI API.
2554 * Clearly not what we are currently doing
2557 TRACE("(%04X, %04X, %08lX, %08lX)\n",
2558 hMidiOut, uMessage, dwParam1, dwParam2);
2560 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2561 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2562 switch (uMessage) {
2563 case MODM_OPEN:
2564 FIXME("can't handle MODM_OPEN!\n");
2565 return 0;
2566 case MODM_GETDEVCAPS:
2567 return midiOutGetDevCapsA(hMidiOut, (LPMIDIOUTCAPSA)dwParam1, dwParam2);
2568 case MODM_GETNUMDEVS:
2569 case MODM_RESET:
2570 case MODM_CLOSE:
2571 case MODM_GETVOLUME:
2572 case MODM_SETVOLUME:
2573 case MODM_LONGDATA:
2574 case MODM_PREPARE:
2575 case MODM_UNPREPARE:
2576 /* no argument conversion needed */
2577 break;
2578 default:
2579 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
2580 hMidiOut, uMessage, dwParam1, dwParam2);
2581 break;
2583 return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2586 /**************************************************************************
2587 * midiOutMessage [MMSYSTEM.216]
2589 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2590 DWORD dwParam1, DWORD dwParam2)
2592 LPMIDIOPENDESC lpDesc;
2594 TRACE("(%04X, %04X, %08lX, %08lX)\n",
2595 hMidiOut, uMessage, dwParam1, dwParam2);
2596 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2597 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2598 switch (uMessage) {
2599 case MODM_OPEN:
2600 FIXME("can't handle MODM_OPEN!\n");
2601 return 0;
2602 case MODM_GETNUMDEVS:
2603 case MODM_RESET:
2604 case MODM_CLOSE:
2605 case MODM_SETVOLUME:
2606 /* no argument conversion needed */
2607 break;
2608 case MODM_GETVOLUME:
2609 return midiOutGetVolume16(hMidiOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
2610 case MODM_LONGDATA:
2611 return midiOutLongMsg16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2612 case MODM_PREPARE:
2613 /* lpMidiOutHdr is still a segmented pointer for this function */
2614 return midiOutPrepareHeader16(hMidiOut, (LPMIDIHDR16)dwParam1, dwParam2);
2615 case MODM_UNPREPARE:
2616 return midiOutUnprepareHeader16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2617 default:
2618 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
2619 hMidiOut, uMessage, dwParam1, dwParam2);
2620 break;
2622 return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2625 /**************************************************************************
2626 * midiInGetNumDevs [WINMM.64]
2628 UINT WINAPI midiInGetNumDevs(void)
2630 return midiInGetNumDevs16();
2633 /**************************************************************************
2634 * midiInGetNumDevs [MMSYSTEM.301]
2636 UINT16 WINAPI midiInGetNumDevs16(void)
2638 UINT16 count = 0;
2639 TRACE("midiInGetNumDevs\n");
2640 count += midMessage(0, MIDM_GETNUMDEVS, 0L, 0L, 0L);
2641 TRACE("midiInGetNumDevs return %u \n", count);
2642 return count;
2645 /**************************************************************************
2646 * midiInGetDevCaps [WINMM.60]
2648 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2650 MIDIINCAPS16 mic16;
2651 UINT ret = midiInGetDevCaps16(uDeviceID, &mic16, uSize);
2653 lpCaps->wMid = mic16.wMid;
2654 lpCaps->wPid = mic16.wPid;
2655 lpCaps->vDriverVersion = mic16.vDriverVersion;
2656 lstrcpyAtoW(lpCaps->szPname, mic16.szPname);
2657 lpCaps->dwSupport = mic16.dwSupport;
2658 return ret;
2661 /**************************************************************************
2662 * midiInGetDevCaps [WINMM.59]
2664 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2666 MIDIINCAPS16 mic16;
2667 UINT ret = midiInGetDevCaps16(uDeviceID, &mic16, uSize);
2669 lpCaps->wMid = mic16.wMid;
2670 lpCaps->wPid = mic16.wPid;
2671 lpCaps->vDriverVersion = mic16.vDriverVersion;
2672 strcpy(lpCaps->szPname, mic16.szPname);
2673 lpCaps->dwSupport = mic16.dwSupport;
2674 return ret;
2677 /**************************************************************************
2678 * midiInGetDevCaps [MMSYSTEM.302]
2680 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID,
2681 LPMIDIINCAPS16 lpCaps, UINT16 uSize)
2683 TRACE("midiInGetDevCaps\n");
2684 return midMessage(uDeviceID, MIDM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
2687 /**************************************************************************
2688 * midiInGetErrorText [WINMM.62]
2690 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2692 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2693 UINT ret = midiInGetErrorText16(uError, xstr, uSize);
2694 lstrcpyAtoW(lpText, xstr);
2695 HeapFree(GetProcessHeap(), 0, xstr);
2696 return ret;
2699 /**************************************************************************
2700 * midiInGetErrorText [WINMM.61]
2702 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2704 return midiInGetErrorText16(uError, lpText, uSize);
2707 /**************************************************************************
2708 * midiInGetErrorText [MMSYSTEM.303]
2710 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2712 TRACE("midiInGetErrorText\n");
2713 return (midiGetErrorText(uError, lpText, uSize));
2716 /**************************************************************************
2717 * midiInOpen [WINMM.66]
2719 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2720 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2722 HMIDIIN16 xhmid16;
2723 UINT ret = midiInOpen16(&xhmid16, uDeviceID, dwCallback, dwInstance,
2724 CALLBACK32CONV(dwFlags));
2725 if (lphMidiIn)
2726 *lphMidiIn = xhmid16;
2727 return ret;
2730 /**************************************************************************
2731 * midiInOpen [MMSYSTEM.304]
2733 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2734 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2736 HMIDI16 hMidiIn;
2737 LPMIDIOPENDESC lpDesc;
2738 DWORD dwRet = 0;
2739 BOOL bMapperFlg = FALSE;
2741 if (lphMidiIn != NULL)
2742 *lphMidiIn = 0;
2743 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2744 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2745 if (uDeviceID == (UINT16)MIDI_MAPPER) {
2746 TRACE("MIDI_MAPPER mode requested !\n");
2747 bMapperFlg = TRUE;
2748 uDeviceID = 0;
2750 hMidiIn = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC));
2751 if (lphMidiIn != NULL)
2752 *lphMidiIn = hMidiIn;
2753 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2754 if (lpDesc == NULL)
2755 return MMSYSERR_NOMEM;
2756 lpDesc->hMidi = hMidiIn;
2757 lpDesc->dwCallback = dwCallback;
2758 lpDesc->dwInstance = dwInstance;
2760 while (uDeviceID < MAXMIDIDRIVERS) {
2761 dwRet = midMessage(uDeviceID, MIDM_OPEN,
2762 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2763 if (dwRet == MMSYSERR_NOERROR)
2764 break;
2765 if (!bMapperFlg)
2766 break;
2767 uDeviceID++;
2768 TRACE("MIDI_MAPPER mode ! try next driver...\n");
2770 lpDesc->wDevID = uDeviceID;
2772 if (dwRet != MMSYSERR_NOERROR) {
2773 USER_HEAP_FREE(hMidiIn);
2774 if (lphMidiIn) *lphMidiIn = 0;
2777 return dwRet;
2780 /**************************************************************************
2781 * midiInClose [WINMM.58]
2783 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2785 return midiInClose16(hMidiIn);
2788 /**************************************************************************
2789 * midiInClose [MMSYSTEM.305]
2791 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2793 LPMIDIOPENDESC lpDesc;
2794 DWORD dwRet;
2796 TRACE("(%04X)\n", hMidiIn);
2797 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2799 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2800 dwRet = midMessage(lpDesc->wDevID, MIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2801 USER_HEAP_FREE(hMidiIn);
2802 return dwRet;
2805 /**************************************************************************
2806 * midiInPrepareHeader [WINMM.67]
2808 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2809 MIDIHDR* lpMidiInHdr, UINT uSize)
2811 LPMIDIOPENDESC lpDesc;
2813 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2815 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2816 if (lpDesc == NULL)
2817 return MMSYSERR_INVALHANDLE;
2818 lpMidiInHdr->reserved = (DWORD)lpMidiInHdr;
2819 return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance,
2820 (DWORD)lpMidiInHdr, (DWORD)uSize);
2823 /**************************************************************************
2824 * midiInPrepareHeader [MMSYSTEM.306]
2826 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn,
2827 MIDIHDR16* /*SEGPTR*/ _lpMidiInHdr, UINT16 uSize)
2829 LPMIDIOPENDESC lpDesc;
2830 LPMIDIHDR16 lpMidiInHdr = (LPMIDIHDR16)PTR_SEG_TO_LIN(_lpMidiInHdr);
2832 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2834 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2835 if (lpDesc == NULL)
2836 return MMSYSERR_INVALHANDLE;
2837 lpMidiInHdr->reserved = (DWORD)_lpMidiInHdr;
2838 return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance,
2839 (DWORD)lpMidiInHdr, (DWORD)uSize);
2842 /**************************************************************************
2843 * midiInUnprepareHeader [WINMM.71]
2845 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2846 MIDIHDR* lpMidiInHdr, UINT uSize)
2848 return midiInUnprepareHeader16(hMidiIn, (MIDIHDR16*)lpMidiInHdr, uSize);
2851 /**************************************************************************
2852 * midiInUnprepareHeader [MMSYSTEM.307]
2854 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn,
2855 MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2857 LPMIDIOPENDESC lpDesc;
2859 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2861 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2862 if (lpDesc == NULL)
2863 return MMSYSERR_INVALHANDLE;
2864 return midMessage(lpDesc->wDevID, MIDM_UNPREPARE, lpDesc->dwInstance,
2865 (DWORD)lpMidiInHdr, (DWORD)uSize);
2868 /**************************************************************************
2869 * midiInAddBuffer [WINMM.57]
2871 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2872 MIDIHDR* lpMidiInHdr, UINT uSize)
2874 return midiInAddBuffer16(hMidiIn, (MIDIHDR16*)lpMidiInHdr, uSize);
2877 /**************************************************************************
2878 * midiInAddBuffer [MMSYSTEM.308]
2880 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn,
2881 MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2883 TRACE("midiInAddBuffer\n");
2884 return 0;
2887 /**************************************************************************
2888 * midiInStart [WINMM.69]
2890 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2892 return midiInStart16(hMidiIn);
2895 /**************************************************************************
2896 * midiInStart [MMSYSTEM.309]
2898 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2900 LPMIDIOPENDESC lpDesc;
2902 TRACE("(%04X)\n", hMidiIn);
2903 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2904 if (lpDesc == NULL)
2905 return MMSYSERR_INVALHANDLE;
2906 return midMessage(lpDesc->wDevID, MIDM_START, lpDesc->dwInstance, 0L, 0L);
2909 /**************************************************************************
2910 * midiInStop [WINMM.70]
2912 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2914 return midiInStop16(hMidiIn);
2917 /**************************************************************************
2918 * midiInStop [MMSYSTEM.310]
2920 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2922 LPMIDIOPENDESC lpDesc;
2924 TRACE("(%04X)\n", hMidiIn);
2925 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2926 if (lpDesc == NULL)
2927 return MMSYSERR_INVALHANDLE;
2928 return midMessage(lpDesc->wDevID, MIDM_STOP, lpDesc->dwInstance, 0L, 0L);
2931 /**************************************************************************
2932 * midiInReset [WINMM.68]
2934 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2936 return midiInReset16(hMidiIn);
2939 /**************************************************************************
2940 * midiInReset [MMSYSTEM.311]
2942 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2944 LPMIDIOPENDESC lpDesc;
2946 TRACE("(%04X)\n", hMidiIn);
2947 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2948 if (lpDesc == NULL)
2949 return MMSYSERR_INVALHANDLE;
2950 return midMessage(lpDesc->wDevID, MIDM_RESET, lpDesc->dwInstance, 0L, 0L);
2953 /**************************************************************************
2954 * midiInGetID [WINMM.63]
2956 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2958 LPMIDIOPENDESC lpDesc;
2960 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2961 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2962 if (lpDesc == NULL)
2963 return MMSYSERR_INVALHANDLE;
2964 if (lpuDeviceID == NULL)
2965 return MMSYSERR_INVALPARAM;
2966 *lpuDeviceID = lpDesc->wDevID;
2968 return MMSYSERR_NOERROR;
2971 /**************************************************************************
2972 * midiInGetID [MMSYSTEM.312]
2974 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
2976 LPMIDIOPENDESC lpDesc;
2978 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2979 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2980 if (lpDesc == NULL)
2981 return MMSYSERR_INVALHANDLE;
2982 if (lpuDeviceID == NULL)
2983 return MMSYSERR_INVALPARAM;
2984 *lpuDeviceID = lpDesc->wDevID;
2986 return MMSYSERR_NOERROR;
2989 /**************************************************************************
2990 * midiInMessage [WINMM.65]
2992 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
2993 DWORD dwParam1, DWORD dwParam2)
2995 LPMIDIOPENDESC lpDesc;
2997 TRACE("(%04X, %04X, %08lX, %08lX)\n",
2998 hMidiIn, uMessage, dwParam1, dwParam2);
2999 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
3000 if (lpDesc == NULL)
3001 return MMSYSERR_INVALHANDLE;
3003 switch (uMessage) {
3004 case MIDM_OPEN:
3005 FIXME("can't handle MIDM_OPEN!\n");
3006 return 0;
3007 case MIDM_GETDEVCAPS:
3008 return midiInGetDevCapsA(hMidiIn, (LPMIDIINCAPSA)dwParam1, dwParam2);
3009 case MIDM_GETNUMDEVS:
3010 case MIDM_RESET:
3011 case MIDM_STOP:
3012 case MIDM_START:
3013 case MIDM_CLOSE:
3014 /* no argument conversion needed */
3015 break;
3016 case MIDM_PREPARE:
3017 return midiInPrepareHeader(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
3018 case MIDM_UNPREPARE:
3019 return midiInUnprepareHeader(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
3020 case MIDM_ADDBUFFER:
3021 return midiInAddBuffer(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
3022 default:
3023 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
3024 hMidiIn, uMessage, dwParam1, dwParam2);
3025 break;
3027 return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
3030 /**************************************************************************
3031 * midiInMessage [MMSYSTEM.313]
3033 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
3034 DWORD dwParam1, DWORD dwParam2)
3036 LPMIDIOPENDESC lpDesc;
3038 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3040 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
3041 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3042 switch (uMessage) {
3043 case MIDM_OPEN:
3044 WARN("can't handle MIDM_OPEN!\n");
3045 return 0;
3046 case MIDM_GETDEVCAPS:
3047 return midiInGetDevCaps16(hMidiIn, (LPMIDIINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3048 case MIDM_GETNUMDEVS:
3049 case MIDM_RESET:
3050 case MIDM_STOP:
3051 case MIDM_START:
3052 case MIDM_CLOSE:
3053 /* no argument conversion needed */
3054 break;
3055 case MIDM_PREPARE:
3056 return midiInPrepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3057 case MIDM_UNPREPARE:
3058 return midiInUnprepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3059 case MIDM_ADDBUFFER:
3060 return midiInAddBuffer16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3061 default:
3062 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
3063 hMidiIn, uMessage, dwParam1, dwParam2);
3064 break;
3066 return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
3069 typedef struct WINE_MIDIStream{
3070 HMIDIOUT hDevice;
3071 HANDLE hThread;
3072 DWORD dwThreadID;
3073 DWORD dwTempo;
3074 DWORD dwTimeDiv;
3075 DWORD dwPositionMS;
3076 DWORD dwPulses;
3077 DWORD dwStartTicks;
3078 WORD wFlags;
3079 BOOL bFlag;
3080 } WINE_MIDIStream;
3082 /**************************************************************************
3083 * MMSYSTEM_GetMidiStream [internal]
3085 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, MIDIOPENDESC** lplpDesc)
3087 MIDIOPENDESC* lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiStrm);
3089 if (lplpDesc)
3090 *lplpDesc = lpDesc;
3092 if (lpDesc == NULL) {
3093 return FALSE;
3096 *lpMidiStrm = (WINE_MIDIStream*)lpDesc->rgIds.dwStreamID;
3098 return *lpMidiStrm != NULL;
3101 /**************************************************************************
3102 * MMSYSTEM_MidiStreamConvert [internal]
3104 static DWORD MMSYSTEM_MidiStreamConvert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
3106 DWORD ret = 0;
3108 if (lpMidiStrm->dwTimeDiv == 0) {
3109 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
3110 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
3111 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
3112 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
3113 ret = (pulse * 1000) / (nf * nsf);
3114 } else {
3115 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
3116 (double)lpMidiStrm->dwTimeDiv);
3119 return ret;
3122 /**************************************************************************
3123 * MMSYSTEM_MidiStreamPlayer [internal]
3125 static DWORD WINAPI MMSYSTEM_MidiStreamPlayer(LPVOID pmt)
3127 WINE_MIDIStream* lpMidiStrm = pmt;
3128 MIDIOPENDESC* lpDesc = USER_HEAP_LIN_ADDR(lpMidiStrm->hDevice);
3129 MSG msg;
3130 DWORD dwToGo;
3131 DWORD dwCurrTC;
3133 TRACE("(%p)!\n", lpMidiStrm);
3135 /* force thread's queue creation */
3136 /* Used to be InitThreadInput16(0, 5); */
3137 /* but following works also with hack in midiStreamOpen */
3138 Callout.PeekMessageA(&msg, 0, 0, 0, 0);
3140 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
3141 lpMidiStrm->bFlag = TRUE;
3142 TRACE("Ready to go 1\n");
3143 SuspendThread(lpMidiStrm->hThread);
3144 TRACE("Ready to go 2\n");
3146 lpMidiStrm->dwStartTicks = 0;
3147 lpMidiStrm->dwPulses = 0;
3149 while (Callout.GetMessageA(&msg, 0, 0, 0)) {
3150 LPMIDIHDR lpMidiHdr = (LPMIDIHDR)msg.lParam;
3151 LPMIDIEVENT me;
3152 LPBYTE lpData;
3154 switch (msg.message) {
3155 case WM_USER:
3156 TRACE("%s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx]\n",
3157 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
3158 lpMidiHdr->reserved, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded, lpMidiHdr->dwFlags);
3160 /* <HACK>
3161 * midiOutPrepareHeader(), in Wine, sets the 'reserved' field of MIDIHDR to the
3162 * 16 or 32 bit address of lpMidiHdr (depending if called from 16 to 32 bit code)
3164 lpData = ((DWORD)lpMidiHdr == lpMidiHdr->reserved) ?
3165 (LPBYTE)lpMidiHdr->lpData : (LPBYTE)PTR_SEG_TO_LIN(lpMidiHdr->lpData);
3167 #if 0
3168 /* dumps content of lpMidiHdr->lpData
3169 * FIXME: there should be a debug routine somewhere that already does this
3170 * I hate spreading this type of shit all around the code
3172 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
3173 DWORD i;
3174 BYTE ch;
3176 for (i = 0; i < MIN(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
3177 printf("%02x ", lpData[dwToGo + i]);
3178 for (; i < 16; i++)
3179 printf(" ");
3180 for (i = 0; i < MIN(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
3181 ch = lpData[dwToGo + i];
3182 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
3184 printf("\n");
3186 #endif
3187 /* FIXME: EPP says "I don't understand the content of the first MIDIHDR sent
3188 * by native mcimidi, it doesn't look like a correct one".
3189 * this trick allows to throw it away... but I don't like it.
3190 * It looks like part of the file I'm trying to play and definitively looks
3191 * like raw midi content
3192 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
3193 * synchronization issue where native mcimidi is still processing raw MIDI
3194 * content before generating MIDIEVENTs ?
3196 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
3197 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
3198 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
3199 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
3200 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
3201 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
3202 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
3203 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
3204 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
3205 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3206 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3207 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3208 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3209 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3210 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3211 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3212 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3214 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3215 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3216 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3217 FIXME("Dropping bad lpMidiHdr (streamID=%08lx)\n", ((LPMIDIEVENT)lpData)->dwStreamID);
3218 } else {
3219 /* sets initial tick count for first MIDIHDR */
3220 if (!lpMidiStrm->dwStartTicks)
3221 lpMidiStrm->dwStartTicks = GetTickCount();
3223 for (lpMidiHdr->dwOffset = 0; lpMidiHdr->dwOffset < lpMidiHdr->dwBufferLength; ) {
3224 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3226 if (me->dwDeltaTime) {
3227 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStreamConvert(lpMidiStrm, me->dwDeltaTime);
3228 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3229 dwCurrTC = GetTickCount();
3231 lpMidiStrm->dwPulses += me->dwDeltaTime;
3233 TRACE("%ld/%ld/%ld\n", dwToGo, dwCurrTC, me->dwDeltaTime);
3234 if (dwCurrTC < dwToGo)
3235 Sleep(dwToGo - dwCurrTC);
3237 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3238 case MEVT_COMMENT:
3239 FIXME("NIY: MEVT_COMMENT\n");
3240 /* do nothing, skip bytes */
3241 break;
3242 case MEVT_LONGMSG:
3243 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3244 break;
3245 case MEVT_NOP:
3246 break;
3247 case MEVT_SHORTMSG:
3248 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3249 break;
3250 case MEVT_TEMPO:
3251 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3252 break;
3253 case MEVT_VERSION:
3254 break;
3255 default:
3256 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3257 break;
3259 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) + ((me->dwEvent & MEVT_F_LONG) ? ((MEVT_EVENTPARM(me->dwEvent) + 3) & ~3): 0);
3260 if (me->dwEvent & MEVT_F_CALLBACK) {
3261 DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3262 MM_MOM_POSITIONCB, lpDesc->dwInstance, (LPARAM)lpMidiHdr, 0L);
3266 lpMidiHdr->dwFlags |= MHDR_DONE;
3267 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3269 DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3270 MM_MOM_DONE, lpDesc->dwInstance, lpMidiHdr->reserved, 0L);
3271 break;
3272 default:
3273 WARN("Unknown message %d\n", msg.message);
3274 break;
3277 return msg.wParam;
3280 /**************************************************************************
3281 * midiStreamClose [WINMM.90]
3283 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3285 WINE_MIDIStream* lpMidiStrm;
3287 TRACE("(%08x)!\n", hMidiStrm);
3289 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3290 return MMSYSERR_INVALHANDLE;
3292 midiStreamStop(hMidiStrm);
3294 USER_HEAP_FREE(hMidiStrm);
3296 return midiOutClose(hMidiStrm);
3299 /**************************************************************************
3300 * MMSYSTEM_MidiStreamOpen [WINMM.91]
3302 static MMRESULT WINAPI MMSYSTEM_MidiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3303 DWORD cMidi, DWORD dwCallback,
3304 DWORD dwInstance, DWORD fdwOpen)
3306 WINE_MIDIStream* lpMidiStrm;
3307 MMRESULT ret;
3308 MIDIOPENSTRMID mosm;
3309 MIDIOPENDESC* lpDesc;
3310 HMIDIOUT16 hMidiOut16;
3312 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3313 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3315 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3316 return MMSYSERR_INVALPARAM;
3318 if (*lpuDeviceID == (UINT16)MIDI_MAPPER) {
3319 FIXME("MIDI_MAPPER mode requested ! => forcing devID to 0\n");
3320 *lpuDeviceID = 0;
3323 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3324 lpMidiStrm->dwTempo = 500000;
3325 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3326 lpMidiStrm->dwPositionMS = 0;
3328 mosm.dwStreamID = (DWORD)lpMidiStrm;
3329 /* FIXME: the correct value is not allocated yet for MAPPER */
3330 mosm.wDeviceID = *lpuDeviceID;
3331 lpDesc = MIDI_OutAlloc(&hMidiOut16, dwCallback, dwInstance, 1, &mosm);
3332 lpMidiStrm->hDevice = hMidiOut16;
3333 if (lphMidiStrm)
3334 *lphMidiStrm = hMidiOut16;
3336 lpDesc->wDevID = *lpuDeviceID;
3337 ret = modMessage(lpDesc->wDevID, MODM_OPEN,
3338 lpDesc->dwInstance, (DWORD)lpDesc, fdwOpen);
3339 lpMidiStrm->bFlag = FALSE;
3340 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3342 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStreamPlayer,
3343 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3345 if (!lpMidiStrm->hThread) {
3346 midiStreamClose((HMIDISTRM)hMidiOut16);
3347 return MMSYSERR_NOMEM;
3350 /* wait for thread to have started, and for it's queue to be created */
3351 while (!((volatile WINE_MIDIStream*)lpMidiStrm)->bFlag) {
3352 DWORD count;
3354 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3355 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3356 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3358 ReleaseThunkLock(&count);
3359 Sleep(1);
3360 RestoreThunkLock(count);
3363 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n", *lpuDeviceID, lpDesc->wDevID, *lphMidiStrm, ret, lpMidiStrm);
3364 return ret;
3367 /**************************************************************************
3368 * midiStreamOpen [WINMM.91]
3370 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3371 DWORD cMidi, DWORD dwCallback,
3372 DWORD dwInstance, DWORD fdwOpen)
3374 return MMSYSTEM_MidiStreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, CALLBACK32CONV(fdwOpen));
3377 /**************************************************************************
3378 * midiStreamOut [WINMM.92]
3380 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, UINT cbMidiHdr)
3382 WINE_MIDIStream* lpMidiStrm;
3383 DWORD ret = MMSYSERR_NOERROR;
3385 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3387 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3388 ret = MMSYSERR_INVALHANDLE;
3389 } else {
3390 if (!Callout.PostThreadMessageA(lpMidiStrm->dwThreadID, WM_USER, 0, (DWORD)lpMidiHdr)) {
3391 WARN("bad PostThreadMessageA\n");
3394 return ret;
3397 /**************************************************************************
3398 * midiStreamPause [WINMM.93]
3400 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3402 WINE_MIDIStream* lpMidiStrm;
3403 DWORD ret = MMSYSERR_NOERROR;
3405 TRACE("(%08x)!\n", hMidiStrm);
3407 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3408 ret = MMSYSERR_INVALHANDLE;
3409 } else {
3410 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3411 WARN("bad Suspend (%ld)\n", GetLastError());
3414 return ret;
3417 /**************************************************************************
3418 * midiStreamPosition [WINMM.94]
3420 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3422 WINE_MIDIStream* lpMidiStrm;
3423 DWORD ret = MMSYSERR_NOERROR;
3425 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3427 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3428 ret = MMSYSERR_INVALHANDLE;
3429 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3430 ret = MMSYSERR_INVALPARAM;
3431 } else {
3432 switch (lpMMT->wType) {
3433 case TIME_MS:
3434 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3435 TRACE("=> %ld ms\n", lpMMT->u.ms);
3436 break;
3437 case TIME_TICKS:
3438 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3439 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
3440 break;
3441 default:
3442 WARN("Unsupported time type %d\n", lpMMT->wType);
3443 lpMMT->wType = TIME_MS;
3444 ret = MMSYSERR_INVALPARAM;
3445 break;
3448 return ret;
3451 /**************************************************************************
3452 * midiStreamProperty [WINMM.95]
3454 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3456 WINE_MIDIStream* lpMidiStrm;
3457 MMRESULT ret = MMSYSERR_NOERROR;
3459 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3461 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3462 ret = MMSYSERR_INVALHANDLE;
3463 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3464 ret = MMSYSERR_INVALPARAM;
3465 } else if (dwProperty & MIDIPROP_TEMPO) {
3466 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3468 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3469 ret = MMSYSERR_INVALPARAM;
3470 } else if (dwProperty & MIDIPROP_SET) {
3471 lpMidiStrm->dwTempo = mpt->dwTempo;
3472 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
3473 } else if (dwProperty & MIDIPROP_GET) {
3474 mpt->dwTempo = lpMidiStrm->dwTempo;
3475 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
3477 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3478 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3480 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3481 ret = MMSYSERR_INVALPARAM;
3482 } else if (dwProperty & MIDIPROP_SET) {
3483 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3484 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
3485 } else if (dwProperty & MIDIPROP_GET) {
3486 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3487 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
3489 } else {
3490 ret = MMSYSERR_INVALPARAM;
3493 return ret;
3496 /**************************************************************************
3497 * midiStreamRestart [WINMM.96]
3499 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3501 WINE_MIDIStream* lpMidiStrm;
3502 MMRESULT ret = MMSYSERR_NOERROR;
3504 TRACE("(%08x)!\n", hMidiStrm);
3506 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3507 ret = MMSYSERR_INVALHANDLE;
3508 } else {
3509 if (ResumeThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3510 WARN("bad Resume (%ld)\n", GetLastError());
3513 return ret;
3516 /**************************************************************************
3517 * midiStreamStop [WINMM.97]
3519 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3521 WINE_MIDIStream* lpMidiStrm;
3522 MMRESULT ret = MMSYSERR_NOERROR;
3524 FIXME("(%08x) stub!\n", hMidiStrm);
3526 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3527 ret = MMSYSERR_INVALHANDLE;
3528 } else {
3529 /* FIXME: should turn off all notes, and return all buffers to
3530 * calling application
3533 return ret;
3536 /**************************************************************************
3537 * midiStreamClose [MMSYSTEM.252]
3539 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3541 return midiStreamClose(hMidiStrm);
3544 /**************************************************************************
3545 * midiStreamOpen [MMSYSTEM.251]
3547 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3548 DWORD cMidi, DWORD dwCallback,
3549 DWORD dwInstance, DWORD fdwOpen)
3551 HMIDISTRM hMidiStrm32;
3552 MMRESULT ret;
3553 UINT devid32;
3555 if (!phMidiStrm || !devid)
3556 return MMSYSERR_INVALPARAM;
3557 devid32 = *devid;
3558 ret = MMSYSTEM_MidiStreamOpen(&hMidiStrm32, &devid32, cMidi, dwCallback, dwInstance, fdwOpen);
3559 *phMidiStrm = hMidiStrm32;
3560 *devid = devid32;
3561 return ret;
3564 /**************************************************************************
3565 * midiStreamOut [MMSYSTEM.254]
3567 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3569 return midiStreamOut(hMidiStrm, (LPMIDIHDR)lpMidiHdr, cbMidiHdr);
3572 /**************************************************************************
3573 * midiStreamPause [MMSYSTEM.255]
3575 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3577 return midiStreamPause(hMidiStrm);
3580 /**************************************************************************
3581 * midiStreamPosition [MMSYSTEM.253]
3583 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3585 MMTIME mmt32;
3586 MMRESULT ret;
3588 if (!lpmmt16)
3589 return MMSYSERR_INVALPARAM;
3590 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3591 ret = midiStreamPosition(hMidiStrm, &mmt32, sizeof(MMTIME));
3592 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3593 return ret;
3596 /**************************************************************************
3597 * midiStreamProperty [MMSYSTEM.250]
3599 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3601 return midiStreamProperty(hMidiStrm, lpPropData, dwProperty);
3604 /**************************************************************************
3605 * midiStreamRestart [MMSYSTEM.256]
3607 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3609 return midiStreamRestart(hMidiStrm);
3612 /**************************************************************************
3613 * midiStreamStop [MMSYSTEM.257]
3615 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3617 return midiStreamStop(hMidiStrm);
3620 /**************************************************************************
3621 * waveOutGetNumDevs [MMSYSTEM.401]
3623 UINT WINAPI waveOutGetNumDevs()
3625 return waveOutGetNumDevs16();
3628 /**************************************************************************
3629 * waveOutGetNumDevs [WINMM.167]
3631 UINT16 WINAPI waveOutGetNumDevs16()
3633 UINT16 count = 0;
3634 TRACE("waveOutGetNumDevs\n");
3635 /* FIXME: I'm not sure MCI_FirstDevID() is correct */
3636 count += wodMessage(MCI_FirstDevID(), WODM_GETNUMDEVS, 0L, 0L, 0L);
3637 TRACE("waveOutGetNumDevs return %u \n", count);
3638 return count;
3641 /**************************************************************************
3642 * waveOutGetDevCaps [MMSYSTEM.402]
3644 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID, LPWAVEOUTCAPS16 lpCaps,
3645 UINT16 uSize)
3647 if (uDeviceID > waveOutGetNumDevs16() - 1) return MMSYSERR_BADDEVICEID;
3648 if (uDeviceID == (UINT16)WAVE_MAPPER) return MMSYSERR_BADDEVICEID; /* FIXME: do we have a wave mapper ? */
3649 TRACE("waveOutGetDevCaps\n");
3650 return wodMessage(uDeviceID, WODM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
3653 /**************************************************************************
3654 * waveOutGetDevCapsA [WINMM.162]
3656 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3657 UINT uSize)
3659 WAVEOUTCAPS16 woc16;
3660 UINT16 ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3662 lpCaps->wMid = woc16.wMid;
3663 lpCaps->wPid = woc16.wPid;
3664 lpCaps->vDriverVersion = woc16.vDriverVersion;
3665 strcpy(lpCaps->szPname, woc16.szPname);
3666 lpCaps->dwFormats = woc16.dwFormats;
3667 lpCaps->wChannels = woc16.wChannels;
3668 lpCaps->dwSupport = woc16.dwSupport;
3669 return ret;
3672 /**************************************************************************
3673 * waveOutGetDevCapsW [WINMM.163]
3675 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3676 UINT uSize)
3678 WAVEOUTCAPS16 woc16;
3679 UINT ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3681 lpCaps->wMid = woc16.wMid;
3682 lpCaps->wPid = woc16.wPid;
3683 lpCaps->vDriverVersion = woc16.vDriverVersion;
3684 lstrcpyAtoW(lpCaps->szPname, woc16.szPname);
3685 lpCaps->dwFormats = woc16.dwFormats;
3686 lpCaps->wChannels = woc16.wChannels;
3687 lpCaps->dwSupport = woc16.dwSupport;
3688 return ret;
3691 /**************************************************************************
3692 * waveOutGetErrorText [MMSYSTEM.403]
3694 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3696 TRACE("waveOutGetErrorText\n");
3697 return waveGetErrorText(uError, lpText, uSize);
3700 /**************************************************************************
3701 * waveOutGetErrorTextA [WINMM.164]
3703 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3705 return waveOutGetErrorText16(uError, lpText, uSize);
3708 /**************************************************************************
3709 * waveOutGetErrorTextW [WINMM.165]
3711 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3713 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3714 UINT ret = waveOutGetErrorTextA(uError, xstr, uSize);
3716 lstrcpyAtoW(lpText, xstr);
3717 HeapFree(GetProcessHeap(), 0, xstr);
3718 return ret;
3721 /**************************************************************************
3722 * waveGetErrorText [internal]
3724 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3726 LPSTR msgptr;
3727 TRACE("(%04X, %p, %d);\n",
3728 uError, lpText, uSize);
3729 if ((lpText == NULL) || (uSize < 1)) return(FALSE);
3730 lpText[0] = '\0';
3731 switch (uError) {
3732 case MMSYSERR_NOERROR:
3733 msgptr = "The specified command was carried out.";
3734 break;
3735 case MMSYSERR_ERROR:
3736 msgptr = "Undefined external error.";
3737 break;
3738 case MMSYSERR_BADDEVICEID:
3739 msgptr = "A device ID has been used that is out of range for your system.";
3740 break;
3741 case MMSYSERR_NOTENABLED:
3742 msgptr = "The driver was not enabled.";
3743 break;
3744 case MMSYSERR_ALLOCATED:
3745 msgptr = "The specified device is already in use. Wait until it is free, and then try again.";
3746 break;
3747 case MMSYSERR_INVALHANDLE:
3748 msgptr = "The specified device handle is invalid.";
3749 break;
3750 case MMSYSERR_NODRIVER:
3751 msgptr = "There is no driver installed on your system !\n";
3752 break;
3753 case MMSYSERR_NOMEM:
3754 msgptr = "Not enough memory available for this task. Quit one or more applications to increase available memory, and then try again.";
3755 break;
3756 case MMSYSERR_NOTSUPPORTED:
3757 msgptr = "This function is not supported. Use the Capabilities function to determine which functions and messages the driver supports.";
3758 break;
3759 case MMSYSERR_BADERRNUM:
3760 msgptr = "An error number was specified that is not defined in the system.";
3761 break;
3762 case MMSYSERR_INVALFLAG:
3763 msgptr = "An invalid flag was passed to a system function.";
3764 break;
3765 case MMSYSERR_INVALPARAM:
3766 msgptr = "An invalid parameter was passed to a system function.";
3767 break;
3768 case WAVERR_BADFORMAT:
3769 msgptr = "The specified format is not supported or cannot be translated. Use the Capabilities function to determine the supported formats";
3770 break;
3771 case WAVERR_STILLPLAYING:
3772 msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
3773 break;
3774 case WAVERR_UNPREPARED:
3775 msgptr = "The wave header was not prepared. Use the Prepare function to prepare the header, and then try again.";
3776 break;
3777 case WAVERR_SYNC:
3778 msgptr = "Cannot open the device without using the WAVE_ALLOWSYNC flag. Use the flag, and then try again.";
3779 break;
3780 default:
3781 msgptr = "Unknown MMSYSTEM Error !\n";
3782 break;
3784 lstrcpynA(lpText, msgptr, uSize);
3785 return TRUE;
3788 /**************************************************************************
3789 * waveOutOpen [WINMM.173]
3790 * All the args/structs have the same layout as the win16 equivalents
3792 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3793 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3794 DWORD dwInstance, DWORD dwFlags)
3796 HWAVEOUT16 hwo16;
3797 UINT ret = waveOutOpen16(&hwo16, uDeviceID, lpFormat, dwCallback, dwInstance,
3798 CALLBACK32CONV(dwFlags));
3800 if (lphWaveOut) *lphWaveOut=hwo16;
3801 return ret;
3804 /**************************************************************************
3805 * waveOutOpen [MMSYSTEM.404]
3807 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3808 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3809 DWORD dwInstance, DWORD dwFlags)
3811 HWAVEOUT16 hWaveOut;
3812 LPWAVEOPENDESC lpDesc;
3813 DWORD dwRet = 0;
3814 BOOL bMapperFlg = FALSE;
3816 TRACE("(%p, %d, %p, %08lX, %08lX, %08lX);\n",
3817 lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
3818 if (dwFlags & WAVE_FORMAT_QUERY)
3819 TRACE("WAVE_FORMAT_QUERY requested !\n");
3820 if (uDeviceID == (UINT16)WAVE_MAPPER) {
3821 TRACE("WAVE_MAPPER mode requested !\n");
3822 bMapperFlg = TRUE;
3823 uDeviceID = 0;
3825 if (lpFormat == NULL) return WAVERR_BADFORMAT;
3827 hWaveOut = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
3828 if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
3829 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3830 if (lpDesc == NULL) return MMSYSERR_NOMEM;
3831 lpDesc->hWave = hWaveOut;
3832 lpDesc->lpFormat = (LPWAVEFORMAT)lpFormat; /* should the struct be copied iso pointer? */
3833 lpDesc->dwCallBack = dwCallback;
3834 lpDesc->dwInstance = dwInstance;
3835 if (uDeviceID >= MAXWAVEDRIVERS)
3836 uDeviceID = 0;
3837 while (uDeviceID < MAXWAVEDRIVERS) {
3838 dwRet = wodMessage(uDeviceID, WODM_OPEN,
3839 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
3840 if (dwRet == MMSYSERR_NOERROR) break;
3841 if (!bMapperFlg) break;
3842 uDeviceID++;
3843 TRACE("WAVE_MAPPER mode ! try next driver...\n");
3845 lpDesc->uDeviceID = uDeviceID; /* save physical Device ID */
3846 if (dwFlags & WAVE_FORMAT_QUERY) {
3847 TRACE("End of WAVE_FORMAT_QUERY !\n");
3848 dwRet = waveOutClose(hWaveOut);
3849 if (lphWaveOut) *lphWaveOut = 0;
3851 else if (dwRet != MMSYSERR_NOERROR)
3853 USER_HEAP_FREE(hWaveOut);
3854 if (lphWaveOut) *lphWaveOut = 0;
3856 return dwRet;
3859 /**************************************************************************
3860 * waveOutClose [WINMM.161]
3862 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3864 return waveOutClose16(hWaveOut);
3867 /**************************************************************************
3868 * waveOutClose [MMSYSTEM.405]
3870 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
3872 LPWAVEOPENDESC lpDesc;
3873 DWORD dwRet;
3875 TRACE("(%04X)\n", hWaveOut);
3877 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3878 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3879 dwRet = wodMessage(lpDesc->uDeviceID, WODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
3880 USER_HEAP_FREE(hWaveOut);
3881 return dwRet;
3884 /**************************************************************************
3885 * waveOutPrepareHeader [WINMM.175]
3887 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
3888 WAVEHDR* lpWaveOutHdr, UINT uSize)
3890 LPWAVEOPENDESC lpDesc;
3892 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3894 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3895 if (lpDesc == NULL)
3896 return MMSYSERR_INVALHANDLE;
3897 lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr;
3898 return wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance,
3899 (DWORD)lpWaveOutHdr, uSize);
3902 /**************************************************************************
3903 * waveOutPrepareHeader [MMSYSTEM.406]
3905 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut,
3906 WAVEHDR* /*SEGPTR*/ _lpWaveOutHdr, UINT16 uSize)
3908 LPWAVEOPENDESC lpDesc;
3909 LPWAVEHDR lpWaveOutHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(_lpWaveOutHdr);
3910 UINT16 ret;
3912 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3914 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3915 if (lpDesc == NULL)
3916 return MMSYSERR_INVALHANDLE;
3917 lpWaveOutHdr->reserved = (DWORD)_lpWaveOutHdr;
3918 ret = wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance,
3919 (DWORD)lpWaveOutHdr, uSize);
3920 return ret;
3923 /**************************************************************************
3924 * waveOutUnprepareHeader [WINMM.181]
3926 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
3927 WAVEHDR* lpWaveOutHdr, UINT uSize)
3929 LPWAVEOPENDESC lpDesc;
3931 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3933 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3934 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3935 lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr;
3936 return wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance,
3937 (DWORD)lpWaveOutHdr, uSize);
3940 /**************************************************************************
3941 * waveOutUnprepareHeader [MMSYSTEM.407]
3943 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut,
3944 WAVEHDR* lpWaveOutHdr, UINT16 uSize)
3946 LPWAVEOPENDESC lpDesc;
3947 UINT16 ret;
3949 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3951 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3952 if (lpDesc == NULL)
3953 return MMSYSERR_INVALHANDLE;
3954 ret = wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance,
3955 (DWORD)lpWaveOutHdr, uSize);
3956 return ret;
3959 /**************************************************************************
3960 * waveOutWrite [MMSYSTEM.408]
3962 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, WAVEHDR* lpWaveOutHdr,
3963 UINT uSize)
3965 LPWAVEOPENDESC lpDesc;
3967 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3969 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3970 if (lpDesc == NULL)
3971 return MMSYSERR_INVALHANDLE;
3972 return wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance,
3973 (DWORD)lpWaveOutHdr, uSize);
3976 /**************************************************************************
3977 * waveOutWrite [MMSYSTEM.408]
3979 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, WAVEHDR* lpWaveOutHdr,
3980 UINT16 uSize)
3982 LPWAVEOPENDESC lpDesc;
3983 UINT16 ret;
3985 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3987 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3988 if (lpDesc == NULL)
3989 return MMSYSERR_INVALHANDLE;
3990 ret = wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance, (DWORD)lpWaveOutHdr, uSize);
3991 return ret;
3994 /**************************************************************************
3995 * waveOutPause [WINMM.174]
3997 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
3999 return waveOutPause16(hWaveOut);
4002 /**************************************************************************
4003 * waveOutPause [MMSYSTEM.409]
4005 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut)
4007 LPWAVEOPENDESC lpDesc;
4009 TRACE("(%04X)\n", hWaveOut);
4011 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4012 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4013 return wodMessage(lpDesc->uDeviceID, WODM_PAUSE, lpDesc->dwInstance, 0L, 0L);
4016 /**************************************************************************
4017 * waveOutRestart [WINMM.177]
4019 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
4021 return waveOutRestart16(hWaveOut);
4024 /**************************************************************************
4025 * waveOutRestart [MMSYSTEM.410]
4027 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut)
4029 LPWAVEOPENDESC lpDesc;
4031 TRACE("(%04X)\n", hWaveOut);
4033 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4034 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4035 return wodMessage(lpDesc->uDeviceID, WODM_RESTART, lpDesc->dwInstance, 0L, 0L);
4038 /**************************************************************************
4039 * waveOutReset [WINMM.176]
4041 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
4043 return waveOutReset16(hWaveOut);
4046 /**************************************************************************
4047 * waveOutReset [MMSYSTEM.411]
4049 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut)
4051 LPWAVEOPENDESC lpDesc;
4053 TRACE("(%04X)\n", hWaveOut);
4055 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4056 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4057 return wodMessage(lpDesc->uDeviceID, WODM_RESET, lpDesc->dwInstance, 0L, 0L);
4060 /**************************************************************************
4061 * waveOutGetPosition [WINMM.170]
4063 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
4064 UINT uSize)
4066 MMTIME16 mmt16;
4067 UINT ret;
4069 mmt16.wType = lpTime->wType;
4070 ret = waveOutGetPosition16(hWaveOut, &mmt16, sizeof(mmt16));
4071 MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
4072 return ret;
4075 /**************************************************************************
4076 * waveOutGetPosition [MMSYSTEM.412]
4078 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
4079 UINT16 uSize)
4081 LPWAVEOPENDESC lpDesc;
4082 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
4083 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4084 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4085 return wodMessage(lpDesc->uDeviceID, WODM_GETPOS, lpDesc->dwInstance,
4086 (DWORD)lpTime, (DWORD)uSize);
4089 #define WAVEOUT_SHORTCUT_1(xx, XX, atype) \
4090 UINT WINAPI waveOut##xx(HWAVEOUT hWaveOut, atype x) \
4092 return waveOut##xx##16(hWaveOut, x); \
4094 UINT16 WINAPI waveOut##xx##16(HWAVEOUT16 hWaveOut, atype x) \
4096 LPWAVEOPENDESC lpDesc; \
4097 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)x); \
4098 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut); \
4099 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE; \
4100 return wodMessage(lpDesc->uDeviceID, WODM_##XX, \
4101 lpDesc->dwInstance, (DWORD)x, 0L); \
4104 WAVEOUT_SHORTCUT_1(GetPitch, GETPITCH, DWORD*)
4105 WAVEOUT_SHORTCUT_1(SetPitch, SETPITCH, DWORD)
4106 WAVEOUT_SHORTCUT_1(GetPlaybackRate, GETPLAYBACKRATE, DWORD*)
4107 WAVEOUT_SHORTCUT_1(SetPlaybackRate, SETPLAYBACKRATE, DWORD)
4109 #define WAVEOUT_SHORTCUT_2(xx, XX, atype) \
4110 UINT WINAPI waveOut##xx(UINT devid, atype x) \
4112 return waveOut##xx##16(devid, x); \
4114 UINT16 WINAPI waveOut##xx##16(UINT16 devid, atype x) \
4116 TRACE("(%04X, %08lx);\n", devid, (DWORD)x); \
4117 return wodMessage(devid, WODM_##XX, 0L, (DWORD)x, 0L); \
4120 WAVEOUT_SHORTCUT_2(GetVolume, GETVOLUME, DWORD*)
4121 WAVEOUT_SHORTCUT_2(SetVolume, SETVOLUME, DWORD)
4123 /**************************************************************************
4124 * waveOutBreakLoop [MMSYSTEM.419]
4126 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
4128 return waveOutBreakLoop16(hWaveOut);
4131 /**************************************************************************
4132 * waveOutBreakLoop [MMSYSTEM.419]
4134 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut)
4136 TRACE("(%04X)\n", hWaveOut);
4137 return MMSYSERR_INVALHANDLE;
4140 /**************************************************************************
4141 * waveOutGetID [MMSYSTEM.420]
4143 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
4145 LPWAVEOPENDESC lpDesc;
4147 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4149 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4150 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4151 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4152 *lpuDeviceID = lpDesc->uDeviceID;
4153 return 0;
4156 /**************************************************************************
4157 * waveOutGetID [MMSYSTEM.420]
4159 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
4161 LPWAVEOPENDESC lpDesc;
4163 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4165 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4166 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4167 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4168 *lpuDeviceID = lpDesc->uDeviceID;
4169 return 0;
4172 /**************************************************************************
4173 * waveOutMessage [MMSYSTEM.421]
4175 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
4176 DWORD dwParam1, DWORD dwParam2)
4178 LPWAVEOPENDESC lpDesc;
4180 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4181 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4182 switch (uMessage) {
4183 case WODM_GETNUMDEVS:
4184 case WODM_GETPOS:
4185 case WODM_GETVOLUME:
4186 case WODM_GETPITCH:
4187 case WODM_GETPLAYBACKRATE:
4188 case WODM_SETVOLUME:
4189 case WODM_SETPITCH:
4190 case WODM_SETPLAYBACKRATE:
4191 case WODM_RESET:
4192 case WODM_PAUSE:
4193 case WODM_PREPARE:
4194 case WODM_UNPREPARE:
4195 case WODM_STOP:
4196 case WODM_CLOSE:
4197 /* no argument conversion needed */
4198 break;
4199 case WODM_WRITE:
4200 return waveOutWrite(hWaveOut, (LPWAVEHDR)dwParam1, dwParam2);
4201 case WODM_GETDEVCAPS:
4202 /* FIXME: UNICODE/ANSI? */
4203 return waveOutGetDevCapsA(hWaveOut, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
4204 case WODM_OPEN:
4205 FIXME("can't handle WODM_OPEN, please report.\n");
4206 break;
4207 default:
4208 ERR("(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
4209 hWaveOut, uMessage, dwParam1, dwParam2);
4210 break;
4212 return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4215 /**************************************************************************
4216 * waveOutMessage [MMSYSTEM.421]
4218 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4219 DWORD dwParam1, DWORD dwParam2)
4221 LPWAVEOPENDESC lpDesc;
4223 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4224 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4225 switch (uMessage) {
4226 case WODM_GETNUMDEVS:
4227 case WODM_SETVOLUME:
4228 case WODM_SETPITCH:
4229 case WODM_SETPLAYBACKRATE:
4230 case WODM_RESET:
4231 case WODM_PAUSE:
4232 case WODM_STOP:
4233 case WODM_CLOSE:
4234 /* no argument conversion needed */
4235 break;
4236 case WODM_GETPOS:
4237 return waveOutGetPosition16(hWaveOut, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4238 case WODM_GETVOLUME:
4239 return waveOutGetVolume16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4240 case WODM_GETPITCH:
4241 return waveOutGetPitch16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4242 case WODM_GETPLAYBACKRATE:
4243 return waveOutGetPlaybackRate16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4244 case WODM_GETDEVCAPS:
4245 return waveOutGetDevCaps16(hWaveOut, (LPWAVEOUTCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4246 case WODM_PREPARE:
4247 return waveOutPrepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4248 case WODM_UNPREPARE:
4249 return waveOutUnprepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4250 case WODM_WRITE:
4251 return waveOutWrite16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4252 case WODM_OPEN:
4253 FIXME("can't handle WODM_OPEN, please report.\n");
4254 break;
4255 default:
4256 ERR("(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
4257 hWaveOut, uMessage, dwParam1, dwParam2);
4259 return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4262 /**************************************************************************
4263 * waveInGetNumDevs [WINMM.151]
4265 UINT WINAPI waveInGetNumDevs()
4267 return waveInGetNumDevs16();
4270 /**************************************************************************
4271 * waveInGetNumDevs [MMSYSTEM.501]
4273 UINT16 WINAPI waveInGetNumDevs16()
4275 UINT16 count = 0;
4277 TRACE("waveInGetNumDevs\n");
4278 count += widMessage(0, WIDM_GETNUMDEVS, 0L, 0L, 0L);
4279 TRACE("waveInGetNumDevs return %u \n", count);
4280 return count;
4283 /**************************************************************************
4284 * waveInGetDevCapsA [WINMM.147]
4286 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4288 WAVEINCAPS16 wic16;
4289 UINT ret = waveInGetDevCaps16(uDeviceID, &wic16, uSize);
4291 lpCaps->wMid = wic16.wMid;
4292 lpCaps->wPid = wic16.wPid;
4293 lpCaps->vDriverVersion = wic16.vDriverVersion;
4294 lstrcpyAtoW(lpCaps->szPname, wic16.szPname);
4295 lpCaps->dwFormats = wic16.dwFormats;
4296 lpCaps->wChannels = wic16.wChannels;
4298 return ret;
4301 /**************************************************************************
4302 * waveInGetDevCapsA [WINMM.146]
4304 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4306 WAVEINCAPS16 wic16;
4307 UINT ret = waveInGetDevCaps16(uDeviceID, &wic16, uSize);
4309 lpCaps->wMid = wic16.wMid;
4310 lpCaps->wPid = wic16.wPid;
4311 lpCaps->vDriverVersion = wic16.vDriverVersion;
4312 strcpy(lpCaps->szPname, wic16.szPname);
4313 lpCaps->dwFormats = wic16.dwFormats;
4314 lpCaps->wChannels = wic16.wChannels;
4315 return ret;
4318 /**************************************************************************
4319 * waveInGetDevCaps [MMSYSTEM.502]
4321 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps, UINT16 uSize)
4323 TRACE("waveInGetDevCaps\n");
4325 return widMessage(uDeviceID, WIDM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
4328 /**************************************************************************
4329 * waveInGetErrorTextA [WINMM.148]
4331 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4333 TRACE("waveInGetErrorText\n");
4334 return waveGetErrorText(uError, lpText, uSize);
4337 /**************************************************************************
4338 * waveInGetErrorTextW [WINMM.149]
4340 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4342 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4343 UINT ret = waveGetErrorText(uError, txt, uSize);
4345 lstrcpyAtoW(lpText, txt);
4346 HeapFree(GetProcessHeap(), 0, txt);
4347 return ret;
4350 /**************************************************************************
4351 * waveInGetErrorText [MMSYSTEM.503]
4353 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4355 TRACE("waveInGetErrorText\n");
4356 return waveGetErrorText(uError, lpText, uSize);
4359 /**************************************************************************
4360 * waveInOpen [WINMM.154]
4362 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4363 const LPWAVEFORMAT lpFormat, DWORD dwCallback,
4364 DWORD dwInstance, DWORD dwFlags)
4366 HWAVEIN16 hwin16;
4367 UINT ret = waveInOpen16(&hwin16, uDeviceID, lpFormat, dwCallback, dwInstance,
4368 CALLBACK32CONV(dwFlags));
4369 if (lphWaveIn) *lphWaveIn = hwin16;
4370 return ret;
4373 /**************************************************************************
4374 * waveInOpen [MMSYSTEM.504]
4376 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4377 const LPWAVEFORMAT lpFormat, DWORD dwCallback,
4378 DWORD dwInstance, DWORD dwFlags)
4380 HWAVEIN16 hWaveIn;
4381 LPWAVEOPENDESC lpDesc;
4382 DWORD dwRet = 0;
4383 BOOL bMapperFlg = FALSE;
4385 TRACE("(%p, %d, %p, %08lX, %08lX, %08lX);\n",
4386 lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
4387 if (dwFlags & WAVE_FORMAT_QUERY)
4388 TRACE("WAVE_FORMAT_QUERY requested !\n");
4389 if (uDeviceID == (UINT16)WAVE_MAPPER) {
4390 TRACE("WAVE_MAPPER mode requested !\n");
4391 bMapperFlg = TRUE;
4392 uDeviceID = 0;
4394 if (lpFormat == NULL) return WAVERR_BADFORMAT;
4395 hWaveIn = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
4396 if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
4397 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4398 if (lpDesc == NULL) return MMSYSERR_NOMEM;
4399 lpDesc->hWave = hWaveIn;
4400 lpDesc->lpFormat = lpFormat;
4401 lpDesc->dwCallBack = dwCallback;
4402 lpDesc->dwInstance = dwInstance;
4403 while (uDeviceID < MAXWAVEDRIVERS) {
4404 dwRet = widMessage(uDeviceID, WIDM_OPEN,
4405 lpDesc->dwInstance, (DWORD)lpDesc, 0L);
4406 if (dwRet == MMSYSERR_NOERROR) break;
4407 if (!bMapperFlg) break;
4408 uDeviceID++;
4409 TRACE("WAVE_MAPPER mode ! try next driver...\n");
4411 lpDesc->uDeviceID = uDeviceID;
4412 if (dwFlags & WAVE_FORMAT_QUERY) {
4413 TRACE("End of WAVE_FORMAT_QUERY !\n");
4414 dwRet = waveInClose16(hWaveIn);
4415 } else if (dwRet != MMSYSERR_NOERROR) {
4416 USER_HEAP_FREE(hWaveIn);
4417 if (lphWaveIn) *lphWaveIn = 0;
4420 return dwRet;
4423 /**************************************************************************
4424 * waveInClose [WINMM.145]
4426 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4428 return waveInClose16(hWaveIn);
4431 /**************************************************************************
4432 * waveInClose [MMSYSTEM.505]
4434 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4436 LPWAVEOPENDESC lpDesc;
4437 DWORD dwRet;
4439 TRACE("(%04X)\n", hWaveIn);
4440 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4441 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4442 dwRet = widMessage(lpDesc->uDeviceID, WIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
4443 USER_HEAP_FREE(hWaveIn);
4444 return dwRet;
4447 /**************************************************************************
4448 * waveInPrepareHeader [WINMM.155]
4450 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn,
4451 WAVEHDR* lpWaveInHdr, UINT uSize)
4453 LPWAVEOPENDESC lpDesc;
4455 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4456 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4457 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4458 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4459 lpWaveInHdr->lpNext = NULL;
4460 lpWaveInHdr->dwBytesRecorded = 0;
4461 lpWaveInHdr->reserved = (DWORD)lpWaveInHdr;
4463 return widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance,
4464 (DWORD)lpWaveInHdr, uSize);
4467 /**************************************************************************
4468 * waveInPrepareHeader [MMSYSTEM.506]
4470 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn,
4471 WAVEHDR* /* SEGPTR */ _lpWaveInHdr, UINT16 uSize)
4473 LPWAVEOPENDESC lpDesc;
4474 LPWAVEHDR lpWaveInHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(_lpWaveInHdr);
4475 UINT16 ret;
4477 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4479 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4480 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4481 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4483 lpWaveInHdr->lpNext = NULL;
4484 lpWaveInHdr->dwBytesRecorded = 0;
4486 lpWaveInHdr->reserved = (DWORD)_lpWaveInHdr;
4488 ret = widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance,
4489 (DWORD)lpWaveInHdr, uSize);
4490 return ret;
4493 /**************************************************************************
4494 * waveInUnprepareHeader [WINMM.159]
4496 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn,
4497 WAVEHDR* lpWaveInHdr, UINT uSize)
4499 LPWAVEOPENDESC lpDesc;
4501 TRACE("(%04X, %p, %u);\n",
4502 hWaveIn, lpWaveInHdr, uSize);
4503 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4504 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4505 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4507 lpWaveInHdr->lpNext = NULL;
4508 return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance,
4509 (DWORD)lpWaveInHdr, uSize);
4512 /**************************************************************************
4513 * waveInUnprepareHeader [MMSYSTEM.507]
4515 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn,
4516 WAVEHDR* lpWaveInHdr, UINT16 uSize)
4518 LPWAVEOPENDESC lpDesc;
4520 TRACE("(%04X, %p, %u);\n",
4521 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;
4526 return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance,
4527 (DWORD)lpWaveInHdr, uSize);
4530 /**************************************************************************
4531 * waveInAddBuffer [WINMM.144]
4533 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4534 WAVEHDR* lpWaveInHdr, UINT uSize)
4536 LPWAVEOPENDESC lpDesc;
4538 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4540 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4541 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4542 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4544 lpWaveInHdr->lpNext = NULL;
4545 lpWaveInHdr->dwBytesRecorded = 0;
4547 return widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
4548 (DWORD)lpWaveInHdr, uSize);
4552 /**************************************************************************
4553 * waveInAddBuffer [MMSYSTEM.508]
4555 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn,
4556 WAVEHDR* lpWaveInHdr, UINT16 uSize)
4558 LPWAVEOPENDESC lpDesc;
4559 UINT16 ret;
4561 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4563 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4564 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4565 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4566 lpWaveInHdr->lpNext = NULL;
4567 lpWaveInHdr->dwBytesRecorded = 0;
4569 ret = widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
4570 (DWORD)lpWaveInHdr, uSize);
4571 return ret;
4574 /**************************************************************************
4575 * waveInStart [WINMM.157]
4577 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4579 return waveInStart16(hWaveIn);
4582 /**************************************************************************
4583 * waveInStart [MMSYSTEM.509]
4585 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn)
4587 LPWAVEOPENDESC lpDesc;
4589 TRACE("(%04X)\n", hWaveIn);
4590 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4591 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4592 return widMessage(lpDesc->uDeviceID, WIDM_START, lpDesc->dwInstance, 0, 0);
4595 /**************************************************************************
4596 * waveInStop [WINMM.158]
4598 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4600 return waveInStop16(hWaveIn);
4603 /**************************************************************************
4604 * waveInStop [MMSYSTEM.510]
4606 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn)
4608 LPWAVEOPENDESC lpDesc;
4610 TRACE("(%04X)\n", hWaveIn);
4611 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4612 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4613 return widMessage(lpDesc->uDeviceID, WIDM_STOP, lpDesc->dwInstance, 0L, 0L);
4616 /**************************************************************************
4617 * waveInReset [WINMM.156]
4619 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4621 return waveInReset16(hWaveIn);
4624 /**************************************************************************
4625 * waveInReset [MMSYSTEM.511]
4627 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn)
4629 LPWAVEOPENDESC lpDesc;
4631 TRACE("(%04X)\n", hWaveIn);
4632 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4633 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4634 return widMessage(lpDesc->uDeviceID, WIDM_RESET, lpDesc->dwInstance, 0, 0);
4637 /**************************************************************************
4638 * waveInGetPosition [WINMM.152]
4640 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4641 UINT uSize)
4643 MMTIME16 mmt16;
4644 UINT ret;
4646 mmt16.wType = lpTime->wType;
4647 ret = waveInGetPosition16(hWaveIn, &mmt16, uSize);
4649 MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
4650 return ret;
4653 /**************************************************************************
4654 * waveInGetPosition [MMSYSTEM.512]
4656 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4657 UINT16 uSize)
4659 LPWAVEOPENDESC lpDesc;
4661 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4662 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4663 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4664 return widMessage(lpDesc->uDeviceID, WIDM_GETPOS, lpDesc->dwInstance,
4665 (DWORD)lpTime, (DWORD)uSize);
4668 /**************************************************************************
4669 * waveInGetID [WINMM.150]
4671 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4673 LPWAVEOPENDESC lpDesc;
4675 TRACE("waveInGetID\n");
4676 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4677 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4678 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4679 *lpuDeviceID = lpDesc->uDeviceID;
4680 return 0;
4683 /**************************************************************************
4684 * waveInGetID [MMSYSTEM.513]
4686 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4688 LPWAVEOPENDESC lpDesc;
4690 TRACE("waveInGetID\n");
4691 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4692 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4693 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4694 *lpuDeviceID = lpDesc->uDeviceID;
4695 return 0;
4698 /**************************************************************************
4699 * waveInMessage [WINMM.153]
4701 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4702 DWORD dwParam1, DWORD dwParam2)
4704 LPWAVEOPENDESC lpDesc;
4706 FIXME("(%04X, %04X, %08lX, %08lX)\n",
4707 hWaveIn, uMessage, dwParam1, dwParam2);
4708 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4709 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4710 switch (uMessage) {
4711 case WIDM_OPEN:
4712 FIXME("cannot handle WIDM_OPEN, please report.\n");
4713 break;
4714 case WIDM_GETNUMDEVS:
4715 case WIDM_GETPOS:
4716 case WIDM_CLOSE:
4717 case WIDM_STOP:
4718 case WIDM_RESET:
4719 case WIDM_START:
4720 case WIDM_PREPARE:
4721 case WIDM_UNPREPARE:
4722 case WIDM_ADDBUFFER:
4723 case WIDM_PAUSE:
4724 /* no argument conversion needed */
4725 break;
4726 case WIDM_GETDEVCAPS:
4727 /*FIXME: ANSI/UNICODE */
4728 return waveInGetDevCapsA(hWaveIn, (LPWAVEINCAPSA)dwParam1, dwParam2);
4729 default:
4730 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
4731 hWaveIn, uMessage, dwParam1, dwParam2);
4732 break;
4734 return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4737 /**************************************************************************
4738 * waveInMessage [MMSYSTEM.514]
4740 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4741 DWORD dwParam1, DWORD dwParam2)
4743 LPWAVEOPENDESC lpDesc;
4745 FIXME("(%04X, %04X, %08lX, %08lX)\n",
4746 hWaveIn, uMessage, dwParam1, dwParam2);
4747 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4748 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4749 switch (uMessage) {
4750 case WIDM_OPEN:
4751 FIXME("cannot handle WIDM_OPEN, please report.\n");
4752 break;
4753 case WIDM_GETNUMDEVS:
4754 case WIDM_CLOSE:
4755 case WIDM_STOP:
4756 case WIDM_RESET:
4757 case WIDM_START:
4758 case WIDM_PAUSE:
4759 /* no argument conversion needed */
4760 break;
4761 case WIDM_GETDEVCAPS:
4762 return waveInGetDevCaps16(hWaveIn, (LPWAVEINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4763 case WIDM_GETPOS:
4764 return waveInGetPosition16(hWaveIn, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4765 case WIDM_PREPARE:
4766 return waveInPrepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4767 case WIDM_UNPREPARE:
4768 return waveInUnprepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4769 case WIDM_ADDBUFFER:
4770 return waveInAddBuffer16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4771 default:
4772 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
4773 hWaveIn, uMessage, dwParam1, dwParam2);
4774 break;
4776 return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4779 /**************************************************************************
4780 * DrvOpen [MMSYSTEM.1100]
4782 HDRVR16 WINAPI DrvOpen(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam)
4784 TRACE("('%s','%s', %08lX);\n", lpDriverName, lpSectionName, lParam);
4786 return OpenDriver16(lpDriverName, lpSectionName, lParam);
4789 /**************************************************************************
4790 * DrvClose [MMSYSTEM.1101]
4792 LRESULT WINAPI DrvClose(HDRVR16 hDrv, LPARAM lParam1, LPARAM lParam2)
4794 TRACE("(%04X, %08lX, %08lX);\n", hDrv, lParam1, lParam2);
4796 return CloseDriver16(hDrv, lParam1, lParam2);
4799 /**************************************************************************
4800 * DrvSendMessage [MMSYSTEM.1102]
4802 LRESULT WINAPI DrvSendMessage(HDRVR16 hDrv, WORD msg, LPARAM lParam1,
4803 LPARAM lParam2)
4805 return SendDriverMessage(hDrv, msg, lParam1, lParam2);
4808 /**************************************************************************
4809 * DrvGetModuleHandle [MMSYSTEM.1103]
4811 HANDLE16 WINAPI DrvGetModuleHandle16(HDRVR16 hDrv)
4813 return GetDriverModuleHandle16(hDrv);
4816 /**************************************************************************
4817 * DrvDefDriverProc [MMSYSTEM.1104]
4819 LRESULT WINAPI DrvDefDriverProc(DWORD dwDriverID, HDRVR16 hDrv, WORD wMsg,
4820 DWORD dwParam1, DWORD dwParam2)
4822 /* FIXME : any mapping from 32 to 16 bit structure ? */
4823 return DefDriverProc16(dwDriverID, hDrv, wMsg, dwParam1, dwParam2);
4826 /**************************************************************************
4827 * DefDriverProc [WINMM.5]
4829 LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR hDrv,
4830 UINT Msg, LPARAM lParam1, LPARAM lParam2)
4832 switch (Msg) {
4833 case DRV_LOAD:
4834 case DRV_FREE:
4835 case DRV_ENABLE:
4836 case DRV_DISABLE:
4837 return 1;
4838 case DRV_INSTALL:
4839 case DRV_REMOVE:
4840 return DRV_SUCCESS;
4841 default:
4842 return 0;
4846 /*#define USE_MM_TSK_WINE*/
4848 /**************************************************************************
4849 * mmTaskCreate [MMSYSTEM.900]
4851 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4852 * called upon creation with dwPmt as parameter.
4854 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4856 DWORD showCmd = 0x40002;
4857 LPSTR cmdline;
4858 WORD sel1, sel2;
4859 LOADPARAMS16* lp;
4860 HINSTANCE16 ret;
4861 HINSTANCE16 handle;
4863 TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
4864 /* This to work requires NE modules to be started with a binary command line
4865 * which is not currently the case. A patch exists but has never been committed.
4866 * A workaround would be to integrate code for mmtask.tsk into Wine, but
4867 * this requires tremendous work (starting with patching tools/build to
4868 * create NE executables (and not only DLLs) for builtins modules.
4869 * EP 99/04/25
4871 FIXME("This is currently broken. It will fail\n");
4873 cmdline = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 0x0d);
4874 cmdline[0] = 0x0d;
4875 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
4876 *(LPDWORD)(cmdline + 5) = dwPmt;
4877 *(LPDWORD)(cmdline + 9) = 0;
4879 sel1 = SELECTOR_AllocBlock(cmdline, 0x0d, SEGMENT_DATA, FALSE, FALSE);
4880 sel2 = SELECTOR_AllocBlock(&showCmd, sizeof(showCmd),
4881 SEGMENT_DATA, FALSE, FALSE);
4883 lp = (LOADPARAMS16*)HeapAlloc(GetProcessHeap(), 0, sizeof(LOADPARAMS16));
4884 lp->hEnvironment = 0;
4885 lp->cmdLine = PTR_SEG_OFF_TO_SEGPTR(sel1, 0);
4886 lp->showCmd = PTR_SEG_OFF_TO_SEGPTR(sel2, 0);
4887 lp->reserved = 0;
4889 #ifndef USE_MM_TSK_WINE
4890 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", lp);
4891 #else
4892 handle = LoadModule16("mmtask.tsk", lp);
4893 #endif
4894 if (handle < 32) {
4895 ret = (handle) ? 1 : 2;
4896 handle = 0;
4897 } else {
4898 ret = 0;
4900 if (lphMmTask)
4901 *lphMmTask = handle;
4903 UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel2, 0));
4904 UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel1, 0));
4906 HeapFree(GetProcessHeap(), 0, lp);
4907 HeapFree(GetProcessHeap(), 0, cmdline);
4909 TRACE("=> 0x%04x/%d\n", handle, ret);
4910 return ret;
4913 #ifdef USE_MM_TSK_WINE
4914 /* C equivalent to mmtask.tsk binary content */
4915 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
4917 int len = cmdLine[0x80];
4919 if (len/2 == 6) {
4920 void (*fpProc)(DWORD) = (void (*)(DWORD))PTR_SEG_TO_LIN(*((DWORD*)(cmdLine + 1)));
4921 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
4923 #if 0
4924 InitTask16(); /* fixme: pmts / from context ? */
4925 InitApp(di);
4926 #endif
4927 if (SetMessageQueue16(0x40)) {
4928 WaitEvent16(0);
4929 if (HIWORD(fpProc)) {
4930 OldYield16();
4931 /* EPP StackEnter16(); */
4932 (fpProc)(dwPmt);
4936 OldYield16();
4937 OldYield16();
4938 OldYield16();
4939 ExitProcess(0);
4941 #endif
4943 /**************************************************************************
4944 * mmTaskBlock [MMSYSTEM.902]
4946 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
4948 MSG msg;
4950 do {
4951 GetMessageA(&msg, 0, 0, 0);
4952 if (msg.hwnd) {
4953 TranslateMessage(&msg);
4954 DispatchMessageA(&msg);
4956 } while (msg.message < 0x3A0);
4959 /**************************************************************************
4960 * mmTaskSignal [MMSYSTEM.903]
4962 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
4964 TRACE("(%04x);\n", ht);
4965 return Callout.PostAppMessage16(ht, WM_USER, 0, 0);
4968 /**************************************************************************
4969 * mmTaskYield16 [MMSYSTEM.905]
4971 void WINAPI mmTaskYield16(void)
4973 MSG msg;
4975 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
4976 Yield16();
4980 DWORD WINAPI GetProcessFlags(DWORD);
4982 /**************************************************************************
4983 * mmThreadCreate [MMSYSTEM.1120]
4985 * undocumented
4986 * Creates a MM thread, calling fpThreadAddr(dwPmt).
4987 * dwFlags:
4988 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
4989 * bit.1 set means to open a VxD for this thread (unsupported)
4991 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
4993 HANDLE16 hndl;
4994 LRESULT ret;
4996 TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
4998 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
5000 if (hndl == 0) {
5001 ret = 2;
5002 } else {
5003 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5005 #if 0
5006 /* force mmtask routines even if mmthread is required */
5007 /* this will work only if the patch about binary cmd line and NE tasks
5008 * is committed
5010 dwFlags |= 1;
5011 #endif
5013 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
5014 lpMMThd->dwCounter = 0;
5015 lpMMThd->hThread = 0;
5016 lpMMThd->dwThreadID = 0;
5017 lpMMThd->fpThread = fpThreadAddr;
5018 lpMMThd->dwThreadPmt = dwPmt;
5019 lpMMThd->dwSignalCount = 0;
5020 lpMMThd->hEvent = 0;
5021 lpMMThd->hVxD = 0;
5022 lpMMThd->dwStatus = 0;
5023 lpMMThd->dwFlags = dwFlags;
5024 lpMMThd->hTask = 0;
5026 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
5027 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
5029 TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
5030 if (lpMMThd->dwFlags & 2) {
5031 /* as long as we don't support MM VxD in wine, we don't need
5032 * to care about this flag
5034 /* FIXME("Don't know how to properly open VxD handles\n"); */
5035 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
5038 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
5039 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
5040 if (lpMMThd->hThread == 0) {
5041 WARN("Couldn't create thread\n");
5042 /* clean-up(VxDhandle...); devicedirectio... */
5043 if (lpMMThd->hEvent != 0)
5044 CloseHandle(lpMMThd->hEvent);
5045 ret = 2;
5046 } else {
5047 TRACE("Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
5048 ret = 0;
5050 } else {
5051 /* get WINE_mmThreadEntryPoint()
5052 * 2047 is its ordinal in mmsystem.spec
5054 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (SEGPTR)2047);
5056 TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, PTR_SEG_TO_LIN(fp));
5058 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
5061 if (ret == 0) {
5062 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
5063 WARN("Couldn't resume thread\n");
5065 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
5066 UserYield16();
5071 if (ret != 0) {
5072 GlobalFree16(hndl);
5073 hndl = 0;
5076 if (lpHndl)
5077 *lpHndl = hndl;
5079 TRACE("ok => %ld\n", ret);
5080 return ret;
5083 /**************************************************************************
5084 * mmThreadSignal [MMSYSTEM.1121]
5086 void WINAPI mmThreadSignal16(HANDLE16 hndl)
5088 TRACE("(%04x)!\n", hndl);
5090 if (hndl) {
5091 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5093 lpMMThd->dwCounter++;
5094 if (lpMMThd->hThread != 0) {
5095 InterlockedIncrement(&lpMMThd->dwSignalCount);
5096 SetEvent(lpMMThd->hEvent);
5097 } else {
5098 mmTaskSignal16(lpMMThd->hTask);
5100 lpMMThd->dwCounter--;
5104 /**************************************************************************
5105 * MMSYSTEM_ThreadBlock [internal]
5107 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
5109 MSG msg;
5110 DWORD ret;
5112 if (lpMMThd->dwThreadID != GetCurrentThreadId())
5113 ERR("Not called by thread itself\n");
5115 for (;;) {
5116 ResetEvent(lpMMThd->hEvent);
5117 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
5118 break;
5119 InterlockedIncrement(&lpMMThd->dwSignalCount);
5121 TRACE("S1\n");
5123 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
5124 switch (ret) {
5125 case WAIT_OBJECT_0: /* Event */
5126 TRACE("S2.1\n");
5127 break;
5128 case WAIT_OBJECT_0 + 1: /* Msg */
5129 TRACE("S2.2\n");
5130 if (Callout.PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
5131 Callout.TranslateMessage(&msg);
5132 Callout.DispatchMessageA(&msg);
5134 break;
5135 default:
5136 WARN("S2.x unsupported ret val 0x%08lx\n", ret);
5138 TRACE("S3\n");
5142 /**************************************************************************
5143 * mmThreadBlock [MMSYSTEM.1122]
5145 void WINAPI mmThreadBlock16(HANDLE16 hndl)
5147 TRACE("(%04x)!\n", hndl);
5149 if (hndl) {
5150 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5152 if (lpMMThd->hThread != 0) {
5153 SYSLEVEL_ReleaseWin16Lock();
5154 MMSYSTEM_ThreadBlock(lpMMThd);
5155 SYSLEVEL_RestoreWin16Lock();
5156 } else {
5157 mmTaskBlock16(lpMMThd->hTask);
5160 TRACE("done\n");
5163 /**************************************************************************
5164 * mmThreadIsCurrent [MMSYSTEM.1123]
5166 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
5168 BOOL16 ret = FALSE;
5170 TRACE("(%04x)!\n", hndl);
5172 if (hndl && mmThreadIsValid16(hndl)) {
5173 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5174 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
5175 #if 1 /* EPP */
5176 /* FIXME: just a test */
5177 SYSLEVEL_ReleaseWin16Lock();
5178 SYSLEVEL_RestoreWin16Lock();
5179 #endif
5181 TRACE("=> %d\n", ret);
5182 return ret;
5185 /**************************************************************************
5186 * mmThreadIsValid [MMSYSTEM.1124]
5188 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
5190 BOOL16 ret = FALSE;
5192 TRACE("(%04x)!\n", hndl);
5194 if (hndl) {
5195 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5197 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
5198 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
5199 IsTask16(lpMMThd->hTask)) {
5200 lpMMThd->dwCounter++;
5201 if (lpMMThd->hThread != 0) {
5202 DWORD dwThreadRet;
5203 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
5204 dwThreadRet == STATUS_PENDING) {
5205 ret = TRUE;
5207 } else {
5208 ret = TRUE;
5210 lpMMThd->dwCounter--;
5213 TRACE("=> %d\n", ret);
5214 return ret;
5217 /**************************************************************************
5218 * mmThreadGetTask [MMSYSTEM.1125]
5220 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5222 HANDLE16 ret = 0;
5224 TRACE("(%04x)\n", hndl);
5226 if (mmThreadIsValid16(hndl)) {
5227 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5228 ret = lpMMThd->hTask;
5230 return ret;
5233 /**************************************************************************
5234 * mmThreadGetTask [internal]
5236 void WINAPI WINE_mmThreadEntryPoint(DWORD _pmt)
5238 HANDLE16 hndl = (HANDLE16)_pmt;
5239 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5240 CRITICAL_SECTION* cs;
5242 TRACE("(%04x %p)\n", hndl, lpMMThd);
5244 GetpWin16Lock(&cs);
5246 TRACE("lc=%ld rc=%ld ot=%08lx\n", cs->LockCount, cs->RecursionCount, (DWORD)cs->OwningThread);
5248 lpMMThd->hTask = LOWORD(GetCurrentTask());
5249 TRACE("[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5250 lpMMThd->dwStatus = 0x10;
5251 MMSYSTEM_ThreadBlock(lpMMThd);
5252 TRACE("[20-%08x]\n", lpMMThd->hThread);
5253 lpMMThd->dwStatus = 0x20;
5254 if (lpMMThd->fpThread) {
5255 #if 0
5256 extern DWORD CALLBACK CallTo16_long_l_x(FARPROC16, DWORD);
5257 TRACE("Calling %08lx(%08lx)\n", (DWORD)lpMMThd->fpThread, lpMMThd->dwThreadPmt);$
5258 CallTo16_long_l_x(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5259 #else
5260 Callbacks->CallWOWCallbackProc(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5261 #endif
5263 lpMMThd->dwStatus = 0x30;
5264 TRACE("[30-%08x]\n", lpMMThd->hThread);
5265 while (lpMMThd->dwCounter) {
5266 Sleep(1);
5267 /* Yield16();*/
5269 TRACE("[XX-%08x]\n", lpMMThd->hThread);
5270 /* paranoia */
5271 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5272 /* close lpMMThread->hVxD directio */
5273 if (lpMMThd->hEvent)
5274 CloseHandle(lpMMThd->hEvent);
5275 GlobalFree16(hndl);
5276 TRACE("lc=%ld rc=%ld ot=%08lx\n", cs->LockCount, cs->RecursionCount, (DWORD)cs->OwningThread);
5277 TRACE("done\n");
5281 typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPSTR, LPSTR, LPSTR);
5283 /**************************************************************************
5284 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5286 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, char* lpStrDevice,
5287 char* lpStrTab, char* lpStrTitle)
5289 HANDLE hndl;
5290 BOOL16 ret = FALSE;
5292 TRACE("(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5294 hndl = LoadLibraryA("MMSYS.CPL");
5295 if (hndl != 0) {
5296 MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5297 if (fp != NULL) {
5298 /* FIXME: wine hangs and/or seg faults in this call,
5299 * after the window is correctly displayed
5301 TRACE("Ready to go ThreadID=%08lx\n", GetCurrentThreadId());
5302 SYSLEVEL_ReleaseWin16Lock();
5303 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5304 SYSLEVEL_RestoreWin16Lock();
5306 FreeLibrary(hndl);
5309 return ret;
5312 /**************************************************************************
5313 * StackEnter & StackLeave [MMSYSTEM.32][MMSYSTEM.33]
5315 void WINAPI StackEnterLeave16(void)
5317 #ifdef __i386__
5318 /* mmsystem.dll from Win 95 does only this: so does Wine */
5319 __asm__("stc");
5320 #endif