1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1993 Martin Ayotte
11 * 98/9 added Win32 MCI support
12 * 99/4 added mmTask and mmThread functions support
13 * added midiStream support
14 * 99/9 added support for loadable low level drivers
17 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses
18 * and long term pointers to 16 bit space in here
27 #include "wine/mmsystem16.h"
28 #include "wine/winuser16.h"
33 #include "debugtools.h"
35 DEFAULT_DEBUG_CHANNEL(mmsys);
37 static LPWINE_MM_IDATA lpFirstIData = NULL;
39 static LPWINE_MM_IDATA MULTIMEDIA_GetIDataNoCheck(void)
41 DWORD pid = GetCurrentProcessId();
42 LPWINE_MM_IDATA iData;
44 for (iData = lpFirstIData; iData; iData = iData->lpNextIData) {
45 if (iData->dwThisProcess == pid)
51 /**************************************************************************
52 * MULTIMEDIA_GetIData [internal]
54 LPWINE_MM_IDATA MULTIMEDIA_GetIData(void)
56 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
59 ERR("IData not found for pid=%08lx. Suicide !!!\n", GetCurrentProcessId());
66 /**************************************************************************
67 * MULTIMEDIA_CreateIData [internal]
69 static BOOL MULTIMEDIA_CreateIData(HINSTANCE hInstDLL)
71 LPWINE_MM_IDATA iData;
73 iData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
77 iData->hWinMM32Instance = hInstDLL;
78 iData->dwThisProcess = GetCurrentProcessId();
79 iData->lpNextIData = lpFirstIData;
81 InitializeCriticalSection(&iData->cs);
82 TRACE("Created IData (%p) for pid %08lx\n", iData, iData->dwThisProcess);
86 /**************************************************************************
87 * MULTIMEDIA_DeleteIData [internal]
89 static void MULTIMEDIA_DeleteIData(void)
91 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
92 LPWINE_MM_IDATA* ppid;
97 for (ppid = &lpFirstIData; *ppid; ppid = &(*ppid)->lpNextIData) {
99 *ppid = iData->lpNextIData;
103 /* FIXME: should also free content and resources allocated
105 HeapFree(GetProcessHeap(), 0, iData);
109 /**************************************************************************
110 * DllEntryPoint (WINMM.init)
112 * WINMM DLL entry point
115 BOOL WINAPI WINMM_LibMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
117 TRACE("0x%x 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
120 case DLL_PROCESS_ATTACH:
121 if (!MULTIMEDIA_CreateIData(hInstDLL))
123 if (!MULTIMEDIA_MciInit() || !MMDRV_Init()) {
124 MULTIMEDIA_DeleteIData();
128 case DLL_PROCESS_DETACH:
129 MULTIMEDIA_DeleteIData();
131 case DLL_THREAD_ATTACH:
132 case DLL_THREAD_DETACH:
138 /**************************************************************************
139 * DllEntryPoint (MMSYSTEM.2046)
141 * MMSYSTEM DLL entry point
144 BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds,
145 WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
148 LPWINE_MM_IDATA iData;
150 TRACE("0x%x 0x%lx\n", hinstDLL, fdwReason);
153 case DLL_PROCESS_ATTACH:
154 /* need to load WinMM in order to:
155 * - initiate correctly shared variables (MULTIMEDIA_Init())
156 * - create correctly the per process WINE_MM_IDATA chunk
158 hndl = LoadLibraryA("WINMM.DLL");
161 ERR("Could not load sibling WinMM.dll\n");
164 iData = MULTIMEDIA_GetIData();
165 iData->hWinMM16Instance = hinstDLL;
166 iData->h16Module32 = hndl;
168 case DLL_PROCESS_DETACH:
169 iData = MULTIMEDIA_GetIData();
170 FreeLibrary(iData->h16Module32);
172 case DLL_THREAD_ATTACH:
173 case DLL_THREAD_DETACH:
179 /**************************************************************************
180 * MMSYSTEM_WEP [MMSYSTEM.1]
182 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
183 WORD cbHeapSize, LPSTR lpCmdLine)
185 FIXME("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
189 void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
191 mmt16->wType = mmt32->wType;
192 /* layout of rest is the same for 32/16,
193 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
195 memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
198 void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
200 mmt32->wType = mmt16->wType;
201 /* layout of rest is the same for 32/16,
202 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
204 memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
207 static HANDLE PlaySound_hThread = 0;
208 static HANDLE PlaySound_hPlayEvent = 0;
209 static HANDLE PlaySound_hReadyEvent = 0;
210 static HANDLE PlaySound_hMiddleEvent = 0;
211 static BOOL PlaySound_Result = FALSE;
212 static int PlaySound_Stop = FALSE;
213 static int PlaySound_Playing = FALSE;
215 static LPCSTR PlaySound_pszSound = NULL;
216 static HMODULE PlaySound_hmod = 0;
217 static DWORD PlaySound_fdwSound = 0;
218 static int PlaySound_Loop = FALSE;
219 static int PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
220 2 - PlaySound order */
222 static HMMIO get_mmioFromFile(LPCSTR lpszName)
224 return mmioOpenA((LPSTR)lpszName, NULL,
225 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
228 static HMMIO get_mmioFromProfile(UINT uFlags, LPCSTR lpszName)
234 TRACE("searching in SystemSound List !\n");
235 GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
236 if (strlen(str) == 0) {
237 if (uFlags & SND_NODEFAULT) return 0;
238 GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
239 if (strlen(str) == 0) return 0;
241 if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
242 hmmio = get_mmioFromFile(str);
244 WARN("can't find SystemSound='%s' !\n", str);
250 struct playsound_data {
255 static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg,
257 DWORD dwParam1, DWORD dwParam2)
259 struct playsound_data* s = (struct playsound_data*)dwInstance;
266 InterlockedIncrement(&s->dwEventCount);
267 TRACE("Returning waveHdr=%lx\n", dwParam1);
271 ERR("Unknown uMsg=%d\n", uMsg);
275 static void PlaySound_WaitDone(struct playsound_data* s)
278 ResetEvent(s->hEvent);
279 if (InterlockedDecrement(&s->dwEventCount) >= 0) {
282 InterlockedIncrement(&s->dwEventCount);
284 WaitForSingleObject(s->hEvent, INFINITE);
288 static BOOL WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
294 LPWAVEFORMATEX lpWaveFormat = NULL;
296 LPWAVEHDR waveHdr = NULL;
297 INT count, bufsize, left, index;
298 struct playsound_data s;
302 TRACE("SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
303 if (lpszSoundName == NULL) {
307 if (uFlags & SND_MEMORY) {
309 memset(&mminfo, 0, sizeof(mminfo));
310 mminfo.fccIOProc = FOURCC_MEM;
311 mminfo.pchBuffer = (LPSTR)lpszSoundName;
312 mminfo.cchBuffer = -1;
313 TRACE("Memory sound %p\n", lpszSoundName);
314 hmmio = mmioOpenA(NULL, &mminfo, MMIO_READ);
317 if (uFlags & SND_ALIAS)
318 if ((hmmio = get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
321 if (uFlags & SND_FILENAME)
322 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
324 if (PlaySound_SearchMode == 1) {
325 PlaySound_SearchMode = 0;
326 if ((hmmio = get_mmioFromFile(lpszSoundName)) == 0)
327 hmmio = get_mmioFromProfile(uFlags, lpszSoundName);
330 if (PlaySound_SearchMode == 2) {
331 PlaySound_SearchMode = 0;
332 if ((hmmio = get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0)
333 if ((hmmio = get_mmioFromFile(lpszSoundName)) == 0)
334 hmmio = get_mmioFromProfile(uFlags, lpszSoundName);
337 if (hmmio == 0) return FALSE;
339 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0))
342 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
343 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
345 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
346 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
349 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
350 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
353 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
354 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
356 lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
357 if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT))
360 TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag);
361 TRACE("nChannels=%d \n", lpWaveFormat->nChannels);
362 TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec);
363 TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec);
364 TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign);
365 TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample);
367 /* move to end of 'fmt ' chunk */
368 mmioAscend(hmmio, &mmckInfo, 0);
370 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
371 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
374 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
375 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
377 s.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
379 if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback,
380 (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
383 /* make it so that 3 buffers per second are needed */
384 bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) *
385 lpWaveFormat->nBlockAlign;
386 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
387 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
388 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
389 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
390 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
391 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
392 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
393 if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
394 waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) {
400 left = mmckInfo.cksize;
401 s.dwEventCount = 1L; /* for first buffer */
403 mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
405 if (PlaySound_Stop) {
406 PlaySound_Stop = PlaySound_Loop = FALSE;
409 count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
410 if (count < 1) break;
412 waveHdr[index].dwBufferLength = count;
413 waveHdr[index].dwFlags &= ~WHDR_DONE;
414 waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR));
416 PlaySound_WaitDone(&s);
419 } while (PlaySound_Loop);
421 PlaySound_WaitDone(&s);
424 waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
425 waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
428 CloseHandle(s.hEvent);
429 HeapFree(GetProcessHeap(), 0, waveHdr);
430 HeapFree(GetProcessHeap(), 0, lpWaveFormat);
431 if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
432 if (hmmio) mmioClose(hmmio, 0);
437 static DWORD WINAPI PlaySound_Thread(LPVOID arg)
442 PlaySound_Playing = FALSE;
443 SetEvent(PlaySound_hReadyEvent);
444 res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
445 ResetEvent(PlaySound_hReadyEvent);
446 SetEvent(PlaySound_hMiddleEvent);
447 if (res == WAIT_FAILED) ExitThread(2);
448 if (res != WAIT_OBJECT_0) continue;
449 PlaySound_Playing = TRUE;
451 if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
456 if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
457 PlaySound_Result = FALSE;
460 if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
461 PlaySound_Result = FALSE;
464 if ((ptr = LockResource(hGLOB)) == NULL) {
466 PlaySound_Result = FALSE;
469 PlaySound_Result = proc_PlaySound(ptr,
470 ((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
474 PlaySound_Result = proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
478 /**************************************************************************
480 * PlaySound [WINMM.@]
481 * PlaySoundA [WINMM.@]
483 BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
485 static LPSTR StrDup = NULL;
487 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
488 pszSound, hmod, fdwSound);
490 if (PlaySound_hThread == 0) { /* This is the first time they called us */
492 if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
494 if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
496 if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
498 if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0)
502 /* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */
503 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing)
506 /* Trying to stop if playing */
507 if (PlaySound_Playing) PlaySound_Stop = TRUE;
509 /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
510 if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
513 if (!pszSound || (fdwSound & SND_PURGE))
514 return TRUE; /* We stopped playing so leaving */
516 if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
517 if (!(fdwSound & SND_ASYNC)) {
518 if (fdwSound & SND_LOOP)
520 PlaySound_pszSound = pszSound;
521 PlaySound_hmod = hmod;
522 PlaySound_fdwSound = fdwSound;
523 PlaySound_Result = FALSE;
524 SetEvent(PlaySound_hPlayEvent);
525 if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0)
527 if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0)
529 return PlaySound_Result;
531 PlaySound_hmod = hmod;
532 PlaySound_fdwSound = fdwSound;
533 PlaySound_Result = FALSE;
535 HeapFree(GetProcessHeap(), 0, StrDup);
538 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
539 !((DWORD)pszSound >> 16)) || !pszSound))
541 StrDup = HeapAlloc(GetProcessHeap(), 0, strlen(pszSound)+1 );
542 strcpy( StrDup, pszSound );
543 PlaySound_pszSound = StrDup;
544 } else PlaySound_pszSound = pszSound;
545 PlaySound_Loop = fdwSound & SND_LOOP;
546 SetEvent(PlaySound_hPlayEvent);
547 ResetEvent(PlaySound_hMiddleEvent);
553 /**************************************************************************
554 * PlaySoundW [WINMM.@]
556 BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
561 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
562 !((DWORD)pszSound >> 16)) || !pszSound)) {
563 pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
564 bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
565 HeapFree(GetProcessHeap(), 0, pszSoundA);
567 bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
572 /**************************************************************************
573 * PlaySound [MMSYSTEM.3]
575 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
580 ReleaseThunkLock(&lc);
581 retv = PlaySoundA(pszSound, hmod, fdwSound);
582 RestoreThunkLock(lc);
587 /**************************************************************************
588 * sndPlaySoundA [WINMM.@]
590 BOOL WINAPI sndPlaySoundA(LPCSTR lpszSoundName, UINT uFlags)
592 PlaySound_SearchMode = 1;
593 return PlaySoundA(lpszSoundName, 0, uFlags);
596 /**************************************************************************
597 * sndPlaySoundW [WINMM.@]
599 BOOL WINAPI sndPlaySoundW(LPCWSTR lpszSoundName, UINT uFlags)
601 PlaySound_SearchMode = 1;
602 return PlaySoundW(lpszSoundName, 0, uFlags);
605 /**************************************************************************
606 * sndPlaySound [MMSYSTEM.2]
608 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
613 ReleaseThunkLock(&lc);
614 retv = sndPlaySoundA( lpszSoundName, uFlags );
615 RestoreThunkLock(lc);
621 /**************************************************************************
622 * mmsystemGetVersion [WINMM.@]
624 UINT WINAPI mmsystemGetVersion(void)
626 return mmsystemGetVersion16();
629 /**************************************************************************
630 * mmsystemGetVersion [MMSYSTEM.5]
631 * return value borrowed from Win95 winmm.dll ;)
633 UINT16 WINAPI mmsystemGetVersion16(void)
635 TRACE("3.10 (Win95?)\n");
639 /**************************************************************************
640 * DriverCallback [WINMM.@]
642 BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
643 UINT wMsg, DWORD dwUser, DWORD dwParam1,
646 TRACE("(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
647 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
649 switch (uFlags & DCB_TYPEMASK) {
653 WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack);
656 TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
657 if (!IsWindow(dwCallBack))
659 PostMessageA((HWND16)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 * mciGetErrorStringA [WINMM.@]
1543 BOOL WINAPI mciGetErrorStringA(DWORD wError, LPSTR lpstrBuffer, UINT uLength)
1545 return mciGetErrorString16(wError, lpstrBuffer, uLength);
1548 /**************************************************************************
1549 * mciGetErrorString [MMSYSTEM.706]
1551 BOOL16 WINAPI mciGetErrorString16(DWORD dwError, LPSTR lpstrBuffer, UINT16 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 if (!IsWindow(hWndCallBack)) {
1574 WARN("bad hWnd for call back (0x%04x)\n", hWndCallBack);
1577 TRACE("before PostMessage\n");
1578 PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1582 /**************************************************************************
1583 * mciDriverNotify [WINMM.@]
1585 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1588 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1590 if (!IsWindow(hWndCallBack)) {
1591 WARN("bad hWnd for call back (0x%04x)\n", hWndCallBack);
1594 TRACE("before PostMessage\n");
1595 PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1599 /**************************************************************************
1600 * mciGetDriverData [MMSYSTEM.708]
1602 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1604 return mciGetDriverData(uDeviceID);
1607 /**************************************************************************
1608 * mciGetDriverData [WINMM.@]
1610 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1612 LPWINE_MCIDRIVER wmd;
1614 TRACE("(%04x)\n", uDeviceID);
1616 wmd = MCI_GetDriver(uDeviceID);
1619 WARN("Bad uDeviceID\n");
1623 return wmd->dwPrivate;
1626 /**************************************************************************
1627 * mciSetDriverData [MMSYSTEM.707]
1629 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1631 return mciSetDriverData(uDeviceID, data);
1634 /**************************************************************************
1635 * mciSetDriverData [WINMM.@]
1637 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1639 LPWINE_MCIDRIVER wmd;
1641 TRACE("(%04x, %08lx)\n", uDeviceID, data);
1643 wmd = MCI_GetDriver(uDeviceID);
1646 WARN("Bad uDeviceID\n");
1650 wmd->dwPrivate = data;
1654 /**************************************************************************
1655 * mciSendCommandA [WINMM.@]
1657 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1661 TRACE("(%08x, %s, %08lx, %08lx)\n",
1662 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1664 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
1665 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1666 TRACE("=> %08lx\n", dwRet);
1670 /**************************************************************************
1671 * mciSendCommandW [WINMM.@]
1673 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1675 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
1676 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1677 return MCIERR_UNSUPPORTED_FUNCTION;
1680 /**************************************************************************
1681 * mciSendCommand [MMSYSTEM.701]
1683 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1687 TRACE("(%04X, %s, %08lX, %08lX)\n",
1688 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1690 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE);
1691 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1692 TRACE("=> %ld\n", dwRet);
1696 /**************************************************************************
1697 * mciGetDeviceID [MMSYSTEM.703]
1699 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1701 TRACE("(\"%s\")\n", lpstrName);
1703 return MCI_GetDriverFromString(lpstrName);
1706 /**************************************************************************
1707 * mciGetDeviceIDA [WINMM.@]
1709 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1711 return MCI_GetDriverFromString(lpstrName);
1714 /**************************************************************************
1715 * mciGetDeviceIDW [WINMM.@]
1717 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1722 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1723 ret = MCI_GetDriverFromString(lpstrName);
1724 HeapFree(GetProcessHeap(), 0, lpstrName);
1728 /**************************************************************************
1729 * MCI_DefYieldProc [internal]
1731 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1735 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1737 if ((HIWORD(data) != 0 && GetActiveWindow() != HIWORD(data)) ||
1738 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1744 msg.hwnd = HIWORD(data);
1745 while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1751 /**************************************************************************
1752 * mciSetYieldProc [MMSYSTEM.714]
1754 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData)
1756 LPWINE_MCIDRIVER wmd;
1758 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1760 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1761 WARN("Bad uDeviceID\n");
1765 wmd->lpfnYieldProc = (YIELDPROC)fpYieldProc;
1766 wmd->dwYieldData = dwYieldData;
1772 /**************************************************************************
1773 * mciSetYieldProc [WINMM.@]
1775 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1777 LPWINE_MCIDRIVER wmd;
1779 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1781 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1782 WARN("Bad uDeviceID\n");
1786 wmd->lpfnYieldProc = fpYieldProc;
1787 wmd->dwYieldData = dwYieldData;
1793 /**************************************************************************
1794 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
1796 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1798 FIXME("(%lu, %s) stub\n", dwElementID, lpstrType);
1802 /**************************************************************************
1803 * mciGetDeviceIDFromElementIDW [WINMM.@]
1805 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1807 /* FIXME: that's rather strange, there is no
1808 * mciGetDeviceIDFromElementID32A in winmm.spec
1810 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1814 /**************************************************************************
1815 * mciGetYieldProc [MMSYSTEM.716]
1817 YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1819 LPWINE_MCIDRIVER wmd;
1821 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1823 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1824 WARN("Bad uDeviceID\n");
1827 if (!wmd->lpfnYieldProc) {
1828 WARN("No proc set\n");
1832 WARN("Proc is 32 bit\n");
1835 return (YIELDPROC16)wmd->lpfnYieldProc;
1838 /**************************************************************************
1839 * mciGetYieldProc [WINMM.@]
1841 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1843 LPWINE_MCIDRIVER wmd;
1845 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1847 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1848 WARN("Bad uDeviceID\n");
1851 if (!wmd->lpfnYieldProc) {
1852 WARN("No proc set\n");
1856 WARN("Proc is 32 bit\n");
1859 return wmd->lpfnYieldProc;
1862 /**************************************************************************
1863 * mciGetCreatorTask [MMSYSTEM.717]
1865 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1867 return mciGetCreatorTask(uDeviceID);
1870 /**************************************************************************
1871 * mciGetCreatorTask [WINMM.@]
1873 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1875 LPWINE_MCIDRIVER wmd;
1878 TRACE("(%u)\n", uDeviceID);
1880 ret = (!(wmd = MCI_GetDriver(uDeviceID))) ? 0 : wmd->hCreatorTask;
1882 TRACE("=> %04x\n", ret);
1886 /**************************************************************************
1887 * mciDriverYield [MMSYSTEM.710]
1889 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
1891 LPWINE_MCIDRIVER wmd;
1894 /* TRACE("(%04x)\n", uDeviceID); */
1896 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) {
1899 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1905 /**************************************************************************
1906 * mciDriverYield [WINMM.@]
1908 UINT WINAPI mciDriverYield(UINT uDeviceID)
1910 LPWINE_MCIDRIVER wmd;
1913 TRACE("(%04x)\n", uDeviceID);
1915 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
1918 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1924 /**************************************************************************
1925 * midiOutGetNumDevs [WINMM.@]
1927 UINT WINAPI midiOutGetNumDevs(void)
1929 return MMDRV_GetNum(MMDRV_MIDIOUT);
1932 /**************************************************************************
1933 * midiOutGetNumDevs [MMSYSTEM.201]
1935 UINT16 WINAPI midiOutGetNumDevs16(void)
1937 return MMDRV_GetNum(MMDRV_MIDIOUT);
1940 /**************************************************************************
1941 * midiOutGetDevCapsW [WINMM.@]
1943 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
1949 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
1950 lpCaps->wMid = mocA.wMid;
1951 lpCaps->wPid = mocA.wPid;
1952 lpCaps->vDriverVersion = mocA.vDriverVersion;
1953 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
1954 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1955 lpCaps->wTechnology = mocA.wTechnology;
1956 lpCaps->wVoices = mocA.wVoices;
1957 lpCaps->wNotes = mocA.wNotes;
1958 lpCaps->wChannelMask = mocA.wChannelMask;
1959 lpCaps->dwSupport = mocA.dwSupport;
1963 /**************************************************************************
1964 * midiOutGetDevCapsA [WINMM.@]
1966 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
1971 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
1973 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1975 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1976 return MMSYSERR_INVALHANDLE;
1978 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1981 /**************************************************************************
1982 * midiOutGetDevCaps [MMSYSTEM.202]
1984 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps,
1990 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1992 dwRet = midiOutGetDevCapsA(uDeviceID, &capsA, sizeof(capsA));
1993 if (dwRet == MMSYSERR_NOERROR) {
1994 lpCaps->wMid = capsA.wMid;
1995 lpCaps->wPid = capsA.wPid;
1996 lpCaps->vDriverVersion = capsA.vDriverVersion;
1997 strcpy(lpCaps->szPname, capsA.szPname);
1998 lpCaps->wTechnology = capsA.wTechnology;
1999 lpCaps->wVoices = capsA.wVoices;
2000 lpCaps->wNotes = capsA.wNotes;
2001 lpCaps->wChannelMask = capsA.wChannelMask;
2002 lpCaps->dwSupport = capsA.dwSupport;
2007 /**************************************************************************
2008 * MIDI_GetErrorText [internal]
2010 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2012 UINT16 ret = MMSYSERR_BADERRNUM;
2014 if (lpText == NULL) {
2015 ret = MMSYSERR_INVALPARAM;
2016 } else if (uSize == 0) {
2017 ret = MMSYSERR_NOERROR;
2019 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2020 * a warning for the test was always true */
2021 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
2022 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
2024 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
2025 uError, lpText, uSize) > 0) {
2026 ret = MMSYSERR_NOERROR;
2032 /**************************************************************************
2033 * midiOutGetErrorTextA [WINMM.@]
2035 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2037 return MIDI_GetErrorText(uError, lpText, uSize);
2040 /**************************************************************************
2041 * midiOutGetErrorTextW [WINMM.@]
2043 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2045 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2048 ret = MIDI_GetErrorText(uError, xstr, uSize);
2049 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2050 HeapFree(GetProcessHeap(), 0, xstr);
2054 /**************************************************************************
2055 * midiOutGetErrorText [MMSYSTEM.203]
2057 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2059 return MIDI_GetErrorText(uError, lpText, uSize);
2062 /**************************************************************************
2063 * MIDI_OutAlloc [internal]
2065 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
2066 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
2067 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
2073 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
2075 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
2076 lpdwCallback, lpdwInstance, bFrom32);
2078 if (lphMidiOut != NULL)
2079 *lphMidiOut = hMidiOut;
2082 lpwm->mod.hMidi = hMidiOut;
2083 lpwm->mod.dwCallback = *lpdwCallback;
2084 lpwm->mod.dwInstance = *lpdwInstance;
2085 lpwm->mod.dnDevNode = 0;
2086 lpwm->mod.cIds = cIDs;
2088 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2093 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
2094 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2100 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2101 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2103 if (lphMidiOut != NULL) *lphMidiOut = 0;
2105 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
2109 return MMSYSERR_NOMEM;
2111 lpwm->mld.uDeviceID = uDeviceID;
2113 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
2116 if (dwRet != MMSYSERR_NOERROR) {
2117 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
2121 if (lphMidiOut) *lphMidiOut = hMidiOut;
2122 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
2127 /**************************************************************************
2128 * midiOutOpen [WINMM.@]
2130 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2131 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2133 return MMSYSTEM_midiOutOpen(lphMidiOut, uDeviceID, dwCallback,
2134 dwInstance, dwFlags, TRUE);
2137 /**************************************************************************
2138 * midiOutOpen [MMSYSTEM.204]
2140 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2141 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2146 ret = MMSYSTEM_midiOutOpen(&hmo, uDeviceID, dwCallback, dwInstance,
2149 if (lphMidiOut != NULL) *lphMidiOut = hmo;
2153 /**************************************************************************
2154 * midiOutClose [WINMM.@]
2156 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2161 TRACE("(%04X)\n", hMidiOut);
2163 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2164 return MMSYSERR_INVALHANDLE;
2166 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
2167 MMDRV_Free(hMidiOut, wmld);
2172 /**************************************************************************
2173 * midiOutClose [MMSYSTEM.205]
2175 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2177 return midiOutClose(hMidiOut);
2180 /**************************************************************************
2181 * midiOutPrepareHeader [WINMM.@]
2183 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2184 MIDIHDR* lpMidiOutHdr, UINT uSize)
2188 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2190 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2191 return MMSYSERR_INVALHANDLE;
2193 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2196 /**************************************************************************
2197 * midiOutPrepareHeader [MMSYSTEM.206]
2199 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2200 SEGPTR lpsegMidiOutHdr, /* [???] */
2201 UINT16 uSize) /* [in] */
2205 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2207 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2208 return MMSYSERR_INVALHANDLE;
2210 return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE);
2213 /**************************************************************************
2214 * midiOutUnprepareHeader [WINMM.@]
2216 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2217 MIDIHDR* lpMidiOutHdr, UINT uSize)
2221 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2223 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2224 return MMSYSERR_NOERROR;
2227 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2228 return MMSYSERR_INVALHANDLE;
2230 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2233 /**************************************************************************
2234 * midiOutUnprepareHeader [MMSYSTEM.207]
2236 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2237 SEGPTR lpsegMidiOutHdr, /* [???] */
2238 UINT16 uSize) /* [in] */
2241 LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr);
2243 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2245 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2246 return MMSYSERR_NOERROR;
2249 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2250 return MMSYSERR_INVALHANDLE;
2252 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2255 /**************************************************************************
2256 * midiOutShortMsg [WINMM.@]
2258 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2262 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
2264 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2265 return MMSYSERR_INVALHANDLE;
2267 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, FALSE);
2270 /**************************************************************************
2271 * midiOutShortMsg [MMSYSTEM.208]
2273 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2275 return midiOutShortMsg(hMidiOut, dwMsg);
2278 /**************************************************************************
2279 * midiOutLongMsg [WINMM.@]
2281 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2282 MIDIHDR* lpMidiOutHdr, UINT uSize)
2286 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2288 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2289 return MMSYSERR_INVALHANDLE;
2291 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
2294 /**************************************************************************
2295 * midiOutLongMsg [MMSYSTEM.209]
2297 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */
2298 LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */
2299 UINT16 uSize) /* [in] */
2303 TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2305 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2306 return MMSYSERR_INVALHANDLE;
2308 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2311 /**************************************************************************
2312 * midiOutReset [WINMM.@]
2314 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2318 TRACE("(%04X)\n", hMidiOut);
2320 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2321 return MMSYSERR_INVALHANDLE;
2323 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
2326 /**************************************************************************
2327 * midiOutReset [MMSYSTEM.210]
2329 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2331 return midiOutReset(hMidiOut);
2334 /**************************************************************************
2335 * midiOutGetVolume [WINMM.@]
2337 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2341 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
2343 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2344 return MMSYSERR_INVALHANDLE;
2346 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
2349 /**************************************************************************
2350 * midiOutGetVolume [MMSYSTEM.211]
2352 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2354 return midiOutGetVolume(uDeviceID, lpdwVolume);
2357 /**************************************************************************
2358 * midiOutSetVolume [WINMM.@]
2360 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2364 TRACE("(%04X, %ld);\n", uDeviceID, dwVolume);
2366 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2367 return MMSYSERR_INVALHANDLE;
2369 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
2372 /**************************************************************************
2373 * midiOutSetVolume [MMSYSTEM.212]
2375 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2377 return midiOutSetVolume(uDeviceID, dwVolume);
2380 /**************************************************************************
2381 * midiOutCachePatches [WINMM.@]
2383 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2384 WORD* lpwPatchArray, UINT uFlags)
2386 /* not really necessary to support this */
2387 FIXME("not supported yet\n");
2388 return MMSYSERR_NOTSUPPORTED;
2391 /**************************************************************************
2392 * midiOutCachePatches [MMSYSTEM.213]
2394 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2395 WORD* lpwPatchArray, UINT16 uFlags)
2397 return midiOutCachePatches(hMidiOut, uBank, lpwPatchArray, uFlags);
2400 /**************************************************************************
2401 * midiOutCacheDrumPatches [WINMM.@]
2403 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2404 WORD* lpwKeyArray, UINT uFlags)
2406 FIXME("not supported yet\n");
2407 return MMSYSERR_NOTSUPPORTED;
2410 /**************************************************************************
2411 * midiOutCacheDrumPatches [MMSYSTEM.214]
2413 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2414 WORD* lpwKeyArray, UINT16 uFlags)
2416 return midiOutCacheDrumPatches16(hMidiOut, uPatch, lpwKeyArray, uFlags);
2419 /**************************************************************************
2420 * midiOutGetID [WINMM.@]
2422 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2426 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2428 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2429 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2430 return MMSYSERR_INVALHANDLE;
2432 *lpuDeviceID = wmld->uDeviceID;
2433 return MMSYSERR_NOERROR;
2436 /**************************************************************************
2437 * midiOutGetID [MMSYSTEM.215]
2439 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2443 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2445 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2446 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2447 return MMSYSERR_INVALHANDLE;
2449 *lpuDeviceID = wmld->uDeviceID;
2450 return MMSYSERR_NOERROR;
2453 /**************************************************************************
2454 * midiOutMessage [WINMM.@]
2456 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2457 DWORD dwParam1, DWORD dwParam2)
2461 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2463 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2464 return MMSYSERR_INVALHANDLE;
2469 FIXME("can't handle OPEN or CLOSE message!\n");
2470 return MMSYSERR_NOTSUPPORTED;
2472 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2475 /**************************************************************************
2476 * midiOutMessage [MMSYSTEM.216]
2478 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2479 DWORD dwParam1, DWORD dwParam2)
2483 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2485 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2486 return MMSYSERR_INVALHANDLE;
2491 FIXME("can't handle OPEN or CLOSE message!\n");
2492 return MMSYSERR_NOTSUPPORTED;
2494 case MODM_GETVOLUME:
2495 return midiOutGetVolume16(hMidiOut, MapSL(dwParam1));
2497 return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2);
2499 /* lpMidiOutHdr is still a segmented pointer for this function */
2500 return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2);
2501 case MODM_UNPREPARE:
2502 return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2);
2504 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2507 /**************************************************************************
2508 * midiInGetNumDevs [WINMM.@]
2510 UINT WINAPI midiInGetNumDevs(void)
2512 return MMDRV_GetNum(MMDRV_MIDIIN);
2515 /**************************************************************************
2516 * midiInGetNumDevs [MMSYSTEM.301]
2518 UINT16 WINAPI midiInGetNumDevs16(void)
2520 return MMDRV_GetNum(MMDRV_MIDIIN);
2523 /**************************************************************************
2524 * midiInGetDevCapsW [WINMM.@]
2526 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2529 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2531 if (ret == MMSYSERR_NOERROR) {
2532 lpCaps->wMid = micA.wMid;
2533 lpCaps->wPid = micA.wPid;
2534 lpCaps->vDriverVersion = micA.vDriverVersion;
2535 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
2536 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2537 lpCaps->dwSupport = micA.dwSupport;
2542 /**************************************************************************
2543 * midiInGetDevCapsA [WINMM.@]
2545 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2549 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
2551 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
2552 return MMSYSERR_INVALHANDLE;
2554 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2557 /**************************************************************************
2558 * midiInGetDevCaps [MMSYSTEM.302]
2560 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps,
2564 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2566 if (ret == MMSYSERR_NOERROR) {
2567 lpCaps->wMid = micA.wMid;
2568 lpCaps->wPid = micA.wPid;
2569 lpCaps->vDriverVersion = micA.vDriverVersion;
2570 strcpy(lpCaps->szPname, micA.szPname);
2571 lpCaps->dwSupport = micA.dwSupport;
2577 /**************************************************************************
2578 * midiInGetErrorTextW [WINMM.@]
2580 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2582 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2583 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
2585 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2586 HeapFree(GetProcessHeap(), 0, xstr);
2590 /**************************************************************************
2591 * midiInGetErrorTextA [WINMM.@]
2593 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2595 return MIDI_GetErrorText(uError, lpText, uSize);
2598 /**************************************************************************
2599 * midiInGetErrorText [MMSYSTEM.303]
2601 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2603 return MIDI_GetErrorText(uError, lpText, uSize);
2606 static UINT MMSYSTEM_midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
2607 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2613 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2614 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2616 if (lphMidiIn != NULL) *lphMidiIn = 0;
2618 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
2619 &dwFlags, &dwCallback, &dwInstance, bFrom32);
2622 return MMSYSERR_NOMEM;
2624 lpwm->mod.hMidi = hMidiIn;
2625 lpwm->mod.dwCallback = dwCallback;
2626 lpwm->mod.dwInstance = dwInstance;
2628 lpwm->mld.uDeviceID = uDeviceID;
2629 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
2631 if (dwRet != MMSYSERR_NOERROR) {
2632 MMDRV_Free(hMidiIn, &lpwm->mld);
2635 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
2636 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
2641 /**************************************************************************
2642 * midiInOpen [WINMM.@]
2644 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2645 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2647 return MMSYSTEM_midiInOpen(lphMidiIn, uDeviceID, dwCallback,
2648 dwInstance, dwFlags, TRUE);
2651 /**************************************************************************
2652 * midiInOpen [MMSYSTEM.304]
2654 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2655 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2660 ret = MMSYSTEM_midiInOpen(&xhmid, uDeviceID, dwCallback, dwInstance,
2663 if (lphMidiIn) *lphMidiIn = xhmid;
2667 /**************************************************************************
2668 * midiInClose [WINMM.@]
2670 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2675 TRACE("(%04X)\n", hMidiIn);
2677 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2678 return MMSYSERR_INVALHANDLE;
2680 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
2681 MMDRV_Free(hMidiIn, wmld);
2685 /**************************************************************************
2686 * midiInClose [MMSYSTEM.305]
2688 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2690 return midiInClose(hMidiIn);
2693 /**************************************************************************
2694 * midiInPrepareHeader [WINMM.@]
2696 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2697 MIDIHDR* lpMidiInHdr, UINT uSize)
2701 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2703 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2704 return MMSYSERR_INVALHANDLE;
2706 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2709 /**************************************************************************
2710 * midiInPrepareHeader [MMSYSTEM.306]
2712 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2713 SEGPTR lpsegMidiInHdr, /* [???] */
2714 UINT16 uSize) /* [in] */
2718 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2720 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2721 return MMSYSERR_INVALHANDLE;
2723 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2726 /**************************************************************************
2727 * midiInUnprepareHeader [WINMM.@]
2729 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2730 MIDIHDR* lpMidiInHdr, UINT uSize)
2734 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2736 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2737 return MMSYSERR_NOERROR;
2740 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2741 return MMSYSERR_INVALHANDLE;
2743 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2746 /**************************************************************************
2747 * midiInUnprepareHeader [MMSYSTEM.307]
2749 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2750 SEGPTR lpsegMidiInHdr, /* [???] */
2751 UINT16 uSize) /* [in] */
2754 LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr);
2756 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2758 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2759 return MMSYSERR_NOERROR;
2762 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2763 return MMSYSERR_INVALHANDLE;
2765 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2768 /**************************************************************************
2769 * midiInAddBuffer [WINMM.@]
2771 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2772 MIDIHDR* lpMidiInHdr, UINT uSize)
2776 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2778 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2779 return MMSYSERR_INVALHANDLE;
2781 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
2784 /**************************************************************************
2785 * midiInAddBuffer [MMSYSTEM.308]
2787 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */
2788 MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */
2789 UINT16 uSize) /* [in] */
2793 TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2795 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2796 return MMSYSERR_INVALHANDLE;
2798 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2801 /**************************************************************************
2802 * midiInStart [WINMM.@]
2804 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2808 TRACE("(%04X)\n", hMidiIn);
2810 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2811 return MMSYSERR_INVALHANDLE;
2813 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
2816 /**************************************************************************
2817 * midiInStart [MMSYSTEM.309]
2819 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2821 return midiInStart(hMidiIn);
2824 /**************************************************************************
2825 * midiInStop [WINMM.@]
2827 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2831 TRACE("(%04X)\n", hMidiIn);
2833 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2834 return MMSYSERR_INVALHANDLE;
2836 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
2839 /**************************************************************************
2840 * midiInStop [MMSYSTEM.310]
2842 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2844 return midiInStop(hMidiIn);
2847 /**************************************************************************
2848 * midiInReset [WINMM.@]
2850 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2854 TRACE("(%04X)\n", hMidiIn);
2856 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2857 return MMSYSERR_INVALHANDLE;
2859 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
2862 /**************************************************************************
2863 * midiInReset [MMSYSTEM.311]
2865 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2867 return midiInReset(hMidiIn);
2870 /**************************************************************************
2871 * midiInGetID [WINMM.@]
2873 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2877 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2879 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2881 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
2882 return MMSYSERR_INVALHANDLE;
2884 *lpuDeviceID = wmld->uDeviceID;
2886 return MMSYSERR_NOERROR;
2889 /**************************************************************************
2890 * midiInGetID [MMSYSTEM.312]
2892 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
2896 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2898 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2900 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
2901 return MMSYSERR_INVALHANDLE;
2903 *lpuDeviceID = wmld->uDeviceID;
2905 return MMSYSERR_NOERROR;
2908 /**************************************************************************
2909 * midiInMessage [WINMM.@]
2911 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
2912 DWORD dwParam1, DWORD dwParam2)
2916 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
2918 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2919 return MMSYSERR_INVALHANDLE;
2924 FIXME("can't handle OPEN or CLOSE message!\n");
2925 return MMSYSERR_NOTSUPPORTED;
2927 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2930 /**************************************************************************
2931 * midiInMessage [MMSYSTEM.313]
2933 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
2934 DWORD dwParam1, DWORD dwParam2)
2938 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
2943 FIXME("can't handle OPEN or CLOSE message!\n");
2944 return MMSYSERR_NOTSUPPORTED;
2946 case MIDM_GETDEVCAPS:
2947 return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2);
2949 return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2);
2950 case MIDM_UNPREPARE:
2951 return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2);
2952 case MIDM_ADDBUFFER:
2953 return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2);
2956 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2957 return MMSYSERR_INVALHANDLE;
2959 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
2962 typedef struct WINE_MIDIStream {
2973 LPMIDIHDR lpMidiHdr;
2976 #define WINE_MSM_HEADER (WM_USER+0)
2977 #define WINE_MSM_STOP (WM_USER+1)
2979 /**************************************************************************
2980 * MMSYSTEM_GetMidiStream [internal]
2982 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
2984 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
2993 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
2995 return *lpMidiStrm != NULL;
2998 /**************************************************************************
2999 * MMSYSTEM_MidiStream_Convert [internal]
3001 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
3005 if (lpMidiStrm->dwTimeDiv == 0) {
3006 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
3007 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
3008 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
3009 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
3010 ret = (pulse * 1000) / (nf * nsf);
3012 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
3013 (double)lpMidiStrm->dwTimeDiv);
3019 /**************************************************************************
3020 * MMSYSTEM_MidiStream_MessageHandler [internal]
3022 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
3024 LPMIDIHDR lpMidiHdr;
3028 switch (msg->message) {
3030 SetEvent(lpMidiStrm->hEvent);
3034 /* this is not quite what MS doc says... */
3035 midiOutReset(lpMidiStrm->hDevice);
3036 /* empty list of already submitted buffers */
3037 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
3038 lpMidiHdr->dwFlags |= MHDR_DONE;
3039 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3041 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3042 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3044 lpMidiStrm->lpMidiHdr = 0;
3045 SetEvent(lpMidiStrm->hEvent);
3047 case WINE_MSM_HEADER:
3048 /* sets initial tick count for first MIDIHDR */
3049 if (!lpMidiStrm->dwStartTicks)
3050 lpMidiStrm->dwStartTicks = GetTickCount();
3052 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
3053 * by native mcimidi, it doesn't look like a correct one".
3054 * this trick allows to throw it away... but I don't like it.
3055 * It looks like part of the file I'm trying to play and definitively looks
3056 * like raw midi content
3057 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
3058 * synchronization issue where native mcimidi is still processing raw MIDI
3059 * content before generating MIDIEVENTs ?
3061 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
3062 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
3063 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
3064 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
3065 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
3066 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
3067 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
3068 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
3069 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
3070 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3071 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3072 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3073 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3074 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3075 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3076 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3077 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3079 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3080 lpData = lpMidiHdr->lpData;
3081 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
3082 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
3083 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
3084 lpMidiHdr->dwFlags, msg->wParam);
3086 /* dumps content of lpMidiHdr->lpData
3087 * FIXME: there should be a debug routine somewhere that already does this
3088 * I hate spreading this type of shit all around the code
3090 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
3094 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
3095 printf("%02x ", lpData[dwToGo + i]);
3098 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
3099 ch = lpData[dwToGo + i];
3100 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
3105 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3106 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3107 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3108 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
3109 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
3110 ((LPMIDIEVENT)lpData)->dwStreamID);
3111 lpMidiHdr->dwFlags |= MHDR_DONE;
3112 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3114 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3115 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3119 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
3121 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3122 lpMidiHdr->lpNext = 0;
3123 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
3124 lpMidiHdr->dwFlags &= MHDR_DONE;
3125 lpMidiHdr->dwOffset = 0;
3129 FIXME("Unknown message %d\n", msg->message);
3135 /**************************************************************************
3136 * MMSYSTEM_MidiStream_Player [internal]
3138 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
3140 WINE_MIDIStream* lpMidiStrm = pmt;
3145 LPMIDIHDR lpMidiHdr;
3149 TRACE("(%p)!\n", lpMidiStrm);
3152 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
3155 /* force thread's queue creation */
3156 /* Used to be InitThreadInput16(0, 5); */
3157 /* but following works also with hack in midiStreamOpen */
3158 PeekMessageA(&msg, 0, 0, 0, 0);
3160 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
3161 SetEvent(lpMidiStrm->hEvent);
3162 TRACE("Ready to go 1\n");
3163 /* thread is started in paused mode */
3164 SuspendThread(lpMidiStrm->hThread);
3165 TRACE("Ready to go 2\n");
3167 lpMidiStrm->dwStartTicks = 0;
3168 lpMidiStrm->dwPulses = 0;
3170 lpMidiStrm->lpMidiHdr = 0;
3173 lpMidiHdr = lpMidiStrm->lpMidiHdr;
3175 /* for first message, block until one arrives, then process all that are available */
3176 GetMessageA(&msg, 0, 0, 0);
3178 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3180 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
3186 lpData = lpMidiHdr->lpData;
3188 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3190 /* do we have to wait ? */
3191 if (me->dwDeltaTime) {
3192 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
3193 lpMidiStrm->dwPulses += me->dwDeltaTime;
3195 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3197 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
3198 while ((dwCurrTC = GetTickCount()) < dwToGo) {
3199 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
3200 /* got a message, handle it */
3201 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
3202 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3207 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
3212 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3214 FIXME("NIY: MEVT_COMMENT\n");
3215 /* do nothing, skip bytes */
3218 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3223 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3226 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3231 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3234 if (me->dwEvent & MEVT_F_CALLBACK) {
3235 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3236 MM_MOM_POSITIONCB, lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
3238 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
3239 if (me->dwEvent & MEVT_F_LONG)
3240 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
3241 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
3242 /* done with this header */
3243 lpMidiHdr->dwFlags |= MHDR_DONE;
3244 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3246 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
3247 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3248 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3253 TRACE("End of thread\n");
3255 return 0; /* for removing the warning, never executed */
3258 /**************************************************************************
3259 * MMSYSTEM_MidiStream_PostMessage [internal]
3261 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
3263 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
3266 ReleaseThunkLock(&count);
3267 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3268 RestoreThunkLock(count);
3270 WARN("bad PostThreadMessageA\n");
3276 /**************************************************************************
3277 * midiStreamClose [WINMM.@]
3279 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3281 WINE_MIDIStream* lpMidiStrm;
3283 TRACE("(%08x)!\n", hMidiStrm);
3285 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3286 return MMSYSERR_INVALHANDLE;
3288 midiStreamStop(hMidiStrm);
3289 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
3290 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
3291 CloseHandle(lpMidiStrm->hEvent);
3293 return midiOutClose(hMidiStrm);
3296 /**************************************************************************
3297 * MMSYSTEM_MidiStream_Open [internal]
3299 static MMRESULT WINAPI MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3300 DWORD cMidi, DWORD dwCallback,
3301 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
3303 WINE_MIDIStream* lpMidiStrm;
3305 MIDIOPENSTRMID mosm;
3309 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3310 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3312 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3313 return MMSYSERR_INVALPARAM;
3315 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3317 return MMSYSERR_NOMEM;
3319 lpMidiStrm->dwTempo = 500000;
3320 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3321 lpMidiStrm->dwPositionMS = 0;
3323 mosm.dwStreamID = (DWORD)lpMidiStrm;
3324 /* FIXME: the correct value is not allocated yet for MAPPER */
3325 mosm.wDeviceID = *lpuDeviceID;
3326 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
3327 lpMidiStrm->hDevice = hMidiOut;
3329 *lphMidiStrm = hMidiOut;
3331 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
3332 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
3333 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
3335 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
3336 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
3337 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3339 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
3340 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3342 if (!lpMidiStrm->hThread) {
3343 midiStreamClose((HMIDISTRM)hMidiOut);
3344 return MMSYSERR_NOMEM;
3347 /* wait for thread to have started, and for its queue to be created */
3351 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3352 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3353 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3355 ReleaseThunkLock(&count);
3356 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3357 RestoreThunkLock(count);
3360 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
3361 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
3365 /**************************************************************************
3366 * midiStreamOpen [WINMM.@]
3368 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3369 DWORD cMidi, DWORD dwCallback,
3370 DWORD dwInstance, DWORD fdwOpen)
3372 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
3373 dwInstance, fdwOpen, TRUE);
3376 /**************************************************************************
3377 * midiStreamOut [WINMM.@]
3379 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
3382 WINE_MIDIStream* lpMidiStrm;
3383 DWORD ret = MMSYSERR_NOERROR;
3385 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3387 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3388 ret = MMSYSERR_INVALHANDLE;
3390 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
3391 WINE_MSM_HEADER, cbMidiHdr,
3392 (DWORD)lpMidiHdr)) {
3393 WARN("bad PostThreadMessageA\n");
3394 ret = MMSYSERR_ERROR;
3400 /**************************************************************************
3401 * midiStreamPause [WINMM.@]
3403 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3405 WINE_MIDIStream* lpMidiStrm;
3406 DWORD ret = MMSYSERR_NOERROR;
3408 TRACE("(%08x)!\n", hMidiStrm);
3410 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3411 ret = MMSYSERR_INVALHANDLE;
3413 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3414 WARN("bad Suspend (%ld)\n", GetLastError());
3415 ret = MMSYSERR_ERROR;
3421 /**************************************************************************
3422 * midiStreamPosition [WINMM.@]
3424 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3426 WINE_MIDIStream* lpMidiStrm;
3427 DWORD ret = MMSYSERR_NOERROR;
3429 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3431 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3432 ret = MMSYSERR_INVALHANDLE;
3433 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3434 ret = MMSYSERR_INVALPARAM;
3436 switch (lpMMT->wType) {
3438 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3439 TRACE("=> %ld ms\n", lpMMT->u.ms);
3442 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3443 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
3446 WARN("Unsupported time type %d\n", lpMMT->wType);
3447 lpMMT->wType = TIME_MS;
3448 ret = MMSYSERR_INVALPARAM;
3455 /**************************************************************************
3456 * midiStreamProperty [WINMM.@]
3458 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3460 WINE_MIDIStream* lpMidiStrm;
3461 MMRESULT ret = MMSYSERR_NOERROR;
3463 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3465 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3466 ret = MMSYSERR_INVALHANDLE;
3467 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3468 ret = MMSYSERR_INVALPARAM;
3469 } else if (dwProperty & MIDIPROP_TEMPO) {
3470 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3472 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3473 ret = MMSYSERR_INVALPARAM;
3474 } else if (dwProperty & MIDIPROP_SET) {
3475 lpMidiStrm->dwTempo = mpt->dwTempo;
3476 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
3477 } else if (dwProperty & MIDIPROP_GET) {
3478 mpt->dwTempo = lpMidiStrm->dwTempo;
3479 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
3481 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3482 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3484 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3485 ret = MMSYSERR_INVALPARAM;
3486 } else if (dwProperty & MIDIPROP_SET) {
3487 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3488 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
3489 } else if (dwProperty & MIDIPROP_GET) {
3490 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3491 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
3494 ret = MMSYSERR_INVALPARAM;
3500 /**************************************************************************
3501 * midiStreamRestart [WINMM.@]
3503 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3505 WINE_MIDIStream* lpMidiStrm;
3506 MMRESULT ret = MMSYSERR_NOERROR;
3508 TRACE("(%08x)!\n", hMidiStrm);
3510 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3511 ret = MMSYSERR_INVALHANDLE;
3515 /* since we increase the thread suspend count on each midiStreamPause
3516 * there may be a need for several midiStreamResume
3519 ret = ResumeThread(lpMidiStrm->hThread);
3520 } while (ret != 0xFFFFFFFF && ret != 0);
3521 if (ret == 0xFFFFFFFF) {
3522 WARN("bad Resume (%ld)\n", GetLastError());
3523 ret = MMSYSERR_ERROR;
3525 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
3531 /**************************************************************************
3532 * midiStreamStop [WINMM.@]
3534 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3536 WINE_MIDIStream* lpMidiStrm;
3537 MMRESULT ret = MMSYSERR_NOERROR;
3539 TRACE("(%08x)!\n", hMidiStrm);
3541 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3542 ret = MMSYSERR_INVALHANDLE;
3544 /* in case stream has been paused... FIXME is the current state correct ? */
3545 midiStreamRestart(hMidiStrm);
3546 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
3551 /**************************************************************************
3552 * midiStreamClose [MMSYSTEM.252]
3554 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3556 return midiStreamClose(hMidiStrm);
3559 /**************************************************************************
3560 * midiStreamOpen [MMSYSTEM.251]
3562 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3563 DWORD cMidi, DWORD dwCallback,
3564 DWORD dwInstance, DWORD fdwOpen)
3566 HMIDISTRM hMidiStrm32;
3570 if (!phMidiStrm || !devid)
3571 return MMSYSERR_INVALPARAM;
3573 ret = MMSYSTEM_MidiStream_Open(&hMidiStrm32, &devid32, cMidi, dwCallback,
3574 dwInstance, fdwOpen, FALSE);
3575 *phMidiStrm = hMidiStrm32;
3580 /**************************************************************************
3581 * midiStreamOut [MMSYSTEM.254]
3583 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3585 return midiStreamOut(hMidiStrm, (LPMIDIHDR)lpMidiHdr, cbMidiHdr);
3588 /**************************************************************************
3589 * midiStreamPause [MMSYSTEM.255]
3591 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3593 return midiStreamPause(hMidiStrm);
3596 /**************************************************************************
3597 * midiStreamPosition [MMSYSTEM.253]
3599 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3605 return MMSYSERR_INVALPARAM;
3606 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3607 ret = midiStreamPosition(hMidiStrm, &mmt32, sizeof(MMTIME));
3608 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3612 /**************************************************************************
3613 * midiStreamProperty [MMSYSTEM.250]
3615 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3617 return midiStreamProperty(hMidiStrm, lpPropData, dwProperty);
3620 /**************************************************************************
3621 * midiStreamRestart [MMSYSTEM.256]
3623 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3625 return midiStreamRestart(hMidiStrm);
3628 /**************************************************************************
3629 * midiStreamStop [MMSYSTEM.257]
3631 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3633 return midiStreamStop(hMidiStrm);
3636 static UINT WINAPI MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
3637 const LPWAVEFORMATEX lpFormat,
3638 DWORD dwCallback, DWORD dwInstance,
3639 DWORD dwFlags, BOOL bFrom32)
3643 DWORD dwRet = MMSYSERR_NOERROR;
3646 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
3647 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
3648 dwInstance, dwFlags, bFrom32?32:16);
3650 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
3652 if (lpFormat == NULL) return WAVERR_BADFORMAT;
3654 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
3655 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
3656 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
3658 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
3659 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
3660 return MMSYSERR_NOMEM;
3663 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
3664 wod.dwCallback = dwCallback;
3665 wod.dwInstance = dwInstance;
3666 wod.uMappedDeviceID = 0;
3669 /* when called from 16 bit code, mapper will be 0x0000FFFF instead of 0xFFFFFFFF */
3670 /* this should fix it */
3671 wmld->uDeviceID = (uDeviceID == (UINT16)-1 && !bFrom32) ? (UINT)-1 : uDeviceID;
3673 dwRet = MMDRV_Open(wmld, (uType==MMDRV_WAVEOUT)?WODM_OPEN:WIDM_OPEN, (DWORD)&wod, dwFlags);
3675 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
3676 MMDRV_Free(handle, wmld);
3680 if (lphndl != NULL) *lphndl = handle;
3681 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
3686 /**************************************************************************
3687 * waveOutGetNumDevs [WINMM.@]
3689 UINT WINAPI waveOutGetNumDevs(void)
3691 return MMDRV_GetNum(MMDRV_WAVEOUT);
3694 /**************************************************************************
3695 * waveOutGetNumDevs [MMSYSTEM.401]
3697 UINT16 WINAPI waveOutGetNumDevs16(void)
3699 return MMDRV_GetNum(MMDRV_WAVEOUT);
3702 /**************************************************************************
3703 * waveOutGetDevCaps [MMSYSTEM.402]
3705 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID,
3706 LPWAVEOUTCAPS16 lpCaps, UINT16 uSize)
3711 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3712 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3714 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3716 if (ret == MMSYSERR_NOERROR) {
3717 lpCaps->wMid = wocA.wMid;
3718 lpCaps->wPid = wocA.wPid;
3719 lpCaps->vDriverVersion = wocA.vDriverVersion;
3720 strcpy(lpCaps->szPname, wocA.szPname);
3721 lpCaps->dwFormats = wocA.dwFormats;
3722 lpCaps->wChannels = wocA.wChannels;
3723 lpCaps->dwSupport = wocA.dwSupport;
3728 /**************************************************************************
3729 * waveOutGetDevCapsA [WINMM.@]
3731 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3736 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3738 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3740 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
3741 return MMSYSERR_INVALHANDLE;
3743 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
3747 /**************************************************************************
3748 * waveOutGetDevCapsW [WINMM.@]
3750 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3756 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3758 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3760 if (ret == MMSYSERR_NOERROR) {
3761 lpCaps->wMid = wocA.wMid;
3762 lpCaps->wPid = wocA.wPid;
3763 lpCaps->vDriverVersion = wocA.vDriverVersion;
3764 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
3765 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
3766 lpCaps->dwFormats = wocA.dwFormats;
3767 lpCaps->wChannels = wocA.wChannels;
3768 lpCaps->dwSupport = wocA.dwSupport;
3773 /**************************************************************************
3774 * WAVE_GetErrorText [internal]
3776 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3778 UINT16 ret = MMSYSERR_BADERRNUM;
3780 if (lpText == NULL) {
3781 ret = MMSYSERR_INVALPARAM;
3782 } else if (uSize == 0) {
3783 ret = MMSYSERR_NOERROR;
3785 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
3786 * a warning for the test was always true */
3787 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
3788 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
3790 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
3791 uError, lpText, uSize) > 0) {
3792 ret = MMSYSERR_NOERROR;
3798 /**************************************************************************
3799 * waveOutGetErrorText [MMSYSTEM.403]
3801 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3803 return WAVE_GetErrorText(uError, lpText, uSize);
3806 /**************************************************************************
3807 * waveOutGetErrorTextA [WINMM.@]
3809 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3811 return WAVE_GetErrorText(uError, lpText, uSize);
3814 /**************************************************************************
3815 * waveOutGetErrorTextW [WINMM.@]
3817 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3819 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3820 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
3822 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
3823 HeapFree(GetProcessHeap(), 0, xstr);
3827 /**************************************************************************
3828 * waveOutOpen [WINMM.@]
3829 * All the args/structs have the same layout as the win16 equivalents
3831 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3832 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3833 DWORD dwInstance, DWORD dwFlags)
3835 return MMSYSTEM_waveOpen(lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
3836 dwCallback, dwInstance, dwFlags, TRUE);
3839 /**************************************************************************
3840 * waveOutOpen [MMSYSTEM.404]
3842 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3843 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3844 DWORD dwInstance, DWORD dwFlags)
3849 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
3850 * call the 32 bit version
3852 ret = MMSYSTEM_waveOpen(&hWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
3853 dwCallback, dwInstance, dwFlags, FALSE);
3855 if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
3859 /**************************************************************************
3860 * waveOutClose [WINMM.@]
3862 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3867 TRACE("(%04X)\n", hWaveOut);
3869 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3870 return MMSYSERR_INVALHANDLE;
3872 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
3873 MMDRV_Free(hWaveOut, wmld);
3878 /**************************************************************************
3879 * waveOutClose [MMSYSTEM.405]
3881 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
3886 ReleaseThunkLock(&level);
3887 ret = waveOutClose(hWaveOut);
3888 RestoreThunkLock(level);
3892 /**************************************************************************
3893 * waveOutPrepareHeader [WINMM.@]
3895 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
3896 WAVEHDR* lpWaveOutHdr, UINT uSize)
3900 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3902 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
3904 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3905 return MMSYSERR_INVALHANDLE;
3907 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
3910 /**************************************************************************
3911 * waveOutPrepareHeader [MMSYSTEM.406]
3913 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
3914 SEGPTR lpsegWaveOutHdr, /* [???] */
3915 UINT16 uSize) /* [in] */
3918 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
3920 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
3922 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
3924 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3925 return MMSYSERR_INVALHANDLE;
3927 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
3930 /**************************************************************************
3931 * waveOutUnprepareHeader [WINMM.@]
3933 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
3934 LPWAVEHDR lpWaveOutHdr, UINT uSize)
3938 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3940 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
3941 return MMSYSERR_NOERROR;
3944 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3945 return MMSYSERR_INVALHANDLE;
3947 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
3950 /**************************************************************************
3951 * waveOutUnprepareHeader [MMSYSTEM.407]
3953 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
3954 SEGPTR lpsegWaveOutHdr, /* [???] */
3955 UINT16 uSize) /* [in] */
3958 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
3960 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
3962 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
3963 return MMSYSERR_NOERROR;
3966 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3967 return MMSYSERR_INVALHANDLE;
3969 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
3972 /**************************************************************************
3973 * waveOutWrite [WINMM.@]
3975 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
3980 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3982 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3983 return MMSYSERR_INVALHANDLE;
3985 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
3988 /**************************************************************************
3989 * waveOutWrite [MMSYSTEM.408]
3991 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */
3992 LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */
3993 UINT16 uSize) /* [in] */
3997 TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
3999 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4000 return MMSYSERR_INVALHANDLE;
4002 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4005 /**************************************************************************
4006 * waveOutBreakLoop [WINMM.@]
4008 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
4012 TRACE("(%04X);\n", hWaveOut);
4014 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4015 return MMSYSERR_INVALHANDLE;
4016 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
4019 /**************************************************************************
4020 * waveOutBreakLoop [MMSYSTEM.419]
4022 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16)
4027 ReleaseThunkLock(&level);
4028 ret = waveOutBreakLoop(hWaveOut16);
4029 RestoreThunkLock(level);
4033 /**************************************************************************
4034 * waveOutPause [WINMM.@]
4036 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
4040 TRACE("(%04X);\n", hWaveOut);
4042 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4043 return MMSYSERR_INVALHANDLE;
4044 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
4047 /**************************************************************************
4048 * waveOutPause [MMSYSTEM.409]
4050 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16)
4055 ReleaseThunkLock(&level);
4056 ret = waveOutPause(hWaveOut16);
4057 RestoreThunkLock(level);
4061 /**************************************************************************
4062 * waveOutReset [WINMM.@]
4064 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
4068 TRACE("(%04X);\n", hWaveOut);
4070 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4071 return MMSYSERR_INVALHANDLE;
4072 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
4075 /**************************************************************************
4076 * waveOutReset [MMSYSTEM.411]
4078 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16)
4083 ReleaseThunkLock(&level);
4084 ret = waveOutReset(hWaveOut16);
4085 RestoreThunkLock(level);
4089 /**************************************************************************
4090 * waveOutRestart [WINMM.@]
4092 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
4096 TRACE("(%04X);\n", hWaveOut);
4098 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4099 return MMSYSERR_INVALHANDLE;
4100 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
4103 /**************************************************************************
4104 * waveOutRestart [MMSYSTEM.410]
4106 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16)
4111 ReleaseThunkLock(&level);
4112 ret = waveOutRestart(hWaveOut16);
4113 RestoreThunkLock(level);
4117 /**************************************************************************
4118 * waveOutGetPosition [WINMM.@]
4120 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
4125 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
4127 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4128 return MMSYSERR_INVALHANDLE;
4130 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4133 /**************************************************************************
4134 * waveOutGetPosition [MMSYSTEM.412]
4136 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
4142 mmt.wType = lpTime->wType;
4143 ret = waveOutGetPosition(hWaveOut, &mmt, sizeof(mmt));
4144 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4148 /**************************************************************************
4149 * waveOutGetPitch [WINMM.@]
4151 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
4155 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4157 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4158 return MMSYSERR_INVALHANDLE;
4159 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
4162 /**************************************************************************
4163 * waveOutGetPitch [MMSYSTEM.413]
4165 UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4167 return waveOutGetPitch(hWaveOut16, lpdw);
4170 /**************************************************************************
4171 * waveOutSetPitch [WINMM.@]
4173 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
4177 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4179 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4180 return MMSYSERR_INVALHANDLE;
4181 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
4184 /**************************************************************************
4185 * waveOutSetPitch [MMSYSTEM.414]
4187 UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw)
4189 return waveOutSetPitch(hWaveOut16, dw);
4192 /**************************************************************************
4193 * waveOutGetPlaybackRate [WINMM.@]
4195 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
4199 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4201 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4202 return MMSYSERR_INVALHANDLE;
4203 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
4206 /**************************************************************************
4207 * waveOutGetPlaybackRate [MMSYSTEM.417]
4209 UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4211 return waveOutGetPlaybackRate(hWaveOut16, lpdw);
4214 /**************************************************************************
4215 * waveOutSetPlaybackRate [WINMM.@]
4217 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
4221 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4223 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4224 return MMSYSERR_INVALHANDLE;
4225 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
4228 /**************************************************************************
4229 * waveOutSetPlaybackRate [MMSYSTEM.418]
4231 UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw)
4233 return waveOutSetPlaybackRate(hWaveOut16, dw);
4236 /**************************************************************************
4237 * waveOutGetVolume [WINMM.@]
4239 UINT WINAPI waveOutGetVolume(UINT devid, LPDWORD lpdw)
4243 TRACE("(%04X, %08lx);\n", devid, (DWORD)lpdw);
4245 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4246 return MMSYSERR_INVALHANDLE;
4248 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
4251 /**************************************************************************
4252 * waveOutGetVolume [MMSYSTEM.415]
4254 UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw)
4256 return waveOutGetVolume(devid, lpdw);
4259 /**************************************************************************
4260 * waveOutSetVolume [WINMM.@]
4262 UINT WINAPI waveOutSetVolume(UINT devid, DWORD dw)
4266 TRACE("(%04X, %08lx);\n", devid, dw);
4268 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4269 return MMSYSERR_INVALHANDLE;
4271 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
4274 /**************************************************************************
4275 * waveOutSetVolume [MMSYSTEM.416]
4277 UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw)
4279 return waveOutSetVolume(devid, dw);
4282 /**************************************************************************
4283 * waveOutGetID [WINMM.@]
4285 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
4289 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4291 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4293 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4294 return MMSYSERR_INVALHANDLE;
4296 *lpuDeviceID = wmld->uDeviceID;
4300 /**************************************************************************
4301 * waveOutGetID [MMSYSTEM.420]
4303 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
4307 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4309 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4311 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4312 return MMSYSERR_INVALHANDLE;
4314 *lpuDeviceID = wmld->uDeviceID;
4318 /**************************************************************************
4319 * waveOutMessage [WINMM.@]
4321 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
4322 DWORD dwParam1, DWORD dwParam2)
4326 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4328 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4329 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4330 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4332 return MMSYSERR_INVALHANDLE;
4336 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4337 return MMSYSERR_INVALPARAM;
4339 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4342 /**************************************************************************
4343 * waveOutMessage [MMSYSTEM.421]
4345 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4346 DWORD dwParam1, DWORD dwParam2)
4350 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4352 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4353 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4354 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4356 return MMSYSERR_INVALHANDLE;
4360 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4361 return MMSYSERR_INVALPARAM;
4363 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
4366 /**************************************************************************
4367 * waveInGetNumDevs [WINMM.@]
4369 UINT WINAPI waveInGetNumDevs(void)
4371 return MMDRV_GetNum(MMDRV_WAVEIN);
4374 /**************************************************************************
4375 * waveInGetNumDevs [MMSYSTEM.501]
4377 UINT16 WINAPI waveInGetNumDevs16(void)
4379 return MMDRV_GetNum(MMDRV_WAVEIN);
4382 /**************************************************************************
4383 * waveInGetDevCapsW [WINMM.@]
4385 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4388 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
4390 if (ret == MMSYSERR_NOERROR) {
4391 lpCaps->wMid = wicA.wMid;
4392 lpCaps->wPid = wicA.wPid;
4393 lpCaps->vDriverVersion = wicA.vDriverVersion;
4394 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
4395 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
4396 lpCaps->dwFormats = wicA.dwFormats;
4397 lpCaps->wChannels = wicA.wChannels;
4403 /**************************************************************************
4404 * waveInGetDevCapsA [WINMM.@]
4406 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4410 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
4412 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
4413 return MMSYSERR_INVALHANDLE;
4415 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
4418 /**************************************************************************
4419 * waveInGetDevCaps [MMSYSTEM.502]
4421 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps,
4425 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
4427 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
4429 if (ret == MMSYSERR_NOERROR) {
4430 lpCaps->wMid = wicA.wMid;
4431 lpCaps->wPid = wicA.wPid;
4432 lpCaps->vDriverVersion = wicA.vDriverVersion;
4433 strcpy(lpCaps->szPname, wicA.szPname);
4434 lpCaps->dwFormats = wicA.dwFormats;
4435 lpCaps->wChannels = wicA.wChannels;
4440 /**************************************************************************
4441 * waveInGetErrorTextA [WINMM.@]
4443 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4445 return WAVE_GetErrorText(uError, lpText, uSize);
4448 /**************************************************************************
4449 * waveInGetErrorTextW [WINMM.@]
4451 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4453 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4454 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
4456 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
4457 HeapFree(GetProcessHeap(), 0, txt);
4461 /**************************************************************************
4462 * waveInGetErrorText [MMSYSTEM.503]
4464 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4466 return WAVE_GetErrorText(uError, lpText, uSize);
4469 /**************************************************************************
4470 * waveInOpen [WINMM.@]
4472 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4473 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4474 DWORD dwInstance, DWORD dwFlags)
4476 return MMSYSTEM_waveOpen(lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
4477 dwCallback, dwInstance, dwFlags, TRUE);
4480 /**************************************************************************
4481 * waveInOpen [MMSYSTEM.504]
4483 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4484 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4485 DWORD dwInstance, DWORD dwFlags)
4490 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
4491 * call the 32 bit version
4493 ret = MMSYSTEM_waveOpen(&hWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
4494 dwCallback, dwInstance, dwFlags, FALSE);
4496 if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
4500 /**************************************************************************
4501 * waveInClose [WINMM.@]
4503 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4508 TRACE("(%04X)\n", hWaveIn);
4510 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4511 return MMSYSERR_INVALHANDLE;
4513 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
4514 MMDRV_Free(hWaveIn, wmld);
4518 /**************************************************************************
4519 * waveInClose [MMSYSTEM.505]
4521 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4526 ReleaseThunkLock(&level);
4527 ret = waveInClose(hWaveIn);
4528 RestoreThunkLock(level);
4532 /**************************************************************************
4533 * waveInPrepareHeader [WINMM.@]
4535 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4540 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4542 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4543 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4544 return MMSYSERR_INVALHANDLE;
4546 lpWaveInHdr->dwBytesRecorded = 0;
4548 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4551 /**************************************************************************
4552 * waveInPrepareHeader [MMSYSTEM.506]
4554 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4555 SEGPTR lpsegWaveInHdr, /* [???] */
4556 UINT16 uSize) /* [in] */
4559 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4562 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4564 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4565 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4566 return MMSYSERR_INVALHANDLE;
4568 lpWaveInHdr->dwBytesRecorded = 0;
4570 ret = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4574 /**************************************************************************
4575 * waveInUnprepareHeader [WINMM.@]
4577 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4582 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4584 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4585 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4586 return MMSYSERR_NOERROR;
4589 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4590 return MMSYSERR_INVALHANDLE;
4592 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4595 /**************************************************************************
4596 * waveInUnprepareHeader [MMSYSTEM.507]
4598 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4599 SEGPTR lpsegWaveInHdr, /* [???] */
4600 UINT16 uSize) /* [in] */
4603 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4605 TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4607 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4609 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4610 return MMSYSERR_NOERROR;
4613 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4614 return MMSYSERR_INVALHANDLE;
4616 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4619 /**************************************************************************
4620 * waveInAddBuffer [WINMM.@]
4622 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4623 WAVEHDR* lpWaveInHdr, UINT uSize)
4627 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4629 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4630 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4631 return MMSYSERR_INVALHANDLE;
4633 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
4636 /**************************************************************************
4637 * waveInAddBuffer [MMSYSTEM.508]
4639 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */
4640 WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */
4641 UINT16 uSize) /* [in] */
4645 TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4647 if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4648 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4649 return MMSYSERR_INVALHANDLE;
4651 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4654 /**************************************************************************
4655 * waveInReset [WINMM.@]
4657 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4661 TRACE("(%04X);\n", hWaveIn);
4663 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4664 return MMSYSERR_INVALHANDLE;
4666 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
4669 /**************************************************************************
4670 * waveInReset [MMSYSTEM.511]
4672 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16)
4677 ReleaseThunkLock(&level);
4678 ret = waveInReset(hWaveIn16);
4679 RestoreThunkLock(level);
4683 /**************************************************************************
4684 * waveInStart [WINMM.@]
4686 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4690 TRACE("(%04X);\n", hWaveIn);
4692 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4693 return MMSYSERR_INVALHANDLE;
4695 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
4698 /**************************************************************************
4699 * waveInStart [MMSYSTEM.509]
4701 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16)
4706 ReleaseThunkLock(&level);
4707 ret = waveInStart(hWaveIn16);
4708 RestoreThunkLock(level);
4712 /**************************************************************************
4713 * waveInStop [WINMM.@]
4715 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4719 TRACE("(%04X);\n", hWaveIn);
4721 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4722 return MMSYSERR_INVALHANDLE;
4724 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
4727 /**************************************************************************
4728 * waveInStop [MMSYSTEM.510]
4730 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16)
4735 ReleaseThunkLock(&level);
4736 ret = waveInStop(hWaveIn16);
4737 RestoreThunkLock(level);
4741 /**************************************************************************
4742 * waveInGetPosition [WINMM.@]
4744 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4749 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4751 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4752 return MMSYSERR_INVALHANDLE;
4754 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4757 /**************************************************************************
4758 * waveInGetPosition [MMSYSTEM.512]
4760 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4766 mmt.wType = lpTime->wType;
4767 ret = waveInGetPosition(hWaveIn, &mmt, sizeof(mmt));
4768 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4772 /**************************************************************************
4773 * waveInGetID [WINMM.@]
4775 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4779 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4781 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4783 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4784 return MMSYSERR_INVALHANDLE;
4786 *lpuDeviceID = wmld->uDeviceID;
4787 return MMSYSERR_NOERROR;
4790 /**************************************************************************
4791 * waveInGetID [MMSYSTEM.513]
4793 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4797 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4799 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4801 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4802 return MMSYSERR_INVALHANDLE;
4804 *lpuDeviceID = wmld->uDeviceID;
4805 return MMSYSERR_NOERROR;
4808 /**************************************************************************
4809 * waveInMessage [WINMM.@]
4811 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4812 DWORD dwParam1, DWORD dwParam2)
4816 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4819 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4820 return MMSYSERR_INVALPARAM;
4822 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4823 return MMSYSERR_INVALHANDLE;
4825 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4828 /**************************************************************************
4829 * waveInMessage [MMSYSTEM.514]
4831 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4832 DWORD dwParam1, DWORD dwParam2)
4836 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4839 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4840 return MMSYSERR_INVALPARAM;
4842 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4843 return MMSYSERR_INVALHANDLE;
4845 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4848 /*#define USE_MM_TSK_WINE*/
4850 /**************************************************************************
4851 * mmTaskCreate [MMSYSTEM.900]
4853 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4854 * called upon creation with dwPmt as parameter.
4856 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4864 TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
4865 /* This to work requires NE modules to be started with a binary command line
4866 * which is not currently the case. A patch exists but has never been committed.
4867 * A workaround would be to integrate code for mmtask.tsk into Wine, but
4868 * this requires tremendous work (starting with patching tools/build to
4869 * create NE executables (and not only DLLs) for builtins modules.
4872 FIXME("This is currently broken. It will fail\n");
4874 cmdline = SEGPTR_ALLOC(0x0d);
4876 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
4877 *(LPDWORD)(cmdline + 5) = dwPmt;
4878 *(LPDWORD)(cmdline + 9) = 0;
4880 pShowCmd = SEGPTR_ALLOC(sizeof(DWORD));
4881 *pShowCmd = 0x40002;
4883 lp = (LOADPARAMS16*)HeapAlloc(GetProcessHeap(), 0, sizeof(LOADPARAMS16));
4884 lp->hEnvironment = 0;
4885 lp->cmdLine = SEGPTR_GET(cmdline);
4886 lp->showCmd = SEGPTR_GET(pShowCmd);
4889 #ifndef USE_MM_TSK_WINE
4890 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", lp);
4892 handle = LoadModule16("mmtask.tsk", lp);
4895 ret = (handle) ? 1 : 2;
4901 *lphMmTask = handle;
4903 HeapFree(GetProcessHeap(), 0, lp);
4904 SEGPTR_FREE(pShowCmd);
4905 SEGPTR_FREE(cmdline);
4907 TRACE("=> 0x%04x/%d\n", handle, ret);
4911 #ifdef USE_MM_TSK_WINE
4912 /* C equivalent to mmtask.tsk binary content */
4913 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
4915 int len = cmdLine[0x80];
4918 void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1)));
4919 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
4922 InitTask16(); /* fixme: pmts / from context ? */
4925 if (SetMessageQueue16(0x40)) {
4927 if (HIWORD(fpProc)) {
4929 /* EPP StackEnter16(); */
4941 /**************************************************************************
4942 * mmTaskBlock [MMSYSTEM.902]
4944 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
4949 GetMessageA(&msg, 0, 0, 0);
4951 TranslateMessage(&msg);
4952 DispatchMessageA(&msg);
4954 } while (msg.message < 0x3A0);
4957 /**************************************************************************
4958 * mmTaskSignal [MMSYSTEM.903]
4960 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
4962 TRACE("(%04x);\n", ht);
4963 return PostAppMessage16(ht, WM_USER, 0, 0);
4966 /**************************************************************************
4967 * mmGetCurrentTask [MMSYSTEM.904]
4969 HTASK16 WINAPI mmGetCurrentTask16(void)
4971 return GetCurrentTask();
4974 /**************************************************************************
4975 * mmTaskYield [MMSYSTEM.905]
4977 void WINAPI mmTaskYield16(void)
4981 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
4986 DWORD WINAPI GetProcessFlags(DWORD);
4988 /**************************************************************************
4989 * mmThreadCreate [MMSYSTEM.1120]
4992 * Creates a MM thread, calling fpThreadAddr(dwPmt).
4994 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
4995 * bit.1 set means to open a VxD for this thread (unsupported)
4997 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
5002 TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
5004 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
5009 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5012 /* force mmtask routines even if mmthread is required */
5013 /* this will work only if the patch about binary cmd line and NE tasks
5019 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
5020 lpMMThd->dwCounter = 0;
5021 lpMMThd->hThread = 0;
5022 lpMMThd->dwThreadID = 0;
5023 lpMMThd->fpThread = fpThreadAddr;
5024 lpMMThd->dwThreadPmt = dwPmt;
5025 lpMMThd->dwSignalCount = 0;
5026 lpMMThd->hEvent = 0;
5028 lpMMThd->dwStatus = 0;
5029 lpMMThd->dwFlags = dwFlags;
5032 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
5033 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
5035 TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
5036 if (lpMMThd->dwFlags & 2) {
5037 /* as long as we don't support MM VxD in wine, we don't need
5038 * to care about this flag
5040 /* FIXME("Don't know how to properly open VxD handles\n"); */
5041 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
5044 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
5045 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
5046 if (lpMMThd->hThread == 0) {
5047 WARN("Couldn't create thread\n");
5048 /* clean-up(VxDhandle...); devicedirectio... */
5049 if (lpMMThd->hEvent != 0)
5050 CloseHandle(lpMMThd->hEvent);
5053 TRACE("Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
5057 /* get WINE_mmThreadEntryPoint()
5058 * 2047 is its ordinal in mmsystem.spec
5060 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047);
5062 TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp));
5064 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
5068 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
5069 WARN("Couldn't resume thread\n");
5071 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
5085 TRACE("ok => %ld\n", ret);
5089 /**************************************************************************
5090 * mmThreadSignal [MMSYSTEM.1121]
5092 void WINAPI mmThreadSignal16(HANDLE16 hndl)
5094 TRACE("(%04x)!\n", hndl);
5097 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5099 lpMMThd->dwCounter++;
5100 if (lpMMThd->hThread != 0) {
5101 InterlockedIncrement(&lpMMThd->dwSignalCount);
5102 SetEvent(lpMMThd->hEvent);
5104 mmTaskSignal16(lpMMThd->hTask);
5106 lpMMThd->dwCounter--;
5110 /**************************************************************************
5111 * MMSYSTEM_ThreadBlock [internal]
5113 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
5118 if (lpMMThd->dwThreadID != GetCurrentThreadId())
5119 ERR("Not called by thread itself\n");
5122 ResetEvent(lpMMThd->hEvent);
5123 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
5125 InterlockedIncrement(&lpMMThd->dwSignalCount);
5129 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
5131 case WAIT_OBJECT_0: /* Event */
5134 case WAIT_OBJECT_0 + 1: /* Msg */
5136 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
5137 TranslateMessage(&msg);
5138 DispatchMessageA(&msg);
5142 WARN("S2.x unsupported ret val 0x%08lx\n", ret);
5148 /**************************************************************************
5149 * mmThreadBlock [MMSYSTEM.1122]
5151 void WINAPI mmThreadBlock16(HANDLE16 hndl)
5153 TRACE("(%04x)!\n", hndl);
5156 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5158 if (lpMMThd->hThread != 0) {
5161 ReleaseThunkLock(&lc);
5162 MMSYSTEM_ThreadBlock(lpMMThd);
5163 RestoreThunkLock(lc);
5165 mmTaskBlock16(lpMMThd->hTask);
5171 /**************************************************************************
5172 * mmThreadIsCurrent [MMSYSTEM.1123]
5174 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
5178 TRACE("(%04x)!\n", hndl);
5180 if (hndl && mmThreadIsValid16(hndl)) {
5181 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5182 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
5184 TRACE("=> %d\n", ret);
5188 /**************************************************************************
5189 * mmThreadIsValid [MMSYSTEM.1124]
5191 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
5195 TRACE("(%04x)!\n", hndl);
5198 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5200 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
5201 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
5202 IsTask16(lpMMThd->hTask)) {
5203 lpMMThd->dwCounter++;
5204 if (lpMMThd->hThread != 0) {
5206 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
5207 dwThreadRet == STATUS_PENDING) {
5213 lpMMThd->dwCounter--;
5216 TRACE("=> %d\n", ret);
5220 /**************************************************************************
5221 * mmThreadGetTask [MMSYSTEM.1125]
5223 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5227 TRACE("(%04x)\n", hndl);
5229 if (mmThreadIsValid16(hndl)) {
5230 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5231 ret = lpMMThd->hTask;
5236 /* ### start build ### */
5237 extern LONG CALLBACK MMSYSTEM_CallTo16_long_l (FARPROC16,LONG);
5238 /* ### stop build ### */
5240 /**************************************************************************
5241 * __wine_mmThreadEntryPoint (MMSYSTEM.2047)
5243 void WINAPI WINE_mmThreadEntryPoint(DWORD _pmt)
5245 HANDLE16 hndl = (HANDLE16)_pmt;
5246 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5248 TRACE("(%04x %p)\n", hndl, lpMMThd);
5250 lpMMThd->hTask = LOWORD(GetCurrentTask());
5251 TRACE("[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5252 lpMMThd->dwStatus = 0x10;
5253 MMSYSTEM_ThreadBlock(lpMMThd);
5254 TRACE("[20-%08x]\n", lpMMThd->hThread);
5255 lpMMThd->dwStatus = 0x20;
5256 if (lpMMThd->fpThread) {
5257 MMSYSTEM_CallTo16_long_l(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5259 lpMMThd->dwStatus = 0x30;
5260 TRACE("[30-%08x]\n", lpMMThd->hThread);
5261 while (lpMMThd->dwCounter) {
5263 /* K32WOWYield16();*/
5265 TRACE("[XX-%08x]\n", lpMMThd->hThread);
5267 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5268 /* close lpMMThread->hVxD directIO */
5269 if (lpMMThd->hEvent)
5270 CloseHandle(lpMMThd->hEvent);
5275 typedef BOOL16 WINAPI (*MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR);
5277 /**************************************************************************
5278 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5280 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice,
5281 LPCSTR lpStrTab, LPCSTR lpStrTitle)
5286 TRACE("(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5288 hndl = LoadLibraryA("MMSYS.CPL");
5290 MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5293 ReleaseThunkLock(&lc);
5294 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5295 RestoreThunkLock(lc);
5303 /**************************************************************************
5304 * StackEnter [MMSYSTEM.32]
5306 void WINAPI StackEnter16(void)
5309 /* mmsystem.dll from Win 95 does only this: so does Wine */
5314 /**************************************************************************
5315 * StackLeave [MMSYSTEM.33]
5317 void WINAPI StackLeave16(void)
5320 /* mmsystem.dll from Win 95 does only this: so does Wine */
5325 /**************************************************************************
5326 * WMMMidiRunOnce [MMSYSTEM.8]
5328 void WINAPI WMMMidiRunOnce16(void)
5330 FIXME("(), stub!\n");
5333 /**************************************************************************
5334 * OutputDebugStr [MMSYSTEM.30]
5336 void WINAPI OutputDebugStr16(
5337 LPCSTR str) /* [in] The message to be logged and given to the debugger. */
5339 OutputDebugStringA( str );