16-bit scheduler reorganized: run all tasks in their own thread.
[wine/hacks.git] / multimedia / mmsystem.c
blobef798bb8d4efc4acfec116fd4a63a04d365c2779
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MMSYTEM functions
6 * Copyright 1993 Martin Ayotte
7 */
9 /*
10 * Eric POUECH :
11 * 98/9 added Win32 MCI support
12 * 99/4 added mmTask and mmThread functions support
13 * added midiStream support
16 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses
17 * and long term pointers to 16 bit space in here
20 #include <stdlib.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <sys/ioctl.h>
26 #include "winbase.h"
27 #include "windef.h"
28 #include "wine/winbase16.h"
29 #include "heap.h"
30 #include "user.h"
31 #include "driver.h"
32 #include "multimedia.h"
33 #include "syslevel.h"
34 #include "callback.h"
35 #include "module.h"
36 #include "selectors.h"
37 #include "debugtools.h"
39 DEFAULT_DEBUG_CHANNEL(mmsys)
41 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
42 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
43 LONG WINAPI DrvDefDriverProc(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg,
44 DWORD dwParam1, DWORD dwParam2);
46 static HINSTANCE WINMM_hInstance = 0;
47 static HINSTANCE MMSYSTEM_hInstance = 0;
49 /**************************************************************************
50 * MULTIMEDIA_Init [internal]
52 static BOOL MULTIMEDIA_Init()
54 static BOOL bInitDone = FALSE;
56 if (!bInitDone) {
57 if (MULTIMEDIA_MidiInit() && MULTIMEDIA_MciInit() && MULTIMEDIA_MMTimeInit()) {
58 bInitDone = TRUE;
59 } else {
60 return FALSE;
63 return TRUE;
66 /**************************************************************************
67 * WINMM_LibMain [EntryPoint]
69 * WINMM DLL entry point
72 BOOL WINAPI WINMM_LibMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
74 TRACE("0x%x 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
76 switch (fdwReason) {
77 case DLL_PROCESS_ATTACH:
78 if (!MULTIMEDIA_Init())
79 return FALSE;
80 WINMM_hInstance = hinstDLL;
81 break;
82 case DLL_THREAD_ATTACH:
83 case DLL_THREAD_DETACH:
84 case DLL_PROCESS_DETACH:
85 break;
87 return TRUE;
90 /**************************************************************************
91 * MMSYSTEM_LibMain [EntryPoint]
93 * MMSYSTEM DLL entry point
96 BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds,
97 WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
99 TRACE("0x%x 0x%lx\n", hinstDLL, fdwReason);
101 switch (fdwReason) {
102 case DLL_PROCESS_ATTACH:
103 if (!MULTIMEDIA_Init())
104 return FALSE;
105 MMSYSTEM_hInstance = hinstDLL;
106 break;
107 case DLL_THREAD_ATTACH:
108 case DLL_THREAD_DETACH:
109 case DLL_PROCESS_DETACH:
110 break;
112 return TRUE;
115 /**************************************************************************
116 * MMSYSTEM_WEP [MMSYSTEM.1]
118 int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg,
119 WORD cbHeapSize, LPSTR lpCmdLine)
121 FIXME("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance);
122 return(TRUE);
125 static void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32)
127 mmt16->wType = mmt32->wType;
128 /* layout of rest is the same for 32/16,
129 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
131 memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u));
134 static void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
136 mmt32->wType = mmt16->wType;
137 /* layout of rest is the same for 32/16,
138 * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding
140 memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
143 static HANDLE PlaySound_hThread = 0;
144 static HANDLE PlaySound_hPlayEvent = 0;
145 static HANDLE PlaySound_hReadyEvent = 0;
146 static HANDLE PlaySound_hMiddleEvent = 0;
147 static BOOL PlaySound_Result = FALSE;
148 static int PlaySound_Stop = FALSE;
149 static int PlaySound_Playing = FALSE;
151 static LPCSTR PlaySound_pszSound = NULL;
152 static HMODULE PlaySound_hmod = 0;
153 static DWORD PlaySound_fdwSound = 0;
154 static int PlaySound_Loop = FALSE;
155 static int PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
156 2 - PlaySound order */
158 static HMMIO16 get_mmioFromFile(LPCSTR lpszName)
160 return mmioOpen16((LPSTR)lpszName, NULL,
161 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
164 static HMMIO16 get_mmioFromProfile(UINT uFlags, LPCSTR lpszName)
166 char str[128];
167 LPSTR ptr;
168 HMMIO16 hmmio;
170 TRACE("searching in SystemSound List !\n");
171 GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
172 if (strlen(str) == 0) {
173 if (uFlags & SND_NODEFAULT) return 0;
174 GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
175 if (strlen(str) == 0) return 0;
177 if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
178 hmmio = get_mmioFromFile(str);
179 if (hmmio == 0) {
180 WARN("can't find SystemSound='%s' !\n", str);
181 return 0;
183 return hmmio;
186 static BOOL16 WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
188 BOOL16 bRet = FALSE;
189 HMMIO16 hmmio;
190 MMCKINFO ckMainRIFF;
192 TRACE("SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
193 if (lpszSoundName == NULL) {
194 TRACE("Stop !\n");
195 return FALSE;
197 if (uFlags & SND_MEMORY) {
198 MMIOINFO16 mminfo;
199 memset(&mminfo, 0, sizeof(mminfo));
200 mminfo.fccIOProc = FOURCC_MEM;
201 mminfo.pchBuffer = (LPSTR)lpszSoundName;
202 mminfo.cchBuffer = -1;
203 TRACE("Memory sound %p\n", lpszSoundName);
204 hmmio = mmioOpen16(NULL, &mminfo, MMIO_READ);
205 } else {
206 hmmio = 0;
207 if (uFlags & SND_ALIAS)
208 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
209 return FALSE;
211 if (uFlags & SND_FILENAME)
212 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
214 if (PlaySound_SearchMode == 1) {
215 PlaySound_SearchMode = 0;
216 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0)
217 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
218 return FALSE;
221 if (PlaySound_SearchMode == 2) {
222 PlaySound_SearchMode = 0;
223 if ((hmmio=get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0)
224 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0)
225 if ((hmmio=get_mmioFromProfile(uFlags, lpszSoundName)) == 0) return FALSE;
229 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0) == 0)
230 do {
231 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
232 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
233 ckMainRIFF.cksize);
235 if ((ckMainRIFF.ckid == FOURCC_RIFF) &&
236 (ckMainRIFF.fccType == mmioFOURCC('W', 'A', 'V', 'E'))) {
237 MMCKINFO mmckInfo;
239 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
241 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
242 PCMWAVEFORMAT pcmWaveFormat;
244 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
245 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
247 if (mmioRead(hmmio, (HPSTR)&pcmWaveFormat,
248 (long) sizeof(PCMWAVEFORMAT)) == (long) sizeof(PCMWAVEFORMAT)) {
249 TRACE("wFormatTag=%04X !\n", pcmWaveFormat.wf.wFormatTag);
250 TRACE("nChannels=%d \n", pcmWaveFormat.wf.nChannels);
251 TRACE("nSamplesPerSec=%ld\n", pcmWaveFormat.wf.nSamplesPerSec);
252 TRACE("nAvgBytesPerSec=%ld\n", pcmWaveFormat.wf.nAvgBytesPerSec);
253 TRACE("nBlockAlign=%d \n", pcmWaveFormat.wf.nBlockAlign);
254 TRACE("wBitsPerSample=%u !\n", pcmWaveFormat.wBitsPerSample);
256 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
257 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
258 WAVEOPENDESC waveDesc;
259 DWORD dwRet;
261 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
262 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
264 pcmWaveFormat.wf.nAvgBytesPerSec = pcmWaveFormat.wf.nSamplesPerSec *
265 pcmWaveFormat.wf.nBlockAlign;
266 waveDesc.hWave = 0;
267 waveDesc.lpFormat = (LPWAVEFORMAT)&pcmWaveFormat;
269 dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
270 if (dwRet == MMSYSERR_NOERROR) {
271 WAVEHDR waveHdr;
272 HGLOBAL16 hData;
273 INT count, bufsize, left = mmckInfo.cksize;
275 bufsize = 64000;
276 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
277 waveHdr.lpData = (LPSTR)GlobalLock16(hData);
278 waveHdr.dwBufferLength = bufsize;
279 waveHdr.dwUser = 0L;
280 waveHdr.dwFlags = 0L;
281 waveHdr.dwLoops = 0L;
283 dwRet = wodMessage(0, WODM_PREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
284 if (dwRet == MMSYSERR_NOERROR) {
285 while (left) {
286 if (PlaySound_Stop) {
287 PlaySound_Stop = FALSE;
288 PlaySound_Loop = FALSE;
289 break;
291 if (bufsize > left) bufsize = left;
292 count = mmioRead(hmmio, waveHdr.lpData,bufsize);
293 if (count < 1) break;
294 left -= count;
295 waveHdr.dwBufferLength = count;
296 /* FIXME */
297 waveHdr.reserved = (DWORD)&waveHdr;
298 /* waveHdr.dwBytesRecorded = count; */
299 /* FIXME: doesn't expect async ops */
300 wodMessage(0, WODM_WRITE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
301 while (!(waveHdr.dwFlags & WHDR_DONE))
302 Sleep(10);
304 wodMessage(0, WODM_UNPREPARE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
305 while (wodMessage(0, WODM_CLOSE, 0, 0L, 0L) == WAVERR_STILLPLAYING)
306 Sleep(100);
308 bRet = TRUE;
309 } else
310 WARN("can't prepare WaveOut device !\n");
312 GlobalUnlock16(hData);
313 GlobalFree16(hData);
319 } while (PlaySound_Loop);
321 if (hmmio != 0) mmioClose(hmmio, 0);
322 return bRet;
325 static DWORD WINAPI PlaySound_Thread(LPVOID arg)
327 DWORD res;
329 for (;;) {
330 PlaySound_Playing = FALSE;
331 SetEvent(PlaySound_hReadyEvent);
332 res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
333 ResetEvent(PlaySound_hReadyEvent);
334 SetEvent(PlaySound_hMiddleEvent);
335 if (res == WAIT_FAILED) ExitThread(2);
336 if (res != WAIT_OBJECT_0) continue;
337 PlaySound_Playing = TRUE;
339 if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
340 HRSRC hRES;
341 HGLOBAL hGLOB;
342 void* ptr;
344 if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
345 PlaySound_Result = FALSE;
346 continue;
348 if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
349 PlaySound_Result = FALSE;
350 continue;
352 if ((ptr = LockResource(hGLOB)) == NULL) {
353 FreeResource(hGLOB);
354 PlaySound_Result = FALSE;
355 continue;
357 PlaySound_Result = proc_PlaySound(ptr,
358 ((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
359 FreeResource(hGLOB);
360 continue;
362 PlaySound_Result=proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
366 /**************************************************************************
367 * PlaySoundA [WINMM.1]
369 BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
371 static LPSTR StrDup = NULL;
373 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
374 pszSound, hmod, fdwSound);
376 if (PlaySound_hThread == 0) { /* This is the first time they called us */
377 DWORD id;
378 if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
379 return FALSE;
380 if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
381 return FALSE;
382 if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
383 return FALSE;
384 if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0)
385 return FALSE;
388 /* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */
389 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing)
390 return FALSE;
392 /* Trying to stop if playing */
393 if (PlaySound_Playing) PlaySound_Stop = TRUE;
395 /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
396 if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
397 return FALSE;
399 if (!pszSound || (fdwSound & SND_PURGE))
400 return FALSE; /* We stoped playing so leaving */
402 if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
403 if (!(fdwSound & SND_ASYNC)) {
404 if (fdwSound & SND_LOOP)
405 return FALSE;
406 PlaySound_pszSound = pszSound;
407 PlaySound_hmod = hmod;
408 PlaySound_fdwSound = fdwSound;
409 PlaySound_Result = FALSE;
410 SetEvent(PlaySound_hPlayEvent);
411 if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0)
412 return FALSE;
413 if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0)
414 return FALSE;
415 return PlaySound_Result;
416 } else {
417 PlaySound_hmod = hmod;
418 PlaySound_fdwSound = fdwSound;
419 PlaySound_Result = FALSE;
420 if (StrDup) {
421 HeapFree(GetProcessHeap(), 0, StrDup);
422 StrDup = NULL;
424 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
425 !((DWORD)pszSound >> 16)) || !pszSound)) {
426 StrDup = HEAP_strdupA(GetProcessHeap(), 0,pszSound);
427 PlaySound_pszSound = StrDup;
428 } else PlaySound_pszSound = pszSound;
429 PlaySound_Loop = fdwSound & SND_LOOP;
430 SetEvent(PlaySound_hPlayEvent);
431 ResetEvent(PlaySound_hMiddleEvent);
432 return TRUE;
434 return FALSE;
437 /**************************************************************************
438 * PlaySoundW [WINMM.18]
440 BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
442 LPSTR pszSoundA;
443 BOOL bSound;
445 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
446 !((DWORD)pszSound >> 16)) || !pszSound)) {
447 pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
448 bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
449 HeapFree(GetProcessHeap(), 0,pszSoundA);
450 } else
451 bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
453 return bSound;
456 /**************************************************************************
457 * PlaySound16 [MMSYSTEM.3]
459 BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
461 BOOL16 retv;
463 SYSLEVEL_ReleaseWin16Lock();
464 retv = PlaySoundA( pszSound, hmod, fdwSound );
465 SYSLEVEL_RestoreWin16Lock();
467 return retv;
470 /**************************************************************************
471 * sndPlaySoundA [WINMM135]
473 BOOL WINAPI sndPlaySoundA(LPCSTR lpszSoundName, UINT uFlags)
475 PlaySound_SearchMode = 1;
476 return PlaySoundA(lpszSoundName, 0, uFlags);
479 /**************************************************************************
480 * sndPlaySoundW [WINMM.136]
482 BOOL WINAPI sndPlaySoundW(LPCWSTR lpszSoundName, UINT uFlags)
484 PlaySound_SearchMode = 1;
485 return PlaySoundW(lpszSoundName, 0, uFlags);
488 /**************************************************************************
489 * sndPlaySound16 [MMSYSTEM.2]
491 BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
493 BOOL16 retv;
495 SYSLEVEL_ReleaseWin16Lock();
496 retv = sndPlaySoundA( lpszSoundName, uFlags );
497 SYSLEVEL_RestoreWin16Lock();
499 return retv;
503 /**************************************************************************
504 * mmsystemGetVersion [WINMM.134]
506 UINT WINAPI mmsystemGetVersion()
508 return mmsystemGetVersion16();
511 /**************************************************************************
512 * mmsystemGetVersion [MMSYSTEM.5]
513 * return value borrowed from Win95 winmm.dll ;)
515 UINT16 WINAPI mmsystemGetVersion16()
517 TRACE("3.10 (Win95?)\n");
518 return 0x030a;
521 /**************************************************************************
522 * DriverProc [MMSYSTEM.6]
524 LRESULT WINAPI DriverProc16(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg,
525 DWORD dwParam1, DWORD dwParam2)
527 return DrvDefDriverProc(dwDevID, hDrv, wMsg, dwParam1, dwParam2);
530 /**************************************************************************
531 * DriverCallback [MMSYSTEM.31]
533 BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HANDLE16 hDev,
534 WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
536 TRACE("(%08lX, %04X, %04X, %04X, %08lX, %08lX, %08lX); !\n",
537 dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
539 switch (uFlags & DCB_TYPEMASK) {
540 case DCB_NULL:
541 TRACE("Null !\n");
542 break;
543 case DCB_WINDOW:
544 TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
545 if (!IsWindow(dwCallBack) || USER_HEAP_LIN_ADDR(hDev) == NULL)
546 return FALSE;
547 Callout.PostMessageA((HWND16)dwCallBack, wMsg, hDev, dwParam1);
548 break;
549 case DCB_TASK: /* aka DCB_THREAD */
550 TRACE("Task(%04lx) !\n", dwCallBack);
551 Callout.PostThreadMessageA(dwCallBack, wMsg, hDev, dwParam1);
552 break;
553 case DCB_FUNCTION:
554 TRACE("Function (16bit) !\n");
555 Callbacks->CallDriverCallback((FARPROC16)dwCallBack, hDev, wMsg, dwUser,
556 dwParam1, dwParam2);
557 break;
558 case DCB_FUNC32: /* This is a Wine only value - AKAIF not used yet by MS */
559 TRACE("Function (32bit) !\n");
560 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
561 break;
562 case DCB_EVENT:
563 TRACE("Event(%08lx) !\n", dwCallBack);
564 SetEvent((HANDLE)dwCallBack);
565 break;
566 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
567 /* this is an undocumented DCB_ value used for mmThreads
568 * loword of dwCallBack contains the handle of the lpMMThd block
569 * which dwSignalCount has to be incremented
572 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(LOWORD(dwCallBack), 0);
574 TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
575 /* same as mmThreadSignal16 */
576 InterlockedIncrement(&lpMMThd->dwSignalCount);
577 SetEvent(lpMMThd->hEvent);
578 /* some other stuff on lpMMThd->hVxD */
580 break;
581 #if 0
582 case 4:
583 /* this is an undocumented DCB_ value for... I don't know */
584 break;
585 #endif
586 default:
587 WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
588 return FALSE;
590 TRACE("Done\n");
591 return TRUE;
594 /**************************************************************************
595 * Mixer devices. New to Win95
598 /**************************************************************************
599 * find out the real mixer ID depending on hmix (depends on dwFlags)
600 * FIXME: also fix dwInstance passing to mixMessage
602 static UINT MIXER_GetDevID(HMIXEROBJ hmix, DWORD dwFlags)
604 /* FIXME: Check dwFlags for MIXER_OBJSECTF_xxxx entries and modify hmix
605 * accordingly. For now we always use mixerdevice 0.
607 return 0;
610 /**************************************************************************
611 * mixerGetNumDevs [WINMM.108]
613 UINT WINAPI mixerGetNumDevs(void)
615 UINT16 count = mixMessage(0, MXDM_GETNUMDEVS, 0L, 0L, 0L);
617 TRACE("mixerGetNumDevs returns %d\n", count);
618 return count;
621 /**************************************************************************
622 * mixerGetNumDevs [MMSYSTEM.800]
624 UINT16 WINAPI mixerGetNumDevs16()
626 return mixerGetNumDevs();
629 /**************************************************************************
630 * mixerGetDevCapsA [WINMM.101]
632 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
634 return mixMessage(devid, MXDM_GETDEVCAPS, 0L, (DWORD)mixcaps, (DWORD)size);
637 /**************************************************************************
638 * mixerGetDevCapsW [WINMM.102]
640 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
642 MIXERCAPSA micA;
643 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
645 if (ret == MMSYSERR_NOERROR) {
646 mixcaps->wMid = micA.wMid;
647 mixcaps->wPid = micA.wPid;
648 mixcaps->vDriverVersion = micA.vDriverVersion;
649 lstrcpyAtoW(mixcaps->szPname, micA.szPname);
650 mixcaps->fdwSupport = micA.fdwSupport;
651 mixcaps->cDestinations = micA.cDestinations;
653 return ret;
656 /**************************************************************************
657 * mixerGetDevCaps [MMSYSTEM.801]
659 UINT16 WINAPI mixerGetDevCaps16(UINT16 devid, LPMIXERCAPS16 mixcaps, UINT16 size)
661 MIXERCAPSA micA;
662 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
664 if (ret == MMSYSERR_NOERROR) {
665 mixcaps->wMid = micA.wMid;
666 mixcaps->wPid = micA.wPid;
667 mixcaps->vDriverVersion = micA.vDriverVersion;
668 strcpy(mixcaps->szPname, micA.szPname);
669 mixcaps->fdwSupport = micA.fdwSupport;
670 mixcaps->cDestinations = micA.cDestinations;
672 return ret;
675 /**************************************************************************
676 * mixerOpen [WINMM.110]
678 UINT WINAPI mixerOpen(LPHMIXER lphmix, UINT uDeviceID, DWORD dwCallback,
679 DWORD dwInstance, DWORD fdwOpen)
681 HMIXER16 hmix16;
682 UINT ret;
684 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
685 lphmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
686 ret = mixerOpen16(&hmix16, uDeviceID, dwCallback, dwInstance,fdwOpen);
687 if (lphmix) *lphmix = hmix16;
688 return ret;
691 /**************************************************************************
692 * mixerOpen [MMSYSTEM.803]
694 UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback,
695 DWORD dwInstance, DWORD fdwOpen)
697 HMIXER16 hmix;
698 LPMIXEROPENDESC lpmod;
699 BOOL mapperflag = (uDeviceID == 0);
700 DWORD dwRet = 0;
702 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
703 lphmix, uDeviceID, dwCallback, dwInstance, fdwOpen);
704 hmix = USER_HEAP_ALLOC(sizeof(MIXEROPENDESC));
705 if (lphmix) *lphmix = hmix;
706 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
707 lpmod->hmx = hmix;
708 lpmod->dwCallback = dwCallback;
709 lpmod->dwInstance = dwInstance;
710 if (uDeviceID >= MAXMIXERDRIVERS)
711 uDeviceID = 0;
712 while (uDeviceID < MAXMIXERDRIVERS) {
713 dwRet = mixMessage(uDeviceID, MXDM_OPEN, dwInstance, (DWORD)lpmod, fdwOpen);
714 if (dwRet == MMSYSERR_NOERROR) break;
715 if (!mapperflag) break;
716 uDeviceID++;
718 lpmod->uDeviceID = uDeviceID;
720 if (dwRet != MMSYSERR_NOERROR) {
721 USER_HEAP_FREE(hmix);
722 if (lphmix) *lphmix = 0;
725 return dwRet;
728 /**************************************************************************
729 * mixerClose [WINMM.98]
731 UINT WINAPI mixerClose(HMIXER hmix)
733 LPMIXEROPENDESC lpmod;
734 DWORD dwRet;
736 TRACE("(%04x)\n", hmix);
738 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
739 if (lpmod == NULL) return MMSYSERR_INVALHANDLE;
740 dwRet = mixMessage(lpmod->uDeviceID, MXDM_CLOSE, lpmod->dwInstance, 0L, 0L);
741 USER_HEAP_FREE(hmix);
742 return dwRet;
745 /**************************************************************************
746 * mixerClose [MMSYSTEM.803]
748 UINT16 WINAPI mixerClose16(HMIXER16 hmix)
750 return mixerClose(hmix);
753 /**************************************************************************
754 * mixerGetID [WINMM.103]
756 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
758 FIXME("(%04x %p %08lx): semi-stub\n", hmix, lpid, fdwID);
760 if (lpid)
761 *lpid = MIXER_GetDevID(hmix, fdwID);
763 return MMSYSERR_NOERROR; /* FIXME: many error possibilities */
766 /**************************************************************************
767 * mixerGetID
769 UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID)
771 UINT xid;
772 UINT ret = mixerGetID(hmix, &xid, fdwID);
774 if (lpid)
775 *lpid = xid;
776 return ret;
779 /**************************************************************************
780 * mixerGetControlDetailsA [WINMM.99]
782 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, DWORD fdwDetails)
784 UINT uDevID;
786 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
788 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
789 return MMSYSERR_INVALPARAM;
791 uDevID = MIXER_GetDevID(hmix, fdwDetails);
793 return mixMessage(uDevID, MXDM_GETCONTROLDETAILS, 0, (DWORD)lpmcdA, fdwDetails);
796 /**************************************************************************
797 * mixerGetControlDetailsW [WINMM.100]
799 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
801 DWORD ret = MMSYSERR_NOTENABLED;
803 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
805 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
806 return MMSYSERR_INVALPARAM;
808 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
809 case MIXER_GETCONTROLDETAILSF_VALUE:
810 /* can savely use W structure as it is, no string inside */
811 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
812 break;
813 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
815 LPVOID paDetailsW = lpmcd->paDetails;
816 int size = MAX(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
818 if (lpmcd->u.cMultipleItems != 0 && lpmcd->u.cMultipleItems != lpmcd->u.hwndOwner) {
819 size *= lpmcd->u.cMultipleItems;
821 lpmcd->paDetails = HeapAlloc(GetProcessHeap(), 0, size);
822 /* set up lpmcd->paDetails */
823 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
824 /* copy from lpmcd->paDetails back to paDetailsW; */
825 HeapFree(GetProcessHeap(), 0, lpmcd->paDetails);
826 lpmcd->paDetails = paDetailsW;
828 break;
829 default:
830 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
833 return ret;
836 /**************************************************************************
837 * mixerGetControlDetails [MMSYSTEM.808]
839 UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails)
841 DWORD ret = MMSYSERR_NOTENABLED;
842 SEGPTR sppaDetails;
844 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
846 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
847 return MMSYSERR_INVALPARAM;
849 sppaDetails = (SEGPTR)lpmcd->paDetails;
850 lpmcd->paDetails = PTR_SEG_TO_LIN(sppaDetails);
851 ret = mixerGetControlDetailsA(hmix, (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails);
852 lpmcd->paDetails = (LPVOID)sppaDetails;
854 return ret;
857 /**************************************************************************
858 * mixerGetLineControlsA [WINMM.104]
860 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA, DWORD fdwControls)
862 UINT uDevID;
864 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
866 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
867 return MMSYSERR_INVALPARAM;
869 uDevID = MIXER_GetDevID(hmix, 0);
871 return mixMessage(uDevID, MXDM_GETLINECONTROLS, 0, (DWORD)lpmlcA, fdwControls);
874 /**************************************************************************
875 * mixerGetLineControlsW [WINMM.105]
877 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, DWORD fdwControls)
879 MIXERLINECONTROLSA mlcA;
880 DWORD ret;
881 int i;
883 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
885 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) || lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
886 return MMSYSERR_INVALPARAM;
888 mlcA.cbStruct = sizeof(mlcA);
889 mlcA.dwLineID = lpmlcW->dwLineID;
890 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
891 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
892 mlcA.cControls = lpmlcW->cControls;
893 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
894 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0, mlcA.cControls * mlcA.cbmxctrl);
896 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
898 if (ret == MMSYSERR_NOERROR) {
899 lpmlcW->dwLineID = mlcA.dwLineID;
900 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
901 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
902 lpmlcW->cControls = mlcA.cControls;
904 for (i = 0; i < mlcA.cControls; i++) {
905 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
906 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
907 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
908 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
909 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
910 lstrcpyAtoW(lpmlcW->pamxctrl[i].szShortName, mlcA.pamxctrl[i].szShortName);
911 lstrcpyAtoW(lpmlcW->pamxctrl[i].szName, mlcA.pamxctrl[i].szName);
912 /* sizeof(lpmlcW->pamxctrl[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
913 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds, sizeof(mlcA.pamxctrl[i].Bounds));
914 /* sizeof(lpmlcW->pamxctrl[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
915 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics, sizeof(mlcA.pamxctrl[i].Metrics));
919 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
921 return ret;
924 /**************************************************************************
925 * mixerGetLineControls [MMSYSTEM.807]
927 UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix, LPMIXERLINECONTROLS16 lpmlc16, DWORD fdwControls)
929 MIXERLINECONTROLSA mlcA;
930 DWORD ret;
931 int i;
932 LPMIXERCONTROL16 lpmc16;
934 TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls);
936 if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) || lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16))
937 return MMSYSERR_INVALPARAM;
939 mlcA.cbStruct = sizeof(mlcA);
940 mlcA.dwLineID = lpmlc16->dwLineID;
941 mlcA.u.dwControlID = lpmlc16->u.dwControlID;
942 mlcA.u.dwControlType = lpmlc16->u.dwControlType;
943 mlcA.cControls = lpmlc16->cControls;
944 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
945 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0, mlcA.cControls * mlcA.cbmxctrl);
947 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
949 if (ret == MMSYSERR_NOERROR) {
950 lpmlc16->dwLineID = mlcA.dwLineID;
951 lpmlc16->u.dwControlID = mlcA.u.dwControlID;
952 lpmlc16->u.dwControlType = mlcA.u.dwControlType;
953 lpmlc16->cControls = mlcA.cControls;
955 lpmc16 = PTR_SEG_TO_LIN(lpmlc16->pamxctrl);
957 for (i = 0; i < mlcA.cControls; i++) {
958 lpmc16[i].cbStruct = sizeof(MIXERCONTROL16);
959 lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
960 lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
961 lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
962 lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
963 strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName);
964 strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName);
965 /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */
966 memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds, sizeof(mlcA.pamxctrl[i].Bounds));
967 /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */
968 memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics, sizeof(mlcA.pamxctrl[i].Metrics));
972 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
974 return ret;
977 /**************************************************************************
978 * mixerGetLineInfoA [WINMM.106]
980 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
982 UINT16 devid;
984 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
986 /* FIXME: I'm not sure of the flags */
987 devid = MIXER_GetDevID(hmix, fdwInfo);
988 return mixMessage(devid, MXDM_GETLINEINFO, 0, (DWORD)lpmliW, fdwInfo);
991 /**************************************************************************
992 * mixerGetLineInfoW [WINMM.107]
994 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo)
996 MIXERLINEA mliA;
997 UINT ret;
999 TRACE("(%04x, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
1001 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
1002 return MMSYSERR_INVALPARAM;
1004 mliA.cbStruct = sizeof(mliA);
1005 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1006 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1007 mliA.dwComponentType = lpmliW->dwComponentType;
1008 break;
1009 case MIXER_GETLINEINFOF_DESTINATION:
1010 mliA.dwDestination = lpmliW->dwDestination;
1011 break;
1012 case MIXER_GETLINEINFOF_LINEID:
1013 mliA.dwLineID = lpmliW->dwLineID;
1014 break;
1015 case MIXER_GETLINEINFOF_SOURCE:
1016 mliA.dwDestination = lpmliW->dwDestination;
1017 mliA.dwSource = lpmliW->dwSource;
1018 break;
1019 case MIXER_GETLINEINFOF_TARGETTYPE:
1020 mliA.Target.dwType = lpmliW->Target.dwType;
1021 mliA.Target.wMid = lpmliW->Target.wMid;
1022 mliA.Target.wPid = lpmliW->Target.wPid;
1023 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
1024 lstrcpyWtoA(mliA.Target.szPname, lpmliW->Target.szPname);
1025 break;
1026 default:
1027 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1030 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1032 lpmliW->dwDestination = mliA.dwDestination;
1033 lpmliW->dwSource = mliA.dwSource;
1034 lpmliW->dwLineID = mliA.dwLineID;
1035 lpmliW->fdwLine = mliA.fdwLine;
1036 lpmliW->dwUser = mliA.dwUser;
1037 lpmliW->dwComponentType = mliA.dwComponentType;
1038 lpmliW->cChannels = mliA.cChannels;
1039 lpmliW->cConnections = mliA.cConnections;
1040 lpmliW->cControls = mliA.cControls;
1041 lstrcpyAtoW(lpmliW->szShortName, mliA.szShortName);
1042 lstrcpyAtoW(lpmliW->szName, mliA.szName);
1043 lpmliW->Target.dwType = mliA.Target.dwType;
1044 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
1045 lpmliW->Target.wMid = mliA.Target.wMid;
1046 lpmliW->Target.wPid = mliA.Target.wPid;
1047 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
1048 lstrcpyAtoW(lpmliW->Target.szPname, mliA.Target.szPname);
1050 return ret;
1053 /**************************************************************************
1054 * mixerGetLineInfo [MMSYSTEM.805]
1056 UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16, DWORD fdwInfo)
1058 MIXERLINEA mliA;
1059 UINT ret;
1061 TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo);
1063 if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16))
1064 return MMSYSERR_INVALPARAM;
1066 mliA.cbStruct = sizeof(mliA);
1067 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1068 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1069 mliA.dwComponentType = lpmli16->dwComponentType;
1070 break;
1071 case MIXER_GETLINEINFOF_DESTINATION:
1072 mliA.dwDestination = lpmli16->dwDestination;
1073 break;
1074 case MIXER_GETLINEINFOF_LINEID:
1075 mliA.dwLineID = lpmli16->dwLineID;
1076 break;
1077 case MIXER_GETLINEINFOF_SOURCE:
1078 mliA.dwDestination = lpmli16->dwDestination;
1079 mliA.dwSource = lpmli16->dwSource;
1080 break;
1081 case MIXER_GETLINEINFOF_TARGETTYPE:
1082 mliA.Target.dwType = lpmli16->Target.dwType;
1083 mliA.Target.wMid = lpmli16->Target.wMid;
1084 mliA.Target.wPid = lpmli16->Target.wPid;
1085 mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion;
1086 strcpy(mliA.Target.szPname, lpmli16->Target.szPname);
1087 break;
1088 default:
1089 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
1092 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
1094 lpmli16->dwDestination = mliA.dwDestination;
1095 lpmli16->dwSource = mliA.dwSource;
1096 lpmli16->dwLineID = mliA.dwLineID;
1097 lpmli16->fdwLine = mliA.fdwLine;
1098 lpmli16->dwUser = mliA.dwUser;
1099 lpmli16->dwComponentType = mliA.dwComponentType;
1100 lpmli16->cChannels = mliA.cChannels;
1101 lpmli16->cConnections = mliA.cConnections;
1102 lpmli16->cControls = mliA.cControls;
1103 strcpy(lpmli16->szShortName, mliA.szShortName);
1104 strcpy(lpmli16->szName, mliA.szName);
1105 lpmli16->Target.dwType = mliA.Target.dwType;
1106 lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID;
1107 lpmli16->Target.wMid = mliA.Target.wMid;
1108 lpmli16->Target.wPid = mliA.Target.wPid;
1109 lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion;
1110 strcpy(lpmli16->Target.szPname, mliA.Target.szPname);
1112 return ret;
1115 /**************************************************************************
1116 * mixerSetControlDetails [WINMM.111]
1118 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, DWORD fdwDetails)
1120 UINT uDevID;
1122 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
1124 uDevID = MIXER_GetDevID(hmix, fdwDetails);
1126 return mixMessage(uDevID, MXDM_SETCONTROLDETAILS, 0, (DWORD)lpmcdA, fdwDetails);
1129 /**************************************************************************
1130 * mixerSetControlDetails [MMSYSTEM.809]
1132 UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix, LPMIXERCONTROLDETAILS16 lpmcd, DWORD fdwDetails)
1134 TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
1135 return MMSYSERR_NOTENABLED;
1138 /**************************************************************************
1139 * mixerMessage [WINMM.109]
1141 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
1143 LPMIXEROPENDESC lpmod;
1144 UINT16 uDeviceID;
1146 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
1147 if (lpmod)
1148 uDeviceID = lpmod->uDeviceID;
1149 else
1150 uDeviceID = 0;
1151 FIXME("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
1152 (DWORD)hmix, uMsg, dwParam1, dwParam2);
1153 return mixMessage(uDeviceID, uMsg, 0L, dwParam1, dwParam2);
1156 /**************************************************************************
1157 * mixerMessage [MMSYSTEM.804]
1159 UINT16 WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1, DWORD dwParam2)
1161 LPMIXEROPENDESC lpmod;
1162 UINT16 uDeviceID;
1164 lpmod = (LPMIXEROPENDESC)USER_HEAP_LIN_ADDR(hmix);
1165 uDeviceID = (lpmod) ? lpmod->uDeviceID : 0;
1166 FIXME("(%04x, %d, %08lx, %08lx) - semi-stub?\n",
1167 hmix, uMsg, dwParam1, dwParam2);
1168 return mixMessage(uDeviceID, uMsg, 0L, dwParam1, dwParam2);
1171 /**************************************************************************
1172 * auxGetNumDevs [WINMM.22]
1174 UINT WINAPI auxGetNumDevs()
1176 return auxGetNumDevs16();
1179 /**************************************************************************
1180 * auxGetNumDevs [MMSYSTEM.350]
1182 UINT16 WINAPI auxGetNumDevs16()
1184 UINT16 count;
1186 TRACE("\n");
1187 count = auxMessage(0, AUXDM_GETNUMDEVS, 0L, 0L, 0L);
1188 TRACE("=> %u\n", count);
1189 return count;
1192 /**************************************************************************
1193 * auxGetDevCaps [WINMM.20]
1195 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
1197 AUXCAPS16 ac16;
1198 UINT ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
1200 lpCaps->wMid = ac16.wMid;
1201 lpCaps->wPid = ac16.wPid;
1202 lpCaps->vDriverVersion = ac16.vDriverVersion;
1203 lstrcpyAtoW(lpCaps->szPname, ac16.szPname);
1204 lpCaps->wTechnology = ac16.wTechnology;
1205 lpCaps->dwSupport = ac16.dwSupport;
1206 return ret;
1209 /**************************************************************************
1210 * auxGetDevCaps [WINMM.21]
1212 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
1214 AUXCAPS16 ac16;
1215 UINT ret = auxGetDevCaps16(uDeviceID, &ac16, sizeof(ac16));
1217 lpCaps->wMid = ac16.wMid;
1218 lpCaps->wPid = ac16.wPid;
1219 lpCaps->vDriverVersion = ac16.vDriverVersion;
1220 strcpy(lpCaps->szPname, ac16.szPname);
1221 lpCaps->wTechnology = ac16.wTechnology;
1222 lpCaps->dwSupport = ac16.dwSupport;
1223 return ret;
1226 /**************************************************************************
1227 * auxGetDevCaps [MMSYSTEM.351]
1229 UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize)
1231 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
1233 return auxMessage(uDeviceID, AUXDM_GETDEVCAPS,
1234 0L, (DWORD)lpCaps, (DWORD)uSize);
1237 /**************************************************************************
1238 * auxGetVolume [WINM.23]
1240 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
1242 return auxGetVolume16(uDeviceID, lpdwVolume);
1245 /**************************************************************************
1246 * auxGetVolume [MMSYSTEM.352]
1248 UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
1250 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
1252 return auxMessage(uDeviceID, AUXDM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
1255 /**************************************************************************
1256 * auxSetVolume [WINMM.25]
1258 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
1260 return auxSetVolume16(uDeviceID, dwVolume);
1263 /**************************************************************************
1264 * auxSetVolume [MMSYSTEM.353]
1266 UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
1268 TRACE("(%04X, %08lX) !\n", uDeviceID, dwVolume);
1270 return auxMessage(uDeviceID, AUXDM_SETVOLUME, 0L, dwVolume, 0L);
1273 /**************************************************************************
1274 * auxOutMessage [MMSYSTEM.354]
1276 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
1278 switch (uMessage) {
1279 case AUXDM_GETNUMDEVS:
1280 case AUXDM_GETVOLUME:
1281 case AUXDM_SETVOLUME:
1282 /* no argument conversion needed */
1283 break;
1284 case AUXDM_GETDEVCAPS:
1285 return auxGetDevCapsA(uDeviceID, (LPAUXCAPSA)dw1, dw2);
1286 default:
1287 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1288 uDeviceID, uMessage, dw1, dw2);
1289 break;
1291 return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
1294 /**************************************************************************
1295 * auxOutMessage [MMSYSTEM.354]
1297 DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2)
1299 TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2);
1301 switch (uMessage) {
1302 case AUXDM_GETNUMDEVS:
1303 case AUXDM_SETVOLUME:
1304 /* no argument conversion needed */
1305 break;
1306 case AUXDM_GETVOLUME:
1307 return auxGetVolume16(uDeviceID, (LPDWORD)PTR_SEG_TO_LIN(dw1));
1308 case AUXDM_GETDEVCAPS:
1309 return auxGetDevCaps16(uDeviceID, (LPAUXCAPS16)PTR_SEG_TO_LIN(dw1), dw2);
1310 default:
1311 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
1312 uDeviceID, uMessage, dw1, dw2);
1313 break;
1315 return auxMessage(uDeviceID, uMessage, 0L, dw1, dw2);
1318 /**************************************************************************
1319 * mciGetErrorStringW [WINMM.46]
1321 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
1323 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
1324 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
1326 lstrcpyAtoW(lpstrBuffer, bufstr);
1327 HeapFree(GetProcessHeap(), 0, bufstr);
1328 return ret;
1331 /**************************************************************************
1332 * mciGetErrorStringA [WINMM.45]
1334 BOOL WINAPI mciGetErrorStringA(DWORD wError, LPSTR lpstrBuffer, UINT uLength)
1336 return mciGetErrorString16(wError, lpstrBuffer, uLength);
1339 /**************************************************************************
1340 * mciGetErrorString [MMSYSTEM.706]
1342 BOOL16 WINAPI mciGetErrorString16(DWORD dwError, LPSTR lpstrBuffer, UINT16 uLength)
1344 LPSTR msgptr = NULL;
1346 TRACE("(%08lX, %p, %d);\n", dwError, lpstrBuffer, uLength);
1348 if ((lpstrBuffer == NULL) || (uLength < 1))
1349 return FALSE;
1351 lpstrBuffer[0] = '\0';
1353 switch (dwError) {
1354 case 0:
1355 msgptr = "The specified command has been executed.";
1356 break;
1357 case MCIERR_INVALID_DEVICE_ID:
1358 msgptr = "Invalid MCI device ID. Use the ID returned when opening the MCI device.";
1359 break;
1360 case MCIERR_UNRECOGNIZED_KEYWORD:
1361 msgptr = "The driver cannot recognize the specified command parameter.";
1362 break;
1363 case MCIERR_UNRECOGNIZED_COMMAND:
1364 msgptr = "The driver cannot recognize the specified command.";
1365 break;
1366 case MCIERR_HARDWARE:
1367 msgptr = "There is a problem with your media device. Make sure it is working correctly or contact the device manufacturer.";
1368 break;
1369 case MCIERR_INVALID_DEVICE_NAME:
1370 msgptr = "The specified device is not open or is not recognized by MCI.";
1371 break;
1372 case MCIERR_OUT_OF_MEMORY:
1373 msgptr = "Not enough memory available for this task. \nQuit one or more applications to increase available memory, and then try again.";
1374 break;
1375 case MCIERR_DEVICE_OPEN:
1376 msgptr = "The device name is already being used as an alias by this application. Use a unique alias.";
1377 break;
1378 case MCIERR_CANNOT_LOAD_DRIVER:
1379 msgptr = "There is an undetectable problem in loading the specified device driver.";
1380 break;
1381 case MCIERR_MISSING_COMMAND_STRING:
1382 msgptr = "No command was specified.";
1383 break;
1384 case MCIERR_PARAM_OVERFLOW:
1385 msgptr = "The output string was to large to fit in the return buffer. Increase the size of the buffer.";
1386 break;
1387 case MCIERR_MISSING_STRING_ARGUMENT:
1388 msgptr = "The specified command requires a character-string parameter. Please provide one.";
1389 break;
1390 case MCIERR_BAD_INTEGER:
1391 msgptr = "The specified integer is invalid for this command.";
1392 break;
1393 case MCIERR_PARSER_INTERNAL:
1394 msgptr = "The device driver returned an invalid return type. Check with the device manufacturer about obtaining a new driver.";
1395 break;
1396 case MCIERR_DRIVER_INTERNAL:
1397 msgptr = "There is a problem with the device driver. Check with the device manufacturer about obtaining a new driver.";
1398 break;
1399 case MCIERR_MISSING_PARAMETER:
1400 msgptr = "The specified command requires a parameter. Please supply one.";
1401 break;
1402 case MCIERR_UNSUPPORTED_FUNCTION:
1403 msgptr = "The MCI device you are using does not support the specified command.";
1404 break;
1405 case MCIERR_FILE_NOT_FOUND:
1406 msgptr = "Cannot find the specified file. Make sure the path and filename are correct.";
1407 break;
1408 case MCIERR_DEVICE_NOT_READY:
1409 msgptr = "The device driver is not ready.";
1410 break;
1411 case MCIERR_INTERNAL:
1412 msgptr = "A problem occurred in initializing MCI. Try restarting Windows.";
1413 break;
1414 case MCIERR_DRIVER:
1415 msgptr = "There is a problem with the device driver. The driver has closed. Cannot access error.";
1416 break;
1417 case MCIERR_CANNOT_USE_ALL:
1418 msgptr = "Cannot use 'all' as the device name with the specified command.";
1419 break;
1420 case MCIERR_MULTIPLE:
1421 msgptr = "Errors occurred in more than one device. Specify each command and device separately to determine which devices caused the error";
1422 break;
1423 case MCIERR_EXTENSION_NOT_FOUND:
1424 msgptr = "Cannot determine the device type from the given filename extension.";
1425 break;
1426 case MCIERR_OUTOFRANGE:
1427 msgptr = "The specified parameter is out of range for the specified command.";
1428 break;
1429 case MCIERR_FLAGS_NOT_COMPATIBLE:
1430 msgptr = "The specified parameters cannot be used together.";
1431 break;
1432 case MCIERR_FILE_NOT_SAVED:
1433 msgptr = "Cannot save the specified file. Make sure you have enough disk space or are still connected to the network.";
1434 break;
1435 case MCIERR_DEVICE_TYPE_REQUIRED:
1436 msgptr = "Cannot find the specified device. Make sure it is installed or that the device name is spelled correctly.";
1437 break;
1438 case MCIERR_DEVICE_LOCKED:
1439 msgptr = "The specified device is now being closed. Wait a few seconds, and then try again.";
1440 break;
1441 case MCIERR_DUPLICATE_ALIAS:
1442 msgptr = "The specified alias is already being used in this application. Use a unique alias.";
1443 break;
1444 case MCIERR_BAD_CONSTANT:
1445 msgptr = "The specified parameter is invalid for this command.";
1446 break;
1447 case MCIERR_MUST_USE_SHAREABLE:
1448 msgptr = "The device driver is already in use. To share it, use the 'shareable' parameter with each 'open' command.";
1449 break;
1450 case MCIERR_MISSING_DEVICE_NAME:
1451 msgptr = "The specified command requires an alias, file, driver, or device name. Please supply one.";
1452 break;
1453 case MCIERR_BAD_TIME_FORMAT:
1454 msgptr = "The specified value for the time format is invalid. Refer to the MCI documentation for valid formats.";
1455 break;
1456 case MCIERR_NO_CLOSING_QUOTE:
1457 msgptr = "A closing double-quotation mark is missing from the parameter value. Please supply one.";
1458 break;
1459 case MCIERR_DUPLICATE_FLAGS:
1460 msgptr = "A parameter or value was specified twice. Only specify it once.";
1461 break;
1462 case MCIERR_INVALID_FILE:
1463 msgptr = "The specified file cannot be played on the specified MCI device. The file may be corrupt, or not in the correct format.";
1464 break;
1465 case MCIERR_NULL_PARAMETER_BLOCK:
1466 msgptr = "A null parameter block was passed to MCI.";
1467 break;
1468 case MCIERR_UNNAMED_RESOURCE:
1469 msgptr = "Cannot save an unnamed file. Supply a filename.";
1470 break;
1471 case MCIERR_NEW_REQUIRES_ALIAS:
1472 msgptr = "You must specify an alias when using the 'new' parameter.";
1473 break;
1474 case MCIERR_NOTIFY_ON_AUTO_OPEN:
1475 msgptr = "Cannot use the 'notify' flag with auto-opened devices.";
1476 break;
1477 case MCIERR_NO_ELEMENT_ALLOWED:
1478 msgptr = "Cannot use a filename with the specified device.";
1479 break;
1480 case MCIERR_NONAPPLICABLE_FUNCTION:
1481 msgptr = "Cannot carry out the commands in the order specified. Correct the command sequence, and then try again.";
1482 break;
1483 case MCIERR_ILLEGAL_FOR_AUTO_OPEN:
1484 msgptr = "Cannot carry out the specified command on an auto-opened device. Wait until the device is closed, and then try again.";
1485 break;
1486 case MCIERR_FILENAME_REQUIRED:
1487 msgptr = "The filename is invalid. Make sure the filename is not longer than 8 characters, followed by a period and an extension.";
1488 break;
1489 case MCIERR_EXTRA_CHARACTERS:
1490 msgptr = "Cannot specify extra characters after a string enclosed in quotation marks.";
1491 break;
1492 case MCIERR_DEVICE_NOT_INSTALLED:
1493 msgptr = "The specified device is not installed on the system. Use the Drivers option in Control Panel to install the device.";
1494 break;
1495 case MCIERR_GET_CD:
1496 msgptr = "Cannot access the specified file or MCI device. Try changing directories or restarting your computer.";
1497 break;
1498 case MCIERR_SET_CD:
1499 msgptr = "Cannot access the specified file or MCI device because the application cannot change directories.";
1500 break;
1501 case MCIERR_SET_DRIVE:
1502 msgptr = "Cannot access specified file or MCI device because the application cannot change drives.";
1503 break;
1504 case MCIERR_DEVICE_LENGTH:
1505 msgptr = "Specify a device or driver name that is less than 79 characters.";
1506 break;
1507 case MCIERR_DEVICE_ORD_LENGTH:
1508 msgptr = "Specify a device or driver name that is less than 69 characters.";
1509 break;
1510 case MCIERR_NO_INTEGER:
1511 msgptr = "The specified command requires an integer parameter. Please provide one.";
1512 break;
1513 case MCIERR_WAVE_OUTPUTSINUSE:
1514 msgptr = "All wave devices that can play files in the current format are in use. Wait until a wave device is free, and then try again.";
1515 break;
1516 case MCIERR_WAVE_SETOUTPUTINUSE:
1517 msgptr = "Cannot set the current wave device for play back because it is in use. Wait until the device is free, and then try again.";
1518 break;
1519 case MCIERR_WAVE_INPUTSINUSE:
1520 msgptr = "All wave devices that can record files in the current format are in use. Wait until a wave device is free, and then try again.";
1521 break;
1522 case MCIERR_WAVE_SETINPUTINUSE:
1523 msgptr = "Cannot set the current wave device for recording because it is in use. Wait until the device is free, and then try again.";
1524 break;
1525 case MCIERR_WAVE_OUTPUTUNSPECIFIED:
1526 msgptr = "Any compatible waveform playback device may be used.";
1527 break;
1528 case MCIERR_WAVE_INPUTUNSPECIFIED:
1529 msgptr = "Any compatible waveform recording device may be used.";
1530 break;
1531 case MCIERR_WAVE_OUTPUTSUNSUITABLE:
1532 msgptr = "No wave device that can play files in the current format is installed. Use the Drivers option to install the wave device.";
1533 break;
1534 case MCIERR_WAVE_SETOUTPUTUNSUITABLE:
1535 msgptr = "The device you are trying to play to cannot recognize the current file format.";
1536 break;
1537 case MCIERR_WAVE_INPUTSUNSUITABLE:
1538 msgptr = "No wave device that can record files in the current format is installed. Use the Drivers option to install the wave device.";
1539 break;
1540 case MCIERR_WAVE_SETINPUTUNSUITABLE:
1541 msgptr = "The device you are trying to record from cannot recognize the current file format.";
1542 break;
1543 case MCIERR_NO_WINDOW:
1544 msgptr = "There is no display window.";
1545 break;
1546 case MCIERR_CREATEWINDOW:
1547 msgptr = "Could not create or use window.";
1548 break;
1549 case MCIERR_FILE_READ:
1550 msgptr = "Cannot read the specified file. Make sure the file is still present, or check your disk or network connection.";
1551 break;
1552 case MCIERR_FILE_WRITE:
1553 msgptr = "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network.";
1554 break;
1555 case MCIERR_SEQ_DIV_INCOMPATIBLE:
1556 msgptr = "The time formats of the \"song pointer\" and SMPTE are mutually exclusive. You can't use them together.";
1557 break;
1558 case MCIERR_SEQ_NOMIDIPRESENT:
1559 msgptr = "The system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver.";
1560 break;
1561 case MCIERR_SEQ_PORT_INUSE:
1562 msgptr = "The specified MIDI port is already in use. Wait until it is free; the try again.";
1563 break;
1564 case MCIERR_SEQ_PORT_MAPNODEVICE:
1565 msgptr = "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use the MIDI Mapper option from the Control Panel to edit the setup.";
1566 break;
1567 case MCIERR_SEQ_PORT_MISCERROR:
1568 msgptr = "An error occurred with the specified port.";
1569 break;
1570 case MCIERR_SEQ_PORT_NONEXISTENT:
1571 msgptr = "The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device.";
1572 break;
1573 case MCIERR_SEQ_PORTUNSPECIFIED:
1574 msgptr = "The system doesnot have a current MIDI port specified.";
1575 break;
1576 case MCIERR_SEQ_TIMER:
1577 msgptr = "All multimedia timers are being used by other applications. Quit one of these applications; then, try again.";
1578 break;
1581 msg# 513 : vcr
1582 msg# 514 : videodisc
1583 msg# 515 : overlay
1584 msg# 516 : cdaudio
1585 msg# 517 : dat
1586 msg# 518 : scanner
1587 msg# 519 : animation
1588 msg# 520 : digitalvideo
1589 msg# 521 : other
1590 msg# 522 : waveaudio
1591 msg# 523 : sequencer
1592 msg# 524 : not ready
1593 msg# 525 : stopped
1594 msg# 526 : playing
1595 msg# 527 : recording
1596 msg# 528 : seeking
1597 msg# 529 : paused
1598 msg# 530 : open
1599 msg# 531 : false
1600 msg# 532 : true
1601 msg# 533 : milliseconds
1602 msg# 534 : hms
1603 msg# 535 : msf
1604 msg# 536 : frames
1605 msg# 537 : smpte 24
1606 msg# 538 : smpte 25
1607 msg# 539 : smpte 30
1608 msg# 540 : smpte 30 drop
1609 msg# 541 : bytes
1610 msg# 542 : samples
1611 msg# 543 : tmsf
1613 default:
1614 TRACE("Unknown MCI Error %ld!\n", dwError);
1615 return FALSE;
1617 lstrcpynA(lpstrBuffer, msgptr, uLength);
1618 TRACE("msg = \"%s\";\n", lpstrBuffer);
1619 return TRUE;
1622 /**************************************************************************
1623 * mciDriverNotify [MMSYSTEM.711]
1625 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
1627 TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1629 if (!IsWindow(hWndCallBack)) {
1630 WARN("bad hWnd for call back (0x%04x)\n", hWndCallBack);
1631 return FALSE;
1633 TRACE("before PostMessage\n");
1634 Callout.PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1635 return TRUE;
1638 /**************************************************************************
1639 * mciDriverNotify [WINMM.36]
1641 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
1644 TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
1646 if (!IsWindow(hWndCallBack)) {
1647 WARN("bad hWnd for call back (0x%04x)\n", hWndCallBack);
1648 return FALSE;
1650 TRACE("before PostMessage\n");
1651 Callout.PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
1652 return TRUE;
1655 /**************************************************************************
1656 * mciGetDriverData [MMSYSTEM.708]
1658 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
1660 return mciGetDriverData(uDeviceID);
1663 /**************************************************************************
1664 * mciGetDriverData [WINMM.44]
1666 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
1668 TRACE("(%04x)\n", uDeviceID);
1669 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1670 WARN("Bad uDeviceID\n");
1671 return 0L;
1674 return MCI_GetDrv(uDeviceID)->dwPrivate;
1677 /**************************************************************************
1678 * mciSetDriverData [MMSYSTEM.707]
1680 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
1682 return mciSetDriverData(uDeviceID, data);
1685 /**************************************************************************
1686 * mciSetDriverData [WINMM.53]
1688 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
1690 TRACE("(%04x, %08lx)\n", uDeviceID, data);
1691 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1692 WARN("Bad uDeviceID\n");
1693 return FALSE;
1696 MCI_GetDrv(uDeviceID)->dwPrivate = data;
1697 return TRUE;
1700 /**************************************************************************
1701 * mciLoadCommandResource [MMSYSTEM.705]
1703 UINT16 WINAPI mciLoadCommandResource16(HANDLE16 hinst, LPCSTR resname, UINT16 type)
1705 char buf[200];
1706 OFSTRUCT ofs;
1707 HANDLE16 xhinst;
1708 HRSRC16 hrsrc;
1709 HGLOBAL16 hmem;
1710 LPSTR segstr;
1711 SEGPTR xmem;
1712 LPBYTE lmem;
1713 static UINT16 mcidevtype = 0;
1715 FIXME("(%04x, %s, %d): stub!\n", hinst, resname, type);
1716 if (!lstrcmpiA(resname, "core")) {
1717 FIXME("(...,\"core\",...), have to use internal tables... (not there yet)\n");
1718 return 0;
1720 return ++mcidevtype;
1721 /* if file exists "resname.mci", then load resource "resname" from it
1722 * otherwise directly from driver
1724 strcpy(buf,resname);
1725 strcat(buf, ".mci");
1726 if (OpenFile(buf, &ofs, OF_EXIST) != HFILE_ERROR) {
1727 xhinst = LoadLibrary16(buf);
1728 if (xhinst > 32)
1729 hinst = xhinst;
1730 } /* else use passed hinst */
1731 segstr = SEGPTR_STRDUP(resname);
1732 hrsrc = FindResource16(hinst, SEGPTR_GET(segstr), type);
1733 SEGPTR_FREE(segstr);
1734 if (!hrsrc) {
1735 WARN("no special commandlist found in resource\n");
1736 return MCI_NO_COMMAND_TABLE;
1738 hmem = LoadResource16(hinst, hrsrc);
1739 if (!hmem) {
1740 WARN("couldn't load resource??\n");
1741 return MCI_NO_COMMAND_TABLE;
1743 xmem = WIN16_LockResource16(hmem);
1744 if (!xmem) {
1745 WARN("couldn't lock resource??\n");
1746 FreeResource16(hmem);
1747 return MCI_NO_COMMAND_TABLE;
1749 lmem = PTR_SEG_TO_LIN(xmem);
1750 TRACE("first resource entry is %s\n", (char*)lmem);
1751 /* parse resource, register stuff, return unique id */
1752 return ++mcidevtype;
1755 /**************************************************************************
1756 * mciFreeCommandResource [MMSYSTEM.713]
1758 BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable)
1760 FIXME("(%04x) stub\n", uTable);
1761 return 0;
1764 /**************************************************************************
1765 * mciFreeCommandResource [WINMM.39]
1767 BOOL WINAPI mciFreeCommandResource(UINT uTable)
1769 FIXME("(%08x) stub\n", uTable);
1770 return 0;
1773 /**************************************************************************
1774 * mciLoadCommandResource [WINMM.48]
1776 UINT WINAPI mciLoadCommandResource(HANDLE hinst, LPCWSTR resname, UINT type)
1778 FIXME("(%04x, %s, %d): stub!\n", hinst, debugstr_w(resname), type);
1779 return 0;
1782 /**************************************************************************
1783 * mciSendCommandA [WINMM.49]
1785 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1787 DWORD dwRet;
1789 TRACE("(%08x, %s, %08lx, %08lx)\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1791 switch (wMsg) {
1792 case MCI_OPEN:
1793 dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1794 break;
1795 case MCI_CLOSE:
1796 dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1797 break;
1798 case MCI_SYSINFO:
1799 dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1800 break;
1801 case MCI_BREAK:
1802 dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2);
1803 break;
1804 /* FIXME: it seems that MCI_BREAK and MCI_SOUND need the same handling */
1805 default:
1806 if (wDevID == MCI_ALL_DEVICE_ID) {
1807 FIXME("unhandled MCI_ALL_DEVICE_ID\n");
1808 dwRet = MCIERR_CANNOT_USE_ALL;
1809 } else {
1810 dwRet = MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2);
1812 break;
1814 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, TRUE);
1815 TRACE("=> %08lx\n", dwRet);
1816 return dwRet;
1819 /**************************************************************************
1820 * mciSendCommandW [WINMM.50]
1822 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
1824 FIXME("(%08x, %s, %08lx, %08lx): stub\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1825 return MCIERR_UNSUPPORTED_FUNCTION;
1828 /**************************************************************************
1829 * mciSendCommand [MMSYSTEM.701]
1831 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1833 DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND;
1835 TRACE("(%04X, %s, %08lX, %08lX)\n",
1836 wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
1838 switch (wMsg) {
1839 case MCI_OPEN:
1840 switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1841 case MCI_MAP_OK:
1842 case MCI_MAP_OKMEM:
1843 dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
1844 MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1845 break;
1846 default: break; /* so that gcc does not bark */
1848 break;
1849 case MCI_CLOSE:
1850 if (wDevID == MCI_ALL_DEVICE_ID) {
1851 FIXME("unhandled MCI_ALL_DEVICE_ID\n");
1852 dwRet = MCIERR_CANNOT_USE_ALL;
1853 } else if (!MCI_DevIDValid(wDevID)) {
1854 dwRet = MCIERR_INVALID_DEVICE_ID;
1855 } else {
1856 switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
1857 case MCI_MAP_OK:
1858 case MCI_MAP_OKMEM:
1859 dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1860 MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
1861 break;
1862 default: break; /* so that gcc does not bark */
1865 break;
1866 case MCI_SYSINFO:
1867 switch (MCI_MapMsg16To32A(0, wDevID, &dwParam2)) {
1868 case MCI_MAP_OK:
1869 case MCI_MAP_OKMEM:
1870 dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
1871 MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
1872 break;
1873 default: break; /* so that gcc doesnot bark */
1875 break;
1876 case MCI_BREAK:
1877 switch (MCI_MapMsg16To32A(0, wDevID, &dwParam2)) {
1878 case MCI_MAP_OK:
1879 case MCI_MAP_OKMEM:
1880 dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2);
1881 MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
1882 break;
1883 default: break; /* so that gcc does not bark */
1885 break;
1887 /* FIXME: it seems that MCI_BREAK and MCI_SOUND need the same handling */
1888 default:
1889 if (wDevID == MCI_ALL_DEVICE_ID) {
1890 FIXME("unhandled MCI_ALL_DEVICE_ID\n");
1891 dwRet = MCIERR_CANNOT_USE_ALL;
1892 } else {
1893 dwRet = MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2);
1895 break;
1897 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
1898 TRACE("=> %ld\n", dwRet);
1899 return dwRet;
1902 /**************************************************************************
1903 * mciGetDeviceID [MMSYSTEM.703]
1905 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
1907 UINT16 wDevID;
1908 TRACE("(\"%s\")\n", lpstrName);
1910 if (!lpstrName)
1911 return 0;
1913 if (!lstrcmpiA(lpstrName, "ALL"))
1914 return MCI_ALL_DEVICE_ID;
1916 for (wDevID = MCI_FirstDevID(); MCI_DevIDValid(wDevID); wDevID = MCI_NextDevID(wDevID)) {
1917 if (MCI_GetDrv(wDevID)->modp.wType) {
1918 FIXME("This is wrong for compound devices\n");
1919 /* FIXME: for compound devices, lpstrName is matched against
1920 * the name of the file, not the name of the device...
1922 if (MCI_GetOpenDrv(wDevID)->lpstrDeviceType &&
1923 strcmp(MCI_GetOpenDrv(wDevID)->lpstrDeviceType, lpstrName) == 0)
1924 return wDevID;
1926 if (MCI_GetOpenDrv(wDevID)->lpstrAlias &&
1927 strcmp(MCI_GetOpenDrv(wDevID)->lpstrAlias, lpstrName) == 0)
1928 return wDevID;
1932 return 0;
1935 /**************************************************************************
1936 * mciGetDeviceIDA [WINMM.41]
1938 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1940 return mciGetDeviceID16(lpstrName);
1943 /**************************************************************************
1944 * mciGetDeviceIDW [WINMM.43]
1946 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1948 LPSTR lpstrName;
1949 UINT ret;
1951 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
1952 ret = mciGetDeviceID16(lpstrName);
1953 HeapFree(GetProcessHeap(), 0, lpstrName);
1954 return ret;
1957 /**************************************************************************
1958 * MCI_DefYieldProc [internal]
1960 UINT16 WINAPI MCI_DefYieldProc(UINT16 wDevID, DWORD data)
1962 INT16 ret;
1964 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1966 if ((HIWORD(data) != 0 && GetActiveWindow16() != HIWORD(data)) ||
1967 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1968 UserYield16();
1969 ret = 0;
1970 } else {
1971 MSG msg;
1973 msg.hwnd = HIWORD(data);
1974 while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1975 ret = 0xFFFF;
1977 return ret;
1980 /**************************************************************************
1981 * mciSetYieldProc [MMSYSTEM.714]
1983 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1985 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1987 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
1988 WARN("Bad uDeviceID\n");
1989 return FALSE;
1992 MCI_GetDrv(uDeviceID)->lpfnYieldProc = fpYieldProc;
1993 MCI_GetDrv(uDeviceID)->dwYieldData = dwYieldData;
1994 MCI_GetDrv(uDeviceID)->bIs32 = FALSE;
1996 return TRUE;
1999 /**************************************************************************
2000 * mciSetYieldProc [WINMM.54]
2002 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
2004 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
2006 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
2007 WARN("Bad uDeviceID\n");
2008 return FALSE;
2011 MCI_GetDrv(uDeviceID)->lpfnYieldProc = fpYieldProc;
2012 MCI_GetDrv(uDeviceID)->dwYieldData = dwYieldData;
2013 MCI_GetDrv(uDeviceID)->bIs32 = TRUE;
2015 return TRUE;
2018 /**************************************************************************
2019 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
2021 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
2023 FIXME("(%lu, %s) stub\n", dwElementID, lpstrType);
2024 return 0;
2027 /**************************************************************************
2028 * mciGetDeviceIDFromElementIDW [WINMM.42]
2030 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
2032 /* FIXME: that's rather strange, there is no
2033 * mciGetDeviceIDFromElementID32A in winmm.spec
2035 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
2036 return 0;
2039 /**************************************************************************
2040 * mciGetYieldProc [MMSYSTEM.716]
2042 YIELDPROC WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
2044 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
2046 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
2047 WARN("Bad uDeviceID\n");
2048 return NULL;
2050 if (!MCI_GetDrv(uDeviceID)->lpfnYieldProc) {
2051 WARN("No proc set\n");
2052 return NULL;
2054 if (MCI_GetDrv(uDeviceID)->bIs32) {
2055 WARN("Proc is 32 bit\n");
2056 return NULL;
2058 return MCI_GetDrv(uDeviceID)->lpfnYieldProc;
2061 /**************************************************************************
2062 * mciGetYieldProc [WINMM.47]
2064 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
2066 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
2068 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
2069 WARN("Bad uDeviceID\n");
2070 return NULL;
2072 if (!MCI_GetDrv(uDeviceID)->lpfnYieldProc) {
2073 WARN("No proc set\n");
2074 return NULL;
2076 if (!MCI_GetDrv(uDeviceID)->bIs32) {
2077 WARN("Proc is 32 bit\n");
2078 return NULL;
2080 return MCI_GetDrv(uDeviceID)->lpfnYieldProc;
2083 /**************************************************************************
2084 * mciGetCreatorTask [MMSYSTEM.717]
2086 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
2088 return mciGetCreatorTask(uDeviceID);
2091 /**************************************************************************
2092 * mciGetCreatorTask [WINMM.40]
2094 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
2096 HTASK ret;
2098 TRACE("(%u)\n", uDeviceID);
2100 ret = (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) ?
2101 0 : MCI_GetDrv(uDeviceID)->hCreatorTask;
2103 TRACE("=> %04x\n", ret);
2104 return ret;
2107 /**************************************************************************
2108 * mciDriverYield [MMSYSTEM.710]
2110 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
2112 UINT16 ret = 0;
2114 /* TRACE("(%04x)\n", uDeviceID); */
2116 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
2117 !MCI_GetDrv(uDeviceID)->lpfnYieldProc || MCI_GetDrv(uDeviceID)->bIs32) {
2118 UserYield16();
2119 } else {
2120 ret = MCI_GetDrv(uDeviceID)->lpfnYieldProc(uDeviceID, MCI_GetDrv(uDeviceID)->dwYieldData);
2123 return ret;
2126 /**************************************************************************
2127 * mciDriverYield [WINMM.37]
2129 UINT WINAPI mciDriverYield(UINT uDeviceID)
2131 UINT ret = 0;
2133 TRACE("(%04x)\n", uDeviceID);
2134 if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
2135 !MCI_GetDrv(uDeviceID)->lpfnYieldProc || !MCI_GetDrv(uDeviceID)->bIs32) {
2136 UserYield16();
2137 } else {
2138 ret = MCI_GetDrv(uDeviceID)->lpfnYieldProc(uDeviceID, MCI_GetDrv(uDeviceID)->dwYieldData);
2141 return ret;
2144 /**************************************************************************
2145 * midiOutGetNumDevs [WINMM.80]
2147 UINT WINAPI midiOutGetNumDevs(void)
2149 return midiOutGetNumDevs16();
2152 /**************************************************************************
2153 * midiOutGetNumDevs [MMSYSTEM.201]
2155 UINT16 WINAPI midiOutGetNumDevs16(void)
2157 UINT16 count = modMessage(0, MODM_GETNUMDEVS, 0L, 0L, 0L);
2159 TRACE("returns %u\n", count);
2160 return count;
2163 /**************************************************************************
2164 * midiOutGetDevCapsW [WINMM.76]
2166 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps, UINT uSize)
2168 MIDIOUTCAPS16 moc16;
2169 UINT ret;
2171 ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
2172 lpCaps->wMid = moc16.wMid;
2173 lpCaps->wPid = moc16.wPid;
2174 lpCaps->vDriverVersion = moc16.vDriverVersion;
2175 lstrcpyAtoW(lpCaps->szPname, moc16.szPname);
2176 lpCaps->wTechnology = moc16.wTechnology;
2177 lpCaps->wVoices = moc16.wVoices;
2178 lpCaps->wNotes = moc16.wNotes;
2179 lpCaps->wChannelMask = moc16.wChannelMask;
2180 lpCaps->dwSupport = moc16.dwSupport;
2181 return ret;
2184 /**************************************************************************
2185 * midiOutGetDevCapsA [WINMM.75]
2187 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps, UINT uSize)
2189 MIDIOUTCAPS16 moc16;
2190 UINT ret;
2192 ret = midiOutGetDevCaps16(uDeviceID, &moc16, sizeof(moc16));
2193 lpCaps->wMid = moc16.wMid;
2194 lpCaps->wPid = moc16.wPid;
2195 lpCaps->vDriverVersion = moc16.vDriverVersion;
2196 strcpy(lpCaps->szPname, moc16.szPname);
2197 lpCaps->wTechnology = moc16.wTechnology;
2198 lpCaps->wVoices = moc16.wVoices;
2199 lpCaps->wNotes = moc16.wNotes;
2200 lpCaps->wChannelMask = moc16.wChannelMask;
2201 lpCaps->dwSupport = moc16.dwSupport;
2202 return ret;
2205 /**************************************************************************
2206 * midiOutGetDevCaps [MMSYSTEM.202]
2208 UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps, UINT16 uSize)
2210 TRACE("midiOutGetDevCaps\n");
2211 return modMessage(uDeviceID, MODM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
2214 /**************************************************************************
2215 * midiOutGetErrorTextA [WINMM.77]
2217 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2219 TRACE("midiOutGetErrorText\n");
2220 return midiGetErrorText(uError, lpText, uSize);
2223 /**************************************************************************
2224 * midiOutGetErrorTextW [WINMM.78]
2226 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2228 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2229 UINT ret;
2231 TRACE("midiOutGetErrorText\n");
2232 ret = midiGetErrorText(uError, xstr, uSize);
2233 lstrcpyAtoW(lpText, xstr);
2234 HeapFree(GetProcessHeap(), 0, xstr);
2235 return ret;
2238 /**************************************************************************
2239 * midiOutGetErrorText [MMSYSTEM.203]
2241 UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2243 TRACE("midiOutGetErrorText\n");
2244 return midiGetErrorText(uError, lpText, uSize);
2247 /**************************************************************************
2248 * midiGetErrorText [internal]
2250 UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2252 LPSTR msgptr;
2253 if ((lpText == NULL) || (uSize < 1)) return(FALSE);
2254 lpText[0] = '\0';
2255 switch (uError) {
2256 case MIDIERR_UNPREPARED:
2257 msgptr = "The MIDI header was not prepared. Use the Prepare function to prepare the header, and then try again.";
2258 break;
2259 case MIDIERR_STILLPLAYING:
2260 msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
2261 break;
2262 case MIDIERR_NOMAP:
2263 msgptr = "A MIDI map was not found. There may be a problem with the driver, or the MIDIMAP.CFG file may be corrupt or missing.";
2264 break;
2265 case MIDIERR_NOTREADY:
2266 msgptr = "The port is transmitting data to the device. Wait until the data has been transmitted, and then try again.";
2267 break;
2268 case MIDIERR_NODEVICE:
2269 msgptr = "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup.";
2270 break;
2271 case MIDIERR_INVALIDSETUP:
2272 msgptr = "The current MIDI setup is damaged. Copy the original MIDIMAP.CFG file to the Windows SYSTEM directory, and then try again.";
2273 break;
2275 msg# 336 : Cannot use the song-pointer time format and the SMPTE time-format together.
2276 msg# 337 : The specified MIDI device is already in use. Wait until it is free, and then try again.
2277 msg# 338 : The specified MIDI device is not installed on the system. Use the Drivers option in Control Panel to install the driver.
2278 msg# 339 : The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup.
2279 msg# 340 : An error occurred using the specified port.
2280 msg# 341 : All multimedia timers are being used by other applications. Quit one of these applications, and then try again.
2281 msg# 342 : There is no current MIDI port.
2282 msg# 343 : There are no MIDI devices installed on the system. Use the Drivers option in Control Panel to install the driver.
2284 default:
2285 msgptr = "Unknown MIDI Error !\n";
2286 break;
2288 lstrcpynA(lpText, msgptr, uSize);
2289 return TRUE;
2292 static LPMIDIOPENDESC MIDI_OutAlloc(HMIDIOUT16* lphMidiOut, DWORD dwCallback,
2293 DWORD dwInstance, DWORD cIDs, MIDIOPENSTRMID* lpIDs)
2295 HMIDI16 hMidiOut;
2296 LPMIDIOPENDESC lpDesc;
2298 hMidiOut = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC) + (cIDs ? (cIDs - 1) : 0) * sizeof(MIDIOPENSTRMID));
2300 if (lphMidiOut != NULL)
2301 *lphMidiOut = hMidiOut;
2302 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2304 if (lpDesc) {
2305 lpDesc->hMidi = hMidiOut;
2306 lpDesc->dwCallback = dwCallback;
2307 lpDesc->dwInstance = dwInstance;
2308 lpDesc->dnDevNode = 0;
2309 lpDesc->cIds = cIDs;
2310 if (cIDs)
2311 memcpy(&(lpDesc->rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
2313 return lpDesc;
2316 /**************************************************************************
2317 * midiOutOpen [WINM.84]
2319 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
2320 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2322 HMIDIOUT16 hmo16;
2323 UINT ret;
2325 ret = midiOutOpen16(&hmo16, uDeviceID, dwCallback, dwInstance,
2326 CALLBACK32CONV(dwFlags));
2327 if (lphMidiOut) *lphMidiOut = hmo16;
2328 return ret;
2331 /**************************************************************************
2332 * midiOutOpen [MMSYSTEM.204]
2334 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
2335 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2337 HMIDIOUT16 hMidiOut;
2338 LPMIDIOPENDESC lpDesc;
2339 UINT16 ret = 0;
2340 BOOL bMapperFlg = FALSE;
2342 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2343 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
2345 if (lphMidiOut != NULL) *lphMidiOut = 0;
2347 if (uDeviceID == (UINT16)MIDI_MAPPER) {
2348 TRACE("MIDI_MAPPER mode requested !\n");
2349 bMapperFlg = TRUE;
2350 uDeviceID = 0;
2353 lpDesc = MIDI_OutAlloc(&hMidiOut, dwCallback, dwInstance, 0, NULL);
2355 if (lpDesc == NULL)
2356 return MMSYSERR_NOMEM;
2358 while (uDeviceID < MAXMIDIDRIVERS) {
2359 ret = modMessage(uDeviceID, MODM_OPEN,
2360 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2361 if (ret == MMSYSERR_NOERROR) break;
2362 if (!bMapperFlg) break;
2363 uDeviceID++;
2364 TRACE("MIDI_MAPPER mode ! try next driver...\n");
2366 TRACE("=> wDevID=%u (%d)\n", uDeviceID, ret);
2367 if (ret != MMSYSERR_NOERROR) {
2368 USER_HEAP_FREE(hMidiOut);
2369 if (lphMidiOut) *lphMidiOut = 0;
2370 } else {
2371 lpDesc->wDevID = uDeviceID;
2372 if (lphMidiOut) *lphMidiOut = hMidiOut;
2375 return ret;
2378 /**************************************************************************
2379 * midiOutClose [WINMM.74]
2381 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
2383 return midiOutClose16(hMidiOut);
2386 /**************************************************************************
2387 * midiOutClose [MMSYSTEM.205]
2389 UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut)
2391 LPMIDIOPENDESC lpDesc;
2392 DWORD dwRet;
2394 TRACE("(%04X)\n", hMidiOut);
2396 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2398 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2399 dwRet = modMessage(lpDesc->wDevID, MODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2400 USER_HEAP_FREE(hMidiOut);
2401 return dwRet;
2404 /**************************************************************************
2405 * midiOutPrepareHeader [WINMM.85]
2407 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
2408 MIDIHDR* lpMidiOutHdr, UINT uSize)
2410 LPMIDIOPENDESC lpDesc;
2412 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2414 lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiOut);
2415 if (lpDesc == NULL)
2416 return MMSYSERR_INVALHANDLE;
2417 lpMidiOutHdr->reserved = (DWORD)lpMidiOutHdr;
2418 return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance,
2419 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2422 /**************************************************************************
2423 * midiOutPrepareHeader [MMSYSTEM.206]
2425 UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut,
2426 LPMIDIHDR16 /*SEGPTR*/ _lpMidiOutHdr, UINT16 uSize)
2428 LPMIDIOPENDESC lpDesc;
2429 LPMIDIHDR16 lpMidiOutHdr = (LPMIDIHDR16)PTR_SEG_TO_LIN(_lpMidiOutHdr);
2431 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2433 lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiOut);
2434 if (lpDesc == NULL)
2435 return MMSYSERR_INVALHANDLE;
2436 lpMidiOutHdr->reserved = (DWORD)_lpMidiOutHdr;
2437 return modMessage(lpDesc->wDevID, MODM_PREPARE, lpDesc->dwInstance,
2438 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2441 /**************************************************************************
2442 * midiOutUnprepareHeader [WINMM.89]
2444 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
2445 MIDIHDR* lpMidiOutHdr, UINT uSize)
2447 return midiOutUnprepareHeader16(hMidiOut, (MIDIHDR16*)lpMidiOutHdr, uSize);
2450 /**************************************************************************
2451 * midiOutUnprepareHeader [MMSYSTEM.207]
2453 UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut,
2454 MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2456 LPMIDIOPENDESC lpDesc;
2458 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2460 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2461 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2462 return modMessage(lpDesc->wDevID, MODM_UNPREPARE, lpDesc->dwInstance,
2463 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2466 /**************************************************************************
2467 * midiOutShortMsg [WINMM.88]
2469 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
2471 return midiOutShortMsg16(hMidiOut, dwMsg);
2474 /**************************************************************************
2475 * midiOutShortMsg [MMSYSTEM.208]
2477 UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg)
2479 LPMIDIOPENDESC lpDesc;
2481 TRACE("(%04X, %08lX)\n", hMidiOut, dwMsg);
2483 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2484 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2485 return modMessage(lpDesc->wDevID, MODM_DATA, lpDesc->dwInstance, dwMsg, 0L);
2488 /**************************************************************************
2489 * midiOutLongMsg [WINMM.82]
2491 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
2492 MIDIHDR* lpMidiOutHdr, UINT uSize)
2494 return midiOutLongMsg16(hMidiOut, (MIDIHDR16*)lpMidiOutHdr, uSize);
2497 /**************************************************************************
2498 * midiOutLongMsg [MMSYSTEM.209]
2500 UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut,
2501 MIDIHDR16* lpMidiOutHdr, UINT16 uSize)
2503 LPMIDIOPENDESC lpDesc;
2505 TRACE("(%04X, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
2507 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2508 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2509 return modMessage(lpDesc->wDevID, MODM_LONGDATA, lpDesc->dwInstance,
2510 (DWORD)lpMidiOutHdr, (DWORD)uSize);
2513 /**************************************************************************
2514 * midiOutReset [WINMM.86]
2516 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
2518 return midiOutReset16(hMidiOut);
2521 /**************************************************************************
2522 * midiOutReset [MMSYSTEM.210]
2524 UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut)
2526 LPMIDIOPENDESC lpDesc;
2528 TRACE("(%04X)\n", hMidiOut);
2530 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2531 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2532 return modMessage(lpDesc->wDevID, MODM_RESET, lpDesc->dwInstance, 0L, 0L);
2535 /**************************************************************************
2536 * midiOutGetVolume [WINM.81]
2538 UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
2540 return midiOutGetVolume16(uDeviceID, lpdwVolume);
2543 /**************************************************************************
2544 * midiOutGetVolume [MMSYSTEM.211]
2546 UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume)
2548 TRACE("(%04X, %p);\n", uDeviceID, lpdwVolume);
2549 return modMessage(uDeviceID, MODM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0L);
2552 /**************************************************************************
2553 * midiOutSetVolume [WINMM.87]
2555 UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume)
2557 return midiOutSetVolume16(uDeviceID, dwVolume);
2560 /**************************************************************************
2561 * midiOutSetVolume [MMSYSTEM.212]
2563 UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume)
2565 TRACE("(%04X, %08lX);\n", uDeviceID, dwVolume);
2566 return modMessage(uDeviceID, MODM_SETVOLUME, 0L, dwVolume, 0L);
2569 /**************************************************************************
2570 * midiOutCachePatches [WINMM.73]
2572 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
2573 WORD* lpwPatchArray, UINT uFlags)
2575 return midiOutCachePatches16(hMidiOut, uBank, lpwPatchArray, uFlags);
2578 /**************************************************************************
2579 * midiOutCachePatches [MMSYSTEM.213]
2581 UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank,
2582 WORD* lpwPatchArray, UINT16 uFlags)
2584 /* not really necessary to support this */
2585 FIXME("not supported yet\n");
2586 return MMSYSERR_NOTSUPPORTED;
2589 /**************************************************************************
2590 * midiOutCacheDrumPatches [WINMM.72]
2592 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
2593 WORD* lpwKeyArray, UINT uFlags)
2595 return midiOutCacheDrumPatches16(hMidiOut, uPatch, lpwKeyArray, uFlags);
2598 /**************************************************************************
2599 * midiOutCacheDrumPatches [MMSYSTEM.214]
2601 UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch,
2602 WORD* lpwKeyArray, UINT16 uFlags)
2604 FIXME("not supported yet\n");
2605 return MMSYSERR_NOTSUPPORTED;
2608 /**************************************************************************
2609 * midiOutGetID [WINMM.79]
2611 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
2613 UINT16 xid;
2614 UINT ret;
2616 ret = midiOutGetID16(hMidiOut, &xid);
2617 *lpuDeviceID = xid;
2618 return ret;
2621 /**************************************************************************
2622 * midiOutGetID [MMSYSTEM.215]
2624 UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID)
2626 TRACE("midiOutGetID\n");
2627 return 0;
2630 /**************************************************************************
2631 * midiOutMessage [WINMM.83]
2633 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
2634 DWORD dwParam1, DWORD dwParam2)
2636 LPMIDIOPENDESC lpDesc;
2638 /* Shouldn't we anyway use the functions midiOutXXX ?
2639 * M$ doc says: This function is used only for driver-specific
2640 * messages that are not supported by the MIDI API.
2641 * Clearly not what we are currently doing
2644 TRACE("(%04X, %04X, %08lX, %08lX)\n",
2645 hMidiOut, uMessage, dwParam1, dwParam2);
2647 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2648 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2649 switch (uMessage) {
2650 case MODM_OPEN:
2651 FIXME("can't handle MODM_OPEN!\n");
2652 return 0;
2653 case MODM_GETDEVCAPS:
2654 return midiOutGetDevCapsA(hMidiOut, (LPMIDIOUTCAPSA)dwParam1, dwParam2);
2655 case MODM_GETNUMDEVS:
2656 case MODM_RESET:
2657 case MODM_CLOSE:
2658 case MODM_GETVOLUME:
2659 case MODM_SETVOLUME:
2660 case MODM_LONGDATA:
2661 case MODM_PREPARE:
2662 case MODM_UNPREPARE:
2663 /* no argument conversion needed */
2664 break;
2665 default:
2666 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
2667 hMidiOut, uMessage, dwParam1, dwParam2);
2668 break;
2670 return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2673 /**************************************************************************
2674 * midiOutMessage [MMSYSTEM.216]
2676 DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage,
2677 DWORD dwParam1, DWORD dwParam2)
2679 LPMIDIOPENDESC lpDesc;
2681 TRACE("(%04X, %04X, %08lX, %08lX)\n",
2682 hMidiOut, uMessage, dwParam1, dwParam2);
2683 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiOut);
2684 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2685 switch (uMessage) {
2686 case MODM_OPEN:
2687 FIXME("can't handle MODM_OPEN!\n");
2688 return 0;
2689 case MODM_GETNUMDEVS:
2690 case MODM_RESET:
2691 case MODM_CLOSE:
2692 case MODM_SETVOLUME:
2693 /* no argument conversion needed */
2694 break;
2695 case MODM_GETVOLUME:
2696 return midiOutGetVolume16(hMidiOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
2697 case MODM_LONGDATA:
2698 return midiOutLongMsg16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2699 case MODM_PREPARE:
2700 /* lpMidiOutHdr is still a segmented pointer for this function */
2701 return midiOutPrepareHeader16(hMidiOut, (LPMIDIHDR16)dwParam1, dwParam2);
2702 case MODM_UNPREPARE:
2703 return midiOutUnprepareHeader16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
2704 default:
2705 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
2706 hMidiOut, uMessage, dwParam1, dwParam2);
2707 break;
2709 return modMessage(lpDesc->wDevID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
2712 /**************************************************************************
2713 * midiInGetNumDevs [WINMM.64]
2715 UINT WINAPI midiInGetNumDevs(void)
2717 return midiInGetNumDevs16();
2720 /**************************************************************************
2721 * midiInGetNumDevs [MMSYSTEM.301]
2723 UINT16 WINAPI midiInGetNumDevs16(void)
2725 UINT16 count = 0;
2726 TRACE("midiInGetNumDevs\n");
2727 count += midMessage(0, MIDM_GETNUMDEVS, 0L, 0L, 0L);
2728 TRACE("midiInGetNumDevs return %u \n", count);
2729 return count;
2732 /**************************************************************************
2733 * midiInGetDevCaps [WINMM.60]
2735 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
2737 MIDIINCAPS16 mic16;
2738 UINT ret = midiInGetDevCaps16(uDeviceID, &mic16, uSize);
2740 lpCaps->wMid = mic16.wMid;
2741 lpCaps->wPid = mic16.wPid;
2742 lpCaps->vDriverVersion = mic16.vDriverVersion;
2743 lstrcpyAtoW(lpCaps->szPname, mic16.szPname);
2744 lpCaps->dwSupport = mic16.dwSupport;
2745 return ret;
2748 /**************************************************************************
2749 * midiInGetDevCaps [WINMM.59]
2751 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
2753 MIDIINCAPS16 mic16;
2754 UINT ret = midiInGetDevCaps16(uDeviceID, &mic16, uSize);
2756 lpCaps->wMid = mic16.wMid;
2757 lpCaps->wPid = mic16.wPid;
2758 lpCaps->vDriverVersion = mic16.vDriverVersion;
2759 strcpy(lpCaps->szPname, mic16.szPname);
2760 lpCaps->dwSupport = mic16.dwSupport;
2761 return ret;
2764 /**************************************************************************
2765 * midiInGetDevCaps [MMSYSTEM.302]
2767 UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID,
2768 LPMIDIINCAPS16 lpCaps, UINT16 uSize)
2770 TRACE("midiInGetDevCaps\n");
2771 return midMessage(uDeviceID, MIDM_GETDEVCAPS, 0, (DWORD)lpCaps, uSize);
2774 /**************************************************************************
2775 * midiInGetErrorText [WINMM.62]
2777 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2779 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2780 UINT ret = midiInGetErrorText16(uError, xstr, uSize);
2781 lstrcpyAtoW(lpText, xstr);
2782 HeapFree(GetProcessHeap(), 0, xstr);
2783 return ret;
2786 /**************************************************************************
2787 * midiInGetErrorText [WINMM.61]
2789 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2791 return midiInGetErrorText16(uError, lpText, uSize);
2794 /**************************************************************************
2795 * midiInGetErrorText [MMSYSTEM.303]
2797 UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
2799 TRACE("midiInGetErrorText\n");
2800 return (midiGetErrorText(uError, lpText, uSize));
2803 /**************************************************************************
2804 * midiInOpen [WINMM.66]
2806 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
2807 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2809 HMIDIIN16 xhmid16;
2810 UINT ret = midiInOpen16(&xhmid16, uDeviceID, dwCallback, dwInstance,
2811 CALLBACK32CONV(dwFlags));
2812 if (lphMidiIn)
2813 *lphMidiIn = xhmid16;
2814 return ret;
2817 /**************************************************************************
2818 * midiInOpen [MMSYSTEM.304]
2820 UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID,
2821 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
2823 HMIDI16 hMidiIn;
2824 LPMIDIOPENDESC lpDesc;
2825 DWORD dwRet = 0;
2826 BOOL bMapperFlg = FALSE;
2828 if (lphMidiIn != NULL)
2829 *lphMidiIn = 0;
2830 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
2831 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
2832 if (uDeviceID == (UINT16)MIDI_MAPPER) {
2833 TRACE("MIDI_MAPPER mode requested !\n");
2834 bMapperFlg = TRUE;
2835 uDeviceID = 0;
2837 hMidiIn = USER_HEAP_ALLOC(sizeof(MIDIOPENDESC));
2838 if (lphMidiIn != NULL)
2839 *lphMidiIn = hMidiIn;
2840 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2841 if (lpDesc == NULL)
2842 return MMSYSERR_NOMEM;
2843 lpDesc->hMidi = hMidiIn;
2844 lpDesc->dwCallback = dwCallback;
2845 lpDesc->dwInstance = dwInstance;
2847 while (uDeviceID < MAXMIDIDRIVERS) {
2848 dwRet = midMessage(uDeviceID, MIDM_OPEN,
2849 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
2850 if (dwRet == MMSYSERR_NOERROR)
2851 break;
2852 if (!bMapperFlg)
2853 break;
2854 uDeviceID++;
2855 TRACE("MIDI_MAPPER mode ! try next driver...\n");
2857 lpDesc->wDevID = uDeviceID;
2859 if (dwRet != MMSYSERR_NOERROR) {
2860 USER_HEAP_FREE(hMidiIn);
2861 if (lphMidiIn) *lphMidiIn = 0;
2864 return dwRet;
2867 /**************************************************************************
2868 * midiInClose [WINMM.58]
2870 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
2872 return midiInClose16(hMidiIn);
2875 /**************************************************************************
2876 * midiInClose [MMSYSTEM.305]
2878 UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn)
2880 LPMIDIOPENDESC lpDesc;
2881 DWORD dwRet;
2883 TRACE("(%04X)\n", hMidiIn);
2884 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2886 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
2887 dwRet = midMessage(lpDesc->wDevID, MIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
2888 USER_HEAP_FREE(hMidiIn);
2889 return dwRet;
2892 /**************************************************************************
2893 * midiInPrepareHeader [WINMM.67]
2895 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
2896 MIDIHDR* lpMidiInHdr, UINT uSize)
2898 LPMIDIOPENDESC lpDesc;
2900 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2902 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2903 if (lpDesc == NULL)
2904 return MMSYSERR_INVALHANDLE;
2905 lpMidiInHdr->reserved = (DWORD)lpMidiInHdr;
2906 return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance,
2907 (DWORD)lpMidiInHdr, (DWORD)uSize);
2910 /**************************************************************************
2911 * midiInPrepareHeader [MMSYSTEM.306]
2913 UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn,
2914 MIDIHDR16* /*SEGPTR*/ _lpMidiInHdr, UINT16 uSize)
2916 LPMIDIOPENDESC lpDesc;
2917 LPMIDIHDR16 lpMidiInHdr = (LPMIDIHDR16)PTR_SEG_TO_LIN(_lpMidiInHdr);
2919 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2921 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2922 if (lpDesc == NULL)
2923 return MMSYSERR_INVALHANDLE;
2924 lpMidiInHdr->reserved = (DWORD)_lpMidiInHdr;
2925 return midMessage(lpDesc->wDevID, MIDM_PREPARE, lpDesc->dwInstance,
2926 (DWORD)lpMidiInHdr, (DWORD)uSize);
2929 /**************************************************************************
2930 * midiInUnprepareHeader [WINMM.71]
2932 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
2933 MIDIHDR* lpMidiInHdr, UINT uSize)
2935 return midiInUnprepareHeader16(hMidiIn, (MIDIHDR16*)lpMidiInHdr, uSize);
2938 /**************************************************************************
2939 * midiInUnprepareHeader [MMSYSTEM.307]
2941 UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn,
2942 MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2944 LPMIDIOPENDESC lpDesc;
2946 TRACE("(%04X, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
2948 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2949 if (lpDesc == NULL)
2950 return MMSYSERR_INVALHANDLE;
2951 return midMessage(lpDesc->wDevID, MIDM_UNPREPARE, lpDesc->dwInstance,
2952 (DWORD)lpMidiInHdr, (DWORD)uSize);
2955 /**************************************************************************
2956 * midiInAddBuffer [WINMM.57]
2958 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
2959 MIDIHDR* lpMidiInHdr, UINT uSize)
2961 return midiInAddBuffer16(hMidiIn, (MIDIHDR16*)lpMidiInHdr, uSize);
2964 /**************************************************************************
2965 * midiInAddBuffer [MMSYSTEM.308]
2967 UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn,
2968 MIDIHDR16* lpMidiInHdr, UINT16 uSize)
2970 TRACE("midiInAddBuffer\n");
2971 return 0;
2974 /**************************************************************************
2975 * midiInStart [WINMM.69]
2977 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
2979 return midiInStart16(hMidiIn);
2982 /**************************************************************************
2983 * midiInStart [MMSYSTEM.309]
2985 UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn)
2987 LPMIDIOPENDESC lpDesc;
2989 TRACE("(%04X)\n", hMidiIn);
2990 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
2991 if (lpDesc == NULL)
2992 return MMSYSERR_INVALHANDLE;
2993 return midMessage(lpDesc->wDevID, MIDM_START, lpDesc->dwInstance, 0L, 0L);
2996 /**************************************************************************
2997 * midiInStop [WINMM.70]
2999 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
3001 return midiInStop16(hMidiIn);
3004 /**************************************************************************
3005 * midiInStop [MMSYSTEM.310]
3007 UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn)
3009 LPMIDIOPENDESC lpDesc;
3011 TRACE("(%04X)\n", hMidiIn);
3012 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
3013 if (lpDesc == NULL)
3014 return MMSYSERR_INVALHANDLE;
3015 return midMessage(lpDesc->wDevID, MIDM_STOP, lpDesc->dwInstance, 0L, 0L);
3018 /**************************************************************************
3019 * midiInReset [WINMM.68]
3021 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
3023 return midiInReset16(hMidiIn);
3026 /**************************************************************************
3027 * midiInReset [MMSYSTEM.311]
3029 UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn)
3031 LPMIDIOPENDESC lpDesc;
3033 TRACE("(%04X)\n", hMidiIn);
3034 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
3035 if (lpDesc == NULL)
3036 return MMSYSERR_INVALHANDLE;
3037 return midMessage(lpDesc->wDevID, MIDM_RESET, lpDesc->dwInstance, 0L, 0L);
3040 /**************************************************************************
3041 * midiInGetID [WINMM.63]
3043 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
3045 LPMIDIOPENDESC lpDesc;
3047 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
3048 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
3049 if (lpDesc == NULL)
3050 return MMSYSERR_INVALHANDLE;
3051 if (lpuDeviceID == NULL)
3052 return MMSYSERR_INVALPARAM;
3053 *lpuDeviceID = lpDesc->wDevID;
3055 return MMSYSERR_NOERROR;
3058 /**************************************************************************
3059 * midiInGetID [MMSYSTEM.312]
3061 UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID)
3063 LPMIDIOPENDESC lpDesc;
3065 TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID);
3066 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
3067 if (lpDesc == NULL)
3068 return MMSYSERR_INVALHANDLE;
3069 if (lpuDeviceID == NULL)
3070 return MMSYSERR_INVALPARAM;
3071 *lpuDeviceID = lpDesc->wDevID;
3073 return MMSYSERR_NOERROR;
3076 /**************************************************************************
3077 * midiInMessage [WINMM.65]
3079 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
3080 DWORD dwParam1, DWORD dwParam2)
3082 LPMIDIOPENDESC lpDesc;
3084 TRACE("(%04X, %04X, %08lX, %08lX)\n",
3085 hMidiIn, uMessage, dwParam1, dwParam2);
3086 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
3087 if (lpDesc == NULL)
3088 return MMSYSERR_INVALHANDLE;
3090 switch (uMessage) {
3091 case MIDM_OPEN:
3092 FIXME("can't handle MIDM_OPEN!\n");
3093 return 0;
3094 case MIDM_GETDEVCAPS:
3095 return midiInGetDevCapsA(hMidiIn, (LPMIDIINCAPSA)dwParam1, dwParam2);
3096 case MIDM_GETNUMDEVS:
3097 case MIDM_RESET:
3098 case MIDM_STOP:
3099 case MIDM_START:
3100 case MIDM_CLOSE:
3101 /* no argument conversion needed */
3102 break;
3103 case MIDM_PREPARE:
3104 return midiInPrepareHeader(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
3105 case MIDM_UNPREPARE:
3106 return midiInUnprepareHeader(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
3107 case MIDM_ADDBUFFER:
3108 return midiInAddBuffer(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
3109 default:
3110 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
3111 hMidiIn, uMessage, dwParam1, dwParam2);
3112 break;
3114 return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
3117 /**************************************************************************
3118 * midiInMessage [MMSYSTEM.313]
3120 DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage,
3121 DWORD dwParam1, DWORD dwParam2)
3123 LPMIDIOPENDESC lpDesc;
3125 TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
3127 lpDesc = (LPMIDIOPENDESC) USER_HEAP_LIN_ADDR(hMidiIn);
3128 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
3129 switch (uMessage) {
3130 case MIDM_OPEN:
3131 WARN("can't handle MIDM_OPEN!\n");
3132 return 0;
3133 case MIDM_GETDEVCAPS:
3134 return midiInGetDevCaps16(hMidiIn, (LPMIDIINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3135 case MIDM_GETNUMDEVS:
3136 case MIDM_RESET:
3137 case MIDM_STOP:
3138 case MIDM_START:
3139 case MIDM_CLOSE:
3140 /* no argument conversion needed */
3141 break;
3142 case MIDM_PREPARE:
3143 return midiInPrepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3144 case MIDM_UNPREPARE:
3145 return midiInUnprepareHeader16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3146 case MIDM_ADDBUFFER:
3147 return midiInAddBuffer16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
3148 default:
3149 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
3150 hMidiIn, uMessage, dwParam1, dwParam2);
3151 break;
3153 return midMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
3156 typedef struct WINE_MIDIStream{
3157 HMIDIOUT hDevice;
3158 HANDLE hThread;
3159 DWORD dwThreadID;
3160 DWORD dwTempo;
3161 DWORD dwTimeDiv;
3162 DWORD dwPositionMS;
3163 DWORD dwPulses;
3164 DWORD dwStartTicks;
3165 WORD wFlags;
3166 HANDLE hEvent;
3167 LPMIDIHDR lpMidiHdr;
3168 } WINE_MIDIStream;
3170 #define WINE_MSM_HEADER (WM_USER+0)
3171 #define WINE_MSM_STOP (WM_USER+1)
3173 /**************************************************************************
3174 * MMSYSTEM_GetMidiStream [internal]
3176 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, MIDIOPENDESC** lplpDesc)
3178 MIDIOPENDESC* lpDesc = (LPMIDIOPENDESC)USER_HEAP_LIN_ADDR(hMidiStrm);
3180 if (lplpDesc)
3181 *lplpDesc = lpDesc;
3183 if (lpDesc == NULL) {
3184 return FALSE;
3187 *lpMidiStrm = (WINE_MIDIStream*)lpDesc->rgIds.dwStreamID;
3189 return *lpMidiStrm != NULL;
3192 /**************************************************************************
3193 * MMSYSTEM_MidiStream_Convert [internal]
3195 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
3197 DWORD ret = 0;
3199 if (lpMidiStrm->dwTimeDiv == 0) {
3200 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
3201 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
3202 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
3203 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
3204 ret = (pulse * 1000) / (nf * nsf);
3205 } else {
3206 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
3207 (double)lpMidiStrm->dwTimeDiv);
3210 return ret;
3213 /**************************************************************************
3214 * MMSYSTEM_MidiStream_MessageHandler [internal]
3216 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPMIDIOPENDESC lpDesc, LPMSG msg)
3218 LPMIDIHDR lpMidiHdr;
3219 LPMIDIHDR* lpmh;
3220 LPBYTE lpData;
3222 switch (msg->message) {
3223 case WM_QUIT:
3224 SetEvent(lpMidiStrm->hEvent);
3225 return FALSE;
3226 case WINE_MSM_STOP:
3227 TRACE("STOP\n");
3228 /* this is not quite what MS doc says... */
3229 midiOutReset(lpMidiStrm->hDevice);
3230 /* empty list of already submitted buffers */
3231 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
3232 lpMidiHdr->dwFlags |= MHDR_DONE;
3233 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3235 DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3236 MM_MOM_DONE, lpDesc->dwInstance, lpMidiHdr->reserved, 0L);
3238 lpMidiStrm->lpMidiHdr = 0;
3239 SetEvent(lpMidiStrm->hEvent);
3240 break;
3241 case WINE_MSM_HEADER:
3242 /* sets initial tick count for first MIDIHDR */
3243 if (!lpMidiStrm->dwStartTicks)
3244 lpMidiStrm->dwStartTicks = GetTickCount();
3246 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
3247 * by native mcimidi, it doesn't look like a correct one".
3248 * this trick allows to throw it away... but I don't like it.
3249 * It looks like part of the file I'm trying to play and definitively looks
3250 * like raw midi content
3251 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
3252 * synchronization issue where native mcimidi is still processing raw MIDI
3253 * content before generating MIDIEVENTs ?
3255 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
3256 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
3257 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
3258 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
3259 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
3260 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
3261 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
3262 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
3263 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
3264 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
3265 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
3266 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
3267 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
3268 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
3269 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
3270 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
3271 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
3273 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3274 lpData = ((DWORD)lpMidiHdr == lpMidiHdr->reserved) ?
3275 (LPBYTE)lpMidiHdr->lpData : (LPBYTE)PTR_SEG_TO_LIN(lpMidiHdr->lpData);
3276 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
3277 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
3278 lpMidiHdr->reserved, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
3279 lpMidiHdr->dwFlags, msg->wParam);
3280 #if 0
3281 /* dumps content of lpMidiHdr->lpData
3282 * FIXME: there should be a debug routine somewhere that already does this
3283 * I hate spreading this type of shit all around the code
3285 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
3286 DWORD i;
3287 BYTE ch;
3289 for (i = 0; i < MIN(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
3290 printf("%02x ", lpData[dwToGo + i]);
3291 for (; i < 16; i++)
3292 printf(" ");
3293 for (i = 0; i < MIN(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
3294 ch = lpData[dwToGo + i];
3295 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
3297 printf("\n");
3299 #endif
3300 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
3301 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
3302 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
3303 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
3304 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
3305 ((LPMIDIEVENT)lpData)->dwStreamID);
3306 lpMidiHdr->dwFlags |= MHDR_DONE;
3307 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3309 DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3310 MM_MOM_DONE, lpDesc->dwInstance, lpMidiHdr->reserved, 0L);
3311 break;
3314 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
3315 *lpmh = lpMidiHdr;
3316 lpMidiHdr = (LPMIDIHDR)msg->lParam;
3317 lpMidiHdr->lpNext = 0;
3318 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
3319 lpMidiHdr->dwFlags &= MHDR_DONE;
3320 lpMidiHdr->dwOffset = 0;
3322 break;
3323 default:
3324 FIXME("Unknown message %d\n", msg->message);
3325 break;
3327 return TRUE;
3330 /**************************************************************************
3331 * MMSYSTEM_MidiStream_Player [internal]
3333 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
3335 WINE_MIDIStream* lpMidiStrm = pmt;
3336 MIDIOPENDESC* lpDesc = USER_HEAP_LIN_ADDR(lpMidiStrm->hDevice);
3337 MSG msg;
3338 DWORD dwToGo;
3339 DWORD dwCurrTC;
3340 LPMIDIHDR lpMidiHdr;
3341 LPMIDIEVENT me;
3342 LPBYTE lpData = 0;
3344 TRACE("(%p)!\n", lpMidiStrm);
3346 /* force thread's queue creation */
3347 /* Used to be InitThreadInput16(0, 5); */
3348 /* but following works also with hack in midiStreamOpen */
3349 Callout.PeekMessageA(&msg, 0, 0, 0, 0);
3351 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
3352 SetEvent(lpMidiStrm->hEvent);
3353 TRACE("Ready to go 1\n");
3354 /* thread is started in paused mode */
3355 SuspendThread(lpMidiStrm->hThread);
3356 TRACE("Ready to go 2\n");
3358 lpMidiStrm->dwStartTicks = 0;
3359 lpMidiStrm->dwPulses = 0;
3361 lpMidiStrm->lpMidiHdr = 0;
3363 for (;;) {
3364 lpMidiHdr = lpMidiStrm->lpMidiHdr;
3365 if (!lpMidiHdr) {
3366 /* for first message, block until one arrives, then process all that are available */
3367 Callout.GetMessageA(&msg, 0, 0, 0);
3368 do {
3369 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpDesc, &msg))
3370 goto the_end;
3371 } while (Callout.PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
3372 lpData = 0;
3373 continue;
3376 /* <HACK>
3377 * midiOutPrepareHeader(), in Wine, sets the 'reserved' field of MIDIHDR to the
3378 * 16 or 32 bit address of lpMidiHdr (depending if called from 16 to 32 bit code)
3380 if (!lpData)
3381 lpData = ((DWORD)lpMidiHdr == lpMidiHdr->reserved) ?
3382 (LPBYTE)lpMidiHdr->lpData : (LPBYTE)PTR_SEG_TO_LIN(lpMidiHdr->lpData);
3384 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
3386 /* do we have to wait ? */
3387 if (me->dwDeltaTime) {
3388 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
3389 lpMidiStrm->dwPulses += me->dwDeltaTime;
3391 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
3393 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
3394 while ((dwCurrTC = GetTickCount()) < dwToGo) {
3395 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
3396 /* got a message, handle it */
3397 while (Callout.PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
3398 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpDesc, &msg))
3399 goto the_end;
3401 lpData = 0;
3402 } else {
3403 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
3404 break;
3408 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
3409 case MEVT_COMMENT:
3410 FIXME("NIY: MEVT_COMMENT\n");
3411 /* do nothing, skip bytes */
3412 break;
3413 case MEVT_LONGMSG:
3414 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
3415 break;
3416 case MEVT_NOP:
3417 break;
3418 case MEVT_SHORTMSG:
3419 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
3420 break;
3421 case MEVT_TEMPO:
3422 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
3423 break;
3424 case MEVT_VERSION:
3425 break;
3426 default:
3427 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
3428 break;
3430 if (me->dwEvent & MEVT_F_CALLBACK) {
3431 DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3432 MM_MOM_POSITIONCB, lpDesc->dwInstance, (LPARAM)lpMidiHdr, 0L);
3434 lpMidiHdr->dwOffset += sizeof(MIDIEVENT);
3435 if (me->dwEvent & MEVT_F_LONG)
3436 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
3437 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
3438 /* done with this header */
3439 lpMidiHdr->dwFlags |= MHDR_DONE;
3440 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
3442 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
3443 DriverCallback16(lpDesc->dwCallback, lpMidiStrm->wFlags, lpMidiStrm->hDevice,
3444 MM_MOM_DONE, lpDesc->dwInstance, lpMidiHdr->reserved, 0L);
3445 lpData = 0;
3448 the_end:
3449 TRACE("End of thread\n");
3450 ExitThread(0);
3451 return 0; /* for removing the warning, never executed */
3454 /**************************************************************************
3455 * MMSYSTEM_MidiStream_PostMessage [internal]
3457 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
3459 if (Callout.PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
3460 DWORD count;
3461 BOOL bHasWin16Lock;
3463 /* FIXME: should use the new syslevel APIs */
3464 if ((bHasWin16Lock = _ConfirmWin16Lock()) != 0) {
3465 ReleaseThunkLock(&count);
3467 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3468 if (bHasWin16Lock) {
3469 RestoreThunkLock(count);
3471 } else {
3472 WARN("bad PostThreadMessageA\n");
3473 return FALSE;
3475 return TRUE;
3478 /**************************************************************************
3479 * midiStreamClose [WINMM.90]
3481 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
3483 WINE_MIDIStream* lpMidiStrm;
3485 TRACE("(%08x)!\n", hMidiStrm);
3487 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
3488 return MMSYSERR_INVALHANDLE;
3490 midiStreamStop(hMidiStrm);
3491 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
3492 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
3493 CloseHandle(lpMidiStrm->hEvent);
3495 return midiOutClose(hMidiStrm);
3498 /**************************************************************************
3499 * MMSYSTEM_MidiStream_Open [internal]
3501 static MMRESULT WINAPI MMSYSTEM_MidiStream_Open(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3502 DWORD cMidi, DWORD dwCallback,
3503 DWORD dwInstance, DWORD fdwOpen)
3505 WINE_MIDIStream* lpMidiStrm;
3506 MMRESULT ret;
3507 MIDIOPENSTRMID mosm;
3508 MIDIOPENDESC* lpDesc;
3509 HMIDIOUT16 hMidiOut16;
3511 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
3512 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
3514 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
3515 return MMSYSERR_INVALPARAM;
3517 if (*lpuDeviceID == (UINT16)MIDI_MAPPER) {
3518 FIXME("MIDI_MAPPER mode requested ! => forcing devID to 0\n");
3519 *lpuDeviceID = 0;
3522 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
3523 if (!lpMidiStrm)
3524 return MMSYSERR_NOMEM;
3526 lpMidiStrm->dwTempo = 500000;
3527 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
3528 lpMidiStrm->dwPositionMS = 0;
3530 mosm.dwStreamID = (DWORD)lpMidiStrm;
3531 /* FIXME: the correct value is not allocated yet for MAPPER */
3532 mosm.wDeviceID = *lpuDeviceID;
3533 lpDesc = MIDI_OutAlloc(&hMidiOut16, dwCallback, dwInstance, 1, &mosm);
3534 lpMidiStrm->hDevice = hMidiOut16;
3535 if (lphMidiStrm)
3536 *lphMidiStrm = hMidiOut16;
3538 lpDesc->wDevID = *lpuDeviceID;
3539 ret = modMessage(lpDesc->wDevID, MODM_OPEN,
3540 lpDesc->dwInstance, (DWORD)lpDesc, fdwOpen);
3541 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
3542 lpMidiStrm->wFlags = HIWORD(fdwOpen);
3544 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
3545 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
3547 if (!lpMidiStrm->hThread) {
3548 midiStreamClose((HMIDISTRM)hMidiOut16);
3549 return MMSYSERR_NOMEM;
3552 /* wait for thread to have started, and for it's queue to be created */
3554 DWORD count;
3555 BOOL bHasWin16Lock;
3557 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
3558 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
3559 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
3561 if ((bHasWin16Lock = _ConfirmWin16Lock()) != 0) {
3562 ReleaseThunkLock(&count);
3564 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
3565 if (bHasWin16Lock) {
3566 RestoreThunkLock(count);
3570 TRACE("=> (%u/%d) hMidi=0x%04x ret=%d lpMidiStrm=%p\n", *lpuDeviceID, lpDesc->wDevID, *lphMidiStrm, ret, lpMidiStrm);
3571 return ret;
3574 /**************************************************************************
3575 * midiStreamOpen [WINMM.91]
3577 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
3578 DWORD cMidi, DWORD dwCallback,
3579 DWORD dwInstance, DWORD fdwOpen)
3581 return MMSYSTEM_MidiStream_Open(lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, CALLBACK32CONV(fdwOpen));
3584 /**************************************************************************
3585 * midiStreamOut [WINMM.92]
3587 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, UINT cbMidiHdr)
3589 WINE_MIDIStream* lpMidiStrm;
3590 DWORD ret = MMSYSERR_NOERROR;
3592 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
3594 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3595 ret = MMSYSERR_INVALHANDLE;
3596 } else {
3597 if (!Callout.PostThreadMessageA(lpMidiStrm->dwThreadID, WINE_MSM_HEADER, cbMidiHdr, (DWORD)lpMidiHdr)) {
3598 WARN("bad PostThreadMessageA\n");
3599 ret = MMSYSERR_ERROR;
3602 return ret;
3605 /**************************************************************************
3606 * midiStreamPause [WINMM.93]
3608 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
3610 WINE_MIDIStream* lpMidiStrm;
3611 DWORD ret = MMSYSERR_NOERROR;
3613 TRACE("(%08x)!\n", hMidiStrm);
3615 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3616 ret = MMSYSERR_INVALHANDLE;
3617 } else {
3618 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3619 WARN("bad Suspend (%ld)\n", GetLastError());
3620 ret = MMSYSERR_ERROR;
3623 return ret;
3626 /**************************************************************************
3627 * midiStreamPosition [WINMM.94]
3629 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
3631 WINE_MIDIStream* lpMidiStrm;
3632 DWORD ret = MMSYSERR_NOERROR;
3634 TRACE("(%08x, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
3636 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3637 ret = MMSYSERR_INVALHANDLE;
3638 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
3639 ret = MMSYSERR_INVALPARAM;
3640 } else {
3641 switch (lpMMT->wType) {
3642 case TIME_MS:
3643 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
3644 TRACE("=> %ld ms\n", lpMMT->u.ms);
3645 break;
3646 case TIME_TICKS:
3647 lpMMT->u.ticks = lpMidiStrm->dwPulses;
3648 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
3649 break;
3650 default:
3651 WARN("Unsupported time type %d\n", lpMMT->wType);
3652 lpMMT->wType = TIME_MS;
3653 ret = MMSYSERR_INVALPARAM;
3654 break;
3657 return ret;
3660 /**************************************************************************
3661 * midiStreamProperty [WINMM.95]
3663 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3665 WINE_MIDIStream* lpMidiStrm;
3666 MMRESULT ret = MMSYSERR_NOERROR;
3668 TRACE("(%08x, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
3670 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3671 ret = MMSYSERR_INVALHANDLE;
3672 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
3673 ret = MMSYSERR_INVALPARAM;
3674 } else if (dwProperty & MIDIPROP_TEMPO) {
3675 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
3677 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
3678 ret = MMSYSERR_INVALPARAM;
3679 } else if (dwProperty & MIDIPROP_SET) {
3680 lpMidiStrm->dwTempo = mpt->dwTempo;
3681 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
3682 } else if (dwProperty & MIDIPROP_GET) {
3683 mpt->dwTempo = lpMidiStrm->dwTempo;
3684 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
3686 } else if (dwProperty & MIDIPROP_TIMEDIV) {
3687 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
3689 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
3690 ret = MMSYSERR_INVALPARAM;
3691 } else if (dwProperty & MIDIPROP_SET) {
3692 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
3693 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
3694 } else if (dwProperty & MIDIPROP_GET) {
3695 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
3696 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
3698 } else {
3699 ret = MMSYSERR_INVALPARAM;
3702 return ret;
3705 /**************************************************************************
3706 * midiStreamRestart [WINMM.96]
3708 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
3710 WINE_MIDIStream* lpMidiStrm;
3711 MMRESULT ret = MMSYSERR_NOERROR;
3713 TRACE("(%08x)!\n", hMidiStrm);
3715 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3716 ret = MMSYSERR_INVALHANDLE;
3717 } else {
3718 if (ResumeThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
3719 WARN("bad Resume (%ld)\n", GetLastError());
3720 ret = MMSYSERR_ERROR;
3721 } else {
3722 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
3725 return ret;
3728 /**************************************************************************
3729 * midiStreamStop [WINMM.97]
3731 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
3733 WINE_MIDIStream* lpMidiStrm;
3734 MMRESULT ret = MMSYSERR_NOERROR;
3736 TRACE("(%08x)!\n", hMidiStrm);
3738 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
3739 ret = MMSYSERR_INVALHANDLE;
3740 } else {
3741 /* in case stream has been paused... FIXME is the current state correct ? */
3742 midiStreamRestart(hMidiStrm);
3743 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
3745 return ret;
3748 /**************************************************************************
3749 * midiStreamClose [MMSYSTEM.252]
3751 MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm)
3753 return midiStreamClose(hMidiStrm);
3756 /**************************************************************************
3757 * midiStreamOpen [MMSYSTEM.251]
3759 MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid,
3760 DWORD cMidi, DWORD dwCallback,
3761 DWORD dwInstance, DWORD fdwOpen)
3763 HMIDISTRM hMidiStrm32;
3764 MMRESULT ret;
3765 UINT devid32;
3767 if (!phMidiStrm || !devid)
3768 return MMSYSERR_INVALPARAM;
3769 devid32 = *devid;
3770 ret = MMSYSTEM_MidiStream_Open(&hMidiStrm32, &devid32, cMidi, dwCallback, dwInstance, fdwOpen);
3771 *phMidiStrm = hMidiStrm32;
3772 *devid = devid32;
3773 return ret;
3776 /**************************************************************************
3777 * midiStreamOut [MMSYSTEM.254]
3779 MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr)
3781 return midiStreamOut(hMidiStrm, (LPMIDIHDR)lpMidiHdr, cbMidiHdr);
3784 /**************************************************************************
3785 * midiStreamPause [MMSYSTEM.255]
3787 MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm)
3789 return midiStreamPause(hMidiStrm);
3792 /**************************************************************************
3793 * midiStreamPosition [MMSYSTEM.253]
3795 MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt)
3797 MMTIME mmt32;
3798 MMRESULT ret;
3800 if (!lpmmt16)
3801 return MMSYSERR_INVALPARAM;
3802 MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16);
3803 ret = midiStreamPosition(hMidiStrm, &mmt32, sizeof(MMTIME));
3804 MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32);
3805 return ret;
3808 /**************************************************************************
3809 * midiStreamProperty [MMSYSTEM.250]
3811 MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
3813 return midiStreamProperty(hMidiStrm, lpPropData, dwProperty);
3816 /**************************************************************************
3817 * midiStreamRestart [MMSYSTEM.256]
3819 MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm)
3821 return midiStreamRestart(hMidiStrm);
3824 /**************************************************************************
3825 * midiStreamStop [MMSYSTEM.257]
3827 MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm)
3829 return midiStreamStop(hMidiStrm);
3832 /**************************************************************************
3833 * waveOutGetNumDevs [MMSYSTEM.401]
3835 UINT WINAPI waveOutGetNumDevs()
3837 return waveOutGetNumDevs16();
3840 /**************************************************************************
3841 * waveOutGetNumDevs [WINMM.167]
3843 UINT16 WINAPI waveOutGetNumDevs16()
3845 UINT16 count = 0;
3846 TRACE("waveOutGetNumDevs\n");
3847 /* FIXME: I'm not sure MCI_FirstDevID() is correct */
3848 count += wodMessage(MCI_FirstDevID(), WODM_GETNUMDEVS, 0L, 0L, 0L);
3849 TRACE("waveOutGetNumDevs return %u \n", count);
3850 return count;
3853 /**************************************************************************
3854 * waveOutGetDevCaps [MMSYSTEM.402]
3856 UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID, LPWAVEOUTCAPS16 lpCaps,
3857 UINT16 uSize)
3859 if (uDeviceID > waveOutGetNumDevs16() - 1) return MMSYSERR_BADDEVICEID;
3860 if (uDeviceID == (UINT16)WAVE_MAPPER) return MMSYSERR_BADDEVICEID; /* FIXME: do we have a wave mapper ? */
3861 TRACE("waveOutGetDevCaps\n");
3862 return wodMessage(uDeviceID, WODM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
3865 /**************************************************************************
3866 * waveOutGetDevCapsA [WINMM.162]
3868 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
3869 UINT uSize)
3871 WAVEOUTCAPS16 woc16;
3872 UINT16 ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3874 lpCaps->wMid = woc16.wMid;
3875 lpCaps->wPid = woc16.wPid;
3876 lpCaps->vDriverVersion = woc16.vDriverVersion;
3877 strcpy(lpCaps->szPname, woc16.szPname);
3878 lpCaps->dwFormats = woc16.dwFormats;
3879 lpCaps->wChannels = woc16.wChannels;
3880 lpCaps->dwSupport = woc16.dwSupport;
3881 return ret;
3884 /**************************************************************************
3885 * waveOutGetDevCapsW [WINMM.163]
3887 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
3888 UINT uSize)
3890 WAVEOUTCAPS16 woc16;
3891 UINT ret = waveOutGetDevCaps16(uDeviceID, &woc16, sizeof(woc16));
3893 lpCaps->wMid = woc16.wMid;
3894 lpCaps->wPid = woc16.wPid;
3895 lpCaps->vDriverVersion = woc16.vDriverVersion;
3896 lstrcpyAtoW(lpCaps->szPname, woc16.szPname);
3897 lpCaps->dwFormats = woc16.dwFormats;
3898 lpCaps->wChannels = woc16.wChannels;
3899 lpCaps->dwSupport = woc16.dwSupport;
3900 return ret;
3903 /**************************************************************************
3904 * waveOutGetErrorText [MMSYSTEM.403]
3906 UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
3908 TRACE("waveOutGetErrorText\n");
3909 return waveGetErrorText(uError, lpText, uSize);
3912 /**************************************************************************
3913 * waveOutGetErrorTextA [WINMM.164]
3915 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3917 return waveOutGetErrorText16(uError, lpText, uSize);
3920 /**************************************************************************
3921 * waveOutGetErrorTextW [WINMM.165]
3923 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3925 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
3926 UINT ret = waveOutGetErrorTextA(uError, xstr, uSize);
3928 lstrcpyAtoW(lpText, xstr);
3929 HeapFree(GetProcessHeap(), 0, xstr);
3930 return ret;
3933 /**************************************************************************
3934 * waveGetErrorText [internal]
3936 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
3938 LPSTR msgptr;
3939 TRACE("(%04X, %p, %d);\n",
3940 uError, lpText, uSize);
3941 if ((lpText == NULL) || (uSize < 1)) return(FALSE);
3942 lpText[0] = '\0';
3943 switch (uError) {
3944 case MMSYSERR_NOERROR:
3945 msgptr = "The specified command was carried out.";
3946 break;
3947 case MMSYSERR_ERROR:
3948 msgptr = "Undefined external error.";
3949 break;
3950 case MMSYSERR_BADDEVICEID:
3951 msgptr = "A device ID has been used that is out of range for your system.";
3952 break;
3953 case MMSYSERR_NOTENABLED:
3954 msgptr = "The driver was not enabled.";
3955 break;
3956 case MMSYSERR_ALLOCATED:
3957 msgptr = "The specified device is already in use. Wait until it is free, and then try again.";
3958 break;
3959 case MMSYSERR_INVALHANDLE:
3960 msgptr = "The specified device handle is invalid.";
3961 break;
3962 case MMSYSERR_NODRIVER:
3963 msgptr = "There is no driver installed on your system !\n";
3964 break;
3965 case MMSYSERR_NOMEM:
3966 msgptr = "Not enough memory available for this task. Quit one or more applications to increase available memory, and then try again.";
3967 break;
3968 case MMSYSERR_NOTSUPPORTED:
3969 msgptr = "This function is not supported. Use the Capabilities function to determine which functions and messages the driver supports.";
3970 break;
3971 case MMSYSERR_BADERRNUM:
3972 msgptr = "An error number was specified that is not defined in the system.";
3973 break;
3974 case MMSYSERR_INVALFLAG:
3975 msgptr = "An invalid flag was passed to a system function.";
3976 break;
3977 case MMSYSERR_INVALPARAM:
3978 msgptr = "An invalid parameter was passed to a system function.";
3979 break;
3980 case WAVERR_BADFORMAT:
3981 msgptr = "The specified format is not supported or cannot be translated. Use the Capabilities function to determine the supported formats";
3982 break;
3983 case WAVERR_STILLPLAYING:
3984 msgptr = "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing.";
3985 break;
3986 case WAVERR_UNPREPARED:
3987 msgptr = "The wave header was not prepared. Use the Prepare function to prepare the header, and then try again.";
3988 break;
3989 case WAVERR_SYNC:
3990 msgptr = "Cannot open the device without using the WAVE_ALLOWSYNC flag. Use the flag, and then try again.";
3991 break;
3992 default:
3993 msgptr = "Unknown MMSYSTEM Error !\n";
3994 break;
3996 lstrcpynA(lpText, msgptr, uSize);
3997 return TRUE;
4000 /**************************************************************************
4001 * waveOutOpen [WINMM.173]
4002 * All the args/structs have the same layout as the win16 equivalents
4004 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
4005 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4006 DWORD dwInstance, DWORD dwFlags)
4008 HWAVEOUT16 hwo16;
4009 UINT ret = waveOutOpen16(&hwo16, uDeviceID, lpFormat, dwCallback, dwInstance,
4010 CALLBACK32CONV(dwFlags));
4012 if (lphWaveOut) *lphWaveOut=hwo16;
4013 return ret;
4016 /**************************************************************************
4017 * waveOutOpen [MMSYSTEM.404]
4019 UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID,
4020 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
4021 DWORD dwInstance, DWORD dwFlags)
4023 HWAVEOUT16 hWaveOut;
4024 LPWAVEOPENDESC lpDesc;
4025 DWORD dwRet = MMSYSERR_NOERROR;
4026 BOOL bMapperFlg = FALSE;
4028 TRACE("(%p, %d, %p, %08lX, %08lX, %08lX);\n",
4029 lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
4030 if (dwFlags & WAVE_FORMAT_QUERY)
4031 TRACE("WAVE_FORMAT_QUERY requested !\n");
4032 if (uDeviceID == (UINT16)WAVE_MAPPER) {
4033 TRACE("WAVE_MAPPER mode requested !\n");
4034 bMapperFlg = TRUE;
4035 uDeviceID = 0;
4037 if (lpFormat == NULL) return WAVERR_BADFORMAT;
4039 hWaveOut = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
4040 if (hWaveOut == 0) return MMSYSERR_NOMEM;
4041 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4042 if (lpDesc == NULL) return MMSYSERR_NOMEM;
4043 lpDesc->hWave = hWaveOut;
4044 lpDesc->lpFormat = (LPWAVEFORMAT)lpFormat; /* should the struct be copied iso pointer? */
4045 lpDesc->dwCallBack = dwCallback;
4046 lpDesc->dwInstance = dwInstance;
4047 if (uDeviceID >= MAXWAVEDRIVERS)
4048 uDeviceID = 0;
4049 while (uDeviceID < MAXWAVEDRIVERS) {
4050 dwRet = wodMessage(uDeviceID, WODM_OPEN,
4051 lpDesc->dwInstance, (DWORD)lpDesc, dwFlags);
4052 if (dwRet == MMSYSERR_NOERROR) break;
4053 if (!bMapperFlg) break;
4054 uDeviceID++;
4055 TRACE("WAVE_MAPPER mode ! try next driver...\n");
4057 lpDesc->uDeviceID = uDeviceID; /* save physical Device ID */
4058 if (dwFlags & WAVE_FORMAT_QUERY) {
4059 TRACE("End of WAVE_FORMAT_QUERY !\n");
4060 USER_HEAP_FREE(hWaveOut);
4061 hWaveOut = 0;
4063 else if (dwRet != MMSYSERR_NOERROR)
4065 USER_HEAP_FREE(hWaveOut);
4066 hWaveOut = 0;
4068 if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
4069 TRACE("=> %ld\n", dwRet);
4070 return dwRet;
4073 /**************************************************************************
4074 * waveOutClose [WINMM.161]
4076 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
4078 return waveOutClose16(hWaveOut);
4081 /**************************************************************************
4082 * waveOutClose [MMSYSTEM.405]
4084 UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut)
4086 LPWAVEOPENDESC lpDesc;
4087 DWORD dwRet;
4089 TRACE("(%04X)\n", hWaveOut);
4091 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4092 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4093 dwRet = wodMessage(lpDesc->uDeviceID, WODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
4094 USER_HEAP_FREE(hWaveOut);
4095 return dwRet;
4098 /**************************************************************************
4099 * waveOutPrepareHeader [WINMM.175]
4101 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
4102 WAVEHDR* lpWaveOutHdr, UINT uSize)
4104 LPWAVEOPENDESC lpDesc;
4106 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4108 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4109 if (lpDesc == NULL)
4110 return MMSYSERR_INVALHANDLE;
4111 lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr;
4112 return wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance,
4113 (DWORD)lpWaveOutHdr, uSize);
4116 /**************************************************************************
4117 * waveOutPrepareHeader [MMSYSTEM.406]
4119 UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut,
4120 WAVEHDR* /*SEGPTR*/ _lpWaveOutHdr, UINT16 uSize)
4122 LPWAVEOPENDESC lpDesc;
4123 LPWAVEHDR lpWaveOutHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(_lpWaveOutHdr);
4124 UINT16 ret;
4126 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4128 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4129 if (lpDesc == NULL)
4130 return MMSYSERR_INVALHANDLE;
4131 lpWaveOutHdr->reserved = (DWORD)_lpWaveOutHdr;
4132 ret = wodMessage(lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance,
4133 (DWORD)lpWaveOutHdr, uSize);
4134 return ret;
4137 /**************************************************************************
4138 * waveOutUnprepareHeader [WINMM.181]
4140 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
4141 WAVEHDR* lpWaveOutHdr, UINT uSize)
4143 LPWAVEOPENDESC lpDesc;
4145 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4147 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4148 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4149 lpWaveOutHdr->reserved = (DWORD)lpWaveOutHdr;
4150 return wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance,
4151 (DWORD)lpWaveOutHdr, uSize);
4154 /**************************************************************************
4155 * waveOutUnprepareHeader [MMSYSTEM.407]
4157 UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut,
4158 WAVEHDR* lpWaveOutHdr, UINT16 uSize)
4160 LPWAVEOPENDESC lpDesc;
4161 UINT16 ret;
4163 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4165 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4166 if (lpDesc == NULL)
4167 return MMSYSERR_INVALHANDLE;
4168 ret = wodMessage(lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance,
4169 (DWORD)lpWaveOutHdr, uSize);
4170 return ret;
4173 /**************************************************************************
4174 * waveOutWrite [MMSYSTEM.408]
4176 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, WAVEHDR* lpWaveOutHdr,
4177 UINT uSize)
4179 LPWAVEOPENDESC lpDesc;
4181 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4183 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4184 if (lpDesc == NULL)
4185 return MMSYSERR_INVALHANDLE;
4186 return wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance,
4187 (DWORD)lpWaveOutHdr, uSize);
4190 /**************************************************************************
4191 * waveOutWrite [MMSYSTEM.408]
4193 UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, WAVEHDR* lpWaveOutHdr,
4194 UINT16 uSize)
4196 LPWAVEOPENDESC lpDesc;
4197 UINT16 ret;
4199 TRACE("(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
4201 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4202 if (lpDesc == NULL)
4203 return MMSYSERR_INVALHANDLE;
4204 ret = wodMessage(lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance, (DWORD)lpWaveOutHdr, uSize);
4205 return ret;
4208 /**************************************************************************
4209 * waveOutPause [WINMM.174]
4211 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
4213 return waveOutPause16(hWaveOut);
4216 /**************************************************************************
4217 * waveOutPause [MMSYSTEM.409]
4219 UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut)
4221 LPWAVEOPENDESC lpDesc;
4223 TRACE("(%04X)\n", hWaveOut);
4225 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4226 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4227 return wodMessage(lpDesc->uDeviceID, WODM_PAUSE, lpDesc->dwInstance, 0L, 0L);
4230 /**************************************************************************
4231 * waveOutRestart [WINMM.177]
4233 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
4235 return waveOutRestart16(hWaveOut);
4238 /**************************************************************************
4239 * waveOutRestart [MMSYSTEM.410]
4241 UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut)
4243 LPWAVEOPENDESC lpDesc;
4245 TRACE("(%04X)\n", hWaveOut);
4247 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4248 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4249 return wodMessage(lpDesc->uDeviceID, WODM_RESTART, lpDesc->dwInstance, 0L, 0L);
4252 /**************************************************************************
4253 * waveOutReset [WINMM.176]
4255 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
4257 return waveOutReset16(hWaveOut);
4260 /**************************************************************************
4261 * waveOutReset [MMSYSTEM.411]
4263 UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut)
4265 LPWAVEOPENDESC lpDesc;
4267 TRACE("(%04X)\n", hWaveOut);
4269 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4270 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4271 return wodMessage(lpDesc->uDeviceID, WODM_RESET, lpDesc->dwInstance, 0L, 0L);
4274 /**************************************************************************
4275 * waveOutGetPosition [WINMM.170]
4277 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
4278 UINT uSize)
4280 MMTIME16 mmt16;
4281 UINT ret;
4283 mmt16.wType = lpTime->wType;
4284 ret = waveOutGetPosition16(hWaveOut, &mmt16, sizeof(mmt16));
4285 MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
4286 return ret;
4289 /**************************************************************************
4290 * waveOutGetPosition [MMSYSTEM.412]
4292 UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime,
4293 UINT16 uSize)
4295 LPWAVEOPENDESC lpDesc;
4296 TRACE("(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
4297 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4298 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4299 return wodMessage(lpDesc->uDeviceID, WODM_GETPOS, lpDesc->dwInstance,
4300 (DWORD)lpTime, (DWORD)uSize);
4303 #define WAVEOUT_SHORTCUT_1(xx, XX, atype) \
4304 UINT WINAPI waveOut##xx(HWAVEOUT hWaveOut, atype x) \
4306 return waveOut##xx##16(hWaveOut, x); \
4308 UINT16 WINAPI waveOut##xx##16(HWAVEOUT16 hWaveOut, atype x) \
4310 LPWAVEOPENDESC lpDesc; \
4311 TRACE("(%04X, %08lx);\n", hWaveOut, (DWORD)x); \
4312 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut); \
4313 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE; \
4314 return wodMessage(lpDesc->uDeviceID, WODM_##XX, \
4315 lpDesc->dwInstance, (DWORD)x, 0L); \
4318 WAVEOUT_SHORTCUT_1(GetPitch, GETPITCH, LPDWORD)
4319 WAVEOUT_SHORTCUT_1(SetPitch, SETPITCH, DWORD)
4320 WAVEOUT_SHORTCUT_1(GetPlaybackRate, GETPLAYBACKRATE, LPDWORD)
4321 WAVEOUT_SHORTCUT_1(SetPlaybackRate, SETPLAYBACKRATE, DWORD)
4323 #define WAVEOUT_SHORTCUT_2(xx, XX, atype) \
4324 UINT WINAPI waveOut##xx(UINT devid, atype x) \
4326 return waveOut##xx##16(devid, x); \
4328 UINT16 WINAPI waveOut##xx##16(UINT16 devid, atype x) \
4330 TRACE("(%04X, %08lx);\n", devid, (DWORD)x); \
4331 return wodMessage(devid, WODM_##XX, 0, (DWORD)x, 0L); \
4334 WAVEOUT_SHORTCUT_2(GetVolume, GETVOLUME, LPDWORD)
4335 WAVEOUT_SHORTCUT_2(SetVolume, SETVOLUME, DWORD)
4337 /**************************************************************************
4338 * waveOutBreakLoop [MMSYSTEM.419]
4340 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
4342 return waveOutBreakLoop16(hWaveOut);
4345 /**************************************************************************
4346 * waveOutBreakLoop [MMSYSTEM.419]
4348 UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut)
4350 FIXME("(%04X)\n", hWaveOut);
4351 return MMSYSERR_INVALHANDLE;
4354 /**************************************************************************
4355 * waveOutGetID [MMSYSTEM.420]
4357 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
4359 LPWAVEOPENDESC lpDesc;
4361 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4363 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4364 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4365 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4366 *lpuDeviceID = lpDesc->uDeviceID;
4367 return 0;
4370 /**************************************************************************
4371 * waveOutGetID [MMSYSTEM.420]
4373 UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID)
4375 LPWAVEOPENDESC lpDesc;
4377 TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID);
4379 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4380 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4381 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4382 *lpuDeviceID = lpDesc->uDeviceID;
4383 return 0;
4386 /**************************************************************************
4387 * waveOutMessage [MMSYSTEM.421]
4389 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
4390 DWORD dwParam1, DWORD dwParam2)
4392 LPWAVEOPENDESC lpDesc;
4394 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4395 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4396 switch (uMessage) {
4397 case WODM_GETNUMDEVS:
4398 case WODM_GETPOS:
4399 case WODM_GETVOLUME:
4400 case WODM_GETPITCH:
4401 case WODM_GETPLAYBACKRATE:
4402 case WODM_SETVOLUME:
4403 case WODM_SETPITCH:
4404 case WODM_SETPLAYBACKRATE:
4405 case WODM_RESET:
4406 case WODM_PAUSE:
4407 case WODM_PREPARE:
4408 case WODM_UNPREPARE:
4409 case WODM_STOP:
4410 case WODM_CLOSE:
4411 /* no argument conversion needed */
4412 break;
4413 case WODM_WRITE:
4414 return waveOutWrite(hWaveOut, (LPWAVEHDR)dwParam1, dwParam2);
4415 case WODM_GETDEVCAPS:
4416 /* FIXME: UNICODE/ANSI? */
4417 return waveOutGetDevCapsA(hWaveOut, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
4418 case WODM_OPEN:
4419 FIXME("can't handle WODM_OPEN, please report.\n");
4420 break;
4421 default:
4422 ERR("(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
4423 hWaveOut, uMessage, dwParam1, dwParam2);
4424 break;
4426 return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4429 /**************************************************************************
4430 * waveOutMessage [MMSYSTEM.421]
4432 DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage,
4433 DWORD dwParam1, DWORD dwParam2)
4435 LPWAVEOPENDESC lpDesc;
4437 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
4438 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4439 switch (uMessage) {
4440 case WODM_GETNUMDEVS:
4441 case WODM_SETVOLUME:
4442 case WODM_SETPITCH:
4443 case WODM_SETPLAYBACKRATE:
4444 case WODM_RESET:
4445 case WODM_PAUSE:
4446 case WODM_STOP:
4447 case WODM_CLOSE:
4448 /* no argument conversion needed */
4449 break;
4450 case WODM_GETPOS:
4451 return waveOutGetPosition16(hWaveOut, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4452 case WODM_GETVOLUME:
4453 return waveOutGetVolume16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4454 case WODM_GETPITCH:
4455 return waveOutGetPitch16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4456 case WODM_GETPLAYBACKRATE:
4457 return waveOutGetPlaybackRate16(hWaveOut, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
4458 case WODM_GETDEVCAPS:
4459 return waveOutGetDevCaps16(hWaveOut, (LPWAVEOUTCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4460 case WODM_PREPARE:
4461 return waveOutPrepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4462 case WODM_UNPREPARE:
4463 return waveOutUnprepareHeader16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4464 case WODM_WRITE:
4465 return waveOutWrite16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4466 case WODM_OPEN:
4467 FIXME("can't handle WODM_OPEN, please report.\n");
4468 break;
4469 default:
4470 ERR("(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
4471 hWaveOut, uMessage, dwParam1, dwParam2);
4473 return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4476 /**************************************************************************
4477 * waveInGetNumDevs [WINMM.151]
4479 UINT WINAPI waveInGetNumDevs()
4481 return waveInGetNumDevs16();
4484 /**************************************************************************
4485 * waveInGetNumDevs [MMSYSTEM.501]
4487 UINT16 WINAPI waveInGetNumDevs16()
4489 UINT16 count = 0;
4491 TRACE("waveInGetNumDevs\n");
4492 count += widMessage(0, WIDM_GETNUMDEVS, 0L, 0L, 0L);
4493 TRACE("waveInGetNumDevs return %u \n", count);
4494 return count;
4497 /**************************************************************************
4498 * waveInGetDevCapsA [WINMM.147]
4500 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
4502 WAVEINCAPS16 wic16;
4503 UINT ret = waveInGetDevCaps16(uDeviceID, &wic16, uSize);
4505 lpCaps->wMid = wic16.wMid;
4506 lpCaps->wPid = wic16.wPid;
4507 lpCaps->vDriverVersion = wic16.vDriverVersion;
4508 lstrcpyAtoW(lpCaps->szPname, wic16.szPname);
4509 lpCaps->dwFormats = wic16.dwFormats;
4510 lpCaps->wChannels = wic16.wChannels;
4512 return ret;
4515 /**************************************************************************
4516 * waveInGetDevCapsA [WINMM.146]
4518 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
4520 WAVEINCAPS16 wic16;
4521 UINT ret = waveInGetDevCaps16(uDeviceID, &wic16, uSize);
4523 lpCaps->wMid = wic16.wMid;
4524 lpCaps->wPid = wic16.wPid;
4525 lpCaps->vDriverVersion = wic16.vDriverVersion;
4526 strcpy(lpCaps->szPname, wic16.szPname);
4527 lpCaps->dwFormats = wic16.dwFormats;
4528 lpCaps->wChannels = wic16.wChannels;
4529 return ret;
4532 /**************************************************************************
4533 * waveInGetDevCaps [MMSYSTEM.502]
4535 UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps, UINT16 uSize)
4537 TRACE("waveInGetDevCaps\n");
4539 return widMessage(uDeviceID, WIDM_GETDEVCAPS, 0L, (DWORD)lpCaps, uSize);
4542 /**************************************************************************
4543 * waveInGetErrorTextA [WINMM.148]
4545 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
4547 TRACE("waveInGetErrorText\n");
4548 return waveGetErrorText(uError, lpText, uSize);
4551 /**************************************************************************
4552 * waveInGetErrorTextW [WINMM.149]
4554 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
4556 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
4557 UINT ret = waveGetErrorText(uError, txt, uSize);
4559 lstrcpyAtoW(lpText, txt);
4560 HeapFree(GetProcessHeap(), 0, txt);
4561 return ret;
4564 /**************************************************************************
4565 * waveInGetErrorText [MMSYSTEM.503]
4567 UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize)
4569 TRACE("waveInGetErrorText\n");
4570 return waveGetErrorText(uError, lpText, uSize);
4573 /**************************************************************************
4574 * waveInOpen [WINMM.154]
4576 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
4577 const LPWAVEFORMAT lpFormat, DWORD dwCallback,
4578 DWORD dwInstance, DWORD dwFlags)
4580 HWAVEIN16 hwin16;
4581 UINT ret = waveInOpen16(&hwin16, uDeviceID, lpFormat, dwCallback, dwInstance,
4582 CALLBACK32CONV(dwFlags));
4583 if (lphWaveIn) *lphWaveIn = hwin16;
4584 return ret;
4587 /**************************************************************************
4588 * waveInOpen [MMSYSTEM.504]
4590 UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID,
4591 const LPWAVEFORMAT lpFormat, DWORD dwCallback,
4592 DWORD dwInstance, DWORD dwFlags)
4594 HWAVEIN16 hWaveIn;
4595 LPWAVEOPENDESC lpDesc;
4596 DWORD dwRet = 0;
4597 BOOL bMapperFlg = FALSE;
4599 TRACE("(%p, %d, %p, %08lX, %08lX, %08lX);\n",
4600 lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
4601 if (dwFlags & WAVE_FORMAT_QUERY)
4602 TRACE("WAVE_FORMAT_QUERY requested !\n");
4603 if (uDeviceID == (UINT16)WAVE_MAPPER) {
4604 TRACE("WAVE_MAPPER mode requested !\n");
4605 bMapperFlg = TRUE;
4606 uDeviceID = 0;
4608 if (lpFormat == NULL) return WAVERR_BADFORMAT;
4609 hWaveIn = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
4610 if (lphWaveIn != NULL) *lphWaveIn = hWaveIn;
4611 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4612 if (lpDesc == NULL) return MMSYSERR_NOMEM;
4613 lpDesc->hWave = hWaveIn;
4614 lpDesc->lpFormat = lpFormat;
4615 lpDesc->dwCallBack = dwCallback;
4616 lpDesc->dwInstance = dwInstance;
4617 while (uDeviceID < MAXWAVEDRIVERS) {
4618 dwRet = widMessage(uDeviceID, WIDM_OPEN,
4619 lpDesc->dwInstance, (DWORD)lpDesc, 0L);
4620 if (dwRet == MMSYSERR_NOERROR) break;
4621 if (!bMapperFlg) break;
4622 uDeviceID++;
4623 TRACE("WAVE_MAPPER mode ! try next driver...\n");
4625 lpDesc->uDeviceID = uDeviceID;
4626 if (dwFlags & WAVE_FORMAT_QUERY) {
4627 TRACE("End of WAVE_FORMAT_QUERY !\n");
4628 dwRet = waveInClose16(hWaveIn);
4629 } else if (dwRet != MMSYSERR_NOERROR) {
4630 USER_HEAP_FREE(hWaveIn);
4631 if (lphWaveIn) *lphWaveIn = 0;
4634 return dwRet;
4637 /**************************************************************************
4638 * waveInClose [WINMM.145]
4640 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
4642 return waveInClose16(hWaveIn);
4645 /**************************************************************************
4646 * waveInClose [MMSYSTEM.505]
4648 UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn)
4650 LPWAVEOPENDESC lpDesc;
4651 DWORD dwRet;
4653 TRACE("(%04X)\n", hWaveIn);
4654 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4655 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4656 dwRet = widMessage(lpDesc->uDeviceID, WIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
4657 USER_HEAP_FREE(hWaveIn);
4658 return dwRet;
4661 /**************************************************************************
4662 * waveInPrepareHeader [WINMM.155]
4664 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn,
4665 WAVEHDR* lpWaveInHdr, UINT uSize)
4667 LPWAVEOPENDESC lpDesc;
4669 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4670 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4671 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4672 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4673 lpWaveInHdr->lpNext = NULL;
4674 lpWaveInHdr->dwBytesRecorded = 0;
4675 lpWaveInHdr->reserved = (DWORD)lpWaveInHdr;
4677 return widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance,
4678 (DWORD)lpWaveInHdr, uSize);
4681 /**************************************************************************
4682 * waveInPrepareHeader [MMSYSTEM.506]
4684 UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn,
4685 WAVEHDR* /* SEGPTR */ _lpWaveInHdr, UINT16 uSize)
4687 LPWAVEOPENDESC lpDesc;
4688 LPWAVEHDR lpWaveInHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(_lpWaveInHdr);
4689 UINT16 ret;
4691 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4693 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4694 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4695 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4697 lpWaveInHdr->lpNext = NULL;
4698 lpWaveInHdr->dwBytesRecorded = 0;
4700 lpWaveInHdr->reserved = (DWORD)_lpWaveInHdr;
4702 ret = widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance,
4703 (DWORD)lpWaveInHdr, uSize);
4704 return ret;
4707 /**************************************************************************
4708 * waveInUnprepareHeader [WINMM.159]
4710 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn,
4711 WAVEHDR* lpWaveInHdr, UINT uSize)
4713 LPWAVEOPENDESC lpDesc;
4715 TRACE("(%04X, %p, %u);\n",
4716 hWaveIn, lpWaveInHdr, uSize);
4717 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4718 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4719 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4721 lpWaveInHdr->lpNext = NULL;
4722 return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance,
4723 (DWORD)lpWaveInHdr, uSize);
4726 /**************************************************************************
4727 * waveInUnprepareHeader [MMSYSTEM.507]
4729 UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn,
4730 WAVEHDR* lpWaveInHdr, UINT16 uSize)
4732 LPWAVEOPENDESC lpDesc;
4734 TRACE("(%04X, %p, %u);\n",
4735 hWaveIn, lpWaveInHdr, uSize);
4736 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4737 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4738 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4740 return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance,
4741 (DWORD)lpWaveInHdr, uSize);
4744 /**************************************************************************
4745 * waveInAddBuffer [WINMM.144]
4747 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
4748 WAVEHDR* lpWaveInHdr, UINT uSize)
4750 LPWAVEOPENDESC lpDesc;
4752 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4754 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4755 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4756 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4758 lpWaveInHdr->lpNext = NULL;
4759 lpWaveInHdr->dwBytesRecorded = 0;
4761 return widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
4762 (DWORD)lpWaveInHdr, uSize);
4766 /**************************************************************************
4767 * waveInAddBuffer [MMSYSTEM.508]
4769 UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn,
4770 WAVEHDR* lpWaveInHdr, UINT16 uSize)
4772 LPWAVEOPENDESC lpDesc;
4773 UINT16 ret;
4775 TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
4777 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4778 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4779 if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE;
4780 lpWaveInHdr->lpNext = NULL;
4781 lpWaveInHdr->dwBytesRecorded = 0;
4783 ret = widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
4784 (DWORD)lpWaveInHdr, uSize);
4785 return ret;
4788 /**************************************************************************
4789 * waveInStart [WINMM.157]
4791 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
4793 return waveInStart16(hWaveIn);
4796 /**************************************************************************
4797 * waveInStart [MMSYSTEM.509]
4799 UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn)
4801 LPWAVEOPENDESC lpDesc;
4803 TRACE("(%04X)\n", hWaveIn);
4804 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4805 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4806 return widMessage(lpDesc->uDeviceID, WIDM_START, lpDesc->dwInstance, 0, 0);
4809 /**************************************************************************
4810 * waveInStop [WINMM.158]
4812 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
4814 return waveInStop16(hWaveIn);
4817 /**************************************************************************
4818 * waveInStop [MMSYSTEM.510]
4820 UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn)
4822 LPWAVEOPENDESC lpDesc;
4824 TRACE("(%04X)\n", hWaveIn);
4825 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4826 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4827 return widMessage(lpDesc->uDeviceID, WIDM_STOP, lpDesc->dwInstance, 0L, 0L);
4830 /**************************************************************************
4831 * waveInReset [WINMM.156]
4833 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
4835 return waveInReset16(hWaveIn);
4838 /**************************************************************************
4839 * waveInReset [MMSYSTEM.511]
4841 UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn)
4843 LPWAVEOPENDESC lpDesc;
4845 TRACE("(%04X)\n", hWaveIn);
4846 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4847 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4848 return widMessage(lpDesc->uDeviceID, WIDM_RESET, lpDesc->dwInstance, 0, 0);
4851 /**************************************************************************
4852 * waveInGetPosition [WINMM.152]
4854 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
4855 UINT uSize)
4857 MMTIME16 mmt16;
4858 UINT ret;
4860 mmt16.wType = lpTime->wType;
4861 ret = waveInGetPosition16(hWaveIn, &mmt16, uSize);
4863 MMSYSTEM_MMTIME16to32(lpTime, &mmt16);
4864 return ret;
4867 /**************************************************************************
4868 * waveInGetPosition [MMSYSTEM.512]
4870 UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime,
4871 UINT16 uSize)
4873 LPWAVEOPENDESC lpDesc;
4875 TRACE("(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
4876 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4877 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4878 return widMessage(lpDesc->uDeviceID, WIDM_GETPOS, lpDesc->dwInstance,
4879 (DWORD)lpTime, (DWORD)uSize);
4882 /**************************************************************************
4883 * waveInGetID [WINMM.150]
4885 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
4887 LPWAVEOPENDESC lpDesc;
4889 TRACE("waveInGetID\n");
4890 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4891 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4892 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4893 *lpuDeviceID = lpDesc->uDeviceID;
4894 return 0;
4897 /**************************************************************************
4898 * waveInGetID [MMSYSTEM.513]
4900 UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID)
4902 LPWAVEOPENDESC lpDesc;
4904 TRACE("waveInGetID\n");
4905 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
4906 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4907 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4908 *lpuDeviceID = lpDesc->uDeviceID;
4909 return 0;
4912 /**************************************************************************
4913 * waveInMessage [WINMM.153]
4915 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
4916 DWORD dwParam1, DWORD dwParam2)
4918 LPWAVEOPENDESC lpDesc;
4920 FIXME("(%04X, %04X, %08lX, %08lX)\n",
4921 hWaveIn, uMessage, dwParam1, dwParam2);
4922 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4923 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4924 switch (uMessage) {
4925 case WIDM_OPEN:
4926 FIXME("cannot handle WIDM_OPEN, please report.\n");
4927 break;
4928 case WIDM_GETNUMDEVS:
4929 case WIDM_GETPOS:
4930 case WIDM_CLOSE:
4931 case WIDM_STOP:
4932 case WIDM_RESET:
4933 case WIDM_START:
4934 case WIDM_PREPARE:
4935 case WIDM_UNPREPARE:
4936 case WIDM_ADDBUFFER:
4937 case WIDM_PAUSE:
4938 /* no argument conversion needed */
4939 break;
4940 case WIDM_GETDEVCAPS:
4941 /*FIXME: ANSI/UNICODE */
4942 return waveInGetDevCapsA(hWaveIn, (LPWAVEINCAPSA)dwParam1, dwParam2);
4943 default:
4944 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
4945 hWaveIn, uMessage, dwParam1, dwParam2);
4946 break;
4948 return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4951 /**************************************************************************
4952 * waveInMessage [MMSYSTEM.514]
4954 DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage,
4955 DWORD dwParam1, DWORD dwParam2)
4957 LPWAVEOPENDESC lpDesc;
4959 FIXME("(%04X, %04X, %08lX, %08lX)\n",
4960 hWaveIn, uMessage, dwParam1, dwParam2);
4961 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
4962 if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
4963 switch (uMessage) {
4964 case WIDM_OPEN:
4965 FIXME("cannot handle WIDM_OPEN, please report.\n");
4966 break;
4967 case WIDM_GETNUMDEVS:
4968 case WIDM_CLOSE:
4969 case WIDM_STOP:
4970 case WIDM_RESET:
4971 case WIDM_START:
4972 case WIDM_PAUSE:
4973 /* no argument conversion needed */
4974 break;
4975 case WIDM_GETDEVCAPS:
4976 return waveInGetDevCaps16(hWaveIn, (LPWAVEINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4977 case WIDM_GETPOS:
4978 return waveInGetPosition16(hWaveIn, (LPMMTIME16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4979 case WIDM_PREPARE:
4980 return waveInPrepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4981 case WIDM_UNPREPARE:
4982 return waveInUnprepareHeader16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4983 case WIDM_ADDBUFFER:
4984 return waveInAddBuffer16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
4985 default:
4986 ERR("(%04x, %04x, %08lx, %08lx): unhandled message\n",
4987 hWaveIn, uMessage, dwParam1, dwParam2);
4988 break;
4990 return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
4993 /**************************************************************************
4994 * DrvOpen [MMSYSTEM.1100]
4996 HDRVR16 WINAPI DrvOpen(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam)
4998 TRACE("('%s','%s', %08lX);\n", lpDriverName, lpSectionName, lParam);
5000 return OpenDriver16(lpDriverName, lpSectionName, lParam);
5003 /**************************************************************************
5004 * DrvClose [MMSYSTEM.1101]
5006 LRESULT WINAPI DrvClose(HDRVR16 hDrv, LPARAM lParam1, LPARAM lParam2)
5008 TRACE("(%04X, %08lX, %08lX);\n", hDrv, lParam1, lParam2);
5010 return CloseDriver16(hDrv, lParam1, lParam2);
5013 /**************************************************************************
5014 * DrvSendMessage [MMSYSTEM.1102]
5016 LRESULT WINAPI DrvSendMessage(HDRVR16 hDrv, WORD msg, LPARAM lParam1,
5017 LPARAM lParam2)
5019 return SendDriverMessage(hDrv, msg, lParam1, lParam2);
5022 /**************************************************************************
5023 * DrvGetModuleHandle [MMSYSTEM.1103]
5025 HANDLE16 WINAPI DrvGetModuleHandle16(HDRVR16 hDrv)
5027 return GetDriverModuleHandle16(hDrv);
5030 /**************************************************************************
5031 * DrvDefDriverProc [MMSYSTEM.1104]
5033 LRESULT WINAPI DrvDefDriverProc(DWORD dwDriverID, HDRVR16 hDrv, WORD wMsg,
5034 DWORD dwParam1, DWORD dwParam2)
5036 /* FIXME : any mapping from 32 to 16 bit structure ? */
5037 return DefDriverProc16(dwDriverID, hDrv, wMsg, dwParam1, dwParam2);
5040 /**************************************************************************
5041 * DefDriverProc [WINMM.5]
5043 LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR hDrv,
5044 UINT Msg, LPARAM lParam1, LPARAM lParam2)
5046 switch (Msg) {
5047 case DRV_LOAD:
5048 case DRV_FREE:
5049 case DRV_ENABLE:
5050 case DRV_DISABLE:
5051 return 1;
5052 case DRV_INSTALL:
5053 case DRV_REMOVE:
5054 return DRV_SUCCESS;
5055 default:
5056 return 0;
5060 /*#define USE_MM_TSK_WINE*/
5062 /**************************************************************************
5063 * mmTaskCreate [MMSYSTEM.900]
5065 * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be
5066 * called upon creation with dwPmt as parameter.
5068 HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt)
5070 DWORD showCmd = 0x40002;
5071 LPSTR cmdline;
5072 WORD sel1, sel2;
5073 LOADPARAMS16* lp;
5074 HINSTANCE16 ret;
5075 HINSTANCE16 handle;
5077 TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
5078 /* This to work requires NE modules to be started with a binary command line
5079 * which is not currently the case. A patch exists but has never been committed.
5080 * A workaround would be to integrate code for mmtask.tsk into Wine, but
5081 * this requires tremendous work (starting with patching tools/build to
5082 * create NE executables (and not only DLLs) for builtins modules.
5083 * EP 99/04/25
5085 FIXME("This is currently broken. It will fail\n");
5087 cmdline = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 0x0d);
5088 cmdline[0] = 0x0d;
5089 *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
5090 *(LPDWORD)(cmdline + 5) = dwPmt;
5091 *(LPDWORD)(cmdline + 9) = 0;
5093 sel1 = SELECTOR_AllocBlock(cmdline, 0x0d, SEGMENT_DATA, FALSE, FALSE);
5094 sel2 = SELECTOR_AllocBlock(&showCmd, sizeof(showCmd),
5095 SEGMENT_DATA, FALSE, FALSE);
5097 lp = (LOADPARAMS16*)HeapAlloc(GetProcessHeap(), 0, sizeof(LOADPARAMS16));
5098 lp->hEnvironment = 0;
5099 lp->cmdLine = PTR_SEG_OFF_TO_SEGPTR(sel1, 0);
5100 lp->showCmd = PTR_SEG_OFF_TO_SEGPTR(sel2, 0);
5101 lp->reserved = 0;
5103 #ifndef USE_MM_TSK_WINE
5104 handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", lp);
5105 #else
5106 handle = LoadModule16("mmtask.tsk", lp);
5107 #endif
5108 if (handle < 32) {
5109 ret = (handle) ? 1 : 2;
5110 handle = 0;
5111 } else {
5112 ret = 0;
5114 if (lphMmTask)
5115 *lphMmTask = handle;
5117 UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel2, 0));
5118 UnMapLS(PTR_SEG_OFF_TO_SEGPTR(sel1, 0));
5120 HeapFree(GetProcessHeap(), 0, lp);
5121 HeapFree(GetProcessHeap(), 0, cmdline);
5123 TRACE("=> 0x%04x/%d\n", handle, ret);
5124 return ret;
5127 #ifdef USE_MM_TSK_WINE
5128 /* C equivalent to mmtask.tsk binary content */
5129 void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
5131 int len = cmdLine[0x80];
5133 if (len / 2 == 6) {
5134 void (*fpProc)(DWORD) = (void (*)(DWORD))PTR_SEG_TO_LIN(*((DWORD*)(cmdLine + 1)));
5135 DWORD dwPmt = *((DWORD*)(cmdLine + 5));
5137 #if 0
5138 InitTask16(); /* fixme: pmts / from context ? */
5139 InitApp(di);
5140 #endif
5141 if (SetMessageQueue16(0x40)) {
5142 WaitEvent16(0);
5143 if (HIWORD(fpProc)) {
5144 OldYield16();
5145 /* EPP StackEnter16(); */
5146 (fpProc)(dwPmt);
5150 OldYield16();
5151 OldYield16();
5152 OldYield16();
5153 ExitProcess(0);
5155 #endif
5157 /**************************************************************************
5158 * mmTaskBlock [MMSYSTEM.902]
5160 void WINAPI mmTaskBlock16(HINSTANCE16 WINE_UNUSED hInst)
5162 MSG msg;
5164 do {
5165 GetMessageA(&msg, 0, 0, 0);
5166 if (msg.hwnd) {
5167 TranslateMessage(&msg);
5168 DispatchMessageA(&msg);
5170 } while (msg.message < 0x3A0);
5173 /**************************************************************************
5174 * mmTaskSignal [MMSYSTEM.903]
5176 LRESULT WINAPI mmTaskSignal16(HTASK16 ht)
5178 TRACE("(%04x);\n", ht);
5179 return Callout.PostAppMessage16(ht, WM_USER, 0, 0);
5182 /**************************************************************************
5183 * mmTaskYield16 [MMSYSTEM.905]
5185 void WINAPI mmTaskYield16(void)
5187 MSG msg;
5189 if (PeekMessageA(&msg, 0, 0, 0, 0)) {
5190 Yield16();
5194 DWORD WINAPI GetProcessFlags(DWORD);
5196 /**************************************************************************
5197 * mmThreadCreate [MMSYSTEM.1120]
5199 * undocumented
5200 * Creates a MM thread, calling fpThreadAddr(dwPmt).
5201 * dwFlags:
5202 * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
5203 * bit.1 set means to open a VxD for this thread (unsupported)
5205 LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags)
5207 HANDLE16 hndl;
5208 LRESULT ret;
5210 TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
5212 hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
5214 if (hndl == 0) {
5215 ret = 2;
5216 } else {
5217 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5219 #if 0
5220 /* force mmtask routines even if mmthread is required */
5221 /* this will work only if the patch about binary cmd line and NE tasks
5222 * is committed
5224 dwFlags |= 1;
5225 #endif
5227 lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
5228 lpMMThd->dwCounter = 0;
5229 lpMMThd->hThread = 0;
5230 lpMMThd->dwThreadID = 0;
5231 lpMMThd->fpThread = fpThreadAddr;
5232 lpMMThd->dwThreadPmt = dwPmt;
5233 lpMMThd->dwSignalCount = 0;
5234 lpMMThd->hEvent = 0;
5235 lpMMThd->hVxD = 0;
5236 lpMMThd->dwStatus = 0;
5237 lpMMThd->dwFlags = dwFlags;
5238 lpMMThd->hTask = 0;
5240 if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
5241 lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
5243 TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
5244 if (lpMMThd->dwFlags & 2) {
5245 /* as long as we don't support MM VxD in wine, we don't need
5246 * to care about this flag
5248 /* FIXME("Don't know how to properly open VxD handles\n"); */
5249 /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
5252 lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint,
5253 (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
5254 if (lpMMThd->hThread == 0) {
5255 WARN("Couldn't create thread\n");
5256 /* clean-up(VxDhandle...); devicedirectio... */
5257 if (lpMMThd->hEvent != 0)
5258 CloseHandle(lpMMThd->hEvent);
5259 ret = 2;
5260 } else {
5261 TRACE("Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
5262 ret = 0;
5264 } else {
5265 /* get WINE_mmThreadEntryPoint()
5266 * 2047 is its ordinal in mmsystem.spec
5268 FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (SEGPTR)2047);
5270 TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, PTR_SEG_TO_LIN(fp));
5272 ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
5275 if (ret == 0) {
5276 if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
5277 WARN("Couldn't resume thread\n");
5279 while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
5280 UserYield16();
5285 if (ret != 0) {
5286 GlobalFree16(hndl);
5287 hndl = 0;
5290 if (lpHndl)
5291 *lpHndl = hndl;
5293 TRACE("ok => %ld\n", ret);
5294 return ret;
5297 /**************************************************************************
5298 * mmThreadSignal [MMSYSTEM.1121]
5300 void WINAPI mmThreadSignal16(HANDLE16 hndl)
5302 TRACE("(%04x)!\n", hndl);
5304 if (hndl) {
5305 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5307 lpMMThd->dwCounter++;
5308 if (lpMMThd->hThread != 0) {
5309 InterlockedIncrement(&lpMMThd->dwSignalCount);
5310 SetEvent(lpMMThd->hEvent);
5311 } else {
5312 mmTaskSignal16(lpMMThd->hTask);
5314 lpMMThd->dwCounter--;
5318 /**************************************************************************
5319 * MMSYSTEM_ThreadBlock [internal]
5321 static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
5323 MSG msg;
5324 DWORD ret;
5326 if (lpMMThd->dwThreadID != GetCurrentThreadId())
5327 ERR("Not called by thread itself\n");
5329 for (;;) {
5330 ResetEvent(lpMMThd->hEvent);
5331 if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
5332 break;
5333 InterlockedIncrement(&lpMMThd->dwSignalCount);
5335 TRACE("S1\n");
5337 ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
5338 switch (ret) {
5339 case WAIT_OBJECT_0: /* Event */
5340 TRACE("S2.1\n");
5341 break;
5342 case WAIT_OBJECT_0 + 1: /* Msg */
5343 TRACE("S2.2\n");
5344 if (Callout.PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
5345 Callout.TranslateMessage(&msg);
5346 Callout.DispatchMessageA(&msg);
5348 break;
5349 default:
5350 WARN("S2.x unsupported ret val 0x%08lx\n", ret);
5352 TRACE("S3\n");
5356 /**************************************************************************
5357 * mmThreadBlock [MMSYSTEM.1122]
5359 void WINAPI mmThreadBlock16(HANDLE16 hndl)
5361 TRACE("(%04x)!\n", hndl);
5363 if (hndl) {
5364 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5366 if (lpMMThd->hThread != 0) {
5367 SYSLEVEL_ReleaseWin16Lock();
5368 MMSYSTEM_ThreadBlock(lpMMThd);
5369 SYSLEVEL_RestoreWin16Lock();
5370 } else {
5371 mmTaskBlock16(lpMMThd->hTask);
5374 TRACE("done\n");
5377 /**************************************************************************
5378 * mmThreadIsCurrent [MMSYSTEM.1123]
5380 BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl)
5382 BOOL16 ret = FALSE;
5384 TRACE("(%04x)!\n", hndl);
5386 if (hndl && mmThreadIsValid16(hndl)) {
5387 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5388 ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
5389 #if 1 /* EPP */
5390 /* FIXME: just a test */
5391 SYSLEVEL_ReleaseWin16Lock();
5392 SYSLEVEL_RestoreWin16Lock();
5393 #endif
5395 TRACE("=> %d\n", ret);
5396 return ret;
5399 /**************************************************************************
5400 * mmThreadIsValid [MMSYSTEM.1124]
5402 BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl)
5404 BOOL16 ret = FALSE;
5406 TRACE("(%04x)!\n", hndl);
5408 if (hndl) {
5409 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5411 if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
5412 lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
5413 IsTask16(lpMMThd->hTask)) {
5414 lpMMThd->dwCounter++;
5415 if (lpMMThd->hThread != 0) {
5416 DWORD dwThreadRet;
5417 if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
5418 dwThreadRet == STATUS_PENDING) {
5419 ret = TRUE;
5421 } else {
5422 ret = TRUE;
5424 lpMMThd->dwCounter--;
5427 TRACE("=> %d\n", ret);
5428 return ret;
5431 /**************************************************************************
5432 * mmThreadGetTask [MMSYSTEM.1125]
5434 HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl)
5436 HANDLE16 ret = 0;
5438 TRACE("(%04x)\n", hndl);
5440 if (mmThreadIsValid16(hndl)) {
5441 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5442 ret = lpMMThd->hTask;
5444 return ret;
5447 /**************************************************************************
5448 * mmThreadGetTask [internal]
5450 void CALLBACK WINE_mmThreadEntryPoint(DWORD _pmt)
5452 HANDLE16 hndl = (HANDLE16)_pmt;
5453 WINE_MMTHREAD* lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
5455 TRACE("(%04x %p)\n", hndl, lpMMThd);
5457 lpMMThd->hTask = LOWORD(GetCurrentTask());
5458 TRACE("[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
5459 lpMMThd->dwStatus = 0x10;
5460 MMSYSTEM_ThreadBlock(lpMMThd);
5461 TRACE("[20-%08x]\n", lpMMThd->hThread);
5462 lpMMThd->dwStatus = 0x20;
5463 if (lpMMThd->fpThread) {
5464 Callbacks->CallWOWCallbackProc(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
5466 lpMMThd->dwStatus = 0x30;
5467 TRACE("[30-%08x]\n", lpMMThd->hThread);
5468 while (lpMMThd->dwCounter) {
5469 Sleep(1);
5470 /* Yield16();*/
5472 TRACE("[XX-%08x]\n", lpMMThd->hThread);
5473 /* paranoia */
5474 lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
5475 /* close lpMMThread->hVxD directio */
5476 if (lpMMThd->hEvent)
5477 CloseHandle(lpMMThd->hEvent);
5478 GlobalFree16(hndl);
5479 TRACE("done\n");
5482 typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR);
5484 /**************************************************************************
5485 * mmShowMMCPLPropertySheet [MMSYSTEM.1150]
5487 BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice,
5488 LPCSTR lpStrTab, LPCSTR lpStrTitle)
5490 HANDLE hndl;
5491 BOOL16 ret = FALSE;
5493 TRACE("(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5495 hndl = LoadLibraryA("MMSYS.CPL");
5496 if (hndl != 0) {
5497 MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet");
5498 if (fp != NULL) {
5499 SYSLEVEL_ReleaseWin16Lock();
5500 ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
5501 SYSLEVEL_RestoreWin16Lock();
5503 FreeLibrary(hndl);
5506 return ret;
5509 /**************************************************************************
5510 * StackEnter & StackLeave [MMSYSTEM.32][MMSYSTEM.33]
5512 void WINAPI StackEnterLeave16(void)
5514 #ifdef __i386__
5515 /* mmsystem.dll from Win 95 does only this: so does Wine */
5516 __asm__("stc");
5517 #endif