1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1993 Martin Ayotte
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
24 #include <sys/ioctl.h>
28 #include "wine/winbase16.h"
32 #include "multimedia.h"
35 #include "selectors.h"
39 DECLARE_DEBUG_CHANNEL(mmaux)
40 DECLARE_DEBUG_CHANNEL(mmsys)
42 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
43 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
44 LONG WINAPI DrvDefDriverProc(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg,
45 DWORD dwParam1, DWORD dwParam2);
47 /**************************************************************************
48 * MMSYSTEM_WEP [MMSYSTEM.1]
50 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
51 WORD cbHeapSize, LPSTR lpCmdLine)
53 FIXME(mmsys, "STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
57 static void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
59 mmt16->wType = mmt32->wType;
60 /* layout of rest is the same for 32/16,
61 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
63 memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
66 static void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
68 mmt32->wType = mmt16->wType;
69 /* layout of rest is the same for 32/16,
70 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
72 memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
75 static HANDLE PlaySound_hThread = 0;
76 static HANDLE PlaySound_hPlayEvent = 0;
77 static HANDLE PlaySound_hReadyEvent = 0;
78 static HANDLE PlaySound_hMiddleEvent = 0;
79 static BOOL PlaySound_Result = FALSE;
80 static int PlaySound_Stop = FALSE;
81 static int PlaySound_Playing = FALSE;
83 static LPCSTR PlaySound_pszSound = NULL;
84 static HMODULE PlaySound_hmod = 0;
85 static DWORD PlaySound_fdwSound = 0;
86 static int PlaySound_Loop = FALSE;
87 static int PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
88 2 - PlaySound order */
90 static HMMIO16 get_mmioFromFile(LPCSTR lpszName)
92 return mmioOpen16((LPSTR)lpszName, NULL,
93 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
96 static HMMIO16 get_mmioFromProfile(UINT uFlags, LPCSTR lpszName)
102 TRACE(mmsys, "searching in SystemSound List !\n");
103 GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
104 if (strlen(str) == 0) {
105 if (uFlags & SND_NODEFAULT) return 0;
106 GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
107 if (strlen(str) == 0) return 0;
109 if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
110 hmmio = get_mmioFromFile(str);
112 WARN(mmsys, "can't find SystemSound='%s' !\n", str);
118 static BOOL16 WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
124 TRACE(mmsys, "SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
125 if (lpszSoundName == NULL) {
126 TRACE(mmsys, "Stop !\n");
129 if (uFlags & SND_MEMORY) {
131 memset(&mminfo, 0, sizeof(mminfo));
132 mminfo.fccIOProc = FOURCC_MEM;
133 mminfo.pchBuffer = (LPSTR)lpszSoundName;
134 mminfo.cchBuffer = -1;
135 TRACE(mmsys, "Memory sound %p\n", lpszSoundName);
136 hmmio = mmioOpen16(NULL, &mminfo, MMIO_READ);
139 if (uFlags & SND_ALIAS)
140 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
143 if (uFlags & SND_FILENAME)
144 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
146 if (PlaySound_SearchMode == 1) {
147 PlaySound_SearchMode = 0;
148 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0)
149 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
153 if (PlaySound_SearchMode == 2) {
154 PlaySound_SearchMode = 0;
155 if ((hmmio=get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0)
156 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0)
157 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) return FALSE;
161 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0) == 0)
163 TRACE(mmsys, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
164 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
167 if ((ckMainRIFF.ckid == FOURCC_RIFF) &&
168 (ckMainRIFF.fccType == mmioFOURCC('W', 'A', 'V', 'E'))) {
171 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
173 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
174 PCMWAVEFORMAT pcmWaveFormat;
176 TRACE(mmsys, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
177 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
179 if (mmioRead(hmmio, (HPSTR)&pcmWaveFormat,
180 (long) sizeof(PCMWAVEFORMAT)) == (long) sizeof(PCMWAVEFORMAT)) {
181 TRACE(mmsys, "wFormatTag=%04X !\n", pcmWaveFormat.wf.wFormatTag);
182 TRACE(mmsys, "nChannels=%d \n", pcmWaveFormat.wf.nChannels);
183 TRACE(mmsys, "nSamplesPerSec=%ld\n", pcmWaveFormat.wf.nSamplesPerSec);
184 TRACE(mmsys, "nAvgBytesPerSec=%ld\n", pcmWaveFormat.wf.nAvgBytesPerSec);
185 TRACE(mmsys, "nBlockAlign=%d \n", pcmWaveFormat.wf.nBlockAlign);
186 TRACE(mmsys, "wBitsPerSample=%u !\n", pcmWaveFormat.wBitsPerSample);
188 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
189 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
190 WAVEOPENDESC waveDesc;
193 TRACE(mmsys, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
194 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
196 pcmWaveFormat.wf.nAvgBytesPerSec = pcmWaveFormat.wf.nSamplesPerSec *
197 pcmWaveFormat.wf.nBlockAlign;
199 waveDesc.lpFormat = (LPWAVEFORMAT)&pcmWaveFormat;
201 dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
202 if (dwRet == MMSYSERR_NOERROR) {
205 INT count, bufsize, left = mmckInfo.cksize;
208 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
209 waveHdr.lpData = (LPSTR)GlobalLock16(hData);
210 waveHdr.dwBufferLength = bufsize;
212 waveHdr.dwFlags = 0L;
213 waveHdr.dwLoops = 0L;
215 dwRet = wodMessage(0, WODM_PREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
216 if (dwRet == MMSYSERR_NOERROR) {
218 if (PlaySound_Stop) {
219 PlaySound_Stop = FALSE;
220 PlaySound_Loop = FALSE;
223 if (bufsize > left) bufsize = left;
224 count = mmioRead(hmmio, waveHdr.lpData,bufsize);
225 if (count < 1) break;
227 waveHdr.dwBufferLength = count;
229 waveHdr.reserved = (DWORD)&waveHdr;
230 /* waveHdr.dwBytesRecorded = count; */
231 /* FIXME: doesn't expect async ops */
232 wodMessage(0, WODM_WRITE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
234 wodMessage(0, WODM_UNPREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
235 wodMessage(0, WODM_CLOSE, 0, 0L, 0L);
239 WARN(mmsys, "can't prepare WaveOut device !\n");
241 GlobalUnlock16(hData);
248 } while (PlaySound_Loop);
250 if (hmmio != 0) mmioClose(hmmio, 0);
254 static DWORD WINAPI PlaySound_Thread(LPVOID arg)
259 PlaySound_Playing = FALSE;
260 SetEvent(PlaySound_hReadyEvent);
261 res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
262 ResetEvent(PlaySound_hReadyEvent);
263 SetEvent(PlaySound_hMiddleEvent);
264 if (res == WAIT_FAILED) ExitThread(2);
265 if (res != WAIT_OBJECT_0) continue;
266 PlaySound_Playing = TRUE;
268 if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
273 if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
274 PlaySound_Result = FALSE;
277 if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
278 PlaySound_Result = FALSE;
281 if ((ptr = LockResource(hGLOB)) == NULL) {
283 PlaySound_Result = FALSE;
286 PlaySound_Result = proc_PlaySound(ptr,
287 ((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
291 PlaySound_Result=proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
295 /**************************************************************************
296 * PlaySoundA [WINMM.1]
298 BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
300 static LPSTR StrDup = NULL;
302 TRACE(mmsys, "pszSound='%p' hmod=%04X fdwSound=%08lX\n",
303 pszSound, hmod, fdwSound);
305 if (PlaySound_hThread == 0) { /* This is the first time they called us */
307 if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
309 if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
311 if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
313 if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0)
317 /* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */
318 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing)
321 /* Trying to stop if playing */
322 if (PlaySound_Playing) PlaySound_Stop = TRUE;
324 /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
325 if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
328 if (!pszSound || (fdwSound & SND_PURGE))
329 return FALSE; /* We stoped playing so leaving */
331 if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
332 if (!(fdwSound & SND_ASYNC)) {
333 if (fdwSound & SND_LOOP)
335 PlaySound_pszSound = pszSound;
336 PlaySound_hmod = hmod;
337 PlaySound_fdwSound = fdwSound;
338 PlaySound_Result = FALSE;
339 SetEvent(PlaySound_hPlayEvent);
340 if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0)
342 if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0)
344 return PlaySound_Result;
346 PlaySound_hmod = hmod;
347 PlaySound_fdwSound = fdwSound;
348 PlaySound_Result = FALSE;
350 HeapFree(GetProcessHeap(), 0, StrDup);
353 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
354 !((DWORD)pszSound >> 16)) || !pszSound)) {
355 StrDup = HEAP_strdupA(GetProcessHeap(), 0,pszSound);
356 PlaySound_pszSound = StrDup;
357 } else PlaySound_pszSound = pszSound;
358 PlaySound_Loop = fdwSound & SND_LOOP;
359 SetEvent(PlaySound_hPlayEvent);
360 ResetEvent(PlaySound_hMiddleEvent);
366 /**************************************************************************
367 * PlaySoundW [WINMM.18]
369 BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
374 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
375 !((DWORD)pszSound >> 16)) || !pszSound)) {
376 pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
377 bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
378 HeapFree(GetProcessHeap(), 0,pszSoundA);
380 bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
385 /**************************************************************************
386 * sndPlaySoundA [MMSYSTEM.2][WINMM135]
388 BOOL16 WINAPI sndPlaySoundA(LPCSTR lpszSoundName, UINT16 uFlags)
390 PlaySound_SearchMode = 1;
391 return PlaySoundA(lpszSoundName, 0, uFlags);
394 /**************************************************************************
395 * sndPlaySoundW [WINMM.136]
397 BOOL16 WINAPI sndPlaySoundW(LPCWSTR lpszSoundName, UINT16 uFlags)
399 PlaySound_SearchMode = 1;
400 return PlaySoundW(lpszSoundName, 0, uFlags);
403 /**************************************************************************
404 * mmsystemGetVersion [WINMM.134]
406 UINT WINAPI mmsystemGetVersion()
408 return mmsystemGetVersion16();
411 /**************************************************************************
412 * mmsystemGetVersion [MMSYSTEM.5]
413 * return value borrowed from Win95 winmm.dll ;)
415 UINT16 WINAPI mmsystemGetVersion16()
417 TRACE(mmsys, "3.10 (Win95?)\n");
421 /**************************************************************************
422 * DriverProc [MMSYSTEM.6]
424 LRESULT WINAPI DriverProc16(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg,
425 DWORD dwParam1, DWORD dwParam2)
427 return DrvDefDriverProc(dwDevID, hDrv, wMsg, dwParam1, dwParam2);
430 /**************************************************************************
431 * DriverCallback [MMSYSTEM.31]
433 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HANDLE16 hDev,
434 WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
436 TRACE(mmsys, "(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
437 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
439 switch (uFlags & DCB_TYPEMASK) {
441 TRACE(mmsys, "Null !\n");
444 TRACE(mmsys, "Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
445 if (!IsWindow(dwCallBack) || USER_HEAP_LIN_ADDR(hDev) == NULL)
447 Callout.PostMessageA((HWND16)dwCallBack, wMsg, hDev, dwParam1);
449 case DCB_TASK: /* aka DCB_THREAD */
450 TRACE(mmsys, "Task(%04lx) !\n", dwCallBack);
451 Callout.PostThreadMessageA(dwCallBack, wMsg, hDev, dwParam1);
454 TRACE(mmsys, "Function (16bit) !\n");
455 Callbacks->CallDriverCallback((FARPROC16)dwCallBack, hDev, wMsg, dwUser,
458 case DCB_FUNC32: /* This is a Wine only value - AKAIF not used yet by MS */
459 TRACE(mmsys, "Function (32bit) !\n");
460 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
463 TRACE(mmsys, "Event(%08lx) !\n", dwCallBack);
464 SetEvent((HANDLE)dwCallBack);
466 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
467 /* this is an undocumented DCB_ value used for mmThreads
468 * loword of dwCallBack contains the handle of the lpMMThd block
469 * which dwSignalCount has to be incremented
472 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(LOWORD(dwCallBack), 0);
474 TRACE(mmsys, "mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
475 /* same as mmThreadSignal16 */
476 InterlockedIncrement(&lpMMThd->dwSignalCount);
477 SetEvent(lpMMThd->hEvent);
478 /* some other stuff on lpMMThd->hVxD */
483 /* this is an undocumented DCB_ value for... I don't know */
487 WARN(mmsys, "Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
490 TRACE(mmsys, "Done\n");
494 /**************************************************************************
495 * Mixer devices. New to Win95
498 /**************************************************************************
499 * find out the real mixer ID depending on hmix (depends on dwFlags)
500 * FIXME: also fix dwInstance passing to mixMessage
502 static UINT MIXER_GetDevID(HMIXEROBJ hmix, DWORD dwFlags)
504 /* FIXME: Check dwFlags for MIXER_OBJSECTF_xxxx entries and modify hmix
505 * accordingly. For now we always use mixerdevice 0.
510 /**************************************************************************
511 * mixerGetNumDevs [WINMM.108]
513 UINT WINAPI mixerGetNumDevs(void)
515 UINT16 count = mixMessage(0, MXDM_GETNUMDEVS, 0L, 0L, 0L);
517 TRACE(mmaux,"mixerGetNumDevs returns %d\n", count);
521 /**************************************************************************
522 * mixerGetNumDevs [MMSYSTEM.800]
524 UINT16 WINAPI mixerGetNumDevs16()
526 return mixerGetNumDevs();
529 /**************************************************************************
530 * mixerGetDevCapsA [WINMM.101]
532 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
534 return mixMessage(devid, MXDM_GETDEVCAPS, 0L, (DWORD)mixcaps, (DWORD)size);
537 /**************************************************************************
538 * mixerGetDevCapsW [WINMM.102]
540 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
543 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
545 if (ret == MMSYSERR_NOERROR) {
546 mixcaps->wMid = micA.wMid;
547 mixcaps->wPid = micA.wPid;
548 mixcaps->vDriverVersion = micA.vDriverVersion;
549 lstrcpyAtoW(mixcaps->szPname, micA.szPname);
550 mixcaps->fdwSupport = micA.fdwSupport;
551 mixcaps->cDestinations = micA.cDestinations;
556 /**************************************************************************
557 * mixerGetDevCaps [MMSYSTEM.801]
559 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps, UINT16 size)
562 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
564 if (ret == MMSYSERR_NOERROR) {
565 mixcaps->wMid = micA.wMid;
566 mixcaps->wPid = micA.wPid;
567 mixcaps->vDriverVersion = micA.vDriverVersion;
568 strcpy(PTR_SEG_TO_LIN(mixcaps->szPname), micA.szPname);
569 mixcaps->fdwSupport = micA.fdwSupport;
570 mixcaps->cDestinations = micA.cDestinations;
575 /**************************************************************************
576 * mixerOpen [WINMM.110]
578 UINT WINAPI mixerOpen(LPHMIXER lphmix, UINT uDeviceID, DWORD dwCallback,
579 DWORD dwInstance, DWORD fdwOpen)
584 FIXME(mmsys,"(%p, %d, %08lx, %08lx, %08lx): semi stub?\n",
585 lphmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
586 ret = mixerOpen16(&hmix16, uDeviceID, dwCallback, dwInstance,fdwOpen);
587 if (lphmix) *lphmix = hmix16;
591 /**************************************************************************
592 * mixerOpen [MMSYSTEM.803]
594 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
595 DWORD dwInstance, DWORD fdwOpen)
598 LPMIXEROPENDESC lpmod;
599 BOOL mapperflag = (uDeviceID == 0);
602 TRACE(mmsys,"(%p, %d, %08lx, %08lx, %08lx)\n",
603 lphmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
604 hmix = USER_HEAP_ALLOC(sizeof(MIXEROPENDESC));
605 if (lphmix) *lphmix = hmix;
606 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
608 lpmod->dwCallback = dwCallback;
609 lpmod->dwInstance = dwInstance;
610 if (uDeviceID >= MAXMIXERDRIVERS)
612 while (uDeviceID < MAXMIXERDRIVERS) {
613 dwRet = mixMessage(uDeviceID, MXDM_OPEN, dwInstance, (DWORD)lpmod, fdwOpen);
614 if (dwRet == MMSYSERR_NOERROR) break;
615 if (!mapperflag) break;
618 lpmod->uDeviceID = uDeviceID;
620 if (dwRet != MMSYSERR_NOERROR) {
621 USER_HEAP_FREE(hmix);
622 if (lphmix) *lphmix = 0;
628 /**************************************************************************
629 * mixerClose [WINMM.98]
631 UINT WINAPI mixerClose(HMIXER hmix)
633 LPMIXEROPENDESC lpmod;
636 FIXME(mmsys,"(%04x): semi-stub?\n", hmix);
638 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
639 if (lpmod == NULL) return MMSYSERR_INVALHANDLE;
640 dwRet = mixMessage(lpmod->uDeviceID, MXDM_CLOSE, lpmod->dwInstance, 0L, 0L);
641 USER_HEAP_FREE(hmix);
645 /**************************************************************************
646 * mixerClose [MMSYSTEM.803]
648 UINT16 WINAPI mixerClose16(HMIXER16 hmix)
650 return mixerClose(hmix);
653 /**************************************************************************
654 * mixerGetID [WINMM.103]
656 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
658 FIXME(mmsys,"(%04x %p %08lx): semi-stub\n", hmix, lpid, fdwID);
661 *lpid = MIXER_GetDevID(hmix, fdwID);
663 return MMSYSERR_NOERROR; /* FIXME: many error possibilities */
666 /**************************************************************************
669 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
672 UINT ret = mixerGetID(hmix, &xid, fdwID);
679 /**************************************************************************
680 * mixerGetControlDetailsA [WINMM.99]
682 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
684 FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
685 return MMSYSERR_NOTENABLED;
688 /**************************************************************************
689 * mixerGetControlDetailsW [WINMM.100]
691 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
693 FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
694 return MMSYSERR_NOTENABLED;
697 /**************************************************************************
698 * mixerGetControlDetails [MMSYSTEM.808]
700 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails)
702 FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
703 return MMSYSERR_NOTENABLED;
706 /**************************************************************************
707 * mixerGetLineControlsA [WINMM.104]
709 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlc, DWORD fdwControls)
713 FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmlc, fdwControls);
715 uDevID = MIXER_GetDevID(hmix, 0);
717 return mixMessage(uDevID, MXDM_GETLINECONTROLS, 0, (DWORD)lpmlc, fdwControls);
720 /**************************************************************************
721 * mixerGetLineControlsW [WINMM.105]
723 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlc, DWORD fdwControls)
725 FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmlc, fdwControls);
726 return MMSYSERR_NOTENABLED;
729 /**************************************************************************
730 * mixerGetLineControls [MMSYSTEM.807]
732 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix, LPMIXERLINECONTROLS16 lpmlc, DWORD fdwControls)
734 FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmlc, fdwControls);
735 return MMSYSERR_NOTENABLED;
738 /**************************************************************************
739 * mixerGetLineInfoA [WINMM.106]
741 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpml, DWORD fdwInfo)
745 TRACE(mmsys, "(%04x, %p, %08lx)\n", hmix, lpml, fdwInfo);
747 /* FIXME: I'm not sure of the flags */
748 devid = MIXER_GetDevID(hmix, fdwInfo);
749 return mixMessage(devid, MXDM_GETLINEINFO, 0, (DWORD)lpml, fdwInfo);
752 /**************************************************************************
753 * mixerGetLineInfoW [WINMM.107]
755 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpml, DWORD fdwInfo)
760 TRACE(mmsys,"(%04x, %p, %08lx)\n", hmix, lpml, fdwInfo);
762 if (lpml == NULL || lpml->cbStruct != sizeof(*lpml))
763 return MMSYSERR_INVALPARAM;
765 mlA.cbStruct = sizeof(mlA);
766 mlA.dwDestination = lpml->dwDestination;
767 mlA.dwSource = lpml->dwSource;
768 mlA.dwLineID = lpml->dwLineID;
769 mlA.dwUser = lpml->dwUser;
770 mlA.dwComponentType = lpml->dwComponentType;
771 mlA.cChannels = lpml->cChannels;
772 mlA.cConnections = lpml->cConnections;
773 mlA.cControls = lpml->cControls;
775 ret = mixerGetLineInfoA(hmix, &mlA, fdwInfo);
777 lpml->dwDestination = mlA.dwDestination;
778 lpml->dwSource = mlA.dwSource;
779 lpml->dwLineID = mlA.dwLineID;
780 lpml->fdwLine = mlA.fdwLine;
781 lpml->dwUser = mlA.dwUser;
782 lpml->dwComponentType = mlA.dwComponentType;
783 lpml->cChannels = mlA.cChannels;
784 lpml->cConnections = mlA.cConnections;
785 lpml->cControls = mlA.cControls;
786 lstrcpyAtoW(lpml->szShortName, mlA.szShortName);
787 lstrcpyAtoW(lpml->szName, mlA.szName);
788 lpml->Target.dwType = mlA.Target.dwType;
789 lpml->Target.dwDeviceID = mlA.Target.dwDeviceID;
790 lpml->Target.wMid = mlA.Target.wMid;
791 lpml->Target.wPid = mlA.Target.wPid;
792 lpml->Target.vDriverVersion = mlA.Target.vDriverVersion;
793 lstrcpyAtoW(lpml->Target.szPname, mlA.Target.szPname);
798 /**************************************************************************
799 * mixerGetLineInfo [MMSYSTEM.805]
801 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpml, DWORD fdwInfo)
806 TRACE(mmsys, "(%04x, %p, %08lx)\n", hmix, lpml, fdwInfo);
808 if (lpml == NULL || lpml->cbStruct != sizeof(*lpml))
809 return MMSYSERR_INVALPARAM;
811 mlA.cbStruct = sizeof(mlA);
812 mlA.dwDestination = lpml->dwDestination;
813 mlA.dwSource = lpml->dwSource;
814 mlA.dwLineID = lpml->dwLineID;
815 mlA.dwUser = lpml->dwUser;
816 mlA.dwComponentType = lpml->dwComponentType;
817 mlA.cChannels = lpml->cChannels;
818 mlA.cConnections = lpml->cConnections;
819 mlA.cControls = lpml->cControls;
821 ret = mixerGetLineInfoA(hmix, &mlA, fdwInfo);
823 lpml->dwDestination = mlA.dwDestination;
824 lpml->dwSource = mlA.dwSource;
825 lpml->dwLineID = mlA.dwLineID;
826 lpml->fdwLine = mlA.fdwLine;
827 lpml->dwUser = mlA.dwUser;
828 lpml->dwComponentType = mlA.dwComponentType;
829 lpml->cChannels = mlA.cChannels;
830 lpml->cConnections = mlA.cConnections;
831 lpml->cControls = mlA.cControls;
832 strcpy(PTR_SEG_TO_LIN(lpml->szShortName), mlA.szShortName);
833 strcpy(PTR_SEG_TO_LIN(lpml->szName), mlA.szName);
834 lpml->Target.dwType = mlA.Target.dwType;
835 lpml->Target.dwDeviceID = mlA.Target.dwDeviceID;
836 lpml->Target.wMid = mlA.Target.wMid;
837 lpml->Target.wPid = mlA.Target.wPid;
838 lpml->Target.vDriverVersion = mlA.Target.vDriverVersion;
839 strcpy(PTR_SEG_TO_LIN(lpml->Target.szPname), mlA.Target.szPname);
843 /**************************************************************************
844 * mixerSetControlDetails [WINMM.111]
846 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
848 FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
849 return MMSYSERR_NOTENABLED;
852 /**************************************************************************
853 * mixerSetControlDetails [MMSYSTEM.809]
855 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails)
857 FIXME(mmsys,"(%04x, %p, %08lx): stub!\n", hmix, lpmcd, fdwDetails);
858 return MMSYSERR_NOTENABLED;
861 /**************************************************************************
862 * mixerMessage [WINMM.109]
864 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
866 LPMIXEROPENDESC lpmod;
869 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
871 uDeviceID = lpmod->uDeviceID;
874 FIXME(mmsys,"(%04lx, %d, %08lx, %08lx): semi-stub?\n",
875 (DWORD)hmix, uMsg, dwParam1, dwParam2);
876 return mixMessage(uDeviceID, uMsg, 0L, dwParam1, dwParam2);
879 /**************************************************************************
880 * mixerMessage [MMSYSTEM.804]
882 UINT16 WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1, DWORD dwParam2)
884 LPMIXEROPENDESC lpmod;
887 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
888 uDeviceID = (lpmod) ? lpmod->uDeviceID : 0;
889 FIXME(mmsys,"(%04x, %d, %08lx, %08lx) - semi-stub?\n",
890 hmix, uMsg, dwParam1, dwParam2);
891 return mixMessage(uDeviceID, uMsg, 0L, dwParam1, dwParam2);
894 /**************************************************************************
895 * auxGetNumDevs [WINMM.22]
897 UINT WINAPI auxGetNumDevs()
899 return auxGetNumDevs16();
902 /**************************************************************************
903 * auxGetNumDevs [MMSYSTEM.350]
905 UINT16 WINAPI auxGetNumDevs16()
910 count = auxMessage(0, AUXDM_GETNUMDEVS, 0L, 0L, 0L);
911 TRACE(mmsys, "=> %u\n", count);
915 /**************************************************************************
916 * auxGetDevCaps [WINMM.20]
918 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
921 UINT ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
923 lpCaps->wMid = ac16.wMid;
924 lpCaps->wPid = ac16.wPid;
925 lpCaps->vDriverVersion = ac16.vDriverVersion;
926 lstrcpyAtoW(lpCaps->szPname, ac16.szPname);
927 lpCaps->wTechnology = ac16.wTechnology;
928 lpCaps->dwSupport = ac16.dwSupport;
932 /**************************************************************************
933 * auxGetDevCaps [WINMM.21]
935 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
938 UINT ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
940 lpCaps->wMid = ac16.wMid;
941 lpCaps->wPid = ac16.wPid;
942 lpCaps->vDriverVersion = ac16.vDriverVersion;
943 strcpy(lpCaps->szPname, ac16.szPname);
944 lpCaps->wTechnology = ac16.wTechnology;
945 lpCaps->dwSupport = ac16.dwSupport;
949 /**************************************************************************
950 * auxGetDevCaps [MMSYSTEM.351]
952 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
954 TRACE(mmsys, "(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
956 return auxMessage(uDeviceID, AUXDM_GETDEVCAPS,
957 0L, (DWORD)lpCaps, (DWORD)uSize);
960 /**************************************************************************
961 * auxGetVolume [WINM.23]
963 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
965 return auxGetVolume16(uDeviceID, lpdwVolume);
968 /**************************************************************************
969 * auxGetVolume [MMSYSTEM.352]
971 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
973 TRACE(mmsys, "(%04X, %p) !\n", uDeviceID, lpdwVolume);
975 return auxMessage(uDeviceID, AUXDM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
978 /**************************************************************************
979 * auxSetVolume [WINMM.25]
981 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
983 return auxSetVolume16(uDeviceID, dwVolume);
986 /**************************************************************************
987 * auxSetVolume [MMSYSTEM.353]
989 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
991 TRACE(mmsys, "(%04X, %08lX) !\n", uDeviceID, dwVolume);
993 return auxMessage(uDeviceID, AUXDM_SETVOLUME, 0L, dwVolume, 0L);
996 /**************************************************************************
997 * auxOutMessage [MMSYSTEM.354]
999 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1002 case AUXDM_GETNUMDEVS:
1003 case AUXDM_GETVOLUME:
1004 case AUXDM_SETVOLUME:
1005 /* no argument conversion needed */
1007 case AUXDM_GETDEVCAPS:
1008 return auxGetDevCapsA(uDeviceID, (LPAUXCAPSA)dw1, dw2);
1010 ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
1011 uDeviceID, uMessage, dw1, dw2);
1014 return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
1017 /**************************************************************************
1018 * auxOutMessage [MMSYSTEM.354]
1020 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1022 TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1025 case AUXDM_GETNUMDEVS:
1026 case AUXDM_SETVOLUME:
1027 /* no argument conversion needed */
1029 case AUXDM_GETVOLUME:
1030 return auxGetVolume16(uDeviceID, (LPDWORD)PTR_SEG_TO_LIN(dw1));
1031 case AUXDM_GETDEVCAPS:
1032 return auxGetDevCaps16(uDeviceID, (LPAUXCAPS16)PTR_SEG_TO_LIN(dw1), dw2);
1034 ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
1035 uDeviceID, uMessage, dw1, dw2);
1038 return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
1041 /**************************************************************************
1042 * mciGetErrorStringW [WINMM.46]
1044 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1046 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1047 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
1049 lstrcpyAtoW(lpstrBuffer, bufstr);
1050 HeapFree(GetProcessHeap(), 0, bufstr);
1054 /**************************************************************************
1055 * mciGetErrorStringA [WINMM.45]
1057 BOOL WINAPI mciGetErrorStringA(DWORD wError, LPSTR lpstrBuffer, UINT uLength)
1059 return mciGetErrorString16(wError, lpstrBuffer, uLength);
1062 /**************************************************************************
1063 * mciGetErrorString [MMSYSTEM.706]
1065 BOOL16 WINAPI mciGetErrorString16(DWORD dwError, LPSTR lpstrBuffer, UINT16 uLength)
1067 LPSTR msgptr = NULL;
1069 TRACE(mmsys, "(%08lX, %p, %d);\n", dwError, lpstrBuffer, uLength);
1071 if ((lpstrBuffer == NULL) || (uLength < 1))
1074 lpstrBuffer[0] = '\0';
1078 msgptr = "The specified command has been executed.";
1080 case MCIERR_INVALID_DEVICE_ID:
1081 msgptr = "Invalid MCI device ID. Use the ID returned when opening the MCI device.";
1083 case MCIERR_UNRECOGNIZED_KEYWORD:
1084 msgptr = "The driver cannot recognize the specified command parameter.";
1086 case MCIERR_UNRECOGNIZED_COMMAND:
1087 msgptr = "The driver cannot recognize the specified command.";
1089 case MCIERR_HARDWARE:
1090 msgptr = "There is a problem with your media device. Make sure it is working correctly or contact the device manufacturer.";
1092 case MCIERR_INVALID_DEVICE_NAME:
1093 msgptr = "The specified device is not open or is not recognized by MCI.";
1095 case MCIERR_OUT_OF_MEMORY:
1096 msgptr = "Not enough memory available for this task. \nQuit one or more applications to increase available memory, and then try again.";
1098 case MCIERR_DEVICE_OPEN:
1099 msgptr = "The device name is already being used as an alias by this application. Use a unique alias.";
1101 case MCIERR_CANNOT_LOAD_DRIVER:
1102 msgptr = "There is an undetectable problem in loading the specified device driver.";
1104 case MCIERR_MISSING_COMMAND_STRING:
1105 msgptr = "No command was specified.";
1107 case MCIERR_PARAM_OVERFLOW:
1108 msgptr = "The output string was to large to fit in the return buffer. Increase the size of the buffer.";
1110 case MCIERR_MISSING_STRING_ARGUMENT:
1111 msgptr = "The specified command requires a character-string parameter. Please provide one.";
1113 case MCIERR_BAD_INTEGER:
1114 msgptr = "The specified integer is invalid for this command.";
1116 case MCIERR_PARSER_INTERNAL:
1117 msgptr = "The device driver returned an invalid return type. Check with the device manufacturer about obtaining a new driver.";
1119 case MCIERR_DRIVER_INTERNAL:
1120 msgptr = "There is a problem with the device driver. Check with the device manufacturer about obtaining a new driver.";
1122 case MCIERR_MISSING_PARAMETER:
1123 msgptr = "The specified command requires a parameter. Please supply one.";
1125 case MCIERR_UNSUPPORTED_FUNCTION:
1126 msgptr = "The MCI device you are using does not support the specified command.";
1128 case MCIERR_FILE_NOT_FOUND:
1129 msgptr = "Cannot find the specified file. Make sure the path and filename are correct.";
1131 case MCIERR_DEVICE_NOT_READY:
1132 msgptr = "The device driver is not ready.";
1134 case MCIERR_INTERNAL:
1135 msgptr = "A problem occurred in initializing MCI. Try restarting Windows.";
1138 msgptr = "There is a problem with the device driver. The driver has closed. Cannot access error.";
1140 case MCIERR_CANNOT_USE_ALL:
1141 msgptr = "Cannot use 'all' as the device name with the specified command.";
1143 case MCIERR_MULTIPLE:
1144 msgptr = "Errors occurred in more than one device. Specify each command and device separately to determine which devices caused the error";
1146 case MCIERR_EXTENSION_NOT_FOUND:
1147 msgptr = "Cannot determine the device type from the given filename extension.";
1149 case MCIERR_OUTOFRANGE:
1150 msgptr = "The specified parameter is out of range for the specified command.";
1152 case MCIERR_FLAGS_NOT_COMPATIBLE:
1153 msgptr = "The specified parameters cannot be used together.";
1155 case MCIERR_FILE_NOT_SAVED:
1156 msgptr = "Cannot save the specified file. Make sure you have enough disk space or are still connected to the network.";
1158 case MCIERR_DEVICE_TYPE_REQUIRED:
1159 msgptr = "Cannot find the specified device. Make sure it is installed or that the device name is spelled correctly.";
1161 case MCIERR_DEVICE_LOCKED:
1162 msgptr = "The specified device is now being closed. Wait a few seconds, and then try again.";
1164 case MCIERR_DUPLICATE_ALIAS:
1165 msgptr = "The specified alias is already being used in this application. Use a unique alias.";
1167 case MCIERR_BAD_CONSTANT:
1168 msgptr = "The specified parameter is invalid for this command.";
1170 case MCIERR_MUST_USE_SHAREABLE:
1171 msgptr = "The device driver is already in use. To share it, use the 'shareable' parameter with each 'open' command.";
1173 case MCIERR_MISSING_DEVICE_NAME:
1174 msgptr = "The specified command requires an alias, file, driver, or device name. Please supply one.";
1176 case MCIERR_BAD_TIME_FORMAT:
1177 msgptr = "The specified value for the time format is invalid. Refer to the MCI documentation for valid formats.";
1179 case MCIERR_NO_CLOSING_QUOTE:
1180 msgptr = "A closing double-quotation mark is missing from the parameter value. Please supply one.";
1182 case MCIERR_DUPLICATE_FLAGS:
1183 msgptr = "A parameter or value was specified twice. Only specify it once.";
1185 case MCIERR_INVALID_FILE:
1186 msgptr = "The specified file cannot be played on the specified MCI device. The file may be corrupt, or not in the correct format.";
1188 case MCIERR_NULL_PARAMETER_BLOCK:
1189 msgptr = "A null parameter block was passed to MCI.";
1191 case MCIERR_UNNAMED_RESOURCE:
1192 msgptr = "Cannot save an unnamed file. Supply a filename.";
1194 case MCIERR_NEW_REQUIRES_ALIAS:
1195 msgptr = "You must specify an alias when using the 'new' parameter.";
1197 case MCIERR_NOTIFY_ON_AUTO_OPEN:
1198 msgptr = "Cannot use the 'notify' flag with auto-opened devices.";
1200 case MCIERR_NO_ELEMENT_ALLOWED:
1201 msgptr = "Cannot use a filename with the specified device.";
1203 case MCIERR_NONAPPLICABLE_FUNCTION:
1204 msgptr = "Cannot carry out the commands in the order specified. Correct the command sequence, and then try again.";
1206 case MCIERR_ILLEGAL_FOR_AUTO_OPEN:
1207 msgptr = "Cannot carry out the specified command on an auto-opened device. Wait until the device is closed, and then try again.";
1209 case MCIERR_FILENAME_REQUIRED:
1210 msgptr = "The filename is invalid. Make sure the filename is not longer than 8 characters, followed by a period and an extension.";
1212 case MCIERR_EXTRA_CHARACTERS:
1213 msgptr = "Cannot specify extra characters after a string enclosed in quotation marks.";
1215 case MCIERR_DEVICE_NOT_INSTALLED:
1216 msgptr = "The specified device is not installed on the system. Use the Drivers option in Control Panel to install the device.";
1219 msgptr = "Cannot access the specified file or MCI device. Try changing directories or restarting your computer.";
1222 msgptr = "Cannot access the specified file or MCI device because the application cannot change directories.";
1224 case MCIERR_SET_DRIVE:
1225 msgptr = "Cannot access specified file or MCI device because the application cannot change drives.";
1227 case MCIERR_DEVICE_LENGTH:
1228 msgptr = "Specify a device or driver name that is less than 79 characters.";
1230 case MCIERR_DEVICE_ORD_LENGTH:
1231 msgptr = "Specify a device or driver name that is less than 69 characters.";
1233 case MCIERR_NO_INTEGER:
1234 msgptr = "The specified command requires an integer parameter. Please provide one.";
1236 case MCIERR_WAVE_OUTPUTSINUSE:
1237 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.";
1239 case MCIERR_WAVE_SETOUTPUTINUSE:
1240 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.";
1242 case MCIERR_WAVE_INPUTSINUSE:
1243 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.";
1245 case MCIERR_WAVE_SETINPUTINUSE:
1246 msgptr = "Cannot set the current wave device for recording because it is in use. Wait until the device is free, and then try again.";
1248 case MCIERR_WAVE_OUTPUTUNSPECIFIED:
1249 msgptr = "Any compatible waveform playback device may be used.";
1251 case MCIERR_WAVE_INPUTUNSPECIFIED:
1252 msgptr = "Any compatible waveform recording device may be used.";
1254 case MCIERR_WAVE_OUTPUTSUNSUITABLE:
1255 msgptr = "No wave device that can play files in the current format is installed. Use the Drivers option to install the wave device.";
1257 case MCIERR_WAVE_SETOUTPUTUNSUITABLE:
1258 msgptr = "The device you are trying to play to cannot recognize the current file format.";
1260 case MCIERR_WAVE_INPUTSUNSUITABLE:
1261 msgptr = "No wave device that can record files in the current format is installed. Use the Drivers option to install the wave device.";
1263 case MCIERR_WAVE_SETINPUTUNSUITABLE:
1264 msgptr = "The device you are trying to record from cannot recognize the current file format.";
1266 case MCIERR_NO_WINDOW:
1267 msgptr = "There is no display window.";
1269 case MCIERR_CREATEWINDOW:
1270 msgptr = "Could not create or use window.";
1272 case MCIERR_FILE_READ:
1273 msgptr = "Cannot read the specified file. Make sure the file is still present, or check your disk or network connection.";
1275 case MCIERR_FILE_WRITE:
1276 msgptr = "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network.";
1278 case MCIERR_SEQ_DIV_INCOMPATIBLE:
1279 msgptr = "The time formats of the \"song pointer\" and SMPTE are mutually exclusive. You can't use them together.";
1281 case MCIERR_SEQ_NOMIDIPRESENT:
1282 msgptr = "The system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver.";
1284 case MCIERR_SEQ_PORT_INUSE:
1285 msgptr = "The specified MIDI port is already in use. Wait until it is free; the try again.";
1287 case MCIERR_SEQ_PORT_MAPNODEVICE:
1288 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.";
1290 case MCIERR_SEQ_PORT_MISCERROR:
1291 msgptr = "An error occurred with the specified port.";
1293 case MCIERR_SEQ_PORT_NONEXISTENT:
1294 msgptr = "The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device.";
1296 case MCIERR_SEQ_PORTUNSPECIFIED:
1297 msgptr = "The system doesnot have a current MIDI port specified.";
1299 case MCIERR_SEQ_TIMER:
1300 msgptr = "All multimedia timers are being used by other applications. Quit one of these applications; then, try again.";
1305 msg# 514 : videodisc
1310 msg# 519 : animation
1311 msg# 520 : digitalvideo
1313 msg# 522 : waveaudio
1314 msg# 523 : sequencer
1315 msg# 524 : not ready
1318 msg# 527 : recording
1324 msg# 533 : milliseconds
1331 msg# 540 : smpte 30 drop
1337 TRACE(mmsys, "Unknown MCI Error %ld!\n", dwError);
1340 lstrcpynA(lpstrBuffer, msgptr, uLength);
1341 TRACE(mmsys, "msg = \"%s\";\n", lpstrBuffer);
1345 /**************************************************************************
1346 * mciDriverNotify [MMSYSTEM.711]
1348 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1350 TRACE(mmsys, "(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1352 if (!IsWindow(hWndCallBack)) {
1353 WARN(mmsys, "bad hWnd for call back (0x%04x)\n", hWndCallBack);
1356 TRACE(mmsys, "before PostMessage\n");
1357 Callout.PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1361 /**************************************************************************
1362 * mciDriverNotify [WINMM.36]
1364 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1366 FIXME(mmsys, "(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1368 if (!IsWindow(hWndCallBack)) {
1369 WARN(mmsys, "bad hWnd for call back (0x%04x)\n", hWndCallBack);
1372 TRACE(mmsys, "before PostMessage\n");
1373 Callout.PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1377 /**************************************************************************
1378 * mciGetDriverData [MMSYSTEM.708]
1380 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1382 return mciGetDriverData(uDeviceID);
1385 /**************************************************************************
1386 * mciGetDriverData [WINMM.44]
1388 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1390 TRACE(mmsys, "(%04x)\n", uDeviceID);
1391 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1392 WARN(mmsys, "Bad uDeviceID\n");
1396 return MCI_GetDrv(uDeviceID)->dwPrivate;
1399 /**************************************************************************
1400 * mciSetDriverData [MMSYSTEM.707]
1402 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1404 return mciSetDriverData(uDeviceID, data);
1407 /**************************************************************************
1408 * mciSetDriverData [WINMM.53]
1410 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1412 TRACE(mmsys, "(%04x, %08lx)\n", uDeviceID, data);
1413 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1414 WARN(mmsys, "Bad uDeviceID\n");
1418 MCI_GetDrv(uDeviceID)->dwPrivate = data;
1422 /**************************************************************************
1423 * mciLoadCommandResource [MMSYSTEM.705]
1425 UINT16 WINAPI mciLoadCommandResource16(HANDLE16 hinst, LPCSTR resname, UINT16 type)
1435 static UINT16 mcidevtype = 0;
1437 FIXME(mmsys, "(%04x, %s, %d): stub!\n", hinst, resname, type);
1438 if (!lstrcmpiA(resname, "core")) {
1439 FIXME(mmsys, "(...,\"core\",...), have to use internal tables... (not there yet)\n");
1442 return ++mcidevtype;
1443 /* if file exists "resname.mci", then load resource "resname" from it
1444 * otherwise directly from driver
1446 strcpy(buf,resname);
1447 strcat(buf, ".mci");
1448 if (OpenFile(buf, &ofs,OF_EXIST) != HFILE_ERROR) {
1449 xhinst = LoadLibrary16(buf);
1452 } /* else use passed hinst */
1453 segstr = SEGPTR_STRDUP(resname);
1454 hrsrc = FindResource16(hinst, SEGPTR_GET(segstr), type);
1455 SEGPTR_FREE(segstr);
1457 WARN(mmsys, "no special commandlist found in resource\n");
1458 return MCI_NO_COMMAND_TABLE;
1460 hmem = LoadResource16(hinst, hrsrc);
1462 WARN(mmsys, "couldn't load resource??\n");
1463 return MCI_NO_COMMAND_TABLE;
1465 xmem = WIN16_LockResource16(hmem);
1467 WARN(mmsys, "couldn't lock resource??\n");
1468 FreeResource16(hmem);
1469 return MCI_NO_COMMAND_TABLE;
1471 lmem = PTR_SEG_TO_LIN(xmem);
1472 TRACE(mmsys, "first resource entry is %s\n", (char*)lmem);
1473 /* parse resource, register stuff, return unique id */
1474 return ++mcidevtype;
1477 /**************************************************************************
1478 * mciFreeCommandResource [MMSYSTEM.713]
1480 BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable)
1482 FIXME(mmsys, "(%04x) stub\n", uTable);
1486 /**************************************************************************
1487 * mciFreeCommandResource [WINMM.39]
1489 BOOL WINAPI mciFreeCommandResource(UINT uTable)
1491 FIXME(mmsys, "(%08x) stub\n", uTable);
1495 /**************************************************************************
1496 * mciLoadCommandResource [WINMM.48]
1498 UINT WINAPI mciLoadCommandResource(HANDLE hinst, LPCWSTR resname, UINT type)
1500 FIXME(mmsys, "(%04x, %s, %d): stub!\n", hinst, debugstr_w(resname), type);
1504 /**************************************************************************
1505 * mciSendCommandA [WINMM.49]
1507 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1511 TRACE(mmsys, "(%08x, %s, %08lx, %08lx)\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1515 dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1518 dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1521 dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1524 if (wDevID == MCI_ALL_DEVICE_ID) {
1525 FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
1526 dwRet = MCIERR_CANNOT_USE_ALL;
1528 dwRet = MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2);
1532 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1533 TRACE(mmsys, "=> %08lx\n", dwRet);
1537 /**************************************************************************
1538 * mciSendCommandW [WINMM.50]
1540 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1542 FIXME(mmsys, "(%08x, %s, %08lx, %08lx): stub\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1543 return MCIERR_UNSUPPORTED_FUNCTION;
1546 /**************************************************************************
1547 * mciSendCommand [MMSYSTEM.701]
1549 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1551 DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND;
1553 TRACE(mmsys, "(%04X, %s, %08lX, %08lX)\n",
1554 wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1558 switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1561 dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1562 MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1564 default: break; /* so that gcc does bark */
1568 if (wDevID == MCI_ALL_DEVICE_ID) {
1569 FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
1570 dwRet = MCIERR_CANNOT_USE_ALL;
1571 } else if (!MCI_DevIDValid(wDevID)) {
1572 dwRet = MCIERR_INVALID_DEVICE_ID;
1574 switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1577 dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1578 MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1580 default: break; /* so that gcc does bark */
1585 switch (MCI_MapMsg16To32A(0, wDevID, &dwParam2)) {
1588 dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1589 MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
1591 default: break; /* so that gcc does bark */
1594 /* FIXME: it seems that MCI_BREAK and MCI_SOUND need the same handling */
1596 if (wDevID == MCI_ALL_DEVICE_ID) {
1597 FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
1598 dwRet = MCIERR_CANNOT_USE_ALL;
1600 dwRet = MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2);
1604 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1605 TRACE(mmsys, "=> %ld\n", dwRet);
1609 /**************************************************************************
1610 * mciGetDeviceID [MMSYSTEM.703]
1612 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1615 TRACE(mmsys, "(\"%s\")\n", lpstrName);
1620 if (!lstrcmpiA(lpstrName, "ALL"))
1621 return MCI_ALL_DEVICE_ID;
1623 for (wDevID = MCI_FirstDevID(); MCI_DevIDValid(wDevID); wDevID = MCI_NextDevID(wDevID)) {
1624 if (MCI_GetDrv(wDevID)->modp.wType) {
1625 FIXME(mmsys, "This is wrong for compound devices\n");
1626 /* FIXME: for compound devices, lpstrName is matched against
1627 * the name of the file, not the name of the device...
1629 if (MCI_GetOpenDrv(wDevID)->lpstrDeviceType &&
1630 strcmp(MCI_GetOpenDrv(wDevID)->lpstrDeviceType, lpstrName) == 0)
1633 if (MCI_GetOpenDrv(wDevID)->lpstrAlias &&
1634 strcmp(MCI_GetOpenDrv(wDevID)->lpstrAlias, lpstrName) == 0)
1642 /**************************************************************************
1643 * mciGetDeviceIDA [WINMM.41]
1645 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1647 return mciGetDeviceID16(lpstrName);
1650 /**************************************************************************
1651 * mciGetDeviceIDW [WINMM.43]
1653 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1658 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1659 ret = mciGetDeviceID16(lpstrName);
1660 HeapFree(GetProcessHeap(), 0, lpstrName);
1664 /**************************************************************************
1665 * MCI_DefYieldProc [internal]
1667 UINT16 WINAPI MCI_DefYieldProc(UINT16 wDevID, DWORD data)
1671 TRACE(mmsys, "(0x%04x, 0x%08lx)\n", wDevID, data);
1673 if ((HIWORD(data) != 0 && GetActiveWindow16() != HIWORD(data)) ||
1674 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1680 msg.hwnd = HIWORD(data);
1681 while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1687 /**************************************************************************
1688 * mciSetYieldProc [MMSYSTEM.714]
1690 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1692 TRACE(mmsys, "(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1694 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1695 WARN(mmsys, "Bad uDeviceID\n");
1699 MCI_GetDrv(uDeviceID)->lpfnYieldProc = fpYieldProc;
1700 MCI_GetDrv(uDeviceID)->dwYieldData = dwYieldData;
1701 MCI_GetDrv(uDeviceID)->bIs32 = FALSE;
1706 /**************************************************************************
1707 * mciSetYieldProc [WINMM.54]
1709 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1711 TRACE(mmsys, "(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1713 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1714 WARN(mmsys, "Bad uDeviceID\n");
1718 MCI_GetDrv(uDeviceID)->lpfnYieldProc = fpYieldProc;
1719 MCI_GetDrv(uDeviceID)->dwYieldData = dwYieldData;
1720 MCI_GetDrv(uDeviceID)->bIs32 = TRUE;
1725 /**************************************************************************
1726 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
1728 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1730 FIXME(mmsys, "(%lu, %s) stub\n", dwElementID, lpstrType);
1734 /**************************************************************************
1735 * mciGetDeviceIDFromElementIDW [WINMM.42]
1737 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1739 /* FIXME: that's rather strange, there is no
1740 * mciGetDeviceIDFromElementID32A in winmm.spec
1742 FIXME(mmsys, "(%lu, %p) stub\n", dwElementID, lpstrType);
1746 /**************************************************************************
1747 * mciGetYieldProc [MMSYSTEM.716]
1749 YIELDPROC WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1751 TRACE(mmsys, "(%u, %p)\n", uDeviceID, lpdwYieldData);
1753 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1754 WARN(mmsys, "Bad uDeviceID\n");
1757 if (!MCI_GetDrv(uDeviceID)->lpfnYieldProc) {
1758 WARN(mmsys, "No proc set\n");
1761 if (MCI_GetDrv(uDeviceID)->bIs32) {
1762 WARN(mmsys, "Proc is 32 bit\n");
1765 return MCI_GetDrv(uDeviceID)->lpfnYieldProc;
1768 /**************************************************************************
1769 * mciGetYieldProc [WINMM.47]
1771 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1773 TRACE(mmsys, "(%u, %p)\n", uDeviceID, lpdwYieldData);
1775 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1776 WARN(mmsys, "Bad uDeviceID\n");
1779 if (!MCI_GetDrv(uDeviceID)->lpfnYieldProc) {
1780 WARN(mmsys, "No proc set\n");
1783 if (!MCI_GetDrv(uDeviceID)->bIs32) {
1784 WARN(mmsys, "Proc is 32 bit\n");
1787 return MCI_GetDrv(uDeviceID)->lpfnYieldProc;
1790 /**************************************************************************
1791 * mciGetCreatorTask [MMSYSTEM.717]
1793 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1795 return mciGetCreatorTask(uDeviceID);
1798 /**************************************************************************
1799 * mciGetCreatorTask [WINMM.40]
1801 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1805 TRACE(mmsys, "(%u)\n", uDeviceID);
1807 ret = (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) ?
1808 0 : MCI_GetDrv(uDeviceID)->hCreatorTask;
1810 TRACE(mmsys, "=> %04x\n", ret);
1814 /**************************************************************************
1815 * mciDriverYield [MMSYSTEM.710]
1817 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
1821 /* TRACE(mmsys, "(%04x)\n", uDeviceID); */
1823 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
1824 !MCI_GetDrv(uDeviceID)->lpfnYieldProc || MCI_GetDrv(uDeviceID)->bIs32) {
1827 ret = MCI_GetDrv(uDeviceID)->lpfnYieldProc(uDeviceID, MCI_GetDrv(uDeviceID)->dwYieldData);
1833 /**************************************************************************
1834 * mciDriverYield [WINMM.37]
1836 UINT WINAPI mciDriverYield(UINT uDeviceID)
1840 TRACE(mmsys, "(%04x)\n", uDeviceID);
1841 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
1842 !MCI_GetDrv(uDeviceID)->lpfnYieldProc || !MCI_GetDrv(uDeviceID)->bIs32) {
1845 ret = MCI_GetDrv(uDeviceID)->lpfnYieldProc(uDeviceID, MCI_GetDrv(uDeviceID)->dwYieldData);
1851 /**************************************************************************
1852 * midiOutGetNumDevs [WINMM.80]
1854 UINT WINAPI midiOutGetNumDevs(void)
1856 return midiOutGetNumDevs16();
1859 /**************************************************************************
1860 * midiOutGetNumDevs [MMSYSTEM.201]
1862 UINT16 WINAPI midiOutGetNumDevs16(void)
1864 UINT16 count = modMessage(0, MODM_GETNUMDEVS, 0L, 0L, 0L);
1866 TRACE(mmsys, "returns %u\n", count);
1870 /**************************************************************************
1871 * midiOutGetDevCapsW [WINMM.76]
1873 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps, UINT uSize)
1875 MIDIOUTCAPS16 moc16;
1878 ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
1879 lpCaps->wMid = moc16.wMid;
1880 lpCaps->wPid = moc16.wPid;
1881 lpCaps->vDriverVersion = moc16.vDriverVersion;
1882 lstrcpyAtoW(lpCaps->szPname, moc16.szPname);
1883 lpCaps->wTechnology = moc16.wTechnology;
1884 lpCaps->wVoices = moc16.wVoices;
1885 lpCaps->wNotes = moc16.wNotes;
1886 lpCaps->wChannelMask = moc16.wChannelMask;
1887 lpCaps->dwSupport = moc16.dwSupport;
1891 /**************************************************************************
1892 * midiOutGetDevCapsA [WINMM.75]
1894 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps, UINT uSize)
1896 MIDIOUTCAPS16 moc16;
1899 ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
1900 lpCaps->wMid = moc16.wMid;
1901 lpCaps->wPid = moc16.wPid;
1902 lpCaps->vDriverVersion = moc16.vDriverVersion;
1903 strcpy(lpCaps->szPname, moc16.szPname);
1904 lpCaps->wTechnology = moc16.wTechnology;
1905 lpCaps->wVoices = moc16.wVoices;
1906 lpCaps->wNotes = moc16.wNotes;
1907 lpCaps->wChannelMask = moc16.wChannelMask;
1908 lpCaps->dwSupport = moc16.dwSupport;
1912 /**************************************************************************
1913 * midiOutGetDevCaps [MMSYSTEM.202]
1915 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps, UINT16 uSize)
1917 TRACE(mmsys, "midiOutGetDevCaps\n");
1918 return modMessage(uDeviceID, MODM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
1921 /**************************************************************************
1922 * midiOutGetErrorTextA [WINMM.77]
1924 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1926 TRACE(mmsys, "midiOutGetErrorText\n");
1927 return midiGetErrorText(uError, lpText, uSize);
1930 /**************************************************************************
1931 * midiOutGetErrorTextW [WINMM.78]
1933 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1935 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1938 TRACE(mmsys, "midiOutGetErrorText\n");
1939 ret = midiGetErrorText(uError, xstr, uSize);
1940 lstrcpyAtoW(lpText, xstr);
1941 HeapFree(GetProcessHeap(), 0, xstr);
1945 /**************************************************************************
1946 * midiOutGetErrorText [MMSYSTEM.203]
1948 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
1950 TRACE(mmsys, "midiOutGetErrorText\n");
1951 return midiGetErrorText(uError, lpText, uSize);
1954 /**************************************************************************
1955 * midiGetErrorText [internal]
1957 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1960 if ((lpText == NULL) || (uSize < 1)) return(FALSE);
1963 case MIDIERR_UNPREPARED:
1964 msgptr = "The MIDI header was not prepared. Use the Prepare function to prepare the header, and then try again.";
1966 case MIDIERR_STILLPLAYING:
1967 msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
1970 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.";
1972 case MIDIERR_NOTREADY:
1973 msgptr = "The port is transmitting data to the device. Wait until the data has been transmitted, and then try again.";
1975 case MIDIERR_NODEVICE:
1976 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.";
1978 case MIDIERR_INVALIDSETUP:
1979 msgptr = "The current MIDI setup is damaged. Copy the original MIDIMAP.CFG file to the Windows SYSTEM directory, and then try again.";
1982 msg# 336 : Cannot use the song-pointer time format and the SMPTE time-format together.
1983 msg# 337 : The specified MIDI device is already in use. Wait until it is free, and then try again.
1984 msg# 338 : The specified MIDI device is not installed on the system. Use the Drivers option in Control Panel to install the driver.
1985 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.
1986 msg# 340 : An error occurred using the specified port.
1987 msg# 341 : All multimedia timers are being used by other applications. Quit one of these applications, and then try again.
1988 msg# 342 : There is no current MIDI port.
1989 msg# 343 : There are no MIDI devices installed on the system. Use the Drivers option in Control Panel to install the driver.
1992 msgptr = "Unknown MIDI Error !\n";
1995 lstrcpynA(lpText, msgptr, uSize);
1999 static LPMIDIOPENDESC MIDI_OutAlloc(HMIDIOUT16* lphMidiOut, DWORD dwCallback,
2000 DWORD dwInstance, DWORD cIDs, MIDIOPENSTRMID* lpIDs)
2003 LPMIDIOPENDESC lpDesc;
2005 hMidiOut = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC) + (cIDs ? (cIDs - 1) : 0) * sizeof(MIDIOPENSTRMID));
2007 if (lphMidiOut != NULL)
2008 *lphMidiOut = hMidiOut;
2009 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2012 lpDesc->hMidi = hMidiOut;
2013 lpDesc->dwCallback = dwCallback;
2014 lpDesc->dwInstance = dwInstance;
2015 lpDesc->dnDevNode = 0;
2016 lpDesc->cIds = cIDs;
2018 memcpy(&(lpDesc->rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2023 /**************************************************************************
2024 * midiOutOpen [WINM.84]
2026 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2027 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2032 ret = midiOutOpen16(&hmo16, uDeviceID, dwCallback, dwInstance,
2033 CALLBACK32CONV(dwFlags));
2034 if (lphMidiOut) *lphMidiOut = hmo16;
2038 /**************************************************************************
2039 * midiOutOpen [MMSYSTEM.204]
2041 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2042 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2044 HMIDIOUT16 hMidiOut;
2045 LPMIDIOPENDESC lpDesc;
2047 BOOL bMapperFlg = FALSE;
2049 TRACE(mmsys, "(%p, %d, %08lX, %08lX, %08lX);\n",
2050 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2052 if (lphMidiOut != NULL) *lphMidiOut = 0;
2054 if (uDeviceID == (UINT16)MIDI_MAPPER) {
2055 TRACE(mmsys, "MIDI_MAPPER mode requested !\n");
2060 lpDesc = MIDI_OutAlloc(&hMidiOut, dwCallback, dwInstance, 0, NULL);
2063 return MMSYSERR_NOMEM;
2065 while (uDeviceID < MAXMIDIDRIVERS) {
2066 ret = modMessage(uDeviceID, MODM_OPEN,
2067 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2068 if (ret == MMSYSERR_NOERROR) break;
2069 if (!bMapperFlg) break;
2071 TRACE(mmsys, "MIDI_MAPPER mode ! try next driver...\n");
2073 TRACE(mmsys, "=> wDevID=%u (%d)\n", uDeviceID, ret);
2074 if (ret != MMSYSERR_NOERROR) {
2075 USER_HEAP_FREE(hMidiOut);
2076 if (lphMidiOut) *lphMidiOut = 0;
2078 lpDesc->wDevID = uDeviceID;
2079 if (lphMidiOut) *lphMidiOut = hMidiOut;
2085 /**************************************************************************
2086 * midiOutClose [WINMM.74]
2088 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2090 return midiOutClose16(hMidiOut);
2093 /**************************************************************************
2094 * midiOutClose [MMSYSTEM.205]
2096 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2098 LPMIDIOPENDESC lpDesc;
2101 TRACE(mmsys, "(%04X)\n", hMidiOut);
2103 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2105 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2106 dwRet = modMessage(lpDesc->wDevID, MODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2107 USER_HEAP_FREE(hMidiOut);
2111 /**************************************************************************
2112 * midiOutPrepareHeader [WINMM.85]
2114 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2115 MIDIHDR* lpMidiOutHdr, UINT uSize)
2117 LPMIDIOPENDESC lpDesc;
2119 TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2121 lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiOut);
2123 return MMSYSERR_INVALHANDLE;
2124 lpMidiOutHdr->reserved = (DWORD)lpMidiOutHdr;
2125 return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance,
2126 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2129 /**************************************************************************
2130 * midiOutPrepareHeader [MMSYSTEM.206]
2132 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut,
2133 LPMIDIHDR16 /*SEGPTR*/ _lpMidiOutHdr, UINT16 uSize)
2135 LPMIDIOPENDESC lpDesc;
2136 LPMIDIHDR16 lpMidiOutHdr = (LPMIDIHDR16)PTR_SEG_TO_LIN(_lpMidiOutHdr);
2138 TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2140 lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiOut);
2142 return MMSYSERR_INVALHANDLE;
2143 lpMidiOutHdr->reserved = (DWORD)_lpMidiOutHdr;
2144 return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance,
2145 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2148 /**************************************************************************
2149 * midiOutUnprepareHeader [WINMM.89]
2151 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2152 MIDIHDR* lpMidiOutHdr, UINT uSize)
2154 return midiOutUnprepareHeader16(hMidiOut, (MIDIHDR16*)lpMidiOutHdr, uSize);
2157 /**************************************************************************
2158 * midiOutUnprepareHeader [MMSYSTEM.207]
2160 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut,
2161 MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2163 LPMIDIOPENDESC lpDesc;
2165 TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2167 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2168 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2169 return modMessage(lpDesc->wDevID, MODM_UNPREPARE, lpDesc->dwInstance,
2170 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2173 /**************************************************************************
2174 * midiOutShortMsg [WINMM.88]
2176 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2178 return midiOutShortMsg16(hMidiOut, dwMsg);
2181 /**************************************************************************
2182 * midiOutShortMsg [MMSYSTEM.208]
2184 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2186 LPMIDIOPENDESC lpDesc;
2188 TRACE(mmsys, "(%04X, %08lX)\n", hMidiOut, dwMsg);
2190 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2191 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2192 return modMessage(lpDesc->wDevID, MODM_DATA, lpDesc->dwInstance, dwMsg, 0L);
2195 /**************************************************************************
2196 * midiOutLongMsg [WINMM.82]
2198 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2199 MIDIHDR* lpMidiOutHdr, UINT uSize)
2201 return midiOutLongMsg16(hMidiOut, (MIDIHDR16*)lpMidiOutHdr, uSize);
2204 /**************************************************************************
2205 * midiOutLongMsg [MMSYSTEM.209]
2207 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut,
2208 MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2210 LPMIDIOPENDESC lpDesc;
2212 TRACE(mmsys, "(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2214 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2215 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2216 return modMessage(lpDesc->wDevID, MODM_LONGDATA, lpDesc->dwInstance,
2217 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2220 /**************************************************************************
2221 * midiOutReset [WINMM.86]
2223 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2225 return midiOutReset16(hMidiOut);
2228 /**************************************************************************
2229 * midiOutReset [MMSYSTEM.210]
2231 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2233 LPMIDIOPENDESC lpDesc;
2235 TRACE(mmsys, "(%04X)\n", hMidiOut);
2237 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2238 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2239 return modMessage(lpDesc->wDevID, MODM_RESET, lpDesc->dwInstance, 0L, 0L);
2242 /**************************************************************************
2243 * midiOutGetVolume [WINM.81]
2245 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2247 return midiOutGetVolume16(uDeviceID, lpdwVolume);
2250 /**************************************************************************
2251 * midiOutGetVolume [MMSYSTEM.211]
2253 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2255 TRACE(mmsys, "(%04X, %p);\n", uDeviceID, lpdwVolume);
2256 return modMessage(uDeviceID, MODM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
2259 /**************************************************************************
2260 * midiOutSetVolume [WINMM.87]
2262 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2264 return midiOutSetVolume16(uDeviceID, dwVolume);
2267 /**************************************************************************
2268 * midiOutSetVolume [MMSYSTEM.212]
2270 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2272 TRACE(mmsys, "(%04X, %08lX);\n", uDeviceID, dwVolume);
2273 return modMessage(uDeviceID, MODM_SETVOLUME, 0L, dwVolume, 0L);
2276 /**************************************************************************
2277 * midiOutCachePatches [WINMM.73]
2279 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2280 WORD* lpwPatchArray, UINT uFlags)
2282 return midiOutCachePatches16(hMidiOut, uBank, lpwPatchArray, uFlags);
2285 /**************************************************************************
2286 * midiOutCachePatches [MMSYSTEM.213]
2288 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2289 WORD* lpwPatchArray, UINT16 uFlags)
2291 /* not really necessary to support this */
2292 FIXME(mmsys, "not supported yet\n");
2293 return MMSYSERR_NOTSUPPORTED;
2296 /**************************************************************************
2297 * midiOutCacheDrumPatches [WINMM.72]
2299 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2300 WORD* lpwKeyArray, UINT uFlags)
2302 return midiOutCacheDrumPatches16(hMidiOut, uPatch, lpwKeyArray, uFlags);
2305 /**************************************************************************
2306 * midiOutCacheDrumPatches [MMSYSTEM.214]
2308 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2309 WORD* lpwKeyArray, UINT16 uFlags)
2311 FIXME(mmsys, "not supported yet\n");
2312 return MMSYSERR_NOTSUPPORTED;
2315 /**************************************************************************
2316 * midiOutGetID [WINMM.79]
2318 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2323 ret = midiOutGetID16(hMidiOut, &xid);
2328 /**************************************************************************
2329 * midiOutGetID [MMSYSTEM.215]
2331 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2333 TRACE(mmsys, "midiOutGetID\n");
2337 /**************************************************************************
2338 * midiOutMessage [WINMM.83]
2340 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2341 DWORD dwParam1, DWORD dwParam2)
2343 LPMIDIOPENDESC lpDesc;
2345 /* Shouldn't we anyway use the functions midiOutXXX ?
2346 * M$ doc says: This function is used only for driver-specific
2347 * messages that are not supported by the MIDI API.
2348 * Clearly not what we are currently doing
2351 TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n",
2352 hMidiOut, uMessage, dwParam1, dwParam2);
2354 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2355 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2358 FIXME(mmsys, "can't handle MODM_OPEN!\n");
2360 case MODM_GETDEVCAPS:
2361 return midiOutGetDevCapsA(hMidiOut, (LPMIDIOUTCAPSA)dwParam1, dwParam2);
2362 case MODM_GETNUMDEVS:
2365 case MODM_GETVOLUME:
2366 case MODM_SETVOLUME:
2369 case MODM_UNPREPARE:
2370 /* no argument conversion needed */
2373 ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
2374 hMidiOut, uMessage, dwParam1, dwParam2);
2377 return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2380 /**************************************************************************
2381 * midiOutMessage [MMSYSTEM.216]
2383 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2384 DWORD dwParam1, DWORD dwParam2)
2386 LPMIDIOPENDESC lpDesc;
2388 TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n",
2389 hMidiOut, uMessage, dwParam1, dwParam2);
2390 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2391 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2394 FIXME(mmsys, "can't handle MODM_OPEN!\n");
2396 case MODM_GETNUMDEVS:
2399 case MODM_SETVOLUME:
2400 /* no argument conversion needed */
2402 case MODM_GETVOLUME:
2403 return midiOutGetVolume16(hMidiOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
2405 return midiOutLongMsg16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2407 /* lpMidiOutHdr is still a segmented pointer for this function */
2408 return midiOutPrepareHeader16(hMidiOut, (LPMIDIHDR16)dwParam1, dwParam2);
2409 case MODM_UNPREPARE:
2410 return midiOutUnprepareHeader16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2412 ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
2413 hMidiOut, uMessage, dwParam1, dwParam2);
2416 return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2419 /**************************************************************************
2420 * midiInGetNumDevs [WINMM.64]
2422 UINT WINAPI midiInGetNumDevs(void)
2424 return midiInGetNumDevs16();
2427 /**************************************************************************
2428 * midiInGetNumDevs [MMSYSTEM.301]
2430 UINT16 WINAPI midiInGetNumDevs16(void)
2433 TRACE(mmsys, "midiInGetNumDevs\n");
2434 count += midMessage(0, MIDM_GETNUMDEVS, 0L, 0L, 0L);
2435 TRACE(mmsys, "midiInGetNumDevs return %u \n", count);
2439 /**************************************************************************
2440 * midiInGetDevCaps [WINMM.60]
2442 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2445 UINT ret = midiInGetDevCaps16(uDeviceID, &mic16, uSize);
2447 lpCaps->wMid = mic16.wMid;
2448 lpCaps->wPid = mic16.wPid;
2449 lpCaps->vDriverVersion = mic16.vDriverVersion;
2450 lstrcpyAtoW(lpCaps->szPname, mic16.szPname);
2451 lpCaps->dwSupport = mic16.dwSupport;
2455 /**************************************************************************
2456 * midiInGetDevCaps [WINMM.59]
2458 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2461 UINT ret = midiInGetDevCaps16(uDeviceID, &mic16, uSize);
2463 lpCaps->wMid = mic16.wMid;
2464 lpCaps->wPid = mic16.wPid;
2465 lpCaps->vDriverVersion = mic16.vDriverVersion;
2466 strcpy(lpCaps->szPname, mic16.szPname);
2467 lpCaps->dwSupport = mic16.dwSupport;
2471 /**************************************************************************
2472 * midiInGetDevCaps [MMSYSTEM.302]
2474 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID,
2475 LPMIDIINCAPS16 lpCaps, UINT16 uSize)
2477 TRACE(mmsys, "midiInGetDevCaps\n");
2478 return midMessage(uDeviceID, MIDM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
2481 /**************************************************************************
2482 * midiInGetErrorText [WINMM.62]
2484 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2486 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2487 UINT ret = midiInGetErrorText16(uError, xstr, uSize);
2488 lstrcpyAtoW(lpText, xstr);
2489 HeapFree(GetProcessHeap(), 0, xstr);
2493 /**************************************************************************
2494 * midiInGetErrorText [WINMM.61]
2496 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2498 return midiInGetErrorText16(uError, lpText, uSize);
2501 /**************************************************************************
2502 * midiInGetErrorText [MMSYSTEM.303]
2504 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2506 TRACE(mmsys, "midiInGetErrorText\n");
2507 return (midiGetErrorText(uError, lpText, uSize));
2510 /**************************************************************************
2511 * midiInOpen [WINMM.66]
2513 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2514 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2517 UINT ret = midiInOpen16(&xhmid16, uDeviceID, dwCallback, dwInstance,
2518 CALLBACK32CONV(dwFlags));
2520 *lphMidiIn = xhmid16;
2524 /**************************************************************************
2525 * midiInOpen [MMSYSTEM.304]
2527 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2528 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2531 LPMIDIOPENDESC lpDesc;
2533 BOOL bMapperFlg = FALSE;
2535 if (lphMidiIn != NULL)
2537 TRACE(mmsys, "(%p, %d, %08lX, %08lX, %08lX);\n",
2538 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2539 if (uDeviceID == (UINT16)MIDI_MAPPER) {
2540 TRACE(mmsys, "MIDI_MAPPER mode requested !\n");
2544 hMidiIn = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC));
2545 if (lphMidiIn != NULL)
2546 *lphMidiIn = hMidiIn;
2547 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2549 return MMSYSERR_NOMEM;
2550 lpDesc->hMidi = hMidiIn;
2551 lpDesc->dwCallback = dwCallback;
2552 lpDesc->dwInstance = dwInstance;
2554 while (uDeviceID < MAXMIDIDRIVERS) {
2555 dwRet = midMessage(uDeviceID, MIDM_OPEN,
2556 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2557 if (dwRet == MMSYSERR_NOERROR)
2562 TRACE(mmsys, "MIDI_MAPPER mode ! try next driver...\n");
2564 lpDesc->wDevID = uDeviceID;
2566 if (dwRet != MMSYSERR_NOERROR) {
2567 USER_HEAP_FREE(hMidiIn);
2568 if (lphMidiIn) *lphMidiIn = 0;
2574 /**************************************************************************
2575 * midiInClose [WINMM.58]
2577 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2579 return midiInClose16(hMidiIn);
2582 /**************************************************************************
2583 * midiInClose [MMSYSTEM.305]
2585 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2587 LPMIDIOPENDESC lpDesc;
2590 TRACE(mmsys, "(%04X)\n", hMidiIn);
2591 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2593 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2594 dwRet = midMessage(lpDesc->wDevID, MIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2595 USER_HEAP_FREE(hMidiIn);
2599 /**************************************************************************
2600 * midiInPrepareHeader [WINMM.67]
2602 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2603 MIDIHDR* lpMidiInHdr, UINT uSize)
2605 LPMIDIOPENDESC lpDesc;
2607 TRACE(mmsys, "(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2609 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2611 return MMSYSERR_INVALHANDLE;
2612 lpMidiInHdr->reserved = (DWORD)lpMidiInHdr;
2613 return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance,
2614 (DWORD)lpMidiInHdr, (DWORD)uSize);
2617 /**************************************************************************
2618 * midiInPrepareHeader [MMSYSTEM.306]
2620 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn,
2621 MIDIHDR16* /*SEGPTR*/ _lpMidiInHdr, UINT16 uSize)
2623 LPMIDIOPENDESC lpDesc;
2624 LPMIDIHDR16 lpMidiInHdr = (LPMIDIHDR16)PTR_SEG_TO_LIN(_lpMidiInHdr);
2626 TRACE(mmsys, "(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2628 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2630 return MMSYSERR_INVALHANDLE;
2631 lpMidiInHdr->reserved = (DWORD)_lpMidiInHdr;
2632 return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance,
2633 (DWORD)lpMidiInHdr, (DWORD)uSize);
2636 /**************************************************************************
2637 * midiInUnprepareHeader [WINMM.71]
2639 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2640 MIDIHDR* lpMidiInHdr, UINT uSize)
2642 return midiInUnprepareHeader16(hMidiIn, (MIDIHDR16*)lpMidiInHdr, uSize);
2645 /**************************************************************************
2646 * midiInUnprepareHeader [MMSYSTEM.307]
2648 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn,
2649 MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2651 LPMIDIOPENDESC lpDesc;
2653 TRACE(mmsys, "(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2655 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2657 return MMSYSERR_INVALHANDLE;
2658 return midMessage(lpDesc->wDevID, MIDM_UNPREPARE, lpDesc->dwInstance,
2659 (DWORD)lpMidiInHdr, (DWORD)uSize);
2662 /**************************************************************************
2663 * midiInAddBuffer [WINMM.57]
2665 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2666 MIDIHDR* lpMidiInHdr, UINT uSize)
2668 return midiInAddBuffer16(hMidiIn, (MIDIHDR16*)lpMidiInHdr, uSize);
2671 /**************************************************************************
2672 * midiInAddBuffer [MMSYSTEM.308]
2674 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn,
2675 MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2677 TRACE(mmsys, "midiInAddBuffer\n");
2681 /**************************************************************************
2682 * midiInStart [WINMM.69]
2684 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2686 return midiInStart16(hMidiIn);
2689 /**************************************************************************
2690 * midiInStart [MMSYSTEM.309]
2692 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2694 LPMIDIOPENDESC lpDesc;
2696 TRACE(mmsys, "(%04X)\n", hMidiIn);
2697 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2699 return MMSYSERR_INVALHANDLE;
2700 return midMessage(lpDesc->wDevID, MIDM_START, lpDesc->dwInstance, 0L, 0L);
2703 /**************************************************************************
2704 * midiInStop [WINMM.70]
2706 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2708 return midiInStop16(hMidiIn);
2711 /**************************************************************************
2712 * midiInStop [MMSYSTEM.310]
2714 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2716 LPMIDIOPENDESC lpDesc;
2718 TRACE(mmsys, "(%04X)\n", hMidiIn);
2719 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2721 return MMSYSERR_INVALHANDLE;
2722 return midMessage(lpDesc->wDevID, MIDM_STOP, lpDesc->dwInstance, 0L, 0L);
2725 /**************************************************************************
2726 * midiInReset [WINMM.68]
2728 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2730 return midiInReset16(hMidiIn);
2733 /**************************************************************************
2734 * midiInReset [MMSYSTEM.311]
2736 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2738 LPMIDIOPENDESC lpDesc;
2740 TRACE(mmsys, "(%04X)\n", hMidiIn);
2741 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2743 return MMSYSERR_INVALHANDLE;
2744 return midMessage(lpDesc->wDevID, MIDM_RESET, lpDesc->dwInstance, 0L, 0L);
2747 /**************************************************************************
2748 * midiInGetID [WINMM.63]
2750 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2752 LPMIDIOPENDESC lpDesc;
2754 TRACE(mmsys, "(%04X, %p)\n", hMidiIn, lpuDeviceID);
2755 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2757 return MMSYSERR_INVALHANDLE;
2758 if (lpuDeviceID == NULL)
2759 return MMSYSERR_INVALPARAM;
2760 *lpuDeviceID = lpDesc->wDevID;
2762 return MMSYSERR_NOERROR;
2765 /**************************************************************************
2766 * midiInGetID [MMSYSTEM.312]
2768 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
2770 LPMIDIOPENDESC lpDesc;
2772 TRACE(mmsys, "(%04X, %p)\n", hMidiIn, lpuDeviceID);
2773 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2775 return MMSYSERR_INVALHANDLE;
2776 if (lpuDeviceID == NULL)
2777 return MMSYSERR_INVALPARAM;
2778 *lpuDeviceID = lpDesc->wDevID;
2780 return MMSYSERR_NOERROR;
2783 /**************************************************************************
2784 * midiInMessage [WINMM.65]
2786 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
2787 DWORD dwParam1, DWORD dwParam2)
2789 LPMIDIOPENDESC lpDesc;
2791 TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n",
2792 hMidiIn, uMessage, dwParam1, dwParam2);
2793 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2795 return MMSYSERR_INVALHANDLE;
2799 FIXME(mmsys, "can't handle MIDM_OPEN!\n");
2801 case MIDM_GETDEVCAPS:
2802 return midiInGetDevCapsA(hMidiIn, (LPMIDIINCAPSA)dwParam1, dwParam2);
2803 case MIDM_GETNUMDEVS:
2808 /* no argument conversion needed */
2811 return midiInPrepareHeader(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
2812 case MIDM_UNPREPARE:
2813 return midiInUnprepareHeader(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
2814 case MIDM_ADDBUFFER:
2815 return midiInAddBuffer(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
2817 ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
2818 hMidiIn, uMessage, dwParam1, dwParam2);
2821 return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2824 /**************************************************************************
2825 * midiInMessage [MMSYSTEM.313]
2827 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
2828 DWORD dwParam1, DWORD dwParam2)
2830 LPMIDIOPENDESC lpDesc;
2832 TRACE(mmsys, "(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
2834 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2835 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2838 WARN(mmsys, "can't handle MIDM_OPEN!\n");
2840 case MIDM_GETDEVCAPS:
2841 return midiInGetDevCaps16(hMidiIn, (LPMIDIINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2842 case MIDM_GETNUMDEVS:
2847 /* no argument conversion needed */
2850 return midiInPrepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2851 case MIDM_UNPREPARE:
2852 return midiInUnprepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2853 case MIDM_ADDBUFFER:
2854 return midiInAddBuffer16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2856 ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
2857 hMidiIn, uMessage, dwParam1, dwParam2);
2860 return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2863 typedef struct WINE_MIDIStream{
2876 /**************************************************************************
2877 * MMSYSTEM_GetMidiStream [internal]
2879 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, MIDIOPENDESC** lplpDesc)
2881 MIDIOPENDESC* lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiStrm);
2886 if (lpDesc == NULL) {
2890 *lpMidiStrm = (WINE_MIDIStream*)lpDesc->rgIds.dwStreamID;
2892 return *lpMidiStrm != NULL;
2895 /**************************************************************************
2896 * MMSYSTEM_MidiStreamConvert [internal]
2898 static DWORD MMSYSTEM_MidiStreamConvert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
2902 if (lpMidiStrm->dwTimeDiv == 0) {
2903 FIXME(mmsys, "Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
2904 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
2905 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
2906 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
2907 ret = (pulse * 1000) / (nf * nsf);
2909 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
2910 (double)lpMidiStrm->dwTimeDiv);
2916 /**************************************************************************
2917 * MMSYSTEM_MidiStreamPlayer [internal]
2919 static DWORD WINAPI MMSYSTEM_MidiStreamPlayer(LPVOID pmt)
2921 WINE_MIDIStream* lpMidiStrm = pmt;
2922 MIDIOPENDESC* lpDesc = USER_HEAP_LIN_ADDR(lpMidiStrm->hDevice);
2927 TRACE(mmsys, "(%p)!\n", lpMidiStrm);
2929 /* force thread's queue creation */
2930 /* Used to be InitThreadInput16(0, 5); */
2931 /* but following works also with hack in midiStreamOpen */
2932 Callout.PeekMessageA(&msg, 0, 0, 0, 0);
2934 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
2935 lpMidiStrm->bFlag = TRUE;
2936 TRACE(mmsys, "Ready to go 1\n");
2937 SuspendThread(lpMidiStrm->hThread);
2938 TRACE(mmsys, "Ready to go 2\n");
2940 lpMidiStrm->dwStartTicks = 0;
2941 lpMidiStrm->dwPulses = 0;
2943 while (Callout.GetMessageA(&msg, 0, 0, 0)) {
2944 LPMIDIHDR lpMidiHdr = (LPMIDIHDR)msg.lParam;
2948 switch (msg.message) {
2950 TRACE(mmsys, "%s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx]\n",
2951 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
2952 lpMidiHdr->reserved, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded, lpMidiHdr->dwFlags);
2955 * midiOutPrepareHeader(), in Wine, sets the 'reserved' field of MIDIHDR to the
2956 * 16 or 32 bit address of lpMidiHdr (depending if called from 16 to 32 bit code)
2958 lpData = ((DWORD)lpMidiHdr == lpMidiHdr->reserved) ?
2959 (LPBYTE)lpMidiHdr->lpData : (LPBYTE)PTR_SEG_TO_LIN(lpMidiHdr->lpData);
2962 /* dumps content of lpMidiHdr->lpData
2963 * FIXME: there should be a debug routine somewhere that already does this
2964 * I hate spreading this type of shit all around the code
2966 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
2970 for (i = 0; i < MIN(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
2971 printf("%02x ", lpData[dwToGo + i]);
2974 for (i = 0; i < MIN(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
2975 ch = lpData[dwToGo + i];
2976 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
2981 /* FIXME: EPP says "I don't understand the content of the first MIDIHDR sent
2982 * by native mcimidi, it doesn't look like a correct one".
2983 * this trick allows to throw it away... but I don't like it.
2984 * It looks like part of the file I'm trying to play and definitively looks
2985 * like raw midi content
2986 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
2987 * synchronization issue where native mcimidi is still processing raw MIDI
2988 * content before generating MIDIEVENTs ?
2990 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
2991 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
2992 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
2993 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
2994 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
2995 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
2996 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
2997 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
2998 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
2999 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3000 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3001 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3002 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3003 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3004 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3005 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3006 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3008 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3009 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3010 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3011 FIXME(mmsys, "Dropping bad lpMidiHdr (streamID=%08lx)\n", ((LPMIDIEVENT)lpData)->dwStreamID);
3013 /* sets initial tick count for first MIDIHDR */
3014 if (!lpMidiStrm->dwStartTicks)
3015 lpMidiStrm->dwStartTicks = GetTickCount();
3017 for (lpMidiHdr->dwOffset = 0; lpMidiHdr->dwOffset < lpMidiHdr->dwBufferLength; ) {
3018 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3020 if (me->dwDeltaTime) {
3021 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStreamConvert(lpMidiStrm, me->dwDeltaTime);
3022 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3023 dwCurrTC = GetTickCount();
3025 lpMidiStrm->dwPulses += me->dwDeltaTime;
3027 TRACE(mmsys, "%ld/%ld/%ld\n", dwToGo, dwCurrTC, me->dwDeltaTime);
3028 if (dwCurrTC < dwToGo)
3029 Sleep(dwToGo - dwCurrTC);
3031 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3033 FIXME(mmsys, "NIY: MEVT_COMMENT\n");
3034 /* do nothing, skip bytes */
3037 FIXME(mmsys, "NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3042 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3045 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3050 FIXME(mmsys, "Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3053 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) + ((me->dwEvent & MEVT_F_LONG) ? ((MEVT_EVENTPARM(me->dwEvent) + 3) & ~3): 0);
3054 if (me->dwEvent & MEVT_F_CALLBACK) {
3055 DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3056 MM_MOM_POSITIONCB, lpDesc->dwInstance, (LPARAM)lpMidiHdr, 0L);
3060 lpMidiHdr->dwFlags |= MHDR_DONE;
3061 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3063 DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3064 MM_MOM_DONE, lpDesc->dwInstance, lpMidiHdr->reserved, 0L);
3067 WARN(mmsys, "Unknown message %d\n", msg.message);
3074 /**************************************************************************
3075 * midiStreamClose [WINMM.90]
3077 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3079 WINE_MIDIStream* lpMidiStrm;
3081 TRACE(mmsys, "(%08x)!\n", hMidiStrm);
3083 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3084 return MMSYSERR_INVALHANDLE;
3086 midiStreamStop(hMidiStrm);
3088 USER_HEAP_FREE(hMidiStrm);
3090 return midiOutClose(hMidiStrm);
3093 /**************************************************************************
3094 * midiStreamOpen [WINMM.91]
3096 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3097 DWORD cMidi, DWORD dwCallback,
3098 DWORD dwInstance, DWORD fdwOpen)
3100 WINE_MIDIStream* lpMidiStrm;
3102 MIDIOPENSTRMID mosm;
3103 MIDIOPENDESC* lpDesc;
3104 HMIDIOUT16 hMidiOut16;
3106 TRACE(mmsys, "(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3107 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3109 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3110 return MMSYSERR_INVALPARAM;
3112 if (*lpuDeviceID == (UINT16)MIDI_MAPPER) {
3113 FIXME(mmsys, "MIDI_MAPPER mode requested ! => forcing devID to 0\n");
3117 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3118 lpMidiStrm->dwTempo = 500000;
3119 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3120 lpMidiStrm->dwPositionMS = 0;
3122 mosm.dwStreamID = (DWORD)lpMidiStrm;
3123 /* FIXME: the correct value is not allocated yet for MAPPER */
3124 mosm.wDeviceID = *lpuDeviceID;
3125 lpDesc = MIDI_OutAlloc(&hMidiOut16, dwCallback, dwInstance, 1, &mosm);
3126 lpMidiStrm->hDevice = hMidiOut16;
3128 *lphMidiStrm = hMidiOut16;
3130 lpDesc->wDevID = *lpuDeviceID;
3131 ret = modMessage(lpDesc->wDevID, MODM_OPEN,
3132 lpDesc->dwInstance, (DWORD)lpDesc, fdwOpen);
3133 lpMidiStrm->bFlag = FALSE;
3134 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3136 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStreamPlayer,
3137 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3139 if (!lpMidiStrm->hThread) {
3140 midiStreamClose((HMIDISTRM)hMidiOut16);
3141 return MMSYSERR_NOMEM;
3144 /* wait for thread to have started, and for it's queue to be created */
3145 while (!((volatile WINE_MIDIStream*)lpMidiStrm)->bFlag) {
3148 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3149 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3150 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3152 ReleaseThunkLock(&count);
3154 RestoreThunkLock(count);
3157 TRACE(mmsys, "=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n", *lpuDeviceID, lpDesc->wDevID, *lphMidiStrm, ret, lpMidiStrm);
3161 /**************************************************************************
3162 * midiStreamOut [WINMM.92]
3164 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, UINT cbMidiHdr)
3166 WINE_MIDIStream* lpMidiStrm;
3167 DWORD ret = MMSYSERR_NOERROR;
3169 TRACE(mmsys, "(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3171 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3172 ret = MMSYSERR_INVALHANDLE;
3174 if (!Callout.PostThreadMessageA(lpMidiStrm->dwThreadID, WM_USER, 0, (DWORD)lpMidiHdr)) {
3175 WARN(mmsys, "bad PostThreadMessageA\n");
3181 /**************************************************************************
3182 * midiStreamPause [WINMM.93]
3184 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3186 WINE_MIDIStream* lpMidiStrm;
3187 DWORD ret = MMSYSERR_NOERROR;
3189 TRACE(mmsys, "(%08x)!\n", hMidiStrm);
3191 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3192 ret = MMSYSERR_INVALHANDLE;
3194 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3195 WARN(mmsys, "bad Suspend (%ld)\n", GetLastError());
3201 /**************************************************************************
3202 * midiStreamPosition [WINMM.94]
3204 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3206 WINE_MIDIStream* lpMidiStrm;
3207 DWORD ret = MMSYSERR_NOERROR;
3209 TRACE(mmsys, "(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3211 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3212 ret = MMSYSERR_INVALHANDLE;
3213 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3214 ret = MMSYSERR_INVALPARAM;
3216 switch (lpMMT->wType) {
3218 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3219 TRACE(mmsys, "=> %ld ms\n", lpMMT->u.ms);
3222 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3223 TRACE(mmsys, "=> %ld ticks\n", lpMMT->u.ticks);
3226 WARN(mmsys, "Unsupported time type %d\n", lpMMT->wType);
3227 lpMMT->wType = TIME_MS;
3228 ret = MMSYSERR_INVALPARAM;
3235 /**************************************************************************
3236 * midiStreamProperty [WINMM.95]
3238 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3240 WINE_MIDIStream* lpMidiStrm;
3241 MMRESULT ret = MMSYSERR_NOERROR;
3243 TRACE(mmsys, "(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3245 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3246 ret = MMSYSERR_INVALHANDLE;
3247 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3248 ret = MMSYSERR_INVALPARAM;
3249 } else if (dwProperty & MIDIPROP_TEMPO) {
3250 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3252 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3253 ret = MMSYSERR_INVALPARAM;
3254 } else if (dwProperty & MIDIPROP_SET) {
3255 lpMidiStrm->dwTempo = mpt->dwTempo;
3256 TRACE(mmsys, "Setting tempo to %ld\n", mpt->dwTempo);
3257 } else if (dwProperty & MIDIPROP_GET) {
3258 mpt->dwTempo = lpMidiStrm->dwTempo;
3259 TRACE(mmsys, "Getting tempo <= %ld\n", mpt->dwTempo);
3261 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3262 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3264 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3265 ret = MMSYSERR_INVALPARAM;
3266 } else if (dwProperty & MIDIPROP_SET) {
3267 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3268 TRACE(mmsys, "Setting time div to %ld\n", mptd->dwTimeDiv);
3269 } else if (dwProperty & MIDIPROP_GET) {
3270 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3271 TRACE(mmsys, "Getting time div <= %ld\n", mptd->dwTimeDiv);
3274 ret = MMSYSERR_INVALPARAM;
3280 /**************************************************************************
3281 * midiStreamRestart [WINMM.96]
3283 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3285 WINE_MIDIStream* lpMidiStrm;
3286 MMRESULT ret = MMSYSERR_NOERROR;
3288 TRACE(mmsys, "(%08x)!\n", hMidiStrm);
3290 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3291 ret = MMSYSERR_INVALHANDLE;
3293 if (ResumeThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3294 WARN(mmsys, "bad Resume (%ld)\n", GetLastError());
3300 /**************************************************************************
3301 * midiStreamStop [WINMM.97]
3303 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3305 WINE_MIDIStream* lpMidiStrm;
3306 MMRESULT ret = MMSYSERR_NOERROR;
3308 FIXME(mmsys, "(%08x) stub!\n", hMidiStrm);
3310 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3311 ret = MMSYSERR_INVALHANDLE;
3313 /* FIXME: should turn off all notes, and return all buffers to
3314 * calling application
3320 /**************************************************************************
3321 * midiStreamClose [MMSYSTEM.252]
3323 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3325 return midiStreamClose(hMidiStrm);
3328 /**************************************************************************
3329 * midiStreamOpen [MMSYSTEM.251]
3331 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3332 DWORD cMidi, DWORD dwCallback,
3333 DWORD dwInstance, DWORD fdwOpen)
3335 HMIDISTRM hMidiStrm32;
3339 if (!phMidiStrm || !devid)
3340 return MMSYSERR_INVALPARAM;
3342 ret = midiStreamOpen(&hMidiStrm32, &devid32, cMidi, dwCallback, dwInstance, fdwOpen);
3343 *phMidiStrm = hMidiStrm32;
3348 /**************************************************************************
3349 * midiStreamOut [MMSYSTEM.254]
3351 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3353 return midiStreamOut(hMidiStrm, (LPMIDIHDR)lpMidiHdr, cbMidiHdr);
3356 /**************************************************************************
3357 * midiStreamPause [MMSYSTEM.255]
3359 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3361 return midiStreamPause(hMidiStrm);
3364 /**************************************************************************
3365 * midiStreamPosition [MMSYSTEM.253]
3367 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3373 return MMSYSERR_INVALPARAM;
3374 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3375 ret = midiStreamPosition(hMidiStrm, &mmt32, sizeof(MMTIME));
3376 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3380 /**************************************************************************
3381 * midiStreamProperty [MMSYSTEM.250]
3383 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3385 return midiStreamProperty(hMidiStrm, lpPropData, dwProperty);
3388 /**************************************************************************
3389 * midiStreamRestart [MMSYSTEM.256]
3391 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3393 return midiStreamRestart(hMidiStrm);
3396 /**************************************************************************
3397 * midiStreamStop [MMSYSTEM.257]
3399 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3401 return midiStreamStop(hMidiStrm);
3404 /**************************************************************************
3405 * waveOutGetNumDevs [MMSYSTEM.401]
3407 UINT WINAPI waveOutGetNumDevs()
3409 return waveOutGetNumDevs16();
3412 /**************************************************************************
3413 * waveOutGetNumDevs [WINMM.167]
3415 UINT16 WINAPI waveOutGetNumDevs16()
3418 TRACE(mmsys, "waveOutGetNumDevs\n");
3419 /* FIXME: I'm not sure MCI_FirstDevID() is correct */
3420 count += wodMessage(MCI_FirstDevID(), WODM_GETNUMDEVS, 0L, 0L, 0L);
3421 TRACE(mmsys, "waveOutGetNumDevs return %u \n", count);
3425 /**************************************************************************
3426 * waveOutGetDevCaps [MMSYSTEM.402]
3428 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID, LPWAVEOUTCAPS16 lpCaps,
3431 if (uDeviceID > waveOutGetNumDevs16() - 1) return MMSYSERR_BADDEVICEID;
3432 if (uDeviceID == (UINT16)WAVE_MAPPER) return MMSYSERR_BADDEVICEID; /* FIXME: do we have a wave mapper ? */
3433 TRACE(mmsys, "waveOutGetDevCaps\n");
3434 return wodMessage(uDeviceID, WODM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
3437 /**************************************************************************
3438 * waveOutGetDevCapsA [WINMM.162]
3440 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3443 WAVEOUTCAPS16 woc16;
3444 UINT16 ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3446 lpCaps->wMid = woc16.wMid;
3447 lpCaps->wPid = woc16.wPid;
3448 lpCaps->vDriverVersion = woc16.vDriverVersion;
3449 strcpy(lpCaps->szPname, woc16.szPname);
3450 lpCaps->dwFormats = woc16.dwFormats;
3451 lpCaps->wChannels = woc16.wChannels;
3452 lpCaps->dwSupport = woc16.dwSupport;
3456 /**************************************************************************
3457 * waveOutGetDevCapsW [WINMM.163]
3459 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3462 WAVEOUTCAPS16 woc16;
3463 UINT ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3465 lpCaps->wMid = woc16.wMid;
3466 lpCaps->wPid = woc16.wPid;
3467 lpCaps->vDriverVersion = woc16.vDriverVersion;
3468 lstrcpyAtoW(lpCaps->szPname, woc16.szPname);
3469 lpCaps->dwFormats = woc16.dwFormats;
3470 lpCaps->wChannels = woc16.wChannels;
3471 lpCaps->dwSupport = woc16.dwSupport;
3475 /**************************************************************************
3476 * waveOutGetErrorText [MMSYSTEM.403]
3478 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3480 TRACE(mmsys, "waveOutGetErrorText\n");
3481 return waveGetErrorText(uError, lpText, uSize);
3484 /**************************************************************************
3485 * waveOutGetErrorTextA [WINMM.164]
3487 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3489 return waveOutGetErrorText16(uError, lpText, uSize);
3492 /**************************************************************************
3493 * waveOutGetErrorTextW [WINMM.165]
3495 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3497 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3498 UINT ret = waveOutGetErrorTextA(uError, xstr, uSize);
3500 lstrcpyAtoW(lpText, xstr);
3501 HeapFree(GetProcessHeap(), 0, xstr);
3505 /**************************************************************************
3506 * waveGetErrorText [internal]
3508 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3511 TRACE(mmsys, "(%04X, %p, %d);\n",
3512 uError, lpText, uSize);
3513 if ((lpText == NULL) || (uSize < 1)) return(FALSE);
3516 case MMSYSERR_NOERROR:
3517 msgptr = "The specified command was carried out.";
3519 case MMSYSERR_ERROR:
3520 msgptr = "Undefined external error.";
3522 case MMSYSERR_BADDEVICEID:
3523 msgptr = "A device ID has been used that is out of range for your system.";
3525 case MMSYSERR_NOTENABLED:
3526 msgptr = "The driver was not enabled.";
3528 case MMSYSERR_ALLOCATED:
3529 msgptr = "The specified device is already in use. Wait until it is free, and then try again.";
3531 case MMSYSERR_INVALHANDLE:
3532 msgptr = "The specified device handle is invalid.";
3534 case MMSYSERR_NODRIVER:
3535 msgptr = "There is no driver installed on your system !\n";
3537 case MMSYSERR_NOMEM:
3538 msgptr = "Not enough memory available for this task. Quit one or more applications to increase available memory, and then try again.";
3540 case MMSYSERR_NOTSUPPORTED:
3541 msgptr = "This function is not supported. Use the Capabilities function to determine which functions and messages the driver supports.";
3543 case MMSYSERR_BADERRNUM:
3544 msgptr = "An error number was specified that is not defined in the system.";
3546 case MMSYSERR_INVALFLAG:
3547 msgptr = "An invalid flag was passed to a system function.";
3549 case MMSYSERR_INVALPARAM:
3550 msgptr = "An invalid parameter was passed to a system function.";
3552 case WAVERR_BADFORMAT:
3553 msgptr = "The specified format is not supported or cannot be translated. Use the Capabilities function to determine the supported formats";
3555 case WAVERR_STILLPLAYING:
3556 msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
3558 case WAVERR_UNPREPARED:
3559 msgptr = "The wave header was not prepared. Use the Prepare function to prepare the header, and then try again.";
3562 msgptr = "Cannot open the device without using the WAVE_ALLOWSYNC flag. Use the flag, and then try again.";
3565 msgptr = "Unknown MMSYSTEM Error !\n";
3568 lstrcpynA(lpText, msgptr, uSize);
3572 /**************************************************************************
3573 * waveOutOpen [WINMM.173]
3574 * All the args/structs have the same layout as the win16 equivalents
3576 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3577 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3578 DWORD dwInstance, DWORD dwFlags)
3581 UINT ret = waveOutOpen16(&hwo16, uDeviceID, lpFormat, dwCallback, dwInstance,
3582 CALLBACK32CONV(dwFlags));
3584 if (lphWaveOut) *lphWaveOut=hwo16;
3588 /**************************************************************************
3589 * waveOutOpen [MMSYSTEM.404]
3591 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3592 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3593 DWORD dwInstance, DWORD dwFlags)
3595 HWAVEOUT16 hWaveOut;
3596 LPWAVEOPENDESC lpDesc;
3598 BOOL bMapperFlg = FALSE;
3600 TRACE(mmsys, "(%p, %d, %p, %08lX, %08lX, %08lX);\n",
3601 lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
3602 if (dwFlags & WAVE_FORMAT_QUERY)
3603 TRACE(mmsys, "WAVE_FORMAT_QUERY requested !\n");
3604 if (uDeviceID == (UINT16)WAVE_MAPPER) {
3605 TRACE(mmsys, "WAVE_MAPPER mode requested !\n");
3609 if (lpFormat == NULL) return WAVERR_BADFORMAT;
3611 hWaveOut = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
3612 if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
3613 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3614 if (lpDesc == NULL) return MMSYSERR_NOMEM;
3615 lpDesc->hWave = hWaveOut;
3616 lpDesc->lpFormat = (LPWAVEFORMAT)lpFormat; /* should the struct be copied iso pointer? */
3617 lpDesc->dwCallBack = dwCallback;
3618 lpDesc->dwInstance = dwInstance;
3619 if (uDeviceID >= MAXWAVEDRIVERS)
3621 while (uDeviceID < MAXWAVEDRIVERS) {
3622 dwRet = wodMessage(uDeviceID, WODM_OPEN,
3623 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
3624 if (dwRet == MMSYSERR_NOERROR) break;
3625 if (!bMapperFlg) break;
3627 TRACE(mmsys, "WAVE_MAPPER mode ! try next driver...\n");
3629 lpDesc->uDeviceID = uDeviceID; /* save physical Device ID */
3630 if (dwFlags & WAVE_FORMAT_QUERY) {
3631 TRACE(mmsys, "End of WAVE_FORMAT_QUERY !\n");
3632 dwRet = waveOutClose(hWaveOut);
3633 if (lphWaveOut) *lphWaveOut = 0;
3635 else if (dwRet != MMSYSERR_NOERROR)
3637 USER_HEAP_FREE(hWaveOut);
3638 if (lphWaveOut) *lphWaveOut = 0;
3643 /**************************************************************************
3644 * waveOutClose [WINMM.161]
3646 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3648 return waveOutClose16(hWaveOut);
3651 /**************************************************************************
3652 * waveOutClose [MMSYSTEM.405]
3654 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
3656 LPWAVEOPENDESC lpDesc;
3659 TRACE(mmsys, "(%04X)\n", hWaveOut);
3661 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3662 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3663 dwRet = wodMessage(lpDesc->uDeviceID, WODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
3664 USER_HEAP_FREE(hWaveOut);
3668 /**************************************************************************
3669 * waveOutPrepareHeader [WINMM.175]
3671 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
3672 WAVEHDR* lpWaveOutHdr, UINT uSize)
3674 LPWAVEOPENDESC lpDesc;
3676 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3678 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3680 return MMSYSERR_INVALHANDLE;
3681 lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr;
3682 return wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance,
3683 (DWORD)lpWaveOutHdr, uSize);
3686 /**************************************************************************
3687 * waveOutPrepareHeader [MMSYSTEM.406]
3689 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut,
3690 WAVEHDR* /*SEGPTR*/ _lpWaveOutHdr, UINT16 uSize)
3692 LPWAVEOPENDESC lpDesc;
3693 LPWAVEHDR lpWaveOutHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(_lpWaveOutHdr);
3696 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3698 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3700 return MMSYSERR_INVALHANDLE;
3701 lpWaveOutHdr->reserved = (DWORD)_lpWaveOutHdr;
3702 ret = wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance,
3703 (DWORD)lpWaveOutHdr, uSize);
3707 /**************************************************************************
3708 * waveOutUnprepareHeader [WINMM.181]
3710 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
3711 WAVEHDR* lpWaveOutHdr, UINT uSize)
3713 LPWAVEOPENDESC lpDesc;
3715 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3717 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3718 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3719 lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr;
3720 return wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance,
3721 (DWORD)lpWaveOutHdr, uSize);
3724 /**************************************************************************
3725 * waveOutUnprepareHeader [MMSYSTEM.407]
3727 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut,
3728 WAVEHDR* lpWaveOutHdr, UINT16 uSize)
3730 LPWAVEOPENDESC lpDesc;
3733 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3735 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3737 return MMSYSERR_INVALHANDLE;
3738 ret = wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance,
3739 (DWORD)lpWaveOutHdr, uSize);
3743 /**************************************************************************
3744 * waveOutWrite [MMSYSTEM.408]
3746 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, WAVEHDR* lpWaveOutHdr,
3749 LPWAVEOPENDESC lpDesc;
3751 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3753 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3755 return MMSYSERR_INVALHANDLE;
3756 return wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance,
3757 (DWORD)lpWaveOutHdr, uSize);
3760 /**************************************************************************
3761 * waveOutWrite [MMSYSTEM.408]
3763 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, WAVEHDR* lpWaveOutHdr,
3766 LPWAVEOPENDESC lpDesc;
3769 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3771 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3773 return MMSYSERR_INVALHANDLE;
3774 ret = wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance, (DWORD)lpWaveOutHdr, uSize);
3778 /**************************************************************************
3779 * waveOutPause [WINMM.174]
3781 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
3783 return waveOutPause16(hWaveOut);
3786 /**************************************************************************
3787 * waveOutPause [MMSYSTEM.409]
3789 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut)
3791 LPWAVEOPENDESC lpDesc;
3793 TRACE(mmsys, "(%04X)\n", hWaveOut);
3795 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3796 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3797 return wodMessage(lpDesc->uDeviceID, WODM_PAUSE, lpDesc->dwInstance, 0L, 0L);
3800 /**************************************************************************
3801 * waveOutRestart [WINMM.177]
3803 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
3805 return waveOutRestart16(hWaveOut);
3808 /**************************************************************************
3809 * waveOutRestart [MMSYSTEM.410]
3811 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut)
3813 LPWAVEOPENDESC lpDesc;
3815 TRACE(mmsys, "(%04X)\n", hWaveOut);
3817 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3818 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3819 return wodMessage(lpDesc->uDeviceID, WODM_RESTART, lpDesc->dwInstance, 0L, 0L);
3822 /**************************************************************************
3823 * waveOutReset [WINMM.176]
3825 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
3827 return waveOutReset16(hWaveOut);
3830 /**************************************************************************
3831 * waveOutReset [MMSYSTEM.411]
3833 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut)
3835 LPWAVEOPENDESC lpDesc;
3837 TRACE(mmsys, "(%04X)\n", hWaveOut);
3839 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3840 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3841 return wodMessage(lpDesc->uDeviceID, WODM_RESET, lpDesc->dwInstance, 0L, 0L);
3844 /**************************************************************************
3845 * waveOutGetPosition [WINMM.170]
3847 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
3853 mmt16.wType = lpTime->wType;
3854 ret = waveOutGetPosition16(hWaveOut, &mmt16, sizeof(mmt16));
3855 MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
3859 /**************************************************************************
3860 * waveOutGetPosition [MMSYSTEM.412]
3862 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
3865 LPWAVEOPENDESC lpDesc;
3866 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
3867 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3868 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3869 return wodMessage(lpDesc->uDeviceID, WODM_GETPOS, lpDesc->dwInstance,
3870 (DWORD)lpTime, (DWORD)uSize);
3873 #define WAVEOUT_SHORTCUT_1(xx, XX, atype) \
3874 UINT WINAPI waveOut##xx(HWAVEOUT hWaveOut, atype x) \
3876 return waveOut##xx##16(hWaveOut, x); \
3878 UINT16 WINAPI waveOut##xx##16(HWAVEOUT16 hWaveOut, atype x) \
3880 LPWAVEOPENDESC lpDesc; \
3881 TRACE(mmsys, "(%04X, %08lx);\n", hWaveOut, (DWORD)x); \
3882 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut); \
3883 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE; \
3884 return wodMessage(lpDesc->uDeviceID, WODM_##XX, \
3885 lpDesc->dwInstance, (DWORD)x, 0L); \
3888 WAVEOUT_SHORTCUT_1(GetPitch, GETPITCH, DWORD*)
3889 WAVEOUT_SHORTCUT_1(SetPitch, SETPITCH, DWORD)
3890 WAVEOUT_SHORTCUT_1(GetPlaybackRate, GETPLAYBACKRATE, DWORD*)
3891 WAVEOUT_SHORTCUT_1(SetPlaybackRate, SETPLAYBACKRATE, DWORD)
3893 #define WAVEOUT_SHORTCUT_2(xx, XX, atype) \
3894 UINT WINAPI waveOut##xx(UINT devid, atype x) \
3896 return waveOut##xx##16(devid, x); \
3898 UINT16 WINAPI waveOut##xx##16(UINT16 devid, atype x) \
3900 TRACE(mmsys, "(%04X, %08lx);\n", devid, (DWORD)x); \
3901 return wodMessage(devid, WODM_##XX, 0L, (DWORD)x, 0L); \
3904 WAVEOUT_SHORTCUT_2(GetVolume, GETVOLUME, DWORD*)
3905 WAVEOUT_SHORTCUT_2(SetVolume, SETVOLUME, DWORD)
3907 /**************************************************************************
3908 * waveOutBreakLoop [MMSYSTEM.419]
3910 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
3912 return waveOutBreakLoop16(hWaveOut);
3915 /**************************************************************************
3916 * waveOutBreakLoop [MMSYSTEM.419]
3918 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut)
3920 TRACE(mmsys, "(%04X)\n", hWaveOut);
3921 return MMSYSERR_INVALHANDLE;
3924 /**************************************************************************
3925 * waveOutGetID [MMSYSTEM.420]
3927 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
3929 LPWAVEOPENDESC lpDesc;
3931 TRACE(mmsys, "(%04X, %p);\n", hWaveOut, lpuDeviceID);
3933 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3934 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3935 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3936 *lpuDeviceID = lpDesc->uDeviceID;
3940 /**************************************************************************
3941 * waveOutGetID [MMSYSTEM.420]
3943 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
3945 LPWAVEOPENDESC lpDesc;
3947 TRACE(mmsys, "(%04X, %p);\n", hWaveOut, lpuDeviceID);
3949 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3950 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3951 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3952 *lpuDeviceID = lpDesc->uDeviceID;
3956 /**************************************************************************
3957 * waveOutMessage [MMSYSTEM.421]
3959 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
3960 DWORD dwParam1, DWORD dwParam2)
3962 LPWAVEOPENDESC lpDesc;
3964 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
3965 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3967 case WODM_GETNUMDEVS:
3969 case WODM_GETVOLUME:
3971 case WODM_GETPLAYBACKRATE:
3972 case WODM_SETVOLUME:
3974 case WODM_SETPLAYBACKRATE:
3978 case WODM_UNPREPARE:
3981 /* no argument conversion needed */
3984 return waveOutWrite(hWaveOut, (LPWAVEHDR)dwParam1, dwParam2);
3985 case WODM_GETDEVCAPS:
3986 /* FIXME: UNICODE/ANSI? */
3987 return waveOutGetDevCapsA(hWaveOut, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
3989 FIXME(mmsys, "can't handle WODM_OPEN, please report.\n");
3992 ERR(mmsys, "(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
3993 hWaveOut, uMessage, dwParam1, dwParam2);
3996 return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
3999 /**************************************************************************
4000 * waveOutMessage [MMSYSTEM.421]
4002 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4003 DWORD dwParam1, DWORD dwParam2)
4005 LPWAVEOPENDESC lpDesc;
4007 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4008 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4010 case WODM_GETNUMDEVS:
4011 case WODM_SETVOLUME:
4013 case WODM_SETPLAYBACKRATE:
4018 /* no argument conversion needed */
4021 return waveOutGetPosition16(hWaveOut, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4022 case WODM_GETVOLUME:
4023 return waveOutGetVolume16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4025 return waveOutGetPitch16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4026 case WODM_GETPLAYBACKRATE:
4027 return waveOutGetPlaybackRate16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4028 case WODM_GETDEVCAPS:
4029 return waveOutGetDevCaps16(hWaveOut, (LPWAVEOUTCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4031 return waveOutPrepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4032 case WODM_UNPREPARE:
4033 return waveOutUnprepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4035 return waveOutWrite16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4037 FIXME(mmsys, "can't handle WODM_OPEN, please report.\n");
4040 ERR(mmsys, "(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
4041 hWaveOut, uMessage, dwParam1, dwParam2);
4043 return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4046 /**************************************************************************
4047 * waveInGetNumDevs [WINMM.151]
4049 UINT WINAPI waveInGetNumDevs()
4051 return waveInGetNumDevs16();
4054 /**************************************************************************
4055 * waveInGetNumDevs [MMSYSTEM.501]
4057 UINT16 WINAPI waveInGetNumDevs16()
4061 TRACE(mmsys, "waveInGetNumDevs\n");
4062 count += widMessage(0, WIDM_GETNUMDEVS, 0L, 0L, 0L);
4063 TRACE(mmsys, "waveInGetNumDevs return %u \n", count);
4067 /**************************************************************************
4068 * waveInGetDevCapsA [WINMM.147]
4070 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4073 UINT ret = waveInGetDevCaps16(uDeviceID, &wic16, uSize);
4075 lpCaps->wMid = wic16.wMid;
4076 lpCaps->wPid = wic16.wPid;
4077 lpCaps->vDriverVersion = wic16.vDriverVersion;
4078 lstrcpyAtoW(lpCaps->szPname, wic16.szPname);
4079 lpCaps->dwFormats = wic16.dwFormats;
4080 lpCaps->wChannels = wic16.wChannels;
4085 /**************************************************************************
4086 * waveInGetDevCapsA [WINMM.146]
4088 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4091 UINT ret = waveInGetDevCaps16(uDeviceID, &wic16, uSize);
4093 lpCaps->wMid = wic16.wMid;
4094 lpCaps->wPid = wic16.wPid;
4095 lpCaps->vDriverVersion = wic16.vDriverVersion;
4096 strcpy(lpCaps->szPname, wic16.szPname);
4097 lpCaps->dwFormats = wic16.dwFormats;
4098 lpCaps->wChannels = wic16.wChannels;
4102 /**************************************************************************
4103 * waveInGetDevCaps [MMSYSTEM.502]
4105 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps, UINT16 uSize)
4107 TRACE(mmsys, "waveInGetDevCaps\n");
4109 return widMessage(uDeviceID, WIDM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
4112 /**************************************************************************
4113 * waveInGetErrorTextA [WINMM.148]
4115 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4117 TRACE(mmsys, "waveInGetErrorText\n");
4118 return waveGetErrorText(uError, lpText, uSize);
4121 /**************************************************************************
4122 * waveInGetErrorTextW [WINMM.149]
4124 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4126 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4127 UINT ret = waveGetErrorText(uError, txt, uSize);
4129 lstrcpyAtoW(lpText, txt);
4130 HeapFree(GetProcessHeap(), 0, txt);
4134 /**************************************************************************
4135 * waveInGetErrorText [MMSYSTEM.503]
4137 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4139 TRACE(mmsys, "waveInGetErrorText\n");
4140 return waveGetErrorText(uError, lpText, uSize);
4143 /**************************************************************************
4144 * waveInOpen [WINMM.154]
4146 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4147 const LPWAVEFORMAT lpFormat, DWORD dwCallback,
4148 DWORD dwInstance, DWORD dwFlags)
4151 UINT ret = waveInOpen16(&hwin16, uDeviceID, lpFormat, dwCallback, dwInstance,
4152 CALLBACK32CONV(dwFlags));
4153 if (lphWaveIn) *lphWaveIn = hwin16;
4157 /**************************************************************************
4158 * waveInOpen [MMSYSTEM.504]
4160 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4161 const LPWAVEFORMAT lpFormat, DWORD dwCallback,
4162 DWORD dwInstance, DWORD dwFlags)
4165 LPWAVEOPENDESC lpDesc;
4167 BOOL bMapperFlg = FALSE;
4169 TRACE(mmsys, "(%p, %d, %p, %08lX, %08lX, %08lX);\n",
4170 lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
4171 if (dwFlags & WAVE_FORMAT_QUERY)
4172 TRACE(mmsys, "WAVE_FORMAT_QUERY requested !\n");
4173 if (uDeviceID == (UINT16)WAVE_MAPPER) {
4174 TRACE(mmsys, "WAVE_MAPPER mode requested !\n");
4178 if (lpFormat == NULL) return WAVERR_BADFORMAT;
4179 hWaveIn = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
4180 if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
4181 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4182 if (lpDesc == NULL) return MMSYSERR_NOMEM;
4183 lpDesc->hWave = hWaveIn;
4184 lpDesc->lpFormat = lpFormat;
4185 lpDesc->dwCallBack = dwCallback;
4186 lpDesc->dwInstance = dwInstance;
4187 while (uDeviceID < MAXWAVEDRIVERS) {
4188 dwRet = widMessage(uDeviceID, WIDM_OPEN,
4189 lpDesc->dwInstance, (DWORD)lpDesc, 0L);
4190 if (dwRet == MMSYSERR_NOERROR) break;
4191 if (!bMapperFlg) break;
4193 TRACE(mmsys, "WAVE_MAPPER mode ! try next driver...\n");
4195 lpDesc->uDeviceID = uDeviceID;
4196 if (dwFlags & WAVE_FORMAT_QUERY) {
4197 TRACE(mmsys, "End of WAVE_FORMAT_QUERY !\n");
4198 dwRet = waveInClose16(hWaveIn);
4199 } else if (dwRet != MMSYSERR_NOERROR) {
4200 USER_HEAP_FREE(hWaveIn);
4201 if (lphWaveIn) *lphWaveIn = 0;
4207 /**************************************************************************
4208 * waveInClose [WINMM.145]
4210 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4212 return waveInClose16(hWaveIn);
4215 /**************************************************************************
4216 * waveInClose [MMSYSTEM.505]
4218 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4220 LPWAVEOPENDESC lpDesc;
4223 TRACE(mmsys, "(%04X)\n", hWaveIn);
4224 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4225 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4226 dwRet = widMessage(lpDesc->uDeviceID, WIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
4227 USER_HEAP_FREE(hWaveIn);
4231 /**************************************************************************
4232 * waveInPrepareHeader [WINMM.155]
4234 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn,
4235 WAVEHDR* lpWaveInHdr, UINT uSize)
4237 LPWAVEOPENDESC lpDesc;
4239 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4240 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4241 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4242 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4243 lpWaveInHdr->lpNext = NULL;
4244 lpWaveInHdr->dwBytesRecorded = 0;
4245 lpWaveInHdr->reserved = (DWORD)lpWaveInHdr;
4247 return widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance,
4248 (DWORD)lpWaveInHdr, uSize);
4251 /**************************************************************************
4252 * waveInPrepareHeader [MMSYSTEM.506]
4254 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn,
4255 WAVEHDR* /* SEGPTR */ _lpWaveInHdr, UINT16 uSize)
4257 LPWAVEOPENDESC lpDesc;
4258 LPWAVEHDR lpWaveInHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(_lpWaveInHdr);
4261 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4263 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4264 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4265 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4267 lpWaveInHdr->lpNext = NULL;
4268 lpWaveInHdr->dwBytesRecorded = 0;
4270 lpWaveInHdr->reserved = (DWORD)_lpWaveInHdr;
4272 ret = widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance,
4273 (DWORD)lpWaveInHdr, uSize);
4277 /**************************************************************************
4278 * waveInUnprepareHeader [WINMM.159]
4280 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn,
4281 WAVEHDR* lpWaveInHdr, UINT uSize)
4283 LPWAVEOPENDESC lpDesc;
4285 TRACE(mmsys, "(%04X, %p, %u);\n",
4286 hWaveIn, lpWaveInHdr, uSize);
4287 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4288 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4289 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4291 lpWaveInHdr->lpNext = NULL;
4292 return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance,
4293 (DWORD)lpWaveInHdr, uSize);
4296 /**************************************************************************
4297 * waveInUnprepareHeader [MMSYSTEM.507]
4299 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn,
4300 WAVEHDR* lpWaveInHdr, UINT16 uSize)
4302 LPWAVEOPENDESC lpDesc;
4304 TRACE(mmsys, "(%04X, %p, %u);\n",
4305 hWaveIn, lpWaveInHdr, uSize);
4306 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4307 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4308 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4310 return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance,
4311 (DWORD)lpWaveInHdr, uSize);
4314 /**************************************************************************
4315 * waveInAddBuffer [WINMM.144]
4317 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4318 WAVEHDR* lpWaveInHdr, UINT uSize)
4320 LPWAVEOPENDESC lpDesc;
4322 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4324 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4325 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4326 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4328 lpWaveInHdr->lpNext = NULL;
4329 lpWaveInHdr->dwBytesRecorded = 0;
4331 return widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
4332 (DWORD)lpWaveInHdr, uSize);
4336 /**************************************************************************
4337 * waveInAddBuffer [MMSYSTEM.508]
4339 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn,
4340 WAVEHDR* lpWaveInHdr, UINT16 uSize)
4342 LPWAVEOPENDESC lpDesc;
4345 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4347 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4348 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4349 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4350 lpWaveInHdr->lpNext = NULL;
4351 lpWaveInHdr->dwBytesRecorded = 0;
4353 ret = widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
4354 (DWORD)lpWaveInHdr, uSize);
4358 /**************************************************************************
4359 * waveInStart [WINMM.157]
4361 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4363 return waveInStart16(hWaveIn);
4366 /**************************************************************************
4367 * waveInStart [MMSYSTEM.509]
4369 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn)
4371 LPWAVEOPENDESC lpDesc;
4373 TRACE(mmsys, "(%04X)\n", hWaveIn);
4374 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4375 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4376 return widMessage(lpDesc->uDeviceID, WIDM_START, lpDesc->dwInstance, 0, 0);
4379 /**************************************************************************
4380 * waveInStop [WINMM.158]
4382 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4384 return waveInStop16(hWaveIn);
4387 /**************************************************************************
4388 * waveInStop [MMSYSTEM.510]
4390 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn)
4392 LPWAVEOPENDESC lpDesc;
4394 TRACE(mmsys, "(%04X)\n", hWaveIn);
4395 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4396 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4397 return widMessage(lpDesc->uDeviceID, WIDM_STOP, lpDesc->dwInstance, 0L, 0L);
4400 /**************************************************************************
4401 * waveInReset [WINMM.156]
4403 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4405 return waveInReset16(hWaveIn);
4408 /**************************************************************************
4409 * waveInReset [MMSYSTEM.511]
4411 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn)
4413 LPWAVEOPENDESC lpDesc;
4415 TRACE(mmsys, "(%04X)\n", hWaveIn);
4416 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4417 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4418 return widMessage(lpDesc->uDeviceID, WIDM_RESET, lpDesc->dwInstance, 0, 0);
4421 /**************************************************************************
4422 * waveInGetPosition [WINMM.152]
4424 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4430 mmt16.wType = lpTime->wType;
4431 ret = waveInGetPosition16(hWaveIn, &mmt16, uSize);
4433 MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
4437 /**************************************************************************
4438 * waveInGetPosition [MMSYSTEM.512]
4440 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4443 LPWAVEOPENDESC lpDesc;
4445 TRACE(mmsys, "(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4446 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4447 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4448 return widMessage(lpDesc->uDeviceID, WIDM_GETPOS, lpDesc->dwInstance,
4449 (DWORD)lpTime, (DWORD)uSize);
4452 /**************************************************************************
4453 * waveInGetID [WINMM.150]
4455 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4457 LPWAVEOPENDESC lpDesc;
4459 TRACE(mmsys, "waveInGetID\n");
4460 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4461 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4462 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4463 *lpuDeviceID = lpDesc->uDeviceID;
4467 /**************************************************************************
4468 * waveInGetID [MMSYSTEM.513]
4470 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4472 LPWAVEOPENDESC lpDesc;
4474 TRACE(mmsys, "waveInGetID\n");
4475 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4476 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4477 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4478 *lpuDeviceID = lpDesc->uDeviceID;
4482 /**************************************************************************
4483 * waveInMessage [WINMM.153]
4485 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4486 DWORD dwParam1, DWORD dwParam2)
4488 LPWAVEOPENDESC lpDesc;
4490 FIXME(mmsys, "(%04X, %04X, %08lX, %08lX)\n",
4491 hWaveIn, uMessage, dwParam1, dwParam2);
4492 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4493 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4496 FIXME(mmsys, "cannot handle WIDM_OPEN, please report.\n");
4498 case WIDM_GETNUMDEVS:
4505 case WIDM_UNPREPARE:
4506 case WIDM_ADDBUFFER:
4508 /* no argument conversion needed */
4510 case WIDM_GETDEVCAPS:
4511 /*FIXME: ANSI/UNICODE */
4512 return waveInGetDevCapsA(hWaveIn, (LPWAVEINCAPSA)dwParam1, dwParam2);
4514 ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
4515 hWaveIn, uMessage, dwParam1, dwParam2);
4518 return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4521 /**************************************************************************
4522 * waveInMessage [MMSYSTEM.514]
4524 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4525 DWORD dwParam1, DWORD dwParam2)
4527 LPWAVEOPENDESC lpDesc;
4529 FIXME(mmsys, "(%04X, %04X, %08lX, %08lX)\n",
4530 hWaveIn, uMessage, dwParam1, dwParam2);
4531 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4532 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4535 FIXME(mmsys, "cannot handle WIDM_OPEN, please report.\n");
4537 case WIDM_GETNUMDEVS:
4543 /* no argument conversion needed */
4545 case WIDM_GETDEVCAPS:
4546 return waveInGetDevCaps16(hWaveIn, (LPWAVEINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4548 return waveInGetPosition16(hWaveIn, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4550 return waveInPrepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4551 case WIDM_UNPREPARE:
4552 return waveInUnprepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4553 case WIDM_ADDBUFFER:
4554 return waveInAddBuffer16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4556 ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
4557 hWaveIn, uMessage, dwParam1, dwParam2);
4560 return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4563 /**************************************************************************
4564 * DrvOpen [MMSYSTEM.1100]
4566 HDRVR16 WINAPI DrvOpen(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam)
4568 TRACE(mmsys, "('%s','%s', %08lX);\n", lpDriverName, lpSectionName, lParam);
4570 return OpenDriver16(lpDriverName, lpSectionName, lParam);
4573 /**************************************************************************
4574 * DrvClose [MMSYSTEM.1101]
4576 LRESULT WINAPI DrvClose(HDRVR16 hDrv, LPARAM lParam1, LPARAM lParam2)
4578 TRACE(mmsys, "(%04X, %08lX, %08lX);\n", hDrv, lParam1, lParam2);
4580 return CloseDriver16(hDrv, lParam1, lParam2);
4583 /**************************************************************************
4584 * DrvSendMessage [MMSYSTEM.1102]
4586 LRESULT WINAPI DrvSendMessage(HDRVR16 hDrv, WORD msg, LPARAM lParam1,
4589 return SendDriverMessage(hDrv, msg, lParam1, lParam2);
4592 /**************************************************************************
4593 * DrvGetModuleHandle [MMSYSTEM.1103]
4595 HANDLE16 WINAPI DrvGetModuleHandle16(HDRVR16 hDrv)
4597 return GetDriverModuleHandle16(hDrv);
4600 /**************************************************************************
4601 * DrvDefDriverProc [MMSYSTEM.1104]
4603 LRESULT WINAPI DrvDefDriverProc(DWORD dwDriverID, HDRVR16 hDrv, WORD wMsg,
4604 DWORD dwParam1, DWORD dwParam2)
4606 /* FIXME : any mapping from 32 to 16 bit structure ? */
4607 return DefDriverProc16(dwDriverID, hDrv, wMsg, dwParam1, dwParam2);
4610 /**************************************************************************
4611 * DefDriverProc [WINMM.5]
4613 LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR hDrv,
4614 UINT Msg, LPARAM lParam1, LPARAM lParam2)
4630 /*#define USE_MM_TSK_WINE*/
4632 /**************************************************************************
4633 * mmTaskCreate [MMSYSTEM.900]
4635 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4636 * called upon creation with dwPmt as parameter.
4638 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4640 DWORD showCmd = 0x40002;
4647 TRACE(mmsys, "(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
4648 /* This to work requires NE modules to be started with a binary command line
4649 * which is not currently the case. A patch exists but has never been committed.
4650 * A workaround would be to integrate code for mmtask.tsk into Wine, but
4651 * this requires tremendous work (starting with patching tools/build to
4652 * create NE executables (and not only DLLs) for builtins modules.
4655 FIXME(mmsys, "This is currently broken. It will fail\n");
4657 cmdline = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 0x0d);
4659 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
4660 *(LPDWORD)(cmdline + 5) = dwPmt;
4661 *(LPDWORD)(cmdline + 9) = 0;
4663 sel1 = SELECTOR_AllocBlock(cmdline, 0x0d, SEGMENT_DATA, FALSE, FALSE);
4664 sel2 = SELECTOR_AllocBlock(&showCmd, sizeof(showCmd),
4665 SEGMENT_DATA, FALSE, FALSE);
4667 lp = (LOADPARAMS16*)HeapAlloc(GetProcessHeap(), 0, sizeof(LOADPARAMS16));
4668 lp->hEnvironment = 0;
4669 lp->cmdLine = PTR_SEG_OFF_TO_SEGPTR(sel1, 0);
4670 lp->showCmd = PTR_SEG_OFF_TO_SEGPTR(sel2, 0);
4673 #ifndef USE_MM_TSK_WINE
4674 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", lp);
4676 handle = LoadModule16("mmtask.tsk", lp);
4679 ret = (handle) ? 1 : 2;
4685 *lphMmTask = handle;
4687 UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel2, 0));
4688 UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel1, 0));
4690 HeapFree(GetProcessHeap(), 0, lp);
4691 HeapFree(GetProcessHeap(), 0, cmdline);
4693 TRACE(mmsys, "=> 0x%04x/%d\n", handle, ret);
4697 #ifdef USE_MM_TSK_WINE
4698 /* C equivalent to mmtask.tsk binary content */
4699 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
4701 int len = cmdLine[0x80];
4704 void (*fpProc)(DWORD) = (void (*)(DWORD))PTR_SEG_TO_LIN(*((DWORD*)(cmdLine + 1)));
4705 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
4708 InitTask16(); /* fixme: pmts / from context ? */
4711 if (SetMessageQueue16(0x40)) {
4713 if (HIWORD(fpProc)) {
4715 /* EPP StackEnter16(); */
4727 /**************************************************************************
4728 * mmTaskBlock [MMSYSTEM.902]
4730 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
4735 GetMessageA(&msg, 0, 0, 0);
4737 TranslateMessage(&msg);
4738 DispatchMessageA(&msg);
4740 } while (msg.message < 0x3A0);
4743 /**************************************************************************
4744 * mmTaskSignal [MMSYSTEM.903]
4746 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
4748 TRACE(mmsys, "(%04x);\n", ht);
4749 return Callout.PostAppMessage16(ht, WM_USER, 0, 0);
4752 /**************************************************************************
4753 * mmTaskYield16 [MMSYSTEM.905]
4755 void WINAPI mmTaskYield16(void)
4759 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
4764 DWORD WINAPI GetProcessFlags(DWORD);
4766 /**************************************************************************
4767 * mmThreadCreate [MMSYSTEM.1120]
4770 * Creates a MM thread, calling fpThreadAddr(dwPmt).
4772 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
4773 * bit.1 set means to open a VxD for this thread (unsupported)
4775 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
4780 TRACE(mmsys, "(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
4782 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
4787 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4790 /* force mmtask routines even if mmthread is required */
4791 /* this will work only if the patch about binary cmd line and NE tasks
4797 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
4798 lpMMThd->dwCounter = 0;
4799 lpMMThd->hThread = 0;
4800 lpMMThd->dwThreadID = 0;
4801 lpMMThd->fpThread = fpThreadAddr;
4802 lpMMThd->dwThreadPmt = dwPmt;
4803 lpMMThd->dwSignalCount = 0;
4804 lpMMThd->hEvent = 0;
4806 lpMMThd->dwStatus = 0;
4807 lpMMThd->dwFlags = dwFlags;
4810 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
4811 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
4813 TRACE(mmsys, "Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
4814 if (lpMMThd->dwFlags & 2) {
4815 /* as long as we don't support MM VxD in wine, we don't need
4816 * to care about this flag
4818 /* FIXME(mmsys, "Don't know how to properly open VxD handles\n"); */
4819 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
4822 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
4823 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
4824 if (lpMMThd->hThread == 0) {
4825 WARN(mmsys, "Couldn't create thread\n");
4826 /* clean-up(VxDhandle...); devicedirectio... */
4827 if (lpMMThd->hEvent != 0)
4828 CloseHandle(lpMMThd->hEvent);
4831 TRACE(mmsys, "Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
4835 /* get WINE_mmThreadEntryPoint()
4836 * 2047 is its ordinal in mmsystem.spec
4838 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (SEGPTR)2047);
4840 TRACE(mmsys, "farproc seg=0x%08lx lin=%p\n", (DWORD)fp, PTR_SEG_TO_LIN(fp));
4842 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
4846 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
4847 WARN(mmsys, "Couldn't resume thread\n");
4849 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
4863 TRACE(mmsys, "ok => %ld\n", ret);
4867 /**************************************************************************
4868 * mmThreadSignal [MMSYSTEM.1121]
4870 void WINAPI mmThreadSignal16(HANDLE16 hndl)
4872 TRACE(mmsys, "(%04x)!\n", hndl);
4875 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4877 lpMMThd->dwCounter++;
4878 if (lpMMThd->hThread != 0) {
4879 InterlockedIncrement(&lpMMThd->dwSignalCount);
4880 SetEvent(lpMMThd->hEvent);
4882 mmTaskSignal16(lpMMThd->hTask);
4884 lpMMThd->dwCounter--;
4888 /**************************************************************************
4889 * MMSYSTEM_ThreadBlock [internal]
4891 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
4896 if (lpMMThd->dwThreadID != GetCurrentThreadId())
4897 ERR(mmsys, "Not called by thread itself\n");
4900 ResetEvent(lpMMThd->hEvent);
4901 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
4903 InterlockedIncrement(&lpMMThd->dwSignalCount);
4905 TRACE(mmsys, "S1\n");
4907 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
4909 case WAIT_OBJECT_0: /* Event */
4910 TRACE(mmsys, "S2.1\n");
4912 case WAIT_OBJECT_0 + 1: /* Msg */
4913 TRACE(mmsys, "S2.2\n");
4914 if (Callout.PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
4915 Callout.TranslateMessage(&msg);
4916 Callout.DispatchMessageA(&msg);
4920 WARN(mmsys, "S2.x unsupported ret val 0x%08lx\n", ret);
4922 TRACE(mmsys, "S3\n");
4926 /**************************************************************************
4927 * mmThreadBlock [MMSYSTEM.1122]
4929 void WINAPI mmThreadBlock16(HANDLE16 hndl)
4931 TRACE(mmsys, "(%04x)!\n", hndl);
4934 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4936 if (lpMMThd->hThread != 0) {
4937 SYSLEVEL_ReleaseWin16Lock();
4938 MMSYSTEM_ThreadBlock(lpMMThd);
4939 SYSLEVEL_RestoreWin16Lock();
4941 mmTaskBlock16(lpMMThd->hTask);
4944 TRACE(mmsys, "done\n");
4947 /**************************************************************************
4948 * mmThreadIsCurrent [MMSYSTEM.1123]
4950 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
4954 TRACE(mmsys, "(%04x)!\n", hndl);
4956 if (hndl && mmThreadIsValid16(hndl)) {
4957 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4958 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
4959 /* FIXME: just a test */
4960 SYSLEVEL_ReleaseWin16Lock();
4961 SYSLEVEL_RestoreWin16Lock();
4963 TRACE(mmsys, "=> %d\n", ret);
4967 /**************************************************************************
4968 * mmThreadIsValid [MMSYSTEM.1124]
4970 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
4974 TRACE(mmsys, "(%04x)!\n", hndl);
4977 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
4979 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
4980 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
4981 IsTask16(lpMMThd->hTask)) {
4982 lpMMThd->dwCounter++;
4983 if (lpMMThd->hThread != 0) {
4985 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
4986 dwThreadRet == STATUS_PENDING) {
4992 lpMMThd->dwCounter--;
4995 TRACE(mmsys, "=> %d\n", ret);
4999 /**************************************************************************
5000 * mmThreadGetTask [MMSYSTEM.1125]
5002 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5006 TRACE(mmsys, "(%04x)\n", hndl);
5008 if (mmThreadIsValid16(hndl)) {
5009 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5010 ret = lpMMThd->hTask;
5015 /**************************************************************************
5016 * mmThreadGetTask [internal]
5018 void WINAPI WINE_mmThreadEntryPoint(DWORD _pmt)
5020 HANDLE16 hndl = (HANDLE16)_pmt;
5021 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5022 CRITICAL_SECTION* cs;
5024 TRACE(mmsys, "(%04x %p)\n", hndl, lpMMThd);
5028 TRACE(mmsys, "lc=%ld rc=%ld ot=%08lx\n", cs->LockCount, cs->RecursionCount, (DWORD)cs->OwningThread);
5030 lpMMThd->hTask = LOWORD(GetCurrentTask());
5031 TRACE(mmsys, "[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5032 lpMMThd->dwStatus = 0x10;
5033 MMSYSTEM_ThreadBlock(lpMMThd);
5034 TRACE(mmsys, "[20-%08x]\n", lpMMThd->hThread);
5035 lpMMThd->dwStatus = 0x20;
5036 if (lpMMThd->fpThread) {
5038 extern DWORD CALLBACK CallTo16_long_l_x(FARPROC16, DWORD);
5039 TRACE(mmsys, "Calling %08lx(%08lx)\n", (DWORD)lpMMThd->fpThread, lpMMThd->dwThreadPmt);$
5040 CallTo16_long_l_x(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5042 Callbacks->CallWOWCallbackProc(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5045 lpMMThd->dwStatus = 0x30;
5046 TRACE(mmsys, "[30-%08x]\n", lpMMThd->hThread);
5047 while (lpMMThd->dwCounter) {
5051 TRACE(mmsys, "[XX-%08x]\n", lpMMThd->hThread);
5053 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5054 /* close lpMMThread->hVxD directio */
5055 if (lpMMThd->hEvent)
5056 CloseHandle(lpMMThd->hEvent);
5058 TRACE(mmsys, "lc=%ld rc=%ld ot=%08lx\n", cs->LockCount, cs->RecursionCount, (DWORD)cs->OwningThread);
5059 TRACE(mmsys, "done\n");
5062 /**************************************************************************
5063 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5065 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, char* lpStrDevice,
5066 char* lpStrTab, char* lpStrTitle)
5071 TRACE(mmsys, "(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5073 hndl = LoadLibraryA("MMSYS.CPL");
5075 BOOL16 (WINAPI *fp)(HWND, LPSTR, LPSTR, LPSTR);
5077 fp = (BOOL16 (WINAPI *)(HWND, LPSTR, LPSTR, LPSTR))GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5079 /* FIXME: wine hangs and/or seg faults in this call,
5080 * after the window is correctly displayed
5082 TRACE(mmsys, "Ready to go ThreadID=%08lx\n", GetCurrentThreadId());
5083 SYSLEVEL_ReleaseWin16Lock();
5084 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5085 SYSLEVEL_RestoreWin16Lock();
5093 /**************************************************************************
5094 * StackEnter & StackLeave [MMSYSTEM.32][MMSYSTEM.33]
5096 void WINAPI StackEnterLeave16(void)
5099 /* mmsystem.dll from Win 95 does only this: so does Wine */