Some other synchronisation issues.
[wine.git] / dlls / winmm / mmsystem.c
blob6e54f29781c3c110824e63fbd4c8e4c7bd0c5ceb
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MMSYTEM functions
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
23 /*
24 * Eric POUECH :
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
35 #include <string.h>
37 #include "mmsystem.h"
38 #include "winbase.h"
39 #include "wingdi.h"
41 #include "wine/mmsystem16.h"
42 #include "wine/winuser16.h"
43 #include "heap.h"
44 #include "ntddk.h"
45 #include "winemm.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)
60 break;
62 return iData;
65 /**************************************************************************
66 * MULTIMEDIA_GetIData [internal]
68 LPWINE_MM_IDATA MULTIMEDIA_GetIData(void)
70 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
72 if (!iData) {
73 ERR("IData not found for pid=%08lx. Suicide !!!\n", GetCurrentProcessId());
74 DbgBreakPoint();
75 ExitProcess(0);
77 return iData;
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));
89 if (!iData)
90 return FALSE;
91 iData->hWinMM32Instance = hInstDLL;
92 iData->dwThisProcess = GetCurrentProcessId();
93 iData->lpNextIData = lpFirstIData;
94 lpFirstIData = iData;
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);
100 return TRUE;
103 /**************************************************************************
104 * MULTIMEDIA_DeleteIData [internal]
106 static void MULTIMEDIA_DeleteIData(void)
108 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
109 LPWINE_MM_IDATA* ppid;
111 if (iData) {
112 TIME_MMTimeStop();
114 for (ppid = &lpFirstIData; *ppid; ppid = &(*ppid)->lpNextIData) {
115 if (*ppid == iData) {
116 *ppid = iData->lpNextIData;
117 break;
120 /* FIXME: should also free content and resources allocated
121 * inside iData */
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);
139 switch (fdwReason) {
140 case DLL_PROCESS_ATTACH:
141 if (!MULTIMEDIA_CreateIData(hInstDLL))
142 return FALSE;
143 if (!MULTIMEDIA_MciInit() || !MMDRV_Init()) {
144 MULTIMEDIA_DeleteIData();
145 return FALSE;
147 break;
148 case DLL_PROCESS_DETACH:
149 MULTIMEDIA_DeleteIData();
150 break;
151 case DLL_THREAD_ATTACH:
152 case DLL_THREAD_DETACH:
153 break;
155 return TRUE;
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)
167 HANDLE hndl;
168 LPWINE_MM_IDATA iData;
170 TRACE("0x%x 0x%lx\n", hinstDLL, fdwReason);
172 switch (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");
180 if (!hndl) {
181 ERR("Could not load sibling WinMM.dll\n");
182 return FALSE;
184 iData = MULTIMEDIA_GetIData();
185 iData->hWinMM16Instance = hinstDLL;
186 iData->h16Module32 = hndl;
187 break;
188 case DLL_PROCESS_DETACH:
189 iData = MULTIMEDIA_GetIData();
190 FreeLibrary(iData->h16Module32);
191 break;
192 case DLL_THREAD_ATTACH:
193 case DLL_THREAD_DETACH:
194 break;
196 return TRUE;
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);
206 return TRUE;
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)
229 HMMIO ret;
230 WCHAR buf[256];
231 LPWSTR dummy;
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);
241 return 0;
244 static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName)
246 WCHAR str[128];
247 LPWSTR ptr;
248 HMMIO hmmio;
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','\\',
256 'A','p','p','s',0};
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++);
269 if (*ptr) *ptr = 0;
270 hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
271 if (hmmio != 0) return hmmio;
272 next:
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)
280 err = 1; /* error */
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;
286 if (*ptr == '\\')
288 err = RegOpenKeyW(hRegSnd, str, &hRegApp);
289 break;
294 else
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);
308 RegCloseKey(hSnd);
309 if (err != 0 || !*str) goto none;
310 hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
311 if (hmmio) return hmmio;
312 none:
313 WARN("can't find SystemSound='%s' !\n", debugstr_w(lpszName));
314 return 0;
317 struct playsound_data
319 HANDLE hEvent;
320 DWORD dwEventCount;
323 static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg,
324 DWORD dwInstance,
325 DWORD dwParam1, DWORD dwParam2)
327 struct playsound_data* s = (struct playsound_data*)dwInstance;
329 switch (uMsg) {
330 case WOM_OPEN:
331 case WOM_CLOSE:
332 break;
333 case WOM_DONE:
334 InterlockedIncrement(&s->dwEventCount);
335 TRACE("Returning waveHdr=%lx\n", dwParam1);
336 SetEvent(s->hEvent);
337 break;
338 default:
339 ERR("Unknown uMsg=%d\n", uMsg);
343 static void PlaySound_WaitDone(struct playsound_data* s)
345 for (;;) {
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 ??? */
364 case SND_FILENAME:
365 case 0: return TRUE;
366 default: FIXME("WTF\n"); return FALSE;
370 static void PlaySound_Free(WINE_PLAYSOUND* wps)
372 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
373 WINE_PLAYSOUND** p;
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)
387 WINE_PLAYSOUND* wps;
389 wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps));
390 if (!wps) return NULL;
392 wps->hMod = hmod;
393 wps->fdwSound = fdwSound;
394 if (PlaySound_IsString(fdwSound, pszSound))
396 if (bUnicode)
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);
404 wps->bAlloc = TRUE;
406 else
407 wps->pszSound = pszSound;
409 else
411 wps->pszSound = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSound);
412 if (!wps->pszSound) goto oom_error;
413 wps->bAlloc = TRUE;
416 else
417 wps->pszSound = pszSound;
419 return wps;
420 oom_error:
421 PlaySound_Free(wps);
422 return NULL;
425 static DWORD WINAPI proc_PlaySound(LPVOID arg)
427 WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg;
428 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
429 BOOL bRet = FALSE;
430 HMMIO hmmio = 0;
431 MMCKINFO ckMainRIFF;
432 MMCKINFO mmckInfo;
433 LPWAVEFORMATEX lpWaveFormat = NULL;
434 HWAVE hWave = 0;
435 LPWAVEHDR waveHdr = NULL;
436 INT count, bufsize, left, index;
437 struct playsound_data s;
438 void* data;
440 s.hEvent = 0;
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};
447 HRSRC hRes;
448 HGLOBAL hGlob;
450 if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 ||
451 (hGlob = LoadResource(wps->hMod, hRes)) == 0)
452 goto errCleanUp;
453 if ((data = LockResource(hGlob)) == NULL) {
454 FreeResource(hGlob);
455 goto errCleanUp;
457 FreeResource(hGlob);
458 } else
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 */
464 MMIOINFO mminfo;
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);
481 else
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))
494 goto errCleanUp;
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')))
501 goto errCleanUp;
503 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
504 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
505 goto errCleanUp;
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))
512 goto errCleanUp;
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))
526 goto errCleanUp;
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)
535 goto errCleanUp;
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))) {
549 goto errCleanUp;
552 do {
553 index = 0;
554 left = mmckInfo.cksize;
555 s.dwEventCount = 1L; /* for first buffer */
557 mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
558 while (left)
560 if (WaitForSingleObject(iData->psStopEvent, 0) == WAIT_OBJECT_0)
562 wps->bLoop = FALSE;
563 break;
565 count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
566 if (count < 1) break;
567 left -= count;
568 waveHdr[index].dwBufferLength = count;
569 waveHdr[index].dwFlags &= ~WHDR_DONE;
570 if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) {
571 index ^= 1;
572 PlaySound_WaitDone(&s);
574 else FIXME("Couldn't play header\n");
576 bRet = TRUE;
577 } while (wps->bLoop);
579 PlaySound_WaitDone(&s); /* for last buffer */
580 waveOutReset(hWave);
582 waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
583 waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
585 errCleanUp:
586 TRACE("Done playing='%s' => %s!\n", debugstr_w(wps->pszSound), bRet ? "ok" : "ko");
587 CloseHandle(s.hEvent);
588 if (waveHdr) HeapFree(GetProcessHeap(), 0, waveHdr);
589 if (lpWaveFormat) HeapFree(GetProcessHeap(), 0, lpWaveFormat);
590 if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
591 if (hmmio) mmioClose(hmmio, 0);
593 PlaySound_Free(wps);
595 return bRet;
598 static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode)
600 WINE_PLAYSOUND* wps = NULL;
601 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
603 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
604 pszSound, hmod, fdwSound);
606 /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP !
607 * there could be one if several sounds can be played at once...
609 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound != NULL)
610 return FALSE;
612 /* alloc internal structure, if we need to play something */
613 if (pszSound && !(fdwSound & SND_PURGE))
615 if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode)))
616 return FALSE;
619 EnterCriticalSection(&iData->cs);
620 /* since several threads can enter PlaySound in parallel, we're not
621 * sure, at this point, that another thread didn't start a new playsound
623 while (iData->lpPlaySound != NULL)
625 ResetEvent(iData->psLastEvent);
626 /* FIXME: doc says we have to stop all instances of pszSound if it's non
627 * NULL... as of today, we stop all playing instances */
628 SetEvent(iData->psStopEvent);
630 LeaveCriticalSection(&iData->cs);
631 WaitForSingleObject(iData->psLastEvent, INFINITE);
632 EnterCriticalSection(&iData->cs);
634 ResetEvent(iData->psStopEvent);
637 wps->lpNext = iData->lpPlaySound;
638 iData->lpPlaySound = wps;
639 LeaveCriticalSection(&iData->cs);
641 if (!pszSound || (fdwSound & SND_PURGE)) return TRUE;
643 if (fdwSound & SND_ASYNC)
645 DWORD id;
646 wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE;
647 if (CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id) != 0)
648 return TRUE;
650 else return proc_PlaySound(wps);
652 /* error cases */
653 PlaySound_Free(wps);
654 return FALSE;
657 /**************************************************************************
658 * PlaySoundA [WINMM.@]
660 BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound)
662 return MULTIMEDIA_PlaySound(pszSoundA, hmod, fdwSound, FALSE);
665 /**************************************************************************
666 * PlaySoundW [WINMM.@]
668 BOOL WINAPI PlaySoundW(LPCWSTR pszSoundW, HMODULE hmod, DWORD fdwSound)
670 return MULTIMEDIA_PlaySound(pszSoundW, hmod, fdwSound, TRUE);
673 /**************************************************************************
674 * PlaySound [MMSYSTEM.3]
676 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
678 BOOL16 retv;
679 DWORD lc;
681 ReleaseThunkLock(&lc);
682 retv = PlaySoundA(pszSound, hmod, fdwSound);
683 RestoreThunkLock(lc);
685 return retv;
688 /**************************************************************************
689 * sndPlaySoundA [WINMM.@]
691 BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags)
693 uFlags &= ~(SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC);
694 return MULTIMEDIA_PlaySound(pszSoundA, 0, uFlags, FALSE);
697 /**************************************************************************
698 * sndPlaySoundW [WINMM.@]
700 BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags)
702 uFlags &= ~(SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC);
703 return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, TRUE);
706 /**************************************************************************
707 * sndPlaySound [MMSYSTEM.2]
709 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
711 BOOL16 retv;
712 DWORD lc;
714 ReleaseThunkLock(&lc);
715 retv = sndPlaySoundA(lpszSoundName, uFlags);
716 RestoreThunkLock(lc);
718 return retv;
721 /**************************************************************************
722 * mmsystemGetVersion [MMSYSTEM.5]
723 * return value borrowed from Win95 winmm.dll ;)
725 UINT16 WINAPI mmsystemGetVersion16(void)
727 return mmsystemGetVersion();
730 /**************************************************************************
731 * mmsystemGetVersion [WINMM.@]
733 UINT WINAPI mmsystemGetVersion(void)
735 TRACE("3.10 (Win95?)\n");
736 return 0x030a;
739 /**************************************************************************
740 * DriverCallback [WINMM.@]
742 BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
743 UINT wMsg, DWORD dwUser, DWORD dwParam1,
744 DWORD dwParam2)
746 TRACE("(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
747 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
749 switch (uFlags & DCB_TYPEMASK) {
750 case DCB_NULL:
751 TRACE("Null !\n");
752 if (dwCallBack)
753 WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack);
754 break;
755 case DCB_WINDOW:
756 TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
757 PostMessageA((HWND)dwCallBack, wMsg, hDev, dwParam1);
758 break;
759 case DCB_TASK: /* aka DCB_THREAD */
760 TRACE("Task(%04lx) !\n", dwCallBack);
761 PostThreadMessageA(dwCallBack, wMsg, hDev, dwParam1);
762 break;
763 case DCB_FUNCTION:
764 TRACE("Function (32 bit) !\n");
765 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
766 break;
767 case DCB_EVENT:
768 TRACE("Event(%08lx) !\n", dwCallBack);
769 SetEvent((HANDLE)dwCallBack);
770 break;
771 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
772 /* this is an undocumented DCB_ value used for mmThreads
773 * loword of dwCallBack contains the handle of the lpMMThd block
774 * which dwSignalCount has to be incremented
777 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(LOWORD(dwCallBack), 0) );
779 TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
780 /* same as mmThreadSignal16 */
781 InterlockedIncrement(&lpMMThd->dwSignalCount);
782 SetEvent(lpMMThd->hEvent);
783 /* some other stuff on lpMMThd->hVxD */
785 break;
786 #if 0
787 case 4:
788 /* this is an undocumented DCB_ value for... I don't know */
789 break;
790 #endif
791 default:
792 WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
793 return FALSE;
795 TRACE("Done\n");
796 return TRUE;
799 /**************************************************************************
800 * DriverCallback [MMSYSTEM.31]
802 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev,
803 WORD wMsg, DWORD dwUser, DWORD dwParam1,
804 DWORD dwParam2)
806 return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
809 /**************************************************************************
810 * Mixer devices. New to Win95
813 /**************************************************************************
814 * find out the real mixer ID depending on hmix (depends on dwFlags)
816 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
818 LPWINE_MIXER lpwm = NULL;
820 switch (dwFlags & 0xF0000000ul) {
821 case MIXER_OBJECTF_MIXER:
822 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
823 break;
824 case MIXER_OBJECTF_HMIXER:
825 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
826 break;
827 case MIXER_OBJECTF_WAVEOUT:
828 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
829 break;
830 case MIXER_OBJECTF_HWAVEOUT:
831 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
832 break;
833 case MIXER_OBJECTF_WAVEIN:
834 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
835 break;
836 case MIXER_OBJECTF_HWAVEIN:
837 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
838 break;
839 case MIXER_OBJECTF_MIDIOUT:
840 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
841 break;
842 case MIXER_OBJECTF_HMIDIOUT:
843 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
844 break;
845 case MIXER_OBJECTF_MIDIIN:
846 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
847 break;
848 case MIXER_OBJECTF_HMIDIIN:
849 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
850 break;
851 case MIXER_OBJECTF_AUX:
852 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
853 break;
854 default:
855 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
856 break;
858 return lpwm;
861 /**************************************************************************
862 * mixerGetNumDevs [WINMM.@]
864 UINT WINAPI mixerGetNumDevs(void)
866 return MMDRV_GetNum(MMDRV_MIXER);
869 /**************************************************************************
870 * mixerGetNumDevs [MMSYSTEM.800]
872 UINT16 WINAPI mixerGetNumDevs16(void)
874 return MMDRV_GetNum(MMDRV_MIXER);
877 /**************************************************************************
878 * mixerGetDevCapsA [WINMM.@]
880 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
882 LPWINE_MLD wmld;
884 if ((wmld = MMDRV_Get(devid, MMDRV_MIXER, TRUE)) == NULL)
885 return MMSYSERR_BADDEVICEID;
887 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
890 /**************************************************************************
891 * mixerGetDevCapsW [WINMM.@]
893 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
895 MIXERCAPSA micA;
896 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
898 if (ret == MMSYSERR_NOERROR) {
899 mixcaps->wMid = micA.wMid;
900 mixcaps->wPid = micA.wPid;
901 mixcaps->vDriverVersion = micA.vDriverVersion;
902 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
903 sizeof(mixcaps->szPname)/sizeof(WCHAR) );
904 mixcaps->fdwSupport = micA.fdwSupport;
905 mixcaps->cDestinations = micA.cDestinations;
907 return ret;
910 /**************************************************************************
911 * mixerGetDevCaps [MMSYSTEM.801]
913 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps,
914 UINT16 size)
916 MIXERCAPSA micA;
917 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
919 if (ret == MMSYSERR_NOERROR) {
920 mixcaps->wMid = micA.wMid;
921 mixcaps->wPid = micA.wPid;
922 mixcaps->vDriverVersion = micA.vDriverVersion;
923 strcpy(mixcaps->szPname, micA.szPname);
924 mixcaps->fdwSupport = micA.fdwSupport;
925 mixcaps->cDestinations = micA.cDestinations;
927 return ret;
930 static UINT MMSYSTEM_mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
931 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
933 HMIXER hMix;
934 LPWINE_MLD wmld;
935 DWORD dwRet = 0;
936 MIXEROPENDESC mod;
938 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
939 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
941 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
942 &dwCallback, &dwInstance, bFrom32);
944 wmld->uDeviceID = uDeviceID;
945 mod.hmx = hMix;
946 mod.dwCallback = dwCallback;
947 mod.dwInstance = dwInstance;
949 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
951 if (dwRet != MMSYSERR_NOERROR) {
952 MMDRV_Free(hMix, wmld);
953 hMix = 0;
955 if (lphMix) *lphMix = hMix;
956 TRACE("=> %ld hMixer=%04x\n", dwRet, hMix);
958 return dwRet;
961 /**************************************************************************
962 * mixerOpen [WINMM.@]
964 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
965 DWORD dwInstance, DWORD fdwOpen)
967 return MMSYSTEM_mixerOpen(lphMix, uDeviceID,
968 dwCallback, dwInstance, fdwOpen, TRUE);
971 /**************************************************************************
972 * mixerOpen [MMSYSTEM.802]
974 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
975 DWORD dwInstance, DWORD fdwOpen)
977 HMIXER hmix;
978 UINT ret;
980 ret = MMSYSTEM_mixerOpen(&hmix, uDeviceID,
981 dwCallback, dwInstance, fdwOpen, FALSE);
982 if (lphmix) *lphmix = hmix;
983 return ret;
986 /**************************************************************************
987 * mixerClose [WINMM.@]
989 UINT WINAPI mixerClose(HMIXER hMix)
991 LPWINE_MLD wmld;
992 DWORD dwRet;
994 TRACE("(%04x)\n", hMix);
996 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
998 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
999 MMDRV_Free(hMix, wmld);
1001 return dwRet;
1004 /**************************************************************************
1005 * mixerClose [MMSYSTEM.803]
1007 UINT16 WINAPI mixerClose16(HMIXER16 hMix)
1009 return mixerClose(hMix);
1012 /**************************************************************************
1013 * mixerGetID [WINMM.@]
1015 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
1017 LPWINE_MIXER lpwm;
1019 TRACE("(%04x %p %08lx)\n", hmix, lpid, fdwID);
1021 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
1022 return MMSYSERR_INVALHANDLE;
1025 if (lpid)
1026 *lpid = lpwm->mld.uDeviceID;
1028 return MMSYSERR_NOERROR;
1031 /**************************************************************************
1032 * mixerGetID (MMSYSTEM.806)
1034 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
1036 UINT xid;
1037 UINT ret = mixerGetID(hmix, &xid, fdwID);
1039 if (lpid)
1040 *lpid = xid;
1041 return ret;
1044 /**************************************************************************
1045 * mixerGetControlDetailsA [WINMM.@]
1047 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1048 DWORD fdwDetails)
1050 LPWINE_MIXER lpwm;
1052 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1054 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1055 return MMSYSERR_INVALHANDLE;
1057 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
1058 return MMSYSERR_INVALPARAM;
1060 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
1061 fdwDetails, TRUE);
1064 /**************************************************************************
1065 * mixerGetControlDetailsW [WINMM.@]
1067 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
1069 DWORD ret = MMSYSERR_NOTENABLED;
1071 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1073 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1074 return MMSYSERR_INVALPARAM;
1076 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
1077 case MIXER_GETCONTROLDETAILSF_VALUE:
1078 /* can savely use W structure as it is, no string inside */
1079 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
1080 break;
1081 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
1083 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
1084 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
1085 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1086 int i;
1088 if (lpmcd->u.cMultipleItems != 0) {
1089 size *= lpmcd->u.cMultipleItems;
1091 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
1092 lpmcd->paDetails = pDetailsA;
1093 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1094 /* set up lpmcd->paDetails */
1095 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
1096 /* copy from lpmcd->paDetails back to paDetailsW; */
1097 if(ret == MMSYSERR_NOERROR) {
1098 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
1099 pDetailsW->dwParam1 = pDetailsA->dwParam1;
1100 pDetailsW->dwParam2 = pDetailsA->dwParam2;
1101 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
1102 pDetailsW->szName,
1103 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
1104 pDetailsA++;
1105 pDetailsW++;
1107 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
1108 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
1110 HeapFree(GetProcessHeap(), 0, pDetailsA);
1111 lpmcd->paDetails = pDetailsW;
1112 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
1114 break;
1115 default:
1116 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
1119 return ret;
1122 /**************************************************************************
1123 * mixerGetControlDetails [MMSYSTEM.808]
1125 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix,
1126 LPMIXERCONTROLDETAILS16 lpmcd,
1127 DWORD fdwDetails)
1129 DWORD ret = MMSYSERR_NOTENABLED;
1130 SEGPTR sppaDetails;
1132 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1134 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1135 return MMSYSERR_INVALPARAM;
1137 sppaDetails = (SEGPTR)lpmcd->paDetails;
1138 lpmcd->paDetails = MapSL(sppaDetails);
1139 ret = mixerGetControlDetailsA(hmix, (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails);
1140 lpmcd->paDetails = (LPVOID)sppaDetails;
1142 return ret;
1145 /**************************************************************************
1146 * mixerGetLineControlsA [WINMM.@]
1148 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
1149 DWORD fdwControls)
1151 LPWINE_MIXER lpwm;
1153 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
1155 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
1156 return MMSYSERR_INVALHANDLE;
1158 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
1159 return MMSYSERR_INVALPARAM;
1161 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
1162 fdwControls, TRUE);
1165 /**************************************************************************
1166 * mixerGetLineControlsW [WINMM.@]
1168 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
1169 DWORD fdwControls)
1171 MIXERLINECONTROLSA mlcA;
1172 DWORD ret;
1173 int i;
1175 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
1177 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
1178 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
1179 return MMSYSERR_INVALPARAM;
1181 mlcA.cbStruct = sizeof(mlcA);
1182 mlcA.dwLineID = lpmlcW->dwLineID;
1183 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
1184 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
1185 mlcA.cControls = lpmlcW->cControls;
1186 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1187 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1188 mlcA.cControls * mlcA.cbmxctrl);
1190 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
1192 if (ret == MMSYSERR_NOERROR) {
1193 lpmlcW->dwLineID = mlcA.dwLineID;
1194 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
1195 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
1196 lpmlcW->cControls = mlcA.cControls;
1198 for (i = 0; i < mlcA.cControls; i++) {
1199 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
1200 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1201 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1202 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1203 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1204 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
1205 lpmlcW->pamxctrl[i].szShortName,
1206 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
1207 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
1208 lpmlcW->pamxctrl[i].szName,
1209 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
1210 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
1211 * sizeof(mlcA.pamxctrl[i].Bounds) */
1212 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1213 sizeof(mlcA.pamxctrl[i].Bounds));
1214 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
1215 * sizeof(mlcA.pamxctrl[i].Metrics) */
1216 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1217 sizeof(mlcA.pamxctrl[i].Metrics));
1221 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1223 return ret;
1226 /**************************************************************************
1227 * mixerGetLineControls [MMSYSTEM.807]
1229 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix,
1230 LPMIXERLINECONTROLS16 lpmlc16,
1231 DWORD fdwControls)
1233 MIXERLINECONTROLSA mlcA;
1234 DWORD ret;
1235 int i;
1236 LPMIXERCONTROL16 lpmc16;
1238 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls);
1240 if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) ||
1241 lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16))
1242 return MMSYSERR_INVALPARAM;
1244 mlcA.cbStruct = sizeof(mlcA);
1245 mlcA.dwLineID = lpmlc16->dwLineID;
1246 mlcA.u.dwControlID = lpmlc16->u.dwControlID;
1247 mlcA.u.dwControlType = lpmlc16->u.dwControlType;
1248 mlcA.cControls = lpmlc16->cControls;
1249 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1250 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1251 mlcA.cControls * mlcA.cbmxctrl);
1253 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
1255 if (ret == MMSYSERR_NOERROR) {
1256 lpmlc16->dwLineID = mlcA.dwLineID;
1257 lpmlc16->u.dwControlID = mlcA.u.dwControlID;
1258 lpmlc16->u.dwControlType = mlcA.u.dwControlType;
1259 lpmlc16->cControls = mlcA.cControls;
1261 lpmc16 = MapSL(lpmlc16->pamxctrl);
1263 for (i = 0; i < mlcA.cControls; i++) {
1264 lpmc16[i].cbStruct = sizeof(MIXERCONTROL16);
1265 lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1266 lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1267 lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1268 lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1269 strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName);
1270 strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName);
1271 /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
1272 memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1273 sizeof(mlcA.pamxctrl[i].Bounds));
1274 /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
1275 memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1276 sizeof(mlcA.pamxctrl[i].Metrics));
1280 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1282 return ret;
1285 /**************************************************************************
1286 * mixerGetLineInfoA [WINMM.@]
1288 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
1290 LPWINE_MIXER lpwm;
1292 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1294 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
1295 return MMSYSERR_INVALHANDLE;
1297 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
1298 fdwInfo, TRUE);
1301 /**************************************************************************
1302 * mixerGetLineInfoW [WINMM.@]
1304 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
1305 DWORD fdwInfo)
1307 MIXERLINEA mliA;
1308 UINT ret;
1310 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1312 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
1313 return MMSYSERR_INVALPARAM;
1315 mliA.cbStruct = sizeof(mliA);
1316 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1317 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1318 mliA.dwComponentType = lpmliW->dwComponentType;
1319 break;
1320 case MIXER_GETLINEINFOF_DESTINATION:
1321 mliA.dwDestination = lpmliW->dwDestination;
1322 break;
1323 case MIXER_GETLINEINFOF_LINEID:
1324 mliA.dwLineID = lpmliW->dwLineID;
1325 break;
1326 case MIXER_GETLINEINFOF_SOURCE:
1327 mliA.dwDestination = lpmliW->dwDestination;
1328 mliA.dwSource = lpmliW->dwSource;
1329 break;
1330 case MIXER_GETLINEINFOF_TARGETTYPE:
1331 mliA.Target.dwType = lpmliW->Target.dwType;
1332 mliA.Target.wMid = lpmliW->Target.wMid;
1333 mliA.Target.wPid = lpmliW->Target.wPid;
1334 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
1335 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
1336 break;
1337 default:
1338 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1341 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1343 lpmliW->dwDestination = mliA.dwDestination;
1344 lpmliW->dwSource = mliA.dwSource;
1345 lpmliW->dwLineID = mliA.dwLineID;
1346 lpmliW->fdwLine = mliA.fdwLine;
1347 lpmliW->dwUser = mliA.dwUser;
1348 lpmliW->dwComponentType = mliA.dwComponentType;
1349 lpmliW->cChannels = mliA.cChannels;
1350 lpmliW->cConnections = mliA.cConnections;
1351 lpmliW->cControls = mliA.cControls;
1352 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
1353 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
1354 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
1355 sizeof(lpmliW->szName)/sizeof(WCHAR) );
1356 lpmliW->Target.dwType = mliA.Target.dwType;
1357 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
1358 lpmliW->Target.wMid = mliA.Target.wMid;
1359 lpmliW->Target.wPid = mliA.Target.wPid;
1360 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
1361 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
1362 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
1364 return ret;
1367 /**************************************************************************
1368 * mixerGetLineInfo [MMSYSTEM.805]
1370 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16,
1371 DWORD fdwInfo)
1373 MIXERLINEA mliA;
1374 UINT ret;
1376 TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo);
1378 if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16))
1379 return MMSYSERR_INVALPARAM;
1381 mliA.cbStruct = sizeof(mliA);
1382 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1383 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1384 mliA.dwComponentType = lpmli16->dwComponentType;
1385 break;
1386 case MIXER_GETLINEINFOF_DESTINATION:
1387 mliA.dwDestination = lpmli16->dwDestination;
1388 break;
1389 case MIXER_GETLINEINFOF_LINEID:
1390 mliA.dwLineID = lpmli16->dwLineID;
1391 break;
1392 case MIXER_GETLINEINFOF_SOURCE:
1393 mliA.dwDestination = lpmli16->dwDestination;
1394 mliA.dwSource = lpmli16->dwSource;
1395 break;
1396 case MIXER_GETLINEINFOF_TARGETTYPE:
1397 mliA.Target.dwType = lpmli16->Target.dwType;
1398 mliA.Target.wMid = lpmli16->Target.wMid;
1399 mliA.Target.wPid = lpmli16->Target.wPid;
1400 mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion;
1401 strcpy(mliA.Target.szPname, lpmli16->Target.szPname);
1402 break;
1403 default:
1404 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1407 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1409 lpmli16->dwDestination = mliA.dwDestination;
1410 lpmli16->dwSource = mliA.dwSource;
1411 lpmli16->dwLineID = mliA.dwLineID;
1412 lpmli16->fdwLine = mliA.fdwLine;
1413 lpmli16->dwUser = mliA.dwUser;
1414 lpmli16->dwComponentType = mliA.dwComponentType;
1415 lpmli16->cChannels = mliA.cChannels;
1416 lpmli16->cConnections = mliA.cConnections;
1417 lpmli16->cControls = mliA.cControls;
1418 strcpy(lpmli16->szShortName, mliA.szShortName);
1419 strcpy(lpmli16->szName, mliA.szName);
1420 lpmli16->Target.dwType = mliA.Target.dwType;
1421 lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID;
1422 lpmli16->Target.wMid = mliA.Target.wMid;
1423 lpmli16->Target.wPid = mliA.Target.wPid;
1424 lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion;
1425 strcpy(lpmli16->Target.szPname, mliA.Target.szPname);
1427 return ret;
1430 /**************************************************************************
1431 * mixerSetControlDetails [WINMM.@]
1433 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1434 DWORD fdwDetails)
1436 LPWINE_MIXER lpwm;
1438 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1440 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1441 return MMSYSERR_INVALHANDLE;
1443 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
1444 fdwDetails, TRUE);
1447 /**************************************************************************
1448 * mixerSetControlDetails [MMSYSTEM.809]
1450 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix,
1451 LPMIXERCONTROLDETAILS16 lpmcd,
1452 DWORD fdwDetails)
1454 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1455 return MMSYSERR_NOTENABLED;
1458 /**************************************************************************
1459 * mixerMessage [WINMM.@]
1461 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
1463 LPWINE_MLD wmld;
1465 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
1466 (DWORD)hmix, uMsg, dwParam1, dwParam2);
1468 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
1469 return MMSYSERR_INVALHANDLE;
1471 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
1474 /**************************************************************************
1475 * mixerMessage [MMSYSTEM.804]
1477 DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1,
1478 DWORD dwParam2)
1480 return mixerMessage(hmix, uMsg, dwParam1, dwParam2);
1483 /**************************************************************************
1484 * auxGetNumDevs [WINMM.@]
1486 UINT WINAPI auxGetNumDevs(void)
1488 return MMDRV_GetNum(MMDRV_AUX);
1491 /**************************************************************************
1492 * auxGetNumDevs [MMSYSTEM.350]
1494 UINT16 WINAPI auxGetNumDevs16(void)
1496 return MMDRV_GetNum(MMDRV_AUX);
1499 /**************************************************************************
1500 * auxGetDevCapsW [WINMM.@]
1502 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
1504 AUXCAPSA acA;
1505 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
1507 lpCaps->wMid = acA.wMid;
1508 lpCaps->wPid = acA.wPid;
1509 lpCaps->vDriverVersion = acA.vDriverVersion;
1510 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
1511 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1512 lpCaps->wTechnology = acA.wTechnology;
1513 lpCaps->dwSupport = acA.dwSupport;
1514 return ret;
1517 /**************************************************************************
1518 * auxGetDevCapsA [WINMM.@]
1520 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
1522 LPWINE_MLD wmld;
1524 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1526 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1527 return MMSYSERR_INVALHANDLE;
1528 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1531 /**************************************************************************
1532 * auxGetDevCaps [MMSYSTEM.351]
1534 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
1536 LPWINE_MLD wmld;
1538 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1540 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1541 return MMSYSERR_INVALHANDLE;
1542 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1545 /**************************************************************************
1546 * auxGetVolume [WINMM.@]
1548 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1550 LPWINE_MLD wmld;
1552 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1554 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1555 return MMSYSERR_INVALHANDLE;
1556 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1559 /**************************************************************************
1560 * auxGetVolume [MMSYSTEM.352]
1562 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume)
1564 LPWINE_MLD wmld;
1566 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1568 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1569 return MMSYSERR_INVALHANDLE;
1570 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1573 /**************************************************************************
1574 * auxSetVolume [WINMM.@]
1576 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
1578 LPWINE_MLD wmld;
1580 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1582 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1583 return MMSYSERR_INVALHANDLE;
1584 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1587 /**************************************************************************
1588 * auxSetVolume [MMSYSTEM.353]
1590 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
1592 LPWINE_MLD wmld;
1594 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1596 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1597 return MMSYSERR_INVALHANDLE;
1598 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1601 /**************************************************************************
1602 * auxOutMessage [WINMM.@]
1604 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1606 LPWINE_MLD wmld;
1608 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1609 return MMSYSERR_INVALHANDLE;
1611 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1614 /**************************************************************************
1615 * auxOutMessage [MMSYSTEM.354]
1617 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1619 LPWINE_MLD wmld;
1621 TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1623 switch (uMessage) {
1624 case AUXDM_GETNUMDEVS:
1625 case AUXDM_SETVOLUME:
1626 /* no argument conversion needed */
1627 break;
1628 case AUXDM_GETVOLUME:
1629 return auxGetVolume16(uDeviceID, MapSL(dw1));
1630 case AUXDM_GETDEVCAPS:
1631 return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2);
1632 default:
1633 TRACE("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1634 uDeviceID, uMessage, dw1, dw2);
1635 break;
1637 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1638 return MMSYSERR_INVALHANDLE;
1640 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1643 /**************************************************************************
1644 * mciGetErrorStringW [WINMM.@]
1646 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1648 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1649 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
1651 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
1652 HeapFree(GetProcessHeap(), 0, bufstr);
1653 return ret;
1656 /**************************************************************************
1657 * mciGetErrorString [MMSYSTEM.706]
1659 BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength)
1661 return mciGetErrorStringA(wError, lpstrBuffer, uLength);
1664 /**************************************************************************
1665 * mciGetErrorStringA [WINMM.@]
1667 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
1669 BOOL16 ret = FALSE;
1671 if (lpstrBuffer != NULL && uLength > 0 &&
1672 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
1674 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
1675 dwError, lpstrBuffer, uLength) > 0) {
1676 ret = TRUE;
1679 return ret;
1682 /**************************************************************************
1683 * mciDriverNotify [MMSYSTEM.711]
1685 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1687 TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1689 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1692 /**************************************************************************
1693 * mciDriverNotify [WINMM.@]
1695 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1698 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1700 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1703 /**************************************************************************
1704 * mciGetDriverData [MMSYSTEM.708]
1706 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1708 return mciGetDriverData(uDeviceID);
1711 /**************************************************************************
1712 * mciGetDriverData [WINMM.@]
1714 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1716 LPWINE_MCIDRIVER wmd;
1718 TRACE("(%04x)\n", uDeviceID);
1720 wmd = MCI_GetDriver(uDeviceID);
1722 if (!wmd) {
1723 WARN("Bad uDeviceID\n");
1724 return 0L;
1727 return wmd->dwPrivate;
1730 /**************************************************************************
1731 * mciSetDriverData [MMSYSTEM.707]
1733 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1735 return mciSetDriverData(uDeviceID, data);
1738 /**************************************************************************
1739 * mciSetDriverData [WINMM.@]
1741 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1743 LPWINE_MCIDRIVER wmd;
1745 TRACE("(%04x, %08lx)\n", uDeviceID, data);
1747 wmd = MCI_GetDriver(uDeviceID);
1749 if (!wmd) {
1750 WARN("Bad uDeviceID\n");
1751 return FALSE;
1754 wmd->dwPrivate = data;
1755 return TRUE;
1758 /**************************************************************************
1759 * mciSendCommandA [WINMM.@]
1761 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1763 DWORD dwRet;
1765 TRACE("(%08x, %s, %08lx, %08lx)\n",
1766 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1768 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
1769 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1770 TRACE("=> %08lx\n", dwRet);
1771 return dwRet;
1774 /**************************************************************************
1775 * mciSendCommandW [WINMM.@]
1777 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1779 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
1780 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1781 return MCIERR_UNSUPPORTED_FUNCTION;
1784 /**************************************************************************
1785 * mciSendCommand [MMSYSTEM.701]
1787 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1789 DWORD dwRet;
1791 TRACE("(%04X, %s, %08lX, %08lX)\n",
1792 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1794 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE);
1795 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1796 TRACE("=> %ld\n", dwRet);
1797 return dwRet;
1800 /**************************************************************************
1801 * mciGetDeviceID [MMSYSTEM.703]
1803 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1805 TRACE("(\"%s\")\n", lpstrName);
1807 return MCI_GetDriverFromString(lpstrName);
1810 /**************************************************************************
1811 * mciGetDeviceIDA [WINMM.@]
1813 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1815 return MCI_GetDriverFromString(lpstrName);
1818 /**************************************************************************
1819 * mciGetDeviceIDW [WINMM.@]
1821 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1823 LPSTR lpstrName;
1824 UINT ret;
1826 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1827 ret = MCI_GetDriverFromString(lpstrName);
1828 HeapFree(GetProcessHeap(), 0, lpstrName);
1829 return ret;
1832 /**************************************************************************
1833 * MCI_DefYieldProc [internal]
1835 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1837 INT16 ret;
1839 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1841 if ((HIWORD(data) != 0 && GetActiveWindow() != HIWORD(data)) ||
1842 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1843 UserYield16();
1844 ret = 0;
1845 } else {
1846 MSG msg;
1848 msg.hwnd = HIWORD(data);
1849 while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1850 ret = -1;
1852 return ret;
1855 /**************************************************************************
1856 * mciSetYieldProc [MMSYSTEM.714]
1858 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData)
1860 LPWINE_MCIDRIVER wmd;
1862 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1864 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1865 WARN("Bad uDeviceID\n");
1866 return FALSE;
1869 wmd->lpfnYieldProc = (YIELDPROC)fpYieldProc;
1870 wmd->dwYieldData = dwYieldData;
1871 wmd->bIs32 = FALSE;
1873 return TRUE;
1876 /**************************************************************************
1877 * mciSetYieldProc [WINMM.@]
1879 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1881 LPWINE_MCIDRIVER wmd;
1883 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1885 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1886 WARN("Bad uDeviceID\n");
1887 return FALSE;
1890 wmd->lpfnYieldProc = fpYieldProc;
1891 wmd->dwYieldData = dwYieldData;
1892 wmd->bIs32 = TRUE;
1894 return TRUE;
1897 /**************************************************************************
1898 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
1900 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1902 FIXME("(%lu, %s) stub\n", dwElementID, lpstrType);
1903 return 0;
1906 /**************************************************************************
1907 * mciGetDeviceIDFromElementIDW [WINMM.@]
1909 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1911 /* FIXME: that's rather strange, there is no
1912 * mciGetDeviceIDFromElementID32A in winmm.spec
1914 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1915 return 0;
1918 /**************************************************************************
1919 * mciGetYieldProc [MMSYSTEM.716]
1921 YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1923 LPWINE_MCIDRIVER wmd;
1925 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1927 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1928 WARN("Bad uDeviceID\n");
1929 return NULL;
1931 if (!wmd->lpfnYieldProc) {
1932 WARN("No proc set\n");
1933 return NULL;
1935 if (wmd->bIs32) {
1936 WARN("Proc is 32 bit\n");
1937 return NULL;
1939 return (YIELDPROC16)wmd->lpfnYieldProc;
1942 /**************************************************************************
1943 * mciGetYieldProc [WINMM.@]
1945 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1947 LPWINE_MCIDRIVER wmd;
1949 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1951 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1952 WARN("Bad uDeviceID\n");
1953 return NULL;
1955 if (!wmd->lpfnYieldProc) {
1956 WARN("No proc set\n");
1957 return NULL;
1959 if (!wmd->bIs32) {
1960 WARN("Proc is 32 bit\n");
1961 return NULL;
1963 return wmd->lpfnYieldProc;
1966 /**************************************************************************
1967 * mciGetCreatorTask [MMSYSTEM.717]
1969 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1971 return mciGetCreatorTask(uDeviceID);
1974 /**************************************************************************
1975 * mciGetCreatorTask [WINMM.@]
1977 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1979 LPWINE_MCIDRIVER wmd;
1980 HTASK ret;
1982 TRACE("(%u)\n", uDeviceID);
1984 ret = (!(wmd = MCI_GetDriver(uDeviceID))) ? 0 : wmd->hCreatorTask;
1986 TRACE("=> %04x\n", ret);
1987 return ret;
1990 /**************************************************************************
1991 * mciDriverYield [MMSYSTEM.710]
1993 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
1995 LPWINE_MCIDRIVER wmd;
1996 UINT16 ret = 0;
1998 /* TRACE("(%04x)\n", uDeviceID); */
2000 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) {
2001 UserYield16();
2002 } else {
2003 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
2006 return ret;
2009 /**************************************************************************
2010 * mciDriverYield [WINMM.@]
2012 UINT WINAPI mciDriverYield(UINT uDeviceID)
2014 LPWINE_MCIDRIVER wmd;
2015 UINT ret = 0;
2017 TRACE("(%04x)\n", uDeviceID);
2019 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
2020 UserYield16();
2021 } else {
2022 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
2025 return ret;
2028 /**************************************************************************
2029 * midiOutGetNumDevs [WINMM.@]
2031 UINT WINAPI midiOutGetNumDevs(void)
2033 return MMDRV_GetNum(MMDRV_MIDIOUT);
2036 /**************************************************************************
2037 * midiOutGetNumDevs [MMSYSTEM.201]
2039 UINT16 WINAPI midiOutGetNumDevs16(void)
2041 return MMDRV_GetNum(MMDRV_MIDIOUT);
2044 /**************************************************************************
2045 * midiOutGetDevCapsW [WINMM.@]
2047 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
2048 UINT uSize)
2050 MIDIOUTCAPSA mocA;
2051 UINT ret;
2053 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
2054 lpCaps->wMid = mocA.wMid;
2055 lpCaps->wPid = mocA.wPid;
2056 lpCaps->vDriverVersion = mocA.vDriverVersion;
2057 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
2058 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2059 lpCaps->wTechnology = mocA.wTechnology;
2060 lpCaps->wVoices = mocA.wVoices;
2061 lpCaps->wNotes = mocA.wNotes;
2062 lpCaps->wChannelMask = mocA.wChannelMask;
2063 lpCaps->dwSupport = mocA.dwSupport;
2064 return ret;
2067 /**************************************************************************
2068 * midiOutGetDevCapsA [WINMM.@]
2070 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
2071 UINT uSize)
2073 LPWINE_MLD wmld;
2075 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
2077 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2079 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2080 return MMSYSERR_INVALHANDLE;
2082 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2085 /**************************************************************************
2086 * midiOutGetDevCaps [MMSYSTEM.202]
2088 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps,
2089 UINT16 uSize)
2091 MIDIOUTCAPSA capsA;
2092 UINT dwRet;
2094 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2096 dwRet = midiOutGetDevCapsA(uDeviceID, &capsA, sizeof(capsA));
2097 if (dwRet == MMSYSERR_NOERROR) {
2098 lpCaps->wMid = capsA.wMid;
2099 lpCaps->wPid = capsA.wPid;
2100 lpCaps->vDriverVersion = capsA.vDriverVersion;
2101 strcpy(lpCaps->szPname, capsA.szPname);
2102 lpCaps->wTechnology = capsA.wTechnology;
2103 lpCaps->wVoices = capsA.wVoices;
2104 lpCaps->wNotes = capsA.wNotes;
2105 lpCaps->wChannelMask = capsA.wChannelMask;
2106 lpCaps->dwSupport = capsA.dwSupport;
2108 return dwRet;
2111 /**************************************************************************
2112 * MIDI_GetErrorText [internal]
2114 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2116 UINT16 ret = MMSYSERR_BADERRNUM;
2118 if (lpText == NULL) {
2119 ret = MMSYSERR_INVALPARAM;
2120 } else if (uSize == 0) {
2121 ret = MMSYSERR_NOERROR;
2122 } else if (
2123 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2124 * a warning for the test was always true */
2125 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
2126 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
2128 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
2129 uError, lpText, uSize) > 0) {
2130 ret = MMSYSERR_NOERROR;
2133 return ret;
2136 /**************************************************************************
2137 * midiOutGetErrorTextA [WINMM.@]
2139 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2141 return MIDI_GetErrorText(uError, lpText, uSize);
2144 /**************************************************************************
2145 * midiOutGetErrorTextW [WINMM.@]
2147 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2149 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2150 UINT ret;
2152 ret = MIDI_GetErrorText(uError, xstr, uSize);
2153 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2154 HeapFree(GetProcessHeap(), 0, xstr);
2155 return ret;
2158 /**************************************************************************
2159 * midiOutGetErrorText [MMSYSTEM.203]
2161 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2163 return MIDI_GetErrorText(uError, lpText, uSize);
2166 /**************************************************************************
2167 * MIDI_OutAlloc [internal]
2169 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
2170 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
2171 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
2173 HMIDIOUT hMidiOut;
2174 LPWINE_MIDI lpwm;
2175 UINT size;
2177 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
2179 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
2180 lpdwCallback, lpdwInstance, bFrom32);
2182 if (lphMidiOut != NULL)
2183 *lphMidiOut = hMidiOut;
2185 if (lpwm) {
2186 lpwm->mod.hMidi = hMidiOut;
2187 lpwm->mod.dwCallback = *lpdwCallback;
2188 lpwm->mod.dwInstance = *lpdwInstance;
2189 lpwm->mod.dnDevNode = 0;
2190 lpwm->mod.cIds = cIDs;
2191 if (cIDs)
2192 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2194 return lpwm;
2197 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
2198 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2200 HMIDIOUT hMidiOut;
2201 LPWINE_MIDI lpwm;
2202 UINT dwRet = 0;
2204 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2205 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2207 if (lphMidiOut != NULL) *lphMidiOut = 0;
2209 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
2210 0, NULL, bFrom32);
2212 if (lpwm == NULL)
2213 return MMSYSERR_NOMEM;
2215 lpwm->mld.uDeviceID = uDeviceID;
2217 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
2218 dwFlags);
2220 if (dwRet != MMSYSERR_NOERROR) {
2221 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
2222 hMidiOut = 0;
2225 if (lphMidiOut) *lphMidiOut = hMidiOut;
2226 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
2228 return dwRet;
2231 /**************************************************************************
2232 * midiOutOpen [WINMM.@]
2234 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2235 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2237 return MMSYSTEM_midiOutOpen(lphMidiOut, uDeviceID, dwCallback,
2238 dwInstance, dwFlags, TRUE);
2241 /**************************************************************************
2242 * midiOutOpen [MMSYSTEM.204]
2244 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2245 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2247 HMIDIOUT hmo;
2248 UINT ret;
2250 ret = MMSYSTEM_midiOutOpen(&hmo, uDeviceID, dwCallback, dwInstance,
2251 dwFlags, FALSE);
2253 if (lphMidiOut != NULL) *lphMidiOut = hmo;
2254 return ret;
2257 /**************************************************************************
2258 * midiOutClose [WINMM.@]
2260 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2262 LPWINE_MLD wmld;
2263 DWORD dwRet;
2265 TRACE("(%04X)\n", hMidiOut);
2267 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2268 return MMSYSERR_INVALHANDLE;
2270 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
2271 MMDRV_Free(hMidiOut, wmld);
2273 return dwRet;
2276 /**************************************************************************
2277 * midiOutClose [MMSYSTEM.205]
2279 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2281 return midiOutClose(hMidiOut);
2284 /**************************************************************************
2285 * midiOutPrepareHeader [WINMM.@]
2287 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2288 MIDIHDR* lpMidiOutHdr, UINT uSize)
2290 LPWINE_MLD wmld;
2292 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2294 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2295 return MMSYSERR_INVALHANDLE;
2297 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2300 /**************************************************************************
2301 * midiOutPrepareHeader [MMSYSTEM.206]
2303 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2304 SEGPTR lpsegMidiOutHdr, /* [???] */
2305 UINT16 uSize) /* [in] */
2307 LPWINE_MLD wmld;
2309 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2311 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2312 return MMSYSERR_INVALHANDLE;
2314 return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE);
2317 /**************************************************************************
2318 * midiOutUnprepareHeader [WINMM.@]
2320 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2321 MIDIHDR* lpMidiOutHdr, UINT uSize)
2323 LPWINE_MLD wmld;
2325 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2327 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2328 return MMSYSERR_NOERROR;
2331 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2332 return MMSYSERR_INVALHANDLE;
2334 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2337 /**************************************************************************
2338 * midiOutUnprepareHeader [MMSYSTEM.207]
2340 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2341 SEGPTR lpsegMidiOutHdr, /* [???] */
2342 UINT16 uSize) /* [in] */
2344 LPWINE_MLD wmld;
2345 LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr);
2347 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2349 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2350 return MMSYSERR_NOERROR;
2353 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2354 return MMSYSERR_INVALHANDLE;
2356 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2359 /**************************************************************************
2360 * midiOutShortMsg [WINMM.@]
2362 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2364 LPWINE_MLD wmld;
2366 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
2368 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2369 return MMSYSERR_INVALHANDLE;
2371 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, FALSE);
2374 /**************************************************************************
2375 * midiOutShortMsg [MMSYSTEM.208]
2377 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2379 return midiOutShortMsg(hMidiOut, dwMsg);
2382 /**************************************************************************
2383 * midiOutLongMsg [WINMM.@]
2385 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2386 MIDIHDR* lpMidiOutHdr, UINT uSize)
2388 LPWINE_MLD wmld;
2390 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2392 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2393 return MMSYSERR_INVALHANDLE;
2395 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
2398 /**************************************************************************
2399 * midiOutLongMsg [MMSYSTEM.209]
2401 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */
2402 LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */
2403 UINT16 uSize) /* [in] */
2405 LPWINE_MLD wmld;
2407 TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2409 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2410 return MMSYSERR_INVALHANDLE;
2412 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2415 /**************************************************************************
2416 * midiOutReset [WINMM.@]
2418 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2420 LPWINE_MLD wmld;
2422 TRACE("(%04X)\n", hMidiOut);
2424 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2425 return MMSYSERR_INVALHANDLE;
2427 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
2430 /**************************************************************************
2431 * midiOutReset [MMSYSTEM.210]
2433 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2435 return midiOutReset(hMidiOut);
2438 /**************************************************************************
2439 * midiOutGetVolume [WINMM.@]
2441 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2443 LPWINE_MLD wmld;
2445 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
2447 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2448 return MMSYSERR_INVALHANDLE;
2450 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
2453 /**************************************************************************
2454 * midiOutGetVolume [MMSYSTEM.211]
2456 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2458 return midiOutGetVolume(uDeviceID, lpdwVolume);
2461 /**************************************************************************
2462 * midiOutSetVolume [WINMM.@]
2464 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2466 LPWINE_MLD wmld;
2468 TRACE("(%04X, %ld);\n", uDeviceID, dwVolume);
2470 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2471 return MMSYSERR_INVALHANDLE;
2473 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
2476 /**************************************************************************
2477 * midiOutSetVolume [MMSYSTEM.212]
2479 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2481 return midiOutSetVolume(uDeviceID, dwVolume);
2484 /**************************************************************************
2485 * midiOutCachePatches [WINMM.@]
2487 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2488 WORD* lpwPatchArray, UINT uFlags)
2490 /* not really necessary to support this */
2491 FIXME("not supported yet\n");
2492 return MMSYSERR_NOTSUPPORTED;
2495 /**************************************************************************
2496 * midiOutCachePatches [MMSYSTEM.213]
2498 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2499 WORD* lpwPatchArray, UINT16 uFlags)
2501 return midiOutCachePatches(hMidiOut, uBank, lpwPatchArray, uFlags);
2504 /**************************************************************************
2505 * midiOutCacheDrumPatches [WINMM.@]
2507 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2508 WORD* lpwKeyArray, UINT uFlags)
2510 FIXME("not supported yet\n");
2511 return MMSYSERR_NOTSUPPORTED;
2514 /**************************************************************************
2515 * midiOutCacheDrumPatches [MMSYSTEM.214]
2517 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2518 WORD* lpwKeyArray, UINT16 uFlags)
2520 return midiOutCacheDrumPatches16(hMidiOut, uPatch, lpwKeyArray, uFlags);
2523 /**************************************************************************
2524 * midiOutGetID [WINMM.@]
2526 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2528 LPWINE_MLD wmld;
2530 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2532 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2533 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2534 return MMSYSERR_INVALHANDLE;
2536 *lpuDeviceID = wmld->uDeviceID;
2537 return MMSYSERR_NOERROR;
2540 /**************************************************************************
2541 * midiOutGetID [MMSYSTEM.215]
2543 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2545 LPWINE_MLD wmld;
2547 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2549 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2550 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2551 return MMSYSERR_INVALHANDLE;
2553 *lpuDeviceID = wmld->uDeviceID;
2554 return MMSYSERR_NOERROR;
2557 /**************************************************************************
2558 * midiOutMessage [WINMM.@]
2560 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2561 DWORD dwParam1, DWORD dwParam2)
2563 LPWINE_MLD wmld;
2565 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2567 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
2568 /* HACK... */
2569 if (uMessage == 0x0001) {
2570 *(LPDWORD)dwParam1 = 1;
2571 return 0;
2573 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
2574 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2576 return MMSYSERR_INVALHANDLE;
2579 switch (uMessage) {
2580 case MODM_OPEN:
2581 case MODM_CLOSE:
2582 FIXME("can't handle OPEN or CLOSE message!\n");
2583 return MMSYSERR_NOTSUPPORTED;
2585 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2588 /**************************************************************************
2589 * midiOutMessage [MMSYSTEM.216]
2591 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2592 DWORD dwParam1, DWORD dwParam2)
2594 LPWINE_MLD wmld;
2596 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2598 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2599 return MMSYSERR_INVALHANDLE;
2601 switch (uMessage) {
2602 case MODM_OPEN:
2603 case MODM_CLOSE:
2604 FIXME("can't handle OPEN or CLOSE message!\n");
2605 return MMSYSERR_NOTSUPPORTED;
2607 case MODM_GETVOLUME:
2608 return midiOutGetVolume16(hMidiOut, MapSL(dwParam1));
2609 case MODM_LONGDATA:
2610 return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2);
2611 case MODM_PREPARE:
2612 /* lpMidiOutHdr is still a segmented pointer for this function */
2613 return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2);
2614 case MODM_UNPREPARE:
2615 return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2);
2617 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2620 /**************************************************************************
2621 * midiInGetNumDevs [WINMM.@]
2623 UINT WINAPI midiInGetNumDevs(void)
2625 return MMDRV_GetNum(MMDRV_MIDIIN);
2628 /**************************************************************************
2629 * midiInGetNumDevs [MMSYSTEM.301]
2631 UINT16 WINAPI midiInGetNumDevs16(void)
2633 return MMDRV_GetNum(MMDRV_MIDIIN);
2636 /**************************************************************************
2637 * midiInGetDevCapsW [WINMM.@]
2639 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2641 MIDIINCAPSA micA;
2642 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2644 if (ret == MMSYSERR_NOERROR) {
2645 lpCaps->wMid = micA.wMid;
2646 lpCaps->wPid = micA.wPid;
2647 lpCaps->vDriverVersion = micA.vDriverVersion;
2648 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
2649 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2650 lpCaps->dwSupport = micA.dwSupport;
2652 return ret;
2655 /**************************************************************************
2656 * midiInGetDevCapsA [WINMM.@]
2658 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2660 LPWINE_MLD wmld;
2662 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
2664 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
2665 return MMSYSERR_INVALHANDLE;
2667 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2670 /**************************************************************************
2671 * midiInGetDevCaps [MMSYSTEM.302]
2673 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps,
2674 UINT16 uSize)
2676 MIDIINCAPSA micA;
2677 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2679 if (ret == MMSYSERR_NOERROR) {
2680 lpCaps->wMid = micA.wMid;
2681 lpCaps->wPid = micA.wPid;
2682 lpCaps->vDriverVersion = micA.vDriverVersion;
2683 strcpy(lpCaps->szPname, micA.szPname);
2684 lpCaps->dwSupport = micA.dwSupport;
2687 return ret;
2690 /**************************************************************************
2691 * midiInGetErrorTextW [WINMM.@]
2693 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2695 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2696 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
2698 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2699 HeapFree(GetProcessHeap(), 0, xstr);
2700 return ret;
2703 /**************************************************************************
2704 * midiInGetErrorTextA [WINMM.@]
2706 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2708 return MIDI_GetErrorText(uError, lpText, uSize);
2711 /**************************************************************************
2712 * midiInGetErrorText [MMSYSTEM.303]
2714 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2716 return MIDI_GetErrorText(uError, lpText, uSize);
2719 static UINT MMSYSTEM_midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
2720 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2722 HMIDIIN hMidiIn;
2723 LPWINE_MIDI lpwm;
2724 DWORD dwRet = 0;
2726 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2727 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2729 if (lphMidiIn != NULL) *lphMidiIn = 0;
2731 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
2732 &dwFlags, &dwCallback, &dwInstance, bFrom32);
2734 if (lpwm == NULL)
2735 return MMSYSERR_NOMEM;
2737 lpwm->mod.hMidi = hMidiIn;
2738 lpwm->mod.dwCallback = dwCallback;
2739 lpwm->mod.dwInstance = dwInstance;
2741 lpwm->mld.uDeviceID = uDeviceID;
2742 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
2744 if (dwRet != MMSYSERR_NOERROR) {
2745 MMDRV_Free(hMidiIn, &lpwm->mld);
2746 hMidiIn = 0;
2748 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
2749 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
2751 return dwRet;
2754 /**************************************************************************
2755 * midiInOpen [WINMM.@]
2757 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2758 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2760 return MMSYSTEM_midiInOpen(lphMidiIn, uDeviceID, dwCallback,
2761 dwInstance, dwFlags, TRUE);
2764 /**************************************************************************
2765 * midiInOpen [MMSYSTEM.304]
2767 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2768 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2770 HMIDIIN xhmid;
2771 UINT ret;
2773 ret = MMSYSTEM_midiInOpen(&xhmid, uDeviceID, dwCallback, dwInstance,
2774 dwFlags, FALSE);
2776 if (lphMidiIn) *lphMidiIn = xhmid;
2777 return ret;
2780 /**************************************************************************
2781 * midiInClose [WINMM.@]
2783 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2785 LPWINE_MLD wmld;
2786 DWORD dwRet;
2788 TRACE("(%04X)\n", hMidiIn);
2790 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2791 return MMSYSERR_INVALHANDLE;
2793 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
2794 MMDRV_Free(hMidiIn, wmld);
2795 return dwRet;
2798 /**************************************************************************
2799 * midiInClose [MMSYSTEM.305]
2801 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2803 return midiInClose(hMidiIn);
2806 /**************************************************************************
2807 * midiInPrepareHeader [WINMM.@]
2809 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2810 MIDIHDR* lpMidiInHdr, UINT uSize)
2812 LPWINE_MLD wmld;
2814 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2816 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2817 return MMSYSERR_INVALHANDLE;
2819 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2822 /**************************************************************************
2823 * midiInPrepareHeader [MMSYSTEM.306]
2825 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2826 SEGPTR lpsegMidiInHdr, /* [???] */
2827 UINT16 uSize) /* [in] */
2829 LPWINE_MLD wmld;
2831 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2833 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2834 return MMSYSERR_INVALHANDLE;
2836 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2839 /**************************************************************************
2840 * midiInUnprepareHeader [WINMM.@]
2842 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2843 MIDIHDR* lpMidiInHdr, UINT uSize)
2845 LPWINE_MLD wmld;
2847 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2849 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2850 return MMSYSERR_NOERROR;
2853 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2854 return MMSYSERR_INVALHANDLE;
2856 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2859 /**************************************************************************
2860 * midiInUnprepareHeader [MMSYSTEM.307]
2862 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2863 SEGPTR lpsegMidiInHdr, /* [???] */
2864 UINT16 uSize) /* [in] */
2866 LPWINE_MLD wmld;
2867 LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr);
2869 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2871 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2872 return MMSYSERR_NOERROR;
2875 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2876 return MMSYSERR_INVALHANDLE;
2878 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2881 /**************************************************************************
2882 * midiInAddBuffer [WINMM.@]
2884 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2885 MIDIHDR* lpMidiInHdr, UINT uSize)
2887 LPWINE_MLD wmld;
2889 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2891 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2892 return MMSYSERR_INVALHANDLE;
2894 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
2897 /**************************************************************************
2898 * midiInAddBuffer [MMSYSTEM.308]
2900 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */
2901 MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */
2902 UINT16 uSize) /* [in] */
2904 LPWINE_MLD wmld;
2906 TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2908 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2909 return MMSYSERR_INVALHANDLE;
2911 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2914 /**************************************************************************
2915 * midiInStart [WINMM.@]
2917 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2919 LPWINE_MLD wmld;
2921 TRACE("(%04X)\n", hMidiIn);
2923 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2924 return MMSYSERR_INVALHANDLE;
2926 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
2929 /**************************************************************************
2930 * midiInStart [MMSYSTEM.309]
2932 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2934 return midiInStart(hMidiIn);
2937 /**************************************************************************
2938 * midiInStop [WINMM.@]
2940 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2942 LPWINE_MLD wmld;
2944 TRACE("(%04X)\n", hMidiIn);
2946 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2947 return MMSYSERR_INVALHANDLE;
2949 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
2952 /**************************************************************************
2953 * midiInStop [MMSYSTEM.310]
2955 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2957 return midiInStop(hMidiIn);
2960 /**************************************************************************
2961 * midiInReset [WINMM.@]
2963 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2965 LPWINE_MLD wmld;
2967 TRACE("(%04X)\n", hMidiIn);
2969 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2970 return MMSYSERR_INVALHANDLE;
2972 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
2975 /**************************************************************************
2976 * midiInReset [MMSYSTEM.311]
2978 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2980 return midiInReset(hMidiIn);
2983 /**************************************************************************
2984 * midiInGetID [WINMM.@]
2986 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2988 LPWINE_MLD wmld;
2990 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2992 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2994 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
2995 return MMSYSERR_INVALHANDLE;
2997 *lpuDeviceID = wmld->uDeviceID;
2999 return MMSYSERR_NOERROR;
3002 /**************************************************************************
3003 * midiInGetID [MMSYSTEM.312]
3005 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
3007 LPWINE_MLD wmld;
3009 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
3011 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
3013 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
3014 return MMSYSERR_INVALHANDLE;
3016 *lpuDeviceID = wmld->uDeviceID;
3018 return MMSYSERR_NOERROR;
3021 /**************************************************************************
3022 * midiInMessage [WINMM.@]
3024 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
3025 DWORD dwParam1, DWORD dwParam2)
3027 LPWINE_MLD wmld;
3029 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3031 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
3032 return MMSYSERR_INVALHANDLE;
3034 switch (uMessage) {
3035 case MIDM_OPEN:
3036 case MIDM_CLOSE:
3037 FIXME("can't handle OPEN or CLOSE message!\n");
3038 return MMSYSERR_NOTSUPPORTED;
3040 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
3043 /**************************************************************************
3044 * midiInMessage [MMSYSTEM.313]
3046 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
3047 DWORD dwParam1, DWORD dwParam2)
3049 LPWINE_MLD wmld;
3051 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3053 switch (uMessage) {
3054 case MIDM_OPEN:
3055 case MIDM_CLOSE:
3056 FIXME("can't handle OPEN or CLOSE message!\n");
3057 return MMSYSERR_NOTSUPPORTED;
3059 case MIDM_GETDEVCAPS:
3060 return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2);
3061 case MIDM_PREPARE:
3062 return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2);
3063 case MIDM_UNPREPARE:
3064 return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2);
3065 case MIDM_ADDBUFFER:
3066 return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2);
3069 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
3070 return MMSYSERR_INVALHANDLE;
3072 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
3075 typedef struct WINE_MIDIStream {
3076 HMIDIOUT hDevice;
3077 HANDLE hThread;
3078 DWORD dwThreadID;
3079 DWORD dwTempo;
3080 DWORD dwTimeDiv;
3081 DWORD dwPositionMS;
3082 DWORD dwPulses;
3083 DWORD dwStartTicks;
3084 WORD wFlags;
3085 HANDLE hEvent;
3086 LPMIDIHDR lpMidiHdr;
3087 } WINE_MIDIStream;
3089 #define WINE_MSM_HEADER (WM_USER+0)
3090 #define WINE_MSM_STOP (WM_USER+1)
3092 /**************************************************************************
3093 * MMSYSTEM_GetMidiStream [internal]
3095 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
3097 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
3099 if (lplpwm)
3100 *lplpwm = lpwm;
3102 if (lpwm == NULL) {
3103 return FALSE;
3106 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
3108 return *lpMidiStrm != NULL;
3111 /**************************************************************************
3112 * MMSYSTEM_MidiStream_Convert [internal]
3114 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
3116 DWORD ret = 0;
3118 if (lpMidiStrm->dwTimeDiv == 0) {
3119 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
3120 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
3121 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
3122 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
3123 ret = (pulse * 1000) / (nf * nsf);
3124 } else {
3125 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
3126 (double)lpMidiStrm->dwTimeDiv);
3129 return ret;
3132 /**************************************************************************
3133 * MMSYSTEM_MidiStream_MessageHandler [internal]
3135 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
3137 LPMIDIHDR lpMidiHdr;
3138 LPMIDIHDR* lpmh;
3139 LPBYTE lpData;
3141 switch (msg->message) {
3142 case WM_QUIT:
3143 SetEvent(lpMidiStrm->hEvent);
3144 return FALSE;
3145 case WINE_MSM_STOP:
3146 TRACE("STOP\n");
3147 /* this is not quite what MS doc says... */
3148 midiOutReset(lpMidiStrm->hDevice);
3149 /* empty list of already submitted buffers */
3150 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
3151 lpMidiHdr->dwFlags |= MHDR_DONE;
3152 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3154 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3155 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3157 lpMidiStrm->lpMidiHdr = 0;
3158 SetEvent(lpMidiStrm->hEvent);
3159 break;
3160 case WINE_MSM_HEADER:
3161 /* sets initial tick count for first MIDIHDR */
3162 if (!lpMidiStrm->dwStartTicks)
3163 lpMidiStrm->dwStartTicks = GetTickCount();
3165 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
3166 * by native mcimidi, it doesn't look like a correct one".
3167 * this trick allows to throw it away... but I don't like it.
3168 * It looks like part of the file I'm trying to play and definitively looks
3169 * like raw midi content
3170 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
3171 * synchronization issue where native mcimidi is still processing raw MIDI
3172 * content before generating MIDIEVENTs ?
3174 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
3175 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
3176 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
3177 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
3178 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
3179 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
3180 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
3181 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
3182 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
3183 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3184 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3185 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3186 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3187 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3188 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3189 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3190 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3192 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3193 lpData = lpMidiHdr->lpData;
3194 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
3195 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
3196 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
3197 lpMidiHdr->dwFlags, msg->wParam);
3198 #if 0
3199 /* dumps content of lpMidiHdr->lpData
3200 * FIXME: there should be a debug routine somewhere that already does this
3201 * I hate spreading this type of shit all around the code
3203 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
3204 DWORD i;
3205 BYTE ch;
3207 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
3208 printf("%02x ", lpData[dwToGo + i]);
3209 for (; i < 16; i++)
3210 printf(" ");
3211 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
3212 ch = lpData[dwToGo + i];
3213 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
3215 printf("\n");
3217 #endif
3218 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3219 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3220 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3221 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
3222 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
3223 ((LPMIDIEVENT)lpData)->dwStreamID);
3224 lpMidiHdr->dwFlags |= MHDR_DONE;
3225 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3227 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3228 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3229 break;
3232 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
3233 *lpmh = lpMidiHdr;
3234 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3235 lpMidiHdr->lpNext = 0;
3236 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
3237 lpMidiHdr->dwFlags &= MHDR_DONE;
3238 lpMidiHdr->dwOffset = 0;
3240 break;
3241 default:
3242 FIXME("Unknown message %d\n", msg->message);
3243 break;
3245 return TRUE;
3248 /**************************************************************************
3249 * MMSYSTEM_MidiStream_Player [internal]
3251 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
3253 WINE_MIDIStream* lpMidiStrm = pmt;
3254 WINE_MIDI* lpwm;
3255 MSG msg;
3256 DWORD dwToGo;
3257 DWORD dwCurrTC;
3258 LPMIDIHDR lpMidiHdr;
3259 LPMIDIEVENT me;
3260 LPBYTE lpData = 0;
3262 TRACE("(%p)!\n", lpMidiStrm);
3264 if (!lpMidiStrm ||
3265 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
3266 goto the_end;
3268 /* force thread's queue creation */
3269 /* Used to be InitThreadInput16(0, 5); */
3270 /* but following works also with hack in midiStreamOpen */
3271 PeekMessageA(&msg, 0, 0, 0, 0);
3273 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
3274 SetEvent(lpMidiStrm->hEvent);
3275 TRACE("Ready to go 1\n");
3276 /* thread is started in paused mode */
3277 SuspendThread(lpMidiStrm->hThread);
3278 TRACE("Ready to go 2\n");
3280 lpMidiStrm->dwStartTicks = 0;
3281 lpMidiStrm->dwPulses = 0;
3283 lpMidiStrm->lpMidiHdr = 0;
3285 for (;;) {
3286 lpMidiHdr = lpMidiStrm->lpMidiHdr;
3287 if (!lpMidiHdr) {
3288 /* for first message, block until one arrives, then process all that are available */
3289 GetMessageA(&msg, 0, 0, 0);
3290 do {
3291 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3292 goto the_end;
3293 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
3294 lpData = 0;
3295 continue;
3298 if (!lpData)
3299 lpData = lpMidiHdr->lpData;
3301 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3303 /* do we have to wait ? */
3304 if (me->dwDeltaTime) {
3305 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
3306 lpMidiStrm->dwPulses += me->dwDeltaTime;
3308 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3310 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
3311 while ((dwCurrTC = GetTickCount()) < dwToGo) {
3312 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
3313 /* got a message, handle it */
3314 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
3315 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3316 goto the_end;
3318 lpData = 0;
3319 } else {
3320 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
3321 break;
3325 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3326 case MEVT_COMMENT:
3327 FIXME("NIY: MEVT_COMMENT\n");
3328 /* do nothing, skip bytes */
3329 break;
3330 case MEVT_LONGMSG:
3331 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3332 break;
3333 case MEVT_NOP:
3334 break;
3335 case MEVT_SHORTMSG:
3336 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3337 break;
3338 case MEVT_TEMPO:
3339 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3340 break;
3341 case MEVT_VERSION:
3342 break;
3343 default:
3344 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3345 break;
3347 if (me->dwEvent & MEVT_F_CALLBACK) {
3348 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3349 MM_MOM_POSITIONCB, lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
3351 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
3352 if (me->dwEvent & MEVT_F_LONG)
3353 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
3354 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
3355 /* done with this header */
3356 lpMidiHdr->dwFlags |= MHDR_DONE;
3357 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3359 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
3360 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3361 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3362 lpData = 0;
3365 the_end:
3366 TRACE("End of thread\n");
3367 ExitThread(0);
3368 return 0; /* for removing the warning, never executed */
3371 /**************************************************************************
3372 * MMSYSTEM_MidiStream_PostMessage [internal]
3374 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
3376 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
3377 DWORD count;
3379 ReleaseThunkLock(&count);
3380 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3381 RestoreThunkLock(count);
3382 } else {
3383 WARN("bad PostThreadMessageA\n");
3384 return FALSE;
3386 return TRUE;
3389 /**************************************************************************
3390 * midiStreamClose [WINMM.@]
3392 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3394 WINE_MIDIStream* lpMidiStrm;
3396 TRACE("(%08x)!\n", hMidiStrm);
3398 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3399 return MMSYSERR_INVALHANDLE;
3401 midiStreamStop(hMidiStrm);
3402 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
3403 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
3404 CloseHandle(lpMidiStrm->hEvent);
3406 return midiOutClose(hMidiStrm);
3409 /**************************************************************************
3410 * MMSYSTEM_MidiStream_Open [internal]
3412 static MMRESULT WINAPI MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3413 DWORD cMidi, DWORD dwCallback,
3414 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
3416 WINE_MIDIStream* lpMidiStrm;
3417 MMRESULT ret;
3418 MIDIOPENSTRMID mosm;
3419 LPWINE_MIDI lpwm;
3420 HMIDIOUT hMidiOut;
3422 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3423 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3425 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3426 return MMSYSERR_INVALPARAM;
3428 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3429 if (!lpMidiStrm)
3430 return MMSYSERR_NOMEM;
3432 lpMidiStrm->dwTempo = 500000;
3433 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3434 lpMidiStrm->dwPositionMS = 0;
3436 mosm.dwStreamID = (DWORD)lpMidiStrm;
3437 /* FIXME: the correct value is not allocated yet for MAPPER */
3438 mosm.wDeviceID = *lpuDeviceID;
3439 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
3440 lpMidiStrm->hDevice = hMidiOut;
3441 if (lphMidiStrm)
3442 *lphMidiStrm = hMidiOut;
3444 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
3445 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
3446 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
3448 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
3449 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
3450 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3452 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
3453 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3455 if (!lpMidiStrm->hThread) {
3456 midiStreamClose((HMIDISTRM)hMidiOut);
3457 return MMSYSERR_NOMEM;
3460 /* wait for thread to have started, and for its queue to be created */
3462 DWORD count;
3464 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3465 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3466 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3468 ReleaseThunkLock(&count);
3469 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3470 RestoreThunkLock(count);
3473 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
3474 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
3475 return ret;
3478 /**************************************************************************
3479 * midiStreamOpen [WINMM.@]
3481 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3482 DWORD cMidi, DWORD dwCallback,
3483 DWORD dwInstance, DWORD fdwOpen)
3485 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
3486 dwInstance, fdwOpen, TRUE);
3489 /**************************************************************************
3490 * midiStreamOut [WINMM.@]
3492 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
3493 UINT cbMidiHdr)
3495 WINE_MIDIStream* lpMidiStrm;
3496 DWORD ret = MMSYSERR_NOERROR;
3498 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3500 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3501 ret = MMSYSERR_INVALHANDLE;
3502 } else if (!lpMidiHdr) {
3503 ret = MMSYSERR_INVALPARAM;
3504 } else {
3505 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
3506 WINE_MSM_HEADER, cbMidiHdr,
3507 (DWORD)lpMidiHdr)) {
3508 WARN("bad PostThreadMessageA\n");
3509 ret = MMSYSERR_ERROR;
3512 return ret;
3515 /**************************************************************************
3516 * midiStreamPause [WINMM.@]
3518 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3520 WINE_MIDIStream* lpMidiStrm;
3521 DWORD ret = MMSYSERR_NOERROR;
3523 TRACE("(%08x)!\n", hMidiStrm);
3525 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3526 ret = MMSYSERR_INVALHANDLE;
3527 } else {
3528 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3529 WARN("bad Suspend (%ld)\n", GetLastError());
3530 ret = MMSYSERR_ERROR;
3533 return ret;
3536 /**************************************************************************
3537 * midiStreamPosition [WINMM.@]
3539 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3541 WINE_MIDIStream* lpMidiStrm;
3542 DWORD ret = MMSYSERR_NOERROR;
3544 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3546 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3547 ret = MMSYSERR_INVALHANDLE;
3548 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3549 ret = MMSYSERR_INVALPARAM;
3550 } else {
3551 switch (lpMMT->wType) {
3552 case TIME_MS:
3553 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3554 TRACE("=> %ld ms\n", lpMMT->u.ms);
3555 break;
3556 case TIME_TICKS:
3557 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3558 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
3559 break;
3560 default:
3561 WARN("Unsupported time type %d\n", lpMMT->wType);
3562 lpMMT->wType = TIME_MS;
3563 ret = MMSYSERR_INVALPARAM;
3564 break;
3567 return ret;
3570 /**************************************************************************
3571 * midiStreamProperty [WINMM.@]
3573 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3575 WINE_MIDIStream* lpMidiStrm;
3576 MMRESULT ret = MMSYSERR_NOERROR;
3578 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3580 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3581 ret = MMSYSERR_INVALHANDLE;
3582 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3583 ret = MMSYSERR_INVALPARAM;
3584 } else if (dwProperty & MIDIPROP_TEMPO) {
3585 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3587 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3588 ret = MMSYSERR_INVALPARAM;
3589 } else if (dwProperty & MIDIPROP_SET) {
3590 lpMidiStrm->dwTempo = mpt->dwTempo;
3591 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
3592 } else if (dwProperty & MIDIPROP_GET) {
3593 mpt->dwTempo = lpMidiStrm->dwTempo;
3594 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
3596 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3597 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3599 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3600 ret = MMSYSERR_INVALPARAM;
3601 } else if (dwProperty & MIDIPROP_SET) {
3602 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3603 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
3604 } else if (dwProperty & MIDIPROP_GET) {
3605 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3606 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
3608 } else {
3609 ret = MMSYSERR_INVALPARAM;
3612 return ret;
3615 /**************************************************************************
3616 * midiStreamRestart [WINMM.@]
3618 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3620 WINE_MIDIStream* lpMidiStrm;
3621 MMRESULT ret = MMSYSERR_NOERROR;
3623 TRACE("(%08x)!\n", hMidiStrm);
3625 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3626 ret = MMSYSERR_INVALHANDLE;
3627 } else {
3628 DWORD ret;
3630 /* since we increase the thread suspend count on each midiStreamPause
3631 * there may be a need for several midiStreamResume
3633 do {
3634 ret = ResumeThread(lpMidiStrm->hThread);
3635 } while (ret != 0xFFFFFFFF && ret != 0);
3636 if (ret == 0xFFFFFFFF) {
3637 WARN("bad Resume (%ld)\n", GetLastError());
3638 ret = MMSYSERR_ERROR;
3639 } else {
3640 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
3643 return ret;
3646 /**************************************************************************
3647 * midiStreamStop [WINMM.@]
3649 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3651 WINE_MIDIStream* lpMidiStrm;
3652 MMRESULT ret = MMSYSERR_NOERROR;
3654 TRACE("(%08x)!\n", hMidiStrm);
3656 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3657 ret = MMSYSERR_INVALHANDLE;
3658 } else {
3659 /* in case stream has been paused... FIXME is the current state correct ? */
3660 midiStreamRestart(hMidiStrm);
3661 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
3663 return ret;
3666 /**************************************************************************
3667 * midiStreamClose [MMSYSTEM.252]
3669 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3671 return midiStreamClose(hMidiStrm);
3674 /**************************************************************************
3675 * midiStreamOpen [MMSYSTEM.251]
3677 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3678 DWORD cMidi, DWORD dwCallback,
3679 DWORD dwInstance, DWORD fdwOpen)
3681 HMIDISTRM hMidiStrm32;
3682 MMRESULT ret;
3683 UINT devid32;
3685 if (!phMidiStrm || !devid)
3686 return MMSYSERR_INVALPARAM;
3687 devid32 = *devid;
3688 ret = MMSYSTEM_MidiStream_Open(&hMidiStrm32, &devid32, cMidi, dwCallback,
3689 dwInstance, fdwOpen, FALSE);
3690 *phMidiStrm = hMidiStrm32;
3691 *devid = devid32;
3692 return ret;
3695 /**************************************************************************
3696 * midiStreamOut [MMSYSTEM.254]
3698 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3700 return midiStreamOut(hMidiStrm, (LPMIDIHDR)lpMidiHdr, cbMidiHdr);
3703 /**************************************************************************
3704 * midiStreamPause [MMSYSTEM.255]
3706 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3708 return midiStreamPause(hMidiStrm);
3711 /**************************************************************************
3712 * midiStreamPosition [MMSYSTEM.253]
3714 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3716 MMTIME mmt32;
3717 MMRESULT ret;
3719 if (!lpmmt16)
3720 return MMSYSERR_INVALPARAM;
3721 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3722 ret = midiStreamPosition(hMidiStrm, &mmt32, sizeof(MMTIME));
3723 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3724 return ret;
3727 /**************************************************************************
3728 * midiStreamProperty [MMSYSTEM.250]
3730 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3732 return midiStreamProperty(hMidiStrm, lpPropData, dwProperty);
3735 /**************************************************************************
3736 * midiStreamRestart [MMSYSTEM.256]
3738 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3740 return midiStreamRestart(hMidiStrm);
3743 /**************************************************************************
3744 * midiStreamStop [MMSYSTEM.257]
3746 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3748 return midiStreamStop(hMidiStrm);
3751 static UINT WINAPI MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
3752 const LPWAVEFORMATEX lpFormat,
3753 DWORD dwCallback, DWORD dwInstance,
3754 DWORD dwFlags, BOOL bFrom32)
3756 HANDLE handle;
3757 LPWINE_MLD wmld;
3758 DWORD dwRet = MMSYSERR_NOERROR;
3759 WAVEOPENDESC wod;
3761 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
3762 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
3763 dwInstance, dwFlags, bFrom32?32:16);
3765 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
3767 if (lpFormat == NULL) return WAVERR_BADFORMAT;
3768 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
3769 return MMSYSERR_INVALPARAM;
3771 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
3772 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
3773 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
3775 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
3776 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
3777 return MMSYSERR_NOMEM;
3779 wod.hWave = handle;
3780 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
3781 wod.dwCallback = dwCallback;
3782 wod.dwInstance = dwInstance;
3783 wod.dnDevNode = 0L;
3785 if (dwFlags & WAVE_MAPPED) {
3786 wod.uMappedDeviceID = uDeviceID;
3787 uDeviceID = WAVE_MAPPER;
3788 } else {
3789 wod.uMappedDeviceID = -1;
3791 wmld->uDeviceID = uDeviceID;
3793 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, (DWORD)&wod, dwFlags);
3795 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
3796 MMDRV_Free(handle, wmld);
3797 handle = 0;
3800 if (lphndl != NULL) *lphndl = handle;
3801 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
3803 return dwRet;
3806 /**************************************************************************
3807 * waveOutGetNumDevs [WINMM.@]
3809 UINT WINAPI waveOutGetNumDevs(void)
3811 return MMDRV_GetNum(MMDRV_WAVEOUT);
3814 /**************************************************************************
3815 * waveOutGetNumDevs [MMSYSTEM.401]
3817 UINT16 WINAPI waveOutGetNumDevs16(void)
3819 return MMDRV_GetNum(MMDRV_WAVEOUT);
3822 /**************************************************************************
3823 * waveOutGetDevCaps [MMSYSTEM.402]
3825 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID,
3826 LPWAVEOUTCAPS16 lpCaps, UINT16 uSize)
3828 WAVEOUTCAPSA wocA;
3829 UINT ret;
3831 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3832 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3834 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3836 if (ret == MMSYSERR_NOERROR) {
3837 lpCaps->wMid = wocA.wMid;
3838 lpCaps->wPid = wocA.wPid;
3839 lpCaps->vDriverVersion = wocA.vDriverVersion;
3840 strcpy(lpCaps->szPname, wocA.szPname);
3841 lpCaps->dwFormats = wocA.dwFormats;
3842 lpCaps->wChannels = wocA.wChannels;
3843 lpCaps->dwSupport = wocA.dwSupport;
3845 return ret;
3848 /**************************************************************************
3849 * waveOutGetDevCapsA [WINMM.@]
3851 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3852 UINT uSize)
3854 LPWINE_MLD wmld;
3856 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3858 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3860 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
3861 return MMSYSERR_INVALHANDLE;
3863 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
3867 /**************************************************************************
3868 * waveOutGetDevCapsW [WINMM.@]
3870 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3871 UINT uSize)
3873 WAVEOUTCAPSA wocA;
3874 UINT ret;
3876 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3878 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3880 if (ret == MMSYSERR_NOERROR) {
3881 lpCaps->wMid = wocA.wMid;
3882 lpCaps->wPid = wocA.wPid;
3883 lpCaps->vDriverVersion = wocA.vDriverVersion;
3884 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
3885 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
3886 lpCaps->dwFormats = wocA.dwFormats;
3887 lpCaps->wChannels = wocA.wChannels;
3888 lpCaps->dwSupport = wocA.dwSupport;
3890 return ret;
3893 /**************************************************************************
3894 * WAVE_GetErrorText [internal]
3896 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3898 UINT16 ret = MMSYSERR_BADERRNUM;
3900 if (lpText == NULL) {
3901 ret = MMSYSERR_INVALPARAM;
3902 } else if (uSize == 0) {
3903 ret = MMSYSERR_NOERROR;
3904 } else if (
3905 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
3906 * a warning for the test was always true */
3907 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
3908 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
3910 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
3911 uError, lpText, uSize) > 0) {
3912 ret = MMSYSERR_NOERROR;
3915 return ret;
3918 /**************************************************************************
3919 * waveOutGetErrorText [MMSYSTEM.403]
3921 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3923 return WAVE_GetErrorText(uError, lpText, uSize);
3926 /**************************************************************************
3927 * waveOutGetErrorTextA [WINMM.@]
3929 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3931 return WAVE_GetErrorText(uError, lpText, uSize);
3934 /**************************************************************************
3935 * waveOutGetErrorTextW [WINMM.@]
3937 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3939 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3940 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
3942 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
3943 HeapFree(GetProcessHeap(), 0, xstr);
3944 return ret;
3947 /**************************************************************************
3948 * waveOutOpen [WINMM.@]
3949 * All the args/structs have the same layout as the win16 equivalents
3951 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3952 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3953 DWORD dwInstance, DWORD dwFlags)
3955 return MMSYSTEM_waveOpen(lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
3956 dwCallback, dwInstance, dwFlags, TRUE);
3959 /**************************************************************************
3960 * waveOutOpen [MMSYSTEM.404]
3962 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3963 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3964 DWORD dwInstance, DWORD dwFlags)
3966 HWAVEOUT hWaveOut;
3967 UINT ret;
3969 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
3970 * call the 32 bit version
3971 * however, we need to promote correctly the wave mapper id
3972 * (0xFFFFFFFF and not 0x0000FFFF)
3974 ret = MMSYSTEM_waveOpen(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
3975 MMDRV_WAVEOUT, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
3977 if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
3978 return ret;
3981 /**************************************************************************
3982 * waveOutClose [WINMM.@]
3984 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3986 LPWINE_MLD wmld;
3987 DWORD dwRet;
3989 TRACE("(%04X)\n", hWaveOut);
3991 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3992 return MMSYSERR_INVALHANDLE;
3994 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
3995 MMDRV_Free(hWaveOut, wmld);
3997 return dwRet;
4000 /**************************************************************************
4001 * waveOutClose [MMSYSTEM.405]
4003 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
4005 DWORD level;
4006 UINT16 ret;
4008 ReleaseThunkLock(&level);
4009 ret = waveOutClose(hWaveOut);
4010 RestoreThunkLock(level);
4011 return ret;
4014 /**************************************************************************
4015 * waveOutPrepareHeader [WINMM.@]
4017 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
4018 WAVEHDR* lpWaveOutHdr, UINT uSize)
4020 LPWINE_MLD wmld;
4022 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4024 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
4026 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4027 return MMSYSERR_INVALHANDLE;
4029 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4032 /**************************************************************************
4033 * waveOutPrepareHeader [MMSYSTEM.406]
4035 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
4036 SEGPTR lpsegWaveOutHdr, /* [???] */
4037 UINT16 uSize) /* [in] */
4039 LPWINE_MLD wmld;
4040 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
4042 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4044 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
4046 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4047 return MMSYSERR_INVALHANDLE;
4049 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4052 /**************************************************************************
4053 * waveOutUnprepareHeader [WINMM.@]
4055 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
4056 LPWAVEHDR lpWaveOutHdr, UINT uSize)
4058 LPWINE_MLD wmld;
4060 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4062 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
4063 return MMSYSERR_NOERROR;
4066 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4067 return MMSYSERR_INVALHANDLE;
4069 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4072 /**************************************************************************
4073 * waveOutUnprepareHeader [MMSYSTEM.407]
4075 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
4076 SEGPTR lpsegWaveOutHdr, /* [???] */
4077 UINT16 uSize) /* [in] */
4079 LPWINE_MLD wmld;
4080 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
4082 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4084 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
4085 return MMSYSERR_NOERROR;
4088 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4089 return MMSYSERR_INVALHANDLE;
4091 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4094 /**************************************************************************
4095 * waveOutWrite [WINMM.@]
4097 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
4098 UINT uSize)
4100 LPWINE_MLD wmld;
4102 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4104 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4105 return MMSYSERR_INVALHANDLE;
4107 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4110 /**************************************************************************
4111 * waveOutWrite [MMSYSTEM.408]
4113 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */
4114 LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */
4115 UINT16 uSize) /* [in] */
4117 LPWINE_MLD wmld;
4119 TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4121 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4122 return MMSYSERR_INVALHANDLE;
4124 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4127 /**************************************************************************
4128 * waveOutBreakLoop [WINMM.@]
4130 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
4132 LPWINE_MLD wmld;
4134 TRACE("(%04X);\n", hWaveOut);
4136 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4137 return MMSYSERR_INVALHANDLE;
4138 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
4141 /**************************************************************************
4142 * waveOutBreakLoop [MMSYSTEM.419]
4144 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16)
4146 DWORD level;
4147 UINT16 ret;
4149 ReleaseThunkLock(&level);
4150 ret = waveOutBreakLoop(hWaveOut16);
4151 RestoreThunkLock(level);
4152 return ret;
4155 /**************************************************************************
4156 * waveOutPause [WINMM.@]
4158 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
4160 LPWINE_MLD wmld;
4162 TRACE("(%04X);\n", hWaveOut);
4164 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4165 return MMSYSERR_INVALHANDLE;
4166 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
4169 /**************************************************************************
4170 * waveOutPause [MMSYSTEM.409]
4172 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16)
4174 DWORD level;
4175 UINT16 ret;
4177 ReleaseThunkLock(&level);
4178 ret = waveOutPause(hWaveOut16);
4179 RestoreThunkLock(level);
4180 return ret;
4183 /**************************************************************************
4184 * waveOutReset [WINMM.@]
4186 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
4188 LPWINE_MLD wmld;
4190 TRACE("(%04X);\n", hWaveOut);
4192 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4193 return MMSYSERR_INVALHANDLE;
4194 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
4197 /**************************************************************************
4198 * waveOutReset [MMSYSTEM.411]
4200 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16)
4202 DWORD level;
4203 UINT16 ret;
4205 ReleaseThunkLock(&level);
4206 ret = waveOutReset(hWaveOut16);
4207 RestoreThunkLock(level);
4208 return ret;
4211 /**************************************************************************
4212 * waveOutRestart [WINMM.@]
4214 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
4216 LPWINE_MLD wmld;
4218 TRACE("(%04X);\n", hWaveOut);
4220 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4221 return MMSYSERR_INVALHANDLE;
4222 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
4225 /**************************************************************************
4226 * waveOutRestart [MMSYSTEM.410]
4228 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16)
4230 DWORD level;
4231 UINT16 ret;
4233 ReleaseThunkLock(&level);
4234 ret = waveOutRestart(hWaveOut16);
4235 RestoreThunkLock(level);
4236 return ret;
4239 /**************************************************************************
4240 * waveOutGetPosition [WINMM.@]
4242 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
4243 UINT uSize)
4245 LPWINE_MLD wmld;
4247 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
4249 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4250 return MMSYSERR_INVALHANDLE;
4252 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4255 /**************************************************************************
4256 * waveOutGetPosition [MMSYSTEM.412]
4258 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
4259 UINT16 uSize)
4261 UINT ret;
4262 MMTIME mmt;
4264 mmt.wType = lpTime->wType;
4265 ret = waveOutGetPosition(hWaveOut, &mmt, sizeof(mmt));
4266 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4267 return ret;
4270 /**************************************************************************
4271 * waveOutGetPitch [WINMM.@]
4273 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
4275 LPWINE_MLD wmld;
4277 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4279 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4280 return MMSYSERR_INVALHANDLE;
4281 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
4284 /**************************************************************************
4285 * waveOutGetPitch [MMSYSTEM.413]
4287 UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4289 return waveOutGetPitch(hWaveOut16, lpdw);
4292 /**************************************************************************
4293 * waveOutSetPitch [WINMM.@]
4295 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
4297 LPWINE_MLD wmld;
4299 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4301 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4302 return MMSYSERR_INVALHANDLE;
4303 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
4306 /**************************************************************************
4307 * waveOutSetPitch [MMSYSTEM.414]
4309 UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw)
4311 return waveOutSetPitch(hWaveOut16, dw);
4314 /**************************************************************************
4315 * waveOutGetPlaybackRate [WINMM.@]
4317 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
4319 LPWINE_MLD wmld;
4321 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4323 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4324 return MMSYSERR_INVALHANDLE;
4325 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
4328 /**************************************************************************
4329 * waveOutGetPlaybackRate [MMSYSTEM.417]
4331 UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4333 return waveOutGetPlaybackRate(hWaveOut16, lpdw);
4336 /**************************************************************************
4337 * waveOutSetPlaybackRate [WINMM.@]
4339 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
4341 LPWINE_MLD wmld;
4343 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4345 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4346 return MMSYSERR_INVALHANDLE;
4347 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
4350 /**************************************************************************
4351 * waveOutSetPlaybackRate [MMSYSTEM.418]
4353 UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw)
4355 return waveOutSetPlaybackRate(hWaveOut16, dw);
4358 /**************************************************************************
4359 * waveOutGetVolume [WINMM.@]
4361 UINT WINAPI waveOutGetVolume(UINT devid, LPDWORD lpdw)
4363 LPWINE_MLD wmld;
4365 TRACE("(%04X, %08lx);\n", devid, (DWORD)lpdw);
4367 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4368 return MMSYSERR_INVALHANDLE;
4370 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
4373 /**************************************************************************
4374 * waveOutGetVolume [MMSYSTEM.415]
4376 UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw)
4378 return waveOutGetVolume(devid, lpdw);
4381 /**************************************************************************
4382 * waveOutSetVolume [WINMM.@]
4384 UINT WINAPI waveOutSetVolume(UINT devid, DWORD dw)
4386 LPWINE_MLD wmld;
4388 TRACE("(%04X, %08lx);\n", devid, dw);
4390 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4391 return MMSYSERR_INVALHANDLE;
4393 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
4396 /**************************************************************************
4397 * waveOutSetVolume [MMSYSTEM.416]
4399 UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw)
4401 return waveOutSetVolume(devid, dw);
4404 /**************************************************************************
4405 * waveOutGetID [WINMM.@]
4407 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
4409 LPWINE_MLD wmld;
4411 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4413 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4415 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4416 return MMSYSERR_INVALHANDLE;
4418 *lpuDeviceID = wmld->uDeviceID;
4419 return 0;
4422 /**************************************************************************
4423 * waveOutGetID [MMSYSTEM.420]
4425 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
4427 LPWINE_MLD wmld;
4429 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4431 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4433 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4434 return MMSYSERR_INVALHANDLE;
4436 *lpuDeviceID = wmld->uDeviceID;
4437 return 0;
4440 /**************************************************************************
4441 * waveOutMessage [WINMM.@]
4443 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
4444 DWORD dwParam1, DWORD dwParam2)
4446 LPWINE_MLD wmld;
4448 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4450 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4451 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4452 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4454 return MMSYSERR_INVALHANDLE;
4457 /* from M$ KB */
4458 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4459 return MMSYSERR_INVALPARAM;
4461 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4464 /**************************************************************************
4465 * waveOutMessage [MMSYSTEM.421]
4467 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4468 DWORD dwParam1, DWORD dwParam2)
4470 LPWINE_MLD wmld;
4472 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4474 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4475 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4476 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4478 return MMSYSERR_INVALHANDLE;
4481 /* from M$ KB */
4482 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4483 return MMSYSERR_INVALPARAM;
4485 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
4488 /**************************************************************************
4489 * waveInGetNumDevs [WINMM.@]
4491 UINT WINAPI waveInGetNumDevs(void)
4493 return MMDRV_GetNum(MMDRV_WAVEIN);
4496 /**************************************************************************
4497 * waveInGetNumDevs [MMSYSTEM.501]
4499 UINT16 WINAPI waveInGetNumDevs16(void)
4501 return MMDRV_GetNum(MMDRV_WAVEIN);
4504 /**************************************************************************
4505 * waveInGetDevCapsW [WINMM.@]
4507 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4509 WAVEINCAPSA wicA;
4510 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
4512 if (ret == MMSYSERR_NOERROR) {
4513 lpCaps->wMid = wicA.wMid;
4514 lpCaps->wPid = wicA.wPid;
4515 lpCaps->vDriverVersion = wicA.vDriverVersion;
4516 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
4517 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
4518 lpCaps->dwFormats = wicA.dwFormats;
4519 lpCaps->wChannels = wicA.wChannels;
4522 return ret;
4525 /**************************************************************************
4526 * waveInGetDevCapsA [WINMM.@]
4528 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4530 LPWINE_MLD wmld;
4532 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
4534 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
4535 return MMSYSERR_INVALHANDLE;
4537 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
4540 /**************************************************************************
4541 * waveInGetDevCaps [MMSYSTEM.502]
4543 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps,
4544 UINT16 uSize)
4546 WAVEINCAPSA wicA;
4547 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
4549 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
4551 if (ret == MMSYSERR_NOERROR) {
4552 lpCaps->wMid = wicA.wMid;
4553 lpCaps->wPid = wicA.wPid;
4554 lpCaps->vDriverVersion = wicA.vDriverVersion;
4555 strcpy(lpCaps->szPname, wicA.szPname);
4556 lpCaps->dwFormats = wicA.dwFormats;
4557 lpCaps->wChannels = wicA.wChannels;
4559 return ret;
4562 /**************************************************************************
4563 * waveInGetErrorTextA [WINMM.@]
4565 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4567 return WAVE_GetErrorText(uError, lpText, uSize);
4570 /**************************************************************************
4571 * waveInGetErrorTextW [WINMM.@]
4573 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4575 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4576 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
4578 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
4579 HeapFree(GetProcessHeap(), 0, txt);
4580 return ret;
4583 /**************************************************************************
4584 * waveInGetErrorText [MMSYSTEM.503]
4586 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4588 return WAVE_GetErrorText(uError, lpText, uSize);
4591 /**************************************************************************
4592 * waveInOpen [WINMM.@]
4594 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4595 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4596 DWORD dwInstance, DWORD dwFlags)
4598 return MMSYSTEM_waveOpen(lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
4599 dwCallback, dwInstance, dwFlags, TRUE);
4602 /**************************************************************************
4603 * waveInOpen [MMSYSTEM.504]
4605 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4606 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4607 DWORD dwInstance, DWORD dwFlags)
4609 HWAVEIN hWaveIn;
4610 UINT ret;
4612 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
4613 * call the 32 bit version
4614 * however, we need to promote correctly the wave mapper id
4615 * (0xFFFFFFFF and not 0x0000FFFF)
4617 ret = MMSYSTEM_waveOpen(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
4618 MMDRV_WAVEIN, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
4620 if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
4621 return ret;
4624 /**************************************************************************
4625 * waveInClose [WINMM.@]
4627 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4629 LPWINE_MLD wmld;
4630 DWORD dwRet;
4632 TRACE("(%04X)\n", hWaveIn);
4634 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4635 return MMSYSERR_INVALHANDLE;
4637 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
4638 MMDRV_Free(hWaveIn, wmld);
4639 return dwRet;
4642 /**************************************************************************
4643 * waveInClose [MMSYSTEM.505]
4645 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4647 DWORD level;
4648 UINT16 ret;
4650 ReleaseThunkLock(&level);
4651 ret = waveInClose(hWaveIn);
4652 RestoreThunkLock(level);
4653 return ret;
4656 /**************************************************************************
4657 * waveInPrepareHeader [WINMM.@]
4659 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4660 UINT uSize)
4662 LPWINE_MLD wmld;
4664 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4666 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4667 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4668 return MMSYSERR_INVALHANDLE;
4670 lpWaveInHdr->dwBytesRecorded = 0;
4672 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4675 /**************************************************************************
4676 * waveInPrepareHeader [MMSYSTEM.506]
4678 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4679 SEGPTR lpsegWaveInHdr, /* [???] */
4680 UINT16 uSize) /* [in] */
4682 LPWINE_MLD wmld;
4683 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4684 UINT16 ret;
4686 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4688 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4689 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4690 return MMSYSERR_INVALHANDLE;
4692 lpWaveInHdr->dwBytesRecorded = 0;
4694 ret = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4695 return ret;
4698 /**************************************************************************
4699 * waveInUnprepareHeader [WINMM.@]
4701 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4702 UINT uSize)
4704 LPWINE_MLD wmld;
4706 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4708 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4709 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4710 return MMSYSERR_NOERROR;
4713 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4714 return MMSYSERR_INVALHANDLE;
4716 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4719 /**************************************************************************
4720 * waveInUnprepareHeader [MMSYSTEM.507]
4722 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4723 SEGPTR lpsegWaveInHdr, /* [???] */
4724 UINT16 uSize) /* [in] */
4726 LPWINE_MLD wmld;
4727 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4729 TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4731 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4733 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4734 return MMSYSERR_NOERROR;
4737 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4738 return MMSYSERR_INVALHANDLE;
4740 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4743 /**************************************************************************
4744 * waveInAddBuffer [WINMM.@]
4746 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4747 WAVEHDR* lpWaveInHdr, UINT uSize)
4749 LPWINE_MLD wmld;
4751 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4753 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4754 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4755 return MMSYSERR_INVALHANDLE;
4757 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
4760 /**************************************************************************
4761 * waveInAddBuffer [MMSYSTEM.508]
4763 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */
4764 WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */
4765 UINT16 uSize) /* [in] */
4767 LPWINE_MLD wmld;
4769 TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4771 if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4772 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4773 return MMSYSERR_INVALHANDLE;
4775 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4778 /**************************************************************************
4779 * waveInReset [WINMM.@]
4781 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4783 LPWINE_MLD wmld;
4785 TRACE("(%04X);\n", hWaveIn);
4787 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4788 return MMSYSERR_INVALHANDLE;
4790 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
4793 /**************************************************************************
4794 * waveInReset [MMSYSTEM.511]
4796 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16)
4798 DWORD level;
4799 UINT16 ret;
4801 ReleaseThunkLock(&level);
4802 ret = waveInReset(hWaveIn16);
4803 RestoreThunkLock(level);
4804 return ret;
4807 /**************************************************************************
4808 * waveInStart [WINMM.@]
4810 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4812 LPWINE_MLD wmld;
4814 TRACE("(%04X);\n", hWaveIn);
4816 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4817 return MMSYSERR_INVALHANDLE;
4819 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
4822 /**************************************************************************
4823 * waveInStart [MMSYSTEM.509]
4825 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16)
4827 DWORD level;
4828 UINT16 ret;
4830 ReleaseThunkLock(&level);
4831 ret = waveInStart(hWaveIn16);
4832 RestoreThunkLock(level);
4833 return ret;
4836 /**************************************************************************
4837 * waveInStop [WINMM.@]
4839 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4841 LPWINE_MLD wmld;
4843 TRACE("(%04X);\n", hWaveIn);
4845 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4846 return MMSYSERR_INVALHANDLE;
4848 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
4851 /**************************************************************************
4852 * waveInStop [MMSYSTEM.510]
4854 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16)
4856 DWORD level;
4857 UINT16 ret;
4859 ReleaseThunkLock(&level);
4860 ret = waveInStop(hWaveIn16);
4861 RestoreThunkLock(level);
4862 return ret;
4865 /**************************************************************************
4866 * waveInGetPosition [WINMM.@]
4868 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4869 UINT uSize)
4871 LPWINE_MLD wmld;
4873 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4875 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4876 return MMSYSERR_INVALHANDLE;
4878 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4881 /**************************************************************************
4882 * waveInGetPosition [MMSYSTEM.512]
4884 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4885 UINT16 uSize)
4887 UINT ret;
4888 MMTIME mmt;
4890 mmt.wType = lpTime->wType;
4891 ret = waveInGetPosition(hWaveIn, &mmt, sizeof(mmt));
4892 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4893 return ret;
4896 /**************************************************************************
4897 * waveInGetID [WINMM.@]
4899 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4901 LPWINE_MLD wmld;
4903 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4905 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4907 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4908 return MMSYSERR_INVALHANDLE;
4910 *lpuDeviceID = wmld->uDeviceID;
4911 return MMSYSERR_NOERROR;
4914 /**************************************************************************
4915 * waveInGetID [MMSYSTEM.513]
4917 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4919 LPWINE_MLD wmld;
4921 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4923 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4925 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4926 return MMSYSERR_INVALHANDLE;
4928 *lpuDeviceID = wmld->uDeviceID;
4929 return MMSYSERR_NOERROR;
4932 /**************************************************************************
4933 * waveInMessage [WINMM.@]
4935 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4936 DWORD dwParam1, DWORD dwParam2)
4938 LPWINE_MLD wmld;
4940 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4942 /* from M$ KB */
4943 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4944 return MMSYSERR_INVALPARAM;
4946 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4947 return MMSYSERR_INVALHANDLE;
4949 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4952 /**************************************************************************
4953 * waveInMessage [MMSYSTEM.514]
4955 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4956 DWORD dwParam1, DWORD dwParam2)
4958 LPWINE_MLD wmld;
4960 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4962 /* from M$ KB */
4963 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4964 return MMSYSERR_INVALPARAM;
4966 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4967 return MMSYSERR_INVALHANDLE;
4969 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4972 /*#define USE_MM_TSK_WINE*/
4974 /**************************************************************************
4975 * mmTaskCreate [MMSYSTEM.900]
4977 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4978 * called upon creation with dwPmt as parameter.
4980 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4982 HINSTANCE16 ret;
4983 HINSTANCE16 handle;
4984 char cmdline[16];
4985 DWORD showCmd = 0x40002;
4986 LOADPARAMS16 lp;
4988 TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
4989 /* This to work requires NE modules to be started with a binary command line
4990 * which is not currently the case. A patch exists but has never been committed.
4991 * A workaround would be to integrate code for mmtask.tsk into Wine, but
4992 * this requires tremendous work (starting with patching tools/build to
4993 * create NE executables (and not only DLLs) for builtins modules.
4994 * EP 99/04/25
4996 FIXME("This is currently broken. It will fail\n");
4998 cmdline[0] = 0x0d;
4999 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
5000 *(LPDWORD)(cmdline + 5) = dwPmt;
5001 *(LPDWORD)(cmdline + 9) = 0;
5003 lp.hEnvironment = 0;
5004 lp.cmdLine = MapLS(cmdline);
5005 lp.showCmd = MapLS(&showCmd);
5006 lp.reserved = 0;
5008 #ifndef USE_MM_TSK_WINE
5009 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp);
5010 #else
5011 handle = LoadModule16("mmtask.tsk", &lp);
5012 #endif
5013 if (handle < 32) {
5014 ret = (handle) ? 1 : 2;
5015 handle = 0;
5016 } else {
5017 ret = 0;
5019 if (lphMmTask)
5020 *lphMmTask = handle;
5022 UnMapLS( lp.cmdLine );
5023 UnMapLS( lp.showCmd );
5024 TRACE("=> 0x%04x/%d\n", handle, ret);
5025 return ret;
5028 #ifdef USE_MM_TSK_WINE
5029 /* C equivalent to mmtask.tsk binary content */
5030 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
5032 int len = cmdLine[0x80];
5034 if (len / 2 == 6) {
5035 void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1)));
5036 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
5038 #if 0
5039 InitTask16(); /* FIXME: pmts / from context ? */
5040 InitApp(di);
5041 #endif
5042 if (SetMessageQueue16(0x40)) {
5043 WaitEvent16(0);
5044 if (HIWORD(fpProc)) {
5045 OldYield16();
5046 /* EPP StackEnter16(); */
5047 (fpProc)(dwPmt);
5051 OldYield16();
5052 OldYield16();
5053 OldYield16();
5054 ExitProcess(0);
5056 #endif
5058 /**************************************************************************
5059 * mmTaskBlock [MMSYSTEM.902]
5061 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
5063 MSG msg;
5065 do {
5066 GetMessageA(&msg, 0, 0, 0);
5067 if (msg.hwnd) {
5068 TranslateMessage(&msg);
5069 DispatchMessageA(&msg);
5071 } while (msg.message < 0x3A0);
5074 /**************************************************************************
5075 * mmTaskSignal [MMSYSTEM.903]
5077 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
5079 TRACE("(%04x);\n", ht);
5080 return PostAppMessage16(ht, WM_USER, 0, 0);
5083 /**************************************************************************
5084 * mmGetCurrentTask [MMSYSTEM.904]
5086 HTASK16 WINAPI mmGetCurrentTask16(void)
5088 return GetCurrentTask();
5091 /**************************************************************************
5092 * mmTaskYield [MMSYSTEM.905]
5094 void WINAPI mmTaskYield16(void)
5096 MSG msg;
5098 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
5099 K32WOWYield16();
5103 DWORD WINAPI GetProcessFlags(DWORD);
5105 /**************************************************************************
5106 * mmThreadCreate [MMSYSTEM.1120]
5108 * undocumented
5109 * Creates a MM thread, calling fpThreadAddr(dwPmt).
5110 * dwFlags:
5111 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
5112 * bit.1 set means to open a VxD for this thread (unsupported)
5114 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
5116 HANDLE16 hndl;
5117 LRESULT ret;
5119 TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
5121 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
5123 if (hndl == 0) {
5124 ret = 2;
5125 } else {
5126 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5128 #if 0
5129 /* force mmtask routines even if mmthread is required */
5130 /* this will work only if the patch about binary cmd line and NE tasks
5131 * is committed
5133 dwFlags |= 1;
5134 #endif
5136 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
5137 lpMMThd->dwCounter = 0;
5138 lpMMThd->hThread = 0;
5139 lpMMThd->dwThreadID = 0;
5140 lpMMThd->fpThread = fpThreadAddr;
5141 lpMMThd->dwThreadPmt = dwPmt;
5142 lpMMThd->dwSignalCount = 0;
5143 lpMMThd->hEvent = 0;
5144 lpMMThd->hVxD = 0;
5145 lpMMThd->dwStatus = 0;
5146 lpMMThd->dwFlags = dwFlags;
5147 lpMMThd->hTask = 0;
5149 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
5150 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
5152 TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
5153 if (lpMMThd->dwFlags & 2) {
5154 /* as long as we don't support MM VxD in wine, we don't need
5155 * to care about this flag
5157 /* FIXME("Don't know how to properly open VxD handles\n"); */
5158 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
5161 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
5162 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
5163 if (lpMMThd->hThread == 0) {
5164 WARN("Couldn't create thread\n");
5165 /* clean-up(VxDhandle...); devicedirectio... */
5166 if (lpMMThd->hEvent != 0)
5167 CloseHandle(lpMMThd->hEvent);
5168 ret = 2;
5169 } else {
5170 TRACE("Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
5171 ret = 0;
5173 } else {
5174 /* get WINE_mmThreadEntryPoint()
5175 * 2047 is its ordinal in mmsystem.spec
5177 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047);
5179 TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp));
5181 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
5184 if (ret == 0) {
5185 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
5186 WARN("Couldn't resume thread\n");
5188 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
5189 UserYield16();
5194 if (ret != 0) {
5195 GlobalFree16(hndl);
5196 hndl = 0;
5199 if (lpHndl)
5200 *lpHndl = hndl;
5202 TRACE("ok => %ld\n", ret);
5203 return ret;
5206 /**************************************************************************
5207 * mmThreadSignal [MMSYSTEM.1121]
5209 void WINAPI mmThreadSignal16(HANDLE16 hndl)
5211 TRACE("(%04x)!\n", hndl);
5213 if (hndl) {
5214 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5216 lpMMThd->dwCounter++;
5217 if (lpMMThd->hThread != 0) {
5218 InterlockedIncrement(&lpMMThd->dwSignalCount);
5219 SetEvent(lpMMThd->hEvent);
5220 } else {
5221 mmTaskSignal16(lpMMThd->hTask);
5223 lpMMThd->dwCounter--;
5227 /**************************************************************************
5228 * MMSYSTEM_ThreadBlock [internal]
5230 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
5232 MSG msg;
5233 DWORD ret;
5235 if (lpMMThd->dwThreadID != GetCurrentThreadId())
5236 ERR("Not called by thread itself\n");
5238 for (;;) {
5239 ResetEvent(lpMMThd->hEvent);
5240 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
5241 break;
5242 InterlockedIncrement(&lpMMThd->dwSignalCount);
5244 TRACE("S1\n");
5246 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
5247 switch (ret) {
5248 case WAIT_OBJECT_0: /* Event */
5249 TRACE("S2.1\n");
5250 break;
5251 case WAIT_OBJECT_0 + 1: /* Msg */
5252 TRACE("S2.2\n");
5253 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
5254 TranslateMessage(&msg);
5255 DispatchMessageA(&msg);
5257 break;
5258 default:
5259 WARN("S2.x unsupported ret val 0x%08lx\n", ret);
5261 TRACE("S3\n");
5265 /**************************************************************************
5266 * mmThreadBlock [MMSYSTEM.1122]
5268 void WINAPI mmThreadBlock16(HANDLE16 hndl)
5270 TRACE("(%04x)!\n", hndl);
5272 if (hndl) {
5273 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5275 if (lpMMThd->hThread != 0) {
5276 DWORD lc;
5278 ReleaseThunkLock(&lc);
5279 MMSYSTEM_ThreadBlock(lpMMThd);
5280 RestoreThunkLock(lc);
5281 } else {
5282 mmTaskBlock16(lpMMThd->hTask);
5285 TRACE("done\n");
5288 /**************************************************************************
5289 * mmThreadIsCurrent [MMSYSTEM.1123]
5291 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
5293 BOOL16 ret = FALSE;
5295 TRACE("(%04x)!\n", hndl);
5297 if (hndl && mmThreadIsValid16(hndl)) {
5298 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5299 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
5301 TRACE("=> %d\n", ret);
5302 return ret;
5305 /**************************************************************************
5306 * mmThreadIsValid [MMSYSTEM.1124]
5308 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
5310 BOOL16 ret = FALSE;
5312 TRACE("(%04x)!\n", hndl);
5314 if (hndl) {
5315 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5317 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
5318 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
5319 IsTask16(lpMMThd->hTask)) {
5320 lpMMThd->dwCounter++;
5321 if (lpMMThd->hThread != 0) {
5322 DWORD dwThreadRet;
5323 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
5324 dwThreadRet == STATUS_PENDING) {
5325 ret = TRUE;
5327 } else {
5328 ret = TRUE;
5330 lpMMThd->dwCounter--;
5333 TRACE("=> %d\n", ret);
5334 return ret;
5337 /**************************************************************************
5338 * mmThreadGetTask [MMSYSTEM.1125]
5340 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5342 HANDLE16 ret = 0;
5344 TRACE("(%04x)\n", hndl);
5346 if (mmThreadIsValid16(hndl)) {
5347 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5348 ret = lpMMThd->hTask;
5350 return ret;
5353 /* ### start build ### */
5354 extern LONG CALLBACK MMSYSTEM_CallTo16_long_l (FARPROC16,LONG);
5355 /* ### stop build ### */
5357 /**************************************************************************
5358 * __wine_mmThreadEntryPoint (MMSYSTEM.2047)
5360 void WINAPI WINE_mmThreadEntryPoint(DWORD _pmt)
5362 HANDLE16 hndl = (HANDLE16)_pmt;
5363 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5365 TRACE("(%04x %p)\n", hndl, lpMMThd);
5367 lpMMThd->hTask = LOWORD(GetCurrentTask());
5368 TRACE("[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5369 lpMMThd->dwStatus = 0x10;
5370 MMSYSTEM_ThreadBlock(lpMMThd);
5371 TRACE("[20-%08x]\n", lpMMThd->hThread);
5372 lpMMThd->dwStatus = 0x20;
5373 if (lpMMThd->fpThread) {
5374 MMSYSTEM_CallTo16_long_l(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5376 lpMMThd->dwStatus = 0x30;
5377 TRACE("[30-%08x]\n", lpMMThd->hThread);
5378 while (lpMMThd->dwCounter) {
5379 Sleep(1);
5380 /* K32WOWYield16();*/
5382 TRACE("[XX-%08x]\n", lpMMThd->hThread);
5383 /* paranoia */
5384 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5385 /* close lpMMThread->hVxD directIO */
5386 if (lpMMThd->hEvent)
5387 CloseHandle(lpMMThd->hEvent);
5388 GlobalFree16(hndl);
5389 TRACE("done\n");
5392 typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR);
5394 /**************************************************************************
5395 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5397 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice,
5398 LPCSTR lpStrTab, LPCSTR lpStrTitle)
5400 HANDLE hndl;
5401 BOOL16 ret = FALSE;
5403 TRACE("(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5405 hndl = LoadLibraryA("MMSYS.CPL");
5406 if (hndl != 0) {
5407 MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5408 if (fp != NULL) {
5409 DWORD lc;
5410 ReleaseThunkLock(&lc);
5411 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5412 RestoreThunkLock(lc);
5414 FreeLibrary(hndl);
5417 return ret;
5420 /**************************************************************************
5421 * StackEnter [MMSYSTEM.32]
5423 void WINAPI StackEnter16(void)
5425 #ifdef __i386__
5426 /* mmsystem.dll from Win 95 does only this: so does Wine */
5427 __asm__("stc");
5428 #endif
5431 /**************************************************************************
5432 * StackLeave [MMSYSTEM.33]
5434 void WINAPI StackLeave16(void)
5436 #ifdef __i386__
5437 /* mmsystem.dll from Win 95 does only this: so does Wine */
5438 __asm__("stc");
5439 #endif
5442 /**************************************************************************
5443 * WMMMidiRunOnce [MMSYSTEM.8]
5445 void WINAPI WMMMidiRunOnce16(void)
5447 FIXME("(), stub!\n");
5450 /**************************************************************************
5451 * OutputDebugStr [MMSYSTEM.30]
5453 void WINAPI OutputDebugStr16(
5454 LPCSTR str) /* [in] The message to be logged and given to the debugger. */
5456 OutputDebugStringA( str );