1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1993 Martin Ayotte
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * 98/9 added Win32 MCI support
26 * 99/4 added mmTask and mmThread functions support
27 * added midiStream support
28 * 99/9 added support for loadable low level drivers
31 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses
32 * and long term pointers to 16 bit space in here
41 #include "wine/mmsystem16.h"
42 #include "wine/winuser16.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(mmsys);
51 static LPWINE_MM_IDATA lpFirstIData = NULL;
53 static LPWINE_MM_IDATA MULTIMEDIA_GetIDataNoCheck(void)
55 DWORD pid = GetCurrentProcessId();
56 LPWINE_MM_IDATA iData;
58 for (iData = lpFirstIData; iData; iData = iData->lpNextIData) {
59 if (iData->dwThisProcess == pid)
65 /**************************************************************************
66 * MULTIMEDIA_GetIData [internal]
68 LPWINE_MM_IDATA MULTIMEDIA_GetIData(void)
70 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
73 ERR("IData not found for pid=%08lx. Suicide !!!\n", GetCurrentProcessId());
80 /**************************************************************************
81 * MULTIMEDIA_CreateIData [internal]
83 static BOOL MULTIMEDIA_CreateIData(HINSTANCE hInstDLL)
85 LPWINE_MM_IDATA iData;
87 iData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
91 iData->hWinMM32Instance = hInstDLL;
92 iData->dwThisProcess = GetCurrentProcessId();
93 iData->lpNextIData = lpFirstIData;
95 InitializeCriticalSection(&iData->cs);
96 iData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
97 iData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
98 iData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
99 TRACE("Created IData (%p) for pid %08lx\n", iData, iData->dwThisProcess);
103 /**************************************************************************
104 * MULTIMEDIA_DeleteIData [internal]
106 static void MULTIMEDIA_DeleteIData(void)
108 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
109 LPWINE_MM_IDATA* ppid;
114 for (ppid = &lpFirstIData; *ppid; ppid = &(*ppid)->lpNextIData) {
115 if (*ppid == iData) {
116 *ppid = iData->lpNextIData;
120 /* FIXME: should also free content and resources allocated
122 CloseHandle(iData->psStopEvent);
123 CloseHandle(iData->psLastEvent);
124 DeleteCriticalSection(&iData->cs);
125 HeapFree(GetProcessHeap(), 0, iData);
129 /**************************************************************************
130 * DllEntryPoint (WINMM.init)
132 * WINMM DLL entry point
135 BOOL WINAPI WINMM_LibMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
137 TRACE("0x%x 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
140 case DLL_PROCESS_ATTACH:
141 if (!MULTIMEDIA_CreateIData(hInstDLL))
143 if (!MULTIMEDIA_MciInit() || !MMDRV_Init()) {
144 MULTIMEDIA_DeleteIData();
148 case DLL_PROCESS_DETACH:
149 MULTIMEDIA_DeleteIData();
151 case DLL_THREAD_ATTACH:
152 case DLL_THREAD_DETACH:
158 /**************************************************************************
159 * DllEntryPoint (MMSYSTEM.2046)
161 * MMSYSTEM DLL entry point
164 BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds,
165 WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
168 LPWINE_MM_IDATA iData;
170 TRACE("0x%x 0x%lx\n", hinstDLL, fdwReason);
173 case DLL_PROCESS_ATTACH:
174 /* need to load WinMM in order to:
175 * - initiate correctly shared variables (MULTIMEDIA_Init())
176 * - create correctly the per process WINE_MM_IDATA chunk
178 hndl = LoadLibraryA("WINMM.DLL");
181 ERR("Could not load sibling WinMM.dll\n");
184 iData = MULTIMEDIA_GetIData();
185 iData->hWinMM16Instance = hinstDLL;
186 iData->h16Module32 = hndl;
188 case DLL_PROCESS_DETACH:
189 iData = MULTIMEDIA_GetIData();
190 FreeLibrary(iData->h16Module32);
192 case DLL_THREAD_ATTACH:
193 case DLL_THREAD_DETACH:
199 /**************************************************************************
200 * MMSYSTEM_WEP [MMSYSTEM.1]
202 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
203 WORD cbHeapSize, LPSTR lpCmdLine)
205 FIXME("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
209 void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
211 mmt16->wType = mmt32->wType;
212 /* layout of rest is the same for 32/16,
213 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
215 memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
218 void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
220 mmt32->wType = mmt16->wType;
221 /* layout of rest is the same for 32/16,
222 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
224 memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
227 static HMMIO get_mmioFromFile(LPCWSTR lpszName)
233 ret = mmioOpenW((LPWSTR)lpszName, NULL,
234 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
235 if (ret != 0) return ret;
236 if (SearchPathW(NULL, lpszName, NULL, sizeof(buf)/sizeof(buf[0]), buf, &dummy))
238 return mmioOpenW(buf, NULL,
239 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
244 static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName)
249 HKEY hRegSnd, hRegApp, hScheme, hSnd;
250 DWORD err, type, count;
252 static WCHAR wszSounds[] = {'S','o','u','n','d','s',0};
253 static WCHAR wszDefault[] = {'D','e','f','a','u','l','t',0};
254 static WCHAR wszKey[] = {'A','p','p','E','v','e','n','t','s','\\',
255 'S','c','h','e','m','e','s','\\',
257 static WCHAR wszDotDefault[] = {'.','D','e','f','a','u','l','t',0};
258 static WCHAR wszNull[] = {0};
260 TRACE("searching in SystemSound list for %s\n", debugstr_w(lpszName));
261 GetProfileStringW(wszSounds, (LPWSTR)lpszName, wszNull, str, sizeof(str)/sizeof(str[0]));
262 if (lstrlenW(str) == 0)
264 if (uFlags & SND_NODEFAULT) goto next;
265 GetProfileStringW(wszSounds, wszDefault, wszNull, str, sizeof(str)/sizeof(str[0]));
266 if (lstrlenW(str) == 0) goto next;
268 for (ptr = str; *ptr && *ptr != ','; ptr++);
270 hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
271 if (hmmio != 0) return hmmio;
273 /* we look up the registry under
274 * HKCU\AppEvents\Schemes\Apps\.Default
275 * HKCU\AppEvents\Schemes\Apps\<AppName>
277 if (RegOpenKeyW(HKEY_CURRENT_USER, wszKey, &hRegSnd) != 0) goto none;
278 if (uFlags & SND_APPLICATION)
281 if (GetModuleFileNameW(0, str, sizeof(str)/sizeof(str[0])))
283 for (ptr = str + lstrlenW(str) - 1; ptr >= str; ptr--)
285 if (*ptr == '.') *ptr = 0;
288 err = RegOpenKeyW(hRegSnd, str, &hRegApp);
296 err = RegOpenKeyW(hRegSnd, wszDotDefault, &hRegApp);
298 RegCloseKey(hRegSnd);
299 if (err != 0) goto none;
300 err = RegOpenKeyW(hRegApp, lpszName, &hScheme);
301 RegCloseKey(hRegApp);
302 if (err != 0) goto none;
303 err = RegOpenKeyW(hScheme, wszDotDefault, &hSnd);
304 RegCloseKey(hScheme);
305 if (err != 0) goto none;
306 count = sizeof(str)/sizeof(str[0]);
307 err = RegQueryValueExW(hSnd, NULL, 0, &type, (LPBYTE)str, &count);
309 if (err != 0 || !*str) goto none;
310 hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
311 if (hmmio) return hmmio;
313 WARN("can't find SystemSound='%s' !\n", debugstr_w(lpszName));
317 struct playsound_data
323 static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg,
325 DWORD dwParam1, DWORD dwParam2)
327 struct playsound_data* s = (struct playsound_data*)dwInstance;
334 InterlockedIncrement(&s->dwEventCount);
335 TRACE("Returning waveHdr=%lx\n", dwParam1);
339 ERR("Unknown uMsg=%d\n", uMsg);
343 static void PlaySound_WaitDone(struct playsound_data* s)
346 ResetEvent(s->hEvent);
347 if (InterlockedDecrement(&s->dwEventCount) >= 0) break;
348 InterlockedIncrement(&s->dwEventCount);
350 WaitForSingleObject(s->hEvent, INFINITE);
354 static BOOL PlaySound_IsString(DWORD fdwSound, const void* psz)
356 /* SND_RESOURCE is 0x40004 while
357 * SND_MEMORY is 0x00004
359 switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME))
361 case SND_RESOURCE: return HIWORD(psz) != 0; /* by name or by ID ? */
362 case SND_MEMORY: return FALSE;
363 case SND_ALIAS: /* what about ALIAS_ID ??? */
366 default: FIXME("WTF\n"); return FALSE;
370 static void PlaySound_Free(WINE_PLAYSOUND* wps)
372 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
375 EnterCriticalSection(&iData->cs);
376 for (p = &iData->lpPlaySound; *p && *p != wps; p = &((*p)->lpNext));
377 if (*p) *p = (*p)->lpNext;
378 if (iData->lpPlaySound == NULL) SetEvent(iData->psLastEvent);
379 LeaveCriticalSection(&iData->cs);
380 if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound);
381 HeapFree(GetProcessHeap(), 0, wps);
384 static WINE_PLAYSOUND* PlaySound_Alloc(const void* pszSound, HMODULE hmod,
385 DWORD fdwSound, BOOL bUnicode)
389 wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps));
390 if (!wps) return NULL;
393 wps->fdwSound = fdwSound;
394 if (PlaySound_IsString(fdwSound, pszSound))
398 if (fdwSound & SND_ASYNC)
400 wps->pszSound = HeapAlloc(GetProcessHeap(), 0,
401 (lstrlenW(pszSound)+1) * sizeof(WCHAR));
402 if (!wps->pszSound) goto oom_error;
403 lstrcpyW((LPWSTR)wps->pszSound, pszSound);
407 wps->pszSound = pszSound;
411 wps->pszSound = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSound);
412 if (!wps->pszSound) goto oom_error;
417 wps->pszSound = pszSound;
425 static DWORD WINAPI proc_PlaySound(LPVOID arg)
427 WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg;
428 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
433 LPWAVEFORMATEX lpWaveFormat = NULL;
435 LPWAVEHDR waveHdr = NULL;
436 INT count, bufsize, left, index;
437 struct playsound_data s;
442 TRACE("SoundName='%s' !\n", debugstr_w(wps->pszSound));
444 /* if resource, grab it */
445 if ((wps->fdwSound & SND_RESOURCE) == SND_RESOURCE) {
446 static WCHAR wszWave[] = {'W','A','V','E',0};
450 if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 ||
451 (hGlob = LoadResource(wps->hMod, hRes)) == 0)
453 if ((data = LockResource(hGlob)) == NULL) {
459 data = (void*)wps->pszSound;
461 /* construct an MMIO stream (either in memory, or from a file */
462 if (wps->fdwSound & SND_MEMORY)
463 { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */
466 memset(&mminfo, 0, sizeof(mminfo));
467 mminfo.fccIOProc = FOURCC_MEM;
468 mminfo.pchBuffer = (LPSTR)data;
469 mminfo.cchBuffer = -1; /* FIXME: when a resource, could grab real size */
470 TRACE("Memory sound %p\n", data);
471 hmmio = mmioOpenW(NULL, &mminfo, MMIO_READ);
473 else if (wps->fdwSound & SND_ALIAS)
475 hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
477 else if (wps->fdwSound & SND_FILENAME)
479 hmmio = get_mmioFromFile(wps->pszSound);
483 if ((hmmio = get_mmioFromProfile(wps->fdwSound | SND_NODEFAULT, wps->pszSound)) == 0)
485 if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0)
487 hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
491 if (hmmio == 0) goto errCleanUp;
493 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0))
496 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
497 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
499 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
500 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
503 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
504 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
507 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
508 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
510 lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
511 if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT))
514 TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag);
515 TRACE("nChannels=%d \n", lpWaveFormat->nChannels);
516 TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec);
517 TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec);
518 TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign);
519 TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample);
521 /* move to end of 'fmt ' chunk */
522 mmioAscend(hmmio, &mmckInfo, 0);
524 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
525 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
528 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
529 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
531 s.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
533 if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback,
534 (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
537 /* make it so that 3 buffers per second are needed */
538 bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) *
539 lpWaveFormat->nBlockAlign;
540 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
541 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
542 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
543 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
544 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
545 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
546 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
547 if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
548 waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) {
552 s.dwEventCount = 1L; /* for first buffer */
556 left = mmckInfo.cksize;
558 mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
561 if (WaitForSingleObject(iData->psStopEvent, 0) == WAIT_OBJECT_0)
566 count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
567 if (count < 1) break;
569 waveHdr[index].dwBufferLength = count;
570 waveHdr[index].dwFlags &= ~WHDR_DONE;
571 if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) {
573 PlaySound_WaitDone(&s);
575 else FIXME("Couldn't play header\n");
578 } while (wps->bLoop);
580 PlaySound_WaitDone(&s); /* for last buffer */
583 waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
584 waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
587 TRACE("Done playing='%s' => %s!\n", debugstr_w(wps->pszSound), bRet ? "ok" : "ko");
588 CloseHandle(s.hEvent);
589 if (waveHdr) HeapFree(GetProcessHeap(), 0, waveHdr);
590 if (lpWaveFormat) HeapFree(GetProcessHeap(), 0, lpWaveFormat);
591 if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
592 if (hmmio) mmioClose(hmmio, 0);
599 static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode)
601 WINE_PLAYSOUND* wps = NULL;
602 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
604 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
605 pszSound, hmod, fdwSound);
607 /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP !
608 * there could be one if several sounds can be played at once...
610 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound != NULL)
613 /* alloc internal structure, if we need to play something */
614 if (pszSound && !(fdwSound & SND_PURGE))
616 if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode)))
620 EnterCriticalSection(&iData->cs);
621 /* since several threads can enter PlaySound in parallel, we're not
622 * sure, at this point, that another thread didn't start a new playsound
624 while (iData->lpPlaySound != NULL)
626 ResetEvent(iData->psLastEvent);
627 /* FIXME: doc says we have to stop all instances of pszSound if it's non
628 * NULL... as of today, we stop all playing instances */
629 SetEvent(iData->psStopEvent);
631 LeaveCriticalSection(&iData->cs);
632 WaitForSingleObject(iData->psLastEvent, INFINITE);
633 EnterCriticalSection(&iData->cs);
635 ResetEvent(iData->psStopEvent);
638 if (wps) wps->lpNext = iData->lpPlaySound;
639 iData->lpPlaySound = wps;
640 LeaveCriticalSection(&iData->cs);
642 if (!pszSound || (fdwSound & SND_PURGE)) return TRUE;
644 if (fdwSound & SND_ASYNC)
647 wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE;
648 if (CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id) != 0)
651 else return proc_PlaySound(wps);
658 /**************************************************************************
659 * PlaySoundA [WINMM.@]
661 BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound)
663 return MULTIMEDIA_PlaySound(pszSoundA, hmod, fdwSound, FALSE);
666 /**************************************************************************
667 * PlaySoundW [WINMM.@]
669 BOOL WINAPI PlaySoundW(LPCWSTR pszSoundW, HMODULE hmod, DWORD fdwSound)
671 return MULTIMEDIA_PlaySound(pszSoundW, hmod, fdwSound, TRUE);
674 /**************************************************************************
675 * PlaySound [MMSYSTEM.3]
677 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
682 ReleaseThunkLock(&lc);
683 retv = PlaySoundA(pszSound, hmod, fdwSound);
684 RestoreThunkLock(lc);
689 /**************************************************************************
690 * sndPlaySoundA [WINMM.@]
692 BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags)
694 uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC;
695 return MULTIMEDIA_PlaySound(pszSoundA, 0, uFlags, FALSE);
698 /**************************************************************************
699 * sndPlaySoundW [WINMM.@]
701 BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags)
703 uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC;
704 return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, TRUE);
707 /**************************************************************************
708 * sndPlaySound [MMSYSTEM.2]
710 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
715 ReleaseThunkLock(&lc);
716 retv = sndPlaySoundA(lpszSoundName, uFlags);
717 RestoreThunkLock(lc);
722 /**************************************************************************
723 * mmsystemGetVersion [MMSYSTEM.5]
724 * return value borrowed from Win95 winmm.dll ;)
726 UINT16 WINAPI mmsystemGetVersion16(void)
728 return mmsystemGetVersion();
731 /**************************************************************************
732 * mmsystemGetVersion [WINMM.@]
734 UINT WINAPI mmsystemGetVersion(void)
736 TRACE("3.10 (Win95?)\n");
740 /**************************************************************************
741 * DriverCallback [WINMM.@]
743 BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
744 UINT wMsg, DWORD dwUser, DWORD dwParam1,
747 TRACE("(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
748 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
750 switch (uFlags & DCB_TYPEMASK) {
754 WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack);
757 TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
758 PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
760 case DCB_TASK: /* aka DCB_THREAD */
761 TRACE("Task(%04lx) !\n", dwCallBack);
762 PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
765 TRACE("Function (32 bit) !\n");
766 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
769 TRACE("Event(%08lx) !\n", dwCallBack);
770 SetEvent((HANDLE)dwCallBack);
772 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
773 /* this is an undocumented DCB_ value used for mmThreads
774 * loword of dwCallBack contains the handle of the lpMMThd block
775 * which dwSignalCount has to be incremented
778 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(LOWORD(dwCallBack), 0) );
780 TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
781 /* same as mmThreadSignal16 */
782 InterlockedIncrement(&lpMMThd->dwSignalCount);
783 SetEvent(lpMMThd->hEvent);
784 /* some other stuff on lpMMThd->hVxD */
789 /* this is an undocumented DCB_ value for... I don't know */
793 WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
800 /**************************************************************************
801 * DriverCallback [MMSYSTEM.31]
803 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev,
804 WORD wMsg, DWORD dwUser, DWORD dwParam1,
807 return DriverCallback(dwCallBack, uFlags, HDRVR_32(hDev), wMsg, dwUser, dwParam1, dwParam2);
810 /**************************************************************************
811 * Mixer devices. New to Win95
814 /**************************************************************************
815 * find out the real mixer ID depending on hmix (depends on dwFlags)
817 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
819 LPWINE_MIXER lpwm = NULL;
821 switch (dwFlags & 0xF0000000ul) {
822 case MIXER_OBJECTF_MIXER:
823 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
825 case MIXER_OBJECTF_HMIXER:
826 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
828 case MIXER_OBJECTF_WAVEOUT:
829 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
831 case MIXER_OBJECTF_HWAVEOUT:
832 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
834 case MIXER_OBJECTF_WAVEIN:
835 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
837 case MIXER_OBJECTF_HWAVEIN:
838 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
840 case MIXER_OBJECTF_MIDIOUT:
841 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
843 case MIXER_OBJECTF_HMIDIOUT:
844 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
846 case MIXER_OBJECTF_MIDIIN:
847 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
849 case MIXER_OBJECTF_HMIDIIN:
850 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
852 case MIXER_OBJECTF_AUX:
853 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
856 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
862 /**************************************************************************
863 * mixerGetNumDevs [WINMM.@]
865 UINT WINAPI mixerGetNumDevs(void)
867 return MMDRV_GetNum(MMDRV_MIXER);
870 /**************************************************************************
871 * mixerGetNumDevs [MMSYSTEM.800]
873 UINT16 WINAPI mixerGetNumDevs16(void)
875 return MMDRV_GetNum(MMDRV_MIXER);
878 /**************************************************************************
879 * mixerGetDevCapsA [WINMM.@]
881 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
885 if ((wmld = MMDRV_Get(devid, MMDRV_MIXER, TRUE)) == NULL)
886 return MMSYSERR_BADDEVICEID;
888 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
891 /**************************************************************************
892 * mixerGetDevCapsW [WINMM.@]
894 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
897 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
899 if (ret == MMSYSERR_NOERROR) {
900 mixcaps->wMid = micA.wMid;
901 mixcaps->wPid = micA.wPid;
902 mixcaps->vDriverVersion = micA.vDriverVersion;
903 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
904 sizeof(mixcaps->szPname)/sizeof(WCHAR) );
905 mixcaps->fdwSupport = micA.fdwSupport;
906 mixcaps->cDestinations = micA.cDestinations;
911 /**************************************************************************
912 * mixerGetDevCaps [MMSYSTEM.801]
914 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps,
918 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
920 if (ret == MMSYSERR_NOERROR) {
921 mixcaps->wMid = micA.wMid;
922 mixcaps->wPid = micA.wPid;
923 mixcaps->vDriverVersion = micA.vDriverVersion;
924 strcpy(mixcaps->szPname, micA.szPname);
925 mixcaps->fdwSupport = micA.fdwSupport;
926 mixcaps->cDestinations = micA.cDestinations;
931 static UINT MMSYSTEM_mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
932 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
939 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
940 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
942 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
943 &dwCallback, &dwInstance, bFrom32);
945 wmld->uDeviceID = uDeviceID;
946 mod.hmx = (HMIXEROBJ)hMix;
947 mod.dwCallback = dwCallback;
948 mod.dwInstance = dwInstance;
950 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
952 if (dwRet != MMSYSERR_NOERROR) {
953 MMDRV_Free(hMix, wmld);
956 if (lphMix) *lphMix = hMix;
957 TRACE("=> %ld hMixer=%04x\n", dwRet, hMix);
962 /**************************************************************************
963 * mixerOpen [WINMM.@]
965 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
966 DWORD dwInstance, DWORD fdwOpen)
968 return MMSYSTEM_mixerOpen(lphMix, uDeviceID,
969 dwCallback, dwInstance, fdwOpen, TRUE);
972 /**************************************************************************
973 * mixerOpen [MMSYSTEM.802]
975 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
976 DWORD dwInstance, DWORD fdwOpen)
981 ret = MMSYSTEM_mixerOpen(&hmix, uDeviceID,
982 dwCallback, dwInstance, fdwOpen, FALSE);
983 if (lphmix) *lphmix = HMIXER_16(hmix);
987 /**************************************************************************
988 * mixerClose [WINMM.@]
990 UINT WINAPI mixerClose(HMIXER hMix)
995 TRACE("(%04x)\n", hMix);
997 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
999 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
1000 MMDRV_Free(hMix, wmld);
1005 /**************************************************************************
1006 * mixerClose [MMSYSTEM.803]
1008 UINT16 WINAPI mixerClose16(HMIXER16 hMix)
1010 return mixerClose(HMIXER_32(hMix));
1013 /**************************************************************************
1014 * mixerGetID [WINMM.@]
1016 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
1020 TRACE("(%04x %p %08lx)\n", hmix, lpid, fdwID);
1022 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
1023 return MMSYSERR_INVALHANDLE;
1027 *lpid = lpwm->mld.uDeviceID;
1029 return MMSYSERR_NOERROR;
1032 /**************************************************************************
1033 * mixerGetID (MMSYSTEM.806)
1035 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
1038 UINT ret = mixerGetID(HMIXEROBJ_32(hmix), &xid, fdwID);
1045 /**************************************************************************
1046 * mixerGetControlDetailsA [WINMM.@]
1048 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1053 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1055 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1056 return MMSYSERR_INVALHANDLE;
1058 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
1059 return MMSYSERR_INVALPARAM;
1061 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
1065 /**************************************************************************
1066 * mixerGetControlDetailsW [WINMM.@]
1068 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
1070 DWORD ret = MMSYSERR_NOTENABLED;
1072 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1074 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1075 return MMSYSERR_INVALPARAM;
1077 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
1078 case MIXER_GETCONTROLDETAILSF_VALUE:
1079 /* can savely use W structure as it is, no string inside */
1080 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
1082 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
1084 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
1085 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
1086 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1089 if (lpmcd->u.cMultipleItems != 0) {
1090 size *= lpmcd->u.cMultipleItems;
1092 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
1093 lpmcd->paDetails = pDetailsA;
1094 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1095 /* set up lpmcd->paDetails */
1096 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
1097 /* copy from lpmcd->paDetails back to paDetailsW; */
1098 if(ret == MMSYSERR_NOERROR) {
1099 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
1100 pDetailsW->dwParam1 = pDetailsA->dwParam1;
1101 pDetailsW->dwParam2 = pDetailsA->dwParam2;
1102 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
1104 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
1108 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
1109 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
1111 HeapFree(GetProcessHeap(), 0, pDetailsA);
1112 lpmcd->paDetails = pDetailsW;
1113 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
1117 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
1123 /**************************************************************************
1124 * mixerGetControlDetails [MMSYSTEM.808]
1126 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix,
1127 LPMIXERCONTROLDETAILS16 lpmcd,
1130 DWORD ret = MMSYSERR_NOTENABLED;
1133 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1135 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1136 return MMSYSERR_INVALPARAM;
1138 sppaDetails = (SEGPTR)lpmcd->paDetails;
1139 lpmcd->paDetails = MapSL(sppaDetails);
1140 ret = mixerGetControlDetailsA(HMIXEROBJ_32(hmix),
1141 (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails);
1142 lpmcd->paDetails = (LPVOID)sppaDetails;
1147 /**************************************************************************
1148 * mixerGetLineControlsA [WINMM.@]
1150 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
1155 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
1157 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
1158 return MMSYSERR_INVALHANDLE;
1160 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
1161 return MMSYSERR_INVALPARAM;
1163 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
1167 /**************************************************************************
1168 * mixerGetLineControlsW [WINMM.@]
1170 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
1173 MIXERLINECONTROLSA mlcA;
1177 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
1179 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
1180 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
1181 return MMSYSERR_INVALPARAM;
1183 mlcA.cbStruct = sizeof(mlcA);
1184 mlcA.dwLineID = lpmlcW->dwLineID;
1185 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
1186 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
1187 mlcA.cControls = lpmlcW->cControls;
1188 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1189 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1190 mlcA.cControls * mlcA.cbmxctrl);
1192 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
1194 if (ret == MMSYSERR_NOERROR) {
1195 lpmlcW->dwLineID = mlcA.dwLineID;
1196 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
1197 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
1198 lpmlcW->cControls = mlcA.cControls;
1200 for (i = 0; i < mlcA.cControls; i++) {
1201 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
1202 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1203 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1204 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1205 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1206 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
1207 lpmlcW->pamxctrl[i].szShortName,
1208 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
1209 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
1210 lpmlcW->pamxctrl[i].szName,
1211 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
1212 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
1213 * sizeof(mlcA.pamxctrl[i].Bounds) */
1214 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1215 sizeof(mlcA.pamxctrl[i].Bounds));
1216 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
1217 * sizeof(mlcA.pamxctrl[i].Metrics) */
1218 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1219 sizeof(mlcA.pamxctrl[i].Metrics));
1223 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1228 /**************************************************************************
1229 * mixerGetLineControls [MMSYSTEM.807]
1231 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix,
1232 LPMIXERLINECONTROLS16 lpmlc16,
1235 MIXERLINECONTROLSA mlcA;
1238 LPMIXERCONTROL16 lpmc16;
1240 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls);
1242 if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) ||
1243 lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16))
1244 return MMSYSERR_INVALPARAM;
1246 mlcA.cbStruct = sizeof(mlcA);
1247 mlcA.dwLineID = lpmlc16->dwLineID;
1248 mlcA.u.dwControlID = lpmlc16->u.dwControlID;
1249 mlcA.u.dwControlType = lpmlc16->u.dwControlType;
1250 mlcA.cControls = lpmlc16->cControls;
1251 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1252 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1253 mlcA.cControls * mlcA.cbmxctrl);
1255 ret = mixerGetLineControlsA(HMIXEROBJ_32(hmix), &mlcA, fdwControls);
1257 if (ret == MMSYSERR_NOERROR) {
1258 lpmlc16->dwLineID = mlcA.dwLineID;
1259 lpmlc16->u.dwControlID = mlcA.u.dwControlID;
1260 lpmlc16->u.dwControlType = mlcA.u.dwControlType;
1261 lpmlc16->cControls = mlcA.cControls;
1263 lpmc16 = MapSL(lpmlc16->pamxctrl);
1265 for (i = 0; i < mlcA.cControls; i++) {
1266 lpmc16[i].cbStruct = sizeof(MIXERCONTROL16);
1267 lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1268 lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1269 lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1270 lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1271 strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName);
1272 strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName);
1273 /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
1274 memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1275 sizeof(mlcA.pamxctrl[i].Bounds));
1276 /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
1277 memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1278 sizeof(mlcA.pamxctrl[i].Metrics));
1282 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1287 /**************************************************************************
1288 * mixerGetLineInfoA [WINMM.@]
1290 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
1294 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1296 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
1297 return MMSYSERR_INVALHANDLE;
1299 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
1303 /**************************************************************************
1304 * mixerGetLineInfoW [WINMM.@]
1306 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
1312 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1314 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
1315 return MMSYSERR_INVALPARAM;
1317 mliA.cbStruct = sizeof(mliA);
1318 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1319 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1320 mliA.dwComponentType = lpmliW->dwComponentType;
1322 case MIXER_GETLINEINFOF_DESTINATION:
1323 mliA.dwDestination = lpmliW->dwDestination;
1325 case MIXER_GETLINEINFOF_LINEID:
1326 mliA.dwLineID = lpmliW->dwLineID;
1328 case MIXER_GETLINEINFOF_SOURCE:
1329 mliA.dwDestination = lpmliW->dwDestination;
1330 mliA.dwSource = lpmliW->dwSource;
1332 case MIXER_GETLINEINFOF_TARGETTYPE:
1333 mliA.Target.dwType = lpmliW->Target.dwType;
1334 mliA.Target.wMid = lpmliW->Target.wMid;
1335 mliA.Target.wPid = lpmliW->Target.wPid;
1336 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
1337 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
1340 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1343 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1345 lpmliW->dwDestination = mliA.dwDestination;
1346 lpmliW->dwSource = mliA.dwSource;
1347 lpmliW->dwLineID = mliA.dwLineID;
1348 lpmliW->fdwLine = mliA.fdwLine;
1349 lpmliW->dwUser = mliA.dwUser;
1350 lpmliW->dwComponentType = mliA.dwComponentType;
1351 lpmliW->cChannels = mliA.cChannels;
1352 lpmliW->cConnections = mliA.cConnections;
1353 lpmliW->cControls = mliA.cControls;
1354 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
1355 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
1356 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
1357 sizeof(lpmliW->szName)/sizeof(WCHAR) );
1358 lpmliW->Target.dwType = mliA.Target.dwType;
1359 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
1360 lpmliW->Target.wMid = mliA.Target.wMid;
1361 lpmliW->Target.wPid = mliA.Target.wPid;
1362 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
1363 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
1364 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
1369 /**************************************************************************
1370 * mixerGetLineInfo [MMSYSTEM.805]
1372 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16,
1378 TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo);
1380 if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16))
1381 return MMSYSERR_INVALPARAM;
1383 mliA.cbStruct = sizeof(mliA);
1384 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1385 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1386 mliA.dwComponentType = lpmli16->dwComponentType;
1388 case MIXER_GETLINEINFOF_DESTINATION:
1389 mliA.dwDestination = lpmli16->dwDestination;
1391 case MIXER_GETLINEINFOF_LINEID:
1392 mliA.dwLineID = lpmli16->dwLineID;
1394 case MIXER_GETLINEINFOF_SOURCE:
1395 mliA.dwDestination = lpmli16->dwDestination;
1396 mliA.dwSource = lpmli16->dwSource;
1398 case MIXER_GETLINEINFOF_TARGETTYPE:
1399 mliA.Target.dwType = lpmli16->Target.dwType;
1400 mliA.Target.wMid = lpmli16->Target.wMid;
1401 mliA.Target.wPid = lpmli16->Target.wPid;
1402 mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion;
1403 strcpy(mliA.Target.szPname, lpmli16->Target.szPname);
1406 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1409 ret = mixerGetLineInfoA(HMIXEROBJ_32(hmix), &mliA, fdwInfo);
1411 lpmli16->dwDestination = mliA.dwDestination;
1412 lpmli16->dwSource = mliA.dwSource;
1413 lpmli16->dwLineID = mliA.dwLineID;
1414 lpmli16->fdwLine = mliA.fdwLine;
1415 lpmli16->dwUser = mliA.dwUser;
1416 lpmli16->dwComponentType = mliA.dwComponentType;
1417 lpmli16->cChannels = mliA.cChannels;
1418 lpmli16->cConnections = mliA.cConnections;
1419 lpmli16->cControls = mliA.cControls;
1420 strcpy(lpmli16->szShortName, mliA.szShortName);
1421 strcpy(lpmli16->szName, mliA.szName);
1422 lpmli16->Target.dwType = mliA.Target.dwType;
1423 lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID;
1424 lpmli16->Target.wMid = mliA.Target.wMid;
1425 lpmli16->Target.wPid = mliA.Target.wPid;
1426 lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion;
1427 strcpy(lpmli16->Target.szPname, mliA.Target.szPname);
1432 /**************************************************************************
1433 * mixerSetControlDetails [WINMM.@]
1435 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1440 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1442 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1443 return MMSYSERR_INVALHANDLE;
1445 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
1449 /**************************************************************************
1450 * mixerSetControlDetails [MMSYSTEM.809]
1452 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix,
1453 LPMIXERCONTROLDETAILS16 lpmcd,
1456 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1457 return MMSYSERR_NOTENABLED;
1460 /**************************************************************************
1461 * mixerMessage [WINMM.@]
1463 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
1467 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
1468 (DWORD)hmix, uMsg, dwParam1, dwParam2);
1470 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
1471 return MMSYSERR_INVALHANDLE;
1473 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
1476 /**************************************************************************
1477 * mixerMessage [MMSYSTEM.804]
1479 DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1,
1482 return mixerMessage(HMIXER_32(hmix), uMsg, dwParam1, dwParam2);
1485 /**************************************************************************
1486 * auxGetNumDevs [WINMM.@]
1488 UINT WINAPI auxGetNumDevs(void)
1490 return MMDRV_GetNum(MMDRV_AUX);
1493 /**************************************************************************
1494 * auxGetNumDevs [MMSYSTEM.350]
1496 UINT16 WINAPI auxGetNumDevs16(void)
1498 return MMDRV_GetNum(MMDRV_AUX);
1501 /**************************************************************************
1502 * auxGetDevCapsW [WINMM.@]
1504 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
1507 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
1509 lpCaps->wMid = acA.wMid;
1510 lpCaps->wPid = acA.wPid;
1511 lpCaps->vDriverVersion = acA.vDriverVersion;
1512 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
1513 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1514 lpCaps->wTechnology = acA.wTechnology;
1515 lpCaps->dwSupport = acA.dwSupport;
1519 /**************************************************************************
1520 * auxGetDevCapsA [WINMM.@]
1522 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
1526 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1528 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1529 return MMSYSERR_INVALHANDLE;
1530 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1533 /**************************************************************************
1534 * auxGetDevCaps [MMSYSTEM.351]
1536 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
1540 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1542 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1543 return MMSYSERR_INVALHANDLE;
1544 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1547 /**************************************************************************
1548 * auxGetVolume [WINMM.@]
1550 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1554 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1556 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1557 return MMSYSERR_INVALHANDLE;
1558 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1561 /**************************************************************************
1562 * auxGetVolume [MMSYSTEM.352]
1564 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume)
1568 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1570 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1571 return MMSYSERR_INVALHANDLE;
1572 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1575 /**************************************************************************
1576 * auxSetVolume [WINMM.@]
1578 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
1582 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1584 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1585 return MMSYSERR_INVALHANDLE;
1586 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1589 /**************************************************************************
1590 * auxSetVolume [MMSYSTEM.353]
1592 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
1596 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1598 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1599 return MMSYSERR_INVALHANDLE;
1600 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1603 /**************************************************************************
1604 * auxOutMessage [WINMM.@]
1606 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1610 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1611 return MMSYSERR_INVALHANDLE;
1613 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1616 /**************************************************************************
1617 * auxOutMessage [MMSYSTEM.354]
1619 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1623 TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1626 case AUXDM_GETNUMDEVS:
1627 case AUXDM_SETVOLUME:
1628 /* no argument conversion needed */
1630 case AUXDM_GETVOLUME:
1631 return auxGetVolume16(uDeviceID, MapSL(dw1));
1632 case AUXDM_GETDEVCAPS:
1633 return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2);
1635 TRACE("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1636 uDeviceID, uMessage, dw1, dw2);
1639 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1640 return MMSYSERR_INVALHANDLE;
1642 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1645 /**************************************************************************
1646 * mciGetErrorStringW [WINMM.@]
1648 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1650 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1651 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
1653 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
1654 HeapFree(GetProcessHeap(), 0, bufstr);
1658 /**************************************************************************
1659 * mciGetErrorString [MMSYSTEM.706]
1661 BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength)
1663 return mciGetErrorStringA(wError, lpstrBuffer, uLength);
1666 /**************************************************************************
1667 * mciGetErrorStringA [WINMM.@]
1669 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
1673 if (lpstrBuffer != NULL && uLength > 0 &&
1674 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
1676 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
1677 dwError, lpstrBuffer, uLength) > 0) {
1684 /**************************************************************************
1685 * mciDriverNotify [MMSYSTEM.711]
1687 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1689 TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1691 return PostMessageA(HWND_32(hWndCallBack), MM_MCINOTIFY, wStatus, wDevID);
1694 /**************************************************************************
1695 * mciDriverNotify [WINMM.@]
1697 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1700 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1702 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1705 /**************************************************************************
1706 * mciGetDriverData [MMSYSTEM.708]
1708 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1710 return mciGetDriverData(uDeviceID);
1713 /**************************************************************************
1714 * mciGetDriverData [WINMM.@]
1716 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1718 LPWINE_MCIDRIVER wmd;
1720 TRACE("(%04x)\n", uDeviceID);
1722 wmd = MCI_GetDriver(uDeviceID);
1725 WARN("Bad uDeviceID\n");
1729 return wmd->dwPrivate;
1732 /**************************************************************************
1733 * mciSetDriverData [MMSYSTEM.707]
1735 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1737 return mciSetDriverData(uDeviceID, data);
1740 /**************************************************************************
1741 * mciSetDriverData [WINMM.@]
1743 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1745 LPWINE_MCIDRIVER wmd;
1747 TRACE("(%04x, %08lx)\n", uDeviceID, data);
1749 wmd = MCI_GetDriver(uDeviceID);
1752 WARN("Bad uDeviceID\n");
1756 wmd->dwPrivate = data;
1760 /**************************************************************************
1761 * mciSendCommandA [WINMM.@]
1763 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1767 TRACE("(%08x, %s, %08lx, %08lx)\n",
1768 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1770 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
1771 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1772 TRACE("=> %08lx\n", dwRet);
1776 /**************************************************************************
1777 * mciSendCommandW [WINMM.@]
1779 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1781 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
1782 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1783 return MCIERR_UNSUPPORTED_FUNCTION;
1786 /**************************************************************************
1787 * mciSendCommand [MMSYSTEM.701]
1789 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1793 TRACE("(%04X, %s, %08lX, %08lX)\n",
1794 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1796 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE);
1797 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1798 TRACE("=> %ld\n", dwRet);
1802 /**************************************************************************
1803 * mciGetDeviceID [MMSYSTEM.703]
1805 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1807 TRACE("(\"%s\")\n", lpstrName);
1809 return MCI_GetDriverFromString(lpstrName);
1812 /**************************************************************************
1813 * mciGetDeviceIDA [WINMM.@]
1815 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1817 return MCI_GetDriverFromString(lpstrName);
1820 /**************************************************************************
1821 * mciGetDeviceIDW [WINMM.@]
1823 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1828 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1829 ret = MCI_GetDriverFromString(lpstrName);
1830 HeapFree(GetProcessHeap(), 0, lpstrName);
1834 /**************************************************************************
1835 * MCI_DefYieldProc [internal]
1837 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1841 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1843 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
1844 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1850 msg.hwnd = HWND_32(HIWORD(data));
1851 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1857 /**************************************************************************
1858 * mciSetYieldProc [MMSYSTEM.714]
1860 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData)
1862 LPWINE_MCIDRIVER wmd;
1864 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1866 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1867 WARN("Bad uDeviceID\n");
1871 wmd->lpfnYieldProc = (YIELDPROC)fpYieldProc;
1872 wmd->dwYieldData = dwYieldData;
1878 /**************************************************************************
1879 * mciSetYieldProc [WINMM.@]
1881 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1883 LPWINE_MCIDRIVER wmd;
1885 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1887 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1888 WARN("Bad uDeviceID\n");
1892 wmd->lpfnYieldProc = fpYieldProc;
1893 wmd->dwYieldData = dwYieldData;
1899 /**************************************************************************
1900 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
1902 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1904 FIXME("(%lu, %s) stub\n", dwElementID, lpstrType);
1908 /**************************************************************************
1909 * mciGetDeviceIDFromElementIDW [WINMM.@]
1911 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1913 /* FIXME: that's rather strange, there is no
1914 * mciGetDeviceIDFromElementID32A in winmm.spec
1916 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1920 /**************************************************************************
1921 * mciGetYieldProc [MMSYSTEM.716]
1923 YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1925 LPWINE_MCIDRIVER wmd;
1927 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1929 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1930 WARN("Bad uDeviceID\n");
1933 if (!wmd->lpfnYieldProc) {
1934 WARN("No proc set\n");
1938 WARN("Proc is 32 bit\n");
1941 return (YIELDPROC16)wmd->lpfnYieldProc;
1944 /**************************************************************************
1945 * mciGetYieldProc [WINMM.@]
1947 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1949 LPWINE_MCIDRIVER wmd;
1951 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1953 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1954 WARN("Bad uDeviceID\n");
1957 if (!wmd->lpfnYieldProc) {
1958 WARN("No proc set\n");
1962 WARN("Proc is 32 bit\n");
1965 return wmd->lpfnYieldProc;
1968 /**************************************************************************
1969 * mciGetCreatorTask [MMSYSTEM.717]
1971 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1973 LPWINE_MCIDRIVER wmd;
1976 if ((wmd = MCI_GetDriver(uDeviceID))) ret = wmd->hCreatorTask;
1978 TRACE("(%u) => %04x\n", uDeviceID, ret);
1982 /**************************************************************************
1983 * mciGetCreatorTask [WINMM.@]
1985 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1987 LPWINE_MCIDRIVER wmd;
1990 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
1992 TRACE("(%u) => %08x\n", uDeviceID, ret);
1996 /**************************************************************************
1997 * mciDriverYield [MMSYSTEM.710]
1999 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
2001 LPWINE_MCIDRIVER wmd;
2004 /* TRACE("(%04x)\n", uDeviceID); */
2006 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) {
2009 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
2015 /**************************************************************************
2016 * mciDriverYield [WINMM.@]
2018 UINT WINAPI mciDriverYield(UINT uDeviceID)
2020 LPWINE_MCIDRIVER wmd;
2023 TRACE("(%04x)\n", uDeviceID);
2025 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
2028 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
2034 /**************************************************************************
2035 * midiOutGetNumDevs [WINMM.@]
2037 UINT WINAPI midiOutGetNumDevs(void)
2039 return MMDRV_GetNum(MMDRV_MIDIOUT);
2042 /**************************************************************************
2043 * midiOutGetNumDevs [MMSYSTEM.201]
2045 UINT16 WINAPI midiOutGetNumDevs16(void)
2047 return MMDRV_GetNum(MMDRV_MIDIOUT);
2050 /**************************************************************************
2051 * midiOutGetDevCapsW [WINMM.@]
2053 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
2059 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
2060 lpCaps->wMid = mocA.wMid;
2061 lpCaps->wPid = mocA.wPid;
2062 lpCaps->vDriverVersion = mocA.vDriverVersion;
2063 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
2064 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2065 lpCaps->wTechnology = mocA.wTechnology;
2066 lpCaps->wVoices = mocA.wVoices;
2067 lpCaps->wNotes = mocA.wNotes;
2068 lpCaps->wChannelMask = mocA.wChannelMask;
2069 lpCaps->dwSupport = mocA.dwSupport;
2073 /**************************************************************************
2074 * midiOutGetDevCapsA [WINMM.@]
2076 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
2081 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
2083 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2085 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2086 return MMSYSERR_INVALHANDLE;
2088 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2091 /**************************************************************************
2092 * midiOutGetDevCaps [MMSYSTEM.202]
2094 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps,
2100 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2102 dwRet = midiOutGetDevCapsA(uDeviceID, &capsA, sizeof(capsA));
2103 if (dwRet == MMSYSERR_NOERROR) {
2104 lpCaps->wMid = capsA.wMid;
2105 lpCaps->wPid = capsA.wPid;
2106 lpCaps->vDriverVersion = capsA.vDriverVersion;
2107 strcpy(lpCaps->szPname, capsA.szPname);
2108 lpCaps->wTechnology = capsA.wTechnology;
2109 lpCaps->wVoices = capsA.wVoices;
2110 lpCaps->wNotes = capsA.wNotes;
2111 lpCaps->wChannelMask = capsA.wChannelMask;
2112 lpCaps->dwSupport = capsA.dwSupport;
2117 /**************************************************************************
2118 * MIDI_GetErrorText [internal]
2120 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2122 UINT16 ret = MMSYSERR_BADERRNUM;
2124 if (lpText == NULL) {
2125 ret = MMSYSERR_INVALPARAM;
2126 } else if (uSize == 0) {
2127 ret = MMSYSERR_NOERROR;
2129 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2130 * a warning for the test was always true */
2131 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
2132 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
2134 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
2135 uError, lpText, uSize) > 0) {
2136 ret = MMSYSERR_NOERROR;
2142 /**************************************************************************
2143 * midiOutGetErrorTextA [WINMM.@]
2145 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2147 return MIDI_GetErrorText(uError, lpText, uSize);
2150 /**************************************************************************
2151 * midiOutGetErrorTextW [WINMM.@]
2153 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2155 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2158 ret = MIDI_GetErrorText(uError, xstr, uSize);
2159 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2160 HeapFree(GetProcessHeap(), 0, xstr);
2164 /**************************************************************************
2165 * midiOutGetErrorText [MMSYSTEM.203]
2167 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2169 return MIDI_GetErrorText(uError, lpText, uSize);
2172 /**************************************************************************
2173 * MIDI_OutAlloc [internal]
2175 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
2176 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
2177 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
2183 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
2185 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
2186 lpdwCallback, lpdwInstance, bFrom32);
2188 if (lphMidiOut != NULL)
2189 *lphMidiOut = hMidiOut;
2192 lpwm->mod.hMidi = (HMIDI) hMidiOut;
2193 lpwm->mod.dwCallback = *lpdwCallback;
2194 lpwm->mod.dwInstance = *lpdwInstance;
2195 lpwm->mod.dnDevNode = 0;
2196 lpwm->mod.cIds = cIDs;
2198 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2203 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
2204 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2210 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2211 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2213 if (lphMidiOut != NULL) *lphMidiOut = 0;
2215 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
2219 return MMSYSERR_NOMEM;
2221 lpwm->mld.uDeviceID = uDeviceID;
2223 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
2226 if (dwRet != MMSYSERR_NOERROR) {
2227 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
2231 if (lphMidiOut) *lphMidiOut = hMidiOut;
2232 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
2237 /**************************************************************************
2238 * midiOutOpen [WINMM.@]
2240 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2241 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2243 return MMSYSTEM_midiOutOpen(lphMidiOut, uDeviceID, dwCallback,
2244 dwInstance, dwFlags, TRUE);
2247 /**************************************************************************
2248 * midiOutOpen [MMSYSTEM.204]
2250 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2251 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2256 ret = MMSYSTEM_midiOutOpen(&hmo, uDeviceID, dwCallback, dwInstance,
2259 if (lphMidiOut != NULL) *lphMidiOut = HMIDIOUT_16(hmo);
2263 /**************************************************************************
2264 * midiOutClose [WINMM.@]
2266 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2271 TRACE("(%04X)\n", hMidiOut);
2273 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2274 return MMSYSERR_INVALHANDLE;
2276 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
2277 MMDRV_Free(hMidiOut, wmld);
2282 /**************************************************************************
2283 * midiOutClose [MMSYSTEM.205]
2285 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2287 return midiOutClose(HMIDIOUT_32(hMidiOut));
2290 /**************************************************************************
2291 * midiOutPrepareHeader [WINMM.@]
2293 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2294 MIDIHDR* lpMidiOutHdr, UINT uSize)
2298 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2300 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2301 return MMSYSERR_INVALHANDLE;
2303 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2306 /**************************************************************************
2307 * midiOutPrepareHeader [MMSYSTEM.206]
2309 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2310 SEGPTR lpsegMidiOutHdr, /* [???] */
2311 UINT16 uSize) /* [in] */
2315 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2317 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2318 return MMSYSERR_INVALHANDLE;
2320 return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE);
2323 /**************************************************************************
2324 * midiOutUnprepareHeader [WINMM.@]
2326 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2327 MIDIHDR* lpMidiOutHdr, UINT uSize)
2331 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2333 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2334 return MMSYSERR_NOERROR;
2337 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2338 return MMSYSERR_INVALHANDLE;
2340 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2343 /**************************************************************************
2344 * midiOutUnprepareHeader [MMSYSTEM.207]
2346 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2347 SEGPTR lpsegMidiOutHdr, /* [???] */
2348 UINT16 uSize) /* [in] */
2351 LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr);
2353 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2355 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2356 return MMSYSERR_NOERROR;
2359 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2360 return MMSYSERR_INVALHANDLE;
2362 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2365 /**************************************************************************
2366 * midiOutShortMsg [WINMM.@]
2368 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2372 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
2374 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2375 return MMSYSERR_INVALHANDLE;
2377 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, FALSE);
2380 /**************************************************************************
2381 * midiOutShortMsg [MMSYSTEM.208]
2383 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2385 return midiOutShortMsg(HMIDIOUT_32(hMidiOut), dwMsg);
2388 /**************************************************************************
2389 * midiOutLongMsg [WINMM.@]
2391 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2392 MIDIHDR* lpMidiOutHdr, UINT uSize)
2396 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2398 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2399 return MMSYSERR_INVALHANDLE;
2401 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
2404 /**************************************************************************
2405 * midiOutLongMsg [MMSYSTEM.209]
2407 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */
2408 LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */
2409 UINT16 uSize) /* [in] */
2413 TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2415 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2416 return MMSYSERR_INVALHANDLE;
2418 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2421 /**************************************************************************
2422 * midiOutReset [WINMM.@]
2424 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2428 TRACE("(%04X)\n", hMidiOut);
2430 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2431 return MMSYSERR_INVALHANDLE;
2433 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
2436 /**************************************************************************
2437 * midiOutReset [MMSYSTEM.210]
2439 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2441 return midiOutReset(HMIDIOUT_32(hMidiOut));
2444 /**************************************************************************
2445 * midiOutGetVolume [WINMM.@]
2447 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2451 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
2453 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2454 return MMSYSERR_INVALHANDLE;
2456 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
2459 /**************************************************************************
2460 * midiOutGetVolume [MMSYSTEM.211]
2462 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2464 return midiOutGetVolume(uDeviceID, lpdwVolume);
2467 /**************************************************************************
2468 * midiOutSetVolume [WINMM.@]
2470 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2474 TRACE("(%04X, %ld);\n", uDeviceID, dwVolume);
2476 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2477 return MMSYSERR_INVALHANDLE;
2479 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
2482 /**************************************************************************
2483 * midiOutSetVolume [MMSYSTEM.212]
2485 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2487 return midiOutSetVolume(uDeviceID, dwVolume);
2490 /**************************************************************************
2491 * midiOutCachePatches [WINMM.@]
2493 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2494 WORD* lpwPatchArray, UINT uFlags)
2496 /* not really necessary to support this */
2497 FIXME("not supported yet\n");
2498 return MMSYSERR_NOTSUPPORTED;
2501 /**************************************************************************
2502 * midiOutCachePatches [MMSYSTEM.213]
2504 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2505 WORD* lpwPatchArray, UINT16 uFlags)
2507 return midiOutCachePatches(HMIDIOUT_32(hMidiOut), uBank, lpwPatchArray,
2511 /**************************************************************************
2512 * midiOutCacheDrumPatches [WINMM.@]
2514 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2515 WORD* lpwKeyArray, UINT uFlags)
2517 FIXME("not supported yet\n");
2518 return MMSYSERR_NOTSUPPORTED;
2521 /**************************************************************************
2522 * midiOutCacheDrumPatches [MMSYSTEM.214]
2524 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2525 WORD* lpwKeyArray, UINT16 uFlags)
2527 return midiOutCacheDrumPatches(HMIDIOUT_32(hMidiOut), uPatch, lpwKeyArray, uFlags);
2530 /**************************************************************************
2531 * midiOutGetID [WINMM.@]
2533 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2537 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2539 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2540 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2541 return MMSYSERR_INVALHANDLE;
2543 *lpuDeviceID = wmld->uDeviceID;
2544 return MMSYSERR_NOERROR;
2547 /**************************************************************************
2548 * midiOutGetID [MMSYSTEM.215]
2550 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2554 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2556 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2557 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2558 return MMSYSERR_INVALHANDLE;
2560 *lpuDeviceID = wmld->uDeviceID;
2561 return MMSYSERR_NOERROR;
2564 /**************************************************************************
2565 * midiOutMessage [WINMM.@]
2567 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2568 DWORD dwParam1, DWORD dwParam2)
2572 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2574 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
2576 if (uMessage == 0x0001) {
2577 *(LPDWORD)dwParam1 = 1;
2580 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
2581 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2583 return MMSYSERR_INVALHANDLE;
2589 FIXME("can't handle OPEN or CLOSE message!\n");
2590 return MMSYSERR_NOTSUPPORTED;
2592 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2595 /**************************************************************************
2596 * midiOutMessage [MMSYSTEM.216]
2598 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2599 DWORD dwParam1, DWORD dwParam2)
2603 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2605 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2606 return MMSYSERR_INVALHANDLE;
2611 FIXME("can't handle OPEN or CLOSE message!\n");
2612 return MMSYSERR_NOTSUPPORTED;
2614 case MODM_GETVOLUME:
2615 return midiOutGetVolume16(hMidiOut, MapSL(dwParam1));
2617 return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2);
2619 /* lpMidiOutHdr is still a segmented pointer for this function */
2620 return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2);
2621 case MODM_UNPREPARE:
2622 return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2);
2624 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2627 /**************************************************************************
2628 * midiInGetNumDevs [WINMM.@]
2630 UINT WINAPI midiInGetNumDevs(void)
2632 return MMDRV_GetNum(MMDRV_MIDIIN);
2635 /**************************************************************************
2636 * midiInGetNumDevs [MMSYSTEM.301]
2638 UINT16 WINAPI midiInGetNumDevs16(void)
2640 return MMDRV_GetNum(MMDRV_MIDIIN);
2643 /**************************************************************************
2644 * midiInGetDevCapsW [WINMM.@]
2646 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2649 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2651 if (ret == MMSYSERR_NOERROR) {
2652 lpCaps->wMid = micA.wMid;
2653 lpCaps->wPid = micA.wPid;
2654 lpCaps->vDriverVersion = micA.vDriverVersion;
2655 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
2656 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2657 lpCaps->dwSupport = micA.dwSupport;
2662 /**************************************************************************
2663 * midiInGetDevCapsA [WINMM.@]
2665 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2669 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
2671 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
2672 return MMSYSERR_INVALHANDLE;
2674 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2677 /**************************************************************************
2678 * midiInGetDevCaps [MMSYSTEM.302]
2680 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps,
2684 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2686 if (ret == MMSYSERR_NOERROR) {
2687 lpCaps->wMid = micA.wMid;
2688 lpCaps->wPid = micA.wPid;
2689 lpCaps->vDriverVersion = micA.vDriverVersion;
2690 strcpy(lpCaps->szPname, micA.szPname);
2691 lpCaps->dwSupport = micA.dwSupport;
2697 /**************************************************************************
2698 * midiInGetErrorTextW [WINMM.@]
2700 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2702 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2703 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
2705 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2706 HeapFree(GetProcessHeap(), 0, xstr);
2710 /**************************************************************************
2711 * midiInGetErrorTextA [WINMM.@]
2713 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2715 return MIDI_GetErrorText(uError, lpText, uSize);
2718 /**************************************************************************
2719 * midiInGetErrorText [MMSYSTEM.303]
2721 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2723 return MIDI_GetErrorText(uError, lpText, uSize);
2726 static UINT MMSYSTEM_midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
2727 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2733 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2734 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2736 if (lphMidiIn != NULL) *lphMidiIn = 0;
2738 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
2739 &dwFlags, &dwCallback, &dwInstance, bFrom32);
2742 return MMSYSERR_NOMEM;
2744 lpwm->mod.hMidi = (HMIDI) hMidiIn;
2745 lpwm->mod.dwCallback = dwCallback;
2746 lpwm->mod.dwInstance = dwInstance;
2748 lpwm->mld.uDeviceID = uDeviceID;
2749 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
2751 if (dwRet != MMSYSERR_NOERROR) {
2752 MMDRV_Free(hMidiIn, &lpwm->mld);
2755 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
2756 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
2761 /**************************************************************************
2762 * midiInOpen [WINMM.@]
2764 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2765 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2767 return MMSYSTEM_midiInOpen(lphMidiIn, uDeviceID, dwCallback,
2768 dwInstance, dwFlags, TRUE);
2771 /**************************************************************************
2772 * midiInOpen [MMSYSTEM.304]
2774 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2775 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2780 ret = MMSYSTEM_midiInOpen(&xhmid, uDeviceID, dwCallback, dwInstance,
2783 if (lphMidiIn) *lphMidiIn = HMIDIIN_16(xhmid);
2787 /**************************************************************************
2788 * midiInClose [WINMM.@]
2790 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2795 TRACE("(%04X)\n", hMidiIn);
2797 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2798 return MMSYSERR_INVALHANDLE;
2800 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
2801 MMDRV_Free(hMidiIn, wmld);
2805 /**************************************************************************
2806 * midiInClose [MMSYSTEM.305]
2808 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2810 return midiInClose(HMIDIIN_32(hMidiIn));
2813 /**************************************************************************
2814 * midiInPrepareHeader [WINMM.@]
2816 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2817 MIDIHDR* lpMidiInHdr, UINT uSize)
2821 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2823 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2824 return MMSYSERR_INVALHANDLE;
2826 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2829 /**************************************************************************
2830 * midiInPrepareHeader [MMSYSTEM.306]
2832 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2833 SEGPTR lpsegMidiInHdr, /* [???] */
2834 UINT16 uSize) /* [in] */
2838 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2840 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL)
2841 return MMSYSERR_INVALHANDLE;
2843 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2846 /**************************************************************************
2847 * midiInUnprepareHeader [WINMM.@]
2849 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2850 MIDIHDR* lpMidiInHdr, UINT uSize)
2854 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2856 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2857 return MMSYSERR_NOERROR;
2860 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2861 return MMSYSERR_INVALHANDLE;
2863 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2866 /**************************************************************************
2867 * midiInUnprepareHeader [MMSYSTEM.307]
2869 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2870 SEGPTR lpsegMidiInHdr, /* [???] */
2871 UINT16 uSize) /* [in] */
2874 LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr);
2876 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2878 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2879 return MMSYSERR_NOERROR;
2882 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL)
2883 return MMSYSERR_INVALHANDLE;
2885 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2888 /**************************************************************************
2889 * midiInAddBuffer [WINMM.@]
2891 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2892 MIDIHDR* lpMidiInHdr, UINT uSize)
2896 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2898 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2899 return MMSYSERR_INVALHANDLE;
2901 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
2904 /**************************************************************************
2905 * midiInAddBuffer [MMSYSTEM.308]
2907 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */
2908 MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */
2909 UINT16 uSize) /* [in] */
2913 TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2915 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL)
2916 return MMSYSERR_INVALHANDLE;
2918 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2921 /**************************************************************************
2922 * midiInStart [WINMM.@]
2924 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2928 TRACE("(%04X)\n", hMidiIn);
2930 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2931 return MMSYSERR_INVALHANDLE;
2933 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
2936 /**************************************************************************
2937 * midiInStart [MMSYSTEM.309]
2939 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2941 return midiInStart(HMIDIIN_32(hMidiIn));
2944 /**************************************************************************
2945 * midiInStop [WINMM.@]
2947 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2951 TRACE("(%04X)\n", hMidiIn);
2953 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2954 return MMSYSERR_INVALHANDLE;
2956 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
2959 /**************************************************************************
2960 * midiInStop [MMSYSTEM.310]
2962 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2964 return midiInStop(HMIDIIN_32(hMidiIn));
2967 /**************************************************************************
2968 * midiInReset [WINMM.@]
2970 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2974 TRACE("(%04X)\n", hMidiIn);
2976 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2977 return MMSYSERR_INVALHANDLE;
2979 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
2982 /**************************************************************************
2983 * midiInReset [MMSYSTEM.311]
2985 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2987 return midiInReset(HMIDIIN_32(hMidiIn));
2990 /**************************************************************************
2991 * midiInGetID [WINMM.@]
2993 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2997 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2999 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
3001 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
3002 return MMSYSERR_INVALHANDLE;
3004 *lpuDeviceID = wmld->uDeviceID;
3006 return MMSYSERR_NOERROR;
3009 /**************************************************************************
3010 * midiInGetID [MMSYSTEM.312]
3012 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
3016 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
3018 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
3020 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, TRUE)) == NULL)
3021 return MMSYSERR_INVALHANDLE;
3023 *lpuDeviceID = wmld->uDeviceID;
3025 return MMSYSERR_NOERROR;
3028 /**************************************************************************
3029 * midiInMessage [WINMM.@]
3031 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
3032 DWORD dwParam1, DWORD dwParam2)
3036 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3038 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
3039 return MMSYSERR_INVALHANDLE;
3044 FIXME("can't handle OPEN or CLOSE message!\n");
3045 return MMSYSERR_NOTSUPPORTED;
3047 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
3050 /**************************************************************************
3051 * midiInMessage [MMSYSTEM.313]
3053 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
3054 DWORD dwParam1, DWORD dwParam2)
3058 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3063 FIXME("can't handle OPEN or CLOSE message!\n");
3064 return MMSYSERR_NOTSUPPORTED;
3066 case MIDM_GETDEVCAPS:
3067 return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2);
3069 return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2);
3070 case MIDM_UNPREPARE:
3071 return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2);
3072 case MIDM_ADDBUFFER:
3073 return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2);
3076 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL)
3077 return MMSYSERR_INVALHANDLE;
3079 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
3082 typedef struct WINE_MIDIStream {
3093 LPMIDIHDR lpMidiHdr;
3096 #define WINE_MSM_HEADER (WM_USER+0)
3097 #define WINE_MSM_STOP (WM_USER+1)
3099 /**************************************************************************
3100 * MMSYSTEM_GetMidiStream [internal]
3102 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
3104 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
3113 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
3115 return *lpMidiStrm != NULL;
3118 /**************************************************************************
3119 * MMSYSTEM_MidiStream_Convert [internal]
3121 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
3125 if (lpMidiStrm->dwTimeDiv == 0) {
3126 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
3127 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
3128 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
3129 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
3130 ret = (pulse * 1000) / (nf * nsf);
3132 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
3133 (double)lpMidiStrm->dwTimeDiv);
3139 /**************************************************************************
3140 * MMSYSTEM_MidiStream_MessageHandler [internal]
3142 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
3144 LPMIDIHDR lpMidiHdr;
3148 switch (msg->message) {
3150 SetEvent(lpMidiStrm->hEvent);
3154 /* this is not quite what MS doc says... */
3155 midiOutReset(lpMidiStrm->hDevice);
3156 /* empty list of already submitted buffers */
3157 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
3158 lpMidiHdr->dwFlags |= MHDR_DONE;
3159 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3161 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
3162 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
3163 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3165 lpMidiStrm->lpMidiHdr = 0;
3166 SetEvent(lpMidiStrm->hEvent);
3168 case WINE_MSM_HEADER:
3169 /* sets initial tick count for first MIDIHDR */
3170 if (!lpMidiStrm->dwStartTicks)
3171 lpMidiStrm->dwStartTicks = GetTickCount();
3173 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
3174 * by native mcimidi, it doesn't look like a correct one".
3175 * this trick allows to throw it away... but I don't like it.
3176 * It looks like part of the file I'm trying to play and definitively looks
3177 * like raw midi content
3178 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
3179 * synchronization issue where native mcimidi is still processing raw MIDI
3180 * content before generating MIDIEVENTs ?
3182 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
3183 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
3184 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
3185 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
3186 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
3187 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
3188 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
3189 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
3190 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
3191 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3192 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3193 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3194 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3195 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3196 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3197 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3198 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3200 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3201 lpData = lpMidiHdr->lpData;
3202 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
3203 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
3204 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
3205 lpMidiHdr->dwFlags, msg->wParam);
3207 /* dumps content of lpMidiHdr->lpData
3208 * FIXME: there should be a debug routine somewhere that already does this
3209 * I hate spreading this type of shit all around the code
3211 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
3215 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
3216 printf("%02x ", lpData[dwToGo + i]);
3219 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
3220 ch = lpData[dwToGo + i];
3221 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
3226 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3227 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3228 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3229 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
3230 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
3231 ((LPMIDIEVENT)lpData)->dwStreamID);
3232 lpMidiHdr->dwFlags |= MHDR_DONE;
3233 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3235 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
3236 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
3237 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3241 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
3243 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3244 lpMidiHdr->lpNext = 0;
3245 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
3246 lpMidiHdr->dwFlags &= MHDR_DONE;
3247 lpMidiHdr->dwOffset = 0;
3251 FIXME("Unknown message %d\n", msg->message);
3257 /**************************************************************************
3258 * MMSYSTEM_MidiStream_Player [internal]
3260 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
3262 WINE_MIDIStream* lpMidiStrm = pmt;
3267 LPMIDIHDR lpMidiHdr;
3271 TRACE("(%p)!\n", lpMidiStrm);
3274 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
3277 /* force thread's queue creation */
3278 /* Used to be InitThreadInput16(0, 5); */
3279 /* but following works also with hack in midiStreamOpen */
3280 PeekMessageA(&msg, 0, 0, 0, 0);
3282 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
3283 SetEvent(lpMidiStrm->hEvent);
3284 TRACE("Ready to go 1\n");
3285 /* thread is started in paused mode */
3286 SuspendThread(lpMidiStrm->hThread);
3287 TRACE("Ready to go 2\n");
3289 lpMidiStrm->dwStartTicks = 0;
3290 lpMidiStrm->dwPulses = 0;
3292 lpMidiStrm->lpMidiHdr = 0;
3295 lpMidiHdr = lpMidiStrm->lpMidiHdr;
3297 /* for first message, block until one arrives, then process all that are available */
3298 GetMessageA(&msg, 0, 0, 0);
3300 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3302 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
3308 lpData = lpMidiHdr->lpData;
3310 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3312 /* do we have to wait ? */
3313 if (me->dwDeltaTime) {
3314 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
3315 lpMidiStrm->dwPulses += me->dwDeltaTime;
3317 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3319 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
3320 while ((dwCurrTC = GetTickCount()) < dwToGo) {
3321 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
3322 /* got a message, handle it */
3323 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
3324 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3329 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
3334 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3336 FIXME("NIY: MEVT_COMMENT\n");
3337 /* do nothing, skip bytes */
3340 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3345 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3348 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3353 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3356 if (me->dwEvent & MEVT_F_CALLBACK) {
3357 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
3358 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
3359 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
3361 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
3362 if (me->dwEvent & MEVT_F_LONG)
3363 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
3364 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
3365 /* done with this header */
3366 lpMidiHdr->dwFlags |= MHDR_DONE;
3367 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3369 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
3370 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
3371 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
3372 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3377 TRACE("End of thread\n");
3379 return 0; /* for removing the warning, never executed */
3382 /**************************************************************************
3383 * MMSYSTEM_MidiStream_PostMessage [internal]
3385 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
3387 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
3390 ReleaseThunkLock(&count);
3391 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3392 RestoreThunkLock(count);
3394 WARN("bad PostThreadMessageA\n");
3400 /**************************************************************************
3401 * midiStreamClose [WINMM.@]
3403 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3405 WINE_MIDIStream* lpMidiStrm;
3407 TRACE("(%08x)!\n", hMidiStrm);
3409 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3410 return MMSYSERR_INVALHANDLE;
3412 midiStreamStop(hMidiStrm);
3413 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
3414 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
3415 CloseHandle(lpMidiStrm->hEvent);
3417 return midiOutClose((HMIDIOUT)hMidiStrm);
3420 /**************************************************************************
3421 * MMSYSTEM_MidiStream_Open [internal]
3423 static MMRESULT WINAPI MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3424 DWORD cMidi, DWORD dwCallback,
3425 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
3427 WINE_MIDIStream* lpMidiStrm;
3429 MIDIOPENSTRMID mosm;
3433 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3434 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3436 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3437 return MMSYSERR_INVALPARAM;
3439 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3441 return MMSYSERR_NOMEM;
3443 lpMidiStrm->dwTempo = 500000;
3444 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3445 lpMidiStrm->dwPositionMS = 0;
3447 mosm.dwStreamID = (DWORD)lpMidiStrm;
3448 /* FIXME: the correct value is not allocated yet for MAPPER */
3449 mosm.wDeviceID = *lpuDeviceID;
3450 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
3451 lpMidiStrm->hDevice = hMidiOut;
3453 *lphMidiStrm = (HMIDISTRM)hMidiOut;
3455 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
3456 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
3457 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
3459 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
3460 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
3461 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3463 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
3464 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3466 if (!lpMidiStrm->hThread) {
3467 midiStreamClose((HMIDISTRM)hMidiOut);
3468 return MMSYSERR_NOMEM;
3471 /* wait for thread to have started, and for its queue to be created */
3475 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3476 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3477 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3479 ReleaseThunkLock(&count);
3480 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3481 RestoreThunkLock(count);
3484 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
3485 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
3489 /**************************************************************************
3490 * midiStreamOpen [WINMM.@]
3492 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3493 DWORD cMidi, DWORD dwCallback,
3494 DWORD dwInstance, DWORD fdwOpen)
3496 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
3497 dwInstance, fdwOpen, TRUE);
3500 /**************************************************************************
3501 * midiStreamOut [WINMM.@]
3503 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
3506 WINE_MIDIStream* lpMidiStrm;
3507 DWORD ret = MMSYSERR_NOERROR;
3509 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3511 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3512 ret = MMSYSERR_INVALHANDLE;
3513 } else if (!lpMidiHdr) {
3514 ret = MMSYSERR_INVALPARAM;
3516 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
3517 WINE_MSM_HEADER, cbMidiHdr,
3518 (DWORD)lpMidiHdr)) {
3519 WARN("bad PostThreadMessageA\n");
3520 ret = MMSYSERR_ERROR;
3526 /**************************************************************************
3527 * midiStreamPause [WINMM.@]
3529 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3531 WINE_MIDIStream* lpMidiStrm;
3532 DWORD ret = MMSYSERR_NOERROR;
3534 TRACE("(%08x)!\n", hMidiStrm);
3536 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3537 ret = MMSYSERR_INVALHANDLE;
3539 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3540 WARN("bad Suspend (%ld)\n", GetLastError());
3541 ret = MMSYSERR_ERROR;
3547 /**************************************************************************
3548 * midiStreamPosition [WINMM.@]
3550 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3552 WINE_MIDIStream* lpMidiStrm;
3553 DWORD ret = MMSYSERR_NOERROR;
3555 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3557 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3558 ret = MMSYSERR_INVALHANDLE;
3559 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3560 ret = MMSYSERR_INVALPARAM;
3562 switch (lpMMT->wType) {
3564 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3565 TRACE("=> %ld ms\n", lpMMT->u.ms);
3568 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3569 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
3572 WARN("Unsupported time type %d\n", lpMMT->wType);
3573 lpMMT->wType = TIME_MS;
3574 ret = MMSYSERR_INVALPARAM;
3581 /**************************************************************************
3582 * midiStreamProperty [WINMM.@]
3584 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3586 WINE_MIDIStream* lpMidiStrm;
3587 MMRESULT ret = MMSYSERR_NOERROR;
3589 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3591 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3592 ret = MMSYSERR_INVALHANDLE;
3593 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3594 ret = MMSYSERR_INVALPARAM;
3595 } else if (dwProperty & MIDIPROP_TEMPO) {
3596 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3598 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3599 ret = MMSYSERR_INVALPARAM;
3600 } else if (dwProperty & MIDIPROP_SET) {
3601 lpMidiStrm->dwTempo = mpt->dwTempo;
3602 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
3603 } else if (dwProperty & MIDIPROP_GET) {
3604 mpt->dwTempo = lpMidiStrm->dwTempo;
3605 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
3607 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3608 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3610 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3611 ret = MMSYSERR_INVALPARAM;
3612 } else if (dwProperty & MIDIPROP_SET) {
3613 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3614 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
3615 } else if (dwProperty & MIDIPROP_GET) {
3616 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3617 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
3620 ret = MMSYSERR_INVALPARAM;
3626 /**************************************************************************
3627 * midiStreamRestart [WINMM.@]
3629 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3631 WINE_MIDIStream* lpMidiStrm;
3632 MMRESULT ret = MMSYSERR_NOERROR;
3634 TRACE("(%08x)!\n", hMidiStrm);
3636 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3637 ret = MMSYSERR_INVALHANDLE;
3641 /* since we increase the thread suspend count on each midiStreamPause
3642 * there may be a need for several midiStreamResume
3645 ret = ResumeThread(lpMidiStrm->hThread);
3646 } while (ret != 0xFFFFFFFF && ret != 0);
3647 if (ret == 0xFFFFFFFF) {
3648 WARN("bad Resume (%ld)\n", GetLastError());
3649 ret = MMSYSERR_ERROR;
3651 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
3657 /**************************************************************************
3658 * midiStreamStop [WINMM.@]
3660 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3662 WINE_MIDIStream* lpMidiStrm;
3663 MMRESULT ret = MMSYSERR_NOERROR;
3665 TRACE("(%08x)!\n", hMidiStrm);
3667 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3668 ret = MMSYSERR_INVALHANDLE;
3670 /* in case stream has been paused... FIXME is the current state correct ? */
3671 midiStreamRestart(hMidiStrm);
3672 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
3677 /**************************************************************************
3678 * midiStreamClose [MMSYSTEM.252]
3680 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3682 return midiStreamClose(HMIDISTRM_32(hMidiStrm));
3685 /**************************************************************************
3686 * midiStreamOpen [MMSYSTEM.251]
3688 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3689 DWORD cMidi, DWORD dwCallback,
3690 DWORD dwInstance, DWORD fdwOpen)
3692 HMIDISTRM hMidiStrm32;
3696 if (!phMidiStrm || !devid)
3697 return MMSYSERR_INVALPARAM;
3699 ret = MMSYSTEM_MidiStream_Open(&hMidiStrm32, &devid32, cMidi, dwCallback,
3700 dwInstance, fdwOpen, FALSE);
3701 *phMidiStrm = HMIDISTRM_16(hMidiStrm32);
3706 /**************************************************************************
3707 * midiStreamOut [MMSYSTEM.254]
3709 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3711 return midiStreamOut(HMIDISTRM_32(hMidiStrm), (LPMIDIHDR)lpMidiHdr,
3715 /**************************************************************************
3716 * midiStreamPause [MMSYSTEM.255]
3718 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3720 return midiStreamPause(HMIDISTRM_32(hMidiStrm));
3723 /**************************************************************************
3724 * midiStreamPosition [MMSYSTEM.253]
3726 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3732 return MMSYSERR_INVALPARAM;
3733 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3734 ret = midiStreamPosition(HMIDISTRM_32(hMidiStrm), &mmt32, sizeof(MMTIME));
3735 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3739 /**************************************************************************
3740 * midiStreamProperty [MMSYSTEM.250]
3742 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3744 return midiStreamProperty(HMIDISTRM_32(hMidiStrm), lpPropData, dwProperty);
3747 /**************************************************************************
3748 * midiStreamRestart [MMSYSTEM.256]
3750 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3752 return midiStreamRestart(HMIDISTRM_32(hMidiStrm));
3755 /**************************************************************************
3756 * midiStreamStop [MMSYSTEM.257]
3758 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3760 return midiStreamStop(HMIDISTRM_32(hMidiStrm));
3763 static UINT WINAPI MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
3764 const LPWAVEFORMATEX lpFormat,
3765 DWORD dwCallback, DWORD dwInstance,
3766 DWORD dwFlags, BOOL bFrom32)
3770 DWORD dwRet = MMSYSERR_NOERROR;
3773 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
3774 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
3775 dwInstance, dwFlags, bFrom32?32:16);
3777 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
3779 if (lpFormat == NULL) return WAVERR_BADFORMAT;
3780 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
3781 return MMSYSERR_INVALPARAM;
3783 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
3784 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
3785 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
3787 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
3788 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
3789 return MMSYSERR_NOMEM;
3792 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
3793 wod.dwCallback = dwCallback;
3794 wod.dwInstance = dwInstance;
3797 if (dwFlags & WAVE_MAPPED) {
3798 wod.uMappedDeviceID = uDeviceID;
3799 uDeviceID = WAVE_MAPPER;
3801 wod.uMappedDeviceID = -1;
3803 wmld->uDeviceID = uDeviceID;
3805 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, (DWORD)&wod, dwFlags);
3807 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
3808 MMDRV_Free(handle, wmld);
3812 if (lphndl != NULL) *lphndl = handle;
3813 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
3818 /**************************************************************************
3819 * waveOutGetNumDevs [WINMM.@]
3821 UINT WINAPI waveOutGetNumDevs(void)
3823 return MMDRV_GetNum(MMDRV_WAVEOUT);
3826 /**************************************************************************
3827 * waveOutGetNumDevs [MMSYSTEM.401]
3829 UINT16 WINAPI waveOutGetNumDevs16(void)
3831 return MMDRV_GetNum(MMDRV_WAVEOUT);
3834 /**************************************************************************
3835 * waveOutGetDevCaps [MMSYSTEM.402]
3837 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID,
3838 LPWAVEOUTCAPS16 lpCaps, UINT16 uSize)
3843 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3844 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3846 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3848 if (ret == MMSYSERR_NOERROR) {
3849 lpCaps->wMid = wocA.wMid;
3850 lpCaps->wPid = wocA.wPid;
3851 lpCaps->vDriverVersion = wocA.vDriverVersion;
3852 strcpy(lpCaps->szPname, wocA.szPname);
3853 lpCaps->dwFormats = wocA.dwFormats;
3854 lpCaps->wChannels = wocA.wChannels;
3855 lpCaps->dwSupport = wocA.dwSupport;
3860 /**************************************************************************
3861 * waveOutGetDevCapsA [WINMM.@]
3863 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3868 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3870 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3872 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
3873 return MMSYSERR_INVALHANDLE;
3875 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
3879 /**************************************************************************
3880 * waveOutGetDevCapsW [WINMM.@]
3882 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3888 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3890 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3892 if (ret == MMSYSERR_NOERROR) {
3893 lpCaps->wMid = wocA.wMid;
3894 lpCaps->wPid = wocA.wPid;
3895 lpCaps->vDriverVersion = wocA.vDriverVersion;
3896 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
3897 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
3898 lpCaps->dwFormats = wocA.dwFormats;
3899 lpCaps->wChannels = wocA.wChannels;
3900 lpCaps->dwSupport = wocA.dwSupport;
3905 /**************************************************************************
3906 * WAVE_GetErrorText [internal]
3908 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3910 UINT16 ret = MMSYSERR_BADERRNUM;
3912 if (lpText == NULL) {
3913 ret = MMSYSERR_INVALPARAM;
3914 } else if (uSize == 0) {
3915 ret = MMSYSERR_NOERROR;
3917 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
3918 * a warning for the test was always true */
3919 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
3920 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
3922 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
3923 uError, lpText, uSize) > 0) {
3924 ret = MMSYSERR_NOERROR;
3930 /**************************************************************************
3931 * waveOutGetErrorText [MMSYSTEM.403]
3933 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3935 return WAVE_GetErrorText(uError, lpText, uSize);
3938 /**************************************************************************
3939 * waveOutGetErrorTextA [WINMM.@]
3941 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3943 return WAVE_GetErrorText(uError, lpText, uSize);
3946 /**************************************************************************
3947 * waveOutGetErrorTextW [WINMM.@]
3949 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3951 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3952 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
3954 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
3955 HeapFree(GetProcessHeap(), 0, xstr);
3959 /**************************************************************************
3960 * waveOutOpen [WINMM.@]
3961 * All the args/structs have the same layout as the win16 equivalents
3963 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3964 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3965 DWORD dwInstance, DWORD dwFlags)
3967 return MMSYSTEM_waveOpen(lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
3968 dwCallback, dwInstance, dwFlags, TRUE);
3971 /**************************************************************************
3972 * waveOutOpen [MMSYSTEM.404]
3974 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3975 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3976 DWORD dwInstance, DWORD dwFlags)
3981 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
3982 * call the 32 bit version
3983 * however, we need to promote correctly the wave mapper id
3984 * (0xFFFFFFFF and not 0x0000FFFF)
3986 ret = MMSYSTEM_waveOpen(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
3987 MMDRV_WAVEOUT, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
3989 if (lphWaveOut != NULL) *lphWaveOut = HWAVEOUT_16(hWaveOut);
3993 /**************************************************************************
3994 * waveOutClose [WINMM.@]
3996 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
4001 TRACE("(%04X)\n", hWaveOut);
4003 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4004 return MMSYSERR_INVALHANDLE;
4006 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
4007 MMDRV_Free(hWaveOut, wmld);
4012 /**************************************************************************
4013 * waveOutClose [MMSYSTEM.405]
4015 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
4020 ReleaseThunkLock(&level);
4021 ret = waveOutClose(HWAVEOUT_32(hWaveOut));
4022 RestoreThunkLock(level);
4026 /**************************************************************************
4027 * waveOutPrepareHeader [WINMM.@]
4029 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
4030 WAVEHDR* lpWaveOutHdr, UINT uSize)
4034 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4036 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
4038 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4039 return MMSYSERR_INVALHANDLE;
4041 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4044 /**************************************************************************
4045 * waveOutPrepareHeader [MMSYSTEM.406]
4047 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
4048 SEGPTR lpsegWaveOutHdr, /* [???] */
4049 UINT16 uSize) /* [in] */
4052 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
4054 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4056 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
4058 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL)
4059 return MMSYSERR_INVALHANDLE;
4061 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4064 /**************************************************************************
4065 * waveOutUnprepareHeader [WINMM.@]
4067 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
4068 LPWAVEHDR lpWaveOutHdr, UINT uSize)
4072 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4074 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
4075 return MMSYSERR_NOERROR;
4078 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4079 return MMSYSERR_INVALHANDLE;
4081 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4084 /**************************************************************************
4085 * waveOutUnprepareHeader [MMSYSTEM.407]
4087 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
4088 SEGPTR lpsegWaveOutHdr, /* [???] */
4089 UINT16 uSize) /* [in] */
4092 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
4094 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4096 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
4097 return MMSYSERR_NOERROR;
4100 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL)
4101 return MMSYSERR_INVALHANDLE;
4103 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4106 /**************************************************************************
4107 * waveOutWrite [WINMM.@]
4109 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
4114 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4116 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4117 return MMSYSERR_INVALHANDLE;
4119 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4122 /**************************************************************************
4123 * waveOutWrite [MMSYSTEM.408]
4125 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */
4126 LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */
4127 UINT16 uSize) /* [in] */
4131 TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4133 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL)
4134 return MMSYSERR_INVALHANDLE;
4136 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4139 /**************************************************************************
4140 * waveOutBreakLoop [WINMM.@]
4142 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
4146 TRACE("(%04X);\n", hWaveOut);
4148 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4149 return MMSYSERR_INVALHANDLE;
4150 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
4153 /**************************************************************************
4154 * waveOutBreakLoop [MMSYSTEM.419]
4156 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16)
4161 ReleaseThunkLock(&level);
4162 ret = waveOutBreakLoop(HWAVEOUT_32(hWaveOut16));
4163 RestoreThunkLock(level);
4167 /**************************************************************************
4168 * waveOutPause [WINMM.@]
4170 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
4174 TRACE("(%04X);\n", hWaveOut);
4176 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4177 return MMSYSERR_INVALHANDLE;
4178 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
4181 /**************************************************************************
4182 * waveOutPause [MMSYSTEM.409]
4184 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16)
4189 ReleaseThunkLock(&level);
4190 ret = waveOutPause(HWAVEOUT_32(hWaveOut16));
4191 RestoreThunkLock(level);
4195 /**************************************************************************
4196 * waveOutReset [WINMM.@]
4198 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
4202 TRACE("(%04X);\n", hWaveOut);
4204 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4205 return MMSYSERR_INVALHANDLE;
4206 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
4209 /**************************************************************************
4210 * waveOutReset [MMSYSTEM.411]
4212 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16)
4217 ReleaseThunkLock(&level);
4218 ret = waveOutReset(HWAVEOUT_32(hWaveOut16));
4219 RestoreThunkLock(level);
4223 /**************************************************************************
4224 * waveOutRestart [WINMM.@]
4226 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
4230 TRACE("(%04X);\n", hWaveOut);
4232 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4233 return MMSYSERR_INVALHANDLE;
4234 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
4237 /**************************************************************************
4238 * waveOutRestart [MMSYSTEM.410]
4240 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16)
4245 ReleaseThunkLock(&level);
4246 ret = waveOutRestart(HWAVEOUT_32(hWaveOut16));
4247 RestoreThunkLock(level);
4251 /**************************************************************************
4252 * waveOutGetPosition [WINMM.@]
4254 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
4259 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
4261 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4262 return MMSYSERR_INVALHANDLE;
4264 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4267 /**************************************************************************
4268 * waveOutGetPosition [MMSYSTEM.412]
4270 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
4276 mmt.wType = lpTime->wType;
4277 ret = waveOutGetPosition(HWAVEOUT_32(hWaveOut), &mmt, sizeof(mmt));
4278 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4282 /**************************************************************************
4283 * waveOutGetPitch [WINMM.@]
4285 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
4289 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4291 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4292 return MMSYSERR_INVALHANDLE;
4293 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
4296 /**************************************************************************
4297 * waveOutGetPitch [MMSYSTEM.413]
4299 UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4301 return waveOutGetPitch(HWAVEOUT_32(hWaveOut16), lpdw);
4304 /**************************************************************************
4305 * waveOutSetPitch [WINMM.@]
4307 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
4311 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4313 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4314 return MMSYSERR_INVALHANDLE;
4315 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
4318 /**************************************************************************
4319 * waveOutSetPitch [MMSYSTEM.414]
4321 UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw)
4323 return waveOutSetPitch(HWAVEOUT_32(hWaveOut16), dw);
4326 /**************************************************************************
4327 * waveOutGetPlaybackRate [WINMM.@]
4329 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
4333 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4335 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4336 return MMSYSERR_INVALHANDLE;
4337 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
4340 /**************************************************************************
4341 * waveOutGetPlaybackRate [MMSYSTEM.417]
4343 UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4345 return waveOutGetPlaybackRate(HWAVEOUT_32(hWaveOut16), lpdw);
4348 /**************************************************************************
4349 * waveOutSetPlaybackRate [WINMM.@]
4351 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
4355 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4357 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4358 return MMSYSERR_INVALHANDLE;
4359 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
4362 /**************************************************************************
4363 * waveOutSetPlaybackRate [MMSYSTEM.418]
4365 UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw)
4367 return waveOutSetPlaybackRate(HWAVEOUT_32(hWaveOut16), dw);
4370 /**************************************************************************
4371 * waveOutGetVolume [WINMM.@]
4373 UINT WINAPI waveOutGetVolume(UINT devid, LPDWORD lpdw)
4377 TRACE("(%04X, %08lx);\n", devid, (DWORD)lpdw);
4379 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4380 return MMSYSERR_INVALHANDLE;
4382 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
4385 /**************************************************************************
4386 * waveOutGetVolume [MMSYSTEM.415]
4388 UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw)
4390 return waveOutGetVolume(devid, lpdw);
4393 /**************************************************************************
4394 * waveOutSetVolume [WINMM.@]
4396 UINT WINAPI waveOutSetVolume(UINT devid, DWORD dw)
4400 TRACE("(%04X, %08lx);\n", devid, dw);
4402 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4403 return MMSYSERR_INVALHANDLE;
4405 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
4408 /**************************************************************************
4409 * waveOutSetVolume [MMSYSTEM.416]
4411 UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw)
4413 return waveOutSetVolume(devid, dw);
4416 /**************************************************************************
4417 * waveOutGetID [WINMM.@]
4419 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
4423 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4425 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4427 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4428 return MMSYSERR_INVALHANDLE;
4430 *lpuDeviceID = wmld->uDeviceID;
4434 /**************************************************************************
4435 * waveOutGetID [MMSYSTEM.420]
4437 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
4441 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4443 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4445 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL)
4446 return MMSYSERR_INVALHANDLE;
4448 *lpuDeviceID = wmld->uDeviceID;
4452 /**************************************************************************
4453 * waveOutMessage [WINMM.@]
4455 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
4456 DWORD dwParam1, DWORD dwParam2)
4460 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4462 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4463 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4464 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4466 return MMSYSERR_INVALHANDLE;
4470 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4471 return MMSYSERR_INVALPARAM;
4473 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4476 /**************************************************************************
4477 * waveOutMessage [MMSYSTEM.421]
4479 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4480 DWORD dwParam1, DWORD dwParam2)
4484 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4486 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) {
4487 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, TRUE)) != NULL) {
4488 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4490 return MMSYSERR_INVALHANDLE;
4494 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4495 return MMSYSERR_INVALPARAM;
4497 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
4500 /**************************************************************************
4501 * waveInGetNumDevs [WINMM.@]
4503 UINT WINAPI waveInGetNumDevs(void)
4505 return MMDRV_GetNum(MMDRV_WAVEIN);
4508 /**************************************************************************
4509 * waveInGetNumDevs [MMSYSTEM.501]
4511 UINT16 WINAPI waveInGetNumDevs16(void)
4513 return MMDRV_GetNum(MMDRV_WAVEIN);
4516 /**************************************************************************
4517 * waveInGetDevCapsW [WINMM.@]
4519 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4522 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
4524 if (ret == MMSYSERR_NOERROR) {
4525 lpCaps->wMid = wicA.wMid;
4526 lpCaps->wPid = wicA.wPid;
4527 lpCaps->vDriverVersion = wicA.vDriverVersion;
4528 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
4529 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
4530 lpCaps->dwFormats = wicA.dwFormats;
4531 lpCaps->wChannels = wicA.wChannels;
4537 /**************************************************************************
4538 * waveInGetDevCapsA [WINMM.@]
4540 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4544 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
4546 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
4547 return MMSYSERR_INVALHANDLE;
4549 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
4552 /**************************************************************************
4553 * waveInGetDevCaps [MMSYSTEM.502]
4555 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps,
4559 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
4561 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
4563 if (ret == MMSYSERR_NOERROR) {
4564 lpCaps->wMid = wicA.wMid;
4565 lpCaps->wPid = wicA.wPid;
4566 lpCaps->vDriverVersion = wicA.vDriverVersion;
4567 strcpy(lpCaps->szPname, wicA.szPname);
4568 lpCaps->dwFormats = wicA.dwFormats;
4569 lpCaps->wChannels = wicA.wChannels;
4574 /**************************************************************************
4575 * waveInGetErrorTextA [WINMM.@]
4577 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4579 return WAVE_GetErrorText(uError, lpText, uSize);
4582 /**************************************************************************
4583 * waveInGetErrorTextW [WINMM.@]
4585 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4587 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4588 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
4590 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
4591 HeapFree(GetProcessHeap(), 0, txt);
4595 /**************************************************************************
4596 * waveInGetErrorText [MMSYSTEM.503]
4598 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4600 return WAVE_GetErrorText(uError, lpText, uSize);
4603 /**************************************************************************
4604 * waveInOpen [WINMM.@]
4606 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4607 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4608 DWORD dwInstance, DWORD dwFlags)
4610 return MMSYSTEM_waveOpen(lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
4611 dwCallback, dwInstance, dwFlags, TRUE);
4614 /**************************************************************************
4615 * waveInOpen [MMSYSTEM.504]
4617 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4618 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4619 DWORD dwInstance, DWORD dwFlags)
4624 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
4625 * call the 32 bit version
4626 * however, we need to promote correctly the wave mapper id
4627 * (0xFFFFFFFF and not 0x0000FFFF)
4629 ret = MMSYSTEM_waveOpen(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
4630 MMDRV_WAVEIN, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
4632 if (lphWaveIn != NULL) *lphWaveIn = HWAVEIN_16(hWaveIn);
4636 /**************************************************************************
4637 * waveInClose [WINMM.@]
4639 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4644 TRACE("(%04X)\n", hWaveIn);
4646 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4647 return MMSYSERR_INVALHANDLE;
4649 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
4650 MMDRV_Free(hWaveIn, wmld);
4654 /**************************************************************************
4655 * waveInClose [MMSYSTEM.505]
4657 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4662 ReleaseThunkLock(&level);
4663 ret = waveInClose(HWAVEIN_32(hWaveIn));
4664 RestoreThunkLock(level);
4668 /**************************************************************************
4669 * waveInPrepareHeader [WINMM.@]
4671 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4676 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4678 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4679 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4680 return MMSYSERR_INVALHANDLE;
4682 lpWaveInHdr->dwBytesRecorded = 0;
4684 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4687 /**************************************************************************
4688 * waveInPrepareHeader [MMSYSTEM.506]
4690 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4691 SEGPTR lpsegWaveInHdr, /* [???] */
4692 UINT16 uSize) /* [in] */
4695 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4698 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4700 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4701 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4702 return MMSYSERR_INVALHANDLE;
4704 lpWaveInHdr->dwBytesRecorded = 0;
4706 ret = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4710 /**************************************************************************
4711 * waveInUnprepareHeader [WINMM.@]
4713 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4718 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4720 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4721 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4722 return MMSYSERR_NOERROR;
4725 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4726 return MMSYSERR_INVALHANDLE;
4728 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4731 /**************************************************************************
4732 * waveInUnprepareHeader [MMSYSTEM.507]
4734 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4735 SEGPTR lpsegWaveInHdr, /* [???] */
4736 UINT16 uSize) /* [in] */
4739 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4741 TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4743 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4745 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4746 return MMSYSERR_NOERROR;
4749 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4750 return MMSYSERR_INVALHANDLE;
4752 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4755 /**************************************************************************
4756 * waveInAddBuffer [WINMM.@]
4758 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4759 WAVEHDR* lpWaveInHdr, UINT uSize)
4763 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4765 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4766 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4767 return MMSYSERR_INVALHANDLE;
4769 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
4772 /**************************************************************************
4773 * waveInAddBuffer [MMSYSTEM.508]
4775 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */
4776 WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */
4777 UINT16 uSize) /* [in] */
4781 TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4783 if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4784 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4785 return MMSYSERR_INVALHANDLE;
4787 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4790 /**************************************************************************
4791 * waveInReset [WINMM.@]
4793 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4797 TRACE("(%04X);\n", hWaveIn);
4799 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4800 return MMSYSERR_INVALHANDLE;
4802 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
4805 /**************************************************************************
4806 * waveInReset [MMSYSTEM.511]
4808 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16)
4813 ReleaseThunkLock(&level);
4814 ret = waveInReset(HWAVEIN_32(hWaveIn16));
4815 RestoreThunkLock(level);
4819 /**************************************************************************
4820 * waveInStart [WINMM.@]
4822 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4826 TRACE("(%04X);\n", hWaveIn);
4828 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4829 return MMSYSERR_INVALHANDLE;
4831 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
4834 /**************************************************************************
4835 * waveInStart [MMSYSTEM.509]
4837 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16)
4842 ReleaseThunkLock(&level);
4843 ret = waveInStart(HWAVEIN_32(hWaveIn16));
4844 RestoreThunkLock(level);
4848 /**************************************************************************
4849 * waveInStop [WINMM.@]
4851 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4855 TRACE("(%04X);\n", hWaveIn);
4857 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4858 return MMSYSERR_INVALHANDLE;
4860 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
4863 /**************************************************************************
4864 * waveInStop [MMSYSTEM.510]
4866 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16)
4871 ReleaseThunkLock(&level);
4872 ret = waveInStop(HWAVEIN_32(hWaveIn16));
4873 RestoreThunkLock(level);
4877 /**************************************************************************
4878 * waveInGetPosition [WINMM.@]
4880 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4885 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4887 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4888 return MMSYSERR_INVALHANDLE;
4890 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4893 /**************************************************************************
4894 * waveInGetPosition [MMSYSTEM.512]
4896 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4902 mmt.wType = lpTime->wType;
4903 ret = waveInGetPosition(HWAVEIN_32(hWaveIn), &mmt, sizeof(mmt));
4904 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4908 /**************************************************************************
4909 * waveInGetID [WINMM.@]
4911 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4915 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4917 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4919 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4920 return MMSYSERR_INVALHANDLE;
4922 *lpuDeviceID = wmld->uDeviceID;
4923 return MMSYSERR_NOERROR;
4926 /**************************************************************************
4927 * waveInGetID [MMSYSTEM.513]
4929 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4933 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4935 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4937 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4938 return MMSYSERR_INVALHANDLE;
4940 *lpuDeviceID = wmld->uDeviceID;
4941 return MMSYSERR_NOERROR;
4944 /**************************************************************************
4945 * waveInMessage [WINMM.@]
4947 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4948 DWORD dwParam1, DWORD dwParam2)
4952 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4955 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4956 return MMSYSERR_INVALPARAM;
4958 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4959 return MMSYSERR_INVALHANDLE;
4961 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4964 /**************************************************************************
4965 * waveInMessage [MMSYSTEM.514]
4967 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4968 DWORD dwParam1, DWORD dwParam2)
4972 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4975 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4976 return MMSYSERR_INVALPARAM;
4978 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4979 return MMSYSERR_INVALHANDLE;
4981 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4984 /*#define USE_MM_TSK_WINE*/
4986 /**************************************************************************
4987 * mmTaskCreate [MMSYSTEM.900]
4989 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4990 * called upon creation with dwPmt as parameter.
4992 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4997 DWORD showCmd = 0x40002;
5000 TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
5001 /* This to work requires NE modules to be started with a binary command line
5002 * which is not currently the case. A patch exists but has never been committed.
5003 * A workaround would be to integrate code for mmtask.tsk into Wine, but
5004 * this requires tremendous work (starting with patching tools/build to
5005 * create NE executables (and not only DLLs) for builtins modules.
5008 FIXME("This is currently broken. It will fail\n");
5011 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
5012 *(LPDWORD)(cmdline + 5) = dwPmt;
5013 *(LPDWORD)(cmdline + 9) = 0;
5015 lp.hEnvironment = 0;
5016 lp.cmdLine = MapLS(cmdline);
5017 lp.showCmd = MapLS(&showCmd);
5020 #ifndef USE_MM_TSK_WINE
5021 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp);
5023 handle = LoadModule16("mmtask.tsk", &lp);
5026 ret = (handle) ? 1 : 2;
5032 *lphMmTask = handle;
5034 UnMapLS( lp.cmdLine );
5035 UnMapLS( lp.showCmd );
5036 TRACE("=> 0x%04x/%d\n", handle, ret);
5040 #ifdef USE_MM_TSK_WINE
5041 /* C equivalent to mmtask.tsk binary content */
5042 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
5044 int len = cmdLine[0x80];
5047 void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1)));
5048 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
5051 InitTask16(); /* FIXME: pmts / from context ? */
5054 if (SetMessageQueue16(0x40)) {
5056 if (HIWORD(fpProc)) {
5058 /* EPP StackEnter16(); */
5070 /**************************************************************************
5071 * mmTaskBlock [MMSYSTEM.902]
5073 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
5078 GetMessageA(&msg, 0, 0, 0);
5080 TranslateMessage(&msg);
5081 DispatchMessageA(&msg);
5083 } while (msg.message < 0x3A0);
5086 /**************************************************************************
5087 * mmTaskSignal [MMSYSTEM.903]
5089 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
5091 TRACE("(%04x);\n", ht);
5092 return PostAppMessage16(ht, WM_USER, 0, 0);
5095 /**************************************************************************
5096 * mmGetCurrentTask [MMSYSTEM.904]
5098 HTASK16 WINAPI mmGetCurrentTask16(void)
5100 return GetCurrentTask();
5103 /**************************************************************************
5104 * mmTaskYield [MMSYSTEM.905]
5106 void WINAPI mmTaskYield16(void)
5110 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
5115 DWORD WINAPI GetProcessFlags(DWORD);
5117 /**************************************************************************
5118 * mmThreadCreate [MMSYSTEM.1120]
5121 * Creates a MM thread, calling fpThreadAddr(dwPmt).
5123 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
5124 * bit.1 set means to open a VxD for this thread (unsupported)
5126 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
5131 TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
5133 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
5138 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5141 /* force mmtask routines even if mmthread is required */
5142 /* this will work only if the patch about binary cmd line and NE tasks
5148 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
5149 lpMMThd->dwCounter = 0;
5150 lpMMThd->hThread = 0;
5151 lpMMThd->dwThreadID = 0;
5152 lpMMThd->fpThread = fpThreadAddr;
5153 lpMMThd->dwThreadPmt = dwPmt;
5154 lpMMThd->dwSignalCount = 0;
5155 lpMMThd->hEvent = 0;
5157 lpMMThd->dwStatus = 0;
5158 lpMMThd->dwFlags = dwFlags;
5161 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
5162 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
5164 TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
5165 if (lpMMThd->dwFlags & 2) {
5166 /* as long as we don't support MM VxD in wine, we don't need
5167 * to care about this flag
5169 /* FIXME("Don't know how to properly open VxD handles\n"); */
5170 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
5173 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
5174 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
5175 if (lpMMThd->hThread == 0) {
5176 WARN("Couldn't create thread\n");
5177 /* clean-up(VxDhandle...); devicedirectio... */
5178 if (lpMMThd->hEvent != 0)
5179 CloseHandle(lpMMThd->hEvent);
5182 TRACE("Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
5186 /* get WINE_mmThreadEntryPoint()
5187 * 2047 is its ordinal in mmsystem.spec
5189 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047);
5191 TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp));
5193 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
5197 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
5198 WARN("Couldn't resume thread\n");
5200 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
5214 TRACE("ok => %ld\n", ret);
5218 /**************************************************************************
5219 * mmThreadSignal [MMSYSTEM.1121]
5221 void WINAPI mmThreadSignal16(HANDLE16 hndl)
5223 TRACE("(%04x)!\n", hndl);
5226 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5228 lpMMThd->dwCounter++;
5229 if (lpMMThd->hThread != 0) {
5230 InterlockedIncrement(&lpMMThd->dwSignalCount);
5231 SetEvent(lpMMThd->hEvent);
5233 mmTaskSignal16(lpMMThd->hTask);
5235 lpMMThd->dwCounter--;
5239 /**************************************************************************
5240 * MMSYSTEM_ThreadBlock [internal]
5242 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
5247 if (lpMMThd->dwThreadID != GetCurrentThreadId())
5248 ERR("Not called by thread itself\n");
5251 ResetEvent(lpMMThd->hEvent);
5252 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
5254 InterlockedIncrement(&lpMMThd->dwSignalCount);
5258 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
5260 case WAIT_OBJECT_0: /* Event */
5263 case WAIT_OBJECT_0 + 1: /* Msg */
5265 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
5266 TranslateMessage(&msg);
5267 DispatchMessageA(&msg);
5271 WARN("S2.x unsupported ret val 0x%08lx\n", ret);
5277 /**************************************************************************
5278 * mmThreadBlock [MMSYSTEM.1122]
5280 void WINAPI mmThreadBlock16(HANDLE16 hndl)
5282 TRACE("(%04x)!\n", hndl);
5285 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5287 if (lpMMThd->hThread != 0) {
5290 ReleaseThunkLock(&lc);
5291 MMSYSTEM_ThreadBlock(lpMMThd);
5292 RestoreThunkLock(lc);
5294 mmTaskBlock16(lpMMThd->hTask);
5300 /**************************************************************************
5301 * mmThreadIsCurrent [MMSYSTEM.1123]
5303 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
5307 TRACE("(%04x)!\n", hndl);
5309 if (hndl && mmThreadIsValid16(hndl)) {
5310 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5311 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
5313 TRACE("=> %d\n", ret);
5317 /**************************************************************************
5318 * mmThreadIsValid [MMSYSTEM.1124]
5320 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
5324 TRACE("(%04x)!\n", hndl);
5327 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5329 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
5330 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
5331 IsTask16(lpMMThd->hTask)) {
5332 lpMMThd->dwCounter++;
5333 if (lpMMThd->hThread != 0) {
5335 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
5336 dwThreadRet == STATUS_PENDING) {
5342 lpMMThd->dwCounter--;
5345 TRACE("=> %d\n", ret);
5349 /**************************************************************************
5350 * mmThreadGetTask [MMSYSTEM.1125]
5352 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5356 TRACE("(%04x)\n", hndl);
5358 if (mmThreadIsValid16(hndl)) {
5359 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5360 ret = lpMMThd->hTask;
5365 /* ### start build ### */
5366 extern LONG CALLBACK MMSYSTEM_CallTo16_long_l (FARPROC16,LONG);
5367 /* ### stop build ### */
5369 /**************************************************************************
5370 * __wine_mmThreadEntryPoint (MMSYSTEM.2047)
5372 void WINAPI WINE_mmThreadEntryPoint(DWORD _pmt)
5374 HANDLE16 hndl = (HANDLE16)_pmt;
5375 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5377 TRACE("(%04x %p)\n", hndl, lpMMThd);
5379 lpMMThd->hTask = LOWORD(GetCurrentTask());
5380 TRACE("[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5381 lpMMThd->dwStatus = 0x10;
5382 MMSYSTEM_ThreadBlock(lpMMThd);
5383 TRACE("[20-%08x]\n", lpMMThd->hThread);
5384 lpMMThd->dwStatus = 0x20;
5385 if (lpMMThd->fpThread) {
5386 MMSYSTEM_CallTo16_long_l(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5388 lpMMThd->dwStatus = 0x30;
5389 TRACE("[30-%08x]\n", lpMMThd->hThread);
5390 while (lpMMThd->dwCounter) {
5392 /* K32WOWYield16();*/
5394 TRACE("[XX-%08x]\n", lpMMThd->hThread);
5396 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5397 /* close lpMMThread->hVxD directIO */
5398 if (lpMMThd->hEvent)
5399 CloseHandle(lpMMThd->hEvent);
5404 typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR);
5406 /**************************************************************************
5407 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5409 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice,
5410 LPCSTR lpStrTab, LPCSTR lpStrTitle)
5415 TRACE("(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5417 hndl = LoadLibraryA("MMSYS.CPL");
5419 MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5422 ReleaseThunkLock(&lc);
5423 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5424 RestoreThunkLock(lc);
5432 /**************************************************************************
5433 * StackEnter [MMSYSTEM.32]
5435 void WINAPI StackEnter16(void)
5438 /* mmsystem.dll from Win 95 does only this: so does Wine */
5443 /**************************************************************************
5444 * StackLeave [MMSYSTEM.33]
5446 void WINAPI StackLeave16(void)
5449 /* mmsystem.dll from Win 95 does only this: so does Wine */
5454 /**************************************************************************
5455 * WMMMidiRunOnce [MMSYSTEM.8]
5457 void WINAPI WMMMidiRunOnce16(void)
5459 FIXME("(), stub!\n");
5462 /**************************************************************************
5463 * OutputDebugStr [MMSYSTEM.30]
5465 void WINAPI OutputDebugStr16(
5466 LPCSTR str) /* [in] The message to be logged and given to the debugger. */
5468 OutputDebugStringA( str );