1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1993 Martin Ayotte
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * 98/9 added Win32 MCI support
26 * 99/4 added mmTask and mmThread functions support
27 * added midiStream support
28 * 99/9 added support for loadable low level drivers
31 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses
32 * and long term pointers to 16 bit space in here
41 #include "wine/mmsystem16.h"
42 #include "wine/winuser16.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(mmsys);
51 static LPWINE_MM_IDATA lpFirstIData = NULL;
53 static LPWINE_MM_IDATA MULTIMEDIA_GetIDataNoCheck(void)
55 DWORD pid = GetCurrentProcessId();
56 LPWINE_MM_IDATA iData;
58 for (iData = lpFirstIData; iData; iData = iData->lpNextIData) {
59 if (iData->dwThisProcess == pid)
65 /**************************************************************************
66 * MULTIMEDIA_GetIData [internal]
68 LPWINE_MM_IDATA MULTIMEDIA_GetIData(void)
70 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
73 ERR("IData not found for pid=%08lx. Suicide !!!\n", GetCurrentProcessId());
80 /**************************************************************************
81 * MULTIMEDIA_CreateIData [internal]
83 static BOOL MULTIMEDIA_CreateIData(HINSTANCE hInstDLL)
85 LPWINE_MM_IDATA iData;
87 iData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
91 iData->hWinMM32Instance = hInstDLL;
92 iData->dwThisProcess = GetCurrentProcessId();
93 iData->lpNextIData = lpFirstIData;
95 InitializeCriticalSection(&iData->cs);
96 TRACE("Created IData (%p) for pid %08lx\n", iData, iData->dwThisProcess);
100 /**************************************************************************
101 * MULTIMEDIA_DeleteIData [internal]
103 static void MULTIMEDIA_DeleteIData(void)
105 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
106 LPWINE_MM_IDATA* ppid;
111 for (ppid = &lpFirstIData; *ppid; ppid = &(*ppid)->lpNextIData) {
112 if (*ppid == iData) {
113 *ppid = iData->lpNextIData;
117 /* FIXME: should also free content and resources allocated
119 HeapFree(GetProcessHeap(), 0, iData);
123 /**************************************************************************
124 * DllEntryPoint (WINMM.init)
126 * WINMM DLL entry point
129 BOOL WINAPI WINMM_LibMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
131 TRACE("0x%x 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
134 case DLL_PROCESS_ATTACH:
135 if (!MULTIMEDIA_CreateIData(hInstDLL))
137 if (!MULTIMEDIA_MciInit() || !MMDRV_Init()) {
138 MULTIMEDIA_DeleteIData();
142 case DLL_PROCESS_DETACH:
143 MULTIMEDIA_DeleteIData();
145 case DLL_THREAD_ATTACH:
146 case DLL_THREAD_DETACH:
152 /**************************************************************************
153 * DllEntryPoint (MMSYSTEM.2046)
155 * MMSYSTEM DLL entry point
158 BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds,
159 WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
162 LPWINE_MM_IDATA iData;
164 TRACE("0x%x 0x%lx\n", hinstDLL, fdwReason);
167 case DLL_PROCESS_ATTACH:
168 /* need to load WinMM in order to:
169 * - initiate correctly shared variables (MULTIMEDIA_Init())
170 * - create correctly the per process WINE_MM_IDATA chunk
172 hndl = LoadLibraryA("WINMM.DLL");
175 ERR("Could not load sibling WinMM.dll\n");
178 iData = MULTIMEDIA_GetIData();
179 iData->hWinMM16Instance = hinstDLL;
180 iData->h16Module32 = hndl;
182 case DLL_PROCESS_DETACH:
183 iData = MULTIMEDIA_GetIData();
184 FreeLibrary(iData->h16Module32);
186 case DLL_THREAD_ATTACH:
187 case DLL_THREAD_DETACH:
193 /**************************************************************************
194 * MMSYSTEM_WEP [MMSYSTEM.1]
196 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
197 WORD cbHeapSize, LPSTR lpCmdLine)
199 FIXME("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
203 void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
205 mmt16->wType = mmt32->wType;
206 /* layout of rest is the same for 32/16,
207 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
209 memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
212 void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
214 mmt32->wType = mmt16->wType;
215 /* layout of rest is the same for 32/16,
216 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
218 memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
221 static HMMIO get_mmioFromFile(LPCWSTR lpszName)
223 return mmioOpenW((LPWSTR)lpszName, NULL,
224 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
227 static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName)
232 static WCHAR wszSounds[] = {'S','o','u','n','d','s',0};
233 static WCHAR wszDefault[] = {'D','e','f','a','u','l','t',0};
234 static WCHAR wszNull[] = {0};
235 TRACE("searching in SystemSound List !\n");
236 GetProfileStringW(wszSounds, (LPWSTR)lpszName, wszNull, str, sizeof(str)/sizeof(str[0]));
237 if (lstrlenW(str) == 0) {
238 if (uFlags & SND_NODEFAULT) return 0;
239 GetProfileStringW(wszSounds, wszDefault, wszNull, str, sizeof(str)/sizeof(str[0]));
240 if (lstrlenW(str) == 0) return 0;
242 for (ptr = str; *ptr && *ptr != ','; ptr++);
244 hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
246 WARN("can't find SystemSound='%s' !\n", debugstr_w(str));
252 struct playsound_data
258 static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg,
260 DWORD dwParam1, DWORD dwParam2)
262 struct playsound_data* s = (struct playsound_data*)dwInstance;
269 InterlockedIncrement(&s->dwEventCount);
270 TRACE("Returning waveHdr=%lx\n", dwParam1);
274 ERR("Unknown uMsg=%d\n", uMsg);
278 static void PlaySound_WaitDone(struct playsound_data* s)
281 ResetEvent(s->hEvent);
282 if (InterlockedDecrement(&s->dwEventCount) >= 0) break;
283 InterlockedIncrement(&s->dwEventCount);
285 WaitForSingleObject(s->hEvent, INFINITE);
289 static DWORD WINAPI proc_PlaySound(LPVOID arg)
291 WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg;
292 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
297 LPWAVEFORMATEX lpWaveFormat = NULL;
299 LPWAVEHDR waveHdr = NULL;
300 INT count, bufsize, left, index;
301 struct playsound_data s;
306 TRACE("SoundName='%s' !\n", debugstr_w(wps->pszSound));
308 /* if resource, grab it */
309 if ((wps->fdwSound & SND_RESOURCE) == SND_RESOURCE) {
310 static WCHAR wszWave[] = {'W','A','V','E',0};
314 if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 ||
315 (hGlob = LoadResource(wps->hMod, hRes)) == 0) {
318 if ((data = LockResource(hGlob)) == NULL) {
324 data = (void*)wps->pszSound;
326 /* construct an MMIO stream (either in memory, or from a file */
327 if (wps->fdwSound & SND_MEMORY) { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */
330 memset(&mminfo, 0, sizeof(mminfo));
331 mminfo.fccIOProc = FOURCC_MEM;
332 mminfo.pchBuffer = (LPSTR)data;
333 mminfo.cchBuffer = -1; /* FIXME: when a resource, could grab real size */
334 TRACE("Memory sound %p\n", data);
335 hmmio = mmioOpenW(NULL, &mminfo, MMIO_READ);
338 if (wps->fdwSound & SND_ALIAS)
339 if ((hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound)) == 0)
342 if (wps->fdwSound & SND_FILENAME)
343 if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0) return FALSE;
345 switch (wps->searchMode) {
347 if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0)
348 hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
351 if ((hmmio = get_mmioFromProfile(wps->fdwSound | SND_NODEFAULT, wps->pszSound)) == 0)
352 if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0)
353 hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
357 if (hmmio == 0) return FALSE;
359 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0))
362 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
363 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
365 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
366 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
369 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
370 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
373 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
374 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
376 lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
377 if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT))
380 TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag);
381 TRACE("nChannels=%d \n", lpWaveFormat->nChannels);
382 TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec);
383 TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec);
384 TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign);
385 TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample);
387 /* move to end of 'fmt ' chunk */
388 mmioAscend(hmmio, &mmckInfo, 0);
390 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
391 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
394 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
395 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
397 s.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
399 if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback,
400 (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
403 /* make it so that 3 buffers per second are needed */
404 bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) *
405 lpWaveFormat->nBlockAlign;
406 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
407 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
408 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
409 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
410 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
411 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
412 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
413 if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
414 waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) {
420 left = mmckInfo.cksize;
421 s.dwEventCount = 1L; /* for first buffer */
423 mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
426 wps->bStop = wps->bLoop = FALSE;
429 count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
430 if (count < 1) break;
432 waveHdr[index].dwBufferLength = count;
433 waveHdr[index].dwFlags &= ~WHDR_DONE;
434 if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) {
436 PlaySound_WaitDone(&s);
438 else FIXME("Couldn't play header\n");
441 } while (wps->bLoop);
443 PlaySound_WaitDone(&s); /* for last buffer */
446 waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
447 waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
450 CloseHandle(s.hEvent);
451 HeapFree(GetProcessHeap(), 0, waveHdr);
452 HeapFree(GetProcessHeap(), 0, lpWaveFormat);
453 if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
454 if (hmmio) mmioClose(hmmio, 0);
456 SetEvent(wps->hReadyEvent);
457 iData->lpPlaySound = NULL;
459 /* when filename: HeapFree(GetProcessHeap(), 0, wps->pszSound); */
460 CloseHandle(wps->hReadyEvent);
461 HeapFree(GetProcessHeap(), 0, wps);
466 static BOOL MULTIMEDIA_PlaySound(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound, DWORD search)
468 WINE_PLAYSOUND* wps = NULL;
470 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
473 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
474 pszSound, hmod, fdwSound);
476 /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP !
477 * there could be one if several sounds can be played at once...
479 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound)
485 /* Trying to stop if playing */
486 EnterCriticalSection(&iData->cs);
487 if (iData->lpPlaySound) {
488 LPWINE_PLAYSOUND ps2stop = iData->lpPlaySound;
490 hEvt = ps2stop->hReadyEvent;
491 ps2stop->bStop = TRUE;
493 LeaveCriticalSection(&iData->cs);
494 /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave
495 * FIXME: race here (if hEvt is destroyed and reallocated - as a handle - to
496 * another object)... unlikely but possible
498 if (hEvt) WaitForSingleObject(hEvt, 1000*10);
500 if (!pszSound || (fdwSound & SND_PURGE))
501 return TRUE; /* We stopped playing so leaving */
505 wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps));
506 if (!wps) return FALSE;
508 wps->searchMode = search;
510 wps->fdwSound = fdwSound;
511 wps->pszSound = pszSound;
512 if ((wps->hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
515 } while (InterlockedCompareExchangePointer((void**)&iData->lpPlaySound, wps, NULL) != NULL);
517 if (fdwSound & SND_ASYNC) {
518 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
519 !((DWORD)pszSound >> 16)) ||
521 wps->pszSound = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pszSound)+1) * sizeof(WCHAR) );
522 lstrcpyW((LPWSTR)wps->pszSound, pszSound);
524 wps->bLoop = fdwSound & SND_LOOP;
525 /* FIXME: memory leak in case of error & cs is still lock */
526 if ((wps->hThread = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) == 0)
532 bRet = proc_PlaySound(wps);
537 /**************************************************************************
538 * PlaySoundA [WINMM.@]
540 BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound)
545 if (!((fdwSound & SND_MEMORY) ||
546 ((fdwSound & SND_RESOURCE) && !((DWORD)pszSoundA >> 16)) ||
548 pszSoundW = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSoundA);
549 bSound = PlaySoundW(pszSoundW, hmod, fdwSound);
550 HeapFree(GetProcessHeap(), 0, pszSoundW);
552 bSound = PlaySoundW((LPWSTR)pszSoundA, hmod, fdwSound);
557 /**************************************************************************
558 * PlaySoundW [WINMM.@]
560 BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
562 return MULTIMEDIA_PlaySound(pszSound, hmod, fdwSound, 2);
565 /**************************************************************************
566 * PlaySound [MMSYSTEM.3]
568 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
573 ReleaseThunkLock(&lc);
574 retv = PlaySoundA(pszSound, hmod, fdwSound);
575 RestoreThunkLock(lc);
580 /**************************************************************************
581 * sndPlaySoundA [WINMM.@]
583 BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags)
588 if (!((uFlags & SND_MEMORY) ||
589 ((uFlags & SND_RESOURCE) && !((DWORD)pszSoundA >> 16)) ||
591 pszSoundW = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSoundA);
592 bSound = sndPlaySoundW(pszSoundW, uFlags);
593 HeapFree(GetProcessHeap(), 0, pszSoundW);
595 bSound = sndPlaySoundW((LPWSTR)pszSoundA, uFlags);
600 /**************************************************************************
601 * sndPlaySoundW [WINMM.@]
603 BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags)
605 return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, 1);
608 /**************************************************************************
609 * sndPlaySound [MMSYSTEM.2]
611 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
616 ReleaseThunkLock(&lc);
617 retv = sndPlaySoundA(lpszSoundName, uFlags);
618 RestoreThunkLock(lc);
623 /**************************************************************************
624 * mmsystemGetVersion [MMSYSTEM.5]
625 * return value borrowed from Win95 winmm.dll ;)
627 UINT16 WINAPI mmsystemGetVersion16(void)
629 return mmsystemGetVersion();
632 /**************************************************************************
633 * mmsystemGetVersion [WINMM.@]
635 UINT WINAPI mmsystemGetVersion(void)
637 TRACE("3.10 (Win95?)\n");
641 /**************************************************************************
642 * DriverCallback [WINMM.@]
644 BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
645 UINT wMsg, DWORD dwUser, DWORD dwParam1,
648 TRACE("(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
649 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
651 switch (uFlags & DCB_TYPEMASK) {
655 WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack);
658 TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
659 PostMessageA((HWND)dwCallBack, wMsg, hDev, dwParam1);
661 case DCB_TASK: /* aka DCB_THREAD */
662 TRACE("Task(%04lx) !\n", dwCallBack);
663 PostThreadMessageA(dwCallBack, wMsg, hDev, dwParam1);
666 TRACE("Function (32 bit) !\n");
667 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
670 TRACE("Event(%08lx) !\n", dwCallBack);
671 SetEvent((HANDLE)dwCallBack);
673 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
674 /* this is an undocumented DCB_ value used for mmThreads
675 * loword of dwCallBack contains the handle of the lpMMThd block
676 * which dwSignalCount has to be incremented
679 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(LOWORD(dwCallBack), 0) );
681 TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
682 /* same as mmThreadSignal16 */
683 InterlockedIncrement(&lpMMThd->dwSignalCount);
684 SetEvent(lpMMThd->hEvent);
685 /* some other stuff on lpMMThd->hVxD */
690 /* this is an undocumented DCB_ value for... I don't know */
694 WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
701 /**************************************************************************
702 * DriverCallback [MMSYSTEM.31]
704 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev,
705 WORD wMsg, DWORD dwUser, DWORD dwParam1,
708 return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
711 /**************************************************************************
712 * Mixer devices. New to Win95
715 /**************************************************************************
716 * find out the real mixer ID depending on hmix (depends on dwFlags)
718 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
720 LPWINE_MIXER lpwm = NULL;
722 switch (dwFlags & 0xF0000000ul) {
723 case MIXER_OBJECTF_MIXER:
724 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
726 case MIXER_OBJECTF_HMIXER:
727 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
729 case MIXER_OBJECTF_WAVEOUT:
730 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
732 case MIXER_OBJECTF_HWAVEOUT:
733 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
735 case MIXER_OBJECTF_WAVEIN:
736 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
738 case MIXER_OBJECTF_HWAVEIN:
739 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
741 case MIXER_OBJECTF_MIDIOUT:
742 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
744 case MIXER_OBJECTF_HMIDIOUT:
745 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
747 case MIXER_OBJECTF_MIDIIN:
748 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
750 case MIXER_OBJECTF_HMIDIIN:
751 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
753 case MIXER_OBJECTF_AUX:
754 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
757 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
763 /**************************************************************************
764 * mixerGetNumDevs [WINMM.@]
766 UINT WINAPI mixerGetNumDevs(void)
768 return MMDRV_GetNum(MMDRV_MIXER);
771 /**************************************************************************
772 * mixerGetNumDevs [MMSYSTEM.800]
774 UINT16 WINAPI mixerGetNumDevs16(void)
776 return MMDRV_GetNum(MMDRV_MIXER);
779 /**************************************************************************
780 * mixerGetDevCapsA [WINMM.@]
782 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
786 if ((wmld = MMDRV_Get(devid, MMDRV_MIXER, TRUE)) == NULL)
787 return MMSYSERR_BADDEVICEID;
789 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
792 /**************************************************************************
793 * mixerGetDevCapsW [WINMM.@]
795 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
798 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
800 if (ret == MMSYSERR_NOERROR) {
801 mixcaps->wMid = micA.wMid;
802 mixcaps->wPid = micA.wPid;
803 mixcaps->vDriverVersion = micA.vDriverVersion;
804 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
805 sizeof(mixcaps->szPname)/sizeof(WCHAR) );
806 mixcaps->fdwSupport = micA.fdwSupport;
807 mixcaps->cDestinations = micA.cDestinations;
812 /**************************************************************************
813 * mixerGetDevCaps [MMSYSTEM.801]
815 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps,
819 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
821 if (ret == MMSYSERR_NOERROR) {
822 mixcaps->wMid = micA.wMid;
823 mixcaps->wPid = micA.wPid;
824 mixcaps->vDriverVersion = micA.vDriverVersion;
825 strcpy(mixcaps->szPname, micA.szPname);
826 mixcaps->fdwSupport = micA.fdwSupport;
827 mixcaps->cDestinations = micA.cDestinations;
832 static UINT MMSYSTEM_mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
833 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
840 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
841 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
843 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
844 &dwCallback, &dwInstance, bFrom32);
846 wmld->uDeviceID = uDeviceID;
848 mod.dwCallback = dwCallback;
849 mod.dwInstance = dwInstance;
851 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
853 if (dwRet != MMSYSERR_NOERROR) {
854 MMDRV_Free(hMix, wmld);
857 if (lphMix) *lphMix = hMix;
858 TRACE("=> %ld hMixer=%04x\n", dwRet, hMix);
863 /**************************************************************************
864 * mixerOpen [WINMM.@]
866 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
867 DWORD dwInstance, DWORD fdwOpen)
869 return MMSYSTEM_mixerOpen(lphMix, uDeviceID,
870 dwCallback, dwInstance, fdwOpen, TRUE);
873 /**************************************************************************
874 * mixerOpen [MMSYSTEM.802]
876 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
877 DWORD dwInstance, DWORD fdwOpen)
882 ret = MMSYSTEM_mixerOpen(&hmix, uDeviceID,
883 dwCallback, dwInstance, fdwOpen, FALSE);
884 if (lphmix) *lphmix = hmix;
888 /**************************************************************************
889 * mixerClose [WINMM.@]
891 UINT WINAPI mixerClose(HMIXER hMix)
896 TRACE("(%04x)\n", hMix);
898 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
900 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
901 MMDRV_Free(hMix, wmld);
906 /**************************************************************************
907 * mixerClose [MMSYSTEM.803]
909 UINT16 WINAPI mixerClose16(HMIXER16 hMix)
911 return mixerClose(hMix);
914 /**************************************************************************
915 * mixerGetID [WINMM.@]
917 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
921 TRACE("(%04x %p %08lx)\n", hmix, lpid, fdwID);
923 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
924 return MMSYSERR_INVALHANDLE;
928 *lpid = lpwm->mld.uDeviceID;
930 return MMSYSERR_NOERROR;
933 /**************************************************************************
934 * mixerGetID (MMSYSTEM.806)
936 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
939 UINT ret = mixerGetID(hmix, &xid, fdwID);
946 /**************************************************************************
947 * mixerGetControlDetailsA [WINMM.@]
949 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
954 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
956 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
957 return MMSYSERR_INVALHANDLE;
959 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
960 return MMSYSERR_INVALPARAM;
962 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
966 /**************************************************************************
967 * mixerGetControlDetailsW [WINMM.@]
969 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
971 DWORD ret = MMSYSERR_NOTENABLED;
973 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
975 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
976 return MMSYSERR_INVALPARAM;
978 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
979 case MIXER_GETCONTROLDETAILSF_VALUE:
980 /* can savely use W structure as it is, no string inside */
981 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
983 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
985 LPVOID paDetailsW = lpmcd->paDetails;
986 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
988 if (lpmcd->u.cMultipleItems != 0 && lpmcd->u.cMultipleItems != lpmcd->u.hwndOwner) {
989 size *= lpmcd->u.cMultipleItems;
991 lpmcd->paDetails = HeapAlloc(GetProcessHeap(), 0, size);
992 /* set up lpmcd->paDetails */
993 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
994 /* copy from lpmcd->paDetails back to paDetailsW; */
995 HeapFree(GetProcessHeap(), 0, lpmcd->paDetails);
996 lpmcd->paDetails = paDetailsW;
1000 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
1006 /**************************************************************************
1007 * mixerGetControlDetails [MMSYSTEM.808]
1009 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix,
1010 LPMIXERCONTROLDETAILS16 lpmcd,
1013 DWORD ret = MMSYSERR_NOTENABLED;
1016 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1018 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1019 return MMSYSERR_INVALPARAM;
1021 sppaDetails = (SEGPTR)lpmcd->paDetails;
1022 lpmcd->paDetails = MapSL(sppaDetails);
1023 ret = mixerGetControlDetailsA(hmix, (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails);
1024 lpmcd->paDetails = (LPVOID)sppaDetails;
1029 /**************************************************************************
1030 * mixerGetLineControlsA [WINMM.@]
1032 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
1037 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
1039 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
1040 return MMSYSERR_INVALHANDLE;
1042 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
1043 return MMSYSERR_INVALPARAM;
1045 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
1049 /**************************************************************************
1050 * mixerGetLineControlsW [WINMM.@]
1052 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
1055 MIXERLINECONTROLSA mlcA;
1059 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
1061 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
1062 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
1063 return MMSYSERR_INVALPARAM;
1065 mlcA.cbStruct = sizeof(mlcA);
1066 mlcA.dwLineID = lpmlcW->dwLineID;
1067 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
1068 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
1069 mlcA.cControls = lpmlcW->cControls;
1070 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1071 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1072 mlcA.cControls * mlcA.cbmxctrl);
1074 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
1076 if (ret == MMSYSERR_NOERROR) {
1077 lpmlcW->dwLineID = mlcA.dwLineID;
1078 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
1079 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
1080 lpmlcW->cControls = mlcA.cControls;
1082 for (i = 0; i < mlcA.cControls; i++) {
1083 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
1084 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1085 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1086 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1087 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1088 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
1089 lpmlcW->pamxctrl[i].szShortName,
1090 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
1091 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
1092 lpmlcW->pamxctrl[i].szName,
1093 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
1094 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
1095 * sizeof(mlcA.pamxctrl[i].Bounds) */
1096 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1097 sizeof(mlcA.pamxctrl[i].Bounds));
1098 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
1099 * sizeof(mlcA.pamxctrl[i].Metrics) */
1100 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1101 sizeof(mlcA.pamxctrl[i].Metrics));
1105 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1110 /**************************************************************************
1111 * mixerGetLineControls [MMSYSTEM.807]
1113 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix,
1114 LPMIXERLINECONTROLS16 lpmlc16,
1117 MIXERLINECONTROLSA mlcA;
1120 LPMIXERCONTROL16 lpmc16;
1122 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls);
1124 if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) ||
1125 lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16))
1126 return MMSYSERR_INVALPARAM;
1128 mlcA.cbStruct = sizeof(mlcA);
1129 mlcA.dwLineID = lpmlc16->dwLineID;
1130 mlcA.u.dwControlID = lpmlc16->u.dwControlID;
1131 mlcA.u.dwControlType = lpmlc16->u.dwControlType;
1132 mlcA.cControls = lpmlc16->cControls;
1133 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1134 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1135 mlcA.cControls * mlcA.cbmxctrl);
1137 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
1139 if (ret == MMSYSERR_NOERROR) {
1140 lpmlc16->dwLineID = mlcA.dwLineID;
1141 lpmlc16->u.dwControlID = mlcA.u.dwControlID;
1142 lpmlc16->u.dwControlType = mlcA.u.dwControlType;
1143 lpmlc16->cControls = mlcA.cControls;
1145 lpmc16 = MapSL(lpmlc16->pamxctrl);
1147 for (i = 0; i < mlcA.cControls; i++) {
1148 lpmc16[i].cbStruct = sizeof(MIXERCONTROL16);
1149 lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1150 lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1151 lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1152 lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1153 strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName);
1154 strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName);
1155 /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
1156 memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1157 sizeof(mlcA.pamxctrl[i].Bounds));
1158 /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
1159 memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1160 sizeof(mlcA.pamxctrl[i].Metrics));
1164 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1169 /**************************************************************************
1170 * mixerGetLineInfoA [WINMM.@]
1172 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
1176 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1178 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
1179 return MMSYSERR_INVALHANDLE;
1181 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
1185 /**************************************************************************
1186 * mixerGetLineInfoW [WINMM.@]
1188 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
1194 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1196 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
1197 return MMSYSERR_INVALPARAM;
1199 mliA.cbStruct = sizeof(mliA);
1200 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1201 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1202 mliA.dwComponentType = lpmliW->dwComponentType;
1204 case MIXER_GETLINEINFOF_DESTINATION:
1205 mliA.dwDestination = lpmliW->dwDestination;
1207 case MIXER_GETLINEINFOF_LINEID:
1208 mliA.dwLineID = lpmliW->dwLineID;
1210 case MIXER_GETLINEINFOF_SOURCE:
1211 mliA.dwDestination = lpmliW->dwDestination;
1212 mliA.dwSource = lpmliW->dwSource;
1214 case MIXER_GETLINEINFOF_TARGETTYPE:
1215 mliA.Target.dwType = lpmliW->Target.dwType;
1216 mliA.Target.wMid = lpmliW->Target.wMid;
1217 mliA.Target.wPid = lpmliW->Target.wPid;
1218 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
1219 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
1222 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1225 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1227 lpmliW->dwDestination = mliA.dwDestination;
1228 lpmliW->dwSource = mliA.dwSource;
1229 lpmliW->dwLineID = mliA.dwLineID;
1230 lpmliW->fdwLine = mliA.fdwLine;
1231 lpmliW->dwUser = mliA.dwUser;
1232 lpmliW->dwComponentType = mliA.dwComponentType;
1233 lpmliW->cChannels = mliA.cChannels;
1234 lpmliW->cConnections = mliA.cConnections;
1235 lpmliW->cControls = mliA.cControls;
1236 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
1237 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
1238 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
1239 sizeof(lpmliW->szName)/sizeof(WCHAR) );
1240 lpmliW->Target.dwType = mliA.Target.dwType;
1241 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
1242 lpmliW->Target.wMid = mliA.Target.wMid;
1243 lpmliW->Target.wPid = mliA.Target.wPid;
1244 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
1245 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
1246 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
1251 /**************************************************************************
1252 * mixerGetLineInfo [MMSYSTEM.805]
1254 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16,
1260 TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo);
1262 if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16))
1263 return MMSYSERR_INVALPARAM;
1265 mliA.cbStruct = sizeof(mliA);
1266 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1267 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1268 mliA.dwComponentType = lpmli16->dwComponentType;
1270 case MIXER_GETLINEINFOF_DESTINATION:
1271 mliA.dwDestination = lpmli16->dwDestination;
1273 case MIXER_GETLINEINFOF_LINEID:
1274 mliA.dwLineID = lpmli16->dwLineID;
1276 case MIXER_GETLINEINFOF_SOURCE:
1277 mliA.dwDestination = lpmli16->dwDestination;
1278 mliA.dwSource = lpmli16->dwSource;
1280 case MIXER_GETLINEINFOF_TARGETTYPE:
1281 mliA.Target.dwType = lpmli16->Target.dwType;
1282 mliA.Target.wMid = lpmli16->Target.wMid;
1283 mliA.Target.wPid = lpmli16->Target.wPid;
1284 mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion;
1285 strcpy(mliA.Target.szPname, lpmli16->Target.szPname);
1288 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1291 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1293 lpmli16->dwDestination = mliA.dwDestination;
1294 lpmli16->dwSource = mliA.dwSource;
1295 lpmli16->dwLineID = mliA.dwLineID;
1296 lpmli16->fdwLine = mliA.fdwLine;
1297 lpmli16->dwUser = mliA.dwUser;
1298 lpmli16->dwComponentType = mliA.dwComponentType;
1299 lpmli16->cChannels = mliA.cChannels;
1300 lpmli16->cConnections = mliA.cConnections;
1301 lpmli16->cControls = mliA.cControls;
1302 strcpy(lpmli16->szShortName, mliA.szShortName);
1303 strcpy(lpmli16->szName, mliA.szName);
1304 lpmli16->Target.dwType = mliA.Target.dwType;
1305 lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID;
1306 lpmli16->Target.wMid = mliA.Target.wMid;
1307 lpmli16->Target.wPid = mliA.Target.wPid;
1308 lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion;
1309 strcpy(lpmli16->Target.szPname, mliA.Target.szPname);
1314 /**************************************************************************
1315 * mixerSetControlDetails [WINMM.@]
1317 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1322 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1324 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1325 return MMSYSERR_INVALHANDLE;
1327 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
1331 /**************************************************************************
1332 * mixerSetControlDetails [MMSYSTEM.809]
1334 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix,
1335 LPMIXERCONTROLDETAILS16 lpmcd,
1338 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1339 return MMSYSERR_NOTENABLED;
1342 /**************************************************************************
1343 * mixerMessage [WINMM.@]
1345 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
1349 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
1350 (DWORD)hmix, uMsg, dwParam1, dwParam2);
1352 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
1353 return MMSYSERR_INVALHANDLE;
1355 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
1358 /**************************************************************************
1359 * mixerMessage [MMSYSTEM.804]
1361 DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1,
1364 return mixerMessage(hmix, uMsg, dwParam1, dwParam2);
1367 /**************************************************************************
1368 * auxGetNumDevs [WINMM.@]
1370 UINT WINAPI auxGetNumDevs(void)
1372 return MMDRV_GetNum(MMDRV_AUX);
1375 /**************************************************************************
1376 * auxGetNumDevs [MMSYSTEM.350]
1378 UINT16 WINAPI auxGetNumDevs16(void)
1380 return MMDRV_GetNum(MMDRV_AUX);
1383 /**************************************************************************
1384 * auxGetDevCapsW [WINMM.@]
1386 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
1389 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
1391 lpCaps->wMid = acA.wMid;
1392 lpCaps->wPid = acA.wPid;
1393 lpCaps->vDriverVersion = acA.vDriverVersion;
1394 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
1395 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1396 lpCaps->wTechnology = acA.wTechnology;
1397 lpCaps->dwSupport = acA.dwSupport;
1401 /**************************************************************************
1402 * auxGetDevCapsA [WINMM.@]
1404 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
1408 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1410 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1411 return MMSYSERR_INVALHANDLE;
1412 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1415 /**************************************************************************
1416 * auxGetDevCaps [MMSYSTEM.351]
1418 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
1422 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1424 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1425 return MMSYSERR_INVALHANDLE;
1426 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1429 /**************************************************************************
1430 * auxGetVolume [WINMM.@]
1432 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1436 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1438 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1439 return MMSYSERR_INVALHANDLE;
1440 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1443 /**************************************************************************
1444 * auxGetVolume [MMSYSTEM.352]
1446 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume)
1450 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1452 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1453 return MMSYSERR_INVALHANDLE;
1454 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1457 /**************************************************************************
1458 * auxSetVolume [WINMM.@]
1460 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
1464 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1466 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1467 return MMSYSERR_INVALHANDLE;
1468 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1471 /**************************************************************************
1472 * auxSetVolume [MMSYSTEM.353]
1474 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
1478 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1480 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1481 return MMSYSERR_INVALHANDLE;
1482 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1485 /**************************************************************************
1486 * auxOutMessage [WINMM.@]
1488 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1492 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1493 return MMSYSERR_INVALHANDLE;
1495 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1498 /**************************************************************************
1499 * auxOutMessage [MMSYSTEM.354]
1501 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1505 TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1508 case AUXDM_GETNUMDEVS:
1509 case AUXDM_SETVOLUME:
1510 /* no argument conversion needed */
1512 case AUXDM_GETVOLUME:
1513 return auxGetVolume16(uDeviceID, MapSL(dw1));
1514 case AUXDM_GETDEVCAPS:
1515 return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2);
1517 TRACE("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1518 uDeviceID, uMessage, dw1, dw2);
1521 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1522 return MMSYSERR_INVALHANDLE;
1524 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1527 /**************************************************************************
1528 * mciGetErrorStringW [WINMM.@]
1530 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1532 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1533 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
1535 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
1536 HeapFree(GetProcessHeap(), 0, bufstr);
1540 /**************************************************************************
1541 * mciGetErrorString [MMSYSTEM.706]
1543 BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength)
1545 return mciGetErrorStringA(wError, lpstrBuffer, uLength);
1548 /**************************************************************************
1549 * mciGetErrorStringA [WINMM.@]
1551 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
1555 if (lpstrBuffer != NULL && uLength > 0 &&
1556 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
1558 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
1559 dwError, lpstrBuffer, uLength) > 0) {
1566 /**************************************************************************
1567 * mciDriverNotify [MMSYSTEM.711]
1569 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1571 TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1573 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1576 /**************************************************************************
1577 * mciDriverNotify [WINMM.@]
1579 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1582 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1584 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1587 /**************************************************************************
1588 * mciGetDriverData [MMSYSTEM.708]
1590 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1592 return mciGetDriverData(uDeviceID);
1595 /**************************************************************************
1596 * mciGetDriverData [WINMM.@]
1598 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1600 LPWINE_MCIDRIVER wmd;
1602 TRACE("(%04x)\n", uDeviceID);
1604 wmd = MCI_GetDriver(uDeviceID);
1607 WARN("Bad uDeviceID\n");
1611 return wmd->dwPrivate;
1614 /**************************************************************************
1615 * mciSetDriverData [MMSYSTEM.707]
1617 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1619 return mciSetDriverData(uDeviceID, data);
1622 /**************************************************************************
1623 * mciSetDriverData [WINMM.@]
1625 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1627 LPWINE_MCIDRIVER wmd;
1629 TRACE("(%04x, %08lx)\n", uDeviceID, data);
1631 wmd = MCI_GetDriver(uDeviceID);
1634 WARN("Bad uDeviceID\n");
1638 wmd->dwPrivate = data;
1642 /**************************************************************************
1643 * mciSendCommandA [WINMM.@]
1645 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1649 TRACE("(%08x, %s, %08lx, %08lx)\n",
1650 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1652 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
1653 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1654 TRACE("=> %08lx\n", dwRet);
1658 /**************************************************************************
1659 * mciSendCommandW [WINMM.@]
1661 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1663 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
1664 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1665 return MCIERR_UNSUPPORTED_FUNCTION;
1668 /**************************************************************************
1669 * mciSendCommand [MMSYSTEM.701]
1671 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1675 TRACE("(%04X, %s, %08lX, %08lX)\n",
1676 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1678 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE);
1679 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1680 TRACE("=> %ld\n", dwRet);
1684 /**************************************************************************
1685 * mciGetDeviceID [MMSYSTEM.703]
1687 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1689 TRACE("(\"%s\")\n", lpstrName);
1691 return MCI_GetDriverFromString(lpstrName);
1694 /**************************************************************************
1695 * mciGetDeviceIDA [WINMM.@]
1697 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1699 return MCI_GetDriverFromString(lpstrName);
1702 /**************************************************************************
1703 * mciGetDeviceIDW [WINMM.@]
1705 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1710 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1711 ret = MCI_GetDriverFromString(lpstrName);
1712 HeapFree(GetProcessHeap(), 0, lpstrName);
1716 /**************************************************************************
1717 * MCI_DefYieldProc [internal]
1719 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1723 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1725 if ((HIWORD(data) != 0 && GetActiveWindow() != HIWORD(data)) ||
1726 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1732 msg.hwnd = HIWORD(data);
1733 while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1739 /**************************************************************************
1740 * mciSetYieldProc [MMSYSTEM.714]
1742 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData)
1744 LPWINE_MCIDRIVER wmd;
1746 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1748 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1749 WARN("Bad uDeviceID\n");
1753 wmd->lpfnYieldProc = (YIELDPROC)fpYieldProc;
1754 wmd->dwYieldData = dwYieldData;
1760 /**************************************************************************
1761 * mciSetYieldProc [WINMM.@]
1763 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1765 LPWINE_MCIDRIVER wmd;
1767 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1769 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1770 WARN("Bad uDeviceID\n");
1774 wmd->lpfnYieldProc = fpYieldProc;
1775 wmd->dwYieldData = dwYieldData;
1781 /**************************************************************************
1782 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
1784 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1786 FIXME("(%lu, %s) stub\n", dwElementID, lpstrType);
1790 /**************************************************************************
1791 * mciGetDeviceIDFromElementIDW [WINMM.@]
1793 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1795 /* FIXME: that's rather strange, there is no
1796 * mciGetDeviceIDFromElementID32A in winmm.spec
1798 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1802 /**************************************************************************
1803 * mciGetYieldProc [MMSYSTEM.716]
1805 YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1807 LPWINE_MCIDRIVER wmd;
1809 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1811 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1812 WARN("Bad uDeviceID\n");
1815 if (!wmd->lpfnYieldProc) {
1816 WARN("No proc set\n");
1820 WARN("Proc is 32 bit\n");
1823 return (YIELDPROC16)wmd->lpfnYieldProc;
1826 /**************************************************************************
1827 * mciGetYieldProc [WINMM.@]
1829 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1831 LPWINE_MCIDRIVER wmd;
1833 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1835 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1836 WARN("Bad uDeviceID\n");
1839 if (!wmd->lpfnYieldProc) {
1840 WARN("No proc set\n");
1844 WARN("Proc is 32 bit\n");
1847 return wmd->lpfnYieldProc;
1850 /**************************************************************************
1851 * mciGetCreatorTask [MMSYSTEM.717]
1853 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1855 return mciGetCreatorTask(uDeviceID);
1858 /**************************************************************************
1859 * mciGetCreatorTask [WINMM.@]
1861 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1863 LPWINE_MCIDRIVER wmd;
1866 TRACE("(%u)\n", uDeviceID);
1868 ret = (!(wmd = MCI_GetDriver(uDeviceID))) ? 0 : wmd->hCreatorTask;
1870 TRACE("=> %04x\n", ret);
1874 /**************************************************************************
1875 * mciDriverYield [MMSYSTEM.710]
1877 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
1879 LPWINE_MCIDRIVER wmd;
1882 /* TRACE("(%04x)\n", uDeviceID); */
1884 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) {
1887 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1893 /**************************************************************************
1894 * mciDriverYield [WINMM.@]
1896 UINT WINAPI mciDriverYield(UINT uDeviceID)
1898 LPWINE_MCIDRIVER wmd;
1901 TRACE("(%04x)\n", uDeviceID);
1903 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
1906 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1912 /**************************************************************************
1913 * midiOutGetNumDevs [WINMM.@]
1915 UINT WINAPI midiOutGetNumDevs(void)
1917 return MMDRV_GetNum(MMDRV_MIDIOUT);
1920 /**************************************************************************
1921 * midiOutGetNumDevs [MMSYSTEM.201]
1923 UINT16 WINAPI midiOutGetNumDevs16(void)
1925 return MMDRV_GetNum(MMDRV_MIDIOUT);
1928 /**************************************************************************
1929 * midiOutGetDevCapsW [WINMM.@]
1931 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
1937 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
1938 lpCaps->wMid = mocA.wMid;
1939 lpCaps->wPid = mocA.wPid;
1940 lpCaps->vDriverVersion = mocA.vDriverVersion;
1941 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
1942 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1943 lpCaps->wTechnology = mocA.wTechnology;
1944 lpCaps->wVoices = mocA.wVoices;
1945 lpCaps->wNotes = mocA.wNotes;
1946 lpCaps->wChannelMask = mocA.wChannelMask;
1947 lpCaps->dwSupport = mocA.dwSupport;
1951 /**************************************************************************
1952 * midiOutGetDevCapsA [WINMM.@]
1954 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
1959 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
1961 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1963 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1964 return MMSYSERR_INVALHANDLE;
1966 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1969 /**************************************************************************
1970 * midiOutGetDevCaps [MMSYSTEM.202]
1972 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps,
1978 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1980 dwRet = midiOutGetDevCapsA(uDeviceID, &capsA, sizeof(capsA));
1981 if (dwRet == MMSYSERR_NOERROR) {
1982 lpCaps->wMid = capsA.wMid;
1983 lpCaps->wPid = capsA.wPid;
1984 lpCaps->vDriverVersion = capsA.vDriverVersion;
1985 strcpy(lpCaps->szPname, capsA.szPname);
1986 lpCaps->wTechnology = capsA.wTechnology;
1987 lpCaps->wVoices = capsA.wVoices;
1988 lpCaps->wNotes = capsA.wNotes;
1989 lpCaps->wChannelMask = capsA.wChannelMask;
1990 lpCaps->dwSupport = capsA.dwSupport;
1995 /**************************************************************************
1996 * MIDI_GetErrorText [internal]
1998 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2000 UINT16 ret = MMSYSERR_BADERRNUM;
2002 if (lpText == NULL) {
2003 ret = MMSYSERR_INVALPARAM;
2004 } else if (uSize == 0) {
2005 ret = MMSYSERR_NOERROR;
2007 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2008 * a warning for the test was always true */
2009 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
2010 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
2012 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
2013 uError, lpText, uSize) > 0) {
2014 ret = MMSYSERR_NOERROR;
2020 /**************************************************************************
2021 * midiOutGetErrorTextA [WINMM.@]
2023 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2025 return MIDI_GetErrorText(uError, lpText, uSize);
2028 /**************************************************************************
2029 * midiOutGetErrorTextW [WINMM.@]
2031 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2033 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2036 ret = MIDI_GetErrorText(uError, xstr, uSize);
2037 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2038 HeapFree(GetProcessHeap(), 0, xstr);
2042 /**************************************************************************
2043 * midiOutGetErrorText [MMSYSTEM.203]
2045 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2047 return MIDI_GetErrorText(uError, lpText, uSize);
2050 /**************************************************************************
2051 * MIDI_OutAlloc [internal]
2053 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
2054 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
2055 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
2061 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
2063 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
2064 lpdwCallback, lpdwInstance, bFrom32);
2066 if (lphMidiOut != NULL)
2067 *lphMidiOut = hMidiOut;
2070 lpwm->mod.hMidi = hMidiOut;
2071 lpwm->mod.dwCallback = *lpdwCallback;
2072 lpwm->mod.dwInstance = *lpdwInstance;
2073 lpwm->mod.dnDevNode = 0;
2074 lpwm->mod.cIds = cIDs;
2076 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2081 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
2082 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2088 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2089 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2091 if (lphMidiOut != NULL) *lphMidiOut = 0;
2093 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
2097 return MMSYSERR_NOMEM;
2099 lpwm->mld.uDeviceID = uDeviceID;
2101 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
2104 if (dwRet != MMSYSERR_NOERROR) {
2105 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
2109 if (lphMidiOut) *lphMidiOut = hMidiOut;
2110 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
2115 /**************************************************************************
2116 * midiOutOpen [WINMM.@]
2118 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2119 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2121 return MMSYSTEM_midiOutOpen(lphMidiOut, uDeviceID, dwCallback,
2122 dwInstance, dwFlags, TRUE);
2125 /**************************************************************************
2126 * midiOutOpen [MMSYSTEM.204]
2128 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2129 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2134 ret = MMSYSTEM_midiOutOpen(&hmo, uDeviceID, dwCallback, dwInstance,
2137 if (lphMidiOut != NULL) *lphMidiOut = hmo;
2141 /**************************************************************************
2142 * midiOutClose [WINMM.@]
2144 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2149 TRACE("(%04X)\n", hMidiOut);
2151 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2152 return MMSYSERR_INVALHANDLE;
2154 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
2155 MMDRV_Free(hMidiOut, wmld);
2160 /**************************************************************************
2161 * midiOutClose [MMSYSTEM.205]
2163 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2165 return midiOutClose(hMidiOut);
2168 /**************************************************************************
2169 * midiOutPrepareHeader [WINMM.@]
2171 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2172 MIDIHDR* lpMidiOutHdr, UINT uSize)
2176 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2178 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2179 return MMSYSERR_INVALHANDLE;
2181 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2184 /**************************************************************************
2185 * midiOutPrepareHeader [MMSYSTEM.206]
2187 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2188 SEGPTR lpsegMidiOutHdr, /* [???] */
2189 UINT16 uSize) /* [in] */
2193 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2195 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2196 return MMSYSERR_INVALHANDLE;
2198 return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE);
2201 /**************************************************************************
2202 * midiOutUnprepareHeader [WINMM.@]
2204 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2205 MIDIHDR* lpMidiOutHdr, UINT uSize)
2209 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2211 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2212 return MMSYSERR_NOERROR;
2215 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2216 return MMSYSERR_INVALHANDLE;
2218 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2221 /**************************************************************************
2222 * midiOutUnprepareHeader [MMSYSTEM.207]
2224 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2225 SEGPTR lpsegMidiOutHdr, /* [???] */
2226 UINT16 uSize) /* [in] */
2229 LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr);
2231 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2233 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2234 return MMSYSERR_NOERROR;
2237 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2238 return MMSYSERR_INVALHANDLE;
2240 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2243 /**************************************************************************
2244 * midiOutShortMsg [WINMM.@]
2246 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2250 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
2252 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2253 return MMSYSERR_INVALHANDLE;
2255 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, FALSE);
2258 /**************************************************************************
2259 * midiOutShortMsg [MMSYSTEM.208]
2261 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2263 return midiOutShortMsg(hMidiOut, dwMsg);
2266 /**************************************************************************
2267 * midiOutLongMsg [WINMM.@]
2269 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2270 MIDIHDR* lpMidiOutHdr, UINT uSize)
2274 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2276 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2277 return MMSYSERR_INVALHANDLE;
2279 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
2282 /**************************************************************************
2283 * midiOutLongMsg [MMSYSTEM.209]
2285 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */
2286 LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */
2287 UINT16 uSize) /* [in] */
2291 TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2293 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2294 return MMSYSERR_INVALHANDLE;
2296 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2299 /**************************************************************************
2300 * midiOutReset [WINMM.@]
2302 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2306 TRACE("(%04X)\n", hMidiOut);
2308 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2309 return MMSYSERR_INVALHANDLE;
2311 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
2314 /**************************************************************************
2315 * midiOutReset [MMSYSTEM.210]
2317 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2319 return midiOutReset(hMidiOut);
2322 /**************************************************************************
2323 * midiOutGetVolume [WINMM.@]
2325 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2329 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
2331 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2332 return MMSYSERR_INVALHANDLE;
2334 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
2337 /**************************************************************************
2338 * midiOutGetVolume [MMSYSTEM.211]
2340 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2342 return midiOutGetVolume(uDeviceID, lpdwVolume);
2345 /**************************************************************************
2346 * midiOutSetVolume [WINMM.@]
2348 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2352 TRACE("(%04X, %ld);\n", uDeviceID, dwVolume);
2354 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2355 return MMSYSERR_INVALHANDLE;
2357 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
2360 /**************************************************************************
2361 * midiOutSetVolume [MMSYSTEM.212]
2363 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2365 return midiOutSetVolume(uDeviceID, dwVolume);
2368 /**************************************************************************
2369 * midiOutCachePatches [WINMM.@]
2371 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2372 WORD* lpwPatchArray, UINT uFlags)
2374 /* not really necessary to support this */
2375 FIXME("not supported yet\n");
2376 return MMSYSERR_NOTSUPPORTED;
2379 /**************************************************************************
2380 * midiOutCachePatches [MMSYSTEM.213]
2382 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2383 WORD* lpwPatchArray, UINT16 uFlags)
2385 return midiOutCachePatches(hMidiOut, uBank, lpwPatchArray, uFlags);
2388 /**************************************************************************
2389 * midiOutCacheDrumPatches [WINMM.@]
2391 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2392 WORD* lpwKeyArray, UINT uFlags)
2394 FIXME("not supported yet\n");
2395 return MMSYSERR_NOTSUPPORTED;
2398 /**************************************************************************
2399 * midiOutCacheDrumPatches [MMSYSTEM.214]
2401 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2402 WORD* lpwKeyArray, UINT16 uFlags)
2404 return midiOutCacheDrumPatches16(hMidiOut, uPatch, lpwKeyArray, uFlags);
2407 /**************************************************************************
2408 * midiOutGetID [WINMM.@]
2410 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2414 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2416 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2417 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2418 return MMSYSERR_INVALHANDLE;
2420 *lpuDeviceID = wmld->uDeviceID;
2421 return MMSYSERR_NOERROR;
2424 /**************************************************************************
2425 * midiOutGetID [MMSYSTEM.215]
2427 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2431 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2433 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2434 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2435 return MMSYSERR_INVALHANDLE;
2437 *lpuDeviceID = wmld->uDeviceID;
2438 return MMSYSERR_NOERROR;
2441 /**************************************************************************
2442 * midiOutMessage [WINMM.@]
2444 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2445 DWORD dwParam1, DWORD dwParam2)
2449 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2451 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2452 return MMSYSERR_INVALHANDLE;
2457 FIXME("can't handle OPEN or CLOSE message!\n");
2458 return MMSYSERR_NOTSUPPORTED;
2460 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2463 /**************************************************************************
2464 * midiOutMessage [MMSYSTEM.216]
2466 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2467 DWORD dwParam1, DWORD dwParam2)
2471 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2473 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2474 return MMSYSERR_INVALHANDLE;
2479 FIXME("can't handle OPEN or CLOSE message!\n");
2480 return MMSYSERR_NOTSUPPORTED;
2482 case MODM_GETVOLUME:
2483 return midiOutGetVolume16(hMidiOut, MapSL(dwParam1));
2485 return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2);
2487 /* lpMidiOutHdr is still a segmented pointer for this function */
2488 return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2);
2489 case MODM_UNPREPARE:
2490 return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2);
2492 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2495 /**************************************************************************
2496 * midiInGetNumDevs [WINMM.@]
2498 UINT WINAPI midiInGetNumDevs(void)
2500 return MMDRV_GetNum(MMDRV_MIDIIN);
2503 /**************************************************************************
2504 * midiInGetNumDevs [MMSYSTEM.301]
2506 UINT16 WINAPI midiInGetNumDevs16(void)
2508 return MMDRV_GetNum(MMDRV_MIDIIN);
2511 /**************************************************************************
2512 * midiInGetDevCapsW [WINMM.@]
2514 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2517 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2519 if (ret == MMSYSERR_NOERROR) {
2520 lpCaps->wMid = micA.wMid;
2521 lpCaps->wPid = micA.wPid;
2522 lpCaps->vDriverVersion = micA.vDriverVersion;
2523 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
2524 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2525 lpCaps->dwSupport = micA.dwSupport;
2530 /**************************************************************************
2531 * midiInGetDevCapsA [WINMM.@]
2533 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2537 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
2539 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
2540 return MMSYSERR_INVALHANDLE;
2542 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2545 /**************************************************************************
2546 * midiInGetDevCaps [MMSYSTEM.302]
2548 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps,
2552 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2554 if (ret == MMSYSERR_NOERROR) {
2555 lpCaps->wMid = micA.wMid;
2556 lpCaps->wPid = micA.wPid;
2557 lpCaps->vDriverVersion = micA.vDriverVersion;
2558 strcpy(lpCaps->szPname, micA.szPname);
2559 lpCaps->dwSupport = micA.dwSupport;
2565 /**************************************************************************
2566 * midiInGetErrorTextW [WINMM.@]
2568 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2570 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2571 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
2573 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2574 HeapFree(GetProcessHeap(), 0, xstr);
2578 /**************************************************************************
2579 * midiInGetErrorTextA [WINMM.@]
2581 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2583 return MIDI_GetErrorText(uError, lpText, uSize);
2586 /**************************************************************************
2587 * midiInGetErrorText [MMSYSTEM.303]
2589 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2591 return MIDI_GetErrorText(uError, lpText, uSize);
2594 static UINT MMSYSTEM_midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
2595 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2601 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2602 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2604 if (lphMidiIn != NULL) *lphMidiIn = 0;
2606 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
2607 &dwFlags, &dwCallback, &dwInstance, bFrom32);
2610 return MMSYSERR_NOMEM;
2612 lpwm->mod.hMidi = hMidiIn;
2613 lpwm->mod.dwCallback = dwCallback;
2614 lpwm->mod.dwInstance = dwInstance;
2616 lpwm->mld.uDeviceID = uDeviceID;
2617 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
2619 if (dwRet != MMSYSERR_NOERROR) {
2620 MMDRV_Free(hMidiIn, &lpwm->mld);
2623 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
2624 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
2629 /**************************************************************************
2630 * midiInOpen [WINMM.@]
2632 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2633 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2635 return MMSYSTEM_midiInOpen(lphMidiIn, uDeviceID, dwCallback,
2636 dwInstance, dwFlags, TRUE);
2639 /**************************************************************************
2640 * midiInOpen [MMSYSTEM.304]
2642 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2643 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2648 ret = MMSYSTEM_midiInOpen(&xhmid, uDeviceID, dwCallback, dwInstance,
2651 if (lphMidiIn) *lphMidiIn = xhmid;
2655 /**************************************************************************
2656 * midiInClose [WINMM.@]
2658 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2663 TRACE("(%04X)\n", hMidiIn);
2665 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2666 return MMSYSERR_INVALHANDLE;
2668 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
2669 MMDRV_Free(hMidiIn, wmld);
2673 /**************************************************************************
2674 * midiInClose [MMSYSTEM.305]
2676 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2678 return midiInClose(hMidiIn);
2681 /**************************************************************************
2682 * midiInPrepareHeader [WINMM.@]
2684 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2685 MIDIHDR* lpMidiInHdr, UINT uSize)
2689 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2691 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2692 return MMSYSERR_INVALHANDLE;
2694 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2697 /**************************************************************************
2698 * midiInPrepareHeader [MMSYSTEM.306]
2700 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2701 SEGPTR lpsegMidiInHdr, /* [???] */
2702 UINT16 uSize) /* [in] */
2706 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2708 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2709 return MMSYSERR_INVALHANDLE;
2711 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2714 /**************************************************************************
2715 * midiInUnprepareHeader [WINMM.@]
2717 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2718 MIDIHDR* lpMidiInHdr, UINT uSize)
2722 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2724 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2725 return MMSYSERR_NOERROR;
2728 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2729 return MMSYSERR_INVALHANDLE;
2731 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2734 /**************************************************************************
2735 * midiInUnprepareHeader [MMSYSTEM.307]
2737 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2738 SEGPTR lpsegMidiInHdr, /* [???] */
2739 UINT16 uSize) /* [in] */
2742 LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr);
2744 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2746 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2747 return MMSYSERR_NOERROR;
2750 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2751 return MMSYSERR_INVALHANDLE;
2753 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2756 /**************************************************************************
2757 * midiInAddBuffer [WINMM.@]
2759 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2760 MIDIHDR* lpMidiInHdr, UINT uSize)
2764 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2766 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2767 return MMSYSERR_INVALHANDLE;
2769 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
2772 /**************************************************************************
2773 * midiInAddBuffer [MMSYSTEM.308]
2775 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */
2776 MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */
2777 UINT16 uSize) /* [in] */
2781 TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2783 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2784 return MMSYSERR_INVALHANDLE;
2786 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2789 /**************************************************************************
2790 * midiInStart [WINMM.@]
2792 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2796 TRACE("(%04X)\n", hMidiIn);
2798 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2799 return MMSYSERR_INVALHANDLE;
2801 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
2804 /**************************************************************************
2805 * midiInStart [MMSYSTEM.309]
2807 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2809 return midiInStart(hMidiIn);
2812 /**************************************************************************
2813 * midiInStop [WINMM.@]
2815 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2819 TRACE("(%04X)\n", hMidiIn);
2821 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2822 return MMSYSERR_INVALHANDLE;
2824 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
2827 /**************************************************************************
2828 * midiInStop [MMSYSTEM.310]
2830 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2832 return midiInStop(hMidiIn);
2835 /**************************************************************************
2836 * midiInReset [WINMM.@]
2838 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2842 TRACE("(%04X)\n", hMidiIn);
2844 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2845 return MMSYSERR_INVALHANDLE;
2847 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
2850 /**************************************************************************
2851 * midiInReset [MMSYSTEM.311]
2853 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2855 return midiInReset(hMidiIn);
2858 /**************************************************************************
2859 * midiInGetID [WINMM.@]
2861 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2865 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2867 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2869 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
2870 return MMSYSERR_INVALHANDLE;
2872 *lpuDeviceID = wmld->uDeviceID;
2874 return MMSYSERR_NOERROR;
2877 /**************************************************************************
2878 * midiInGetID [MMSYSTEM.312]
2880 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
2884 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2886 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2888 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
2889 return MMSYSERR_INVALHANDLE;
2891 *lpuDeviceID = wmld->uDeviceID;
2893 return MMSYSERR_NOERROR;
2896 /**************************************************************************
2897 * midiInMessage [WINMM.@]
2899 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
2900 DWORD dwParam1, DWORD dwParam2)
2904 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
2906 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2907 return MMSYSERR_INVALHANDLE;
2912 FIXME("can't handle OPEN or CLOSE message!\n");
2913 return MMSYSERR_NOTSUPPORTED;
2915 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2918 /**************************************************************************
2919 * midiInMessage [MMSYSTEM.313]
2921 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
2922 DWORD dwParam1, DWORD dwParam2)
2926 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
2931 FIXME("can't handle OPEN or CLOSE message!\n");
2932 return MMSYSERR_NOTSUPPORTED;
2934 case MIDM_GETDEVCAPS:
2935 return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2);
2937 return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2);
2938 case MIDM_UNPREPARE:
2939 return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2);
2940 case MIDM_ADDBUFFER:
2941 return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2);
2944 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2945 return MMSYSERR_INVALHANDLE;
2947 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
2950 typedef struct WINE_MIDIStream {
2961 LPMIDIHDR lpMidiHdr;
2964 #define WINE_MSM_HEADER (WM_USER+0)
2965 #define WINE_MSM_STOP (WM_USER+1)
2967 /**************************************************************************
2968 * MMSYSTEM_GetMidiStream [internal]
2970 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
2972 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
2981 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
2983 return *lpMidiStrm != NULL;
2986 /**************************************************************************
2987 * MMSYSTEM_MidiStream_Convert [internal]
2989 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
2993 if (lpMidiStrm->dwTimeDiv == 0) {
2994 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
2995 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
2996 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
2997 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
2998 ret = (pulse * 1000) / (nf * nsf);
3000 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
3001 (double)lpMidiStrm->dwTimeDiv);
3007 /**************************************************************************
3008 * MMSYSTEM_MidiStream_MessageHandler [internal]
3010 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
3012 LPMIDIHDR lpMidiHdr;
3016 switch (msg->message) {
3018 SetEvent(lpMidiStrm->hEvent);
3022 /* this is not quite what MS doc says... */
3023 midiOutReset(lpMidiStrm->hDevice);
3024 /* empty list of already submitted buffers */
3025 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
3026 lpMidiHdr->dwFlags |= MHDR_DONE;
3027 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3029 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3030 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3032 lpMidiStrm->lpMidiHdr = 0;
3033 SetEvent(lpMidiStrm->hEvent);
3035 case WINE_MSM_HEADER:
3036 /* sets initial tick count for first MIDIHDR */
3037 if (!lpMidiStrm->dwStartTicks)
3038 lpMidiStrm->dwStartTicks = GetTickCount();
3040 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
3041 * by native mcimidi, it doesn't look like a correct one".
3042 * this trick allows to throw it away... but I don't like it.
3043 * It looks like part of the file I'm trying to play and definitively looks
3044 * like raw midi content
3045 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
3046 * synchronization issue where native mcimidi is still processing raw MIDI
3047 * content before generating MIDIEVENTs ?
3049 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
3050 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
3051 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
3052 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
3053 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
3054 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
3055 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
3056 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
3057 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
3058 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3059 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3060 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3061 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3062 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3063 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3064 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3065 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3067 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3068 lpData = lpMidiHdr->lpData;
3069 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
3070 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
3071 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
3072 lpMidiHdr->dwFlags, msg->wParam);
3074 /* dumps content of lpMidiHdr->lpData
3075 * FIXME: there should be a debug routine somewhere that already does this
3076 * I hate spreading this type of shit all around the code
3078 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
3082 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
3083 printf("%02x ", lpData[dwToGo + i]);
3086 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
3087 ch = lpData[dwToGo + i];
3088 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
3093 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3094 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3095 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3096 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
3097 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
3098 ((LPMIDIEVENT)lpData)->dwStreamID);
3099 lpMidiHdr->dwFlags |= MHDR_DONE;
3100 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3102 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3103 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3107 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
3109 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3110 lpMidiHdr->lpNext = 0;
3111 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
3112 lpMidiHdr->dwFlags &= MHDR_DONE;
3113 lpMidiHdr->dwOffset = 0;
3117 FIXME("Unknown message %d\n", msg->message);
3123 /**************************************************************************
3124 * MMSYSTEM_MidiStream_Player [internal]
3126 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
3128 WINE_MIDIStream* lpMidiStrm = pmt;
3133 LPMIDIHDR lpMidiHdr;
3137 TRACE("(%p)!\n", lpMidiStrm);
3140 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
3143 /* force thread's queue creation */
3144 /* Used to be InitThreadInput16(0, 5); */
3145 /* but following works also with hack in midiStreamOpen */
3146 PeekMessageA(&msg, 0, 0, 0, 0);
3148 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
3149 SetEvent(lpMidiStrm->hEvent);
3150 TRACE("Ready to go 1\n");
3151 /* thread is started in paused mode */
3152 SuspendThread(lpMidiStrm->hThread);
3153 TRACE("Ready to go 2\n");
3155 lpMidiStrm->dwStartTicks = 0;
3156 lpMidiStrm->dwPulses = 0;
3158 lpMidiStrm->lpMidiHdr = 0;
3161 lpMidiHdr = lpMidiStrm->lpMidiHdr;
3163 /* for first message, block until one arrives, then process all that are available */
3164 GetMessageA(&msg, 0, 0, 0);
3166 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3168 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
3174 lpData = lpMidiHdr->lpData;
3176 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3178 /* do we have to wait ? */
3179 if (me->dwDeltaTime) {
3180 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
3181 lpMidiStrm->dwPulses += me->dwDeltaTime;
3183 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3185 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
3186 while ((dwCurrTC = GetTickCount()) < dwToGo) {
3187 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
3188 /* got a message, handle it */
3189 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
3190 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3195 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
3200 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3202 FIXME("NIY: MEVT_COMMENT\n");
3203 /* do nothing, skip bytes */
3206 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3211 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3214 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3219 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3222 if (me->dwEvent & MEVT_F_CALLBACK) {
3223 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3224 MM_MOM_POSITIONCB, lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
3226 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
3227 if (me->dwEvent & MEVT_F_LONG)
3228 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
3229 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
3230 /* done with this header */
3231 lpMidiHdr->dwFlags |= MHDR_DONE;
3232 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3234 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
3235 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3236 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3241 TRACE("End of thread\n");
3243 return 0; /* for removing the warning, never executed */
3246 /**************************************************************************
3247 * MMSYSTEM_MidiStream_PostMessage [internal]
3249 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
3251 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
3254 ReleaseThunkLock(&count);
3255 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3256 RestoreThunkLock(count);
3258 WARN("bad PostThreadMessageA\n");
3264 /**************************************************************************
3265 * midiStreamClose [WINMM.@]
3267 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3269 WINE_MIDIStream* lpMidiStrm;
3271 TRACE("(%08x)!\n", hMidiStrm);
3273 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3274 return MMSYSERR_INVALHANDLE;
3276 midiStreamStop(hMidiStrm);
3277 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
3278 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
3279 CloseHandle(lpMidiStrm->hEvent);
3281 return midiOutClose(hMidiStrm);
3284 /**************************************************************************
3285 * MMSYSTEM_MidiStream_Open [internal]
3287 static MMRESULT WINAPI MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3288 DWORD cMidi, DWORD dwCallback,
3289 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
3291 WINE_MIDIStream* lpMidiStrm;
3293 MIDIOPENSTRMID mosm;
3297 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3298 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3300 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3301 return MMSYSERR_INVALPARAM;
3303 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3305 return MMSYSERR_NOMEM;
3307 lpMidiStrm->dwTempo = 500000;
3308 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3309 lpMidiStrm->dwPositionMS = 0;
3311 mosm.dwStreamID = (DWORD)lpMidiStrm;
3312 /* FIXME: the correct value is not allocated yet for MAPPER */
3313 mosm.wDeviceID = *lpuDeviceID;
3314 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
3315 lpMidiStrm->hDevice = hMidiOut;
3317 *lphMidiStrm = hMidiOut;
3319 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
3320 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
3321 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
3323 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
3324 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
3325 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3327 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
3328 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3330 if (!lpMidiStrm->hThread) {
3331 midiStreamClose((HMIDISTRM)hMidiOut);
3332 return MMSYSERR_NOMEM;
3335 /* wait for thread to have started, and for its queue to be created */
3339 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3340 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3341 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3343 ReleaseThunkLock(&count);
3344 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3345 RestoreThunkLock(count);
3348 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
3349 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
3353 /**************************************************************************
3354 * midiStreamOpen [WINMM.@]
3356 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3357 DWORD cMidi, DWORD dwCallback,
3358 DWORD dwInstance, DWORD fdwOpen)
3360 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
3361 dwInstance, fdwOpen, TRUE);
3364 /**************************************************************************
3365 * midiStreamOut [WINMM.@]
3367 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
3370 WINE_MIDIStream* lpMidiStrm;
3371 DWORD ret = MMSYSERR_NOERROR;
3373 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3375 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3376 ret = MMSYSERR_INVALHANDLE;
3378 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
3379 WINE_MSM_HEADER, cbMidiHdr,
3380 (DWORD)lpMidiHdr)) {
3381 WARN("bad PostThreadMessageA\n");
3382 ret = MMSYSERR_ERROR;
3388 /**************************************************************************
3389 * midiStreamPause [WINMM.@]
3391 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3393 WINE_MIDIStream* lpMidiStrm;
3394 DWORD ret = MMSYSERR_NOERROR;
3396 TRACE("(%08x)!\n", hMidiStrm);
3398 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3399 ret = MMSYSERR_INVALHANDLE;
3401 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3402 WARN("bad Suspend (%ld)\n", GetLastError());
3403 ret = MMSYSERR_ERROR;
3409 /**************************************************************************
3410 * midiStreamPosition [WINMM.@]
3412 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3414 WINE_MIDIStream* lpMidiStrm;
3415 DWORD ret = MMSYSERR_NOERROR;
3417 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3419 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3420 ret = MMSYSERR_INVALHANDLE;
3421 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3422 ret = MMSYSERR_INVALPARAM;
3424 switch (lpMMT->wType) {
3426 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3427 TRACE("=> %ld ms\n", lpMMT->u.ms);
3430 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3431 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
3434 WARN("Unsupported time type %d\n", lpMMT->wType);
3435 lpMMT->wType = TIME_MS;
3436 ret = MMSYSERR_INVALPARAM;
3443 /**************************************************************************
3444 * midiStreamProperty [WINMM.@]
3446 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3448 WINE_MIDIStream* lpMidiStrm;
3449 MMRESULT ret = MMSYSERR_NOERROR;
3451 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3453 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3454 ret = MMSYSERR_INVALHANDLE;
3455 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3456 ret = MMSYSERR_INVALPARAM;
3457 } else if (dwProperty & MIDIPROP_TEMPO) {
3458 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3460 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3461 ret = MMSYSERR_INVALPARAM;
3462 } else if (dwProperty & MIDIPROP_SET) {
3463 lpMidiStrm->dwTempo = mpt->dwTempo;
3464 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
3465 } else if (dwProperty & MIDIPROP_GET) {
3466 mpt->dwTempo = lpMidiStrm->dwTempo;
3467 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
3469 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3470 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3472 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3473 ret = MMSYSERR_INVALPARAM;
3474 } else if (dwProperty & MIDIPROP_SET) {
3475 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3476 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
3477 } else if (dwProperty & MIDIPROP_GET) {
3478 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3479 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
3482 ret = MMSYSERR_INVALPARAM;
3488 /**************************************************************************
3489 * midiStreamRestart [WINMM.@]
3491 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3493 WINE_MIDIStream* lpMidiStrm;
3494 MMRESULT ret = MMSYSERR_NOERROR;
3496 TRACE("(%08x)!\n", hMidiStrm);
3498 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3499 ret = MMSYSERR_INVALHANDLE;
3503 /* since we increase the thread suspend count on each midiStreamPause
3504 * there may be a need for several midiStreamResume
3507 ret = ResumeThread(lpMidiStrm->hThread);
3508 } while (ret != 0xFFFFFFFF && ret != 0);
3509 if (ret == 0xFFFFFFFF) {
3510 WARN("bad Resume (%ld)\n", GetLastError());
3511 ret = MMSYSERR_ERROR;
3513 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
3519 /**************************************************************************
3520 * midiStreamStop [WINMM.@]
3522 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3524 WINE_MIDIStream* lpMidiStrm;
3525 MMRESULT ret = MMSYSERR_NOERROR;
3527 TRACE("(%08x)!\n", hMidiStrm);
3529 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3530 ret = MMSYSERR_INVALHANDLE;
3532 /* in case stream has been paused... FIXME is the current state correct ? */
3533 midiStreamRestart(hMidiStrm);
3534 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
3539 /**************************************************************************
3540 * midiStreamClose [MMSYSTEM.252]
3542 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3544 return midiStreamClose(hMidiStrm);
3547 /**************************************************************************
3548 * midiStreamOpen [MMSYSTEM.251]
3550 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3551 DWORD cMidi, DWORD dwCallback,
3552 DWORD dwInstance, DWORD fdwOpen)
3554 HMIDISTRM hMidiStrm32;
3558 if (!phMidiStrm || !devid)
3559 return MMSYSERR_INVALPARAM;
3561 ret = MMSYSTEM_MidiStream_Open(&hMidiStrm32, &devid32, cMidi, dwCallback,
3562 dwInstance, fdwOpen, FALSE);
3563 *phMidiStrm = hMidiStrm32;
3568 /**************************************************************************
3569 * midiStreamOut [MMSYSTEM.254]
3571 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3573 return midiStreamOut(hMidiStrm, (LPMIDIHDR)lpMidiHdr, cbMidiHdr);
3576 /**************************************************************************
3577 * midiStreamPause [MMSYSTEM.255]
3579 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3581 return midiStreamPause(hMidiStrm);
3584 /**************************************************************************
3585 * midiStreamPosition [MMSYSTEM.253]
3587 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3593 return MMSYSERR_INVALPARAM;
3594 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3595 ret = midiStreamPosition(hMidiStrm, &mmt32, sizeof(MMTIME));
3596 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3600 /**************************************************************************
3601 * midiStreamProperty [MMSYSTEM.250]
3603 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3605 return midiStreamProperty(hMidiStrm, lpPropData, dwProperty);
3608 /**************************************************************************
3609 * midiStreamRestart [MMSYSTEM.256]
3611 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3613 return midiStreamRestart(hMidiStrm);
3616 /**************************************************************************
3617 * midiStreamStop [MMSYSTEM.257]
3619 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3621 return midiStreamStop(hMidiStrm);
3624 static UINT WINAPI MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
3625 const LPWAVEFORMATEX lpFormat,
3626 DWORD dwCallback, DWORD dwInstance,
3627 DWORD dwFlags, BOOL bFrom32)
3631 DWORD dwRet = MMSYSERR_NOERROR;
3634 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
3635 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
3636 dwInstance, dwFlags, bFrom32?32:16);
3638 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
3640 if (lpFormat == NULL) return WAVERR_BADFORMAT;
3641 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
3642 return MMSYSERR_INVALPARAM;
3644 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
3645 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
3646 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
3648 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
3649 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
3650 return MMSYSERR_NOMEM;
3653 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
3654 wod.dwCallback = dwCallback;
3655 wod.dwInstance = dwInstance;
3658 if (dwFlags & WAVE_MAPPED) {
3659 wod.uMappedDeviceID = uDeviceID;
3660 uDeviceID = WAVE_MAPPER;
3662 wod.uMappedDeviceID = -1;
3664 wmld->uDeviceID = uDeviceID;
3666 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, (DWORD)&wod, dwFlags);
3668 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
3669 MMDRV_Free(handle, wmld);
3673 if (lphndl != NULL) *lphndl = handle;
3674 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
3679 /**************************************************************************
3680 * waveOutGetNumDevs [WINMM.@]
3682 UINT WINAPI waveOutGetNumDevs(void)
3684 return MMDRV_GetNum(MMDRV_WAVEOUT);
3687 /**************************************************************************
3688 * waveOutGetNumDevs [MMSYSTEM.401]
3690 UINT16 WINAPI waveOutGetNumDevs16(void)
3692 return MMDRV_GetNum(MMDRV_WAVEOUT);
3695 /**************************************************************************
3696 * waveOutGetDevCaps [MMSYSTEM.402]
3698 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID,
3699 LPWAVEOUTCAPS16 lpCaps, UINT16 uSize)
3704 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3705 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3707 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3709 if (ret == MMSYSERR_NOERROR) {
3710 lpCaps->wMid = wocA.wMid;
3711 lpCaps->wPid = wocA.wPid;
3712 lpCaps->vDriverVersion = wocA.vDriverVersion;
3713 strcpy(lpCaps->szPname, wocA.szPname);
3714 lpCaps->dwFormats = wocA.dwFormats;
3715 lpCaps->wChannels = wocA.wChannels;
3716 lpCaps->dwSupport = wocA.dwSupport;
3721 /**************************************************************************
3722 * waveOutGetDevCapsA [WINMM.@]
3724 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3729 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3731 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3733 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
3734 return MMSYSERR_INVALHANDLE;
3736 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
3740 /**************************************************************************
3741 * waveOutGetDevCapsW [WINMM.@]
3743 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3749 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3751 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3753 if (ret == MMSYSERR_NOERROR) {
3754 lpCaps->wMid = wocA.wMid;
3755 lpCaps->wPid = wocA.wPid;
3756 lpCaps->vDriverVersion = wocA.vDriverVersion;
3757 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
3758 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
3759 lpCaps->dwFormats = wocA.dwFormats;
3760 lpCaps->wChannels = wocA.wChannels;
3761 lpCaps->dwSupport = wocA.dwSupport;
3766 /**************************************************************************
3767 * WAVE_GetErrorText [internal]
3769 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3771 UINT16 ret = MMSYSERR_BADERRNUM;
3773 if (lpText == NULL) {
3774 ret = MMSYSERR_INVALPARAM;
3775 } else if (uSize == 0) {
3776 ret = MMSYSERR_NOERROR;
3778 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
3779 * a warning for the test was always true */
3780 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
3781 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
3783 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
3784 uError, lpText, uSize) > 0) {
3785 ret = MMSYSERR_NOERROR;
3791 /**************************************************************************
3792 * waveOutGetErrorText [MMSYSTEM.403]
3794 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3796 return WAVE_GetErrorText(uError, lpText, uSize);
3799 /**************************************************************************
3800 * waveOutGetErrorTextA [WINMM.@]
3802 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3804 return WAVE_GetErrorText(uError, lpText, uSize);
3807 /**************************************************************************
3808 * waveOutGetErrorTextW [WINMM.@]
3810 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3812 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3813 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
3815 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
3816 HeapFree(GetProcessHeap(), 0, xstr);
3820 /**************************************************************************
3821 * waveOutOpen [WINMM.@]
3822 * All the args/structs have the same layout as the win16 equivalents
3824 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3825 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3826 DWORD dwInstance, DWORD dwFlags)
3828 return MMSYSTEM_waveOpen(lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
3829 dwCallback, dwInstance, dwFlags, TRUE);
3832 /**************************************************************************
3833 * waveOutOpen [MMSYSTEM.404]
3835 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3836 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3837 DWORD dwInstance, DWORD dwFlags)
3842 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
3843 * call the 32 bit version
3844 * however, we need to promote correctly the wave mapper id
3845 * (0xFFFFFFFF and not 0x0000FFFF)
3847 ret = MMSYSTEM_waveOpen(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
3848 MMDRV_WAVEOUT, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
3850 if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
3854 /**************************************************************************
3855 * waveOutClose [WINMM.@]
3857 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3862 TRACE("(%04X)\n", hWaveOut);
3864 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3865 return MMSYSERR_INVALHANDLE;
3867 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
3868 MMDRV_Free(hWaveOut, wmld);
3873 /**************************************************************************
3874 * waveOutClose [MMSYSTEM.405]
3876 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
3881 ReleaseThunkLock(&level);
3882 ret = waveOutClose(hWaveOut);
3883 RestoreThunkLock(level);
3887 /**************************************************************************
3888 * waveOutPrepareHeader [WINMM.@]
3890 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
3891 WAVEHDR* lpWaveOutHdr, UINT uSize)
3895 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3897 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
3899 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3900 return MMSYSERR_INVALHANDLE;
3902 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
3905 /**************************************************************************
3906 * waveOutPrepareHeader [MMSYSTEM.406]
3908 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
3909 SEGPTR lpsegWaveOutHdr, /* [???] */
3910 UINT16 uSize) /* [in] */
3913 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
3915 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
3917 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
3919 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3920 return MMSYSERR_INVALHANDLE;
3922 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
3925 /**************************************************************************
3926 * waveOutUnprepareHeader [WINMM.@]
3928 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
3929 LPWAVEHDR lpWaveOutHdr, UINT uSize)
3933 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3935 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
3936 return MMSYSERR_NOERROR;
3939 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3940 return MMSYSERR_INVALHANDLE;
3942 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
3945 /**************************************************************************
3946 * waveOutUnprepareHeader [MMSYSTEM.407]
3948 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
3949 SEGPTR lpsegWaveOutHdr, /* [???] */
3950 UINT16 uSize) /* [in] */
3953 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
3955 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
3957 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
3958 return MMSYSERR_NOERROR;
3961 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3962 return MMSYSERR_INVALHANDLE;
3964 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
3967 /**************************************************************************
3968 * waveOutWrite [WINMM.@]
3970 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
3975 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3977 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3978 return MMSYSERR_INVALHANDLE;
3980 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
3983 /**************************************************************************
3984 * waveOutWrite [MMSYSTEM.408]
3986 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */
3987 LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */
3988 UINT16 uSize) /* [in] */
3992 TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
3994 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3995 return MMSYSERR_INVALHANDLE;
3997 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4000 /**************************************************************************
4001 * waveOutBreakLoop [WINMM.@]
4003 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
4007 TRACE("(%04X);\n", hWaveOut);
4009 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4010 return MMSYSERR_INVALHANDLE;
4011 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
4014 /**************************************************************************
4015 * waveOutBreakLoop [MMSYSTEM.419]
4017 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16)
4022 ReleaseThunkLock(&level);
4023 ret = waveOutBreakLoop(hWaveOut16);
4024 RestoreThunkLock(level);
4028 /**************************************************************************
4029 * waveOutPause [WINMM.@]
4031 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
4035 TRACE("(%04X);\n", hWaveOut);
4037 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4038 return MMSYSERR_INVALHANDLE;
4039 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
4042 /**************************************************************************
4043 * waveOutPause [MMSYSTEM.409]
4045 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16)
4050 ReleaseThunkLock(&level);
4051 ret = waveOutPause(hWaveOut16);
4052 RestoreThunkLock(level);
4056 /**************************************************************************
4057 * waveOutReset [WINMM.@]
4059 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
4063 TRACE("(%04X);\n", hWaveOut);
4065 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4066 return MMSYSERR_INVALHANDLE;
4067 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
4070 /**************************************************************************
4071 * waveOutReset [MMSYSTEM.411]
4073 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16)
4078 ReleaseThunkLock(&level);
4079 ret = waveOutReset(hWaveOut16);
4080 RestoreThunkLock(level);
4084 /**************************************************************************
4085 * waveOutRestart [WINMM.@]
4087 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
4091 TRACE("(%04X);\n", hWaveOut);
4093 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4094 return MMSYSERR_INVALHANDLE;
4095 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
4098 /**************************************************************************
4099 * waveOutRestart [MMSYSTEM.410]
4101 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16)
4106 ReleaseThunkLock(&level);
4107 ret = waveOutRestart(hWaveOut16);
4108 RestoreThunkLock(level);
4112 /**************************************************************************
4113 * waveOutGetPosition [WINMM.@]
4115 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
4120 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
4122 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4123 return MMSYSERR_INVALHANDLE;
4125 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4128 /**************************************************************************
4129 * waveOutGetPosition [MMSYSTEM.412]
4131 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
4137 mmt.wType = lpTime->wType;
4138 ret = waveOutGetPosition(hWaveOut, &mmt, sizeof(mmt));
4139 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4143 /**************************************************************************
4144 * waveOutGetPitch [WINMM.@]
4146 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
4150 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4152 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4153 return MMSYSERR_INVALHANDLE;
4154 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
4157 /**************************************************************************
4158 * waveOutGetPitch [MMSYSTEM.413]
4160 UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4162 return waveOutGetPitch(hWaveOut16, lpdw);
4165 /**************************************************************************
4166 * waveOutSetPitch [WINMM.@]
4168 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
4172 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4174 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4175 return MMSYSERR_INVALHANDLE;
4176 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
4179 /**************************************************************************
4180 * waveOutSetPitch [MMSYSTEM.414]
4182 UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw)
4184 return waveOutSetPitch(hWaveOut16, dw);
4187 /**************************************************************************
4188 * waveOutGetPlaybackRate [WINMM.@]
4190 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
4194 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4196 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4197 return MMSYSERR_INVALHANDLE;
4198 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
4201 /**************************************************************************
4202 * waveOutGetPlaybackRate [MMSYSTEM.417]
4204 UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4206 return waveOutGetPlaybackRate(hWaveOut16, lpdw);
4209 /**************************************************************************
4210 * waveOutSetPlaybackRate [WINMM.@]
4212 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
4216 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4218 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4219 return MMSYSERR_INVALHANDLE;
4220 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
4223 /**************************************************************************
4224 * waveOutSetPlaybackRate [MMSYSTEM.418]
4226 UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw)
4228 return waveOutSetPlaybackRate(hWaveOut16, dw);
4231 /**************************************************************************
4232 * waveOutGetVolume [WINMM.@]
4234 UINT WINAPI waveOutGetVolume(UINT devid, LPDWORD lpdw)
4238 TRACE("(%04X, %08lx);\n", devid, (DWORD)lpdw);
4240 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4241 return MMSYSERR_INVALHANDLE;
4243 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
4246 /**************************************************************************
4247 * waveOutGetVolume [MMSYSTEM.415]
4249 UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw)
4251 return waveOutGetVolume(devid, lpdw);
4254 /**************************************************************************
4255 * waveOutSetVolume [WINMM.@]
4257 UINT WINAPI waveOutSetVolume(UINT devid, DWORD dw)
4261 TRACE("(%04X, %08lx);\n", devid, dw);
4263 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4264 return MMSYSERR_INVALHANDLE;
4266 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
4269 /**************************************************************************
4270 * waveOutSetVolume [MMSYSTEM.416]
4272 UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw)
4274 return waveOutSetVolume(devid, dw);
4277 /**************************************************************************
4278 * waveOutGetID [WINMM.@]
4280 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
4284 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4286 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4288 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4289 return MMSYSERR_INVALHANDLE;
4291 *lpuDeviceID = wmld->uDeviceID;
4295 /**************************************************************************
4296 * waveOutGetID [MMSYSTEM.420]
4298 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
4302 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4304 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4306 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4307 return MMSYSERR_INVALHANDLE;
4309 *lpuDeviceID = wmld->uDeviceID;
4313 /**************************************************************************
4314 * waveOutMessage [WINMM.@]
4316 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
4317 DWORD dwParam1, DWORD dwParam2)
4321 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4323 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4324 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4325 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4327 return MMSYSERR_INVALHANDLE;
4331 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4332 return MMSYSERR_INVALPARAM;
4334 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4337 /**************************************************************************
4338 * waveOutMessage [MMSYSTEM.421]
4340 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4341 DWORD dwParam1, DWORD dwParam2)
4345 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4347 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4348 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4349 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4351 return MMSYSERR_INVALHANDLE;
4355 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4356 return MMSYSERR_INVALPARAM;
4358 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
4361 /**************************************************************************
4362 * waveInGetNumDevs [WINMM.@]
4364 UINT WINAPI waveInGetNumDevs(void)
4366 return MMDRV_GetNum(MMDRV_WAVEIN);
4369 /**************************************************************************
4370 * waveInGetNumDevs [MMSYSTEM.501]
4372 UINT16 WINAPI waveInGetNumDevs16(void)
4374 return MMDRV_GetNum(MMDRV_WAVEIN);
4377 /**************************************************************************
4378 * waveInGetDevCapsW [WINMM.@]
4380 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4383 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
4385 if (ret == MMSYSERR_NOERROR) {
4386 lpCaps->wMid = wicA.wMid;
4387 lpCaps->wPid = wicA.wPid;
4388 lpCaps->vDriverVersion = wicA.vDriverVersion;
4389 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
4390 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
4391 lpCaps->dwFormats = wicA.dwFormats;
4392 lpCaps->wChannels = wicA.wChannels;
4398 /**************************************************************************
4399 * waveInGetDevCapsA [WINMM.@]
4401 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4405 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
4407 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
4408 return MMSYSERR_INVALHANDLE;
4410 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
4413 /**************************************************************************
4414 * waveInGetDevCaps [MMSYSTEM.502]
4416 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps,
4420 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
4422 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
4424 if (ret == MMSYSERR_NOERROR) {
4425 lpCaps->wMid = wicA.wMid;
4426 lpCaps->wPid = wicA.wPid;
4427 lpCaps->vDriverVersion = wicA.vDriverVersion;
4428 strcpy(lpCaps->szPname, wicA.szPname);
4429 lpCaps->dwFormats = wicA.dwFormats;
4430 lpCaps->wChannels = wicA.wChannels;
4435 /**************************************************************************
4436 * waveInGetErrorTextA [WINMM.@]
4438 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4440 return WAVE_GetErrorText(uError, lpText, uSize);
4443 /**************************************************************************
4444 * waveInGetErrorTextW [WINMM.@]
4446 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4448 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4449 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
4451 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
4452 HeapFree(GetProcessHeap(), 0, txt);
4456 /**************************************************************************
4457 * waveInGetErrorText [MMSYSTEM.503]
4459 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4461 return WAVE_GetErrorText(uError, lpText, uSize);
4464 /**************************************************************************
4465 * waveInOpen [WINMM.@]
4467 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4468 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4469 DWORD dwInstance, DWORD dwFlags)
4471 return MMSYSTEM_waveOpen(lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
4472 dwCallback, dwInstance, dwFlags, TRUE);
4475 /**************************************************************************
4476 * waveInOpen [MMSYSTEM.504]
4478 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4479 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4480 DWORD dwInstance, DWORD dwFlags)
4485 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
4486 * call the 32 bit version
4487 * however, we need to promote correctly the wave mapper id
4488 * (0xFFFFFFFF and not 0x0000FFFF)
4490 ret = MMSYSTEM_waveOpen(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
4491 MMDRV_WAVEIN, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
4493 if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
4497 /**************************************************************************
4498 * waveInClose [WINMM.@]
4500 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4505 TRACE("(%04X)\n", hWaveIn);
4507 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4508 return MMSYSERR_INVALHANDLE;
4510 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
4511 MMDRV_Free(hWaveIn, wmld);
4515 /**************************************************************************
4516 * waveInClose [MMSYSTEM.505]
4518 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4523 ReleaseThunkLock(&level);
4524 ret = waveInClose(hWaveIn);
4525 RestoreThunkLock(level);
4529 /**************************************************************************
4530 * waveInPrepareHeader [WINMM.@]
4532 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4537 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4539 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4540 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4541 return MMSYSERR_INVALHANDLE;
4543 lpWaveInHdr->dwBytesRecorded = 0;
4545 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4548 /**************************************************************************
4549 * waveInPrepareHeader [MMSYSTEM.506]
4551 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4552 SEGPTR lpsegWaveInHdr, /* [???] */
4553 UINT16 uSize) /* [in] */
4556 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4559 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4561 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4562 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4563 return MMSYSERR_INVALHANDLE;
4565 lpWaveInHdr->dwBytesRecorded = 0;
4567 ret = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4571 /**************************************************************************
4572 * waveInUnprepareHeader [WINMM.@]
4574 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4579 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4581 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4582 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4583 return MMSYSERR_NOERROR;
4586 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4587 return MMSYSERR_INVALHANDLE;
4589 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4592 /**************************************************************************
4593 * waveInUnprepareHeader [MMSYSTEM.507]
4595 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4596 SEGPTR lpsegWaveInHdr, /* [???] */
4597 UINT16 uSize) /* [in] */
4600 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4602 TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4604 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4606 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4607 return MMSYSERR_NOERROR;
4610 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4611 return MMSYSERR_INVALHANDLE;
4613 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4616 /**************************************************************************
4617 * waveInAddBuffer [WINMM.@]
4619 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4620 WAVEHDR* lpWaveInHdr, UINT uSize)
4624 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4626 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4627 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4628 return MMSYSERR_INVALHANDLE;
4630 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
4633 /**************************************************************************
4634 * waveInAddBuffer [MMSYSTEM.508]
4636 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */
4637 WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */
4638 UINT16 uSize) /* [in] */
4642 TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4644 if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4645 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4646 return MMSYSERR_INVALHANDLE;
4648 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4651 /**************************************************************************
4652 * waveInReset [WINMM.@]
4654 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4658 TRACE("(%04X);\n", hWaveIn);
4660 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4661 return MMSYSERR_INVALHANDLE;
4663 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
4666 /**************************************************************************
4667 * waveInReset [MMSYSTEM.511]
4669 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16)
4674 ReleaseThunkLock(&level);
4675 ret = waveInReset(hWaveIn16);
4676 RestoreThunkLock(level);
4680 /**************************************************************************
4681 * waveInStart [WINMM.@]
4683 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4687 TRACE("(%04X);\n", hWaveIn);
4689 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4690 return MMSYSERR_INVALHANDLE;
4692 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
4695 /**************************************************************************
4696 * waveInStart [MMSYSTEM.509]
4698 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16)
4703 ReleaseThunkLock(&level);
4704 ret = waveInStart(hWaveIn16);
4705 RestoreThunkLock(level);
4709 /**************************************************************************
4710 * waveInStop [WINMM.@]
4712 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4716 TRACE("(%04X);\n", hWaveIn);
4718 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4719 return MMSYSERR_INVALHANDLE;
4721 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
4724 /**************************************************************************
4725 * waveInStop [MMSYSTEM.510]
4727 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16)
4732 ReleaseThunkLock(&level);
4733 ret = waveInStop(hWaveIn16);
4734 RestoreThunkLock(level);
4738 /**************************************************************************
4739 * waveInGetPosition [WINMM.@]
4741 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4746 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4748 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4749 return MMSYSERR_INVALHANDLE;
4751 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4754 /**************************************************************************
4755 * waveInGetPosition [MMSYSTEM.512]
4757 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4763 mmt.wType = lpTime->wType;
4764 ret = waveInGetPosition(hWaveIn, &mmt, sizeof(mmt));
4765 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4769 /**************************************************************************
4770 * waveInGetID [WINMM.@]
4772 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4776 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4778 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4780 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4781 return MMSYSERR_INVALHANDLE;
4783 *lpuDeviceID = wmld->uDeviceID;
4784 return MMSYSERR_NOERROR;
4787 /**************************************************************************
4788 * waveInGetID [MMSYSTEM.513]
4790 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4794 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4796 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4798 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4799 return MMSYSERR_INVALHANDLE;
4801 *lpuDeviceID = wmld->uDeviceID;
4802 return MMSYSERR_NOERROR;
4805 /**************************************************************************
4806 * waveInMessage [WINMM.@]
4808 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4809 DWORD dwParam1, DWORD dwParam2)
4813 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4816 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4817 return MMSYSERR_INVALPARAM;
4819 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4820 return MMSYSERR_INVALHANDLE;
4822 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4825 /**************************************************************************
4826 * waveInMessage [MMSYSTEM.514]
4828 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4829 DWORD dwParam1, DWORD dwParam2)
4833 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4836 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4837 return MMSYSERR_INVALPARAM;
4839 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4840 return MMSYSERR_INVALHANDLE;
4842 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4845 /*#define USE_MM_TSK_WINE*/
4847 /**************************************************************************
4848 * mmTaskCreate [MMSYSTEM.900]
4850 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4851 * called upon creation with dwPmt as parameter.
4853 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4858 DWORD showCmd = 0x40002;
4861 TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
4862 /* This to work requires NE modules to be started with a binary command line
4863 * which is not currently the case. A patch exists but has never been committed.
4864 * A workaround would be to integrate code for mmtask.tsk into Wine, but
4865 * this requires tremendous work (starting with patching tools/build to
4866 * create NE executables (and not only DLLs) for builtins modules.
4869 FIXME("This is currently broken. It will fail\n");
4872 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
4873 *(LPDWORD)(cmdline + 5) = dwPmt;
4874 *(LPDWORD)(cmdline + 9) = 0;
4876 lp.hEnvironment = 0;
4877 lp.cmdLine = MapLS(cmdline);
4878 lp.showCmd = MapLS(&showCmd);
4881 #ifndef USE_MM_TSK_WINE
4882 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp);
4884 handle = LoadModule16("mmtask.tsk", &lp);
4887 ret = (handle) ? 1 : 2;
4893 *lphMmTask = handle;
4895 UnMapLS( lp.cmdLine );
4896 UnMapLS( lp.showCmd );
4897 TRACE("=> 0x%04x/%d\n", handle, ret);
4901 #ifdef USE_MM_TSK_WINE
4902 /* C equivalent to mmtask.tsk binary content */
4903 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
4905 int len = cmdLine[0x80];
4908 void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1)));
4909 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
4912 InitTask16(); /* FIXME: pmts / from context ? */
4915 if (SetMessageQueue16(0x40)) {
4917 if (HIWORD(fpProc)) {
4919 /* EPP StackEnter16(); */
4931 /**************************************************************************
4932 * mmTaskBlock [MMSYSTEM.902]
4934 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
4939 GetMessageA(&msg, 0, 0, 0);
4941 TranslateMessage(&msg);
4942 DispatchMessageA(&msg);
4944 } while (msg.message < 0x3A0);
4947 /**************************************************************************
4948 * mmTaskSignal [MMSYSTEM.903]
4950 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
4952 TRACE("(%04x);\n", ht);
4953 return PostAppMessage16(ht, WM_USER, 0, 0);
4956 /**************************************************************************
4957 * mmGetCurrentTask [MMSYSTEM.904]
4959 HTASK16 WINAPI mmGetCurrentTask16(void)
4961 return GetCurrentTask();
4964 /**************************************************************************
4965 * mmTaskYield [MMSYSTEM.905]
4967 void WINAPI mmTaskYield16(void)
4971 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
4976 DWORD WINAPI GetProcessFlags(DWORD);
4978 /**************************************************************************
4979 * mmThreadCreate [MMSYSTEM.1120]
4982 * Creates a MM thread, calling fpThreadAddr(dwPmt).
4984 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
4985 * bit.1 set means to open a VxD for this thread (unsupported)
4987 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
4992 TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
4994 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
4999 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5002 /* force mmtask routines even if mmthread is required */
5003 /* this will work only if the patch about binary cmd line and NE tasks
5009 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
5010 lpMMThd->dwCounter = 0;
5011 lpMMThd->hThread = 0;
5012 lpMMThd->dwThreadID = 0;
5013 lpMMThd->fpThread = fpThreadAddr;
5014 lpMMThd->dwThreadPmt = dwPmt;
5015 lpMMThd->dwSignalCount = 0;
5016 lpMMThd->hEvent = 0;
5018 lpMMThd->dwStatus = 0;
5019 lpMMThd->dwFlags = dwFlags;
5022 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
5023 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
5025 TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
5026 if (lpMMThd->dwFlags & 2) {
5027 /* as long as we don't support MM VxD in wine, we don't need
5028 * to care about this flag
5030 /* FIXME("Don't know how to properly open VxD handles\n"); */
5031 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
5034 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
5035 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
5036 if (lpMMThd->hThread == 0) {
5037 WARN("Couldn't create thread\n");
5038 /* clean-up(VxDhandle...); devicedirectio... */
5039 if (lpMMThd->hEvent != 0)
5040 CloseHandle(lpMMThd->hEvent);
5043 TRACE("Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
5047 /* get WINE_mmThreadEntryPoint()
5048 * 2047 is its ordinal in mmsystem.spec
5050 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047);
5052 TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp));
5054 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
5058 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
5059 WARN("Couldn't resume thread\n");
5061 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
5075 TRACE("ok => %ld\n", ret);
5079 /**************************************************************************
5080 * mmThreadSignal [MMSYSTEM.1121]
5082 void WINAPI mmThreadSignal16(HANDLE16 hndl)
5084 TRACE("(%04x)!\n", hndl);
5087 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5089 lpMMThd->dwCounter++;
5090 if (lpMMThd->hThread != 0) {
5091 InterlockedIncrement(&lpMMThd->dwSignalCount);
5092 SetEvent(lpMMThd->hEvent);
5094 mmTaskSignal16(lpMMThd->hTask);
5096 lpMMThd->dwCounter--;
5100 /**************************************************************************
5101 * MMSYSTEM_ThreadBlock [internal]
5103 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
5108 if (lpMMThd->dwThreadID != GetCurrentThreadId())
5109 ERR("Not called by thread itself\n");
5112 ResetEvent(lpMMThd->hEvent);
5113 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
5115 InterlockedIncrement(&lpMMThd->dwSignalCount);
5119 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
5121 case WAIT_OBJECT_0: /* Event */
5124 case WAIT_OBJECT_0 + 1: /* Msg */
5126 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
5127 TranslateMessage(&msg);
5128 DispatchMessageA(&msg);
5132 WARN("S2.x unsupported ret val 0x%08lx\n", ret);
5138 /**************************************************************************
5139 * mmThreadBlock [MMSYSTEM.1122]
5141 void WINAPI mmThreadBlock16(HANDLE16 hndl)
5143 TRACE("(%04x)!\n", hndl);
5146 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5148 if (lpMMThd->hThread != 0) {
5151 ReleaseThunkLock(&lc);
5152 MMSYSTEM_ThreadBlock(lpMMThd);
5153 RestoreThunkLock(lc);
5155 mmTaskBlock16(lpMMThd->hTask);
5161 /**************************************************************************
5162 * mmThreadIsCurrent [MMSYSTEM.1123]
5164 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
5168 TRACE("(%04x)!\n", hndl);
5170 if (hndl && mmThreadIsValid16(hndl)) {
5171 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5172 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
5174 TRACE("=> %d\n", ret);
5178 /**************************************************************************
5179 * mmThreadIsValid [MMSYSTEM.1124]
5181 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
5185 TRACE("(%04x)!\n", hndl);
5188 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5190 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
5191 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
5192 IsTask16(lpMMThd->hTask)) {
5193 lpMMThd->dwCounter++;
5194 if (lpMMThd->hThread != 0) {
5196 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
5197 dwThreadRet == STATUS_PENDING) {
5203 lpMMThd->dwCounter--;
5206 TRACE("=> %d\n", ret);
5210 /**************************************************************************
5211 * mmThreadGetTask [MMSYSTEM.1125]
5213 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5217 TRACE("(%04x)\n", hndl);
5219 if (mmThreadIsValid16(hndl)) {
5220 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5221 ret = lpMMThd->hTask;
5226 /* ### start build ### */
5227 extern LONG CALLBACK MMSYSTEM_CallTo16_long_l (FARPROC16,LONG);
5228 /* ### stop build ### */
5230 /**************************************************************************
5231 * __wine_mmThreadEntryPoint (MMSYSTEM.2047)
5233 void WINAPI WINE_mmThreadEntryPoint(DWORD _pmt)
5235 HANDLE16 hndl = (HANDLE16)_pmt;
5236 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5238 TRACE("(%04x %p)\n", hndl, lpMMThd);
5240 lpMMThd->hTask = LOWORD(GetCurrentTask());
5241 TRACE("[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5242 lpMMThd->dwStatus = 0x10;
5243 MMSYSTEM_ThreadBlock(lpMMThd);
5244 TRACE("[20-%08x]\n", lpMMThd->hThread);
5245 lpMMThd->dwStatus = 0x20;
5246 if (lpMMThd->fpThread) {
5247 MMSYSTEM_CallTo16_long_l(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5249 lpMMThd->dwStatus = 0x30;
5250 TRACE("[30-%08x]\n", lpMMThd->hThread);
5251 while (lpMMThd->dwCounter) {
5253 /* K32WOWYield16();*/
5255 TRACE("[XX-%08x]\n", lpMMThd->hThread);
5257 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5258 /* close lpMMThread->hVxD directIO */
5259 if (lpMMThd->hEvent)
5260 CloseHandle(lpMMThd->hEvent);
5265 typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR);
5267 /**************************************************************************
5268 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5270 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice,
5271 LPCSTR lpStrTab, LPCSTR lpStrTitle)
5276 TRACE("(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5278 hndl = LoadLibraryA("MMSYS.CPL");
5280 MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5283 ReleaseThunkLock(&lc);
5284 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5285 RestoreThunkLock(lc);
5293 /**************************************************************************
5294 * StackEnter [MMSYSTEM.32]
5296 void WINAPI StackEnter16(void)
5299 /* mmsystem.dll from Win 95 does only this: so does Wine */
5304 /**************************************************************************
5305 * StackLeave [MMSYSTEM.33]
5307 void WINAPI StackLeave16(void)
5310 /* mmsystem.dll from Win 95 does only this: so does Wine */
5315 /**************************************************************************
5316 * WMMMidiRunOnce [MMSYSTEM.8]
5318 void WINAPI WMMMidiRunOnce16(void)
5320 FIXME("(), stub!\n");
5323 /**************************************************************************
5324 * OutputDebugStr [MMSYSTEM.30]
5326 void WINAPI OutputDebugStr16(
5327 LPCSTR str) /* [in] The message to be logged and given to the debugger. */
5329 OutputDebugStringA( str );