Check for NULL ptr in midiStreamOut.
[wine/dcerpc.git] / dlls / winmm / mmsystem.c
blob5a51ff39dca622adeed213bfe277197646958409
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MMSYTEM functions
6 * Copyright 1993 Martin Ayotte
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /*
24 * Eric POUECH :
25 * 98/9 added Win32 MCI support
26 * 99/4 added mmTask and mmThread functions support
27 * added midiStream support
28 * 99/9 added support for loadable low level drivers
31 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses
32 * and long term pointers to 16 bit space in here
35 #include <string.h>
37 #include "mmsystem.h"
38 #include "winbase.h"
39 #include "wingdi.h"
41 #include "wine/mmsystem16.h"
42 #include "wine/winuser16.h"
43 #include "heap.h"
44 #include "ntddk.h"
45 #include "winemm.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(mmsys);
51 static LPWINE_MM_IDATA lpFirstIData = NULL;
53 static LPWINE_MM_IDATA MULTIMEDIA_GetIDataNoCheck(void)
55 DWORD pid = GetCurrentProcessId();
56 LPWINE_MM_IDATA iData;
58 for (iData = lpFirstIData; iData; iData = iData->lpNextIData) {
59 if (iData->dwThisProcess == pid)
60 break;
62 return iData;
65 /**************************************************************************
66 * MULTIMEDIA_GetIData [internal]
68 LPWINE_MM_IDATA MULTIMEDIA_GetIData(void)
70 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
72 if (!iData) {
73 ERR("IData not found for pid=%08lx. Suicide !!!\n", GetCurrentProcessId());
74 DbgBreakPoint();
75 ExitProcess(0);
77 return iData;
80 /**************************************************************************
81 * MULTIMEDIA_CreateIData [internal]
83 static BOOL MULTIMEDIA_CreateIData(HINSTANCE hInstDLL)
85 LPWINE_MM_IDATA iData;
87 iData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
89 if (!iData)
90 return FALSE;
91 iData->hWinMM32Instance = hInstDLL;
92 iData->dwThisProcess = GetCurrentProcessId();
93 iData->lpNextIData = lpFirstIData;
94 lpFirstIData = iData;
95 InitializeCriticalSection(&iData->cs);
96 TRACE("Created IData (%p) for pid %08lx\n", iData, iData->dwThisProcess);
97 return TRUE;
100 /**************************************************************************
101 * MULTIMEDIA_DeleteIData [internal]
103 static void MULTIMEDIA_DeleteIData(void)
105 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIDataNoCheck();
106 LPWINE_MM_IDATA* ppid;
108 if (iData) {
109 TIME_MMTimeStop();
111 for (ppid = &lpFirstIData; *ppid; ppid = &(*ppid)->lpNextIData) {
112 if (*ppid == iData) {
113 *ppid = iData->lpNextIData;
114 break;
117 /* FIXME: should also free content and resources allocated
118 * inside iData */
119 HeapFree(GetProcessHeap(), 0, iData);
123 /**************************************************************************
124 * DllEntryPoint (WINMM.init)
126 * WINMM DLL entry point
129 BOOL WINAPI WINMM_LibMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
131 TRACE("0x%x 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
133 switch (fdwReason) {
134 case DLL_PROCESS_ATTACH:
135 if (!MULTIMEDIA_CreateIData(hInstDLL))
136 return FALSE;
137 if (!MULTIMEDIA_MciInit() || !MMDRV_Init()) {
138 MULTIMEDIA_DeleteIData();
139 return FALSE;
141 break;
142 case DLL_PROCESS_DETACH:
143 MULTIMEDIA_DeleteIData();
144 break;
145 case DLL_THREAD_ATTACH:
146 case DLL_THREAD_DETACH:
147 break;
149 return TRUE;
152 /**************************************************************************
153 * DllEntryPoint (MMSYSTEM.2046)
155 * MMSYSTEM DLL entry point
158 BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds,
159 WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
161 HANDLE hndl;
162 LPWINE_MM_IDATA iData;
164 TRACE("0x%x 0x%lx\n", hinstDLL, fdwReason);
166 switch (fdwReason) {
167 case DLL_PROCESS_ATTACH:
168 /* need to load WinMM in order to:
169 * - initiate correctly shared variables (MULTIMEDIA_Init())
170 * - create correctly the per process WINE_MM_IDATA chunk
172 hndl = LoadLibraryA("WINMM.DLL");
174 if (!hndl) {
175 ERR("Could not load sibling WinMM.dll\n");
176 return FALSE;
178 iData = MULTIMEDIA_GetIData();
179 iData->hWinMM16Instance = hinstDLL;
180 iData->h16Module32 = hndl;
181 break;
182 case DLL_PROCESS_DETACH:
183 iData = MULTIMEDIA_GetIData();
184 FreeLibrary(iData->h16Module32);
185 break;
186 case DLL_THREAD_ATTACH:
187 case DLL_THREAD_DETACH:
188 break;
190 return TRUE;
193 /**************************************************************************
194 * MMSYSTEM_WEP [MMSYSTEM.1]
196 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
197 WORD cbHeapSize, LPSTR lpCmdLine)
199 FIXME("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
200 return TRUE;
203 void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
205 mmt16->wType = mmt32->wType;
206 /* layout of rest is the same for 32/16,
207 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
209 memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
212 void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
214 mmt32->wType = mmt16->wType;
215 /* layout of rest is the same for 32/16,
216 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
218 memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
221 static HMMIO get_mmioFromFile(LPCWSTR lpszName)
223 HMMIO ret;
224 WCHAR buf[256];
225 LPWSTR dummy;
227 ret = mmioOpenW((LPWSTR)lpszName, NULL,
228 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
229 if (ret != 0) return ret;
230 if (SearchPathW(NULL, lpszName, NULL, sizeof(buf)/sizeof(buf[0]), buf, &dummy))
232 return mmioOpenW(buf, NULL,
233 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
235 return 0;
238 static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName)
240 WCHAR str[128];
241 LPWSTR ptr;
242 HMMIO hmmio;
243 HKEY hRegSnd, hRegApp, hScheme, hSnd;
244 DWORD err, type, count;
246 static WCHAR wszSounds[] = {'S','o','u','n','d','s',0};
247 static WCHAR wszDefault[] = {'D','e','f','a','u','l','t',0};
248 static WCHAR wszKey[] = {'A','p','p','E','v','e','n','t','s','\\','\\',
249 'S','c','h','e','m','e','s','\\','\\',
250 'A','p','p','s',0};
251 static WCHAR wszDotDefault[] = {'.','D','e','f','a','u','l','t',0};
252 static WCHAR wszNull[] = {0};
254 /* FIXME: we should also look up the registry under
255 * HKCU\AppEvents\Schemes\Apps\.Default
256 * HKCU\AppEvents\Schemes\Apps\<AppName>
259 TRACE("searching in SystemSound list for %s\n", debugstr_w(lpszName));
260 GetProfileStringW(wszSounds, (LPWSTR)lpszName, wszNull, str, sizeof(str)/sizeof(str[0]));
261 if (lstrlenW(str) == 0)
263 if (uFlags & SND_NODEFAULT) goto next;
264 GetProfileStringW(wszSounds, wszDefault, wszNull, str, sizeof(str)/sizeof(str[0]));
265 if (lstrlenW(str) == 0) goto next;
267 for (ptr = str; *ptr && *ptr != ','; ptr++);
268 if (*ptr) *ptr = 0;
269 hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
270 if (hmmio != 0) return hmmio;
271 next:
272 if (RegOpenKeyW(HKEY_CURRENT_USER, wszKey, &hRegSnd) != 0) goto none;
273 if (uFlags & SND_APPLICATION)
275 err = 1;
276 if (GetModuleFileNameW(0, str, sizeof(str)/sizeof(str[0])))
278 LPWSTR ptr;
280 for (ptr = str + lstrlenW(str) - 1; ptr >= str; ptr--)
282 if (*ptr == '.') *ptr = 0;
283 if (*ptr == '\\')
285 err = RegOpenKeyW(hRegSnd, str, &hRegApp);
286 break;
291 else
293 err = RegOpenKeyW(hRegSnd, wszDotDefault, &hRegApp);
295 RegCloseKey(hRegSnd);
296 if (err != 0) goto none;
297 err = RegOpenKeyW(hRegApp, lpszName, &hScheme);
298 RegCloseKey(hRegApp);
299 if (err != 0) goto none;
300 err = RegOpenKeyW(hScheme, wszDotDefault, &hSnd);
301 RegCloseKey(hScheme);
302 if (err != 0) goto none;
303 count = sizeof(str)/sizeof(str[0]);
304 err = RegQueryValueExW(hSnd, NULL, 0, &type, (LPBYTE)str, &count);
305 RegCloseKey(hSnd);
306 if (err != 0) goto none;
307 hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
308 if (hmmio) return hmmio;
309 none:
310 WARN("can't find SystemSound='%s' !\n", debugstr_w(lpszName));
311 return 0;
314 struct playsound_data
316 HANDLE hEvent;
317 DWORD dwEventCount;
320 static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg,
321 DWORD dwInstance,
322 DWORD dwParam1, DWORD dwParam2)
324 struct playsound_data* s = (struct playsound_data*)dwInstance;
326 switch (uMsg) {
327 case WOM_OPEN:
328 case WOM_CLOSE:
329 break;
330 case WOM_DONE:
331 InterlockedIncrement(&s->dwEventCount);
332 TRACE("Returning waveHdr=%lx\n", dwParam1);
333 SetEvent(s->hEvent);
334 break;
335 default:
336 ERR("Unknown uMsg=%d\n", uMsg);
340 static void PlaySound_WaitDone(struct playsound_data* s)
342 for (;;) {
343 ResetEvent(s->hEvent);
344 if (InterlockedDecrement(&s->dwEventCount) >= 0) break;
345 InterlockedIncrement(&s->dwEventCount);
347 WaitForSingleObject(s->hEvent, INFINITE);
351 static DWORD WINAPI proc_PlaySound(LPVOID arg)
353 WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg;
354 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
355 BOOL bRet = FALSE;
356 HMMIO hmmio = 0;
357 MMCKINFO ckMainRIFF;
358 MMCKINFO mmckInfo;
359 LPWAVEFORMATEX lpWaveFormat = NULL;
360 HWAVE hWave = 0;
361 LPWAVEHDR waveHdr = NULL;
362 INT count, bufsize, left, index;
363 struct playsound_data s;
364 void* data;
366 s.hEvent = 0;
368 TRACE("SoundName='%s' !\n", debugstr_w(wps->pszSound));
370 /* if resource, grab it */
371 if ((wps->fdwSound & SND_RESOURCE) == SND_RESOURCE) {
372 static WCHAR wszWave[] = {'W','A','V','E',0};
373 HRSRC hRes;
374 HGLOBAL hGlob;
376 if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 ||
377 (hGlob = LoadResource(wps->hMod, hRes)) == 0)
378 goto errCleanUp;
379 if ((data = LockResource(hGlob)) == NULL) {
380 FreeResource(hGlob);
381 goto errCleanUp;
383 FreeResource(hGlob);
384 } else
385 data = (void*)wps->pszSound;
387 /* construct an MMIO stream (either in memory, or from a file */
388 /* hmmio = 0; */ /* to catch errors */
389 if (wps->fdwSound & SND_MEMORY)
390 { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */
391 MMIOINFO mminfo;
393 memset(&mminfo, 0, sizeof(mminfo));
394 mminfo.fccIOProc = FOURCC_MEM;
395 mminfo.pchBuffer = (LPSTR)data;
396 mminfo.cchBuffer = -1; /* FIXME: when a resource, could grab real size */
397 TRACE("Memory sound %p\n", data);
398 hmmio = mmioOpenW(NULL, &mminfo, MMIO_READ);
400 else if (wps->fdwSound & SND_ALIAS)
402 hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
404 else if (wps->fdwSound & SND_FILENAME)
406 hmmio = get_mmioFromFile(wps->pszSound);
408 else
410 if ((hmmio = get_mmioFromProfile(wps->fdwSound | SND_NODEFAULT, wps->pszSound)) == 0)
412 if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0)
414 hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
418 if (hmmio == 0) goto errCleanUp;
420 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0))
421 goto errCleanUp;
423 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
424 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
426 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
427 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
428 goto errCleanUp;
430 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
431 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
432 goto errCleanUp;
434 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
435 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
437 lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
438 if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT))
439 goto errCleanUp;
441 TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag);
442 TRACE("nChannels=%d \n", lpWaveFormat->nChannels);
443 TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec);
444 TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec);
445 TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign);
446 TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample);
448 /* move to end of 'fmt ' chunk */
449 mmioAscend(hmmio, &mmckInfo, 0);
451 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
452 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
453 goto errCleanUp;
455 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
456 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
458 s.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
460 if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback,
461 (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
462 goto errCleanUp;
464 /* make it so that 3 buffers per second are needed */
465 bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) *
466 lpWaveFormat->nBlockAlign;
467 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
468 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
469 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
470 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
471 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
472 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
473 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
474 if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
475 waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) {
476 goto errCleanUp;
479 do {
480 index = 0;
481 left = mmckInfo.cksize;
482 s.dwEventCount = 1L; /* for first buffer */
484 mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
485 while (left) {
486 if (wps->bStop) {
487 wps->bStop = wps->bLoop = FALSE;
488 break;
490 count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
491 if (count < 1) break;
492 left -= count;
493 waveHdr[index].dwBufferLength = count;
494 waveHdr[index].dwFlags &= ~WHDR_DONE;
495 if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) {
496 index ^= 1;
497 PlaySound_WaitDone(&s);
499 else FIXME("Couldn't play header\n");
501 bRet = TRUE;
502 } while (wps->bLoop);
504 PlaySound_WaitDone(&s); /* for last buffer */
505 waveOutReset(hWave);
507 waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
508 waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
510 errCleanUp:
511 TRACE("Done playing='%s' => %s!\n", debugstr_w(wps->pszSound), bRet ? "ok" : "ko");
512 CloseHandle(s.hEvent);
513 if (waveHdr) HeapFree(GetProcessHeap(), 0, waveHdr);
514 if (lpWaveFormat) HeapFree(GetProcessHeap(), 0, lpWaveFormat);
515 if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
516 if (hmmio) mmioClose(hmmio, 0);
518 SetEvent(wps->hReadyEvent);
519 iData->lpPlaySound = NULL;
521 if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound);
522 CloseHandle(wps->hReadyEvent);
523 HeapFree(GetProcessHeap(), 0, wps);
525 return bRet;
528 static BOOL MULTIMEDIA_IsString(DWORD fdwSound, const void* psz)
530 /* SND_RESOURCE is 0x40004 while
531 * SND_MEMORY is 0x00004
533 switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME))
535 case SND_RESOURCE: return HIWORD(psz) != 0; /* by name or by ID ? */
536 case SND_MEMORY: return FALSE;
537 case SND_ALIAS: /* what about ALIAS_ID ??? */
538 case SND_FILENAME:
539 case 0: return TRUE;
540 default: FIXME("WTF\n"); return FALSE;
544 static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode)
546 WINE_PLAYSOUND* wps = NULL;
547 DWORD id;
548 LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
549 BOOL bRet = FALSE;
551 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
552 pszSound, hmod, fdwSound);
554 /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP !
555 * there could be one if several sounds can be played at once...
557 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound)
558 return FALSE;
560 do {
561 HANDLE hEvt = 0;
563 /* Trying to stop if playing */
564 EnterCriticalSection(&iData->cs);
565 if (iData->lpPlaySound) {
566 LPWINE_PLAYSOUND ps2stop = iData->lpPlaySound;
568 hEvt = ps2stop->hReadyEvent;
569 ps2stop->bStop = TRUE;
571 LeaveCriticalSection(&iData->cs);
572 /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave
573 * FIXME: race here (if hEvt is destroyed and reallocated - as a handle - to
574 * another object)... unlikely but possible
576 if (hEvt) WaitForSingleObject(hEvt, 1000*10);
578 if (!pszSound || (fdwSound & SND_PURGE))
579 return TRUE; /* We stopped playing so leaving */
581 if (wps == NULL)
583 wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps));
584 if (!wps) return FALSE;
586 wps->hMod = hmod;
587 wps->fdwSound = fdwSound;
588 wps->bAlloc = FALSE;
589 if (MULTIMEDIA_IsString(fdwSound, pszSound))
591 if (bUnicode)
593 if (fdwSound & SND_ASYNC)
595 wps->pszSound = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pszSound)+1) * sizeof(WCHAR));
596 lstrcpyW((LPWSTR)wps->pszSound, pszSound);
597 wps->bAlloc = TRUE;
599 else
600 wps->pszSound = pszSound;
602 else
604 wps->pszSound = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSound);
605 wps->bAlloc = TRUE;
608 else
609 wps->pszSound = pszSound;
610 if ((wps->hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
611 goto cleanup;
613 } while (InterlockedCompareExchangePointer((void**)&iData->lpPlaySound, wps, NULL) != NULL);
615 if (fdwSound & SND_ASYNC)
617 wps->bLoop = fdwSound & SND_LOOP;
618 /* FIXME: memory leak in case of error & cs is still locked */
619 return ((wps->hThread = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) != 0);
622 bRet = proc_PlaySound(wps);
623 cleanup:
624 return bRet;
627 /**************************************************************************
628 * PlaySoundA [WINMM.@]
630 BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound)
632 return MULTIMEDIA_PlaySound(pszSoundA, hmod, fdwSound, FALSE);
635 /**************************************************************************
636 * PlaySoundW [WINMM.@]
638 BOOL WINAPI PlaySoundW(LPCWSTR pszSoundW, HMODULE hmod, DWORD fdwSound)
640 return MULTIMEDIA_PlaySound(pszSoundW, hmod, fdwSound, TRUE);
643 /**************************************************************************
644 * PlaySound [MMSYSTEM.3]
646 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
648 BOOL16 retv;
649 DWORD lc;
651 ReleaseThunkLock(&lc);
652 retv = PlaySoundA(pszSound, hmod, fdwSound);
653 RestoreThunkLock(lc);
655 return retv;
658 /**************************************************************************
659 * sndPlaySoundA [WINMM.@]
661 BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags)
663 uFlags &= ~(SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC);
664 return MULTIMEDIA_PlaySound(pszSoundA, 0, uFlags, FALSE);
667 /**************************************************************************
668 * sndPlaySoundW [WINMM.@]
670 BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags)
672 uFlags &= ~(SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC);
673 return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, TRUE);
676 /**************************************************************************
677 * sndPlaySound [MMSYSTEM.2]
679 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
681 BOOL16 retv;
682 DWORD lc;
684 ReleaseThunkLock(&lc);
685 retv = sndPlaySoundA(lpszSoundName, uFlags);
686 RestoreThunkLock(lc);
688 return retv;
691 /**************************************************************************
692 * mmsystemGetVersion [MMSYSTEM.5]
693 * return value borrowed from Win95 winmm.dll ;)
695 UINT16 WINAPI mmsystemGetVersion16(void)
697 return mmsystemGetVersion();
700 /**************************************************************************
701 * mmsystemGetVersion [WINMM.@]
703 UINT WINAPI mmsystemGetVersion(void)
705 TRACE("3.10 (Win95?)\n");
706 return 0x030a;
709 /**************************************************************************
710 * DriverCallback [WINMM.@]
712 BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
713 UINT wMsg, DWORD dwUser, DWORD dwParam1,
714 DWORD dwParam2)
716 TRACE("(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
717 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
719 switch (uFlags & DCB_TYPEMASK) {
720 case DCB_NULL:
721 TRACE("Null !\n");
722 if (dwCallBack)
723 WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack);
724 break;
725 case DCB_WINDOW:
726 TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
727 PostMessageA((HWND)dwCallBack, wMsg, hDev, dwParam1);
728 break;
729 case DCB_TASK: /* aka DCB_THREAD */
730 TRACE("Task(%04lx) !\n", dwCallBack);
731 PostThreadMessageA(dwCallBack, wMsg, hDev, dwParam1);
732 break;
733 case DCB_FUNCTION:
734 TRACE("Function (32 bit) !\n");
735 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
736 break;
737 case DCB_EVENT:
738 TRACE("Event(%08lx) !\n", dwCallBack);
739 SetEvent((HANDLE)dwCallBack);
740 break;
741 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
742 /* this is an undocumented DCB_ value used for mmThreads
743 * loword of dwCallBack contains the handle of the lpMMThd block
744 * which dwSignalCount has to be incremented
747 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(LOWORD(dwCallBack), 0) );
749 TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
750 /* same as mmThreadSignal16 */
751 InterlockedIncrement(&lpMMThd->dwSignalCount);
752 SetEvent(lpMMThd->hEvent);
753 /* some other stuff on lpMMThd->hVxD */
755 break;
756 #if 0
757 case 4:
758 /* this is an undocumented DCB_ value for... I don't know */
759 break;
760 #endif
761 default:
762 WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
763 return FALSE;
765 TRACE("Done\n");
766 return TRUE;
769 /**************************************************************************
770 * DriverCallback [MMSYSTEM.31]
772 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev,
773 WORD wMsg, DWORD dwUser, DWORD dwParam1,
774 DWORD dwParam2)
776 return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
779 /**************************************************************************
780 * Mixer devices. New to Win95
783 /**************************************************************************
784 * find out the real mixer ID depending on hmix (depends on dwFlags)
786 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
788 LPWINE_MIXER lpwm = NULL;
790 switch (dwFlags & 0xF0000000ul) {
791 case MIXER_OBJECTF_MIXER:
792 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
793 break;
794 case MIXER_OBJECTF_HMIXER:
795 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
796 break;
797 case MIXER_OBJECTF_WAVEOUT:
798 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
799 break;
800 case MIXER_OBJECTF_HWAVEOUT:
801 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
802 break;
803 case MIXER_OBJECTF_WAVEIN:
804 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
805 break;
806 case MIXER_OBJECTF_HWAVEIN:
807 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
808 break;
809 case MIXER_OBJECTF_MIDIOUT:
810 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
811 break;
812 case MIXER_OBJECTF_HMIDIOUT:
813 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
814 break;
815 case MIXER_OBJECTF_MIDIIN:
816 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
817 break;
818 case MIXER_OBJECTF_HMIDIIN:
819 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
820 break;
821 case MIXER_OBJECTF_AUX:
822 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
823 break;
824 default:
825 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
826 break;
828 return lpwm;
831 /**************************************************************************
832 * mixerGetNumDevs [WINMM.@]
834 UINT WINAPI mixerGetNumDevs(void)
836 return MMDRV_GetNum(MMDRV_MIXER);
839 /**************************************************************************
840 * mixerGetNumDevs [MMSYSTEM.800]
842 UINT16 WINAPI mixerGetNumDevs16(void)
844 return MMDRV_GetNum(MMDRV_MIXER);
847 /**************************************************************************
848 * mixerGetDevCapsA [WINMM.@]
850 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
852 LPWINE_MLD wmld;
854 if ((wmld = MMDRV_Get(devid, MMDRV_MIXER, TRUE)) == NULL)
855 return MMSYSERR_BADDEVICEID;
857 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
860 /**************************************************************************
861 * mixerGetDevCapsW [WINMM.@]
863 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
865 MIXERCAPSA micA;
866 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
868 if (ret == MMSYSERR_NOERROR) {
869 mixcaps->wMid = micA.wMid;
870 mixcaps->wPid = micA.wPid;
871 mixcaps->vDriverVersion = micA.vDriverVersion;
872 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
873 sizeof(mixcaps->szPname)/sizeof(WCHAR) );
874 mixcaps->fdwSupport = micA.fdwSupport;
875 mixcaps->cDestinations = micA.cDestinations;
877 return ret;
880 /**************************************************************************
881 * mixerGetDevCaps [MMSYSTEM.801]
883 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps,
884 UINT16 size)
886 MIXERCAPSA micA;
887 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
889 if (ret == MMSYSERR_NOERROR) {
890 mixcaps->wMid = micA.wMid;
891 mixcaps->wPid = micA.wPid;
892 mixcaps->vDriverVersion = micA.vDriverVersion;
893 strcpy(mixcaps->szPname, micA.szPname);
894 mixcaps->fdwSupport = micA.fdwSupport;
895 mixcaps->cDestinations = micA.cDestinations;
897 return ret;
900 static UINT MMSYSTEM_mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
901 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
903 HMIXER hMix;
904 LPWINE_MLD wmld;
905 DWORD dwRet = 0;
906 MIXEROPENDESC mod;
908 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
909 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
911 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
912 &dwCallback, &dwInstance, bFrom32);
914 wmld->uDeviceID = uDeviceID;
915 mod.hmx = hMix;
916 mod.dwCallback = dwCallback;
917 mod.dwInstance = dwInstance;
919 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
921 if (dwRet != MMSYSERR_NOERROR) {
922 MMDRV_Free(hMix, wmld);
923 hMix = 0;
925 if (lphMix) *lphMix = hMix;
926 TRACE("=> %ld hMixer=%04x\n", dwRet, hMix);
928 return dwRet;
931 /**************************************************************************
932 * mixerOpen [WINMM.@]
934 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
935 DWORD dwInstance, DWORD fdwOpen)
937 return MMSYSTEM_mixerOpen(lphMix, uDeviceID,
938 dwCallback, dwInstance, fdwOpen, TRUE);
941 /**************************************************************************
942 * mixerOpen [MMSYSTEM.802]
944 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
945 DWORD dwInstance, DWORD fdwOpen)
947 HMIXER hmix;
948 UINT ret;
950 ret = MMSYSTEM_mixerOpen(&hmix, uDeviceID,
951 dwCallback, dwInstance, fdwOpen, FALSE);
952 if (lphmix) *lphmix = hmix;
953 return ret;
956 /**************************************************************************
957 * mixerClose [WINMM.@]
959 UINT WINAPI mixerClose(HMIXER hMix)
961 LPWINE_MLD wmld;
962 DWORD dwRet;
964 TRACE("(%04x)\n", hMix);
966 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
968 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
969 MMDRV_Free(hMix, wmld);
971 return dwRet;
974 /**************************************************************************
975 * mixerClose [MMSYSTEM.803]
977 UINT16 WINAPI mixerClose16(HMIXER16 hMix)
979 return mixerClose(hMix);
982 /**************************************************************************
983 * mixerGetID [WINMM.@]
985 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
987 LPWINE_MIXER lpwm;
989 TRACE("(%04x %p %08lx)\n", hmix, lpid, fdwID);
991 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
992 return MMSYSERR_INVALHANDLE;
995 if (lpid)
996 *lpid = lpwm->mld.uDeviceID;
998 return MMSYSERR_NOERROR;
1001 /**************************************************************************
1002 * mixerGetID (MMSYSTEM.806)
1004 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
1006 UINT xid;
1007 UINT ret = mixerGetID(hmix, &xid, fdwID);
1009 if (lpid)
1010 *lpid = xid;
1011 return ret;
1014 /**************************************************************************
1015 * mixerGetControlDetailsA [WINMM.@]
1017 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1018 DWORD fdwDetails)
1020 LPWINE_MIXER lpwm;
1022 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1024 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1025 return MMSYSERR_INVALHANDLE;
1027 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
1028 return MMSYSERR_INVALPARAM;
1030 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
1031 fdwDetails, TRUE);
1034 /**************************************************************************
1035 * mixerGetControlDetailsW [WINMM.@]
1037 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
1039 DWORD ret = MMSYSERR_NOTENABLED;
1041 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1043 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1044 return MMSYSERR_INVALPARAM;
1046 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
1047 case MIXER_GETCONTROLDETAILSF_VALUE:
1048 /* can savely use W structure as it is, no string inside */
1049 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
1050 break;
1051 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
1053 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
1054 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
1055 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1056 int i;
1058 if (lpmcd->u.cMultipleItems != 0) {
1059 size *= lpmcd->u.cMultipleItems;
1061 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
1062 lpmcd->paDetails = pDetailsA;
1063 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1064 /* set up lpmcd->paDetails */
1065 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
1066 /* copy from lpmcd->paDetails back to paDetailsW; */
1067 if(ret == MMSYSERR_NOERROR) {
1068 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
1069 pDetailsW->dwParam1 = pDetailsA->dwParam1;
1070 pDetailsW->dwParam2 = pDetailsA->dwParam2;
1071 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
1072 pDetailsW->szName,
1073 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
1074 pDetailsA++;
1075 pDetailsW++;
1077 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
1078 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
1080 HeapFree(GetProcessHeap(), 0, pDetailsA);
1081 lpmcd->paDetails = pDetailsW;
1082 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
1084 break;
1085 default:
1086 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
1089 return ret;
1092 /**************************************************************************
1093 * mixerGetControlDetails [MMSYSTEM.808]
1095 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix,
1096 LPMIXERCONTROLDETAILS16 lpmcd,
1097 DWORD fdwDetails)
1099 DWORD ret = MMSYSERR_NOTENABLED;
1100 SEGPTR sppaDetails;
1102 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1104 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
1105 return MMSYSERR_INVALPARAM;
1107 sppaDetails = (SEGPTR)lpmcd->paDetails;
1108 lpmcd->paDetails = MapSL(sppaDetails);
1109 ret = mixerGetControlDetailsA(hmix, (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails);
1110 lpmcd->paDetails = (LPVOID)sppaDetails;
1112 return ret;
1115 /**************************************************************************
1116 * mixerGetLineControlsA [WINMM.@]
1118 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
1119 DWORD fdwControls)
1121 LPWINE_MIXER lpwm;
1123 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
1125 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
1126 return MMSYSERR_INVALHANDLE;
1128 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
1129 return MMSYSERR_INVALPARAM;
1131 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
1132 fdwControls, TRUE);
1135 /**************************************************************************
1136 * mixerGetLineControlsW [WINMM.@]
1138 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
1139 DWORD fdwControls)
1141 MIXERLINECONTROLSA mlcA;
1142 DWORD ret;
1143 int i;
1145 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
1147 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
1148 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
1149 return MMSYSERR_INVALPARAM;
1151 mlcA.cbStruct = sizeof(mlcA);
1152 mlcA.dwLineID = lpmlcW->dwLineID;
1153 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
1154 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
1155 mlcA.cControls = lpmlcW->cControls;
1156 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1157 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1158 mlcA.cControls * mlcA.cbmxctrl);
1160 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
1162 if (ret == MMSYSERR_NOERROR) {
1163 lpmlcW->dwLineID = mlcA.dwLineID;
1164 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
1165 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
1166 lpmlcW->cControls = mlcA.cControls;
1168 for (i = 0; i < mlcA.cControls; i++) {
1169 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
1170 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1171 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1172 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1173 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1174 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
1175 lpmlcW->pamxctrl[i].szShortName,
1176 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
1177 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
1178 lpmlcW->pamxctrl[i].szName,
1179 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
1180 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
1181 * sizeof(mlcA.pamxctrl[i].Bounds) */
1182 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1183 sizeof(mlcA.pamxctrl[i].Bounds));
1184 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
1185 * sizeof(mlcA.pamxctrl[i].Metrics) */
1186 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1187 sizeof(mlcA.pamxctrl[i].Metrics));
1191 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1193 return ret;
1196 /**************************************************************************
1197 * mixerGetLineControls [MMSYSTEM.807]
1199 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix,
1200 LPMIXERLINECONTROLS16 lpmlc16,
1201 DWORD fdwControls)
1203 MIXERLINECONTROLSA mlcA;
1204 DWORD ret;
1205 int i;
1206 LPMIXERCONTROL16 lpmc16;
1208 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls);
1210 if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) ||
1211 lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16))
1212 return MMSYSERR_INVALPARAM;
1214 mlcA.cbStruct = sizeof(mlcA);
1215 mlcA.dwLineID = lpmlc16->dwLineID;
1216 mlcA.u.dwControlID = lpmlc16->u.dwControlID;
1217 mlcA.u.dwControlType = lpmlc16->u.dwControlType;
1218 mlcA.cControls = lpmlc16->cControls;
1219 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
1220 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1221 mlcA.cControls * mlcA.cbmxctrl);
1223 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
1225 if (ret == MMSYSERR_NOERROR) {
1226 lpmlc16->dwLineID = mlcA.dwLineID;
1227 lpmlc16->u.dwControlID = mlcA.u.dwControlID;
1228 lpmlc16->u.dwControlType = mlcA.u.dwControlType;
1229 lpmlc16->cControls = mlcA.cControls;
1231 lpmc16 = MapSL(lpmlc16->pamxctrl);
1233 for (i = 0; i < mlcA.cControls; i++) {
1234 lpmc16[i].cbStruct = sizeof(MIXERCONTROL16);
1235 lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
1236 lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
1237 lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
1238 lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
1239 strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName);
1240 strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName);
1241 /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
1242 memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds,
1243 sizeof(mlcA.pamxctrl[i].Bounds));
1244 /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
1245 memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics,
1246 sizeof(mlcA.pamxctrl[i].Metrics));
1250 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
1252 return ret;
1255 /**************************************************************************
1256 * mixerGetLineInfoA [WINMM.@]
1258 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
1260 LPWINE_MIXER lpwm;
1262 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1264 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
1265 return MMSYSERR_INVALHANDLE;
1267 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
1268 fdwInfo, TRUE);
1271 /**************************************************************************
1272 * mixerGetLineInfoW [WINMM.@]
1274 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
1275 DWORD fdwInfo)
1277 MIXERLINEA mliA;
1278 UINT ret;
1280 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1282 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
1283 return MMSYSERR_INVALPARAM;
1285 mliA.cbStruct = sizeof(mliA);
1286 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1287 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1288 mliA.dwComponentType = lpmliW->dwComponentType;
1289 break;
1290 case MIXER_GETLINEINFOF_DESTINATION:
1291 mliA.dwDestination = lpmliW->dwDestination;
1292 break;
1293 case MIXER_GETLINEINFOF_LINEID:
1294 mliA.dwLineID = lpmliW->dwLineID;
1295 break;
1296 case MIXER_GETLINEINFOF_SOURCE:
1297 mliA.dwDestination = lpmliW->dwDestination;
1298 mliA.dwSource = lpmliW->dwSource;
1299 break;
1300 case MIXER_GETLINEINFOF_TARGETTYPE:
1301 mliA.Target.dwType = lpmliW->Target.dwType;
1302 mliA.Target.wMid = lpmliW->Target.wMid;
1303 mliA.Target.wPid = lpmliW->Target.wPid;
1304 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
1305 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
1306 break;
1307 default:
1308 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1311 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1313 lpmliW->dwDestination = mliA.dwDestination;
1314 lpmliW->dwSource = mliA.dwSource;
1315 lpmliW->dwLineID = mliA.dwLineID;
1316 lpmliW->fdwLine = mliA.fdwLine;
1317 lpmliW->dwUser = mliA.dwUser;
1318 lpmliW->dwComponentType = mliA.dwComponentType;
1319 lpmliW->cChannels = mliA.cChannels;
1320 lpmliW->cConnections = mliA.cConnections;
1321 lpmliW->cControls = mliA.cControls;
1322 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
1323 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
1324 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
1325 sizeof(lpmliW->szName)/sizeof(WCHAR) );
1326 lpmliW->Target.dwType = mliA.Target.dwType;
1327 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
1328 lpmliW->Target.wMid = mliA.Target.wMid;
1329 lpmliW->Target.wPid = mliA.Target.wPid;
1330 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
1331 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
1332 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
1334 return ret;
1337 /**************************************************************************
1338 * mixerGetLineInfo [MMSYSTEM.805]
1340 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16,
1341 DWORD fdwInfo)
1343 MIXERLINEA mliA;
1344 UINT ret;
1346 TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo);
1348 if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16))
1349 return MMSYSERR_INVALPARAM;
1351 mliA.cbStruct = sizeof(mliA);
1352 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1353 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1354 mliA.dwComponentType = lpmli16->dwComponentType;
1355 break;
1356 case MIXER_GETLINEINFOF_DESTINATION:
1357 mliA.dwDestination = lpmli16->dwDestination;
1358 break;
1359 case MIXER_GETLINEINFOF_LINEID:
1360 mliA.dwLineID = lpmli16->dwLineID;
1361 break;
1362 case MIXER_GETLINEINFOF_SOURCE:
1363 mliA.dwDestination = lpmli16->dwDestination;
1364 mliA.dwSource = lpmli16->dwSource;
1365 break;
1366 case MIXER_GETLINEINFOF_TARGETTYPE:
1367 mliA.Target.dwType = lpmli16->Target.dwType;
1368 mliA.Target.wMid = lpmli16->Target.wMid;
1369 mliA.Target.wPid = lpmli16->Target.wPid;
1370 mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion;
1371 strcpy(mliA.Target.szPname, lpmli16->Target.szPname);
1372 break;
1373 default:
1374 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1377 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1379 lpmli16->dwDestination = mliA.dwDestination;
1380 lpmli16->dwSource = mliA.dwSource;
1381 lpmli16->dwLineID = mliA.dwLineID;
1382 lpmli16->fdwLine = mliA.fdwLine;
1383 lpmli16->dwUser = mliA.dwUser;
1384 lpmli16->dwComponentType = mliA.dwComponentType;
1385 lpmli16->cChannels = mliA.cChannels;
1386 lpmli16->cConnections = mliA.cConnections;
1387 lpmli16->cControls = mliA.cControls;
1388 strcpy(lpmli16->szShortName, mliA.szShortName);
1389 strcpy(lpmli16->szName, mliA.szName);
1390 lpmli16->Target.dwType = mliA.Target.dwType;
1391 lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID;
1392 lpmli16->Target.wMid = mliA.Target.wMid;
1393 lpmli16->Target.wPid = mliA.Target.wPid;
1394 lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion;
1395 strcpy(lpmli16->Target.szPname, mliA.Target.szPname);
1397 return ret;
1400 /**************************************************************************
1401 * mixerSetControlDetails [WINMM.@]
1403 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1404 DWORD fdwDetails)
1406 LPWINE_MIXER lpwm;
1408 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1410 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
1411 return MMSYSERR_INVALHANDLE;
1413 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
1414 fdwDetails, TRUE);
1417 /**************************************************************************
1418 * mixerSetControlDetails [MMSYSTEM.809]
1420 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix,
1421 LPMIXERCONTROLDETAILS16 lpmcd,
1422 DWORD fdwDetails)
1424 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1425 return MMSYSERR_NOTENABLED;
1428 /**************************************************************************
1429 * mixerMessage [WINMM.@]
1431 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
1433 LPWINE_MLD wmld;
1435 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
1436 (DWORD)hmix, uMsg, dwParam1, dwParam2);
1438 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
1439 return MMSYSERR_INVALHANDLE;
1441 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
1444 /**************************************************************************
1445 * mixerMessage [MMSYSTEM.804]
1447 DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1,
1448 DWORD dwParam2)
1450 return mixerMessage(hmix, uMsg, dwParam1, dwParam2);
1453 /**************************************************************************
1454 * auxGetNumDevs [WINMM.@]
1456 UINT WINAPI auxGetNumDevs(void)
1458 return MMDRV_GetNum(MMDRV_AUX);
1461 /**************************************************************************
1462 * auxGetNumDevs [MMSYSTEM.350]
1464 UINT16 WINAPI auxGetNumDevs16(void)
1466 return MMDRV_GetNum(MMDRV_AUX);
1469 /**************************************************************************
1470 * auxGetDevCapsW [WINMM.@]
1472 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
1474 AUXCAPSA acA;
1475 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
1477 lpCaps->wMid = acA.wMid;
1478 lpCaps->wPid = acA.wPid;
1479 lpCaps->vDriverVersion = acA.vDriverVersion;
1480 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
1481 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1482 lpCaps->wTechnology = acA.wTechnology;
1483 lpCaps->dwSupport = acA.dwSupport;
1484 return ret;
1487 /**************************************************************************
1488 * auxGetDevCapsA [WINMM.@]
1490 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
1492 LPWINE_MLD wmld;
1494 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1496 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1497 return MMSYSERR_INVALHANDLE;
1498 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1501 /**************************************************************************
1502 * auxGetDevCaps [MMSYSTEM.351]
1504 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
1506 LPWINE_MLD wmld;
1508 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1510 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1511 return MMSYSERR_INVALHANDLE;
1512 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1515 /**************************************************************************
1516 * auxGetVolume [WINMM.@]
1518 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1520 LPWINE_MLD wmld;
1522 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1524 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1525 return MMSYSERR_INVALHANDLE;
1526 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1529 /**************************************************************************
1530 * auxGetVolume [MMSYSTEM.352]
1532 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume)
1534 LPWINE_MLD wmld;
1536 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1538 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1539 return MMSYSERR_INVALHANDLE;
1540 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1543 /**************************************************************************
1544 * auxSetVolume [WINMM.@]
1546 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
1548 LPWINE_MLD wmld;
1550 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1552 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1553 return MMSYSERR_INVALHANDLE;
1554 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1557 /**************************************************************************
1558 * auxSetVolume [MMSYSTEM.353]
1560 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
1562 LPWINE_MLD wmld;
1564 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
1566 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1567 return MMSYSERR_INVALHANDLE;
1568 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
1571 /**************************************************************************
1572 * auxOutMessage [WINMM.@]
1574 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1576 LPWINE_MLD wmld;
1578 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1579 return MMSYSERR_INVALHANDLE;
1581 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1584 /**************************************************************************
1585 * auxOutMessage [MMSYSTEM.354]
1587 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1589 LPWINE_MLD wmld;
1591 TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1593 switch (uMessage) {
1594 case AUXDM_GETNUMDEVS:
1595 case AUXDM_SETVOLUME:
1596 /* no argument conversion needed */
1597 break;
1598 case AUXDM_GETVOLUME:
1599 return auxGetVolume16(uDeviceID, MapSL(dw1));
1600 case AUXDM_GETDEVCAPS:
1601 return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2);
1602 default:
1603 TRACE("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1604 uDeviceID, uMessage, dw1, dw2);
1605 break;
1607 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_AUX, TRUE)) == NULL)
1608 return MMSYSERR_INVALHANDLE;
1610 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
1613 /**************************************************************************
1614 * mciGetErrorStringW [WINMM.@]
1616 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1618 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1619 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
1621 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
1622 HeapFree(GetProcessHeap(), 0, bufstr);
1623 return ret;
1626 /**************************************************************************
1627 * mciGetErrorString [MMSYSTEM.706]
1629 BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength)
1631 return mciGetErrorStringA(wError, lpstrBuffer, uLength);
1634 /**************************************************************************
1635 * mciGetErrorStringA [WINMM.@]
1637 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
1639 BOOL16 ret = FALSE;
1641 if (lpstrBuffer != NULL && uLength > 0 &&
1642 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
1644 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
1645 dwError, lpstrBuffer, uLength) > 0) {
1646 ret = TRUE;
1649 return ret;
1652 /**************************************************************************
1653 * mciDriverNotify [MMSYSTEM.711]
1655 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1657 TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1659 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1662 /**************************************************************************
1663 * mciDriverNotify [WINMM.@]
1665 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1668 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1670 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1673 /**************************************************************************
1674 * mciGetDriverData [MMSYSTEM.708]
1676 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1678 return mciGetDriverData(uDeviceID);
1681 /**************************************************************************
1682 * mciGetDriverData [WINMM.@]
1684 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1686 LPWINE_MCIDRIVER wmd;
1688 TRACE("(%04x)\n", uDeviceID);
1690 wmd = MCI_GetDriver(uDeviceID);
1692 if (!wmd) {
1693 WARN("Bad uDeviceID\n");
1694 return 0L;
1697 return wmd->dwPrivate;
1700 /**************************************************************************
1701 * mciSetDriverData [MMSYSTEM.707]
1703 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1705 return mciSetDriverData(uDeviceID, data);
1708 /**************************************************************************
1709 * mciSetDriverData [WINMM.@]
1711 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1713 LPWINE_MCIDRIVER wmd;
1715 TRACE("(%04x, %08lx)\n", uDeviceID, data);
1717 wmd = MCI_GetDriver(uDeviceID);
1719 if (!wmd) {
1720 WARN("Bad uDeviceID\n");
1721 return FALSE;
1724 wmd->dwPrivate = data;
1725 return TRUE;
1728 /**************************************************************************
1729 * mciSendCommandA [WINMM.@]
1731 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1733 DWORD dwRet;
1735 TRACE("(%08x, %s, %08lx, %08lx)\n",
1736 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1738 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
1739 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1740 TRACE("=> %08lx\n", dwRet);
1741 return dwRet;
1744 /**************************************************************************
1745 * mciSendCommandW [WINMM.@]
1747 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1749 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
1750 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1751 return MCIERR_UNSUPPORTED_FUNCTION;
1754 /**************************************************************************
1755 * mciSendCommand [MMSYSTEM.701]
1757 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1759 DWORD dwRet;
1761 TRACE("(%04X, %s, %08lX, %08lX)\n",
1762 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1764 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE);
1765 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1766 TRACE("=> %ld\n", dwRet);
1767 return dwRet;
1770 /**************************************************************************
1771 * mciGetDeviceID [MMSYSTEM.703]
1773 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1775 TRACE("(\"%s\")\n", lpstrName);
1777 return MCI_GetDriverFromString(lpstrName);
1780 /**************************************************************************
1781 * mciGetDeviceIDA [WINMM.@]
1783 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1785 return MCI_GetDriverFromString(lpstrName);
1788 /**************************************************************************
1789 * mciGetDeviceIDW [WINMM.@]
1791 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1793 LPSTR lpstrName;
1794 UINT ret;
1796 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1797 ret = MCI_GetDriverFromString(lpstrName);
1798 HeapFree(GetProcessHeap(), 0, lpstrName);
1799 return ret;
1802 /**************************************************************************
1803 * MCI_DefYieldProc [internal]
1805 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1807 INT16 ret;
1809 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1811 if ((HIWORD(data) != 0 && GetActiveWindow() != HIWORD(data)) ||
1812 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1813 UserYield16();
1814 ret = 0;
1815 } else {
1816 MSG msg;
1818 msg.hwnd = HIWORD(data);
1819 while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1820 ret = -1;
1822 return ret;
1825 /**************************************************************************
1826 * mciSetYieldProc [MMSYSTEM.714]
1828 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData)
1830 LPWINE_MCIDRIVER wmd;
1832 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1834 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1835 WARN("Bad uDeviceID\n");
1836 return FALSE;
1839 wmd->lpfnYieldProc = (YIELDPROC)fpYieldProc;
1840 wmd->dwYieldData = dwYieldData;
1841 wmd->bIs32 = FALSE;
1843 return TRUE;
1846 /**************************************************************************
1847 * mciSetYieldProc [WINMM.@]
1849 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1851 LPWINE_MCIDRIVER wmd;
1853 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1855 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1856 WARN("Bad uDeviceID\n");
1857 return FALSE;
1860 wmd->lpfnYieldProc = fpYieldProc;
1861 wmd->dwYieldData = dwYieldData;
1862 wmd->bIs32 = TRUE;
1864 return TRUE;
1867 /**************************************************************************
1868 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
1870 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
1872 FIXME("(%lu, %s) stub\n", dwElementID, lpstrType);
1873 return 0;
1876 /**************************************************************************
1877 * mciGetDeviceIDFromElementIDW [WINMM.@]
1879 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1881 /* FIXME: that's rather strange, there is no
1882 * mciGetDeviceIDFromElementID32A in winmm.spec
1884 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1885 return 0;
1888 /**************************************************************************
1889 * mciGetYieldProc [MMSYSTEM.716]
1891 YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
1893 LPWINE_MCIDRIVER wmd;
1895 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1897 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1898 WARN("Bad uDeviceID\n");
1899 return NULL;
1901 if (!wmd->lpfnYieldProc) {
1902 WARN("No proc set\n");
1903 return NULL;
1905 if (wmd->bIs32) {
1906 WARN("Proc is 32 bit\n");
1907 return NULL;
1909 return (YIELDPROC16)wmd->lpfnYieldProc;
1912 /**************************************************************************
1913 * mciGetYieldProc [WINMM.@]
1915 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
1917 LPWINE_MCIDRIVER wmd;
1919 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1921 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1922 WARN("Bad uDeviceID\n");
1923 return NULL;
1925 if (!wmd->lpfnYieldProc) {
1926 WARN("No proc set\n");
1927 return NULL;
1929 if (!wmd->bIs32) {
1930 WARN("Proc is 32 bit\n");
1931 return NULL;
1933 return wmd->lpfnYieldProc;
1936 /**************************************************************************
1937 * mciGetCreatorTask [MMSYSTEM.717]
1939 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
1941 return mciGetCreatorTask(uDeviceID);
1944 /**************************************************************************
1945 * mciGetCreatorTask [WINMM.@]
1947 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
1949 LPWINE_MCIDRIVER wmd;
1950 HTASK ret;
1952 TRACE("(%u)\n", uDeviceID);
1954 ret = (!(wmd = MCI_GetDriver(uDeviceID))) ? 0 : wmd->hCreatorTask;
1956 TRACE("=> %04x\n", ret);
1957 return ret;
1960 /**************************************************************************
1961 * mciDriverYield [MMSYSTEM.710]
1963 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
1965 LPWINE_MCIDRIVER wmd;
1966 UINT16 ret = 0;
1968 /* TRACE("(%04x)\n", uDeviceID); */
1970 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) {
1971 UserYield16();
1972 } else {
1973 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1976 return ret;
1979 /**************************************************************************
1980 * mciDriverYield [WINMM.@]
1982 UINT WINAPI mciDriverYield(UINT uDeviceID)
1984 LPWINE_MCIDRIVER wmd;
1985 UINT ret = 0;
1987 TRACE("(%04x)\n", uDeviceID);
1989 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
1990 UserYield16();
1991 } else {
1992 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1995 return ret;
1998 /**************************************************************************
1999 * midiOutGetNumDevs [WINMM.@]
2001 UINT WINAPI midiOutGetNumDevs(void)
2003 return MMDRV_GetNum(MMDRV_MIDIOUT);
2006 /**************************************************************************
2007 * midiOutGetNumDevs [MMSYSTEM.201]
2009 UINT16 WINAPI midiOutGetNumDevs16(void)
2011 return MMDRV_GetNum(MMDRV_MIDIOUT);
2014 /**************************************************************************
2015 * midiOutGetDevCapsW [WINMM.@]
2017 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
2018 UINT uSize)
2020 MIDIOUTCAPSA mocA;
2021 UINT ret;
2023 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
2024 lpCaps->wMid = mocA.wMid;
2025 lpCaps->wPid = mocA.wPid;
2026 lpCaps->vDriverVersion = mocA.vDriverVersion;
2027 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
2028 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2029 lpCaps->wTechnology = mocA.wTechnology;
2030 lpCaps->wVoices = mocA.wVoices;
2031 lpCaps->wNotes = mocA.wNotes;
2032 lpCaps->wChannelMask = mocA.wChannelMask;
2033 lpCaps->dwSupport = mocA.dwSupport;
2034 return ret;
2037 /**************************************************************************
2038 * midiOutGetDevCapsA [WINMM.@]
2040 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
2041 UINT uSize)
2043 LPWINE_MLD wmld;
2045 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
2047 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2049 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2050 return MMSYSERR_INVALHANDLE;
2052 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2055 /**************************************************************************
2056 * midiOutGetDevCaps [MMSYSTEM.202]
2058 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps,
2059 UINT16 uSize)
2061 MIDIOUTCAPSA capsA;
2062 UINT dwRet;
2064 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2066 dwRet = midiOutGetDevCapsA(uDeviceID, &capsA, sizeof(capsA));
2067 if (dwRet == MMSYSERR_NOERROR) {
2068 lpCaps->wMid = capsA.wMid;
2069 lpCaps->wPid = capsA.wPid;
2070 lpCaps->vDriverVersion = capsA.vDriverVersion;
2071 strcpy(lpCaps->szPname, capsA.szPname);
2072 lpCaps->wTechnology = capsA.wTechnology;
2073 lpCaps->wVoices = capsA.wVoices;
2074 lpCaps->wNotes = capsA.wNotes;
2075 lpCaps->wChannelMask = capsA.wChannelMask;
2076 lpCaps->dwSupport = capsA.dwSupport;
2078 return dwRet;
2081 /**************************************************************************
2082 * MIDI_GetErrorText [internal]
2084 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2086 UINT16 ret = MMSYSERR_BADERRNUM;
2088 if (lpText == NULL) {
2089 ret = MMSYSERR_INVALPARAM;
2090 } else if (uSize == 0) {
2091 ret = MMSYSERR_NOERROR;
2092 } else if (
2093 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2094 * a warning for the test was always true */
2095 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
2096 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
2098 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
2099 uError, lpText, uSize) > 0) {
2100 ret = MMSYSERR_NOERROR;
2103 return ret;
2106 /**************************************************************************
2107 * midiOutGetErrorTextA [WINMM.@]
2109 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2111 return MIDI_GetErrorText(uError, lpText, uSize);
2114 /**************************************************************************
2115 * midiOutGetErrorTextW [WINMM.@]
2117 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2119 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2120 UINT ret;
2122 ret = MIDI_GetErrorText(uError, xstr, uSize);
2123 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2124 HeapFree(GetProcessHeap(), 0, xstr);
2125 return ret;
2128 /**************************************************************************
2129 * midiOutGetErrorText [MMSYSTEM.203]
2131 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2133 return MIDI_GetErrorText(uError, lpText, uSize);
2136 /**************************************************************************
2137 * MIDI_OutAlloc [internal]
2139 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
2140 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
2141 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
2143 HMIDIOUT hMidiOut;
2144 LPWINE_MIDI lpwm;
2145 UINT size;
2147 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
2149 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
2150 lpdwCallback, lpdwInstance, bFrom32);
2152 if (lphMidiOut != NULL)
2153 *lphMidiOut = hMidiOut;
2155 if (lpwm) {
2156 lpwm->mod.hMidi = hMidiOut;
2157 lpwm->mod.dwCallback = *lpdwCallback;
2158 lpwm->mod.dwInstance = *lpdwInstance;
2159 lpwm->mod.dnDevNode = 0;
2160 lpwm->mod.cIds = cIDs;
2161 if (cIDs)
2162 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2164 return lpwm;
2167 UINT MMSYSTEM_midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
2168 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2170 HMIDIOUT hMidiOut;
2171 LPWINE_MIDI lpwm;
2172 UINT dwRet = 0;
2174 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2175 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2177 if (lphMidiOut != NULL) *lphMidiOut = 0;
2179 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
2180 0, NULL, bFrom32);
2182 if (lpwm == NULL)
2183 return MMSYSERR_NOMEM;
2185 lpwm->mld.uDeviceID = uDeviceID;
2187 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod,
2188 dwFlags);
2190 if (dwRet != MMSYSERR_NOERROR) {
2191 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
2192 hMidiOut = 0;
2195 if (lphMidiOut) *lphMidiOut = hMidiOut;
2196 TRACE("=> %d hMidi=%04x\n", dwRet, hMidiOut);
2198 return dwRet;
2201 /**************************************************************************
2202 * midiOutOpen [WINMM.@]
2204 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2205 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2207 return MMSYSTEM_midiOutOpen(lphMidiOut, uDeviceID, dwCallback,
2208 dwInstance, dwFlags, TRUE);
2211 /**************************************************************************
2212 * midiOutOpen [MMSYSTEM.204]
2214 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2215 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2217 HMIDIOUT hmo;
2218 UINT ret;
2220 ret = MMSYSTEM_midiOutOpen(&hmo, uDeviceID, dwCallback, dwInstance,
2221 dwFlags, FALSE);
2223 if (lphMidiOut != NULL) *lphMidiOut = hmo;
2224 return ret;
2227 /**************************************************************************
2228 * midiOutClose [WINMM.@]
2230 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2232 LPWINE_MLD wmld;
2233 DWORD dwRet;
2235 TRACE("(%04X)\n", hMidiOut);
2237 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2238 return MMSYSERR_INVALHANDLE;
2240 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
2241 MMDRV_Free(hMidiOut, wmld);
2243 return dwRet;
2246 /**************************************************************************
2247 * midiOutClose [MMSYSTEM.205]
2249 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2251 return midiOutClose(hMidiOut);
2254 /**************************************************************************
2255 * midiOutPrepareHeader [WINMM.@]
2257 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2258 MIDIHDR* lpMidiOutHdr, UINT uSize)
2260 LPWINE_MLD wmld;
2262 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2264 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2265 return MMSYSERR_INVALHANDLE;
2267 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2270 /**************************************************************************
2271 * midiOutPrepareHeader [MMSYSTEM.206]
2273 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2274 SEGPTR lpsegMidiOutHdr, /* [???] */
2275 UINT16 uSize) /* [in] */
2277 LPWINE_MLD wmld;
2279 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2281 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2282 return MMSYSERR_INVALHANDLE;
2284 return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE);
2287 /**************************************************************************
2288 * midiOutUnprepareHeader [WINMM.@]
2290 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2291 MIDIHDR* lpMidiOutHdr, UINT uSize)
2293 LPWINE_MLD wmld;
2295 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2297 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2298 return MMSYSERR_NOERROR;
2301 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2302 return MMSYSERR_INVALHANDLE;
2304 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
2307 /**************************************************************************
2308 * midiOutUnprepareHeader [MMSYSTEM.207]
2310 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */
2311 SEGPTR lpsegMidiOutHdr, /* [???] */
2312 UINT16 uSize) /* [in] */
2314 LPWINE_MLD wmld;
2315 LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr);
2317 TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2319 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
2320 return MMSYSERR_NOERROR;
2323 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2324 return MMSYSERR_INVALHANDLE;
2326 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2329 /**************************************************************************
2330 * midiOutShortMsg [WINMM.@]
2332 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2334 LPWINE_MLD wmld;
2336 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
2338 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2339 return MMSYSERR_INVALHANDLE;
2341 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, FALSE);
2344 /**************************************************************************
2345 * midiOutShortMsg [MMSYSTEM.208]
2347 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2349 return midiOutShortMsg(hMidiOut, dwMsg);
2352 /**************************************************************************
2353 * midiOutLongMsg [WINMM.@]
2355 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2356 MIDIHDR* lpMidiOutHdr, UINT uSize)
2358 LPWINE_MLD wmld;
2360 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2362 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2363 return MMSYSERR_INVALHANDLE;
2365 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
2368 /**************************************************************************
2369 * midiOutLongMsg [MMSYSTEM.209]
2371 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */
2372 LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */
2373 UINT16 uSize) /* [in] */
2375 LPWINE_MLD wmld;
2377 TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize);
2379 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2380 return MMSYSERR_INVALHANDLE;
2382 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpsegMidiOutHdr, uSize, FALSE);
2385 /**************************************************************************
2386 * midiOutReset [WINMM.@]
2388 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2390 LPWINE_MLD wmld;
2392 TRACE("(%04X)\n", hMidiOut);
2394 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2395 return MMSYSERR_INVALHANDLE;
2397 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
2400 /**************************************************************************
2401 * midiOutReset [MMSYSTEM.210]
2403 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2405 return midiOutReset(hMidiOut);
2408 /**************************************************************************
2409 * midiOutGetVolume [WINMM.@]
2411 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2413 LPWINE_MLD wmld;
2415 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
2417 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2418 return MMSYSERR_INVALHANDLE;
2420 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
2423 /**************************************************************************
2424 * midiOutGetVolume [MMSYSTEM.211]
2426 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2428 return midiOutGetVolume(uDeviceID, lpdwVolume);
2431 /**************************************************************************
2432 * midiOutSetVolume [WINMM.@]
2434 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2436 LPWINE_MLD wmld;
2438 TRACE("(%04X, %ld);\n", uDeviceID, dwVolume);
2440 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
2441 return MMSYSERR_INVALHANDLE;
2443 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
2446 /**************************************************************************
2447 * midiOutSetVolume [MMSYSTEM.212]
2449 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2451 return midiOutSetVolume(uDeviceID, dwVolume);
2454 /**************************************************************************
2455 * midiOutCachePatches [WINMM.@]
2457 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2458 WORD* lpwPatchArray, UINT uFlags)
2460 /* not really necessary to support this */
2461 FIXME("not supported yet\n");
2462 return MMSYSERR_NOTSUPPORTED;
2465 /**************************************************************************
2466 * midiOutCachePatches [MMSYSTEM.213]
2468 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2469 WORD* lpwPatchArray, UINT16 uFlags)
2471 return midiOutCachePatches(hMidiOut, uBank, lpwPatchArray, uFlags);
2474 /**************************************************************************
2475 * midiOutCacheDrumPatches [WINMM.@]
2477 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2478 WORD* lpwKeyArray, UINT uFlags)
2480 FIXME("not supported yet\n");
2481 return MMSYSERR_NOTSUPPORTED;
2484 /**************************************************************************
2485 * midiOutCacheDrumPatches [MMSYSTEM.214]
2487 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2488 WORD* lpwKeyArray, UINT16 uFlags)
2490 return midiOutCacheDrumPatches16(hMidiOut, uPatch, lpwKeyArray, uFlags);
2493 /**************************************************************************
2494 * midiOutGetID [WINMM.@]
2496 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2498 LPWINE_MLD wmld;
2500 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2502 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2503 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2504 return MMSYSERR_INVALHANDLE;
2506 *lpuDeviceID = wmld->uDeviceID;
2507 return MMSYSERR_NOERROR;
2510 /**************************************************************************
2511 * midiOutGetID [MMSYSTEM.215]
2513 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2515 LPWINE_MLD wmld;
2517 TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID);
2519 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2520 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2521 return MMSYSERR_INVALHANDLE;
2523 *lpuDeviceID = wmld->uDeviceID;
2524 return MMSYSERR_NOERROR;
2527 /**************************************************************************
2528 * midiOutMessage [WINMM.@]
2530 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2531 DWORD dwParam1, DWORD dwParam2)
2533 LPWINE_MLD wmld;
2535 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2537 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
2538 /* HACK... */
2539 if (uMessage == 0x0001) {
2540 *(LPDWORD)dwParam1 = 1;
2541 return 0;
2543 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
2544 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2546 return MMSYSERR_INVALHANDLE;
2549 switch (uMessage) {
2550 case MODM_OPEN:
2551 case MODM_CLOSE:
2552 FIXME("can't handle OPEN or CLOSE message!\n");
2553 return MMSYSERR_NOTSUPPORTED;
2555 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2558 /**************************************************************************
2559 * midiOutMessage [MMSYSTEM.216]
2561 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2562 DWORD dwParam1, DWORD dwParam2)
2564 LPWINE_MLD wmld;
2566 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
2568 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
2569 return MMSYSERR_INVALHANDLE;
2571 switch (uMessage) {
2572 case MODM_OPEN:
2573 case MODM_CLOSE:
2574 FIXME("can't handle OPEN or CLOSE message!\n");
2575 return MMSYSERR_NOTSUPPORTED;
2577 case MODM_GETVOLUME:
2578 return midiOutGetVolume16(hMidiOut, MapSL(dwParam1));
2579 case MODM_LONGDATA:
2580 return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2);
2581 case MODM_PREPARE:
2582 /* lpMidiOutHdr is still a segmented pointer for this function */
2583 return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2);
2584 case MODM_UNPREPARE:
2585 return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2);
2587 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2590 /**************************************************************************
2591 * midiInGetNumDevs [WINMM.@]
2593 UINT WINAPI midiInGetNumDevs(void)
2595 return MMDRV_GetNum(MMDRV_MIDIIN);
2598 /**************************************************************************
2599 * midiInGetNumDevs [MMSYSTEM.301]
2601 UINT16 WINAPI midiInGetNumDevs16(void)
2603 return MMDRV_GetNum(MMDRV_MIDIIN);
2606 /**************************************************************************
2607 * midiInGetDevCapsW [WINMM.@]
2609 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2611 MIDIINCAPSA micA;
2612 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2614 if (ret == MMSYSERR_NOERROR) {
2615 lpCaps->wMid = micA.wMid;
2616 lpCaps->wPid = micA.wPid;
2617 lpCaps->vDriverVersion = micA.vDriverVersion;
2618 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
2619 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2620 lpCaps->dwSupport = micA.dwSupport;
2622 return ret;
2625 /**************************************************************************
2626 * midiInGetDevCapsA [WINMM.@]
2628 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2630 LPWINE_MLD wmld;
2632 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
2634 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
2635 return MMSYSERR_INVALHANDLE;
2637 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2640 /**************************************************************************
2641 * midiInGetDevCaps [MMSYSTEM.302]
2643 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps,
2644 UINT16 uSize)
2646 MIDIINCAPSA micA;
2647 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
2649 if (ret == MMSYSERR_NOERROR) {
2650 lpCaps->wMid = micA.wMid;
2651 lpCaps->wPid = micA.wPid;
2652 lpCaps->vDriverVersion = micA.vDriverVersion;
2653 strcpy(lpCaps->szPname, micA.szPname);
2654 lpCaps->dwSupport = micA.dwSupport;
2657 return ret;
2660 /**************************************************************************
2661 * midiInGetErrorTextW [WINMM.@]
2663 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2665 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2666 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
2668 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2669 HeapFree(GetProcessHeap(), 0, xstr);
2670 return ret;
2673 /**************************************************************************
2674 * midiInGetErrorTextA [WINMM.@]
2676 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2678 return MIDI_GetErrorText(uError, lpText, uSize);
2681 /**************************************************************************
2682 * midiInGetErrorText [MMSYSTEM.303]
2684 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2686 return MIDI_GetErrorText(uError, lpText, uSize);
2689 static UINT MMSYSTEM_midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
2690 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2692 HMIDIIN hMidiIn;
2693 LPWINE_MIDI lpwm;
2694 DWORD dwRet = 0;
2696 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2697 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2699 if (lphMidiIn != NULL) *lphMidiIn = 0;
2701 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
2702 &dwFlags, &dwCallback, &dwInstance, bFrom32);
2704 if (lpwm == NULL)
2705 return MMSYSERR_NOMEM;
2707 lpwm->mod.hMidi = hMidiIn;
2708 lpwm->mod.dwCallback = dwCallback;
2709 lpwm->mod.dwInstance = dwInstance;
2711 lpwm->mld.uDeviceID = uDeviceID;
2712 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
2714 if (dwRet != MMSYSERR_NOERROR) {
2715 MMDRV_Free(hMidiIn, &lpwm->mld);
2716 hMidiIn = 0;
2718 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
2719 TRACE("=> %ld hMidi=%04x\n", dwRet, hMidiIn);
2721 return dwRet;
2724 /**************************************************************************
2725 * midiInOpen [WINMM.@]
2727 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2728 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2730 return MMSYSTEM_midiInOpen(lphMidiIn, uDeviceID, dwCallback,
2731 dwInstance, dwFlags, TRUE);
2734 /**************************************************************************
2735 * midiInOpen [MMSYSTEM.304]
2737 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2738 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2740 HMIDIIN xhmid;
2741 UINT ret;
2743 ret = MMSYSTEM_midiInOpen(&xhmid, uDeviceID, dwCallback, dwInstance,
2744 dwFlags, FALSE);
2746 if (lphMidiIn) *lphMidiIn = xhmid;
2747 return ret;
2750 /**************************************************************************
2751 * midiInClose [WINMM.@]
2753 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2755 LPWINE_MLD wmld;
2756 DWORD dwRet;
2758 TRACE("(%04X)\n", hMidiIn);
2760 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2761 return MMSYSERR_INVALHANDLE;
2763 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
2764 MMDRV_Free(hMidiIn, wmld);
2765 return dwRet;
2768 /**************************************************************************
2769 * midiInClose [MMSYSTEM.305]
2771 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2773 return midiInClose(hMidiIn);
2776 /**************************************************************************
2777 * midiInPrepareHeader [WINMM.@]
2779 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2780 MIDIHDR* lpMidiInHdr, UINT uSize)
2782 LPWINE_MLD wmld;
2784 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2786 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2787 return MMSYSERR_INVALHANDLE;
2789 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2792 /**************************************************************************
2793 * midiInPrepareHeader [MMSYSTEM.306]
2795 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2796 SEGPTR lpsegMidiInHdr, /* [???] */
2797 UINT16 uSize) /* [in] */
2799 LPWINE_MLD wmld;
2801 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2803 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2804 return MMSYSERR_INVALHANDLE;
2806 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2809 /**************************************************************************
2810 * midiInUnprepareHeader [WINMM.@]
2812 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2813 MIDIHDR* lpMidiInHdr, UINT uSize)
2815 LPWINE_MLD wmld;
2817 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2819 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2820 return MMSYSERR_NOERROR;
2823 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2824 return MMSYSERR_INVALHANDLE;
2826 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
2829 /**************************************************************************
2830 * midiInUnprepareHeader [MMSYSTEM.307]
2832 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */
2833 SEGPTR lpsegMidiInHdr, /* [???] */
2834 UINT16 uSize) /* [in] */
2836 LPWINE_MLD wmld;
2837 LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr);
2839 TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2841 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
2842 return MMSYSERR_NOERROR;
2845 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2846 return MMSYSERR_INVALHANDLE;
2848 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2851 /**************************************************************************
2852 * midiInAddBuffer [WINMM.@]
2854 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2855 MIDIHDR* lpMidiInHdr, UINT uSize)
2857 LPWINE_MLD wmld;
2859 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2861 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2862 return MMSYSERR_INVALHANDLE;
2864 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
2867 /**************************************************************************
2868 * midiInAddBuffer [MMSYSTEM.308]
2870 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */
2871 MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */
2872 UINT16 uSize) /* [in] */
2874 LPWINE_MLD wmld;
2876 TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize);
2878 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2879 return MMSYSERR_INVALHANDLE;
2881 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpsegMidiInHdr, uSize, FALSE);
2884 /**************************************************************************
2885 * midiInStart [WINMM.@]
2887 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2889 LPWINE_MLD wmld;
2891 TRACE("(%04X)\n", hMidiIn);
2893 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2894 return MMSYSERR_INVALHANDLE;
2896 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
2899 /**************************************************************************
2900 * midiInStart [MMSYSTEM.309]
2902 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2904 return midiInStart(hMidiIn);
2907 /**************************************************************************
2908 * midiInStop [WINMM.@]
2910 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
2912 LPWINE_MLD wmld;
2914 TRACE("(%04X)\n", hMidiIn);
2916 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2917 return MMSYSERR_INVALHANDLE;
2919 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
2922 /**************************************************************************
2923 * midiInStop [MMSYSTEM.310]
2925 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
2927 return midiInStop(hMidiIn);
2930 /**************************************************************************
2931 * midiInReset [WINMM.@]
2933 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
2935 LPWINE_MLD wmld;
2937 TRACE("(%04X)\n", hMidiIn);
2939 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
2940 return MMSYSERR_INVALHANDLE;
2942 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
2945 /**************************************************************************
2946 * midiInReset [MMSYSTEM.311]
2948 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
2950 return midiInReset(hMidiIn);
2953 /**************************************************************************
2954 * midiInGetID [WINMM.@]
2956 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
2958 LPWINE_MLD wmld;
2960 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2962 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2964 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
2965 return MMSYSERR_INVALHANDLE;
2967 *lpuDeviceID = wmld->uDeviceID;
2969 return MMSYSERR_NOERROR;
2972 /**************************************************************************
2973 * midiInGetID [MMSYSTEM.312]
2975 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
2977 LPWINE_MLD wmld;
2979 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
2981 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
2983 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
2984 return MMSYSERR_INVALHANDLE;
2986 *lpuDeviceID = wmld->uDeviceID;
2988 return MMSYSERR_NOERROR;
2991 /**************************************************************************
2992 * midiInMessage [WINMM.@]
2994 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
2995 DWORD dwParam1, DWORD dwParam2)
2997 LPWINE_MLD wmld;
2999 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3001 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
3002 return MMSYSERR_INVALHANDLE;
3004 switch (uMessage) {
3005 case MIDM_OPEN:
3006 case MIDM_CLOSE:
3007 FIXME("can't handle OPEN or CLOSE message!\n");
3008 return MMSYSERR_NOTSUPPORTED;
3010 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
3013 /**************************************************************************
3014 * midiInMessage [MMSYSTEM.313]
3016 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
3017 DWORD dwParam1, DWORD dwParam2)
3019 LPWINE_MLD wmld;
3021 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3023 switch (uMessage) {
3024 case MIDM_OPEN:
3025 case MIDM_CLOSE:
3026 FIXME("can't handle OPEN or CLOSE message!\n");
3027 return MMSYSERR_NOTSUPPORTED;
3029 case MIDM_GETDEVCAPS:
3030 return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2);
3031 case MIDM_PREPARE:
3032 return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2);
3033 case MIDM_UNPREPARE:
3034 return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2);
3035 case MIDM_ADDBUFFER:
3036 return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2);
3039 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
3040 return MMSYSERR_INVALHANDLE;
3042 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
3045 typedef struct WINE_MIDIStream {
3046 HMIDIOUT hDevice;
3047 HANDLE hThread;
3048 DWORD dwThreadID;
3049 DWORD dwTempo;
3050 DWORD dwTimeDiv;
3051 DWORD dwPositionMS;
3052 DWORD dwPulses;
3053 DWORD dwStartTicks;
3054 WORD wFlags;
3055 HANDLE hEvent;
3056 LPMIDIHDR lpMidiHdr;
3057 } WINE_MIDIStream;
3059 #define WINE_MSM_HEADER (WM_USER+0)
3060 #define WINE_MSM_STOP (WM_USER+1)
3062 /**************************************************************************
3063 * MMSYSTEM_GetMidiStream [internal]
3065 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
3067 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
3069 if (lplpwm)
3070 *lplpwm = lpwm;
3072 if (lpwm == NULL) {
3073 return FALSE;
3076 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
3078 return *lpMidiStrm != NULL;
3081 /**************************************************************************
3082 * MMSYSTEM_MidiStream_Convert [internal]
3084 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
3086 DWORD ret = 0;
3088 if (lpMidiStrm->dwTimeDiv == 0) {
3089 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
3090 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
3091 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
3092 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
3093 ret = (pulse * 1000) / (nf * nsf);
3094 } else {
3095 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
3096 (double)lpMidiStrm->dwTimeDiv);
3099 return ret;
3102 /**************************************************************************
3103 * MMSYSTEM_MidiStream_MessageHandler [internal]
3105 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
3107 LPMIDIHDR lpMidiHdr;
3108 LPMIDIHDR* lpmh;
3109 LPBYTE lpData;
3111 switch (msg->message) {
3112 case WM_QUIT:
3113 SetEvent(lpMidiStrm->hEvent);
3114 return FALSE;
3115 case WINE_MSM_STOP:
3116 TRACE("STOP\n");
3117 /* this is not quite what MS doc says... */
3118 midiOutReset(lpMidiStrm->hDevice);
3119 /* empty list of already submitted buffers */
3120 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
3121 lpMidiHdr->dwFlags |= MHDR_DONE;
3122 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3124 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3125 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3127 lpMidiStrm->lpMidiHdr = 0;
3128 SetEvent(lpMidiStrm->hEvent);
3129 break;
3130 case WINE_MSM_HEADER:
3131 /* sets initial tick count for first MIDIHDR */
3132 if (!lpMidiStrm->dwStartTicks)
3133 lpMidiStrm->dwStartTicks = GetTickCount();
3135 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
3136 * by native mcimidi, it doesn't look like a correct one".
3137 * this trick allows to throw it away... but I don't like it.
3138 * It looks like part of the file I'm trying to play and definitively looks
3139 * like raw midi content
3140 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
3141 * synchronization issue where native mcimidi is still processing raw MIDI
3142 * content before generating MIDIEVENTs ?
3144 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
3145 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
3146 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
3147 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
3148 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
3149 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
3150 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
3151 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
3152 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
3153 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3154 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3155 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3156 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3157 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3158 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3159 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3160 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3162 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3163 lpData = lpMidiHdr->lpData;
3164 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
3165 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
3166 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
3167 lpMidiHdr->dwFlags, msg->wParam);
3168 #if 0
3169 /* dumps content of lpMidiHdr->lpData
3170 * FIXME: there should be a debug routine somewhere that already does this
3171 * I hate spreading this type of shit all around the code
3173 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
3174 DWORD i;
3175 BYTE ch;
3177 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
3178 printf("%02x ", lpData[dwToGo + i]);
3179 for (; i < 16; i++)
3180 printf(" ");
3181 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
3182 ch = lpData[dwToGo + i];
3183 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
3185 printf("\n");
3187 #endif
3188 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3189 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3190 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3191 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
3192 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
3193 ((LPMIDIEVENT)lpData)->dwStreamID);
3194 lpMidiHdr->dwFlags |= MHDR_DONE;
3195 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3197 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3198 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3199 break;
3202 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
3203 *lpmh = lpMidiHdr;
3204 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3205 lpMidiHdr->lpNext = 0;
3206 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
3207 lpMidiHdr->dwFlags &= MHDR_DONE;
3208 lpMidiHdr->dwOffset = 0;
3210 break;
3211 default:
3212 FIXME("Unknown message %d\n", msg->message);
3213 break;
3215 return TRUE;
3218 /**************************************************************************
3219 * MMSYSTEM_MidiStream_Player [internal]
3221 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
3223 WINE_MIDIStream* lpMidiStrm = pmt;
3224 WINE_MIDI* lpwm;
3225 MSG msg;
3226 DWORD dwToGo;
3227 DWORD dwCurrTC;
3228 LPMIDIHDR lpMidiHdr;
3229 LPMIDIEVENT me;
3230 LPBYTE lpData = 0;
3232 TRACE("(%p)!\n", lpMidiStrm);
3234 if (!lpMidiStrm ||
3235 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
3236 goto the_end;
3238 /* force thread's queue creation */
3239 /* Used to be InitThreadInput16(0, 5); */
3240 /* but following works also with hack in midiStreamOpen */
3241 PeekMessageA(&msg, 0, 0, 0, 0);
3243 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
3244 SetEvent(lpMidiStrm->hEvent);
3245 TRACE("Ready to go 1\n");
3246 /* thread is started in paused mode */
3247 SuspendThread(lpMidiStrm->hThread);
3248 TRACE("Ready to go 2\n");
3250 lpMidiStrm->dwStartTicks = 0;
3251 lpMidiStrm->dwPulses = 0;
3253 lpMidiStrm->lpMidiHdr = 0;
3255 for (;;) {
3256 lpMidiHdr = lpMidiStrm->lpMidiHdr;
3257 if (!lpMidiHdr) {
3258 /* for first message, block until one arrives, then process all that are available */
3259 GetMessageA(&msg, 0, 0, 0);
3260 do {
3261 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3262 goto the_end;
3263 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
3264 lpData = 0;
3265 continue;
3268 if (!lpData)
3269 lpData = lpMidiHdr->lpData;
3271 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3273 /* do we have to wait ? */
3274 if (me->dwDeltaTime) {
3275 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
3276 lpMidiStrm->dwPulses += me->dwDeltaTime;
3278 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3280 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
3281 while ((dwCurrTC = GetTickCount()) < dwToGo) {
3282 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
3283 /* got a message, handle it */
3284 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
3285 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
3286 goto the_end;
3288 lpData = 0;
3289 } else {
3290 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
3291 break;
3295 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3296 case MEVT_COMMENT:
3297 FIXME("NIY: MEVT_COMMENT\n");
3298 /* do nothing, skip bytes */
3299 break;
3300 case MEVT_LONGMSG:
3301 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3302 break;
3303 case MEVT_NOP:
3304 break;
3305 case MEVT_SHORTMSG:
3306 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3307 break;
3308 case MEVT_TEMPO:
3309 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3310 break;
3311 case MEVT_VERSION:
3312 break;
3313 default:
3314 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3315 break;
3317 if (me->dwEvent & MEVT_F_CALLBACK) {
3318 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3319 MM_MOM_POSITIONCB, lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
3321 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
3322 if (me->dwEvent & MEVT_F_LONG)
3323 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
3324 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
3325 /* done with this header */
3326 lpMidiHdr->dwFlags |= MHDR_DONE;
3327 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3329 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
3330 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3331 MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
3332 lpData = 0;
3335 the_end:
3336 TRACE("End of thread\n");
3337 ExitThread(0);
3338 return 0; /* for removing the warning, never executed */
3341 /**************************************************************************
3342 * MMSYSTEM_MidiStream_PostMessage [internal]
3344 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
3346 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
3347 DWORD count;
3349 ReleaseThunkLock(&count);
3350 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3351 RestoreThunkLock(count);
3352 } else {
3353 WARN("bad PostThreadMessageA\n");
3354 return FALSE;
3356 return TRUE;
3359 /**************************************************************************
3360 * midiStreamClose [WINMM.@]
3362 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3364 WINE_MIDIStream* lpMidiStrm;
3366 TRACE("(%08x)!\n", hMidiStrm);
3368 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3369 return MMSYSERR_INVALHANDLE;
3371 midiStreamStop(hMidiStrm);
3372 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
3373 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
3374 CloseHandle(lpMidiStrm->hEvent);
3376 return midiOutClose(hMidiStrm);
3379 /**************************************************************************
3380 * MMSYSTEM_MidiStream_Open [internal]
3382 static MMRESULT WINAPI MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3383 DWORD cMidi, DWORD dwCallback,
3384 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
3386 WINE_MIDIStream* lpMidiStrm;
3387 MMRESULT ret;
3388 MIDIOPENSTRMID mosm;
3389 LPWINE_MIDI lpwm;
3390 HMIDIOUT hMidiOut;
3392 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3393 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3395 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3396 return MMSYSERR_INVALPARAM;
3398 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3399 if (!lpMidiStrm)
3400 return MMSYSERR_NOMEM;
3402 lpMidiStrm->dwTempo = 500000;
3403 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3404 lpMidiStrm->dwPositionMS = 0;
3406 mosm.dwStreamID = (DWORD)lpMidiStrm;
3407 /* FIXME: the correct value is not allocated yet for MAPPER */
3408 mosm.wDeviceID = *lpuDeviceID;
3409 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
3410 lpMidiStrm->hDevice = hMidiOut;
3411 if (lphMidiStrm)
3412 *lphMidiStrm = hMidiOut;
3414 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
3415 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
3416 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
3418 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
3419 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
3420 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3422 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
3423 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3425 if (!lpMidiStrm->hThread) {
3426 midiStreamClose((HMIDISTRM)hMidiOut);
3427 return MMSYSERR_NOMEM;
3430 /* wait for thread to have started, and for its queue to be created */
3432 DWORD count;
3434 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3435 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3436 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3438 ReleaseThunkLock(&count);
3439 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3440 RestoreThunkLock(count);
3443 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n",
3444 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
3445 return ret;
3448 /**************************************************************************
3449 * midiStreamOpen [WINMM.@]
3451 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3452 DWORD cMidi, DWORD dwCallback,
3453 DWORD dwInstance, DWORD fdwOpen)
3455 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
3456 dwInstance, fdwOpen, TRUE);
3459 /**************************************************************************
3460 * midiStreamOut [WINMM.@]
3462 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
3463 UINT cbMidiHdr)
3465 WINE_MIDIStream* lpMidiStrm;
3466 DWORD ret = MMSYSERR_NOERROR;
3468 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3470 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3471 ret = MMSYSERR_INVALHANDLE;
3472 } else if (!lpMidiHdr) {
3473 ret = MMSYSERR_INVALPARAM;
3474 } else {
3475 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
3476 WINE_MSM_HEADER, cbMidiHdr,
3477 (DWORD)lpMidiHdr)) {
3478 WARN("bad PostThreadMessageA\n");
3479 ret = MMSYSERR_ERROR;
3482 return ret;
3485 /**************************************************************************
3486 * midiStreamPause [WINMM.@]
3488 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3490 WINE_MIDIStream* lpMidiStrm;
3491 DWORD ret = MMSYSERR_NOERROR;
3493 TRACE("(%08x)!\n", hMidiStrm);
3495 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3496 ret = MMSYSERR_INVALHANDLE;
3497 } else {
3498 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3499 WARN("bad Suspend (%ld)\n", GetLastError());
3500 ret = MMSYSERR_ERROR;
3503 return ret;
3506 /**************************************************************************
3507 * midiStreamPosition [WINMM.@]
3509 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3511 WINE_MIDIStream* lpMidiStrm;
3512 DWORD ret = MMSYSERR_NOERROR;
3514 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3516 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3517 ret = MMSYSERR_INVALHANDLE;
3518 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3519 ret = MMSYSERR_INVALPARAM;
3520 } else {
3521 switch (lpMMT->wType) {
3522 case TIME_MS:
3523 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3524 TRACE("=> %ld ms\n", lpMMT->u.ms);
3525 break;
3526 case TIME_TICKS:
3527 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3528 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
3529 break;
3530 default:
3531 WARN("Unsupported time type %d\n", lpMMT->wType);
3532 lpMMT->wType = TIME_MS;
3533 ret = MMSYSERR_INVALPARAM;
3534 break;
3537 return ret;
3540 /**************************************************************************
3541 * midiStreamProperty [WINMM.@]
3543 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3545 WINE_MIDIStream* lpMidiStrm;
3546 MMRESULT ret = MMSYSERR_NOERROR;
3548 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3550 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3551 ret = MMSYSERR_INVALHANDLE;
3552 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3553 ret = MMSYSERR_INVALPARAM;
3554 } else if (dwProperty & MIDIPROP_TEMPO) {
3555 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3557 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3558 ret = MMSYSERR_INVALPARAM;
3559 } else if (dwProperty & MIDIPROP_SET) {
3560 lpMidiStrm->dwTempo = mpt->dwTempo;
3561 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
3562 } else if (dwProperty & MIDIPROP_GET) {
3563 mpt->dwTempo = lpMidiStrm->dwTempo;
3564 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
3566 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3567 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3569 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3570 ret = MMSYSERR_INVALPARAM;
3571 } else if (dwProperty & MIDIPROP_SET) {
3572 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3573 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
3574 } else if (dwProperty & MIDIPROP_GET) {
3575 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3576 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
3578 } else {
3579 ret = MMSYSERR_INVALPARAM;
3582 return ret;
3585 /**************************************************************************
3586 * midiStreamRestart [WINMM.@]
3588 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3590 WINE_MIDIStream* lpMidiStrm;
3591 MMRESULT ret = MMSYSERR_NOERROR;
3593 TRACE("(%08x)!\n", hMidiStrm);
3595 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3596 ret = MMSYSERR_INVALHANDLE;
3597 } else {
3598 DWORD ret;
3600 /* since we increase the thread suspend count on each midiStreamPause
3601 * there may be a need for several midiStreamResume
3603 do {
3604 ret = ResumeThread(lpMidiStrm->hThread);
3605 } while (ret != 0xFFFFFFFF && ret != 0);
3606 if (ret == 0xFFFFFFFF) {
3607 WARN("bad Resume (%ld)\n", GetLastError());
3608 ret = MMSYSERR_ERROR;
3609 } else {
3610 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
3613 return ret;
3616 /**************************************************************************
3617 * midiStreamStop [WINMM.@]
3619 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3621 WINE_MIDIStream* lpMidiStrm;
3622 MMRESULT ret = MMSYSERR_NOERROR;
3624 TRACE("(%08x)!\n", hMidiStrm);
3626 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3627 ret = MMSYSERR_INVALHANDLE;
3628 } else {
3629 /* in case stream has been paused... FIXME is the current state correct ? */
3630 midiStreamRestart(hMidiStrm);
3631 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
3633 return ret;
3636 /**************************************************************************
3637 * midiStreamClose [MMSYSTEM.252]
3639 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3641 return midiStreamClose(hMidiStrm);
3644 /**************************************************************************
3645 * midiStreamOpen [MMSYSTEM.251]
3647 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3648 DWORD cMidi, DWORD dwCallback,
3649 DWORD dwInstance, DWORD fdwOpen)
3651 HMIDISTRM hMidiStrm32;
3652 MMRESULT ret;
3653 UINT devid32;
3655 if (!phMidiStrm || !devid)
3656 return MMSYSERR_INVALPARAM;
3657 devid32 = *devid;
3658 ret = MMSYSTEM_MidiStream_Open(&hMidiStrm32, &devid32, cMidi, dwCallback,
3659 dwInstance, fdwOpen, FALSE);
3660 *phMidiStrm = hMidiStrm32;
3661 *devid = devid32;
3662 return ret;
3665 /**************************************************************************
3666 * midiStreamOut [MMSYSTEM.254]
3668 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3670 return midiStreamOut(hMidiStrm, (LPMIDIHDR)lpMidiHdr, cbMidiHdr);
3673 /**************************************************************************
3674 * midiStreamPause [MMSYSTEM.255]
3676 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3678 return midiStreamPause(hMidiStrm);
3681 /**************************************************************************
3682 * midiStreamPosition [MMSYSTEM.253]
3684 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3686 MMTIME mmt32;
3687 MMRESULT ret;
3689 if (!lpmmt16)
3690 return MMSYSERR_INVALPARAM;
3691 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3692 ret = midiStreamPosition(hMidiStrm, &mmt32, sizeof(MMTIME));
3693 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3694 return ret;
3697 /**************************************************************************
3698 * midiStreamProperty [MMSYSTEM.250]
3700 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3702 return midiStreamProperty(hMidiStrm, lpPropData, dwProperty);
3705 /**************************************************************************
3706 * midiStreamRestart [MMSYSTEM.256]
3708 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3710 return midiStreamRestart(hMidiStrm);
3713 /**************************************************************************
3714 * midiStreamStop [MMSYSTEM.257]
3716 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3718 return midiStreamStop(hMidiStrm);
3721 static UINT WINAPI MMSYSTEM_waveOpen(HANDLE* lphndl, UINT uDeviceID, UINT uType,
3722 const LPWAVEFORMATEX lpFormat,
3723 DWORD dwCallback, DWORD dwInstance,
3724 DWORD dwFlags, BOOL bFrom32)
3726 HANDLE handle;
3727 LPWINE_MLD wmld;
3728 DWORD dwRet = MMSYSERR_NOERROR;
3729 WAVEOPENDESC wod;
3731 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
3732 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
3733 dwInstance, dwFlags, bFrom32?32:16);
3735 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
3737 if (lpFormat == NULL) return WAVERR_BADFORMAT;
3738 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
3739 return MMSYSERR_INVALPARAM;
3741 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
3742 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
3743 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
3745 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
3746 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
3747 return MMSYSERR_NOMEM;
3749 wod.hWave = handle;
3750 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
3751 wod.dwCallback = dwCallback;
3752 wod.dwInstance = dwInstance;
3753 wod.dnDevNode = 0L;
3755 if (dwFlags & WAVE_MAPPED) {
3756 wod.uMappedDeviceID = uDeviceID;
3757 uDeviceID = WAVE_MAPPER;
3758 } else {
3759 wod.uMappedDeviceID = -1;
3761 wmld->uDeviceID = uDeviceID;
3763 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, (DWORD)&wod, dwFlags);
3765 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
3766 MMDRV_Free(handle, wmld);
3767 handle = 0;
3770 if (lphndl != NULL) *lphndl = handle;
3771 TRACE("=> %ld hWave=%04x\n", dwRet, handle);
3773 return dwRet;
3776 /**************************************************************************
3777 * waveOutGetNumDevs [WINMM.@]
3779 UINT WINAPI waveOutGetNumDevs(void)
3781 return MMDRV_GetNum(MMDRV_WAVEOUT);
3784 /**************************************************************************
3785 * waveOutGetNumDevs [MMSYSTEM.401]
3787 UINT16 WINAPI waveOutGetNumDevs16(void)
3789 return MMDRV_GetNum(MMDRV_WAVEOUT);
3792 /**************************************************************************
3793 * waveOutGetDevCaps [MMSYSTEM.402]
3795 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID,
3796 LPWAVEOUTCAPS16 lpCaps, UINT16 uSize)
3798 WAVEOUTCAPSA wocA;
3799 UINT ret;
3801 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3802 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3804 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3806 if (ret == MMSYSERR_NOERROR) {
3807 lpCaps->wMid = wocA.wMid;
3808 lpCaps->wPid = wocA.wPid;
3809 lpCaps->vDriverVersion = wocA.vDriverVersion;
3810 strcpy(lpCaps->szPname, wocA.szPname);
3811 lpCaps->dwFormats = wocA.dwFormats;
3812 lpCaps->wChannels = wocA.wChannels;
3813 lpCaps->dwSupport = wocA.dwSupport;
3815 return ret;
3818 /**************************************************************************
3819 * waveOutGetDevCapsA [WINMM.@]
3821 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3822 UINT uSize)
3824 LPWINE_MLD wmld;
3826 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3828 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3830 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
3831 return MMSYSERR_INVALHANDLE;
3833 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
3837 /**************************************************************************
3838 * waveOutGetDevCapsW [WINMM.@]
3840 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3841 UINT uSize)
3843 WAVEOUTCAPSA wocA;
3844 UINT ret;
3846 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3848 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
3850 if (ret == MMSYSERR_NOERROR) {
3851 lpCaps->wMid = wocA.wMid;
3852 lpCaps->wPid = wocA.wPid;
3853 lpCaps->vDriverVersion = wocA.vDriverVersion;
3854 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
3855 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
3856 lpCaps->dwFormats = wocA.dwFormats;
3857 lpCaps->wChannels = wocA.wChannels;
3858 lpCaps->dwSupport = wocA.dwSupport;
3860 return ret;
3863 /**************************************************************************
3864 * WAVE_GetErrorText [internal]
3866 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3868 UINT16 ret = MMSYSERR_BADERRNUM;
3870 if (lpText == NULL) {
3871 ret = MMSYSERR_INVALPARAM;
3872 } else if (uSize == 0) {
3873 ret = MMSYSERR_NOERROR;
3874 } else if (
3875 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
3876 * a warning for the test was always true */
3877 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
3878 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
3880 if (LoadStringA(MULTIMEDIA_GetIData()->hWinMM32Instance,
3881 uError, lpText, uSize) > 0) {
3882 ret = MMSYSERR_NOERROR;
3885 return ret;
3888 /**************************************************************************
3889 * waveOutGetErrorText [MMSYSTEM.403]
3891 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3893 return WAVE_GetErrorText(uError, lpText, uSize);
3896 /**************************************************************************
3897 * waveOutGetErrorTextA [WINMM.@]
3899 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3901 return WAVE_GetErrorText(uError, lpText, uSize);
3904 /**************************************************************************
3905 * waveOutGetErrorTextW [WINMM.@]
3907 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3909 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3910 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
3912 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
3913 HeapFree(GetProcessHeap(), 0, xstr);
3914 return ret;
3917 /**************************************************************************
3918 * waveOutOpen [WINMM.@]
3919 * All the args/structs have the same layout as the win16 equivalents
3921 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
3922 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3923 DWORD dwInstance, DWORD dwFlags)
3925 return MMSYSTEM_waveOpen(lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
3926 dwCallback, dwInstance, dwFlags, TRUE);
3929 /**************************************************************************
3930 * waveOutOpen [MMSYSTEM.404]
3932 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
3933 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3934 DWORD dwInstance, DWORD dwFlags)
3936 HWAVEOUT hWaveOut;
3937 UINT ret;
3939 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
3940 * call the 32 bit version
3941 * however, we need to promote correctly the wave mapper id
3942 * (0xFFFFFFFF and not 0x0000FFFF)
3944 ret = MMSYSTEM_waveOpen(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
3945 MMDRV_WAVEOUT, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
3947 if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
3948 return ret;
3951 /**************************************************************************
3952 * waveOutClose [WINMM.@]
3954 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
3956 LPWINE_MLD wmld;
3957 DWORD dwRet;
3959 TRACE("(%04X)\n", hWaveOut);
3961 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3962 return MMSYSERR_INVALHANDLE;
3964 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
3965 MMDRV_Free(hWaveOut, wmld);
3967 return dwRet;
3970 /**************************************************************************
3971 * waveOutClose [MMSYSTEM.405]
3973 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
3975 DWORD level;
3976 UINT16 ret;
3978 ReleaseThunkLock(&level);
3979 ret = waveOutClose(hWaveOut);
3980 RestoreThunkLock(level);
3981 return ret;
3984 /**************************************************************************
3985 * waveOutPrepareHeader [WINMM.@]
3987 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
3988 WAVEHDR* lpWaveOutHdr, UINT uSize)
3990 LPWINE_MLD wmld;
3992 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
3994 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
3996 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
3997 return MMSYSERR_INVALHANDLE;
3999 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4002 /**************************************************************************
4003 * waveOutPrepareHeader [MMSYSTEM.406]
4005 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
4006 SEGPTR lpsegWaveOutHdr, /* [???] */
4007 UINT16 uSize) /* [in] */
4009 LPWINE_MLD wmld;
4010 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
4012 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4014 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
4016 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4017 return MMSYSERR_INVALHANDLE;
4019 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4022 /**************************************************************************
4023 * waveOutUnprepareHeader [WINMM.@]
4025 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
4026 LPWAVEHDR lpWaveOutHdr, UINT uSize)
4028 LPWINE_MLD wmld;
4030 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4032 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
4033 return MMSYSERR_NOERROR;
4036 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4037 return MMSYSERR_INVALHANDLE;
4039 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4042 /**************************************************************************
4043 * waveOutUnprepareHeader [MMSYSTEM.407]
4045 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */
4046 SEGPTR lpsegWaveOutHdr, /* [???] */
4047 UINT16 uSize) /* [in] */
4049 LPWINE_MLD wmld;
4050 LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr);
4052 TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4054 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
4055 return MMSYSERR_NOERROR;
4058 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4059 return MMSYSERR_INVALHANDLE;
4061 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4064 /**************************************************************************
4065 * waveOutWrite [WINMM.@]
4067 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
4068 UINT uSize)
4070 LPWINE_MLD wmld;
4072 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4074 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4075 return MMSYSERR_INVALHANDLE;
4077 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
4080 /**************************************************************************
4081 * waveOutWrite [MMSYSTEM.408]
4083 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */
4084 LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */
4085 UINT16 uSize) /* [in] */
4087 LPWINE_MLD wmld;
4089 TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize);
4091 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4092 return MMSYSERR_INVALHANDLE;
4094 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpsegWaveOutHdr, uSize, FALSE);
4097 /**************************************************************************
4098 * waveOutBreakLoop [WINMM.@]
4100 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
4102 LPWINE_MLD wmld;
4104 TRACE("(%04X);\n", hWaveOut);
4106 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4107 return MMSYSERR_INVALHANDLE;
4108 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
4111 /**************************************************************************
4112 * waveOutBreakLoop [MMSYSTEM.419]
4114 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16)
4116 DWORD level;
4117 UINT16 ret;
4119 ReleaseThunkLock(&level);
4120 ret = waveOutBreakLoop(hWaveOut16);
4121 RestoreThunkLock(level);
4122 return ret;
4125 /**************************************************************************
4126 * waveOutPause [WINMM.@]
4128 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
4130 LPWINE_MLD wmld;
4132 TRACE("(%04X);\n", hWaveOut);
4134 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4135 return MMSYSERR_INVALHANDLE;
4136 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
4139 /**************************************************************************
4140 * waveOutPause [MMSYSTEM.409]
4142 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16)
4144 DWORD level;
4145 UINT16 ret;
4147 ReleaseThunkLock(&level);
4148 ret = waveOutPause(hWaveOut16);
4149 RestoreThunkLock(level);
4150 return ret;
4153 /**************************************************************************
4154 * waveOutReset [WINMM.@]
4156 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
4158 LPWINE_MLD wmld;
4160 TRACE("(%04X);\n", hWaveOut);
4162 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4163 return MMSYSERR_INVALHANDLE;
4164 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
4167 /**************************************************************************
4168 * waveOutReset [MMSYSTEM.411]
4170 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16)
4172 DWORD level;
4173 UINT16 ret;
4175 ReleaseThunkLock(&level);
4176 ret = waveOutReset(hWaveOut16);
4177 RestoreThunkLock(level);
4178 return ret;
4181 /**************************************************************************
4182 * waveOutRestart [WINMM.@]
4184 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
4186 LPWINE_MLD wmld;
4188 TRACE("(%04X);\n", hWaveOut);
4190 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4191 return MMSYSERR_INVALHANDLE;
4192 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
4195 /**************************************************************************
4196 * waveOutRestart [MMSYSTEM.410]
4198 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16)
4200 DWORD level;
4201 UINT16 ret;
4203 ReleaseThunkLock(&level);
4204 ret = waveOutRestart(hWaveOut16);
4205 RestoreThunkLock(level);
4206 return ret;
4209 /**************************************************************************
4210 * waveOutGetPosition [WINMM.@]
4212 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
4213 UINT uSize)
4215 LPWINE_MLD wmld;
4217 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
4219 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4220 return MMSYSERR_INVALHANDLE;
4222 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4225 /**************************************************************************
4226 * waveOutGetPosition [MMSYSTEM.412]
4228 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
4229 UINT16 uSize)
4231 UINT ret;
4232 MMTIME mmt;
4234 mmt.wType = lpTime->wType;
4235 ret = waveOutGetPosition(hWaveOut, &mmt, sizeof(mmt));
4236 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4237 return ret;
4240 /**************************************************************************
4241 * waveOutGetPitch [WINMM.@]
4243 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
4245 LPWINE_MLD wmld;
4247 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4249 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4250 return MMSYSERR_INVALHANDLE;
4251 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
4254 /**************************************************************************
4255 * waveOutGetPitch [MMSYSTEM.413]
4257 UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4259 return waveOutGetPitch(hWaveOut16, lpdw);
4262 /**************************************************************************
4263 * waveOutSetPitch [WINMM.@]
4265 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
4267 LPWINE_MLD wmld;
4269 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4271 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4272 return MMSYSERR_INVALHANDLE;
4273 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
4276 /**************************************************************************
4277 * waveOutSetPitch [MMSYSTEM.414]
4279 UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw)
4281 return waveOutSetPitch(hWaveOut16, dw);
4284 /**************************************************************************
4285 * waveOutGetPlaybackRate [WINMM.@]
4287 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
4289 LPWINE_MLD wmld;
4291 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)lpdw);
4293 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4294 return MMSYSERR_INVALHANDLE;
4295 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
4298 /**************************************************************************
4299 * waveOutGetPlaybackRate [MMSYSTEM.417]
4301 UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw)
4303 return waveOutGetPlaybackRate(hWaveOut16, lpdw);
4306 /**************************************************************************
4307 * waveOutSetPlaybackRate [WINMM.@]
4309 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
4311 LPWINE_MLD wmld;
4313 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)dw);
4315 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4316 return MMSYSERR_INVALHANDLE;
4317 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
4320 /**************************************************************************
4321 * waveOutSetPlaybackRate [MMSYSTEM.418]
4323 UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw)
4325 return waveOutSetPlaybackRate(hWaveOut16, dw);
4328 /**************************************************************************
4329 * waveOutGetVolume [WINMM.@]
4331 UINT WINAPI waveOutGetVolume(UINT devid, LPDWORD lpdw)
4333 LPWINE_MLD wmld;
4335 TRACE("(%04X, %08lx);\n", devid, (DWORD)lpdw);
4337 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4338 return MMSYSERR_INVALHANDLE;
4340 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
4343 /**************************************************************************
4344 * waveOutGetVolume [MMSYSTEM.415]
4346 UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw)
4348 return waveOutGetVolume(devid, lpdw);
4351 /**************************************************************************
4352 * waveOutSetVolume [WINMM.@]
4354 UINT WINAPI waveOutSetVolume(UINT devid, DWORD dw)
4356 LPWINE_MLD wmld;
4358 TRACE("(%04X, %08lx);\n", devid, dw);
4360 if ((wmld = MMDRV_Get(devid, MMDRV_WAVEOUT, TRUE)) == NULL)
4361 return MMSYSERR_INVALHANDLE;
4363 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
4366 /**************************************************************************
4367 * waveOutSetVolume [MMSYSTEM.416]
4369 UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw)
4371 return waveOutSetVolume(devid, dw);
4374 /**************************************************************************
4375 * waveOutGetID [WINMM.@]
4377 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
4379 LPWINE_MLD wmld;
4381 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4383 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4385 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4386 return MMSYSERR_INVALHANDLE;
4388 *lpuDeviceID = wmld->uDeviceID;
4389 return 0;
4392 /**************************************************************************
4393 * waveOutGetID [MMSYSTEM.420]
4395 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
4397 LPWINE_MLD wmld;
4399 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4401 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4403 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
4404 return MMSYSERR_INVALHANDLE;
4406 *lpuDeviceID = wmld->uDeviceID;
4407 return 0;
4410 /**************************************************************************
4411 * waveOutMessage [WINMM.@]
4413 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
4414 DWORD dwParam1, DWORD dwParam2)
4416 LPWINE_MLD wmld;
4418 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4420 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4421 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4422 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4424 return MMSYSERR_INVALHANDLE;
4427 /* from M$ KB */
4428 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4429 return MMSYSERR_INVALPARAM;
4431 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4434 /**************************************************************************
4435 * waveOutMessage [MMSYSTEM.421]
4437 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4438 DWORD dwParam1, DWORD dwParam2)
4440 LPWINE_MLD wmld;
4442 TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
4444 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
4445 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
4446 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
4448 return MMSYSERR_INVALHANDLE;
4451 /* from M$ KB */
4452 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4453 return MMSYSERR_INVALPARAM;
4455 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE);
4458 /**************************************************************************
4459 * waveInGetNumDevs [WINMM.@]
4461 UINT WINAPI waveInGetNumDevs(void)
4463 return MMDRV_GetNum(MMDRV_WAVEIN);
4466 /**************************************************************************
4467 * waveInGetNumDevs [MMSYSTEM.501]
4469 UINT16 WINAPI waveInGetNumDevs16(void)
4471 return MMDRV_GetNum(MMDRV_WAVEIN);
4474 /**************************************************************************
4475 * waveInGetDevCapsW [WINMM.@]
4477 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4479 WAVEINCAPSA wicA;
4480 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
4482 if (ret == MMSYSERR_NOERROR) {
4483 lpCaps->wMid = wicA.wMid;
4484 lpCaps->wPid = wicA.wPid;
4485 lpCaps->vDriverVersion = wicA.vDriverVersion;
4486 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
4487 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
4488 lpCaps->dwFormats = wicA.dwFormats;
4489 lpCaps->wChannels = wicA.wChannels;
4492 return ret;
4495 /**************************************************************************
4496 * waveInGetDevCapsA [WINMM.@]
4498 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4500 LPWINE_MLD wmld;
4502 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
4504 if ((wmld = MMDRV_Get(uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
4505 return MMSYSERR_INVALHANDLE;
4507 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
4510 /**************************************************************************
4511 * waveInGetDevCaps [MMSYSTEM.502]
4513 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps,
4514 UINT16 uSize)
4516 WAVEINCAPSA wicA;
4517 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
4519 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
4521 if (ret == MMSYSERR_NOERROR) {
4522 lpCaps->wMid = wicA.wMid;
4523 lpCaps->wPid = wicA.wPid;
4524 lpCaps->vDriverVersion = wicA.vDriverVersion;
4525 strcpy(lpCaps->szPname, wicA.szPname);
4526 lpCaps->dwFormats = wicA.dwFormats;
4527 lpCaps->wChannels = wicA.wChannels;
4529 return ret;
4532 /**************************************************************************
4533 * waveInGetErrorTextA [WINMM.@]
4535 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4537 return WAVE_GetErrorText(uError, lpText, uSize);
4540 /**************************************************************************
4541 * waveInGetErrorTextW [WINMM.@]
4543 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4545 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4546 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
4548 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
4549 HeapFree(GetProcessHeap(), 0, txt);
4550 return ret;
4553 /**************************************************************************
4554 * waveInGetErrorText [MMSYSTEM.503]
4556 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4558 return WAVE_GetErrorText(uError, lpText, uSize);
4561 /**************************************************************************
4562 * waveInOpen [WINMM.@]
4564 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4565 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4566 DWORD dwInstance, DWORD dwFlags)
4568 return MMSYSTEM_waveOpen(lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
4569 dwCallback, dwInstance, dwFlags, TRUE);
4572 /**************************************************************************
4573 * waveInOpen [MMSYSTEM.504]
4575 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4576 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4577 DWORD dwInstance, DWORD dwFlags)
4579 HWAVEIN hWaveIn;
4580 UINT ret;
4582 /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly
4583 * call the 32 bit version
4584 * however, we need to promote correctly the wave mapper id
4585 * (0xFFFFFFFF and not 0x0000FFFF)
4587 ret = MMSYSTEM_waveOpen(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID,
4588 MMDRV_WAVEIN, lpFormat, dwCallback, dwInstance, dwFlags, FALSE);
4590 if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
4591 return ret;
4594 /**************************************************************************
4595 * waveInClose [WINMM.@]
4597 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4599 LPWINE_MLD wmld;
4600 DWORD dwRet;
4602 TRACE("(%04X)\n", hWaveIn);
4604 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4605 return MMSYSERR_INVALHANDLE;
4607 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
4608 MMDRV_Free(hWaveIn, wmld);
4609 return dwRet;
4612 /**************************************************************************
4613 * waveInClose [MMSYSTEM.505]
4615 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4617 DWORD level;
4618 UINT16 ret;
4620 ReleaseThunkLock(&level);
4621 ret = waveInClose(hWaveIn);
4622 RestoreThunkLock(level);
4623 return ret;
4626 /**************************************************************************
4627 * waveInPrepareHeader [WINMM.@]
4629 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
4630 UINT uSize)
4632 LPWINE_MLD wmld;
4634 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4636 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4637 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4638 return MMSYSERR_INVALHANDLE;
4640 lpWaveInHdr->dwBytesRecorded = 0;
4642 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4645 /**************************************************************************
4646 * waveInPrepareHeader [MMSYSTEM.506]
4648 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4649 SEGPTR lpsegWaveInHdr, /* [???] */
4650 UINT16 uSize) /* [in] */
4652 LPWINE_MLD wmld;
4653 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4654 UINT16 ret;
4656 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4658 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4659 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4660 return MMSYSERR_INVALHANDLE;
4662 lpWaveInHdr->dwBytesRecorded = 0;
4664 ret = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4665 return ret;
4668 /**************************************************************************
4669 * waveInUnprepareHeader [WINMM.@]
4671 UINT WINAPI waveInUnprepareHeader(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 (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4680 return MMSYSERR_NOERROR;
4683 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4684 return MMSYSERR_INVALHANDLE;
4686 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
4689 /**************************************************************************
4690 * waveInUnprepareHeader [MMSYSTEM.507]
4692 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */
4693 SEGPTR lpsegWaveInHdr, /* [???] */
4694 UINT16 uSize) /* [in] */
4696 LPWINE_MLD wmld;
4697 LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr);
4699 TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4701 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4703 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
4704 return MMSYSERR_NOERROR;
4707 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4708 return MMSYSERR_INVALHANDLE;
4710 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4713 /**************************************************************************
4714 * waveInAddBuffer [WINMM.@]
4716 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4717 WAVEHDR* lpWaveInHdr, UINT uSize)
4719 LPWINE_MLD wmld;
4721 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4723 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4724 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4725 return MMSYSERR_INVALHANDLE;
4727 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
4730 /**************************************************************************
4731 * waveInAddBuffer [MMSYSTEM.508]
4733 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */
4734 WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */
4735 UINT16 uSize) /* [in] */
4737 LPWINE_MLD wmld;
4739 TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize);
4741 if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
4742 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4743 return MMSYSERR_INVALHANDLE;
4745 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpsegWaveInHdr, uSize, FALSE);
4748 /**************************************************************************
4749 * waveInReset [WINMM.@]
4751 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4753 LPWINE_MLD wmld;
4755 TRACE("(%04X);\n", hWaveIn);
4757 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4758 return MMSYSERR_INVALHANDLE;
4760 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
4763 /**************************************************************************
4764 * waveInReset [MMSYSTEM.511]
4766 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16)
4768 DWORD level;
4769 UINT16 ret;
4771 ReleaseThunkLock(&level);
4772 ret = waveInReset(hWaveIn16);
4773 RestoreThunkLock(level);
4774 return ret;
4777 /**************************************************************************
4778 * waveInStart [WINMM.@]
4780 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4782 LPWINE_MLD wmld;
4784 TRACE("(%04X);\n", hWaveIn);
4786 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4787 return MMSYSERR_INVALHANDLE;
4789 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
4792 /**************************************************************************
4793 * waveInStart [MMSYSTEM.509]
4795 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16)
4797 DWORD level;
4798 UINT16 ret;
4800 ReleaseThunkLock(&level);
4801 ret = waveInStart(hWaveIn16);
4802 RestoreThunkLock(level);
4803 return ret;
4806 /**************************************************************************
4807 * waveInStop [WINMM.@]
4809 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4811 LPWINE_MLD wmld;
4813 TRACE("(%04X);\n", hWaveIn);
4815 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4816 return MMSYSERR_INVALHANDLE;
4818 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
4821 /**************************************************************************
4822 * waveInStop [MMSYSTEM.510]
4824 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16)
4826 DWORD level;
4827 UINT16 ret;
4829 ReleaseThunkLock(&level);
4830 ret = waveInStop(hWaveIn16);
4831 RestoreThunkLock(level);
4832 return ret;
4835 /**************************************************************************
4836 * waveInGetPosition [WINMM.@]
4838 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4839 UINT uSize)
4841 LPWINE_MLD wmld;
4843 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4845 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4846 return MMSYSERR_INVALHANDLE;
4848 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
4851 /**************************************************************************
4852 * waveInGetPosition [MMSYSTEM.512]
4854 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4855 UINT16 uSize)
4857 UINT ret;
4858 MMTIME mmt;
4860 mmt.wType = lpTime->wType;
4861 ret = waveInGetPosition(hWaveIn, &mmt, sizeof(mmt));
4862 MMSYSTEM_MMTIME32to16(lpTime, &mmt);
4863 return ret;
4866 /**************************************************************************
4867 * waveInGetID [WINMM.@]
4869 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4871 LPWINE_MLD wmld;
4873 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4875 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4877 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4878 return MMSYSERR_INVALHANDLE;
4880 *lpuDeviceID = wmld->uDeviceID;
4881 return MMSYSERR_NOERROR;
4884 /**************************************************************************
4885 * waveInGetID [MMSYSTEM.513]
4887 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4889 LPWINE_MLD wmld;
4891 TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID);
4893 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4895 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4896 return MMSYSERR_INVALHANDLE;
4898 *lpuDeviceID = wmld->uDeviceID;
4899 return MMSYSERR_NOERROR;
4902 /**************************************************************************
4903 * waveInMessage [WINMM.@]
4905 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4906 DWORD dwParam1, DWORD dwParam2)
4908 LPWINE_MLD wmld;
4910 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4912 /* from M$ KB */
4913 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4914 return MMSYSERR_INVALPARAM;
4916 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4917 return MMSYSERR_INVALHANDLE;
4919 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4922 /**************************************************************************
4923 * waveInMessage [MMSYSTEM.514]
4925 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4926 DWORD dwParam1, DWORD dwParam2)
4928 LPWINE_MLD wmld;
4930 TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
4932 /* from M$ KB */
4933 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
4934 return MMSYSERR_INVALPARAM;
4936 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
4937 return MMSYSERR_INVALHANDLE;
4939 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
4942 /*#define USE_MM_TSK_WINE*/
4944 /**************************************************************************
4945 * mmTaskCreate [MMSYSTEM.900]
4947 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
4948 * called upon creation with dwPmt as parameter.
4950 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
4952 HINSTANCE16 ret;
4953 HINSTANCE16 handle;
4954 char cmdline[16];
4955 DWORD showCmd = 0x40002;
4956 LOADPARAMS16 lp;
4958 TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
4959 /* This to work requires NE modules to be started with a binary command line
4960 * which is not currently the case. A patch exists but has never been committed.
4961 * A workaround would be to integrate code for mmtask.tsk into Wine, but
4962 * this requires tremendous work (starting with patching tools/build to
4963 * create NE executables (and not only DLLs) for builtins modules.
4964 * EP 99/04/25
4966 FIXME("This is currently broken. It will fail\n");
4968 cmdline[0] = 0x0d;
4969 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
4970 *(LPDWORD)(cmdline + 5) = dwPmt;
4971 *(LPDWORD)(cmdline + 9) = 0;
4973 lp.hEnvironment = 0;
4974 lp.cmdLine = MapLS(cmdline);
4975 lp.showCmd = MapLS(&showCmd);
4976 lp.reserved = 0;
4978 #ifndef USE_MM_TSK_WINE
4979 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp);
4980 #else
4981 handle = LoadModule16("mmtask.tsk", &lp);
4982 #endif
4983 if (handle < 32) {
4984 ret = (handle) ? 1 : 2;
4985 handle = 0;
4986 } else {
4987 ret = 0;
4989 if (lphMmTask)
4990 *lphMmTask = handle;
4992 UnMapLS( lp.cmdLine );
4993 UnMapLS( lp.showCmd );
4994 TRACE("=> 0x%04x/%d\n", handle, ret);
4995 return ret;
4998 #ifdef USE_MM_TSK_WINE
4999 /* C equivalent to mmtask.tsk binary content */
5000 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
5002 int len = cmdLine[0x80];
5004 if (len / 2 == 6) {
5005 void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1)));
5006 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
5008 #if 0
5009 InitTask16(); /* FIXME: pmts / from context ? */
5010 InitApp(di);
5011 #endif
5012 if (SetMessageQueue16(0x40)) {
5013 WaitEvent16(0);
5014 if (HIWORD(fpProc)) {
5015 OldYield16();
5016 /* EPP StackEnter16(); */
5017 (fpProc)(dwPmt);
5021 OldYield16();
5022 OldYield16();
5023 OldYield16();
5024 ExitProcess(0);
5026 #endif
5028 /**************************************************************************
5029 * mmTaskBlock [MMSYSTEM.902]
5031 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
5033 MSG msg;
5035 do {
5036 GetMessageA(&msg, 0, 0, 0);
5037 if (msg.hwnd) {
5038 TranslateMessage(&msg);
5039 DispatchMessageA(&msg);
5041 } while (msg.message < 0x3A0);
5044 /**************************************************************************
5045 * mmTaskSignal [MMSYSTEM.903]
5047 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
5049 TRACE("(%04x);\n", ht);
5050 return PostAppMessage16(ht, WM_USER, 0, 0);
5053 /**************************************************************************
5054 * mmGetCurrentTask [MMSYSTEM.904]
5056 HTASK16 WINAPI mmGetCurrentTask16(void)
5058 return GetCurrentTask();
5061 /**************************************************************************
5062 * mmTaskYield [MMSYSTEM.905]
5064 void WINAPI mmTaskYield16(void)
5066 MSG msg;
5068 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
5069 K32WOWYield16();
5073 DWORD WINAPI GetProcessFlags(DWORD);
5075 /**************************************************************************
5076 * mmThreadCreate [MMSYSTEM.1120]
5078 * undocumented
5079 * Creates a MM thread, calling fpThreadAddr(dwPmt).
5080 * dwFlags:
5081 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
5082 * bit.1 set means to open a VxD for this thread (unsupported)
5084 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
5086 HANDLE16 hndl;
5087 LRESULT ret;
5089 TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
5091 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
5093 if (hndl == 0) {
5094 ret = 2;
5095 } else {
5096 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5098 #if 0
5099 /* force mmtask routines even if mmthread is required */
5100 /* this will work only if the patch about binary cmd line and NE tasks
5101 * is committed
5103 dwFlags |= 1;
5104 #endif
5106 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
5107 lpMMThd->dwCounter = 0;
5108 lpMMThd->hThread = 0;
5109 lpMMThd->dwThreadID = 0;
5110 lpMMThd->fpThread = fpThreadAddr;
5111 lpMMThd->dwThreadPmt = dwPmt;
5112 lpMMThd->dwSignalCount = 0;
5113 lpMMThd->hEvent = 0;
5114 lpMMThd->hVxD = 0;
5115 lpMMThd->dwStatus = 0;
5116 lpMMThd->dwFlags = dwFlags;
5117 lpMMThd->hTask = 0;
5119 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
5120 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
5122 TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
5123 if (lpMMThd->dwFlags & 2) {
5124 /* as long as we don't support MM VxD in wine, we don't need
5125 * to care about this flag
5127 /* FIXME("Don't know how to properly open VxD handles\n"); */
5128 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
5131 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
5132 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
5133 if (lpMMThd->hThread == 0) {
5134 WARN("Couldn't create thread\n");
5135 /* clean-up(VxDhandle...); devicedirectio... */
5136 if (lpMMThd->hEvent != 0)
5137 CloseHandle(lpMMThd->hEvent);
5138 ret = 2;
5139 } else {
5140 TRACE("Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
5141 ret = 0;
5143 } else {
5144 /* get WINE_mmThreadEntryPoint()
5145 * 2047 is its ordinal in mmsystem.spec
5147 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047);
5149 TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp));
5151 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
5154 if (ret == 0) {
5155 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
5156 WARN("Couldn't resume thread\n");
5158 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
5159 UserYield16();
5164 if (ret != 0) {
5165 GlobalFree16(hndl);
5166 hndl = 0;
5169 if (lpHndl)
5170 *lpHndl = hndl;
5172 TRACE("ok => %ld\n", ret);
5173 return ret;
5176 /**************************************************************************
5177 * mmThreadSignal [MMSYSTEM.1121]
5179 void WINAPI mmThreadSignal16(HANDLE16 hndl)
5181 TRACE("(%04x)!\n", hndl);
5183 if (hndl) {
5184 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5186 lpMMThd->dwCounter++;
5187 if (lpMMThd->hThread != 0) {
5188 InterlockedIncrement(&lpMMThd->dwSignalCount);
5189 SetEvent(lpMMThd->hEvent);
5190 } else {
5191 mmTaskSignal16(lpMMThd->hTask);
5193 lpMMThd->dwCounter--;
5197 /**************************************************************************
5198 * MMSYSTEM_ThreadBlock [internal]
5200 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
5202 MSG msg;
5203 DWORD ret;
5205 if (lpMMThd->dwThreadID != GetCurrentThreadId())
5206 ERR("Not called by thread itself\n");
5208 for (;;) {
5209 ResetEvent(lpMMThd->hEvent);
5210 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
5211 break;
5212 InterlockedIncrement(&lpMMThd->dwSignalCount);
5214 TRACE("S1\n");
5216 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
5217 switch (ret) {
5218 case WAIT_OBJECT_0: /* Event */
5219 TRACE("S2.1\n");
5220 break;
5221 case WAIT_OBJECT_0 + 1: /* Msg */
5222 TRACE("S2.2\n");
5223 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
5224 TranslateMessage(&msg);
5225 DispatchMessageA(&msg);
5227 break;
5228 default:
5229 WARN("S2.x unsupported ret val 0x%08lx\n", ret);
5231 TRACE("S3\n");
5235 /**************************************************************************
5236 * mmThreadBlock [MMSYSTEM.1122]
5238 void WINAPI mmThreadBlock16(HANDLE16 hndl)
5240 TRACE("(%04x)!\n", hndl);
5242 if (hndl) {
5243 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5245 if (lpMMThd->hThread != 0) {
5246 DWORD lc;
5248 ReleaseThunkLock(&lc);
5249 MMSYSTEM_ThreadBlock(lpMMThd);
5250 RestoreThunkLock(lc);
5251 } else {
5252 mmTaskBlock16(lpMMThd->hTask);
5255 TRACE("done\n");
5258 /**************************************************************************
5259 * mmThreadIsCurrent [MMSYSTEM.1123]
5261 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
5263 BOOL16 ret = FALSE;
5265 TRACE("(%04x)!\n", hndl);
5267 if (hndl && mmThreadIsValid16(hndl)) {
5268 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5269 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
5271 TRACE("=> %d\n", ret);
5272 return ret;
5275 /**************************************************************************
5276 * mmThreadIsValid [MMSYSTEM.1124]
5278 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
5280 BOOL16 ret = FALSE;
5282 TRACE("(%04x)!\n", hndl);
5284 if (hndl) {
5285 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5287 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
5288 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
5289 IsTask16(lpMMThd->hTask)) {
5290 lpMMThd->dwCounter++;
5291 if (lpMMThd->hThread != 0) {
5292 DWORD dwThreadRet;
5293 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
5294 dwThreadRet == STATUS_PENDING) {
5295 ret = TRUE;
5297 } else {
5298 ret = TRUE;
5300 lpMMThd->dwCounter--;
5303 TRACE("=> %d\n", ret);
5304 return ret;
5307 /**************************************************************************
5308 * mmThreadGetTask [MMSYSTEM.1125]
5310 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5312 HANDLE16 ret = 0;
5314 TRACE("(%04x)\n", hndl);
5316 if (mmThreadIsValid16(hndl)) {
5317 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5318 ret = lpMMThd->hTask;
5320 return ret;
5323 /* ### start build ### */
5324 extern LONG CALLBACK MMSYSTEM_CallTo16_long_l (FARPROC16,LONG);
5325 /* ### stop build ### */
5327 /**************************************************************************
5328 * __wine_mmThreadEntryPoint (MMSYSTEM.2047)
5330 void WINAPI WINE_mmThreadEntryPoint(DWORD _pmt)
5332 HANDLE16 hndl = (HANDLE16)_pmt;
5333 WINE_MMTHREAD* lpMMThd = MapSL( MAKESEGPTR(hndl, 0) );
5335 TRACE("(%04x %p)\n", hndl, lpMMThd);
5337 lpMMThd->hTask = LOWORD(GetCurrentTask());
5338 TRACE("[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5339 lpMMThd->dwStatus = 0x10;
5340 MMSYSTEM_ThreadBlock(lpMMThd);
5341 TRACE("[20-%08x]\n", lpMMThd->hThread);
5342 lpMMThd->dwStatus = 0x20;
5343 if (lpMMThd->fpThread) {
5344 MMSYSTEM_CallTo16_long_l(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5346 lpMMThd->dwStatus = 0x30;
5347 TRACE("[30-%08x]\n", lpMMThd->hThread);
5348 while (lpMMThd->dwCounter) {
5349 Sleep(1);
5350 /* K32WOWYield16();*/
5352 TRACE("[XX-%08x]\n", lpMMThd->hThread);
5353 /* paranoia */
5354 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5355 /* close lpMMThread->hVxD directIO */
5356 if (lpMMThd->hEvent)
5357 CloseHandle(lpMMThd->hEvent);
5358 GlobalFree16(hndl);
5359 TRACE("done\n");
5362 typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR);
5364 /**************************************************************************
5365 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5367 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice,
5368 LPCSTR lpStrTab, LPCSTR lpStrTitle)
5370 HANDLE hndl;
5371 BOOL16 ret = FALSE;
5373 TRACE("(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5375 hndl = LoadLibraryA("MMSYS.CPL");
5376 if (hndl != 0) {
5377 MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5378 if (fp != NULL) {
5379 DWORD lc;
5380 ReleaseThunkLock(&lc);
5381 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5382 RestoreThunkLock(lc);
5384 FreeLibrary(hndl);
5387 return ret;
5390 /**************************************************************************
5391 * StackEnter [MMSYSTEM.32]
5393 void WINAPI StackEnter16(void)
5395 #ifdef __i386__
5396 /* mmsystem.dll from Win 95 does only this: so does Wine */
5397 __asm__("stc");
5398 #endif
5401 /**************************************************************************
5402 * StackLeave [MMSYSTEM.33]
5404 void WINAPI StackLeave16(void)
5406 #ifdef __i386__
5407 /* mmsystem.dll from Win 95 does only this: so does Wine */
5408 __asm__("stc");
5409 #endif
5412 /**************************************************************************
5413 * WMMMidiRunOnce [MMSYSTEM.8]
5415 void WINAPI WMMMidiRunOnce16(void)
5417 FIXME("(), stub!\n");
5420 /**************************************************************************
5421 * OutputDebugStr [MMSYSTEM.30]
5423 void WINAPI OutputDebugStr16(
5424 LPCSTR str) /* [in] The message to be logged and given to the debugger. */
5426 OutputDebugStringA( str );