Prepare dlls/{comctl32,gdi,msvideo,setupapi,shell32,twain,winmm} for
[wine/multimedia.git] / dlls / winmm / mmsystem.c
blob42cbf8dd13ebca0baf007d7370f774538e6c70ca
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
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 HWAVEOUT 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 s.dwEventCount = 1L; /* for first buffer */
554 do {
555 index = 0;
556 left = mmckInfo.cksize;
558 mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
559 while (left)
561 if (WaitForSingleObject(iData->psStopEvent, 0) == WAIT_OBJECT_0)
563 wps->bLoop = FALSE;
564 break;
566 count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
567 if (count < 1) break;
568 left -= count;
569 waveHdr[index].dwBufferLength = count;
570 waveHdr[index].dwFlags &= ~WHDR_DONE;
571 if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) {
572 index ^= 1;
573 PlaySound_WaitDone(&s);
575 else FIXME("Couldn't play header\n");
577 bRet = TRUE;
578 } while (wps->bLoop);
580 PlaySound_WaitDone(&s); /* for last buffer */
581 waveOutReset(hWave);
583 waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
584 waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
586 errCleanUp:
587 TRACE("Done playing='%s' => %s!\n", debugstr_w(wps->pszSound), bRet ? "ok" : "ko");
588 CloseHandle(s.hEvent);
589 if (waveHdr) HeapFree(GetProcessHeap(), 0, waveHdr);
590 if (lpWaveFormat) HeapFree(GetProcessHeap(), 0, lpWaveFormat);
591 if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
592 if (hmmio) mmioClose(hmmio, 0);
594 PlaySound_Free(wps);
596 return bRet;
599 static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode)
601 WINE_PLAYSOUND* wps = NULL;
602 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
604 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
605 pszSound, hmod, fdwSound);
607 /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP !
608 * there could be one if several sounds can be played at once...
610 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound != NULL)
611 return FALSE;
613 /* alloc internal structure, if we need to play something */
614 if (pszSound && !(fdwSound & SND_PURGE))
616 if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode)))
617 return FALSE;
620 EnterCriticalSection(&iData->cs);
621 /* since several threads can enter PlaySound in parallel, we're not
622 * sure, at this point, that another thread didn't start a new playsound
624 while (iData->lpPlaySound != NULL)
626 ResetEvent(iData->psLastEvent);
627 /* FIXME: doc says we have to stop all instances of pszSound if it's non
628 * NULL... as of today, we stop all playing instances */
629 SetEvent(iData->psStopEvent);
631 LeaveCriticalSection(&iData->cs);
632 WaitForSingleObject(iData->psLastEvent, INFINITE);
633 EnterCriticalSection(&iData->cs);
635 ResetEvent(iData->psStopEvent);
638 if (wps) wps->lpNext = iData->lpPlaySound;
639 iData->lpPlaySound = wps;
640 LeaveCriticalSection(&iData->cs);
642 if (!pszSound || (fdwSound & SND_PURGE)) return TRUE;
644 if (fdwSound & SND_ASYNC)
646 DWORD id;
647 wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE;
648 if (CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id) != 0)
649 return TRUE;
651 else return proc_PlaySound(wps);
653 /* error cases */
654 PlaySound_Free(wps);
655 return FALSE;
658 /**************************************************************************
659 * PlaySoundA [WINMM.@]
661 BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound)
663 return MULTIMEDIA_PlaySound(pszSoundA, hmod, fdwSound, FALSE);
666 /**************************************************************************
667 * PlaySoundW [WINMM.@]
669 BOOL WINAPI PlaySoundW(LPCWSTR pszSoundW, HMODULE hmod, DWORD fdwSound)
671 return MULTIMEDIA_PlaySound(pszSoundW, hmod, fdwSound, TRUE);
674 /**************************************************************************
675 * PlaySound [MMSYSTEM.3]
677 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
679 BOOL16 retv;
680 DWORD lc;
682 ReleaseThunkLock(&lc);
683 retv = PlaySoundA(pszSound, hmod, fdwSound);
684 RestoreThunkLock(lc);
686 return retv;
689 /**************************************************************************
690 * sndPlaySoundA [WINMM.@]
692 BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags)
694 uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC;
695 return MULTIMEDIA_PlaySound(pszSoundA, 0, uFlags, FALSE);
698 /**************************************************************************
699 * sndPlaySoundW [WINMM.@]
701 BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags)
703 uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC;
704 return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, TRUE);
707 /**************************************************************************
708 * sndPlaySound [MMSYSTEM.2]
710 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
712 BOOL16 retv;
713 DWORD lc;
715 ReleaseThunkLock(&lc);
716 retv = sndPlaySoundA(lpszSoundName, uFlags);
717 RestoreThunkLock(lc);
719 return retv;
722 /**************************************************************************
723 * mmsystemGetVersion [MMSYSTEM.5]
724 * return value borrowed from Win95 winmm.dll ;)
726 UINT16 WINAPI mmsystemGetVersion16(void)
728 return mmsystemGetVersion();
731 /**************************************************************************
732 * mmsystemGetVersion [WINMM.@]
734 UINT WINAPI mmsystemGetVersion(void)
736 TRACE("3.10 (Win95?)\n");
737 return 0x030a;
740 /**************************************************************************
741 * DriverCallback [WINMM.@]
743 BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
744 UINT wMsg, DWORD dwUser, DWORD dwParam1,
745 DWORD dwParam2)
747 TRACE("(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
748 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
750 switch (uFlags & DCB_TYPEMASK) {
751 case DCB_NULL:
752 TRACE("Null !\n");
753 if (dwCallBack)
754 WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack);
755 break;
756 case DCB_WINDOW:
757 TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
758 PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
759 break;
760 case DCB_TASK: /* aka DCB_THREAD */
761 TRACE("Task(%04lx) !\n", dwCallBack);
762 PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
763 break;
764 case DCB_FUNCTION:
765 TRACE("Function (32 bit) !\n");
766 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
767 break;
768 case DCB_EVENT:
769 TRACE("Event(%08lx) !\n", dwCallBack);
770 SetEvent((HANDLE)dwCallBack);
771 break;
772 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
773 /* this is an undocumented DCB_ value used for mmThreads
774 * loword of dwCallBack contains the handle of the lpMMThd block
775 * which dwSignalCount has to be incremented
778 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(LOWORD(dwCallBack), 0) );
780 TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
781 /* same as mmThreadSignal16 */
782 InterlockedIncrement(&lpMMThd->dwSignalCount);
783 SetEvent(lpMMThd->hEvent);
784 /* some other stuff on lpMMThd->hVxD */
786 break;
787 #if 0
788 case 4:
789 /* this is an undocumented DCB_ value for... I don't know */
790 break;
791 #endif
792 default:
793 WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
794 return FALSE;
796 TRACE("Done\n");
797 return TRUE;
800 /**************************************************************************
801 * DriverCallback [MMSYSTEM.31]
803 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev,
804 WORD wMsg, DWORD dwUser, DWORD dwParam1,
805 DWORD dwParam2)
807 return DriverCallback(dwCallBack, uFlags, HDRVR_32(hDev), wMsg, dwUser, dwParam1, dwParam2);
810 /**************************************************************************
811 * Mixer devices. New to Win95
814 /**************************************************************************
815 * find out the real mixer ID depending on hmix (depends on dwFlags)
817 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
819 LPWINE_MIXER lpwm = NULL;
821 switch (dwFlags & 0xF0000000ul) {
822 case MIXER_OBJECTF_MIXER:
823 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
824 break;
825 case MIXER_OBJECTF_HMIXER:
826 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
827 break;
828 case MIXER_OBJECTF_WAVEOUT:
829 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
830 break;
831 case MIXER_OBJECTF_HWAVEOUT:
832 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
833 break;
834 case MIXER_OBJECTF_WAVEIN:
835 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
836 break;
837 case MIXER_OBJECTF_HWAVEIN:
838 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
839 break;
840 case MIXER_OBJECTF_MIDIOUT:
841 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
842 break;
843 case MIXER_OBJECTF_HMIDIOUT:
844 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
845 break;
846 case MIXER_OBJECTF_MIDIIN:
847 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
848 break;
849 case MIXER_OBJECTF_HMIDIIN:
850 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
851 break;
852 case MIXER_OBJECTF_AUX:
853 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
854 break;
855 default:
856 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
857 break;
859 return lpwm;
862 /**************************************************************************
863 * mixerGetNumDevs [WINMM.@]
865 UINT WINAPI mixerGetNumDevs(void)
867 return MMDRV_GetNum(MMDRV_MIXER);
870 /**************************************************************************
871 * mixerGetNumDevs [MMSYSTEM.800]
873 UINT16 WINAPI mixerGetNumDevs16(void)
875 return MMDRV_GetNum(MMDRV_MIXER);
878 /**************************************************************************
879 * mixerGetDevCapsA [WINMM.@]
881 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
883 LPWINE_MLD wmld;
885 if ((wmld = MMDRV_Get(devid, MMDRV_MIXER, TRUE)) == NULL)
886 return MMSYSERR_BADDEVICEID;
888 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
891 /**************************************************************************
892 * mixerGetDevCapsW [WINMM.@]
894 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
896 MIXERCAPSA micA;
897 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
899 if (ret == MMSYSERR_NOERROR) {
900 mixcaps->wMid = micA.wMid;
901 mixcaps->wPid = micA.wPid;
902 mixcaps->vDriverVersion = micA.vDriverVersion;
903 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
904 sizeof(mixcaps->szPname)/sizeof(WCHAR) );
905 mixcaps->fdwSupport = micA.fdwSupport;
906 mixcaps->cDestinations = micA.cDestinations;
908 return ret;
911 /**************************************************************************
912 * mixerGetDevCaps [MMSYSTEM.801]
914 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps,
915 UINT16 size)
917 MIXERCAPSA micA;
918 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
920 if (ret == MMSYSERR_NOERROR) {
921 mixcaps->wMid = micA.wMid;
922 mixcaps->wPid = micA.wPid;
923 mixcaps->vDriverVersion = micA.vDriverVersion;
924 strcpy(mixcaps->szPname, micA.szPname);
925 mixcaps->fdwSupport = micA.fdwSupport;
926 mixcaps->cDestinations = micA.cDestinations;
928 return ret;
931 static UINT MMSYSTEM_mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
932 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
934 HMIXER hMix;
935 LPWINE_MLD wmld;
936 DWORD dwRet = 0;
937 MIXEROPENDESC mod;
939 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
940 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
942 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
943 &dwCallback, &dwInstance, bFrom32);
945 wmld->uDeviceID = uDeviceID;
946 mod.hmx = (HMIXEROBJ)hMix;
947 mod.dwCallback = dwCallback;
948 mod.dwInstance = dwInstance;
950 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
952 if (dwRet != MMSYSERR_NOERROR) {
953 MMDRV_Free(hMix, wmld);
954 hMix = 0;
956 if (lphMix) *lphMix = hMix;
957 TRACE("=> %ld hMixer=%04x\n", dwRet, hMix);
959 return dwRet;
962 /**************************************************************************
963 * mixerOpen [WINMM.@]
965 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
966 DWORD dwInstance, DWORD fdwOpen)
968 return MMSYSTEM_mixerOpen(lphMix, uDeviceID,
969 dwCallback, dwInstance, fdwOpen, TRUE);
972 /**************************************************************************
973 * mixerOpen [MMSYSTEM.802]
975 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
976 DWORD dwInstance, DWORD fdwOpen)
978 HMIXER hmix;
979 UINT ret;
981 ret = MMSYSTEM_mixerOpen(&hmix, uDeviceID,
982 dwCallback, dwInstance, fdwOpen, FALSE);
983 if (lphmix) *lphmix = HMIXER_16(hmix);
984 return ret;
987 /**************************************************************************
988 * mixerClose [WINMM.@]
990 UINT WINAPI mixerClose(HMIXER hMix)
992 LPWINE_MLD wmld;
993 DWORD dwRet;
995 TRACE("(%04x)\n", hMix);
997 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
999 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
1000 MMDRV_Free(hMix, wmld);
1002 return dwRet;
1005 /**************************************************************************
1006 * mixerClose [MMSYSTEM.803]
1008 UINT16 WINAPI mixerClose16(HMIXER16 hMix)
1010 return mixerClose(HMIXER_32(hMix));
1013 /**************************************************************************
1014 * mixerGetID [WINMM.@]
1016 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
1018 LPWINE_MIXER lpwm;
1020 TRACE("(%04x %p %08lx)\n", hmix, lpid, fdwID);
1022 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
1023 return MMSYSERR_INVALHANDLE;
1026 if (lpid)
1027 *lpid = lpwm->mld.uDeviceID;
1029 return MMSYSERR_NOERROR;
1032 /**************************************************************************
1033 * mixerGetID (MMSYSTEM.806)
1035 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
1037 UINT xid;
1038 UINT ret = mixerGetID(HMIXEROBJ_32(hmix), &xid, fdwID);
1040 if (lpid)
1041 *lpid = xid;
1042 return ret;
1045 /**************************************************************************
1046 * mixerGetControlDetailsA [WINMM.@]
1048 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1049 DWORD fdwDetails)
1051 LPWINE_MIXER lpwm;
1053 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1055 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1056 return MMSYSERR_INVALHANDLE;
1058 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
1059 return MMSYSERR_INVALPARAM;
1061 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
1062 fdwDetails, TRUE);
1065 /**************************************************************************
1066 * mixerGetControlDetailsW [WINMM.@]
1068 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
1070 DWORD ret = MMSYSERR_NOTENABLED;
1072 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1074 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1075 return MMSYSERR_INVALPARAM;
1077 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
1078 case MIXER_GETCONTROLDETAILSF_VALUE:
1079 /* can savely use W structure as it is, no string inside */
1080 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
1081 break;
1082 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
1084 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
1085 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
1086 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1087 int i;
1089 if (lpmcd->u.cMultipleItems != 0) {
1090 size *= lpmcd->u.cMultipleItems;
1092 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
1093 lpmcd->paDetails = pDetailsA;
1094 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1095 /* set up lpmcd->paDetails */
1096 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
1097 /* copy from lpmcd->paDetails back to paDetailsW; */
1098 if(ret == MMSYSERR_NOERROR) {
1099 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
1100 pDetailsW->dwParam1 = pDetailsA->dwParam1;
1101 pDetailsW->dwParam2 = pDetailsA->dwParam2;
1102 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
1103 pDetailsW->szName,
1104 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
1105 pDetailsA++;
1106 pDetailsW++;
1108 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
1109 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
1111 HeapFree(GetProcessHeap(), 0, pDetailsA);
1112 lpmcd->paDetails = pDetailsW;
1113 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
1115 break;
1116 default:
1117 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
1120 return ret;
1123 /**************************************************************************
1124 * mixerGetControlDetails [MMSYSTEM.808]
1126 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix,
1127 LPMIXERCONTROLDETAILS16 lpmcd,
1128 DWORD fdwDetails)
1130 DWORD ret = MMSYSERR_NOTENABLED;
1131 SEGPTR sppaDetails;
1133 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1135 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1136 return MMSYSERR_INVALPARAM;
1138 sppaDetails = (SEGPTR)lpmcd->paDetails;
1139 lpmcd->paDetails = MapSL(sppaDetails);
1140 ret = mixerGetControlDetailsA(HMIXEROBJ_32(hmix),
1141 (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails);
1142 lpmcd->paDetails = (LPVOID)sppaDetails;
1144 return ret;
1147 /**************************************************************************
1148 * mixerGetLineControlsA [WINMM.@]
1150 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
1151 DWORD fdwControls)
1153 LPWINE_MIXER lpwm;
1155 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
1157 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
1158 return MMSYSERR_INVALHANDLE;
1160 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
1161 return MMSYSERR_INVALPARAM;
1163 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
1164 fdwControls, TRUE);
1167 /**************************************************************************
1168 * mixerGetLineControlsW [WINMM.@]
1170 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
1171 DWORD fdwControls)
1173 MIXERLINECONTROLSA mlcA;
1174 DWORD ret;
1175 int i;
1177 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
1179 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
1180 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
1181 return MMSYSERR_INVALPARAM;
1183 mlcA.cbStruct = sizeof(mlcA);
1184 mlcA.dwLineID = lpmlcW->dwLineID;
1185 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
1186 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
1187 mlcA.cControls = lpmlcW->cControls;
1188 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1189 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1190 mlcA.cControls * mlcA.cbmxctrl);
1192 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
1194 if (ret == MMSYSERR_NOERROR) {
1195 lpmlcW->dwLineID = mlcA.dwLineID;
1196 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
1197 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
1198 lpmlcW->cControls = mlcA.cControls;
1200 for (i = 0; i < mlcA.cControls; i++) {
1201 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
1202 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1203 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1204 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1205 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1206 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
1207 lpmlcW->pamxctrl[i].szShortName,
1208 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
1209 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
1210 lpmlcW->pamxctrl[i].szName,
1211 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
1212 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
1213 * sizeof(mlcA.pamxctrl[i].Bounds) */
1214 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1215 sizeof(mlcA.pamxctrl[i].Bounds));
1216 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
1217 * sizeof(mlcA.pamxctrl[i].Metrics) */
1218 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1219 sizeof(mlcA.pamxctrl[i].Metrics));
1223 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1225 return ret;
1228 /**************************************************************************
1229 * mixerGetLineControls [MMSYSTEM.807]
1231 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix,
1232 LPMIXERLINECONTROLS16 lpmlc16,
1233 DWORD fdwControls)
1235 MIXERLINECONTROLSA mlcA;
1236 DWORD ret;
1237 int i;
1238 LPMIXERCONTROL16 lpmc16;
1240 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls);
1242 if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) ||
1243 lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16))
1244 return MMSYSERR_INVALPARAM;
1246 mlcA.cbStruct = sizeof(mlcA);
1247 mlcA.dwLineID = lpmlc16->dwLineID;
1248 mlcA.u.dwControlID = lpmlc16->u.dwControlID;
1249 mlcA.u.dwControlType = lpmlc16->u.dwControlType;
1250 mlcA.cControls = lpmlc16->cControls;
1251 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1252 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1253 mlcA.cControls * mlcA.cbmxctrl);
1255 ret = mixerGetLineControlsA(HMIXEROBJ_32(hmix), &mlcA, fdwControls);
1257 if (ret == MMSYSERR_NOERROR) {
1258 lpmlc16->dwLineID = mlcA.dwLineID;
1259 lpmlc16->u.dwControlID = mlcA.u.dwControlID;
1260 lpmlc16->u.dwControlType = mlcA.u.dwControlType;
1261 lpmlc16->cControls = mlcA.cControls;
1263 lpmc16 = MapSL(lpmlc16->pamxctrl);
1265 for (i = 0; i < mlcA.cControls; i++) {
1266 lpmc16[i].cbStruct = sizeof(MIXERCONTROL16);
1267 lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1268 lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1269 lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1270 lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1271 strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName);
1272 strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName);
1273 /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
1274 memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1275 sizeof(mlcA.pamxctrl[i].Bounds));
1276 /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
1277 memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1278 sizeof(mlcA.pamxctrl[i].Metrics));
1282 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1284 return ret;
1287 /**************************************************************************
1288 * mixerGetLineInfoA [WINMM.@]
1290 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
1292 LPWINE_MIXER lpwm;
1294 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1296 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
1297 return MMSYSERR_INVALHANDLE;
1299 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
1300 fdwInfo, TRUE);
1303 /**************************************************************************
1304 * mixerGetLineInfoW [WINMM.@]
1306 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
1307 DWORD fdwInfo)
1309 MIXERLINEA mliA;
1310 UINT ret;
1312 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1314 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
1315 return MMSYSERR_INVALPARAM;
1317 mliA.cbStruct = sizeof(mliA);
1318 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1319 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1320 mliA.dwComponentType = lpmliW->dwComponentType;
1321 break;
1322 case MIXER_GETLINEINFOF_DESTINATION:
1323 mliA.dwDestination = lpmliW->dwDestination;
1324 break;
1325 case MIXER_GETLINEINFOF_LINEID:
1326 mliA.dwLineID = lpmliW->dwLineID;
1327 break;
1328 case MIXER_GETLINEINFOF_SOURCE:
1329 mliA.dwDestination = lpmliW->dwDestination;
1330 mliA.dwSource = lpmliW->dwSource;
1331 break;
1332 case MIXER_GETLINEINFOF_TARGETTYPE:
1333 mliA.Target.dwType = lpmliW->Target.dwType;
1334 mliA.Target.wMid = lpmliW->Target.wMid;
1335 mliA.Target.wPid = lpmliW->Target.wPid;
1336 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
1337 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
1338 break;
1339 default:
1340 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1343 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1345 lpmliW->dwDestination = mliA.dwDestination;
1346 lpmliW->dwSource = mliA.dwSource;
1347 lpmliW->dwLineID = mliA.dwLineID;
1348 lpmliW->fdwLine = mliA.fdwLine;
1349 lpmliW->dwUser = mliA.dwUser;
1350 lpmliW->dwComponentType = mliA.dwComponentType;
1351 lpmliW->cChannels = mliA.cChannels;
1352 lpmliW->cConnections = mliA.cConnections;
1353 lpmliW->cControls = mliA.cControls;
1354 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
1355 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
1356 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
1357 sizeof(lpmliW->szName)/sizeof(WCHAR) );
1358 lpmliW->Target.dwType = mliA.Target.dwType;
1359 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
1360 lpmliW->Target.wMid = mliA.Target.wMid;
1361 lpmliW->Target.wPid = mliA.Target.wPid;
1362 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
1363 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
1364 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
1366 return ret;
1369 /**************************************************************************
1370 * mixerGetLineInfo [MMSYSTEM.805]
1372 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16,
1373 DWORD fdwInfo)
1375 MIXERLINEA mliA;
1376 UINT ret;
1378 TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo);
1380 if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16))
1381 return MMSYSERR_INVALPARAM;
1383 mliA.cbStruct = sizeof(mliA);
1384 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1385 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1386 mliA.dwComponentType = lpmli16->dwComponentType;
1387 break;
1388 case MIXER_GETLINEINFOF_DESTINATION:
1389 mliA.dwDestination = lpmli16->dwDestination;
1390 break;
1391 case MIXER_GETLINEINFOF_LINEID:
1392 mliA.dwLineID = lpmli16->dwLineID;
1393 break;
1394 case MIXER_GETLINEINFOF_SOURCE:
1395 mliA.dwDestination = lpmli16->dwDestination;
1396 mliA.dwSource = lpmli16->dwSource;
1397 break;
1398 case MIXER_GETLINEINFOF_TARGETTYPE:
1399 mliA.Target.dwType = lpmli16->Target.dwType;
1400 mliA.Target.wMid = lpmli16->Target.wMid;
1401 mliA.Target.wPid = lpmli16->Target.wPid;
1402 mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion;
1403 strcpy(mliA.Target.szPname, lpmli16->Target.szPname);
1404 break;
1405 default:
1406 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1409 ret = mixerGetLineInfoA(HMIXEROBJ_32(hmix), &mliA, fdwInfo);
1411 lpmli16->dwDestination = mliA.dwDestination;
1412 lpmli16->dwSource = mliA.dwSource;
1413 lpmli16->dwLineID = mliA.dwLineID;
1414 lpmli16->fdwLine = mliA.fdwLine;
1415 lpmli16->dwUser = mliA.dwUser;
1416 lpmli16->dwComponentType = mliA.dwComponentType;
1417 lpmli16->cChannels = mliA.cChannels;
1418 lpmli16->cConnections = mliA.cConnections;
1419 lpmli16->cControls = mliA.cControls;
1420 strcpy(lpmli16->szShortName, mliA.szShortName);
1421 strcpy(lpmli16->szName, mliA.szName);
1422 lpmli16->Target.dwType = mliA.Target.dwType;
1423 lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID;
1424 lpmli16->Target.wMid = mliA.Target.wMid;
1425 lpmli16->Target.wPid = mliA.Target.wPid;
1426 lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion;
1427 strcpy(lpmli16->Target.szPname, mliA.Target.szPname);
1429 return ret;
1432 /**************************************************************************
1433 * mixerSetControlDetails [WINMM.@]
1435 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1436 DWORD fdwDetails)
1438 LPWINE_MIXER lpwm;
1440 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1442 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1443 return MMSYSERR_INVALHANDLE;
1445 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
1446 fdwDetails, TRUE);
1449 /**************************************************************************
1450 * mixerSetControlDetails [MMSYSTEM.809]
1452 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix,
1453 LPMIXERCONTROLDETAILS16 lpmcd,
1454 DWORD fdwDetails)
1456 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1457 return MMSYSERR_NOTENABLED;
1460 /**************************************************************************
1461 * mixerMessage [WINMM.@]
1463 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
1465 LPWINE_MLD wmld;
1467 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
1468 (DWORD)hmix, uMsg, dwParam1, dwParam2);
1470 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
1471 return MMSYSERR_INVALHANDLE;
1473 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
1476 /**************************************************************************
1477 * mixerMessage [MMSYSTEM.804]
1479 DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1,
1480 DWORD dwParam2)
1482 return mixerMessage(HMIXER_32(hmix), uMsg, dwParam1, dwParam2);
1485 /**************************************************************************
1486 * auxGetNumDevs [WINMM.@]
1488 UINT WINAPI auxGetNumDevs(void)
1490 return MMDRV_GetNum(MMDRV_AUX);
1493 /**************************************************************************
1494 * auxGetNumDevs [MMSYSTEM.350]
1496 UINT16 WINAPI auxGetNumDevs16(void)
1498 return MMDRV_GetNum(MMDRV_AUX);
1501 /**************************************************************************
1502 * auxGetDevCapsW [WINMM.@]
1504 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
1506 AUXCAPSA acA;
1507 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
1509 lpCaps->wMid = acA.wMid;
1510 lpCaps->wPid = acA.wPid;
1511 lpCaps->vDriverVersion = acA.vDriverVersion;
1512 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
1513 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1514 lpCaps->wTechnology = acA.wTechnology;
1515 lpCaps->dwSupport = acA.dwSupport;
1516 return ret;
1519 /**************************************************************************
1520 * auxGetDevCapsA [WINMM.@]
1522 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
1524 LPWINE_MLD wmld;
1526 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1528 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1529 return MMSYSERR_INVALHANDLE;
1530 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1533 /**************************************************************************
1534 * auxGetDevCaps [MMSYSTEM.351]
1536 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
1538 LPWINE_MLD wmld;
1540 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1542 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1543 return MMSYSERR_INVALHANDLE;
1544 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1547 /**************************************************************************
1548 * auxGetVolume [WINMM.@]
1550 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1552 LPWINE_MLD wmld;
1554 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1556 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1557 return MMSYSERR_INVALHANDLE;
1558 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1561 /**************************************************************************
1562 * auxGetVolume [MMSYSTEM.352]
1564 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume)
1566 LPWINE_MLD wmld;
1568 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1570 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1571 return MMSYSERR_INVALHANDLE;
1572 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1575 /**************************************************************************
1576 * auxSetVolume [WINMM.@]
1578 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
1580 LPWINE_MLD wmld;
1582 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1584 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1585 return MMSYSERR_INVALHANDLE;
1586 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1589 /**************************************************************************
1590 * auxSetVolume [MMSYSTEM.353]
1592 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
1594 LPWINE_MLD wmld;
1596 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1598 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1599 return MMSYSERR_INVALHANDLE;
1600 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1603 /**************************************************************************
1604 * auxOutMessage [WINMM.@]
1606 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1608 LPWINE_MLD wmld;
1610 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1611 return MMSYSERR_INVALHANDLE;
1613 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1616 /**************************************************************************
1617 * auxOutMessage [MMSYSTEM.354]
1619 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1621 LPWINE_MLD wmld;
1623 TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1625 switch (uMessage) {
1626 case AUXDM_GETNUMDEVS:
1627 case AUXDM_SETVOLUME:
1628 /* no argument conversion needed */
1629 break;
1630 case AUXDM_GETVOLUME:
1631 return auxGetVolume16(uDeviceID, MapSL(dw1));
1632 case AUXDM_GETDEVCAPS:
1633 return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2);
1634 default:
1635 TRACE("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1636 uDeviceID, uMessage, dw1, dw2);
1637 break;
1639 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1640 return MMSYSERR_INVALHANDLE;
1642 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1645 /**************************************************************************
1646 * mciGetErrorStringW [WINMM.@]
1648 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1650 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1651 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
1653 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
1654 HeapFree(GetProcessHeap(), 0, bufstr);
1655 return ret;
1658 /**************************************************************************
1659 * mciGetErrorString [MMSYSTEM.706]
1661 BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength)
1663 return mciGetErrorStringA(wError, lpstrBuffer, uLength);
1666 /**************************************************************************
1667 * mciGetErrorStringA [WINMM.@]
1669 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
1671 BOOL16 ret = FALSE;
1673 if (lpstrBuffer != NULL && uLength > 0 &&
1674 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
1676 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
1677 dwError, lpstrBuffer, uLength) > 0) {
1678 ret = TRUE;
1681 return ret;
1684 /**************************************************************************
1685 * mciDriverNotify [MMSYSTEM.711]
1687 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1689 TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1691 return PostMessageA(HWND_32(hWndCallBack), MM_MCINOTIFY, wStatus, wDevID);
1694 /**************************************************************************
1695 * mciDriverNotify [WINMM.@]
1697 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1700 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1702 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1705 /**************************************************************************
1706 * mciGetDriverData [MMSYSTEM.708]
1708 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1710 return mciGetDriverData(uDeviceID);
1713 /**************************************************************************
1714 * mciGetDriverData [WINMM.@]
1716 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1718 LPWINE_MCIDRIVER wmd;
1720 TRACE("(%04x)\n", uDeviceID);
1722 wmd = MCI_GetDriver(uDeviceID);
1724 if (!wmd) {
1725 WARN("Bad uDeviceID\n");
1726 return 0L;
1729 return wmd->dwPrivate;
1732 /**************************************************************************
1733 * mciSetDriverData [MMSYSTEM.707]
1735 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1737 return mciSetDriverData(uDeviceID, data);
1740 /**************************************************************************
1741 * mciSetDriverData [WINMM.@]
1743 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1745 LPWINE_MCIDRIVER wmd;
1747 TRACE("(%04x, %08lx)\n", uDeviceID, data);
1749 wmd = MCI_GetDriver(uDeviceID);
1751 if (!wmd) {
1752 WARN("Bad uDeviceID\n");
1753 return FALSE;
1756 wmd->dwPrivate = data;
1757 return TRUE;
1760 /**************************************************************************
1761 * mciSendCommandA [WINMM.@]
1763 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1765 DWORD dwRet;
1767 TRACE("(%08x, %s, %08lx, %08lx)\n",
1768 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1770 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
1771 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1772 TRACE("=> %08lx\n", dwRet);
1773 return dwRet;
1776 /**************************************************************************
1777 * mciSendCommandW [WINMM.@]
1779 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1781 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
1782 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1783 return MCIERR_UNSUPPORTED_FUNCTION;
1786 /**************************************************************************
1787 * mciSendCommand [MMSYSTEM.701]
1789 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1791 DWORD dwRet;
1793 TRACE("(%04X, %s, %08lX, %08lX)\n",
1794 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1796 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE);
1797 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1798 TRACE("=> %ld\n", dwRet);
1799 return dwRet;
1802 /**************************************************************************
1803 * mciGetDeviceID [MMSYSTEM.703]
1805 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1807 TRACE("(\"%s\")\n", lpstrName);
1809 return MCI_GetDriverFromString(lpstrName);
1812 /**************************************************************************
1813 * mciGetDeviceIDA [WINMM.@]
1815 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1817 return MCI_GetDriverFromString(lpstrName);
1820 /**************************************************************************
1821 * mciGetDeviceIDW [WINMM.@]
1823 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1825 LPSTR lpstrName;
1826 UINT ret;
1828 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1829 ret = MCI_GetDriverFromString(lpstrName);
1830 HeapFree(GetProcessHeap(), 0, lpstrName);
1831 return ret;
1834 /**************************************************************************
1835 * MCI_DefYieldProc [internal]
1837 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1839 INT16 ret;
1841 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1843 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
1844 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1845 UserYield16();
1846 ret = 0;
1847 } else {
1848 MSG msg;
1850 msg.hwnd = HWND_32(HIWORD(data));
1851 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1852 ret = -1;
1854 return ret;
1857 /**************************************************************************
1858 * mciSetYieldProc [MMSYSTEM.714]
1860 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData)
1862 LPWINE_MCIDRIVER wmd;
1864 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1866 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1867 WARN("Bad uDeviceID\n");
1868 return FALSE;
1871 wmd->lpfnYieldProc = (YIELDPROC)fpYieldProc;
1872 wmd->dwYieldData = dwYieldData;
1873 wmd->bIs32 = FALSE;
1875 return TRUE;
1878 /**************************************************************************
1879 * mciSetYieldProc [WINMM.@]
1881 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1883 LPWINE_MCIDRIVER wmd;
1885 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1887 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1888 WARN("Bad uDeviceID\n");
1889 return FALSE;
1892 wmd->lpfnYieldProc = fpYieldProc;
1893 wmd->dwYieldData = dwYieldData;
1894 wmd->bIs32 = TRUE;
1896 return TRUE;
1899 /**************************************************************************
1900 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
1902 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1904 FIXME("(%lu, %s) stub\n", dwElementID, lpstrType);
1905 return 0;
1908 /**************************************************************************
1909 * mciGetDeviceIDFromElementIDW [WINMM.@]
1911 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1913 /* FIXME: that's rather strange, there is no
1914 * mciGetDeviceIDFromElementID32A in winmm.spec
1916 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1917 return 0;
1920 /**************************************************************************
1921 * mciGetYieldProc [MMSYSTEM.716]
1923 YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1925 LPWINE_MCIDRIVER wmd;
1927 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1929 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1930 WARN("Bad uDeviceID\n");
1931 return NULL;
1933 if (!wmd->lpfnYieldProc) {
1934 WARN("No proc set\n");
1935 return NULL;
1937 if (wmd->bIs32) {
1938 WARN("Proc is 32 bit\n");
1939 return NULL;
1941 return (YIELDPROC16)wmd->lpfnYieldProc;
1944 /**************************************************************************
1945 * mciGetYieldProc [WINMM.@]
1947 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1949 LPWINE_MCIDRIVER wmd;
1951 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1953 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1954 WARN("Bad uDeviceID\n");
1955 return NULL;
1957 if (!wmd->lpfnYieldProc) {
1958 WARN("No proc set\n");
1959 return NULL;
1961 if (!wmd->bIs32) {
1962 WARN("Proc is 32 bit\n");
1963 return NULL;
1965 return wmd->lpfnYieldProc;
1968 /**************************************************************************
1969 * mciGetCreatorTask [MMSYSTEM.717]
1971 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1973 LPWINE_MCIDRIVER wmd;
1974 HTASK16 ret = 0;
1976 if ((wmd = MCI_GetDriver(uDeviceID))) ret = wmd->hCreatorTask;
1978 TRACE("(%u) => %04x\n", uDeviceID, ret);
1979 return ret;
1982 /**************************************************************************
1983 * mciGetCreatorTask [WINMM.@]
1985 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1987 LPWINE_MCIDRIVER wmd;
1988 HTASK ret = 0;
1990 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
1992 TRACE("(%u) => %08x\n", uDeviceID, ret);
1993 return ret;
1996 /**************************************************************************
1997 * mciDriverYield [MMSYSTEM.710]
1999 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
2001 LPWINE_MCIDRIVER wmd;
2002 UINT16 ret = 0;
2004 /* TRACE("(%04x)\n", uDeviceID); */
2006 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) {
2007 UserYield16();
2008 } else {
2009 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
2012 return ret;
2015 /**************************************************************************
2016 * mciDriverYield [WINMM.@]
2018 UINT WINAPI mciDriverYield(UINT uDeviceID)
2020 LPWINE_MCIDRIVER wmd;
2021 UINT ret = 0;
2023 TRACE("(%04x)\n", uDeviceID);
2025 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
2026 UserYield16();
2027 } else {
2028 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
2031 return ret;
2034 /**************************************************************************
2035 * midiOutGetNumDevs [WINMM.@]
2037 UINT WINAPI midiOutGetNumDevs(void)
2039 return MMDRV_GetNum(MMDRV_MIDIOUT);
2042 /**************************************************************************
2043 * midiOutGetNumDevs [MMSYSTEM.201]
2045 UINT16 WINAPI midiOutGetNumDevs16(void)
2047 return MMDRV_GetNum(MMDRV_MIDIOUT);
2050 /**************************************************************************
2051 * midiOutGetDevCapsW [WINMM.@]
2053 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
2054 UINT uSize)
2056 MIDIOUTCAPSA mocA;
2057 UINT ret;
2059 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
2060 lpCaps->wMid = mocA.wMid;
2061 lpCaps->wPid = mocA.wPid;
2062 lpCaps->vDriverVersion = mocA.vDriverVersion;
2063 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
2064 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2065 lpCaps->wTechnology = mocA.wTechnology;
2066 lpCaps->wVoices = mocA.wVoices;
2067 lpCaps->wNotes = mocA.wNotes;
2068 lpCaps->wChannelMask = mocA.wChannelMask;
2069 lpCaps->dwSupport = mocA.dwSupport;
2070 return ret;
2073 /**************************************************************************
2074 * midiOutGetDevCapsA [WINMM.@]
2076 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
2077 UINT uSize)
2079 LPWINE_MLD wmld;
2081 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
2083 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2085 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2086 return MMSYSERR_INVALHANDLE;
2088 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2091 /**************************************************************************
2092 * midiOutGetDevCaps [MMSYSTEM.202]
2094 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps,
2095 UINT16 uSize)
2097 MIDIOUTCAPSA capsA;
2098 UINT dwRet;
2100 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2102 dwRet = midiOutGetDevCapsA(uDeviceID, &capsA, sizeof(capsA));
2103 if (dwRet == MMSYSERR_NOERROR) {
2104 lpCaps->wMid = capsA.wMid;
2105 lpCaps->wPid = capsA.wPid;
2106 lpCaps->vDriverVersion = capsA.vDriverVersion;
2107 strcpy(lpCaps->szPname, capsA.szPname);
2108 lpCaps->wTechnology = capsA.wTechnology;
2109 lpCaps->wVoices = capsA.wVoices;
2110 lpCaps->wNotes = capsA.wNotes;
2111 lpCaps->wChannelMask = capsA.wChannelMask;
2112 lpCaps->dwSupport = capsA.dwSupport;
2114 return dwRet;
2117 /**************************************************************************
2118 * MIDI_GetErrorText [internal]
2120 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2122 UINT16 ret = MMSYSERR_BADERRNUM;
2124 if (lpText == NULL) {
2125 ret = MMSYSERR_INVALPARAM;
2126 } else if (uSize == 0) {
2127 ret = MMSYSERR_NOERROR;
2128 } else if (
2129 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2130 * a warning for the test was always true */
2131 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
2132 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
2134 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
2135 uError, lpText, uSize) > 0) {
2136 ret = MMSYSERR_NOERROR;
2139 return ret;
2142 /**************************************************************************
2143 * midiOutGetErrorTextA [WINMM.@]
2145 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2147 return MIDI_GetErrorText(uError, lpText, uSize);
2150 /**************************************************************************
2151 * midiOutGetErrorTextW [WINMM.@]
2153 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2155 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2156 UINT ret;
2158 ret = MIDI_GetErrorText(uError, xstr, uSize);
2159 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2160 HeapFree(GetProcessHeap(), 0, xstr);
2161 return ret;
2164 /**************************************************************************
2165 * midiOutGetErrorText [MMSYSTEM.203]
2167 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2169 return MIDI_GetErrorText(uError, lpText, uSize);
2172 /**************************************************************************
2173 * MIDI_OutAlloc [internal]
2175 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
2176 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
2177 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
2179 HMIDIOUT hMidiOut;
2180 LPWINE_MIDI lpwm;
2181 UINT size;
2183 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
2185 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
2186 lpdwCallback, lpdwInstance, bFrom32);
2188 if (lphMidiOut != NULL)
2189 *lphMidiOut = hMidiOut;
2191 if (lpwm) {
2192 lpwm->mod.hMidi = (HMIDI) hMidiOut;
2193 lpwm->mod.dwCallback = *lpdwCallback;
2194 lpwm->mod.dwInstance = *lpdwInstance;
2195 lpwm->mod.dnDevNode = 0;
2196 lpwm->mod.cIds = cIDs;
2197 if (cIDs)
2198 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2200 return lpwm;
2203 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
2204 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2206 HMIDIOUT hMidiOut;
2207 LPWINE_MIDI lpwm;
2208 UINT dwRet = 0;
2210 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2211 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2213 if (lphMidiOut != NULL) *lphMidiOut = 0;
2215 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
2216 0, NULL, bFrom32);
2218 if (lpwm == NULL)
2219 return MMSYSERR_NOMEM;
2221 lpwm->mld.uDeviceID = uDeviceID;
2223 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
2224 dwFlags);
2226 if (dwRet != MMSYSERR_NOERROR) {
2227 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
2228 hMidiOut = 0;
2231 if (lphMidiOut) *lphMidiOut = hMidiOut;
2232 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
2234 return dwRet;
2237 /**************************************************************************
2238 * midiOutOpen [WINMM.@]
2240 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2241 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2243 return MMSYSTEM_midiOutOpen(lphMidiOut, uDeviceID, dwCallback,
2244 dwInstance, dwFlags, TRUE);
2247 /**************************************************************************
2248 * midiOutOpen [MMSYSTEM.204]
2250 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2251 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2253 HMIDIOUT hmo;
2254 UINT ret;
2256 ret = MMSYSTEM_midiOutOpen(&hmo, uDeviceID, dwCallback, dwInstance,
2257 dwFlags, FALSE);
2259 if (lphMidiOut != NULL) *lphMidiOut = HMIDIOUT_16(hmo);
2260 return ret;
2263 /**************************************************************************
2264 * midiOutClose [WINMM.@]
2266 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2268 LPWINE_MLD wmld;
2269 DWORD dwRet;
2271 TRACE("(%04X)\n", hMidiOut);
2273 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2274 return MMSYSERR_INVALHANDLE;
2276 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
2277 MMDRV_Free(hMidiOut, wmld);
2279 return dwRet;
2282 /**************************************************************************
2283 * midiOutClose [MMSYSTEM.205]
2285 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2287 return midiOutClose(HMIDIOUT_32(hMidiOut));
2290 /**************************************************************************
2291 * midiOutPrepareHeader [WINMM.@]
2293 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2294 MIDIHDR* lpMidiOutHdr, UINT uSize)
2296 LPWINE_MLD wmld;
2298 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2300 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2301 return MMSYSERR_INVALHANDLE;
2303 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2306 /**************************************************************************
2307 * midiOutPrepareHeader [MMSYSTEM.206]
2309 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2310 SEGPTR lpsegMidiOutHdr, /* [???] */
2311 UINT16 uSize) /* [in] */
2313 LPWINE_MLD wmld;
2315 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2317 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2318 return MMSYSERR_INVALHANDLE;
2320 return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE);
2323 /**************************************************************************
2324 * midiOutUnprepareHeader [WINMM.@]
2326 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2327 MIDIHDR* lpMidiOutHdr, UINT uSize)
2329 LPWINE_MLD wmld;
2331 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2333 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2334 return MMSYSERR_NOERROR;
2337 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2338 return MMSYSERR_INVALHANDLE;
2340 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2343 /**************************************************************************
2344 * midiOutUnprepareHeader [MMSYSTEM.207]
2346 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2347 SEGPTR lpsegMidiOutHdr, /* [???] */
2348 UINT16 uSize) /* [in] */
2350 LPWINE_MLD wmld;
2351 LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr);
2353 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2355 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2356 return MMSYSERR_NOERROR;
2359 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2360 return MMSYSERR_INVALHANDLE;
2362 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2365 /**************************************************************************
2366 * midiOutShortMsg [WINMM.@]
2368 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2370 LPWINE_MLD wmld;
2372 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
2374 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2375 return MMSYSERR_INVALHANDLE;
2377 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, FALSE);
2380 /**************************************************************************
2381 * midiOutShortMsg [MMSYSTEM.208]
2383 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2385 return midiOutShortMsg(HMIDIOUT_32(hMidiOut), dwMsg);
2388 /**************************************************************************
2389 * midiOutLongMsg [WINMM.@]
2391 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2392 MIDIHDR* lpMidiOutHdr, UINT uSize)
2394 LPWINE_MLD wmld;
2396 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2398 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2399 return MMSYSERR_INVALHANDLE;
2401 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
2404 /**************************************************************************
2405 * midiOutLongMsg [MMSYSTEM.209]
2407 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */
2408 LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */
2409 UINT16 uSize) /* [in] */
2411 LPWINE_MLD wmld;
2413 TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2415 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2416 return MMSYSERR_INVALHANDLE;
2418 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2421 /**************************************************************************
2422 * midiOutReset [WINMM.@]
2424 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2426 LPWINE_MLD wmld;
2428 TRACE("(%04X)\n", hMidiOut);
2430 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2431 return MMSYSERR_INVALHANDLE;
2433 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
2436 /**************************************************************************
2437 * midiOutReset [MMSYSTEM.210]
2439 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2441 return midiOutReset(HMIDIOUT_32(hMidiOut));
2444 /**************************************************************************
2445 * midiOutGetVolume [WINMM.@]
2447 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2449 LPWINE_MLD wmld;
2451 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
2453 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2454 return MMSYSERR_INVALHANDLE;
2456 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
2459 /**************************************************************************
2460 * midiOutGetVolume [MMSYSTEM.211]
2462 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2464 return midiOutGetVolume(uDeviceID, lpdwVolume);
2467 /**************************************************************************
2468 * midiOutSetVolume [WINMM.@]
2470 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2472 LPWINE_MLD wmld;
2474 TRACE("(%04X, %ld);\n", uDeviceID, dwVolume);
2476 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2477 return MMSYSERR_INVALHANDLE;
2479 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
2482 /**************************************************************************
2483 * midiOutSetVolume [MMSYSTEM.212]
2485 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2487 return midiOutSetVolume(uDeviceID, dwVolume);
2490 /**************************************************************************
2491 * midiOutCachePatches [WINMM.@]
2493 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2494 WORD* lpwPatchArray, UINT uFlags)
2496 /* not really necessary to support this */
2497 FIXME("not supported yet\n");
2498 return MMSYSERR_NOTSUPPORTED;
2501 /**************************************************************************
2502 * midiOutCachePatches [MMSYSTEM.213]
2504 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2505 WORD* lpwPatchArray, UINT16 uFlags)
2507 return midiOutCachePatches(HMIDIOUT_32(hMidiOut), uBank, lpwPatchArray,
2508 uFlags);
2511 /**************************************************************************
2512 * midiOutCacheDrumPatches [WINMM.@]
2514 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2515 WORD* lpwKeyArray, UINT uFlags)
2517 FIXME("not supported yet\n");
2518 return MMSYSERR_NOTSUPPORTED;
2521 /**************************************************************************
2522 * midiOutCacheDrumPatches [MMSYSTEM.214]
2524 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2525 WORD* lpwKeyArray, UINT16 uFlags)
2527 return midiOutCacheDrumPatches(HMIDIOUT_32(hMidiOut), uPatch, lpwKeyArray, uFlags);
2530 /**************************************************************************
2531 * midiOutGetID [WINMM.@]
2533 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2535 LPWINE_MLD wmld;
2537 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2539 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2540 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2541 return MMSYSERR_INVALHANDLE;
2543 *lpuDeviceID = wmld->uDeviceID;
2544 return MMSYSERR_NOERROR;
2547 /**************************************************************************
2548 * midiOutGetID [MMSYSTEM.215]
2550 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2552 LPWINE_MLD wmld;
2554 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2556 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2557 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2558 return MMSYSERR_INVALHANDLE;
2560 *lpuDeviceID = wmld->uDeviceID;
2561 return MMSYSERR_NOERROR;
2564 /**************************************************************************
2565 * midiOutMessage [WINMM.@]
2567 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2568 DWORD dwParam1, DWORD dwParam2)
2570 LPWINE_MLD wmld;
2572 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2574 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
2575 /* HACK... */
2576 if (uMessage == 0x0001) {
2577 *(LPDWORD)dwParam1 = 1;
2578 return 0;
2580 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
2581 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2583 return MMSYSERR_INVALHANDLE;
2586 switch (uMessage) {
2587 case MODM_OPEN:
2588 case MODM_CLOSE:
2589 FIXME("can't handle OPEN or CLOSE message!\n");
2590 return MMSYSERR_NOTSUPPORTED;
2592 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2595 /**************************************************************************
2596 * midiOutMessage [MMSYSTEM.216]
2598 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2599 DWORD dwParam1, DWORD dwParam2)
2601 LPWINE_MLD wmld;
2603 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2605 if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL)
2606 return MMSYSERR_INVALHANDLE;
2608 switch (uMessage) {
2609 case MODM_OPEN:
2610 case MODM_CLOSE:
2611 FIXME("can't handle OPEN or CLOSE message!\n");
2612 return MMSYSERR_NOTSUPPORTED;
2614 case MODM_GETVOLUME:
2615 return midiOutGetVolume16(hMidiOut, MapSL(dwParam1));
2616 case MODM_LONGDATA:
2617 return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2);
2618 case MODM_PREPARE:
2619 /* lpMidiOutHdr is still a segmented pointer for this function */
2620 return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2);
2621 case MODM_UNPREPARE:
2622 return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2);
2624 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2627 /**************************************************************************
2628 * midiInGetNumDevs [WINMM.@]
2630 UINT WINAPI midiInGetNumDevs(void)
2632 return MMDRV_GetNum(MMDRV_MIDIIN);
2635 /**************************************************************************
2636 * midiInGetNumDevs [MMSYSTEM.301]
2638 UINT16 WINAPI midiInGetNumDevs16(void)
2640 return MMDRV_GetNum(MMDRV_MIDIIN);
2643 /**************************************************************************
2644 * midiInGetDevCapsW [WINMM.@]
2646 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2648 MIDIINCAPSA micA;
2649 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2651 if (ret == MMSYSERR_NOERROR) {
2652 lpCaps->wMid = micA.wMid;
2653 lpCaps->wPid = micA.wPid;
2654 lpCaps->vDriverVersion = micA.vDriverVersion;
2655 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
2656 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2657 lpCaps->dwSupport = micA.dwSupport;
2659 return ret;
2662 /**************************************************************************
2663 * midiInGetDevCapsA [WINMM.@]
2665 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2667 LPWINE_MLD wmld;
2669 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
2671 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
2672 return MMSYSERR_INVALHANDLE;
2674 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2677 /**************************************************************************
2678 * midiInGetDevCaps [MMSYSTEM.302]
2680 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps,
2681 UINT16 uSize)
2683 MIDIINCAPSA micA;
2684 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2686 if (ret == MMSYSERR_NOERROR) {
2687 lpCaps->wMid = micA.wMid;
2688 lpCaps->wPid = micA.wPid;
2689 lpCaps->vDriverVersion = micA.vDriverVersion;
2690 strcpy(lpCaps->szPname, micA.szPname);
2691 lpCaps->dwSupport = micA.dwSupport;
2694 return ret;
2697 /**************************************************************************
2698 * midiInGetErrorTextW [WINMM.@]
2700 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2702 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2703 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
2705 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2706 HeapFree(GetProcessHeap(), 0, xstr);
2707 return ret;
2710 /**************************************************************************
2711 * midiInGetErrorTextA [WINMM.@]
2713 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2715 return MIDI_GetErrorText(uError, lpText, uSize);
2718 /**************************************************************************
2719 * midiInGetErrorText [MMSYSTEM.303]
2721 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2723 return MIDI_GetErrorText(uError, lpText, uSize);
2726 static UINT MMSYSTEM_midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
2727 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2729 HMIDIIN hMidiIn;
2730 LPWINE_MIDI lpwm;
2731 DWORD dwRet = 0;
2733 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2734 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2736 if (lphMidiIn != NULL) *lphMidiIn = 0;
2738 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
2739 &dwFlags, &dwCallback, &dwInstance, bFrom32);
2741 if (lpwm == NULL)
2742 return MMSYSERR_NOMEM;
2744 lpwm->mod.hMidi = (HMIDI) hMidiIn;
2745 lpwm->mod.dwCallback = dwCallback;
2746 lpwm->mod.dwInstance = dwInstance;
2748 lpwm->mld.uDeviceID = uDeviceID;
2749 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
2751 if (dwRet != MMSYSERR_NOERROR) {
2752 MMDRV_Free(hMidiIn, &lpwm->mld);
2753 hMidiIn = 0;
2755 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
2756 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
2758 return dwRet;
2761 /**************************************************************************
2762 * midiInOpen [WINMM.@]
2764 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2765 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2767 return MMSYSTEM_midiInOpen(lphMidiIn, uDeviceID, dwCallback,
2768 dwInstance, dwFlags, TRUE);
2771 /**************************************************************************
2772 * midiInOpen [MMSYSTEM.304]
2774 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2775 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2777 HMIDIIN xhmid;
2778 UINT ret;
2780 ret = MMSYSTEM_midiInOpen(&xhmid, uDeviceID, dwCallback, dwInstance,
2781 dwFlags, FALSE);
2783 if (lphMidiIn) *lphMidiIn = HMIDIIN_16(xhmid);
2784 return ret;
2787 /**************************************************************************
2788 * midiInClose [WINMM.@]
2790 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2792 LPWINE_MLD wmld;
2793 DWORD dwRet;
2795 TRACE("(%04X)\n", hMidiIn);
2797 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2798 return MMSYSERR_INVALHANDLE;
2800 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
2801 MMDRV_Free(hMidiIn, wmld);
2802 return dwRet;
2805 /**************************************************************************
2806 * midiInClose [MMSYSTEM.305]
2808 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2810 return midiInClose(HMIDIIN_32(hMidiIn));
2813 /**************************************************************************
2814 * midiInPrepareHeader [WINMM.@]
2816 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2817 MIDIHDR* lpMidiInHdr, UINT uSize)
2819 LPWINE_MLD wmld;
2821 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2823 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2824 return MMSYSERR_INVALHANDLE;
2826 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2829 /**************************************************************************
2830 * midiInPrepareHeader [MMSYSTEM.306]
2832 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2833 SEGPTR lpsegMidiInHdr, /* [???] */
2834 UINT16 uSize) /* [in] */
2836 LPWINE_MLD wmld;
2838 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2840 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL)
2841 return MMSYSERR_INVALHANDLE;
2843 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2846 /**************************************************************************
2847 * midiInUnprepareHeader [WINMM.@]
2849 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2850 MIDIHDR* lpMidiInHdr, UINT uSize)
2852 LPWINE_MLD wmld;
2854 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2856 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2857 return MMSYSERR_NOERROR;
2860 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2861 return MMSYSERR_INVALHANDLE;
2863 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2866 /**************************************************************************
2867 * midiInUnprepareHeader [MMSYSTEM.307]
2869 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2870 SEGPTR lpsegMidiInHdr, /* [???] */
2871 UINT16 uSize) /* [in] */
2873 LPWINE_MLD wmld;
2874 LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr);
2876 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2878 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2879 return MMSYSERR_NOERROR;
2882 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL)
2883 return MMSYSERR_INVALHANDLE;
2885 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2888 /**************************************************************************
2889 * midiInAddBuffer [WINMM.@]
2891 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2892 MIDIHDR* lpMidiInHdr, UINT uSize)
2894 LPWINE_MLD wmld;
2896 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2898 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2899 return MMSYSERR_INVALHANDLE;
2901 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
2904 /**************************************************************************
2905 * midiInAddBuffer [MMSYSTEM.308]
2907 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */
2908 MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */
2909 UINT16 uSize) /* [in] */
2911 LPWINE_MLD wmld;
2913 TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2915 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL)
2916 return MMSYSERR_INVALHANDLE;
2918 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2921 /**************************************************************************
2922 * midiInStart [WINMM.@]
2924 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2926 LPWINE_MLD wmld;
2928 TRACE("(%04X)\n", hMidiIn);
2930 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2931 return MMSYSERR_INVALHANDLE;
2933 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
2936 /**************************************************************************
2937 * midiInStart [MMSYSTEM.309]
2939 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2941 return midiInStart(HMIDIIN_32(hMidiIn));
2944 /**************************************************************************
2945 * midiInStop [WINMM.@]
2947 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2949 LPWINE_MLD wmld;
2951 TRACE("(%04X)\n", hMidiIn);
2953 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2954 return MMSYSERR_INVALHANDLE;
2956 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
2959 /**************************************************************************
2960 * midiInStop [MMSYSTEM.310]
2962 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2964 return midiInStop(HMIDIIN_32(hMidiIn));
2967 /**************************************************************************
2968 * midiInReset [WINMM.@]
2970 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2972 LPWINE_MLD wmld;
2974 TRACE("(%04X)\n", hMidiIn);
2976 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2977 return MMSYSERR_INVALHANDLE;
2979 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
2982 /**************************************************************************
2983 * midiInReset [MMSYSTEM.311]
2985 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2987 return midiInReset(HMIDIIN_32(hMidiIn));
2990 /**************************************************************************
2991 * midiInGetID [WINMM.@]
2993 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2995 LPWINE_MLD wmld;
2997 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2999 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
3001 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
3002 return MMSYSERR_INVALHANDLE;
3004 *lpuDeviceID = wmld->uDeviceID;
3006 return MMSYSERR_NOERROR;
3009 /**************************************************************************
3010 * midiInGetID [MMSYSTEM.312]
3012 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
3014 LPWINE_MLD wmld;
3016 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
3018 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
3020 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, TRUE)) == NULL)
3021 return MMSYSERR_INVALHANDLE;
3023 *lpuDeviceID = wmld->uDeviceID;
3025 return MMSYSERR_NOERROR;
3028 /**************************************************************************
3029 * midiInMessage [WINMM.@]
3031 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
3032 DWORD dwParam1, DWORD dwParam2)
3034 LPWINE_MLD wmld;
3036 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3038 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
3039 return MMSYSERR_INVALHANDLE;
3041 switch (uMessage) {
3042 case MIDM_OPEN:
3043 case MIDM_CLOSE:
3044 FIXME("can't handle OPEN or CLOSE message!\n");
3045 return MMSYSERR_NOTSUPPORTED;
3047 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
3050 /**************************************************************************
3051 * midiInMessage [MMSYSTEM.313]
3053 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
3054 DWORD dwParam1, DWORD dwParam2)
3056 LPWINE_MLD wmld;
3058 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3060 switch (uMessage) {
3061 case MIDM_OPEN:
3062 case MIDM_CLOSE:
3063 FIXME("can't handle OPEN or CLOSE message!\n");
3064 return MMSYSERR_NOTSUPPORTED;
3066 case MIDM_GETDEVCAPS:
3067 return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2);
3068 case MIDM_PREPARE:
3069 return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2);
3070 case MIDM_UNPREPARE:
3071 return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2);
3072 case MIDM_ADDBUFFER:
3073 return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2);
3076 if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL)
3077 return MMSYSERR_INVALHANDLE;
3079 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
3082 typedef struct WINE_MIDIStream {
3083 HMIDIOUT hDevice;
3084 HANDLE hThread;
3085 DWORD dwThreadID;
3086 DWORD dwTempo;
3087 DWORD dwTimeDiv;
3088 DWORD dwPositionMS;
3089 DWORD dwPulses;
3090 DWORD dwStartTicks;
3091 WORD wFlags;
3092 HANDLE hEvent;
3093 LPMIDIHDR lpMidiHdr;
3094 } WINE_MIDIStream;
3096 #define WINE_MSM_HEADER (WM_USER+0)
3097 #define WINE_MSM_STOP (WM_USER+1)
3099 /**************************************************************************
3100 * MMSYSTEM_GetMidiStream [internal]
3102 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
3104 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
3106 if (lplpwm)
3107 *lplpwm = lpwm;
3109 if (lpwm == NULL) {
3110 return FALSE;
3113 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
3115 return *lpMidiStrm != NULL;
3118 /**************************************************************************
3119 * MMSYSTEM_MidiStream_Convert [internal]
3121 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
3123 DWORD ret = 0;
3125 if (lpMidiStrm->dwTimeDiv == 0) {
3126 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
3127 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
3128 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
3129 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
3130 ret = (pulse * 1000) / (nf * nsf);
3131 } else {
3132 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
3133 (double)lpMidiStrm->dwTimeDiv);
3136 return ret;
3139 /**************************************************************************
3140 * MMSYSTEM_MidiStream_MessageHandler [internal]
3142 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
3144 LPMIDIHDR lpMidiHdr;
3145 LPMIDIHDR* lpmh;
3146 LPBYTE lpData;
3148 switch (msg->message) {
3149 case WM_QUIT:
3150 SetEvent(lpMidiStrm->hEvent);
3151 return FALSE;
3152 case WINE_MSM_STOP:
3153 TRACE("STOP\n");
3154 /* this is not quite what MS doc says... */
3155 midiOutReset(lpMidiStrm->hDevice);
3156 /* empty list of already submitted buffers */
3157 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
3158 lpMidiHdr->dwFlags |= MHDR_DONE;
3159 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3161 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
3162 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
3163 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3165 lpMidiStrm->lpMidiHdr = 0;
3166 SetEvent(lpMidiStrm->hEvent);
3167 break;
3168 case WINE_MSM_HEADER:
3169 /* sets initial tick count for first MIDIHDR */
3170 if (!lpMidiStrm->dwStartTicks)
3171 lpMidiStrm->dwStartTicks = GetTickCount();
3173 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
3174 * by native mcimidi, it doesn't look like a correct one".
3175 * this trick allows to throw it away... but I don't like it.
3176 * It looks like part of the file I'm trying to play and definitively looks
3177 * like raw midi content
3178 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
3179 * synchronization issue where native mcimidi is still processing raw MIDI
3180 * content before generating MIDIEVENTs ?
3182 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
3183 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
3184 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
3185 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
3186 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
3187 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
3188 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
3189 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
3190 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
3191 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3192 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3193 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3194 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3195 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3196 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3197 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3198 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3200 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3201 lpData = lpMidiHdr->lpData;
3202 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
3203 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
3204 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
3205 lpMidiHdr->dwFlags, msg->wParam);
3206 #if 0
3207 /* dumps content of lpMidiHdr->lpData
3208 * FIXME: there should be a debug routine somewhere that already does this
3209 * I hate spreading this type of shit all around the code
3211 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
3212 DWORD i;
3213 BYTE ch;
3215 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
3216 printf("%02x ", lpData[dwToGo + i]);
3217 for (; i < 16; i++)
3218 printf(" ");
3219 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
3220 ch = lpData[dwToGo + i];
3221 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
3223 printf("\n");
3225 #endif
3226 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3227 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3228 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3229 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
3230 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
3231 ((LPMIDIEVENT)lpData)->dwStreamID);
3232 lpMidiHdr->dwFlags |= MHDR_DONE;
3233 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3235 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
3236 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
3237 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3238 break;
3241 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
3242 *lpmh = lpMidiHdr;
3243 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3244 lpMidiHdr->lpNext = 0;
3245 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
3246 lpMidiHdr->dwFlags &= MHDR_DONE;
3247 lpMidiHdr->dwOffset = 0;
3249 break;
3250 default:
3251 FIXME("Unknown message %d\n", msg->message);
3252 break;
3254 return TRUE;
3257 /**************************************************************************
3258 * MMSYSTEM_MidiStream_Player [internal]
3260 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
3262 WINE_MIDIStream* lpMidiStrm = pmt;
3263 WINE_MIDI* lpwm;
3264 MSG msg;
3265 DWORD dwToGo;
3266 DWORD dwCurrTC;
3267 LPMIDIHDR lpMidiHdr;
3268 LPMIDIEVENT me;
3269 LPBYTE lpData = 0;
3271 TRACE("(%p)!\n", lpMidiStrm);
3273 if (!lpMidiStrm ||
3274 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
3275 goto the_end;
3277 /* force thread's queue creation */
3278 /* Used to be InitThreadInput16(0, 5); */
3279 /* but following works also with hack in midiStreamOpen */
3280 PeekMessageA(&msg, 0, 0, 0, 0);
3282 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
3283 SetEvent(lpMidiStrm->hEvent);
3284 TRACE("Ready to go 1\n");
3285 /* thread is started in paused mode */
3286 SuspendThread(lpMidiStrm->hThread);
3287 TRACE("Ready to go 2\n");
3289 lpMidiStrm->dwStartTicks = 0;
3290 lpMidiStrm->dwPulses = 0;
3292 lpMidiStrm->lpMidiHdr = 0;
3294 for (;;) {
3295 lpMidiHdr = lpMidiStrm->lpMidiHdr;
3296 if (!lpMidiHdr) {
3297 /* for first message, block until one arrives, then process all that are available */
3298 GetMessageA(&msg, 0, 0, 0);
3299 do {
3300 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3301 goto the_end;
3302 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
3303 lpData = 0;
3304 continue;
3307 if (!lpData)
3308 lpData = lpMidiHdr->lpData;
3310 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3312 /* do we have to wait ? */
3313 if (me->dwDeltaTime) {
3314 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
3315 lpMidiStrm->dwPulses += me->dwDeltaTime;
3317 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3319 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
3320 while ((dwCurrTC = GetTickCount()) < dwToGo) {
3321 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
3322 /* got a message, handle it */
3323 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
3324 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3325 goto the_end;
3327 lpData = 0;
3328 } else {
3329 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
3330 break;
3334 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3335 case MEVT_COMMENT:
3336 FIXME("NIY: MEVT_COMMENT\n");
3337 /* do nothing, skip bytes */
3338 break;
3339 case MEVT_LONGMSG:
3340 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3341 break;
3342 case MEVT_NOP:
3343 break;
3344 case MEVT_SHORTMSG:
3345 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3346 break;
3347 case MEVT_TEMPO:
3348 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3349 break;
3350 case MEVT_VERSION:
3351 break;
3352 default:
3353 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3354 break;
3356 if (me->dwEvent & MEVT_F_CALLBACK) {
3357 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
3358 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
3359 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
3361 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
3362 if (me->dwEvent & MEVT_F_LONG)
3363 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
3364 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
3365 /* done with this header */
3366 lpMidiHdr->dwFlags |= MHDR_DONE;
3367 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3369 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
3370 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
3371 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
3372 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3373 lpData = 0;
3376 the_end:
3377 TRACE("End of thread\n");
3378 ExitThread(0);
3379 return 0; /* for removing the warning, never executed */
3382 /**************************************************************************
3383 * MMSYSTEM_MidiStream_PostMessage [internal]
3385 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
3387 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
3388 DWORD count;
3390 ReleaseThunkLock(&count);
3391 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3392 RestoreThunkLock(count);
3393 } else {
3394 WARN("bad PostThreadMessageA\n");
3395 return FALSE;
3397 return TRUE;
3400 /**************************************************************************
3401 * midiStreamClose [WINMM.@]
3403 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3405 WINE_MIDIStream* lpMidiStrm;
3407 TRACE("(%08x)!\n", hMidiStrm);
3409 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3410 return MMSYSERR_INVALHANDLE;
3412 midiStreamStop(hMidiStrm);
3413 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
3414 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
3415 CloseHandle(lpMidiStrm->hEvent);
3417 return midiOutClose((HMIDIOUT)hMidiStrm);
3420 /**************************************************************************
3421 * MMSYSTEM_MidiStream_Open [internal]
3423 static MMRESULT WINAPI MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3424 DWORD cMidi, DWORD dwCallback,
3425 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
3427 WINE_MIDIStream* lpMidiStrm;
3428 MMRESULT ret;
3429 MIDIOPENSTRMID mosm;
3430 LPWINE_MIDI lpwm;
3431 HMIDIOUT hMidiOut;
3433 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3434 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3436 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3437 return MMSYSERR_INVALPARAM;
3439 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3440 if (!lpMidiStrm)
3441 return MMSYSERR_NOMEM;
3443 lpMidiStrm->dwTempo = 500000;
3444 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3445 lpMidiStrm->dwPositionMS = 0;
3447 mosm.dwStreamID = (DWORD)lpMidiStrm;
3448 /* FIXME: the correct value is not allocated yet for MAPPER */
3449 mosm.wDeviceID = *lpuDeviceID;
3450 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
3451 lpMidiStrm->hDevice = hMidiOut;
3452 if (lphMidiStrm)
3453 *lphMidiStrm = (HMIDISTRM)hMidiOut;
3455 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
3456 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
3457 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
3459 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
3460 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
3461 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3463 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
3464 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3466 if (!lpMidiStrm->hThread) {
3467 midiStreamClose((HMIDISTRM)hMidiOut);
3468 return MMSYSERR_NOMEM;
3471 /* wait for thread to have started, and for its queue to be created */
3473 DWORD count;
3475 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3476 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3477 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3479 ReleaseThunkLock(&count);
3480 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3481 RestoreThunkLock(count);
3484 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
3485 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
3486 return ret;
3489 /**************************************************************************
3490 * midiStreamOpen [WINMM.@]
3492 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3493 DWORD cMidi, DWORD dwCallback,
3494 DWORD dwInstance, DWORD fdwOpen)
3496 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
3497 dwInstance, fdwOpen, TRUE);
3500 /**************************************************************************
3501 * midiStreamOut [WINMM.@]
3503 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
3504 UINT cbMidiHdr)
3506 WINE_MIDIStream* lpMidiStrm;
3507 DWORD ret = MMSYSERR_NOERROR;
3509 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3511 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3512 ret = MMSYSERR_INVALHANDLE;
3513 } else if (!lpMidiHdr) {
3514 ret = MMSYSERR_INVALPARAM;
3515 } else {
3516 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
3517 WINE_MSM_HEADER, cbMidiHdr,
3518 (DWORD)lpMidiHdr)) {
3519 WARN("bad PostThreadMessageA\n");
3520 ret = MMSYSERR_ERROR;
3523 return ret;
3526 /**************************************************************************
3527 * midiStreamPause [WINMM.@]
3529 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3531 WINE_MIDIStream* lpMidiStrm;
3532 DWORD ret = MMSYSERR_NOERROR;
3534 TRACE("(%08x)!\n", hMidiStrm);
3536 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3537 ret = MMSYSERR_INVALHANDLE;
3538 } else {
3539 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3540 WARN("bad Suspend (%ld)\n", GetLastError());
3541 ret = MMSYSERR_ERROR;
3544 return ret;
3547 /**************************************************************************
3548 * midiStreamPosition [WINMM.@]
3550 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3552 WINE_MIDIStream* lpMidiStrm;
3553 DWORD ret = MMSYSERR_NOERROR;
3555 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3557 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3558 ret = MMSYSERR_INVALHANDLE;
3559 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3560 ret = MMSYSERR_INVALPARAM;
3561 } else {
3562 switch (lpMMT->wType) {
3563 case TIME_MS:
3564 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3565 TRACE("=> %ld ms\n", lpMMT->u.ms);
3566 break;
3567 case TIME_TICKS:
3568 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3569 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
3570 break;
3571 default:
3572 WARN("Unsupported time type %d\n", lpMMT->wType);
3573 lpMMT->wType = TIME_MS;
3574 ret = MMSYSERR_INVALPARAM;
3575 break;
3578 return ret;
3581 /**************************************************************************
3582 * midiStreamProperty [WINMM.@]
3584 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3586 WINE_MIDIStream* lpMidiStrm;
3587 MMRESULT ret = MMSYSERR_NOERROR;
3589 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3591 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3592 ret = MMSYSERR_INVALHANDLE;
3593 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3594 ret = MMSYSERR_INVALPARAM;
3595 } else if (dwProperty & MIDIPROP_TEMPO) {
3596 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3598 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3599 ret = MMSYSERR_INVALPARAM;
3600 } else if (dwProperty & MIDIPROP_SET) {
3601 lpMidiStrm->dwTempo = mpt->dwTempo;
3602 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
3603 } else if (dwProperty & MIDIPROP_GET) {
3604 mpt->dwTempo = lpMidiStrm->dwTempo;
3605 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
3607 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3608 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3610 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3611 ret = MMSYSERR_INVALPARAM;
3612 } else if (dwProperty & MIDIPROP_SET) {
3613 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3614 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
3615 } else if (dwProperty & MIDIPROP_GET) {
3616 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3617 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
3619 } else {
3620 ret = MMSYSERR_INVALPARAM;
3623 return ret;
3626 /**************************************************************************
3627 * midiStreamRestart [WINMM.@]
3629 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3631 WINE_MIDIStream* lpMidiStrm;
3632 MMRESULT ret = MMSYSERR_NOERROR;
3634 TRACE("(%08x)!\n", hMidiStrm);
3636 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3637 ret = MMSYSERR_INVALHANDLE;
3638 } else {
3639 DWORD ret;
3641 /* since we increase the thread suspend count on each midiStreamPause
3642 * there may be a need for several midiStreamResume
3644 do {
3645 ret = ResumeThread(lpMidiStrm->hThread);
3646 } while (ret != 0xFFFFFFFF && ret != 0);
3647 if (ret == 0xFFFFFFFF) {
3648 WARN("bad Resume (%ld)\n", GetLastError());
3649 ret = MMSYSERR_ERROR;
3650 } else {
3651 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
3654 return ret;
3657 /**************************************************************************
3658 * midiStreamStop [WINMM.@]
3660 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3662 WINE_MIDIStream* lpMidiStrm;
3663 MMRESULT ret = MMSYSERR_NOERROR;
3665 TRACE("(%08x)!\n", hMidiStrm);
3667 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3668 ret = MMSYSERR_INVALHANDLE;
3669 } else {
3670 /* in case stream has been paused... FIXME is the current state correct ? */
3671 midiStreamRestart(hMidiStrm);
3672 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
3674 return ret;
3677 /**************************************************************************
3678 * midiStreamClose [MMSYSTEM.252]
3680 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3682 return midiStreamClose(HMIDISTRM_32(hMidiStrm));
3685 /**************************************************************************
3686 * midiStreamOpen [MMSYSTEM.251]
3688 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3689 DWORD cMidi, DWORD dwCallback,
3690 DWORD dwInstance, DWORD fdwOpen)
3692 HMIDISTRM hMidiStrm32;
3693 MMRESULT ret;
3694 UINT devid32;
3696 if (!phMidiStrm || !devid)
3697 return MMSYSERR_INVALPARAM;
3698 devid32 = *devid;
3699 ret = MMSYSTEM_MidiStream_Open(&hMidiStrm32, &devid32, cMidi, dwCallback,
3700 dwInstance, fdwOpen, FALSE);
3701 *phMidiStrm = HMIDISTRM_16(hMidiStrm32);
3702 *devid = devid32;
3703 return ret;
3706 /**************************************************************************
3707 * midiStreamOut [MMSYSTEM.254]
3709 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3711 return midiStreamOut(HMIDISTRM_32(hMidiStrm), (LPMIDIHDR)lpMidiHdr,
3712 cbMidiHdr);
3715 /**************************************************************************
3716 * midiStreamPause [MMSYSTEM.255]
3718 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3720 return midiStreamPause(HMIDISTRM_32(hMidiStrm));
3723 /**************************************************************************
3724 * midiStreamPosition [MMSYSTEM.253]
3726 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3728 MMTIME mmt32;
3729 MMRESULT ret;
3731 if (!lpmmt16)
3732 return MMSYSERR_INVALPARAM;
3733 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3734 ret = midiStreamPosition(HMIDISTRM_32(hMidiStrm), &mmt32, sizeof(MMTIME));
3735 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3736 return ret;
3739 /**************************************************************************
3740 * midiStreamProperty [MMSYSTEM.250]
3742 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3744 return midiStreamProperty(HMIDISTRM_32(hMidiStrm), lpPropData, dwProperty);
3747 /**************************************************************************
3748 * midiStreamRestart [MMSYSTEM.256]
3750 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3752 return midiStreamRestart(HMIDISTRM_32(hMidiStrm));
3755 /**************************************************************************
3756 * midiStreamStop [MMSYSTEM.257]
3758 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3760 return midiStreamStop(HMIDISTRM_32(hMidiStrm));
3763 static UINT WINAPI MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
3764 const LPWAVEFORMATEX lpFormat,
3765 DWORD dwCallback, DWORD dwInstance,
3766 DWORD dwFlags, BOOL bFrom32)
3768 HANDLE handle;
3769 LPWINE_MLD wmld;
3770 DWORD dwRet = MMSYSERR_NOERROR;
3771 WAVEOPENDESC wod;
3773 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
3774 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
3775 dwInstance, dwFlags, bFrom32?32:16);
3777 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
3779 if (lpFormat == NULL) return WAVERR_BADFORMAT;
3780 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
3781 return MMSYSERR_INVALPARAM;
3783 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
3784 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
3785 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
3787 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
3788 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
3789 return MMSYSERR_NOMEM;
3791 wod.hWave = handle;
3792 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
3793 wod.dwCallback = dwCallback;
3794 wod.dwInstance = dwInstance;
3795 wod.dnDevNode = 0L;
3797 if (dwFlags & WAVE_MAPPED) {
3798 wod.uMappedDeviceID = uDeviceID;
3799 uDeviceID = WAVE_MAPPER;
3800 } else {
3801 wod.uMappedDeviceID = -1;
3803 wmld->uDeviceID = uDeviceID;
3805 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, (DWORD)&wod, dwFlags);
3807 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
3808 MMDRV_Free(handle, wmld);
3809 handle = 0;
3812 if (lphndl != NULL) *lphndl = handle;
3813 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
3815 return dwRet;
3818 /**************************************************************************
3819 * waveOutGetNumDevs [WINMM.@]
3821 UINT WINAPI waveOutGetNumDevs(void)
3823 return MMDRV_GetNum(MMDRV_WAVEOUT);
3826 /**************************************************************************
3827 * waveOutGetNumDevs [MMSYSTEM.401]
3829 UINT16 WINAPI waveOutGetNumDevs16(void)
3831 return MMDRV_GetNum(MMDRV_WAVEOUT);
3834 /**************************************************************************
3835 * waveOutGetDevCaps [MMSYSTEM.402]
3837 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID,
3838 LPWAVEOUTCAPS16 lpCaps, UINT16 uSize)
3840 WAVEOUTCAPSA wocA;
3841 UINT ret;
3843 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3844 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3846 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3848 if (ret == MMSYSERR_NOERROR) {
3849 lpCaps->wMid = wocA.wMid;
3850 lpCaps->wPid = wocA.wPid;
3851 lpCaps->vDriverVersion = wocA.vDriverVersion;
3852 strcpy(lpCaps->szPname, wocA.szPname);
3853 lpCaps->dwFormats = wocA.dwFormats;
3854 lpCaps->wChannels = wocA.wChannels;
3855 lpCaps->dwSupport = wocA.dwSupport;
3857 return ret;
3860 /**************************************************************************
3861 * waveOutGetDevCapsA [WINMM.@]
3863 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3864 UINT uSize)
3866 LPWINE_MLD wmld;
3868 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3870 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3872 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
3873 return MMSYSERR_INVALHANDLE;
3875 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
3879 /**************************************************************************
3880 * waveOutGetDevCapsW [WINMM.@]
3882 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3883 UINT uSize)
3885 WAVEOUTCAPSA wocA;
3886 UINT ret;
3888 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3890 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3892 if (ret == MMSYSERR_NOERROR) {
3893 lpCaps->wMid = wocA.wMid;
3894 lpCaps->wPid = wocA.wPid;
3895 lpCaps->vDriverVersion = wocA.vDriverVersion;
3896 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
3897 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
3898 lpCaps->dwFormats = wocA.dwFormats;
3899 lpCaps->wChannels = wocA.wChannels;
3900 lpCaps->dwSupport = wocA.dwSupport;
3902 return ret;
3905 /**************************************************************************
3906 * WAVE_GetErrorText [internal]
3908 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3910 UINT16 ret = MMSYSERR_BADERRNUM;
3912 if (lpText == NULL) {
3913 ret = MMSYSERR_INVALPARAM;
3914 } else if (uSize == 0) {
3915 ret = MMSYSERR_NOERROR;
3916 } else if (
3917 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
3918 * a warning for the test was always true */
3919 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
3920 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
3922 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
3923 uError, lpText, uSize) > 0) {
3924 ret = MMSYSERR_NOERROR;
3927 return ret;
3930 /**************************************************************************
3931 * waveOutGetErrorText [MMSYSTEM.403]
3933 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3935 return WAVE_GetErrorText(uError, lpText, uSize);
3938 /**************************************************************************
3939 * waveOutGetErrorTextA [WINMM.@]
3941 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3943 return WAVE_GetErrorText(uError, lpText, uSize);
3946 /**************************************************************************
3947 * waveOutGetErrorTextW [WINMM.@]
3949 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3951 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3952 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
3954 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
3955 HeapFree(GetProcessHeap(), 0, xstr);
3956 return ret;
3959 /**************************************************************************
3960 * waveOutOpen [WINMM.@]
3961 * All the args/structs have the same layout as the win16 equivalents
3963 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3964 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3965 DWORD dwInstance, DWORD dwFlags)
3967 return MMSYSTEM_waveOpen(lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
3968 dwCallback, dwInstance, dwFlags, TRUE);
3971 /**************************************************************************
3972 * waveOutOpen [MMSYSTEM.404]
3974 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3975 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3976 DWORD dwInstance, DWORD dwFlags)
3978 HWAVEOUT hWaveOut;
3979 UINT ret;
3981 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
3982 * call the 32 bit version
3983 * however, we need to promote correctly the wave mapper id
3984 * (0xFFFFFFFF and not 0x0000FFFF)
3986 ret = MMSYSTEM_waveOpen(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
3987 MMDRV_WAVEOUT, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
3989 if (lphWaveOut != NULL) *lphWaveOut = HWAVEOUT_16(hWaveOut);
3990 return ret;
3993 /**************************************************************************
3994 * waveOutClose [WINMM.@]
3996 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3998 LPWINE_MLD wmld;
3999 DWORD dwRet;
4001 TRACE("(%04X)\n", hWaveOut);
4003 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4004 return MMSYSERR_INVALHANDLE;
4006 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
4007 MMDRV_Free(hWaveOut, wmld);
4009 return dwRet;
4012 /**************************************************************************
4013 * waveOutClose [MMSYSTEM.405]
4015 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
4017 DWORD level;
4018 UINT16 ret;
4020 ReleaseThunkLock(&level);
4021 ret = waveOutClose(HWAVEOUT_32(hWaveOut));
4022 RestoreThunkLock(level);
4023 return ret;
4026 /**************************************************************************
4027 * waveOutPrepareHeader [WINMM.@]
4029 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
4030 WAVEHDR* lpWaveOutHdr, UINT uSize)
4032 LPWINE_MLD wmld;
4034 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4036 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
4038 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4039 return MMSYSERR_INVALHANDLE;
4041 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4044 /**************************************************************************
4045 * waveOutPrepareHeader [MMSYSTEM.406]
4047 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
4048 SEGPTR lpsegWaveOutHdr, /* [???] */
4049 UINT16 uSize) /* [in] */
4051 LPWINE_MLD wmld;
4052 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
4054 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4056 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
4058 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL)
4059 return MMSYSERR_INVALHANDLE;
4061 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4064 /**************************************************************************
4065 * waveOutUnprepareHeader [WINMM.@]
4067 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
4068 LPWAVEHDR lpWaveOutHdr, UINT uSize)
4070 LPWINE_MLD wmld;
4072 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4074 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
4075 return MMSYSERR_NOERROR;
4078 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4079 return MMSYSERR_INVALHANDLE;
4081 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4084 /**************************************************************************
4085 * waveOutUnprepareHeader [MMSYSTEM.407]
4087 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
4088 SEGPTR lpsegWaveOutHdr, /* [???] */
4089 UINT16 uSize) /* [in] */
4091 LPWINE_MLD wmld;
4092 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
4094 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4096 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
4097 return MMSYSERR_NOERROR;
4100 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL)
4101 return MMSYSERR_INVALHANDLE;
4103 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4106 /**************************************************************************
4107 * waveOutWrite [WINMM.@]
4109 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
4110 UINT uSize)
4112 LPWINE_MLD wmld;
4114 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4116 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4117 return MMSYSERR_INVALHANDLE;
4119 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4122 /**************************************************************************
4123 * waveOutWrite [MMSYSTEM.408]
4125 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */
4126 LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */
4127 UINT16 uSize) /* [in] */
4129 LPWINE_MLD wmld;
4131 TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4133 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL)
4134 return MMSYSERR_INVALHANDLE;
4136 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4139 /**************************************************************************
4140 * waveOutBreakLoop [WINMM.@]
4142 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
4144 LPWINE_MLD wmld;
4146 TRACE("(%04X);\n", hWaveOut);
4148 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4149 return MMSYSERR_INVALHANDLE;
4150 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
4153 /**************************************************************************
4154 * waveOutBreakLoop [MMSYSTEM.419]
4156 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16)
4158 DWORD level;
4159 UINT16 ret;
4161 ReleaseThunkLock(&level);
4162 ret = waveOutBreakLoop(HWAVEOUT_32(hWaveOut16));
4163 RestoreThunkLock(level);
4164 return ret;
4167 /**************************************************************************
4168 * waveOutPause [WINMM.@]
4170 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
4172 LPWINE_MLD wmld;
4174 TRACE("(%04X);\n", hWaveOut);
4176 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4177 return MMSYSERR_INVALHANDLE;
4178 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
4181 /**************************************************************************
4182 * waveOutPause [MMSYSTEM.409]
4184 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16)
4186 DWORD level;
4187 UINT16 ret;
4189 ReleaseThunkLock(&level);
4190 ret = waveOutPause(HWAVEOUT_32(hWaveOut16));
4191 RestoreThunkLock(level);
4192 return ret;
4195 /**************************************************************************
4196 * waveOutReset [WINMM.@]
4198 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
4200 LPWINE_MLD wmld;
4202 TRACE("(%04X);\n", hWaveOut);
4204 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4205 return MMSYSERR_INVALHANDLE;
4206 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
4209 /**************************************************************************
4210 * waveOutReset [MMSYSTEM.411]
4212 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16)
4214 DWORD level;
4215 UINT16 ret;
4217 ReleaseThunkLock(&level);
4218 ret = waveOutReset(HWAVEOUT_32(hWaveOut16));
4219 RestoreThunkLock(level);
4220 return ret;
4223 /**************************************************************************
4224 * waveOutRestart [WINMM.@]
4226 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
4228 LPWINE_MLD wmld;
4230 TRACE("(%04X);\n", hWaveOut);
4232 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4233 return MMSYSERR_INVALHANDLE;
4234 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
4237 /**************************************************************************
4238 * waveOutRestart [MMSYSTEM.410]
4240 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16)
4242 DWORD level;
4243 UINT16 ret;
4245 ReleaseThunkLock(&level);
4246 ret = waveOutRestart(HWAVEOUT_32(hWaveOut16));
4247 RestoreThunkLock(level);
4248 return ret;
4251 /**************************************************************************
4252 * waveOutGetPosition [WINMM.@]
4254 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
4255 UINT uSize)
4257 LPWINE_MLD wmld;
4259 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
4261 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4262 return MMSYSERR_INVALHANDLE;
4264 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4267 /**************************************************************************
4268 * waveOutGetPosition [MMSYSTEM.412]
4270 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
4271 UINT16 uSize)
4273 UINT ret;
4274 MMTIME mmt;
4276 mmt.wType = lpTime->wType;
4277 ret = waveOutGetPosition(HWAVEOUT_32(hWaveOut), &mmt, sizeof(mmt));
4278 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4279 return ret;
4282 /**************************************************************************
4283 * waveOutGetPitch [WINMM.@]
4285 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
4287 LPWINE_MLD wmld;
4289 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4291 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4292 return MMSYSERR_INVALHANDLE;
4293 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
4296 /**************************************************************************
4297 * waveOutGetPitch [MMSYSTEM.413]
4299 UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4301 return waveOutGetPitch(HWAVEOUT_32(hWaveOut16), lpdw);
4304 /**************************************************************************
4305 * waveOutSetPitch [WINMM.@]
4307 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
4309 LPWINE_MLD wmld;
4311 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4313 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4314 return MMSYSERR_INVALHANDLE;
4315 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
4318 /**************************************************************************
4319 * waveOutSetPitch [MMSYSTEM.414]
4321 UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw)
4323 return waveOutSetPitch(HWAVEOUT_32(hWaveOut16), dw);
4326 /**************************************************************************
4327 * waveOutGetPlaybackRate [WINMM.@]
4329 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
4331 LPWINE_MLD wmld;
4333 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4335 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4336 return MMSYSERR_INVALHANDLE;
4337 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
4340 /**************************************************************************
4341 * waveOutGetPlaybackRate [MMSYSTEM.417]
4343 UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4345 return waveOutGetPlaybackRate(HWAVEOUT_32(hWaveOut16), lpdw);
4348 /**************************************************************************
4349 * waveOutSetPlaybackRate [WINMM.@]
4351 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
4353 LPWINE_MLD wmld;
4355 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4357 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4358 return MMSYSERR_INVALHANDLE;
4359 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
4362 /**************************************************************************
4363 * waveOutSetPlaybackRate [MMSYSTEM.418]
4365 UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw)
4367 return waveOutSetPlaybackRate(HWAVEOUT_32(hWaveOut16), dw);
4370 /**************************************************************************
4371 * waveOutGetVolume [WINMM.@]
4373 UINT WINAPI waveOutGetVolume(UINT devid, LPDWORD lpdw)
4375 LPWINE_MLD wmld;
4377 TRACE("(%04X, %08lx);\n", devid, (DWORD)lpdw);
4379 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4380 return MMSYSERR_INVALHANDLE;
4382 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
4385 /**************************************************************************
4386 * waveOutGetVolume [MMSYSTEM.415]
4388 UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw)
4390 return waveOutGetVolume(devid, lpdw);
4393 /**************************************************************************
4394 * waveOutSetVolume [WINMM.@]
4396 UINT WINAPI waveOutSetVolume(UINT devid, DWORD dw)
4398 LPWINE_MLD wmld;
4400 TRACE("(%04X, %08lx);\n", devid, dw);
4402 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4403 return MMSYSERR_INVALHANDLE;
4405 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
4408 /**************************************************************************
4409 * waveOutSetVolume [MMSYSTEM.416]
4411 UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw)
4413 return waveOutSetVolume(devid, dw);
4416 /**************************************************************************
4417 * waveOutGetID [WINMM.@]
4419 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
4421 LPWINE_MLD wmld;
4423 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4425 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4427 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4428 return MMSYSERR_INVALHANDLE;
4430 *lpuDeviceID = wmld->uDeviceID;
4431 return 0;
4434 /**************************************************************************
4435 * waveOutGetID [MMSYSTEM.420]
4437 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
4439 LPWINE_MLD wmld;
4441 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4443 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4445 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL)
4446 return MMSYSERR_INVALHANDLE;
4448 *lpuDeviceID = wmld->uDeviceID;
4449 return 0;
4452 /**************************************************************************
4453 * waveOutMessage [WINMM.@]
4455 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
4456 DWORD dwParam1, DWORD dwParam2)
4458 LPWINE_MLD wmld;
4460 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4462 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4463 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4464 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4466 return MMSYSERR_INVALHANDLE;
4469 /* from M$ KB */
4470 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4471 return MMSYSERR_INVALPARAM;
4473 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4476 /**************************************************************************
4477 * waveOutMessage [MMSYSTEM.421]
4479 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4480 DWORD dwParam1, DWORD dwParam2)
4482 LPWINE_MLD wmld;
4484 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4486 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) {
4487 if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, TRUE)) != NULL) {
4488 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4490 return MMSYSERR_INVALHANDLE;
4493 /* from M$ KB */
4494 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4495 return MMSYSERR_INVALPARAM;
4497 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
4500 /**************************************************************************
4501 * waveInGetNumDevs [WINMM.@]
4503 UINT WINAPI waveInGetNumDevs(void)
4505 return MMDRV_GetNum(MMDRV_WAVEIN);
4508 /**************************************************************************
4509 * waveInGetNumDevs [MMSYSTEM.501]
4511 UINT16 WINAPI waveInGetNumDevs16(void)
4513 return MMDRV_GetNum(MMDRV_WAVEIN);
4516 /**************************************************************************
4517 * waveInGetDevCapsW [WINMM.@]
4519 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4521 WAVEINCAPSA wicA;
4522 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
4524 if (ret == MMSYSERR_NOERROR) {
4525 lpCaps->wMid = wicA.wMid;
4526 lpCaps->wPid = wicA.wPid;
4527 lpCaps->vDriverVersion = wicA.vDriverVersion;
4528 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
4529 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
4530 lpCaps->dwFormats = wicA.dwFormats;
4531 lpCaps->wChannels = wicA.wChannels;
4534 return ret;
4537 /**************************************************************************
4538 * waveInGetDevCapsA [WINMM.@]
4540 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4542 LPWINE_MLD wmld;
4544 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
4546 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
4547 return MMSYSERR_INVALHANDLE;
4549 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
4552 /**************************************************************************
4553 * waveInGetDevCaps [MMSYSTEM.502]
4555 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps,
4556 UINT16 uSize)
4558 WAVEINCAPSA wicA;
4559 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
4561 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
4563 if (ret == MMSYSERR_NOERROR) {
4564 lpCaps->wMid = wicA.wMid;
4565 lpCaps->wPid = wicA.wPid;
4566 lpCaps->vDriverVersion = wicA.vDriverVersion;
4567 strcpy(lpCaps->szPname, wicA.szPname);
4568 lpCaps->dwFormats = wicA.dwFormats;
4569 lpCaps->wChannels = wicA.wChannels;
4571 return ret;
4574 /**************************************************************************
4575 * waveInGetErrorTextA [WINMM.@]
4577 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4579 return WAVE_GetErrorText(uError, lpText, uSize);
4582 /**************************************************************************
4583 * waveInGetErrorTextW [WINMM.@]
4585 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4587 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4588 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
4590 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
4591 HeapFree(GetProcessHeap(), 0, txt);
4592 return ret;
4595 /**************************************************************************
4596 * waveInGetErrorText [MMSYSTEM.503]
4598 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4600 return WAVE_GetErrorText(uError, lpText, uSize);
4603 /**************************************************************************
4604 * waveInOpen [WINMM.@]
4606 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4607 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4608 DWORD dwInstance, DWORD dwFlags)
4610 return MMSYSTEM_waveOpen(lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
4611 dwCallback, dwInstance, dwFlags, TRUE);
4614 /**************************************************************************
4615 * waveInOpen [MMSYSTEM.504]
4617 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4618 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4619 DWORD dwInstance, DWORD dwFlags)
4621 HWAVEIN hWaveIn;
4622 UINT ret;
4624 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
4625 * call the 32 bit version
4626 * however, we need to promote correctly the wave mapper id
4627 * (0xFFFFFFFF and not 0x0000FFFF)
4629 ret = MMSYSTEM_waveOpen(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
4630 MMDRV_WAVEIN, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
4632 if (lphWaveIn != NULL) *lphWaveIn = HWAVEIN_16(hWaveIn);
4633 return ret;
4636 /**************************************************************************
4637 * waveInClose [WINMM.@]
4639 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4641 LPWINE_MLD wmld;
4642 DWORD dwRet;
4644 TRACE("(%04X)\n", hWaveIn);
4646 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4647 return MMSYSERR_INVALHANDLE;
4649 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
4650 MMDRV_Free(hWaveIn, wmld);
4651 return dwRet;
4654 /**************************************************************************
4655 * waveInClose [MMSYSTEM.505]
4657 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4659 DWORD level;
4660 UINT16 ret;
4662 ReleaseThunkLock(&level);
4663 ret = waveInClose(HWAVEIN_32(hWaveIn));
4664 RestoreThunkLock(level);
4665 return ret;
4668 /**************************************************************************
4669 * waveInPrepareHeader [WINMM.@]
4671 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4672 UINT uSize)
4674 LPWINE_MLD wmld;
4676 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4678 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4679 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4680 return MMSYSERR_INVALHANDLE;
4682 lpWaveInHdr->dwBytesRecorded = 0;
4684 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4687 /**************************************************************************
4688 * waveInPrepareHeader [MMSYSTEM.506]
4690 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4691 SEGPTR lpsegWaveInHdr, /* [???] */
4692 UINT16 uSize) /* [in] */
4694 LPWINE_MLD wmld;
4695 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4696 UINT16 ret;
4698 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4700 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4701 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4702 return MMSYSERR_INVALHANDLE;
4704 lpWaveInHdr->dwBytesRecorded = 0;
4706 ret = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4707 return ret;
4710 /**************************************************************************
4711 * waveInUnprepareHeader [WINMM.@]
4713 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4714 UINT uSize)
4716 LPWINE_MLD wmld;
4718 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4720 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4721 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4722 return MMSYSERR_NOERROR;
4725 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4726 return MMSYSERR_INVALHANDLE;
4728 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4731 /**************************************************************************
4732 * waveInUnprepareHeader [MMSYSTEM.507]
4734 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4735 SEGPTR lpsegWaveInHdr, /* [???] */
4736 UINT16 uSize) /* [in] */
4738 LPWINE_MLD wmld;
4739 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4741 TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4743 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4745 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4746 return MMSYSERR_NOERROR;
4749 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4750 return MMSYSERR_INVALHANDLE;
4752 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4755 /**************************************************************************
4756 * waveInAddBuffer [WINMM.@]
4758 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4759 WAVEHDR* lpWaveInHdr, UINT uSize)
4761 LPWINE_MLD wmld;
4763 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4765 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4766 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4767 return MMSYSERR_INVALHANDLE;
4769 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
4772 /**************************************************************************
4773 * waveInAddBuffer [MMSYSTEM.508]
4775 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */
4776 WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */
4777 UINT16 uSize) /* [in] */
4779 LPWINE_MLD wmld;
4781 TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4783 if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4784 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4785 return MMSYSERR_INVALHANDLE;
4787 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4790 /**************************************************************************
4791 * waveInReset [WINMM.@]
4793 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4795 LPWINE_MLD wmld;
4797 TRACE("(%04X);\n", hWaveIn);
4799 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4800 return MMSYSERR_INVALHANDLE;
4802 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
4805 /**************************************************************************
4806 * waveInReset [MMSYSTEM.511]
4808 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16)
4810 DWORD level;
4811 UINT16 ret;
4813 ReleaseThunkLock(&level);
4814 ret = waveInReset(HWAVEIN_32(hWaveIn16));
4815 RestoreThunkLock(level);
4816 return ret;
4819 /**************************************************************************
4820 * waveInStart [WINMM.@]
4822 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4824 LPWINE_MLD wmld;
4826 TRACE("(%04X);\n", hWaveIn);
4828 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4829 return MMSYSERR_INVALHANDLE;
4831 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
4834 /**************************************************************************
4835 * waveInStart [MMSYSTEM.509]
4837 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16)
4839 DWORD level;
4840 UINT16 ret;
4842 ReleaseThunkLock(&level);
4843 ret = waveInStart(HWAVEIN_32(hWaveIn16));
4844 RestoreThunkLock(level);
4845 return ret;
4848 /**************************************************************************
4849 * waveInStop [WINMM.@]
4851 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4853 LPWINE_MLD wmld;
4855 TRACE("(%04X);\n", hWaveIn);
4857 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4858 return MMSYSERR_INVALHANDLE;
4860 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
4863 /**************************************************************************
4864 * waveInStop [MMSYSTEM.510]
4866 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16)
4868 DWORD level;
4869 UINT16 ret;
4871 ReleaseThunkLock(&level);
4872 ret = waveInStop(HWAVEIN_32(hWaveIn16));
4873 RestoreThunkLock(level);
4874 return ret;
4877 /**************************************************************************
4878 * waveInGetPosition [WINMM.@]
4880 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4881 UINT uSize)
4883 LPWINE_MLD wmld;
4885 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4887 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4888 return MMSYSERR_INVALHANDLE;
4890 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4893 /**************************************************************************
4894 * waveInGetPosition [MMSYSTEM.512]
4896 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4897 UINT16 uSize)
4899 UINT ret;
4900 MMTIME mmt;
4902 mmt.wType = lpTime->wType;
4903 ret = waveInGetPosition(HWAVEIN_32(hWaveIn), &mmt, sizeof(mmt));
4904 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4905 return ret;
4908 /**************************************************************************
4909 * waveInGetID [WINMM.@]
4911 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4913 LPWINE_MLD wmld;
4915 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4917 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4919 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4920 return MMSYSERR_INVALHANDLE;
4922 *lpuDeviceID = wmld->uDeviceID;
4923 return MMSYSERR_NOERROR;
4926 /**************************************************************************
4927 * waveInGetID [MMSYSTEM.513]
4929 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4931 LPWINE_MLD wmld;
4933 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4935 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4937 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4938 return MMSYSERR_INVALHANDLE;
4940 *lpuDeviceID = wmld->uDeviceID;
4941 return MMSYSERR_NOERROR;
4944 /**************************************************************************
4945 * waveInMessage [WINMM.@]
4947 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4948 DWORD dwParam1, DWORD dwParam2)
4950 LPWINE_MLD wmld;
4952 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4954 /* from M$ KB */
4955 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4956 return MMSYSERR_INVALPARAM;
4958 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4959 return MMSYSERR_INVALHANDLE;
4961 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4964 /**************************************************************************
4965 * waveInMessage [MMSYSTEM.514]
4967 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4968 DWORD dwParam1, DWORD dwParam2)
4970 LPWINE_MLD wmld;
4972 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4974 /* from M$ KB */
4975 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4976 return MMSYSERR_INVALPARAM;
4978 if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL)
4979 return MMSYSERR_INVALHANDLE;
4981 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4984 /*#define USE_MM_TSK_WINE*/
4986 /**************************************************************************
4987 * mmTaskCreate [MMSYSTEM.900]
4989 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4990 * called upon creation with dwPmt as parameter.
4992 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4994 HINSTANCE16 ret;
4995 HINSTANCE16 handle;
4996 char cmdline[16];
4997 DWORD showCmd = 0x40002;
4998 LOADPARAMS16 lp;
5000 TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
5001 /* This to work requires NE modules to be started with a binary command line
5002 * which is not currently the case. A patch exists but has never been committed.
5003 * A workaround would be to integrate code for mmtask.tsk into Wine, but
5004 * this requires tremendous work (starting with patching tools/build to
5005 * create NE executables (and not only DLLs) for builtins modules.
5006 * EP 99/04/25
5008 FIXME("This is currently broken. It will fail\n");
5010 cmdline[0] = 0x0d;
5011 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
5012 *(LPDWORD)(cmdline + 5) = dwPmt;
5013 *(LPDWORD)(cmdline + 9) = 0;
5015 lp.hEnvironment = 0;
5016 lp.cmdLine = MapLS(cmdline);
5017 lp.showCmd = MapLS(&showCmd);
5018 lp.reserved = 0;
5020 #ifndef USE_MM_TSK_WINE
5021 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp);
5022 #else
5023 handle = LoadModule16("mmtask.tsk", &lp);
5024 #endif
5025 if (handle < 32) {
5026 ret = (handle) ? 1 : 2;
5027 handle = 0;
5028 } else {
5029 ret = 0;
5031 if (lphMmTask)
5032 *lphMmTask = handle;
5034 UnMapLS( lp.cmdLine );
5035 UnMapLS( lp.showCmd );
5036 TRACE("=> 0x%04x/%d\n", handle, ret);
5037 return ret;
5040 #ifdef USE_MM_TSK_WINE
5041 /* C equivalent to mmtask.tsk binary content */
5042 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
5044 int len = cmdLine[0x80];
5046 if (len / 2 == 6) {
5047 void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1)));
5048 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
5050 #if 0
5051 InitTask16(); /* FIXME: pmts / from context ? */
5052 InitApp(di);
5053 #endif
5054 if (SetMessageQueue16(0x40)) {
5055 WaitEvent16(0);
5056 if (HIWORD(fpProc)) {
5057 OldYield16();
5058 /* EPP StackEnter16(); */
5059 (fpProc)(dwPmt);
5063 OldYield16();
5064 OldYield16();
5065 OldYield16();
5066 ExitProcess(0);
5068 #endif
5070 /**************************************************************************
5071 * mmTaskBlock [MMSYSTEM.902]
5073 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
5075 MSG msg;
5077 do {
5078 GetMessageA(&msg, 0, 0, 0);
5079 if (msg.hwnd) {
5080 TranslateMessage(&msg);
5081 DispatchMessageA(&msg);
5083 } while (msg.message < 0x3A0);
5086 /**************************************************************************
5087 * mmTaskSignal [MMSYSTEM.903]
5089 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
5091 TRACE("(%04x);\n", ht);
5092 return PostAppMessage16(ht, WM_USER, 0, 0);
5095 /**************************************************************************
5096 * mmGetCurrentTask [MMSYSTEM.904]
5098 HTASK16 WINAPI mmGetCurrentTask16(void)
5100 return GetCurrentTask();
5103 /**************************************************************************
5104 * mmTaskYield [MMSYSTEM.905]
5106 void WINAPI mmTaskYield16(void)
5108 MSG msg;
5110 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
5111 K32WOWYield16();
5115 DWORD WINAPI GetProcessFlags(DWORD);
5117 /**************************************************************************
5118 * mmThreadCreate [MMSYSTEM.1120]
5120 * undocumented
5121 * Creates a MM thread, calling fpThreadAddr(dwPmt).
5122 * dwFlags:
5123 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
5124 * bit.1 set means to open a VxD for this thread (unsupported)
5126 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
5128 HANDLE16 hndl;
5129 LRESULT ret;
5131 TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
5133 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
5135 if (hndl == 0) {
5136 ret = 2;
5137 } else {
5138 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5140 #if 0
5141 /* force mmtask routines even if mmthread is required */
5142 /* this will work only if the patch about binary cmd line and NE tasks
5143 * is committed
5145 dwFlags |= 1;
5146 #endif
5148 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
5149 lpMMThd->dwCounter = 0;
5150 lpMMThd->hThread = 0;
5151 lpMMThd->dwThreadID = 0;
5152 lpMMThd->fpThread = fpThreadAddr;
5153 lpMMThd->dwThreadPmt = dwPmt;
5154 lpMMThd->dwSignalCount = 0;
5155 lpMMThd->hEvent = 0;
5156 lpMMThd->hVxD = 0;
5157 lpMMThd->dwStatus = 0;
5158 lpMMThd->dwFlags = dwFlags;
5159 lpMMThd->hTask = 0;
5161 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
5162 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
5164 TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
5165 if (lpMMThd->dwFlags & 2) {
5166 /* as long as we don't support MM VxD in wine, we don't need
5167 * to care about this flag
5169 /* FIXME("Don't know how to properly open VxD handles\n"); */
5170 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
5173 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
5174 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
5175 if (lpMMThd->hThread == 0) {
5176 WARN("Couldn't create thread\n");
5177 /* clean-up(VxDhandle...); devicedirectio... */
5178 if (lpMMThd->hEvent != 0)
5179 CloseHandle(lpMMThd->hEvent);
5180 ret = 2;
5181 } else {
5182 TRACE("Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
5183 ret = 0;
5185 } else {
5186 /* get WINE_mmThreadEntryPoint()
5187 * 2047 is its ordinal in mmsystem.spec
5189 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047);
5191 TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp));
5193 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
5196 if (ret == 0) {
5197 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
5198 WARN("Couldn't resume thread\n");
5200 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
5201 UserYield16();
5206 if (ret != 0) {
5207 GlobalFree16(hndl);
5208 hndl = 0;
5211 if (lpHndl)
5212 *lpHndl = hndl;
5214 TRACE("ok => %ld\n", ret);
5215 return ret;
5218 /**************************************************************************
5219 * mmThreadSignal [MMSYSTEM.1121]
5221 void WINAPI mmThreadSignal16(HANDLE16 hndl)
5223 TRACE("(%04x)!\n", hndl);
5225 if (hndl) {
5226 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5228 lpMMThd->dwCounter++;
5229 if (lpMMThd->hThread != 0) {
5230 InterlockedIncrement(&lpMMThd->dwSignalCount);
5231 SetEvent(lpMMThd->hEvent);
5232 } else {
5233 mmTaskSignal16(lpMMThd->hTask);
5235 lpMMThd->dwCounter--;
5239 /**************************************************************************
5240 * MMSYSTEM_ThreadBlock [internal]
5242 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
5244 MSG msg;
5245 DWORD ret;
5247 if (lpMMThd->dwThreadID != GetCurrentThreadId())
5248 ERR("Not called by thread itself\n");
5250 for (;;) {
5251 ResetEvent(lpMMThd->hEvent);
5252 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
5253 break;
5254 InterlockedIncrement(&lpMMThd->dwSignalCount);
5256 TRACE("S1\n");
5258 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
5259 switch (ret) {
5260 case WAIT_OBJECT_0: /* Event */
5261 TRACE("S2.1\n");
5262 break;
5263 case WAIT_OBJECT_0 + 1: /* Msg */
5264 TRACE("S2.2\n");
5265 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
5266 TranslateMessage(&msg);
5267 DispatchMessageA(&msg);
5269 break;
5270 default:
5271 WARN("S2.x unsupported ret val 0x%08lx\n", ret);
5273 TRACE("S3\n");
5277 /**************************************************************************
5278 * mmThreadBlock [MMSYSTEM.1122]
5280 void WINAPI mmThreadBlock16(HANDLE16 hndl)
5282 TRACE("(%04x)!\n", hndl);
5284 if (hndl) {
5285 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5287 if (lpMMThd->hThread != 0) {
5288 DWORD lc;
5290 ReleaseThunkLock(&lc);
5291 MMSYSTEM_ThreadBlock(lpMMThd);
5292 RestoreThunkLock(lc);
5293 } else {
5294 mmTaskBlock16(lpMMThd->hTask);
5297 TRACE("done\n");
5300 /**************************************************************************
5301 * mmThreadIsCurrent [MMSYSTEM.1123]
5303 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
5305 BOOL16 ret = FALSE;
5307 TRACE("(%04x)!\n", hndl);
5309 if (hndl && mmThreadIsValid16(hndl)) {
5310 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5311 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
5313 TRACE("=> %d\n", ret);
5314 return ret;
5317 /**************************************************************************
5318 * mmThreadIsValid [MMSYSTEM.1124]
5320 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
5322 BOOL16 ret = FALSE;
5324 TRACE("(%04x)!\n", hndl);
5326 if (hndl) {
5327 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5329 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
5330 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
5331 IsTask16(lpMMThd->hTask)) {
5332 lpMMThd->dwCounter++;
5333 if (lpMMThd->hThread != 0) {
5334 DWORD dwThreadRet;
5335 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
5336 dwThreadRet == STATUS_PENDING) {
5337 ret = TRUE;
5339 } else {
5340 ret = TRUE;
5342 lpMMThd->dwCounter--;
5345 TRACE("=> %d\n", ret);
5346 return ret;
5349 /**************************************************************************
5350 * mmThreadGetTask [MMSYSTEM.1125]
5352 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5354 HANDLE16 ret = 0;
5356 TRACE("(%04x)\n", hndl);
5358 if (mmThreadIsValid16(hndl)) {
5359 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5360 ret = lpMMThd->hTask;
5362 return ret;
5365 /* ### start build ### */
5366 extern LONG CALLBACK MMSYSTEM_CallTo16_long_l (FARPROC16,LONG);
5367 /* ### stop build ### */
5369 /**************************************************************************
5370 * __wine_mmThreadEntryPoint (MMSYSTEM.2047)
5372 void WINAPI WINE_mmThreadEntryPoint(DWORD _pmt)
5374 HANDLE16 hndl = (HANDLE16)_pmt;
5375 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5377 TRACE("(%04x %p)\n", hndl, lpMMThd);
5379 lpMMThd->hTask = LOWORD(GetCurrentTask());
5380 TRACE("[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5381 lpMMThd->dwStatus = 0x10;
5382 MMSYSTEM_ThreadBlock(lpMMThd);
5383 TRACE("[20-%08x]\n", lpMMThd->hThread);
5384 lpMMThd->dwStatus = 0x20;
5385 if (lpMMThd->fpThread) {
5386 MMSYSTEM_CallTo16_long_l(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5388 lpMMThd->dwStatus = 0x30;
5389 TRACE("[30-%08x]\n", lpMMThd->hThread);
5390 while (lpMMThd->dwCounter) {
5391 Sleep(1);
5392 /* K32WOWYield16();*/
5394 TRACE("[XX-%08x]\n", lpMMThd->hThread);
5395 /* paranoia */
5396 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5397 /* close lpMMThread->hVxD directIO */
5398 if (lpMMThd->hEvent)
5399 CloseHandle(lpMMThd->hEvent);
5400 GlobalFree16(hndl);
5401 TRACE("done\n");
5404 typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR);
5406 /**************************************************************************
5407 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5409 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice,
5410 LPCSTR lpStrTab, LPCSTR lpStrTitle)
5412 HANDLE hndl;
5413 BOOL16 ret = FALSE;
5415 TRACE("(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5417 hndl = LoadLibraryA("MMSYS.CPL");
5418 if (hndl != 0) {
5419 MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5420 if (fp != NULL) {
5421 DWORD lc;
5422 ReleaseThunkLock(&lc);
5423 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5424 RestoreThunkLock(lc);
5426 FreeLibrary(hndl);
5429 return ret;
5432 /**************************************************************************
5433 * StackEnter [MMSYSTEM.32]
5435 void WINAPI StackEnter16(void)
5437 #ifdef __i386__
5438 /* mmsystem.dll from Win 95 does only this: so does Wine */
5439 __asm__("stc");
5440 #endif
5443 /**************************************************************************
5444 * StackLeave [MMSYSTEM.33]
5446 void WINAPI StackLeave16(void)
5448 #ifdef __i386__
5449 /* mmsystem.dll from Win 95 does only this: so does Wine */
5450 __asm__("stc");
5451 #endif
5454 /**************************************************************************
5455 * WMMMidiRunOnce [MMSYSTEM.8]
5457 void WINAPI WMMMidiRunOnce16(void)
5459 FIXME("(), stub!\n");
5462 /**************************************************************************
5463 * OutputDebugStr [MMSYSTEM.30]
5465 void WINAPI OutputDebugStr16(
5466 LPCSTR str) /* [in] The message to be logged and given to the debugger. */
5468 OutputDebugStringA( str );