1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1993 Martin Ayotte
7 * 1998-2002 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * 98/9 added Win32 MCI support
27 * 99/4 added midiStream support
28 * 99/9 added support for loadable low level drivers
32 * + it seems that some programs check what's installed in
33 * registry against the value returned by drivers. Wine is
34 * currently broken regarding this point.
35 * + check thread-safeness for MMSYSTEM and WINMM entry points
36 * + unicode entry points are badly supported (would require
37 * moving 32 bit drivers as Unicode as they are supposed to be)
38 * + allow joystick and timer external calls as we do for wave,
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
62 /******************************************************************
65 * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32).
67 static void MyUserYield(void)
69 HMODULE mod = GetModuleHandleA( "user32.dll" );
72 FARPROC proc = GetProcAddress( mod, "UserYield16" );
77 void (WINAPI *pFnReleaseThunkLock)(DWORD*);
78 void (WINAPI *pFnRestoreThunkLock)(DWORD);
80 /* ========================================================================
81 * G L O B A L S E T T I N G S
82 * ========================================================================*/
84 LPWINE_MM_IDATA WINMM_IData /* = NULL */;
86 /**************************************************************************
87 * WINMM_CreateIData [internal]
89 static BOOL WINMM_CreateIData(HINSTANCE hInstDLL)
91 WINMM_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
95 WINMM_IData->hWinMM32Instance = hInstDLL;
96 InitializeCriticalSection(&WINMM_IData->cs);
97 WINMM_IData->cs.DebugInfo->Spare[1] = (DWORD)"WINMM_IData";
98 WINMM_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
99 WINMM_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
100 TRACE("Created IData (%p)\n", WINMM_IData);
104 /**************************************************************************
105 * WINMM_DeleteIData [internal]
107 static void WINMM_DeleteIData(void)
112 /* FIXME: should also free content and resources allocated
113 * inside WINMM_IData */
114 CloseHandle(WINMM_IData->psStopEvent);
115 CloseHandle(WINMM_IData->psLastEvent);
116 DeleteCriticalSection(&WINMM_IData->cs);
117 HeapFree(GetProcessHeap(), 0, WINMM_IData);
122 /******************************************************************
126 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR);
127 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR);
129 BOOL WINMM_CheckForMMSystem(void)
131 /* 0 is not checked yet, -1 is not present, 1 is present */
132 static int loaded /* = 0 */;
136 HANDLE h = GetModuleHandleA("kernel32");
140 pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16");
141 pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16");
142 if (pGetModuleHandle16 && pLoadLibrary16 &&
143 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
150 /******************************************************************
151 * WINMM_ErrorToString
153 const char* WINMM_ErrorToString(MMRESULT error)
155 #define ERR_TO_STR(dev) case dev: return #dev
156 static char unknown[32];
158 ERR_TO_STR(MMSYSERR_NOERROR);
159 ERR_TO_STR(MMSYSERR_ERROR);
160 ERR_TO_STR(MMSYSERR_BADDEVICEID);
161 ERR_TO_STR(MMSYSERR_NOTENABLED);
162 ERR_TO_STR(MMSYSERR_ALLOCATED);
163 ERR_TO_STR(MMSYSERR_INVALHANDLE);
164 ERR_TO_STR(MMSYSERR_NODRIVER);
165 ERR_TO_STR(MMSYSERR_NOMEM);
166 ERR_TO_STR(MMSYSERR_NOTSUPPORTED);
167 ERR_TO_STR(MMSYSERR_BADERRNUM);
168 ERR_TO_STR(MMSYSERR_INVALFLAG);
169 ERR_TO_STR(MMSYSERR_INVALPARAM);
170 ERR_TO_STR(WAVERR_BADFORMAT);
171 ERR_TO_STR(WAVERR_STILLPLAYING);
172 ERR_TO_STR(WAVERR_UNPREPARED);
173 ERR_TO_STR(WAVERR_SYNC);
175 sprintf(unknown, "Unknown(0x%08x)", error);
180 /**************************************************************************
181 * DllMain (WINMM.init)
183 * WINMM DLL entry point
186 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
188 TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
191 case DLL_PROCESS_ATTACH:
192 DisableThreadLibraryCalls(hInstDLL);
194 if (!WINMM_CreateIData(hInstDLL))
201 case DLL_PROCESS_DETACH:
202 /* close all opened MCI drivers */
203 MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE);
205 /* now unload all remaining drivers... */
214 /**************************************************************************
215 * Mixer devices. New to Win95
218 /**************************************************************************
219 * find out the real mixer ID depending on hmix (depends on dwFlags)
221 static UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm)
223 LPWINE_MIXER lpwm = NULL;
224 UINT uRet = MMSYSERR_NOERROR;
226 switch (dwFlags & 0xF0000000ul) {
227 case MIXER_OBJECTF_MIXER:
228 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
230 case MIXER_OBJECTF_HMIXER:
231 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
233 case MIXER_OBJECTF_WAVEOUT:
234 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
236 case MIXER_OBJECTF_HWAVEOUT:
237 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
239 case MIXER_OBJECTF_WAVEIN:
240 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
242 case MIXER_OBJECTF_HWAVEIN:
243 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
245 case MIXER_OBJECTF_MIDIOUT:
246 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
248 case MIXER_OBJECTF_HMIDIOUT:
249 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
251 case MIXER_OBJECTF_MIDIIN:
252 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
254 case MIXER_OBJECTF_HMIDIIN:
255 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
257 case MIXER_OBJECTF_AUX:
258 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
261 WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
263 uRet = MMSYSERR_INVALFLAG;
267 if (lpwm == 0 && uRet == MMSYSERR_NOERROR)
268 uRet = MMSYSERR_INVALPARAM;
272 /**************************************************************************
273 * mixerGetNumDevs [WINMM.@]
275 UINT WINAPI mixerGetNumDevs(void)
277 return MMDRV_GetNum(MMDRV_MIXER);
280 /**************************************************************************
281 * mixerGetDevCapsA [WINMM.@]
283 UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize)
287 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
289 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL)
290 return MMSYSERR_BADDEVICEID;
292 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
295 /**************************************************************************
296 * mixerGetDevCapsW [WINMM.@]
298 UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize)
303 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
305 ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA));
306 if (ret == MMSYSERR_NOERROR) {
308 micW.wMid = micA.wMid;
309 micW.wPid = micA.wPid;
310 micW.vDriverVersion = micA.vDriverVersion;
311 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
312 sizeof(micW.szPname)/sizeof(WCHAR) );
313 micW.fdwSupport = micA.fdwSupport;
314 micW.cDestinations = micA.cDestinations;
315 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
320 UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
321 DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32)
328 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
329 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
331 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
332 &dwCallback, &dwInstance, bFrom32);
334 wmld->uDeviceID = uDeviceID;
335 mod.hmx = (HMIXEROBJ)hMix;
336 mod.dwCallback = dwCallback;
337 mod.dwInstance = dwInstance;
339 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
341 if (dwRet != MMSYSERR_NOERROR) {
342 MMDRV_Free(hMix, wmld);
345 if (lphMix) *lphMix = hMix;
346 TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
351 /**************************************************************************
352 * mixerOpen [WINMM.@]
354 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
355 DWORD_PTR dwInstance, DWORD fdwOpen)
357 return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
360 /**************************************************************************
361 * mixerClose [WINMM.@]
363 UINT WINAPI mixerClose(HMIXER hMix)
368 TRACE("(%p)\n", hMix);
370 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
372 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
373 MMDRV_Free(hMix, wmld);
378 /**************************************************************************
379 * mixerGetID [WINMM.@]
381 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
384 UINT uRet = MMSYSERR_NOERROR;
386 TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID);
388 if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR)
392 *lpid = lpwm->mld.uDeviceID;
397 /**************************************************************************
398 * mixerGetControlDetailsA [WINMM.@]
400 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
404 UINT uRet = MMSYSERR_NOERROR;
406 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
408 if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR)
411 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
412 return MMSYSERR_INVALPARAM;
414 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdA,
418 /**************************************************************************
419 * mixerGetControlDetailsW [WINMM.@]
421 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
423 DWORD ret = MMSYSERR_NOTENABLED;
425 TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
427 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
428 return MMSYSERR_INVALPARAM;
430 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
431 case MIXER_GETCONTROLDETAILSF_VALUE:
432 /* can savely use W structure as it is, no string inside */
433 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
435 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
437 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
438 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
439 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
442 if (lpmcd->u.cMultipleItems != 0) {
443 size *= lpmcd->u.cMultipleItems;
445 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
446 lpmcd->paDetails = pDetailsA;
447 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
448 /* set up lpmcd->paDetails */
449 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
450 /* copy from lpmcd->paDetails back to paDetailsW; */
451 if(ret == MMSYSERR_NOERROR) {
452 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
453 pDetailsW->dwParam1 = pDetailsA->dwParam1;
454 pDetailsW->dwParam2 = pDetailsA->dwParam2;
455 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
457 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
461 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
462 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
464 HeapFree(GetProcessHeap(), 0, pDetailsA);
465 lpmcd->paDetails = pDetailsW;
466 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
470 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
476 /**************************************************************************
477 * mixerGetLineControlsA [WINMM.@]
479 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
483 UINT uRet = MMSYSERR_NOERROR;
485 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
487 if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR)
490 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
491 return MMSYSERR_INVALPARAM;
493 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcA,
497 /**************************************************************************
498 * mixerGetLineControlsW [WINMM.@]
500 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
503 MIXERLINECONTROLSA mlcA;
507 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
509 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
510 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
511 return MMSYSERR_INVALPARAM;
513 mlcA.cbStruct = sizeof(mlcA);
514 mlcA.dwLineID = lpmlcW->dwLineID;
515 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
516 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
517 mlcA.cControls = lpmlcW->cControls;
518 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
519 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
520 mlcA.cControls * mlcA.cbmxctrl);
522 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
524 if (ret == MMSYSERR_NOERROR) {
525 lpmlcW->dwLineID = mlcA.dwLineID;
526 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
527 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
528 lpmlcW->cControls = mlcA.cControls;
530 for (i = 0; i < mlcA.cControls; i++) {
531 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
532 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
533 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
534 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
535 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
536 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
537 lpmlcW->pamxctrl[i].szShortName,
538 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
539 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
540 lpmlcW->pamxctrl[i].szName,
541 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
542 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
543 * sizeof(mlcA.pamxctrl[i].Bounds) */
544 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
545 sizeof(mlcA.pamxctrl[i].Bounds));
546 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
547 * sizeof(mlcA.pamxctrl[i].Metrics) */
548 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
549 sizeof(mlcA.pamxctrl[i].Metrics));
553 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
558 /**************************************************************************
559 * mixerGetLineInfoA [WINMM.@]
561 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
564 UINT uRet = MMSYSERR_NOERROR;
566 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
568 if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR)
571 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW,
575 /**************************************************************************
576 * mixerGetLineInfoW [WINMM.@]
578 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
584 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
586 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
587 return MMSYSERR_INVALPARAM;
589 mliA.cbStruct = sizeof(mliA);
590 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
591 case MIXER_GETLINEINFOF_COMPONENTTYPE:
592 mliA.dwComponentType = lpmliW->dwComponentType;
594 case MIXER_GETLINEINFOF_DESTINATION:
595 mliA.dwDestination = lpmliW->dwDestination;
597 case MIXER_GETLINEINFOF_LINEID:
598 mliA.dwLineID = lpmliW->dwLineID;
600 case MIXER_GETLINEINFOF_SOURCE:
601 mliA.dwDestination = lpmliW->dwDestination;
602 mliA.dwSource = lpmliW->dwSource;
604 case MIXER_GETLINEINFOF_TARGETTYPE:
605 mliA.Target.dwType = lpmliW->Target.dwType;
606 mliA.Target.wMid = lpmliW->Target.wMid;
607 mliA.Target.wPid = lpmliW->Target.wPid;
608 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
609 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
612 WARN("Unsupported fdwControls=0x%08lx\n", fdwInfo);
613 return MMSYSERR_INVALFLAG;
616 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
618 lpmliW->dwDestination = mliA.dwDestination;
619 lpmliW->dwSource = mliA.dwSource;
620 lpmliW->dwLineID = mliA.dwLineID;
621 lpmliW->fdwLine = mliA.fdwLine;
622 lpmliW->dwUser = mliA.dwUser;
623 lpmliW->dwComponentType = mliA.dwComponentType;
624 lpmliW->cChannels = mliA.cChannels;
625 lpmliW->cConnections = mliA.cConnections;
626 lpmliW->cControls = mliA.cControls;
627 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
628 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
629 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
630 sizeof(lpmliW->szName)/sizeof(WCHAR) );
631 lpmliW->Target.dwType = mliA.Target.dwType;
632 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
633 lpmliW->Target.wMid = mliA.Target.wMid;
634 lpmliW->Target.wPid = mliA.Target.wPid;
635 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
636 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
637 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
642 /**************************************************************************
643 * mixerSetControlDetails [WINMM.@]
645 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
649 UINT uRet = MMSYSERR_NOERROR;
651 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
653 if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR)
656 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcdA,
660 /**************************************************************************
661 * mixerMessage [WINMM.@]
663 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
667 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
668 (DWORD)hmix, uMsg, dwParam1, dwParam2);
670 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
671 return MMSYSERR_INVALHANDLE;
673 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
676 /**************************************************************************
677 * auxGetNumDevs [WINMM.@]
679 UINT WINAPI auxGetNumDevs(void)
681 return MMDRV_GetNum(MMDRV_AUX);
684 /**************************************************************************
685 * auxGetDevCapsW [WINMM.@]
687 UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
692 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
694 ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
695 if (ret == MMSYSERR_NOERROR) {
699 acW.vDriverVersion = acA.vDriverVersion;
700 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, acW.szPname,
701 sizeof(acW.szPname)/sizeof(WCHAR) );
702 acW.wTechnology = acA.wTechnology;
703 acW.dwSupport = acA.dwSupport;
704 memcpy(lpCaps, &acW, min(uSize, sizeof(acW)));
709 /**************************************************************************
710 * auxGetDevCapsA [WINMM.@]
712 UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
716 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
718 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
720 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
721 return MMSYSERR_INVALHANDLE;
722 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
725 /**************************************************************************
726 * auxGetVolume [WINMM.@]
728 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
732 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
734 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
735 return MMSYSERR_INVALHANDLE;
736 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE);
739 /**************************************************************************
740 * auxSetVolume [WINMM.@]
742 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
746 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
748 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
749 return MMSYSERR_INVALHANDLE;
750 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
753 /**************************************************************************
754 * auxOutMessage [WINMM.@]
756 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2)
760 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
761 return MMSYSERR_INVALHANDLE;
763 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
766 /**************************************************************************
767 * mciGetErrorStringW [WINMM.@]
769 BOOL WINAPI mciGetErrorStringW(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength)
771 char bufstr[MAXERRORLENGTH];
772 BOOL ret = mciGetErrorStringA(wError, bufstr, MAXERRORLENGTH);
774 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
778 /**************************************************************************
779 * mciGetErrorStringA [WINMM.@]
781 BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength)
785 if (lpstrBuffer != NULL && uLength > 0 &&
786 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
788 if (LoadStringA(WINMM_IData->hWinMM32Instance,
789 dwError, lpstrBuffer, uLength) > 0) {
796 /**************************************************************************
797 * mciDriverNotify [WINMM.@]
799 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, MCIDEVICEID wDevID, UINT wStatus)
801 TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
803 return PostMessageW(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
806 /**************************************************************************
807 * mciGetDriverData [WINMM.@]
809 DWORD WINAPI mciGetDriverData(MCIDEVICEID uDeviceID)
811 LPWINE_MCIDRIVER wmd;
813 TRACE("(%04x)\n", uDeviceID);
815 wmd = MCI_GetDriver(uDeviceID);
818 WARN("Bad uDeviceID\n");
822 return wmd->dwPrivate;
825 /**************************************************************************
826 * mciSetDriverData [WINMM.@]
828 BOOL WINAPI mciSetDriverData(MCIDEVICEID uDeviceID, DWORD data)
830 LPWINE_MCIDRIVER wmd;
832 TRACE("(%04x, %08lx)\n", uDeviceID, data);
834 wmd = MCI_GetDriver(uDeviceID);
837 WARN("Bad uDeviceID\n");
841 wmd->dwPrivate = data;
845 /**************************************************************************
846 * mciSendCommandA [WINMM.@]
848 DWORD WINAPI mciSendCommandA(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
852 TRACE("(%08x, %s, %08lx, %08lx)\n",
853 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
855 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
856 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
857 TRACE("=> %08lx\n", dwRet);
861 inline static LPSTR strdupWtoA( LPCWSTR str )
866 if (!str) return NULL;
867 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
868 ret = HeapAlloc( GetProcessHeap(), 0, len );
869 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
873 static int MCI_MapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2)
906 MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*dwParam2;
907 MCI_OPEN_PARMSA *mci_openA;
910 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_openA) + sizeof(DWORD_PTR));
913 *ptr++ = *dwParam2; /* save the previous pointer */
914 *dwParam2 = (DWORD_PTR)ptr;
915 mci_openA = (MCI_OPEN_PARMSA *)ptr;
917 if (dwParam1 & MCI_NOTIFY)
918 mci_openA->dwCallback = mci_openW->dwCallback;
920 if (dwParam1 & MCI_OPEN_TYPE)
922 if (dwParam1 & MCI_OPEN_TYPE_ID)
923 mci_openA->lpstrDeviceType = (LPSTR)mci_openW->lpstrDeviceType;
925 mci_openA->lpstrDeviceType = strdupWtoA(mci_openW->lpstrDeviceType);
927 if (dwParam1 & MCI_OPEN_ELEMENT)
929 if (dwParam1 & MCI_OPEN_ELEMENT_ID)
930 mci_openA->lpstrElementName = (LPSTR)mci_openW->lpstrElementName;
932 mci_openA->lpstrElementName = strdupWtoA(mci_openW->lpstrElementName);
934 if (dwParam1 & MCI_OPEN_ALIAS)
935 mci_openA->lpstrAlias = strdupWtoA(mci_openW->lpstrAlias);
940 if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
942 MCI_ANIM_WINDOW_PARMSW *mci_windowW = (MCI_ANIM_WINDOW_PARMSW *)*dwParam2;
943 MCI_ANIM_WINDOW_PARMSA *mci_windowA;
945 mci_windowA = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowA));
946 if (!mci_windowA) return -1;
948 *dwParam2 = (DWORD_PTR)mci_windowA;
950 mci_windowA->lpstrText = strdupWtoA(mci_windowW->lpstrText);
952 if (dwParam1 & MCI_NOTIFY)
953 mci_windowA->dwCallback = mci_windowW->dwCallback;
954 if (dwParam1 & MCI_ANIM_WINDOW_HWND)
955 mci_windowA->hWnd = mci_windowW->hWnd;
956 if (dwParam1 & MCI_ANIM_WINDOW_STATE)
957 mci_windowA->nCmdShow = mci_windowW->nCmdShow;
965 MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*dwParam2;
966 MCI_SYSINFO_PARMSA *mci_sysinfoA;
969 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoA) + sizeof(DWORD_PTR));
972 *ptr++ = *dwParam2; /* save the previous pointer */
973 *dwParam2 = (DWORD_PTR)ptr;
974 mci_sysinfoA = (MCI_SYSINFO_PARMSA *)ptr;
976 if (dwParam1 & MCI_NOTIFY)
977 mci_sysinfoA->dwCallback = mci_sysinfoW->dwCallback;
979 mci_sysinfoA->dwRetSize = mci_sysinfoW->dwRetSize; /* FIXME */
980 mci_sysinfoA->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoA->dwRetSize);
990 FIXME("Message 0x%04x needs translation\n", msg);
996 static DWORD MCI_UnmapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2,
1003 DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
1004 MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*ptr;
1005 MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA *)(ptr + 1);
1007 mci_openW->wDeviceID = mci_openA->wDeviceID;
1009 if (dwParam1 & MCI_OPEN_TYPE)
1011 if (!(dwParam1 & MCI_OPEN_TYPE_ID))
1012 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrDeviceType);
1014 if (dwParam1 & MCI_OPEN_ELEMENT)
1016 if (!(dwParam1 & MCI_OPEN_ELEMENT_ID))
1017 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrElementName);
1019 if (dwParam1 & MCI_OPEN_ALIAS)
1020 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrAlias);
1021 HeapFree(GetProcessHeap(), 0, ptr);
1026 if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
1028 MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)dwParam2;
1030 HeapFree(GetProcessHeap(), 0, (void *)mci_windowA->lpstrText);
1031 HeapFree(GetProcessHeap(), 0, mci_windowA);
1037 DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
1038 MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*ptr;
1039 MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)(ptr + 1);
1043 mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber;
1044 mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType;
1045 MultiByteToWideChar(CP_ACP, 0,
1046 mci_sysinfoA->lpstrReturn, mci_sysinfoA->dwRetSize,
1047 mci_sysinfoW->lpstrReturn, mci_sysinfoW->dwRetSize);
1050 HeapFree(GetProcessHeap(), 0, mci_sysinfoA->lpstrReturn);
1051 HeapFree(GetProcessHeap(), 0, ptr);
1056 FIXME("Message 0x%04x needs unmapping\n", msg);
1064 /**************************************************************************
1065 * mciSendCommandW [WINMM.@]
1067 * FIXME: we should do the things other way around, but since our
1068 * MM subsystem is not unicode aware...
1070 DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1075 TRACE("(%08x, %s, %08lx, %08lx)\n",
1076 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1078 mapped = MCI_MapMsgWtoA(wMsg, dwParam1, &dwParam2);
1081 FIXME("message %04x mapping failed\n", wMsg);
1082 return MMSYSERR_NOMEM;
1084 ret = mciSendCommandA(wDevID, wMsg, dwParam1, dwParam2);
1086 MCI_UnmapMsgWtoA(wMsg, dwParam1, dwParam2, ret);
1090 /**************************************************************************
1091 * mciGetDeviceIDA [WINMM.@]
1093 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1095 return MCI_GetDriverFromString(lpstrName);
1098 /**************************************************************************
1099 * mciGetDeviceIDW [WINMM.@]
1101 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1103 LPSTR lpstrName = NULL;
1108 len = WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, NULL, 0, NULL, NULL );
1109 lpstrName = HeapAlloc( GetProcessHeap(), 0, len );
1110 if (lpstrName) WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, lpstrName, len, NULL, NULL );
1112 ret = MCI_GetDriverFromString(lpstrName);
1113 HeapFree(GetProcessHeap(), 0, lpstrName);
1117 /**************************************************************************
1118 * MCI_DefYieldProc [internal]
1120 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1124 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1126 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
1127 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1133 msg.hwnd = HWND_32(HIWORD(data));
1134 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1140 /**************************************************************************
1141 * mciSetYieldProc [WINMM.@]
1143 BOOL WINAPI mciSetYieldProc(MCIDEVICEID uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1145 LPWINE_MCIDRIVER wmd;
1147 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1149 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1150 WARN("Bad uDeviceID\n");
1154 wmd->lpfnYieldProc = fpYieldProc;
1155 wmd->dwYieldData = dwYieldData;
1161 /**************************************************************************
1162 * mciGetDeviceIDFromElementIDW [WINMM.@]
1164 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1166 /* FIXME: that's rather strange, there is no
1167 * mciGetDeviceIDFromElementID32A in winmm.spec
1169 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1173 /**************************************************************************
1174 * mciGetYieldProc [WINMM.@]
1176 YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID uDeviceID, DWORD* lpdwYieldData)
1178 LPWINE_MCIDRIVER wmd;
1180 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1182 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1183 WARN("Bad uDeviceID\n");
1186 if (!wmd->lpfnYieldProc) {
1187 WARN("No proc set\n");
1191 WARN("Proc is 32 bit\n");
1194 return wmd->lpfnYieldProc;
1197 /**************************************************************************
1198 * mciGetCreatorTask [WINMM.@]
1200 HTASK WINAPI mciGetCreatorTask(MCIDEVICEID uDeviceID)
1202 LPWINE_MCIDRIVER wmd;
1205 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
1207 TRACE("(%u) => %p\n", uDeviceID, ret);
1211 /**************************************************************************
1212 * mciDriverYield [WINMM.@]
1214 UINT WINAPI mciDriverYield(MCIDEVICEID uDeviceID)
1216 LPWINE_MCIDRIVER wmd;
1219 TRACE("(%04x)\n", uDeviceID);
1221 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
1224 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1230 /**************************************************************************
1231 * midiOutGetNumDevs [WINMM.@]
1233 UINT WINAPI midiOutGetNumDevs(void)
1235 return MMDRV_GetNum(MMDRV_MIDIOUT);
1238 /**************************************************************************
1239 * midiOutGetDevCapsW [WINMM.@]
1241 UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps,
1247 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1249 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
1250 if (ret == MMSYSERR_NOERROR) {
1252 mocW.wMid = mocA.wMid;
1253 mocW.wPid = mocA.wPid;
1254 mocW.vDriverVersion = mocA.vDriverVersion;
1255 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, mocW.szPname,
1256 sizeof(mocW.szPname)/sizeof(WCHAR) );
1257 mocW.wTechnology = mocA.wTechnology;
1258 mocW.wVoices = mocA.wVoices;
1259 mocW.wNotes = mocA.wNotes;
1260 mocW.wChannelMask = mocA.wChannelMask;
1261 mocW.dwSupport = mocA.dwSupport;
1262 memcpy(lpCaps, &mocW, min(uSize, sizeof(mocW)));
1267 /**************************************************************************
1268 * midiOutGetDevCapsA [WINMM.@]
1270 UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps,
1275 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
1277 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1279 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1280 return MMSYSERR_INVALHANDLE;
1282 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
1285 /**************************************************************************
1286 * MIDI_GetErrorText [internal]
1288 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1290 UINT16 ret = MMSYSERR_BADERRNUM;
1292 if (lpText == NULL) {
1293 ret = MMSYSERR_INVALPARAM;
1294 } else if (uSize == 0) {
1295 ret = MMSYSERR_NOERROR;
1297 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
1298 * a warning for the test was always true */
1299 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
1300 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
1302 if (LoadStringA(WINMM_IData->hWinMM32Instance,
1303 uError, lpText, uSize) > 0) {
1304 ret = MMSYSERR_NOERROR;
1310 /**************************************************************************
1311 * midiOutGetErrorTextA [WINMM.@]
1313 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1315 return MIDI_GetErrorText(uError, lpText, uSize);
1318 /**************************************************************************
1319 * midiOutGetErrorTextW [WINMM.@]
1321 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1323 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1326 ret = MIDI_GetErrorText(uError, xstr, uSize);
1327 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1328 HeapFree(GetProcessHeap(), 0, xstr);
1332 /**************************************************************************
1333 * MIDI_OutAlloc [internal]
1335 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1336 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1337 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1343 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1345 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1346 lpdwCallback, lpdwInstance, bFrom32);
1348 if (lphMidiOut != NULL)
1349 *lphMidiOut = hMidiOut;
1352 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1353 lpwm->mod.dwCallback = *lpdwCallback;
1354 lpwm->mod.dwInstance = *lpdwInstance;
1355 lpwm->mod.dnDevNode = 0;
1356 lpwm->mod.cIds = cIDs;
1358 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1363 UINT MIDI_OutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback,
1364 DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32)
1370 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1371 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1373 if (lphMidiOut != NULL) *lphMidiOut = 0;
1375 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1379 return MMSYSERR_NOMEM;
1381 lpwm->mld.uDeviceID = uDeviceID;
1383 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1385 if (dwRet != MMSYSERR_NOERROR) {
1386 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1390 if (lphMidiOut) *lphMidiOut = hMidiOut;
1391 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
1396 /**************************************************************************
1397 * midiOutOpen [WINMM.@]
1399 UINT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
1400 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
1402 return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1405 /**************************************************************************
1406 * midiOutClose [WINMM.@]
1408 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1413 TRACE("(%p)\n", hMidiOut);
1415 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1416 return MMSYSERR_INVALHANDLE;
1418 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1419 MMDRV_Free(hMidiOut, wmld);
1424 /**************************************************************************
1425 * midiOutPrepareHeader [WINMM.@]
1427 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1428 MIDIHDR* lpMidiOutHdr, UINT uSize)
1432 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1434 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
1435 return MMSYSERR_INVALPARAM;
1437 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1438 return MMSYSERR_INVALHANDLE;
1440 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1443 /**************************************************************************
1444 * midiOutUnprepareHeader [WINMM.@]
1446 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1447 MIDIHDR* lpMidiOutHdr, UINT uSize)
1451 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1453 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
1454 return MMSYSERR_INVALPARAM;
1456 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1457 return MMSYSERR_NOERROR;
1460 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1461 return MMSYSERR_INVALHANDLE;
1463 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1466 /**************************************************************************
1467 * midiOutShortMsg [WINMM.@]
1469 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1473 TRACE("(%p, %08lX)\n", hMidiOut, dwMsg);
1475 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1476 return MMSYSERR_INVALHANDLE;
1478 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE);
1481 /**************************************************************************
1482 * midiOutLongMsg [WINMM.@]
1484 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1485 MIDIHDR* lpMidiOutHdr, UINT uSize)
1489 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1491 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1492 return MMSYSERR_INVALHANDLE;
1494 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1497 /**************************************************************************
1498 * midiOutReset [WINMM.@]
1500 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1504 TRACE("(%p)\n", hMidiOut);
1506 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1507 return MMSYSERR_INVALHANDLE;
1509 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1512 /**************************************************************************
1513 * midiOutGetVolume [WINMM.@]
1515 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
1519 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
1521 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1522 return MMSYSERR_INVALHANDLE;
1524 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE);
1527 /**************************************************************************
1528 * midiOutSetVolume [WINMM.@]
1530 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
1534 TRACE("(%p, %ld);\n", hMidiOut, dwVolume);
1536 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1537 return MMSYSERR_INVALHANDLE;
1539 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1542 /**************************************************************************
1543 * midiOutCachePatches [WINMM.@]
1545 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1546 WORD* lpwPatchArray, UINT uFlags)
1548 /* not really necessary to support this */
1549 FIXME("not supported yet\n");
1550 return MMSYSERR_NOTSUPPORTED;
1553 /**************************************************************************
1554 * midiOutCacheDrumPatches [WINMM.@]
1556 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1557 WORD* lpwKeyArray, UINT uFlags)
1559 FIXME("not supported yet\n");
1560 return MMSYSERR_NOTSUPPORTED;
1563 /**************************************************************************
1564 * midiOutGetID [WINMM.@]
1566 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1570 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
1572 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1573 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1574 return MMSYSERR_INVALHANDLE;
1576 *lpuDeviceID = wmld->uDeviceID;
1577 return MMSYSERR_NOERROR;
1580 /**************************************************************************
1581 * midiOutMessage [WINMM.@]
1583 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1584 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1588 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1590 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1592 if (uMessage == 0x0001) {
1593 *(LPDWORD)dwParam1 = 1;
1596 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1597 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1599 return MMSYSERR_INVALHANDLE;
1605 FIXME("can't handle OPEN or CLOSE message!\n");
1606 return MMSYSERR_NOTSUPPORTED;
1608 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1611 /**************************************************************************
1612 * midiInGetNumDevs [WINMM.@]
1614 UINT WINAPI midiInGetNumDevs(void)
1616 return MMDRV_GetNum(MMDRV_MIDIIN);
1619 /**************************************************************************
1620 * midiInGetDevCapsW [WINMM.@]
1622 UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1627 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1629 ret = midiInGetDevCapsA(uDeviceID, &micA, sizeof(micA));
1630 if (ret == MMSYSERR_NOERROR) {
1632 micW.wMid = micA.wMid;
1633 micW.wPid = micA.wPid;
1634 micW.vDriverVersion = micA.vDriverVersion;
1635 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
1636 sizeof(micW.szPname)/sizeof(WCHAR) );
1637 micW.dwSupport = micA.dwSupport;
1638 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
1643 /**************************************************************************
1644 * midiInGetDevCapsA [WINMM.@]
1646 UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1650 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1652 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1654 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1655 return MMSYSERR_INVALHANDLE;
1657 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
1660 /**************************************************************************
1661 * midiInGetErrorTextW [WINMM.@]
1663 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1665 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1666 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1668 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1669 HeapFree(GetProcessHeap(), 0, xstr);
1673 /**************************************************************************
1674 * midiInGetErrorTextA [WINMM.@]
1676 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1678 return MIDI_GetErrorText(uError, lpText, uSize);
1681 UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD_PTR dwCallback,
1682 DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32)
1688 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1689 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1691 if (lphMidiIn != NULL) *lphMidiIn = 0;
1693 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1694 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1697 return MMSYSERR_NOMEM;
1699 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1700 lpwm->mod.dwCallback = dwCallback;
1701 lpwm->mod.dwInstance = dwInstance;
1703 lpwm->mld.uDeviceID = uDeviceID;
1704 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1706 if (dwRet != MMSYSERR_NOERROR) {
1707 MMDRV_Free(hMidiIn, &lpwm->mld);
1710 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1711 TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn);
1716 /**************************************************************************
1717 * midiInOpen [WINMM.@]
1719 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1720 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
1722 return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1725 /**************************************************************************
1726 * midiInClose [WINMM.@]
1728 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1733 TRACE("(%p)\n", hMidiIn);
1735 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1736 return MMSYSERR_INVALHANDLE;
1738 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1739 MMDRV_Free(hMidiIn, wmld);
1743 /**************************************************************************
1744 * midiInPrepareHeader [WINMM.@]
1746 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1747 MIDIHDR* lpMidiInHdr, UINT uSize)
1751 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1753 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
1754 return MMSYSERR_INVALPARAM;
1756 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1757 return MMSYSERR_INVALHANDLE;
1759 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1762 /**************************************************************************
1763 * midiInUnprepareHeader [WINMM.@]
1765 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1766 MIDIHDR* lpMidiInHdr, UINT uSize)
1770 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1772 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
1773 return MMSYSERR_INVALPARAM;
1775 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1776 return MMSYSERR_NOERROR;
1779 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1780 return MMSYSERR_INVALHANDLE;
1782 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1785 /**************************************************************************
1786 * midiInAddBuffer [WINMM.@]
1788 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1789 MIDIHDR* lpMidiInHdr, UINT uSize)
1793 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1795 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1796 return MMSYSERR_INVALHANDLE;
1798 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1801 /**************************************************************************
1802 * midiInStart [WINMM.@]
1804 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1808 TRACE("(%p)\n", hMidiIn);
1810 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1811 return MMSYSERR_INVALHANDLE;
1813 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1816 /**************************************************************************
1817 * midiInStop [WINMM.@]
1819 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1823 TRACE("(%p)\n", hMidiIn);
1825 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1826 return MMSYSERR_INVALHANDLE;
1828 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1831 /**************************************************************************
1832 * midiInReset [WINMM.@]
1834 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1838 TRACE("(%p)\n", hMidiIn);
1840 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1841 return MMSYSERR_INVALHANDLE;
1843 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1846 /**************************************************************************
1847 * midiInGetID [WINMM.@]
1849 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1853 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
1855 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1857 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1858 return MMSYSERR_INVALHANDLE;
1860 *lpuDeviceID = wmld->uDeviceID;
1862 return MMSYSERR_NOERROR;
1865 /**************************************************************************
1866 * midiInMessage [WINMM.@]
1868 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1869 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1873 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1875 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1876 return MMSYSERR_INVALHANDLE;
1881 FIXME("can't handle OPEN or CLOSE message!\n");
1882 return MMSYSERR_NOTSUPPORTED;
1884 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1887 typedef struct WINE_MIDIStream {
1898 LPMIDIHDR lpMidiHdr;
1901 #define WINE_MSM_HEADER (WM_USER+0)
1902 #define WINE_MSM_STOP (WM_USER+1)
1904 /**************************************************************************
1905 * MMSYSTEM_GetMidiStream [internal]
1907 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1909 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1918 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1920 return *lpMidiStrm != NULL;
1923 /**************************************************************************
1924 * MMSYSTEM_MidiStream_Convert [internal]
1926 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1930 if (lpMidiStrm->dwTimeDiv == 0) {
1931 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1932 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1933 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1934 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1935 ret = (pulse * 1000) / (nf * nsf);
1937 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1938 (double)lpMidiStrm->dwTimeDiv);
1944 /**************************************************************************
1945 * MMSYSTEM_MidiStream_MessageHandler [internal]
1947 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1949 LPMIDIHDR lpMidiHdr;
1953 switch (msg->message) {
1955 SetEvent(lpMidiStrm->hEvent);
1959 /* this is not quite what MS doc says... */
1960 midiOutReset(lpMidiStrm->hDevice);
1961 /* empty list of already submitted buffers */
1962 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1963 lpMidiHdr->dwFlags |= MHDR_DONE;
1964 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1966 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1967 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1968 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1970 lpMidiStrm->lpMidiHdr = 0;
1971 SetEvent(lpMidiStrm->hEvent);
1973 case WINE_MSM_HEADER:
1974 /* sets initial tick count for first MIDIHDR */
1975 if (!lpMidiStrm->dwStartTicks)
1976 lpMidiStrm->dwStartTicks = GetTickCount();
1978 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1979 * by native mcimidi, it doesn't look like a correct one".
1980 * this trick allows to throw it away... but I don't like it.
1981 * It looks like part of the file I'm trying to play and definitively looks
1982 * like raw midi content
1983 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1984 * synchronization issue where native mcimidi is still processing raw MIDI
1985 * content before generating MIDIEVENTs ?
1987 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1988 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1989 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1990 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1991 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1992 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1993 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1994 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1995 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1996 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1997 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1998 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1999 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
2000 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
2001 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
2002 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
2003 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
2005 lpMidiHdr = (LPMIDIHDR)msg->lParam;
2006 lpData = lpMidiHdr->lpData;
2007 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
2008 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
2009 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
2010 lpMidiHdr->dwFlags, msg->wParam);
2012 /* dumps content of lpMidiHdr->lpData
2013 * FIXME: there should be a debug routine somewhere that already does this
2014 * I hate spreading this type of shit all around the code
2016 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
2020 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
2021 printf("%02x ", lpData[dwToGo + i]);
2024 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
2025 ch = lpData[dwToGo + i];
2026 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
2031 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
2032 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
2033 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
2034 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
2035 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
2036 ((LPMIDIEVENT)lpData)->dwStreamID);
2037 lpMidiHdr->dwFlags |= MHDR_DONE;
2038 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2040 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2041 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
2042 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
2046 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
2048 lpMidiHdr = (LPMIDIHDR)msg->lParam;
2049 lpMidiHdr->lpNext = 0;
2050 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
2051 lpMidiHdr->dwFlags &= ~MHDR_DONE;
2052 lpMidiHdr->dwOffset = 0;
2056 FIXME("Unknown message %d\n", msg->message);
2062 /**************************************************************************
2063 * MMSYSTEM_MidiStream_Player [internal]
2065 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
2067 WINE_MIDIStream* lpMidiStrm = pmt;
2072 LPMIDIHDR lpMidiHdr;
2076 TRACE("(%p)!\n", lpMidiStrm);
2079 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
2082 /* force thread's queue creation */
2083 /* Used to be InitThreadInput16(0, 5); */
2084 /* but following works also with hack in midiStreamOpen */
2085 PeekMessageA(&msg, 0, 0, 0, 0);
2087 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
2088 SetEvent(lpMidiStrm->hEvent);
2089 TRACE("Ready to go 1\n");
2090 /* thread is started in paused mode */
2091 SuspendThread(lpMidiStrm->hThread);
2092 TRACE("Ready to go 2\n");
2094 lpMidiStrm->dwStartTicks = 0;
2095 lpMidiStrm->dwPulses = 0;
2097 lpMidiStrm->lpMidiHdr = 0;
2100 lpMidiHdr = lpMidiStrm->lpMidiHdr;
2102 /* for first message, block until one arrives, then process all that are available */
2103 GetMessageA(&msg, 0, 0, 0);
2105 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
2107 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
2113 lpData = lpMidiHdr->lpData;
2115 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
2117 /* do we have to wait ? */
2118 if (me->dwDeltaTime) {
2119 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
2120 lpMidiStrm->dwPulses += me->dwDeltaTime;
2122 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
2124 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
2125 while ((dwCurrTC = GetTickCount()) < dwToGo) {
2126 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
2127 /* got a message, handle it */
2128 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
2129 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
2134 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
2139 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
2141 FIXME("NIY: MEVT_COMMENT\n");
2142 /* do nothing, skip bytes */
2145 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
2150 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
2153 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
2158 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
2161 if (me->dwEvent & MEVT_F_CALLBACK) {
2162 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2163 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
2164 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
2166 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
2167 if (me->dwEvent & MEVT_F_LONG)
2168 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
2169 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
2170 /* done with this header */
2171 lpMidiHdr->dwFlags |= MHDR_DONE;
2172 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2174 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
2175 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2176 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
2177 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
2182 TRACE("End of thread\n");
2184 return 0; /* for removing the warning, never executed */
2187 /**************************************************************************
2188 * MMSYSTEM_MidiStream_PostMessage [internal]
2190 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
2192 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
2195 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
2196 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
2197 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
2199 WARN("bad PostThreadMessageA\n");
2205 /**************************************************************************
2206 * midiStreamClose [WINMM.@]
2208 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
2210 WINE_MIDIStream* lpMidiStrm;
2212 TRACE("(%p)!\n", hMidiStrm);
2214 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
2215 return MMSYSERR_INVALHANDLE;
2217 midiStreamStop(hMidiStrm);
2218 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
2219 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
2220 CloseHandle(lpMidiStrm->hEvent);
2222 return midiOutClose((HMIDIOUT)hMidiStrm);
2225 /**************************************************************************
2226 * MMSYSTEM_MidiStream_Open [internal]
2228 MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi,
2229 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen,
2232 WINE_MIDIStream* lpMidiStrm;
2234 MIDIOPENSTRMID mosm;
2238 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
2239 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
2241 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
2242 return MMSYSERR_INVALPARAM;
2244 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
2246 return MMSYSERR_NOMEM;
2248 lpMidiStrm->dwTempo = 500000;
2249 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
2250 lpMidiStrm->dwPositionMS = 0;
2252 mosm.dwStreamID = (DWORD)lpMidiStrm;
2253 /* FIXME: the correct value is not allocated yet for MAPPER */
2254 mosm.wDeviceID = *lpuDeviceID;
2255 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
2256 lpMidiStrm->hDevice = hMidiOut;
2258 *lphMidiStrm = (HMIDISTRM)hMidiOut;
2260 lpwm->mld.uDeviceID = *lpuDeviceID;
2262 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
2263 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2264 lpMidiStrm->wFlags = HIWORD(fdwOpen);
2266 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
2267 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
2269 if (!lpMidiStrm->hThread) {
2270 midiStreamClose((HMIDISTRM)hMidiOut);
2271 return MMSYSERR_NOMEM;
2274 /* wait for thread to have started, and for its queue to be created */
2278 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
2279 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
2280 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
2282 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
2283 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
2284 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
2287 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
2288 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
2292 /**************************************************************************
2293 * midiStreamOpen [WINMM.@]
2295 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
2296 DWORD cMidi, DWORD_PTR dwCallback,
2297 DWORD_PTR dwInstance, DWORD fdwOpen)
2299 return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
2300 dwInstance, fdwOpen, TRUE);
2303 /**************************************************************************
2304 * midiStreamOut [WINMM.@]
2306 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
2309 WINE_MIDIStream* lpMidiStrm;
2310 DWORD ret = MMSYSERR_NOERROR;
2312 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
2314 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2315 ret = MMSYSERR_INVALHANDLE;
2316 } else if (!lpMidiHdr) {
2317 ret = MMSYSERR_INVALPARAM;
2319 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
2320 WINE_MSM_HEADER, cbMidiHdr,
2321 (DWORD)lpMidiHdr)) {
2322 WARN("bad PostThreadMessageA\n");
2323 ret = MMSYSERR_ERROR;
2329 /**************************************************************************
2330 * midiStreamPause [WINMM.@]
2332 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
2334 WINE_MIDIStream* lpMidiStrm;
2335 DWORD ret = MMSYSERR_NOERROR;
2337 TRACE("(%p)!\n", hMidiStrm);
2339 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2340 ret = MMSYSERR_INVALHANDLE;
2342 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2343 WARN("bad Suspend (%ld)\n", GetLastError());
2344 ret = MMSYSERR_ERROR;
2350 /**************************************************************************
2351 * midiStreamPosition [WINMM.@]
2353 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2355 WINE_MIDIStream* lpMidiStrm;
2356 DWORD ret = MMSYSERR_NOERROR;
2358 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2360 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2361 ret = MMSYSERR_INVALHANDLE;
2362 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2363 ret = MMSYSERR_INVALPARAM;
2365 switch (lpMMT->wType) {
2367 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2368 TRACE("=> %ld ms\n", lpMMT->u.ms);
2371 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2372 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2375 WARN("Unsupported time type %d\n", lpMMT->wType);
2376 lpMMT->wType = TIME_MS;
2377 ret = MMSYSERR_INVALPARAM;
2384 /**************************************************************************
2385 * midiStreamProperty [WINMM.@]
2387 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2389 WINE_MIDIStream* lpMidiStrm;
2390 MMRESULT ret = MMSYSERR_NOERROR;
2392 TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2394 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2395 ret = MMSYSERR_INVALHANDLE;
2396 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2397 ret = MMSYSERR_INVALPARAM;
2398 } else if (dwProperty & MIDIPROP_TEMPO) {
2399 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2401 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2402 ret = MMSYSERR_INVALPARAM;
2403 } else if (dwProperty & MIDIPROP_SET) {
2404 lpMidiStrm->dwTempo = mpt->dwTempo;
2405 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2406 } else if (dwProperty & MIDIPROP_GET) {
2407 mpt->dwTempo = lpMidiStrm->dwTempo;
2408 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2410 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2411 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2413 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2414 ret = MMSYSERR_INVALPARAM;
2415 } else if (dwProperty & MIDIPROP_SET) {
2416 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2417 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2418 } else if (dwProperty & MIDIPROP_GET) {
2419 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2420 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2423 ret = MMSYSERR_INVALPARAM;
2429 /**************************************************************************
2430 * midiStreamRestart [WINMM.@]
2432 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2434 WINE_MIDIStream* lpMidiStrm;
2435 MMRESULT ret = MMSYSERR_NOERROR;
2437 TRACE("(%p)!\n", hMidiStrm);
2439 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2440 ret = MMSYSERR_INVALHANDLE;
2444 /* since we increase the thread suspend count on each midiStreamPause
2445 * there may be a need for several midiStreamResume
2448 ret = ResumeThread(lpMidiStrm->hThread);
2449 } while (ret != 0xFFFFFFFF && ret != 0);
2450 if (ret == 0xFFFFFFFF) {
2451 WARN("bad Resume (%ld)\n", GetLastError());
2452 ret = MMSYSERR_ERROR;
2454 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2460 /**************************************************************************
2461 * midiStreamStop [WINMM.@]
2463 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2465 WINE_MIDIStream* lpMidiStrm;
2466 MMRESULT ret = MMSYSERR_NOERROR;
2468 TRACE("(%p)!\n", hMidiStrm);
2470 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2471 ret = MMSYSERR_INVALHANDLE;
2473 /* in case stream has been paused... FIXME is the current state correct ? */
2474 midiStreamRestart(hMidiStrm);
2475 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2480 UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2481 const LPWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
2482 DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32)
2486 DWORD dwRet = MMSYSERR_NOERROR;
2489 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2490 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2491 dwInstance, dwFlags, bFrom32?32:16);
2493 if (dwFlags & WAVE_FORMAT_QUERY)
2494 TRACE("WAVE_FORMAT_QUERY requested !\n");
2496 if (lpFormat == NULL) {
2497 WARN("bad format\n");
2498 return WAVERR_BADFORMAT;
2501 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) {
2502 WARN("invalid parameter\n");
2503 return MMSYSERR_INVALPARAM;
2506 /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */
2507 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u\n",
2508 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2509 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample);
2511 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2512 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL) {
2513 WARN("no memory\n");
2514 return MMSYSERR_NOMEM;
2518 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2519 wod.dwCallback = dwCallback;
2520 wod.dwInstance = dwInstance;
2523 TRACE("cb=%08lx\n", wod.dwCallback);
2526 if (dwFlags & WAVE_MAPPED) {
2527 wod.uMappedDeviceID = uDeviceID;
2528 uDeviceID = WAVE_MAPPER;
2530 wod.uMappedDeviceID = -1;
2532 wmld->uDeviceID = uDeviceID;
2534 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2535 (DWORD)&wod, dwFlags);
2537 TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet));
2538 if (dwRet != WAVERR_BADFORMAT ||
2539 ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break;
2540 /* if we ask for a format which isn't supported by the physical driver,
2541 * let's try to map it through the wave mapper (except, if we already tried
2542 * or user didn't allow us to use acm codecs or the device is already the mapper)
2544 dwFlags |= WAVE_MAPPED;
2545 /* we shall loop only one */
2548 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2549 MMDRV_Free(handle, wmld);
2553 if (lphndl != NULL) *lphndl = handle;
2554 TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle);
2559 /**************************************************************************
2560 * waveOutGetNumDevs [WINMM.@]
2562 UINT WINAPI waveOutGetNumDevs(void)
2564 return MMDRV_GetNum(MMDRV_WAVEOUT);
2567 /**************************************************************************
2568 * waveOutGetDevCapsA [WINMM.@]
2570 UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps,
2575 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2577 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2579 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2580 return MMSYSERR_BADDEVICEID;
2582 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
2586 /**************************************************************************
2587 * waveOutGetDevCapsW [WINMM.@]
2589 UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps,
2595 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2597 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2598 if (ret == MMSYSERR_NOERROR) {
2600 wocW.wMid = wocA.wMid;
2601 wocW.wPid = wocA.wPid;
2602 wocW.vDriverVersion = wocA.vDriverVersion;
2603 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, wocW.szPname,
2604 sizeof(wocW.szPname)/sizeof(WCHAR) );
2605 wocW.dwFormats = wocA.dwFormats;
2606 wocW.wChannels = wocA.wChannels;
2607 wocW.dwSupport = wocA.dwSupport;
2608 memcpy(lpCaps, &wocW, min(uSize, sizeof(wocW)));
2613 /**************************************************************************
2614 * WAVE_GetErrorText [internal]
2616 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2618 UINT16 ret = MMSYSERR_BADERRNUM;
2620 if (lpText == NULL) {
2621 ret = MMSYSERR_INVALPARAM;
2622 } else if (uSize == 0) {
2623 ret = MMSYSERR_NOERROR;
2625 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2626 * a warning for the test was always true */
2627 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2628 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2630 if (LoadStringA(WINMM_IData->hWinMM32Instance,
2631 uError, lpText, uSize) > 0) {
2632 ret = MMSYSERR_NOERROR;
2638 /**************************************************************************
2639 * waveOutGetErrorTextA [WINMM.@]
2641 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2643 return WAVE_GetErrorText(uError, lpText, uSize);
2646 /**************************************************************************
2647 * waveOutGetErrorTextW [WINMM.@]
2649 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2651 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2652 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2654 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2655 HeapFree(GetProcessHeap(), 0, xstr);
2659 /**************************************************************************
2660 * waveOutOpen [WINMM.@]
2661 * All the args/structs have the same layout as the win16 equivalents
2663 UINT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
2664 const LPWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
2665 DWORD_PTR dwInstance, DWORD dwFlags)
2667 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2668 dwCallback, dwInstance, dwFlags, TRUE);
2671 /**************************************************************************
2672 * waveOutClose [WINMM.@]
2674 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2679 TRACE("(%p)\n", hWaveOut);
2681 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2682 return MMSYSERR_INVALHANDLE;
2684 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2685 if (dwRet != WAVERR_STILLPLAYING)
2686 MMDRV_Free(hWaveOut, wmld);
2691 /**************************************************************************
2692 * waveOutPrepareHeader [WINMM.@]
2694 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2695 WAVEHDR* lpWaveOutHdr, UINT uSize)
2700 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2702 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
2703 return MMSYSERR_INVALPARAM;
2705 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2706 return MMSYSERR_INVALHANDLE;
2708 if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr,
2709 uSize, TRUE)) != MMSYSERR_NOTSUPPORTED)
2712 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
2713 return WAVERR_STILLPLAYING;
2715 lpWaveOutHdr->dwFlags |= WHDR_PREPARED;
2716 lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
2718 return MMSYSERR_NOERROR;
2721 /**************************************************************************
2722 * waveOutUnprepareHeader [WINMM.@]
2724 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2725 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2730 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2732 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
2733 return MMSYSERR_INVALPARAM;
2735 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2736 return MMSYSERR_NOERROR;
2739 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2740 return MMSYSERR_INVALHANDLE;
2742 if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr,
2743 uSize, TRUE)) != MMSYSERR_NOTSUPPORTED)
2746 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
2747 return WAVERR_STILLPLAYING;
2749 lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED;
2750 lpWaveOutHdr->dwFlags |= WHDR_DONE;
2752 return MMSYSERR_NOERROR;
2755 /**************************************************************************
2756 * waveOutWrite [WINMM.@]
2758 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2763 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2765 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2766 return MMSYSERR_INVALHANDLE;
2768 return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize, TRUE);
2771 /**************************************************************************
2772 * waveOutBreakLoop [WINMM.@]
2774 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2778 TRACE("(%p);\n", hWaveOut);
2780 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2781 return MMSYSERR_INVALHANDLE;
2782 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2785 /**************************************************************************
2786 * waveOutPause [WINMM.@]
2788 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2792 TRACE("(%p);\n", hWaveOut);
2794 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2795 return MMSYSERR_INVALHANDLE;
2796 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2799 /**************************************************************************
2800 * waveOutReset [WINMM.@]
2802 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2806 TRACE("(%p);\n", hWaveOut);
2808 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2809 return MMSYSERR_INVALHANDLE;
2810 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2813 /**************************************************************************
2814 * waveOutRestart [WINMM.@]
2816 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2820 TRACE("(%p);\n", hWaveOut);
2822 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2823 return MMSYSERR_INVALHANDLE;
2824 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2827 /**************************************************************************
2828 * waveOutGetPosition [WINMM.@]
2830 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2835 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
2837 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2838 return MMSYSERR_INVALHANDLE;
2840 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE);
2843 /**************************************************************************
2844 * waveOutGetPitch [WINMM.@]
2846 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2850 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2852 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2853 return MMSYSERR_INVALHANDLE;
2854 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L, TRUE);
2857 /**************************************************************************
2858 * waveOutSetPitch [WINMM.@]
2860 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2864 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2866 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2867 return MMSYSERR_INVALHANDLE;
2868 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2871 /**************************************************************************
2872 * waveOutGetPlaybackRate [WINMM.@]
2874 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2878 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2880 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2881 return MMSYSERR_INVALHANDLE;
2882 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L, TRUE);
2885 /**************************************************************************
2886 * waveOutSetPlaybackRate [WINMM.@]
2888 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2892 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2894 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2895 return MMSYSERR_INVALHANDLE;
2896 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2899 /**************************************************************************
2900 * waveOutGetVolume [WINMM.@]
2902 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
2906 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2908 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2909 return MMSYSERR_INVALHANDLE;
2911 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L, TRUE);
2914 /**************************************************************************
2915 * waveOutSetVolume [WINMM.@]
2917 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
2921 TRACE("(%p, %08lx);\n", hWaveOut, dw);
2923 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2924 return MMSYSERR_INVALHANDLE;
2926 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2929 /**************************************************************************
2930 * waveOutGetID [WINMM.@]
2932 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2936 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
2938 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2940 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2941 return MMSYSERR_INVALHANDLE;
2943 *lpuDeviceID = wmld->uDeviceID;
2947 /**************************************************************************
2948 * waveOutMessage [WINMM.@]
2950 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2951 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
2955 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2957 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2958 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2959 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2961 WARN("invalid handle\n");
2962 return MMSYSERR_INVALHANDLE;
2966 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) {
2967 WARN("invalid parameter\n");
2968 return MMSYSERR_INVALPARAM;
2971 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2974 /**************************************************************************
2975 * waveInGetNumDevs [WINMM.@]
2977 UINT WINAPI waveInGetNumDevs(void)
2979 return MMDRV_GetNum(MMDRV_WAVEIN);
2982 /**************************************************************************
2983 * waveInGetDevCapsW [WINMM.@]
2985 UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2990 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2992 ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
2993 if (ret == MMSYSERR_NOERROR) {
2995 wicW.wMid = wicA.wMid;
2996 wicW.wPid = wicA.wPid;
2997 wicW.vDriverVersion = wicA.vDriverVersion;
2998 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, wicW.szPname,
2999 sizeof(wicW.szPname)/sizeof(WCHAR) );
3000 wicW.dwFormats = wicA.dwFormats;
3001 wicW.wChannels = wicA.wChannels;
3002 memcpy(lpCaps, &wicW, min(uSize, sizeof(wicW)));
3007 /**************************************************************************
3008 * waveInGetDevCapsA [WINMM.@]
3010 UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
3014 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3016 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3018 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
3019 return MMSYSERR_BADDEVICEID;
3021 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
3024 /**************************************************************************
3025 * waveInGetErrorTextA [WINMM.@]
3027 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3029 return WAVE_GetErrorText(uError, lpText, uSize);
3032 /**************************************************************************
3033 * waveInGetErrorTextW [WINMM.@]
3035 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3037 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
3038 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
3040 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
3041 HeapFree(GetProcessHeap(), 0, txt);
3045 /**************************************************************************
3046 * waveInOpen [WINMM.@]
3048 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
3049 const LPWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
3050 DWORD_PTR dwInstance, DWORD dwFlags)
3052 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
3053 dwCallback, dwInstance, dwFlags, TRUE);
3056 /**************************************************************************
3057 * waveInClose [WINMM.@]
3059 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
3064 TRACE("(%p)\n", hWaveIn);
3066 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3067 return MMSYSERR_INVALHANDLE;
3069 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
3070 if (dwRet != WAVERR_STILLPLAYING)
3071 MMDRV_Free(hWaveIn, wmld);
3075 /**************************************************************************
3076 * waveInPrepareHeader [WINMM.@]
3078 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
3083 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3085 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
3086 return MMSYSERR_INVALPARAM;
3088 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3089 return MMSYSERR_INVALHANDLE;
3091 lpWaveInHdr->dwBytesRecorded = 0;
3093 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3096 /**************************************************************************
3097 * waveInUnprepareHeader [WINMM.@]
3099 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
3104 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3106 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
3107 return MMSYSERR_INVALPARAM;
3109 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
3110 return MMSYSERR_NOERROR;
3113 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3114 return MMSYSERR_INVALHANDLE;
3116 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3119 /**************************************************************************
3120 * waveInAddBuffer [WINMM.@]
3122 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
3123 WAVEHDR* lpWaveInHdr, UINT uSize)
3127 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3129 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
3130 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3131 return MMSYSERR_INVALHANDLE;
3133 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3136 /**************************************************************************
3137 * waveInReset [WINMM.@]
3139 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
3143 TRACE("(%p);\n", hWaveIn);
3145 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3146 return MMSYSERR_INVALHANDLE;
3148 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
3151 /**************************************************************************
3152 * waveInStart [WINMM.@]
3154 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
3158 TRACE("(%p);\n", hWaveIn);
3160 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3161 return MMSYSERR_INVALHANDLE;
3163 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
3166 /**************************************************************************
3167 * waveInStop [WINMM.@]
3169 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
3173 TRACE("(%p);\n", hWaveIn);
3175 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3176 return MMSYSERR_INVALHANDLE;
3178 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
3181 /**************************************************************************
3182 * waveInGetPosition [WINMM.@]
3184 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
3189 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
3191 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3192 return MMSYSERR_INVALHANDLE;
3194 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE);
3197 /**************************************************************************
3198 * waveInGetID [WINMM.@]
3200 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
3204 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
3206 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3208 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3209 return MMSYSERR_INVALHANDLE;
3211 *lpuDeviceID = wmld->uDeviceID;
3212 return MMSYSERR_NOERROR;
3215 /**************************************************************************
3216 * waveInMessage [WINMM.@]
3218 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
3219 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
3223 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
3225 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
3226 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
3227 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
3229 return MMSYSERR_INVALHANDLE;
3233 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
3234 return MMSYSERR_INVALPARAM;
3237 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
3247 static DWORD WINAPI mmTaskRun(void* pmt)
3249 struct mm_starter mms;
3251 memcpy(&mms, pmt, sizeof(struct mm_starter));
3252 HeapFree(GetProcessHeap(), 0, pmt);
3254 if (mms.event) SetEvent(mms.event);
3258 /******************************************************************
3259 * mmTaskCreate (WINMM.@)
3261 MMRESULT WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD client)
3265 struct mm_starter *mms;
3267 mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter));
3268 if (mms == NULL) return TASKERR_OUTOFMEMORY;
3271 mms->client = client;
3272 if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
3273 mms->event = hEvent;
3275 hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL);
3277 HeapFree(GetProcessHeap(), 0, mms);
3278 if (hEvent) CloseHandle(hEvent);
3279 return TASKERR_OUTOFMEMORY;
3281 if (ph) *ph = hEvent;
3282 CloseHandle(hThread);
3286 /******************************************************************
3287 * mmTaskBlock (WINMM.@)
3289 void WINAPI mmTaskBlock(HANDLE tid)
3295 GetMessageA(&msg, 0, 0, 0);
3296 if (msg.hwnd) DispatchMessageA(&msg);
3297 } while (msg.message != WM_USER);
3300 /******************************************************************
3301 * mmTaskSignal (WINMM.@)
3303 BOOL WINAPI mmTaskSignal(HANDLE tid)
3305 return PostThreadMessageW((DWORD)tid, WM_USER, 0, 0);
3308 /******************************************************************
3309 * mmTaskYield (WINMM.@)
3311 void WINAPI mmTaskYield(void) {}
3313 /******************************************************************
3314 * mmGetCurrentTask (WINMM.@)
3316 HANDLE WINAPI mmGetCurrentTask(void)
3318 return (HANDLE)GetCurrentThreadId();