Lookup driver information in registry and system.ini.
[wine/dcerpc.git] / dlls / winmm / winmm.c
blobc4e39279069ebf285fbd8e363214657dcba42cbe
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * WINMM functions
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
25 * Eric POUECH :
26 * 98/9 added Win32 MCI support
27 * 99/4 added midiStream support
28 * 99/9 added support for loadable low level drivers
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <string.h>
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
37 #include "windef.h"
38 #include "winbase.h"
39 #include "mmsystem.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "winreg.h"
43 #include "winternl.h"
44 #include "winemm.h"
45 #include "wownt32.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
51 /******************************************************************
52 * MyUserYield
54 * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32).
56 static void MyUserYield(void)
58 HMODULE mod = GetModuleHandleA( "user32.dll" );
59 if (mod)
61 FARPROC proc = GetProcAddress( mod, "UserYield16" );
62 if (proc) proc();
66 void (WINAPI *pFnReleaseThunkLock)(DWORD*);
67 void (WINAPI *pFnRestoreThunkLock)(DWORD);
69 /* ========================================================================
70 * G L O B A L S E T T I N G S
71 * ========================================================================*/
73 LPWINE_MM_IDATA WINMM_IData /* = NULL */;
75 /**************************************************************************
76 * WINMM_CreateIData [internal]
78 static BOOL WINMM_CreateIData(HINSTANCE hInstDLL)
80 WINMM_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
82 if (!WINMM_IData)
83 return FALSE;
84 WINMM_IData->hWinMM32Instance = hInstDLL;
85 InitializeCriticalSection(&WINMM_IData->cs);
86 WINMM_IData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
87 WINMM_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
88 WINMM_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
89 TRACE("Created IData (%p)\n", WINMM_IData);
90 return TRUE;
93 /**************************************************************************
94 * WINMM_DeleteIData [internal]
96 static void WINMM_DeleteIData(void)
98 if (WINMM_IData) {
99 TIME_MMTimeStop();
101 /* FIXME: should also free content and resources allocated
102 * inside WINMM_IData */
103 CloseHandle(WINMM_IData->psStopEvent);
104 CloseHandle(WINMM_IData->psLastEvent);
105 DeleteCriticalSection(&WINMM_IData->cs);
106 HeapFree(GetProcessHeap(), 0, WINMM_IData);
107 WINMM_IData = NULL;
111 /******************************************************************
112 * WINMM_LoadMMSystem
115 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR);
116 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR);
118 BOOL WINMM_CheckForMMSystem(void)
120 /* 0 is not checked yet, -1 is not present, 1 is present */
121 static int loaded /* = 0 */;
123 if (loaded == 0)
125 HANDLE h = GetModuleHandleA("kernel32");
126 loaded = -1;
127 if (h)
129 pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16");
130 pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16");
131 if (pGetModuleHandle16 && pLoadLibrary16 &&
132 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
133 loaded = 1;
136 return loaded > 0;
139 /******************************************************************
140 * WINMM_ErrorToString
142 const char* WINMM_ErrorToString(MMRESULT error)
144 #define ERR_TO_STR(dev) case dev: return #dev
145 static char unknown[32];
146 switch (error) {
147 ERR_TO_STR(MMSYSERR_NOERROR);
148 ERR_TO_STR(MMSYSERR_ERROR);
149 ERR_TO_STR(MMSYSERR_BADDEVICEID);
150 ERR_TO_STR(MMSYSERR_NOTENABLED);
151 ERR_TO_STR(MMSYSERR_ALLOCATED);
152 ERR_TO_STR(MMSYSERR_INVALHANDLE);
153 ERR_TO_STR(MMSYSERR_NODRIVER);
154 ERR_TO_STR(MMSYSERR_NOMEM);
155 ERR_TO_STR(MMSYSERR_NOTSUPPORTED);
156 ERR_TO_STR(MMSYSERR_BADERRNUM);
157 ERR_TO_STR(MMSYSERR_INVALFLAG);
158 ERR_TO_STR(MMSYSERR_INVALPARAM);
159 ERR_TO_STR(WAVERR_BADFORMAT);
160 ERR_TO_STR(WAVERR_STILLPLAYING);
161 ERR_TO_STR(WAVERR_UNPREPARED);
162 ERR_TO_STR(WAVERR_SYNC);
164 sprintf(unknown, "Unknown(0x%08x)", error);
165 return unknown;
166 #undef ERR_TO_STR
169 /**************************************************************************
170 * DllMain (WINMM.init)
172 * WINMM DLL entry point
175 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
177 TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
179 switch (fdwReason) {
180 case DLL_PROCESS_ATTACH:
181 DisableThreadLibraryCalls(hInstDLL);
183 if (!WINMM_CreateIData(hInstDLL))
184 return FALSE;
185 if (!MMDRV_Init()) {
186 WINMM_DeleteIData();
187 return FALSE;
189 break;
190 case DLL_PROCESS_DETACH:
191 /* close all opened MCI drivers */
192 MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE);
193 MMDRV_Exit();
194 /* now unload all remaining drivers... */
195 DRIVER_UnloadAll();
197 WINMM_DeleteIData();
198 break;
200 return TRUE;
203 /**************************************************************************
204 * Mixer devices. New to Win95
207 /**************************************************************************
208 * find out the real mixer ID depending on hmix (depends on dwFlags)
210 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
212 LPWINE_MIXER lpwm = NULL;
214 switch (dwFlags & 0xF0000000ul) {
215 case MIXER_OBJECTF_MIXER:
216 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
217 break;
218 case MIXER_OBJECTF_HMIXER:
219 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
220 break;
221 case MIXER_OBJECTF_WAVEOUT:
222 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
223 break;
224 case MIXER_OBJECTF_HWAVEOUT:
225 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
226 break;
227 case MIXER_OBJECTF_WAVEIN:
228 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
229 break;
230 case MIXER_OBJECTF_HWAVEIN:
231 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
232 break;
233 case MIXER_OBJECTF_MIDIOUT:
234 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
235 break;
236 case MIXER_OBJECTF_HMIDIOUT:
237 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
238 break;
239 case MIXER_OBJECTF_MIDIIN:
240 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
241 break;
242 case MIXER_OBJECTF_HMIDIIN:
243 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
244 break;
245 case MIXER_OBJECTF_AUX:
246 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
247 break;
248 default:
249 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
250 break;
252 return lpwm;
255 /**************************************************************************
256 * mixerGetNumDevs [WINMM.@]
258 UINT WINAPI mixerGetNumDevs(void)
260 return MMDRV_GetNum(MMDRV_MIXER);
263 /**************************************************************************
264 * mixerGetDevCapsA [WINMM.@]
266 UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize)
268 LPWINE_MLD wmld;
270 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
272 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL)
273 return MMSYSERR_BADDEVICEID;
275 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
278 /**************************************************************************
279 * mixerGetDevCapsW [WINMM.@]
281 UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize)
283 MIXERCAPSA micA;
284 UINT ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA));
286 if (ret == MMSYSERR_NOERROR) {
287 MIXERCAPSW micW;
288 micW.wMid = micA.wMid;
289 micW.wPid = micA.wPid;
290 micW.vDriverVersion = micA.vDriverVersion;
291 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
292 sizeof(micW.szPname)/sizeof(WCHAR) );
293 micW.fdwSupport = micA.fdwSupport;
294 micW.cDestinations = micA.cDestinations;
295 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
297 return ret;
300 UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
301 DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32)
303 HANDLE hMix;
304 LPWINE_MLD wmld;
305 DWORD dwRet = 0;
306 MIXEROPENDESC mod;
308 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
309 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
311 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
312 &dwCallback, &dwInstance, bFrom32);
314 wmld->uDeviceID = uDeviceID;
315 mod.hmx = (HMIXEROBJ)hMix;
316 mod.dwCallback = dwCallback;
317 mod.dwInstance = dwInstance;
319 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
321 if (dwRet != MMSYSERR_NOERROR) {
322 MMDRV_Free(hMix, wmld);
323 hMix = 0;
325 if (lphMix) *lphMix = hMix;
326 TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
328 return dwRet;
331 /**************************************************************************
332 * mixerOpen [WINMM.@]
334 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
335 DWORD_PTR dwInstance, DWORD fdwOpen)
337 return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
340 /**************************************************************************
341 * mixerClose [WINMM.@]
343 UINT WINAPI mixerClose(HMIXER hMix)
345 LPWINE_MLD wmld;
346 DWORD dwRet;
348 TRACE("(%p)\n", hMix);
350 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
352 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
353 MMDRV_Free(hMix, wmld);
355 return dwRet;
358 /**************************************************************************
359 * mixerGetID [WINMM.@]
361 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
363 LPWINE_MIXER lpwm;
365 TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID);
367 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
368 return MMSYSERR_INVALHANDLE;
371 if (lpid)
372 *lpid = lpwm->mld.uDeviceID;
374 return MMSYSERR_NOERROR;
377 /**************************************************************************
378 * mixerGetControlDetailsA [WINMM.@]
380 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
381 DWORD fdwDetails)
383 LPWINE_MIXER lpwm;
385 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
387 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
388 return MMSYSERR_INVALHANDLE;
390 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
391 return MMSYSERR_INVALPARAM;
393 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdA,
394 fdwDetails, TRUE);
397 /**************************************************************************
398 * mixerGetControlDetailsW [WINMM.@]
400 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
402 DWORD ret = MMSYSERR_NOTENABLED;
404 TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
406 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
407 return MMSYSERR_INVALPARAM;
409 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
410 case MIXER_GETCONTROLDETAILSF_VALUE:
411 /* can savely use W structure as it is, no string inside */
412 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
413 break;
414 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
416 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
417 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
418 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
419 int i;
421 if (lpmcd->u.cMultipleItems != 0) {
422 size *= lpmcd->u.cMultipleItems;
424 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
425 lpmcd->paDetails = pDetailsA;
426 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
427 /* set up lpmcd->paDetails */
428 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
429 /* copy from lpmcd->paDetails back to paDetailsW; */
430 if(ret == MMSYSERR_NOERROR) {
431 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
432 pDetailsW->dwParam1 = pDetailsA->dwParam1;
433 pDetailsW->dwParam2 = pDetailsA->dwParam2;
434 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
435 pDetailsW->szName,
436 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
437 pDetailsA++;
438 pDetailsW++;
440 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
441 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
443 HeapFree(GetProcessHeap(), 0, pDetailsA);
444 lpmcd->paDetails = pDetailsW;
445 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
447 break;
448 default:
449 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
452 return ret;
455 /**************************************************************************
456 * mixerGetLineControlsA [WINMM.@]
458 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
459 DWORD fdwControls)
461 LPWINE_MIXER lpwm;
463 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
465 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
466 return MMSYSERR_INVALHANDLE;
468 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
469 return MMSYSERR_INVALPARAM;
471 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcA,
472 fdwControls, TRUE);
475 /**************************************************************************
476 * mixerGetLineControlsW [WINMM.@]
478 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
479 DWORD fdwControls)
481 MIXERLINECONTROLSA mlcA;
482 DWORD ret;
483 int i;
485 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
487 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
488 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
489 return MMSYSERR_INVALPARAM;
491 mlcA.cbStruct = sizeof(mlcA);
492 mlcA.dwLineID = lpmlcW->dwLineID;
493 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
494 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
495 mlcA.cControls = lpmlcW->cControls;
496 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
497 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
498 mlcA.cControls * mlcA.cbmxctrl);
500 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
502 if (ret == MMSYSERR_NOERROR) {
503 lpmlcW->dwLineID = mlcA.dwLineID;
504 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
505 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
506 lpmlcW->cControls = mlcA.cControls;
508 for (i = 0; i < mlcA.cControls; i++) {
509 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
510 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
511 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
512 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
513 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
514 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
515 lpmlcW->pamxctrl[i].szShortName,
516 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
517 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
518 lpmlcW->pamxctrl[i].szName,
519 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
520 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
521 * sizeof(mlcA.pamxctrl[i].Bounds) */
522 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
523 sizeof(mlcA.pamxctrl[i].Bounds));
524 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
525 * sizeof(mlcA.pamxctrl[i].Metrics) */
526 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
527 sizeof(mlcA.pamxctrl[i].Metrics));
531 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
533 return ret;
536 /**************************************************************************
537 * mixerGetLineInfoA [WINMM.@]
539 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
541 LPWINE_MIXER lpwm;
543 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
545 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
546 return MMSYSERR_INVALHANDLE;
548 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW,
549 fdwInfo, TRUE);
552 /**************************************************************************
553 * mixerGetLineInfoW [WINMM.@]
555 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
556 DWORD fdwInfo)
558 MIXERLINEA mliA;
559 UINT ret;
561 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
563 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
564 return MMSYSERR_INVALPARAM;
566 mliA.cbStruct = sizeof(mliA);
567 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
568 case MIXER_GETLINEINFOF_COMPONENTTYPE:
569 mliA.dwComponentType = lpmliW->dwComponentType;
570 break;
571 case MIXER_GETLINEINFOF_DESTINATION:
572 mliA.dwDestination = lpmliW->dwDestination;
573 break;
574 case MIXER_GETLINEINFOF_LINEID:
575 mliA.dwLineID = lpmliW->dwLineID;
576 break;
577 case MIXER_GETLINEINFOF_SOURCE:
578 mliA.dwDestination = lpmliW->dwDestination;
579 mliA.dwSource = lpmliW->dwSource;
580 break;
581 case MIXER_GETLINEINFOF_TARGETTYPE:
582 mliA.Target.dwType = lpmliW->Target.dwType;
583 mliA.Target.wMid = lpmliW->Target.wMid;
584 mliA.Target.wPid = lpmliW->Target.wPid;
585 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
586 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
587 break;
588 default:
589 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
592 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
594 lpmliW->dwDestination = mliA.dwDestination;
595 lpmliW->dwSource = mliA.dwSource;
596 lpmliW->dwLineID = mliA.dwLineID;
597 lpmliW->fdwLine = mliA.fdwLine;
598 lpmliW->dwUser = mliA.dwUser;
599 lpmliW->dwComponentType = mliA.dwComponentType;
600 lpmliW->cChannels = mliA.cChannels;
601 lpmliW->cConnections = mliA.cConnections;
602 lpmliW->cControls = mliA.cControls;
603 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
604 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
605 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
606 sizeof(lpmliW->szName)/sizeof(WCHAR) );
607 lpmliW->Target.dwType = mliA.Target.dwType;
608 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
609 lpmliW->Target.wMid = mliA.Target.wMid;
610 lpmliW->Target.wPid = mliA.Target.wPid;
611 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
612 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
613 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
615 return ret;
618 /**************************************************************************
619 * mixerSetControlDetails [WINMM.@]
621 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
622 DWORD fdwDetails)
624 LPWINE_MIXER lpwm;
626 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
628 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
629 return MMSYSERR_INVALHANDLE;
631 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcdA,
632 fdwDetails, TRUE);
635 /**************************************************************************
636 * mixerMessage [WINMM.@]
638 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
640 LPWINE_MLD wmld;
642 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
643 (DWORD)hmix, uMsg, dwParam1, dwParam2);
645 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
646 return MMSYSERR_INVALHANDLE;
648 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
651 /**************************************************************************
652 * auxGetNumDevs [WINMM.@]
654 UINT WINAPI auxGetNumDevs(void)
656 return MMDRV_GetNum(MMDRV_AUX);
659 /**************************************************************************
660 * auxGetDevCapsW [WINMM.@]
662 UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
664 AUXCAPSA acA;
665 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
667 if (ret == MMSYSERR_NOERROR) {
668 AUXCAPSW acW;
669 acW.wMid = acA.wMid;
670 acW.wPid = acA.wPid;
671 acW.vDriverVersion = acA.vDriverVersion;
672 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, acW.szPname,
673 sizeof(acW.szPname)/sizeof(WCHAR) );
674 acW.wTechnology = acA.wTechnology;
675 acW.dwSupport = acA.dwSupport;
676 memcpy(lpCaps, &acW, min(uSize, sizeof(acW)));
678 return ret;
681 /**************************************************************************
682 * auxGetDevCapsA [WINMM.@]
684 UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
686 LPWINE_MLD wmld;
688 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
690 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
692 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
693 return MMSYSERR_INVALHANDLE;
694 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
697 /**************************************************************************
698 * auxGetVolume [WINMM.@]
700 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
702 LPWINE_MLD wmld;
704 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
706 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
707 return MMSYSERR_INVALHANDLE;
708 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE);
711 /**************************************************************************
712 * auxSetVolume [WINMM.@]
714 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
716 LPWINE_MLD wmld;
718 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
720 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
721 return MMSYSERR_INVALHANDLE;
722 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
725 /**************************************************************************
726 * auxOutMessage [WINMM.@]
728 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2)
730 LPWINE_MLD wmld;
732 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
733 return MMSYSERR_INVALHANDLE;
735 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
738 /**************************************************************************
739 * mciGetErrorStringW [WINMM.@]
741 BOOL WINAPI mciGetErrorStringW(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength)
743 char bufstr[MAXERRORLENGTH];
744 BOOL ret = mciGetErrorStringA(wError, bufstr, MAXERRORLENGTH);
746 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
747 return ret;
750 /**************************************************************************
751 * mciGetErrorStringA [WINMM.@]
753 BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength)
755 BOOL ret = FALSE;
757 if (lpstrBuffer != NULL && uLength > 0 &&
758 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
760 if (LoadStringA(WINMM_IData->hWinMM32Instance,
761 dwError, lpstrBuffer, uLength) > 0) {
762 ret = TRUE;
765 return ret;
768 /**************************************************************************
769 * mciDriverNotify [WINMM.@]
771 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, MCIDEVICEID wDevID, UINT wStatus)
773 TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
775 return PostMessageW(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
778 /**************************************************************************
779 * mciGetDriverData [WINMM.@]
781 DWORD WINAPI mciGetDriverData(MCIDEVICEID uDeviceID)
783 LPWINE_MCIDRIVER wmd;
785 TRACE("(%04x)\n", uDeviceID);
787 wmd = MCI_GetDriver(uDeviceID);
789 if (!wmd) {
790 WARN("Bad uDeviceID\n");
791 return 0L;
794 return wmd->dwPrivate;
797 /**************************************************************************
798 * mciSetDriverData [WINMM.@]
800 BOOL WINAPI mciSetDriverData(MCIDEVICEID uDeviceID, DWORD data)
802 LPWINE_MCIDRIVER wmd;
804 TRACE("(%04x, %08lx)\n", uDeviceID, data);
806 wmd = MCI_GetDriver(uDeviceID);
808 if (!wmd) {
809 WARN("Bad uDeviceID\n");
810 return FALSE;
813 wmd->dwPrivate = data;
814 return TRUE;
817 /**************************************************************************
818 * mciSendCommandA [WINMM.@]
820 DWORD WINAPI mciSendCommandA(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
822 DWORD dwRet;
824 TRACE("(%08x, %s, %08lx, %08lx)\n",
825 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
827 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
828 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
829 TRACE("=> %08lx\n", dwRet);
830 return dwRet;
833 inline static LPSTR strdupWtoA( LPCWSTR str )
835 LPSTR ret;
836 INT len;
838 if (!str) return NULL;
839 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
840 ret = HeapAlloc( GetProcessHeap(), 0, len );
841 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
842 return ret;
845 static int MCI_MapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2)
847 switch(msg)
849 case MCI_CLOSE:
850 case MCI_PLAY:
851 case MCI_SEEK:
852 case MCI_STOP:
853 case MCI_PAUSE:
854 case MCI_GETDEVCAPS:
855 case MCI_SPIN:
856 case MCI_SET:
857 case MCI_STEP:
858 case MCI_RECORD:
859 case MCI_BREAK:
860 case MCI_SOUND:
861 case MCI_STATUS:
862 case MCI_CUE:
863 case MCI_REALIZE:
864 case MCI_PUT:
865 case MCI_WHERE:
866 case MCI_FREEZE:
867 case MCI_UNFREEZE:
868 case MCI_CUT:
869 case MCI_COPY:
870 case MCI_PASTE:
871 case MCI_UPDATE:
872 case MCI_RESUME:
873 case MCI_DELETE:
874 return 0;
876 case MCI_OPEN:
878 MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*dwParam2;
879 MCI_OPEN_PARMSA *mci_openA;
880 DWORD_PTR *ptr;
882 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_openA) + sizeof(DWORD_PTR));
883 if (!ptr) return -1;
885 *ptr++ = *dwParam2; /* save the previous pointer */
886 *dwParam2 = (DWORD_PTR)ptr;
887 mci_openA = (MCI_OPEN_PARMSA *)ptr;
889 if (dwParam1 & MCI_NOTIFY)
890 mci_openA->dwCallback = mci_openW->dwCallback;
892 if (dwParam1 & MCI_OPEN_TYPE)
894 if (dwParam1 & MCI_OPEN_TYPE_ID)
895 mci_openA->lpstrDeviceType = (LPSTR)mci_openW->lpstrDeviceType;
896 else
897 mci_openA->lpstrDeviceType = strdupWtoA(mci_openW->lpstrDeviceType);
899 if (dwParam1 & MCI_OPEN_ELEMENT)
901 if (dwParam1 & MCI_OPEN_ELEMENT_ID)
902 mci_openA->lpstrElementName = (LPSTR)mci_openW->lpstrElementName;
903 else
904 mci_openA->lpstrElementName = strdupWtoA(mci_openW->lpstrElementName);
906 if (dwParam1 & MCI_OPEN_ALIAS)
907 mci_openA->lpstrAlias = strdupWtoA(mci_openW->lpstrAlias);
909 return 1;
911 case MCI_WINDOW:
912 if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
914 MCI_ANIM_WINDOW_PARMSW *mci_windowW = (MCI_ANIM_WINDOW_PARMSW *)*dwParam2;
915 MCI_ANIM_WINDOW_PARMSA *mci_windowA;
917 mci_windowA = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowA));
918 if (!mci_windowA) return -1;
920 *dwParam2 = (DWORD_PTR)mci_windowA;
922 mci_windowA->lpstrText = strdupWtoA(mci_windowW->lpstrText);
924 if (dwParam1 & MCI_NOTIFY)
925 mci_windowA->dwCallback = mci_windowW->dwCallback;
926 if (dwParam1 & MCI_ANIM_WINDOW_HWND)
927 mci_windowA->hWnd = mci_windowW->hWnd;
928 if (dwParam1 & MCI_ANIM_WINDOW_STATE)
929 mci_windowA->nCmdShow = mci_windowW->nCmdShow;
931 return 1;
933 return 0;
935 case MCI_SYSINFO:
937 MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*dwParam2;
938 MCI_SYSINFO_PARMSA *mci_sysinfoA;
939 DWORD_PTR *ptr;
941 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoA) + sizeof(DWORD_PTR));
942 if (!ptr) return -1;
944 *ptr++ = *dwParam2; /* save the previous pointer */
945 *dwParam2 = (DWORD_PTR)ptr;
946 mci_sysinfoA = (MCI_SYSINFO_PARMSA *)ptr;
948 if (dwParam1 & MCI_NOTIFY)
949 mci_sysinfoA->dwCallback = mci_sysinfoW->dwCallback;
951 mci_sysinfoA->dwRetSize = mci_sysinfoW->dwRetSize; /* FIXME */
952 mci_sysinfoA->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoA->dwRetSize);
954 return 1;
957 case MCI_INFO:
958 case MCI_SAVE:
959 case MCI_LOAD:
960 case MCI_ESCAPE:
961 default:
962 FIXME("Message 0x%04x needs translation\n", msg);
963 return -1;
965 return 0;
968 static DWORD MCI_UnmapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2,
969 DWORD result)
971 switch(msg)
973 case MCI_OPEN:
975 DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
976 MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*ptr;
977 MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA *)(ptr + 1);
979 mci_openW->wDeviceID = mci_openA->wDeviceID;
981 if (dwParam1 & MCI_OPEN_TYPE)
983 if (!(dwParam1 & MCI_OPEN_TYPE_ID))
984 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrDeviceType);
986 if (dwParam1 & MCI_OPEN_ELEMENT)
988 if (!(dwParam1 & MCI_OPEN_ELEMENT_ID))
989 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrElementName);
991 if (dwParam1 & MCI_OPEN_ALIAS)
992 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrAlias);
993 HeapFree(GetProcessHeap(), 0, ptr);
995 break;
997 case MCI_WINDOW:
998 if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
1000 MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)dwParam2;
1002 HeapFree(GetProcessHeap(), 0, (void *)mci_windowA->lpstrText);
1003 HeapFree(GetProcessHeap(), 0, mci_windowA);
1005 break;
1007 case MCI_SYSINFO:
1009 DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
1010 MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*ptr;
1011 MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)(ptr + 1);
1013 if (!result)
1015 mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber;
1016 mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType;
1017 MultiByteToWideChar(CP_ACP, 0,
1018 mci_sysinfoA->lpstrReturn, mci_sysinfoA->dwRetSize,
1019 mci_sysinfoW->lpstrReturn, mci_sysinfoW->dwRetSize);
1022 HeapFree(GetProcessHeap(), 0, mci_sysinfoA->lpstrReturn);
1023 HeapFree(GetProcessHeap(), 0, ptr);
1025 break;
1027 default:
1028 FIXME("Message 0x%04x needs unmapping\n", msg);
1029 break;
1032 return result;
1036 /**************************************************************************
1037 * mciSendCommandW [WINMM.@]
1039 * FIXME: we should do the things other way around, but since our
1040 * MM subsystem is not unicode aware...
1042 DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1044 DWORD ret;
1045 int mapped;
1047 TRACE("(%08x, %s, %08lx, %08lx)\n",
1048 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1050 mapped = MCI_MapMsgWtoA(wMsg, dwParam1, &dwParam2);
1051 if (mapped == -1)
1053 FIXME("message %04x mapping failed\n", wMsg);
1054 return MMSYSERR_NOMEM;
1056 ret = mciSendCommandA(wDevID, wMsg, dwParam1, dwParam2);
1057 if (mapped)
1058 MCI_UnmapMsgWtoA(wMsg, dwParam1, dwParam2, ret);
1059 return ret;
1062 /**************************************************************************
1063 * mciGetDeviceIDA [WINMM.@]
1065 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1067 return MCI_GetDriverFromString(lpstrName);
1070 /**************************************************************************
1071 * mciGetDeviceIDW [WINMM.@]
1073 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1075 LPSTR lpstrName = NULL;
1076 UINT ret;
1077 INT len;
1079 if (lpwstrName) {
1080 len = WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, NULL, 0, NULL, NULL );
1081 lpstrName = HeapAlloc( GetProcessHeap(), 0, len );
1082 if (lpstrName) WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, lpstrName, len, NULL, NULL );
1084 ret = MCI_GetDriverFromString(lpstrName);
1085 HeapFree(GetProcessHeap(), 0, lpstrName);
1086 return ret;
1089 /**************************************************************************
1090 * MCI_DefYieldProc [internal]
1092 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1094 INT16 ret;
1096 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1098 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
1099 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1100 MyUserYield();
1101 ret = 0;
1102 } else {
1103 MSG msg;
1105 msg.hwnd = HWND_32(HIWORD(data));
1106 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1107 ret = -1;
1109 return ret;
1112 /**************************************************************************
1113 * mciSetYieldProc [WINMM.@]
1115 BOOL WINAPI mciSetYieldProc(MCIDEVICEID uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1117 LPWINE_MCIDRIVER wmd;
1119 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1121 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1122 WARN("Bad uDeviceID\n");
1123 return FALSE;
1126 wmd->lpfnYieldProc = fpYieldProc;
1127 wmd->dwYieldData = dwYieldData;
1128 wmd->bIs32 = TRUE;
1130 return TRUE;
1133 /**************************************************************************
1134 * mciGetDeviceIDFromElementIDW [WINMM.@]
1136 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1138 /* FIXME: that's rather strange, there is no
1139 * mciGetDeviceIDFromElementID32A in winmm.spec
1141 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1142 return 0;
1145 /**************************************************************************
1146 * mciGetYieldProc [WINMM.@]
1148 YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID uDeviceID, DWORD* lpdwYieldData)
1150 LPWINE_MCIDRIVER wmd;
1152 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1154 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1155 WARN("Bad uDeviceID\n");
1156 return NULL;
1158 if (!wmd->lpfnYieldProc) {
1159 WARN("No proc set\n");
1160 return NULL;
1162 if (!wmd->bIs32) {
1163 WARN("Proc is 32 bit\n");
1164 return NULL;
1166 return wmd->lpfnYieldProc;
1169 /**************************************************************************
1170 * mciGetCreatorTask [WINMM.@]
1172 HTASK WINAPI mciGetCreatorTask(MCIDEVICEID uDeviceID)
1174 LPWINE_MCIDRIVER wmd;
1175 HTASK ret = 0;
1177 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
1179 TRACE("(%u) => %p\n", uDeviceID, ret);
1180 return ret;
1183 /**************************************************************************
1184 * mciDriverYield [WINMM.@]
1186 UINT WINAPI mciDriverYield(MCIDEVICEID uDeviceID)
1188 LPWINE_MCIDRIVER wmd;
1189 UINT ret = 0;
1191 TRACE("(%04x)\n", uDeviceID);
1193 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
1194 MyUserYield();
1195 } else {
1196 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1199 return ret;
1202 /**************************************************************************
1203 * midiOutGetNumDevs [WINMM.@]
1205 UINT WINAPI midiOutGetNumDevs(void)
1207 return MMDRV_GetNum(MMDRV_MIDIOUT);
1210 /**************************************************************************
1211 * midiOutGetDevCapsW [WINMM.@]
1213 UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps,
1214 UINT uSize)
1216 MIDIOUTCAPSA mocA;
1217 UINT ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
1219 if (ret == MMSYSERR_NOERROR) {
1220 MIDIOUTCAPSW mocW;
1221 mocW.wMid = mocA.wMid;
1222 mocW.wPid = mocA.wPid;
1223 mocW.vDriverVersion = mocA.vDriverVersion;
1224 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, mocW.szPname,
1225 sizeof(mocW.szPname)/sizeof(WCHAR) );
1226 mocW.wTechnology = mocA.wTechnology;
1227 mocW.wVoices = mocA.wVoices;
1228 mocW.wNotes = mocA.wNotes;
1229 mocW.wChannelMask = mocA.wChannelMask;
1230 mocW.dwSupport = mocA.dwSupport;
1231 memcpy(lpCaps, &mocW, min(uSize, sizeof(mocW)));
1233 return ret;
1236 /**************************************************************************
1237 * midiOutGetDevCapsA [WINMM.@]
1239 UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps,
1240 UINT uSize)
1242 LPWINE_MLD wmld;
1244 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
1246 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1248 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1249 return MMSYSERR_INVALHANDLE;
1251 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
1254 /**************************************************************************
1255 * MIDI_GetErrorText [internal]
1257 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1259 UINT16 ret = MMSYSERR_BADERRNUM;
1261 if (lpText == NULL) {
1262 ret = MMSYSERR_INVALPARAM;
1263 } else if (uSize == 0) {
1264 ret = MMSYSERR_NOERROR;
1265 } else if (
1266 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
1267 * a warning for the test was always true */
1268 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
1269 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
1271 if (LoadStringA(WINMM_IData->hWinMM32Instance,
1272 uError, lpText, uSize) > 0) {
1273 ret = MMSYSERR_NOERROR;
1276 return ret;
1279 /**************************************************************************
1280 * midiOutGetErrorTextA [WINMM.@]
1282 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1284 return MIDI_GetErrorText(uError, lpText, uSize);
1287 /**************************************************************************
1288 * midiOutGetErrorTextW [WINMM.@]
1290 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1292 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1293 UINT ret;
1295 ret = MIDI_GetErrorText(uError, xstr, uSize);
1296 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1297 HeapFree(GetProcessHeap(), 0, xstr);
1298 return ret;
1301 /**************************************************************************
1302 * MIDI_OutAlloc [internal]
1304 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1305 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1306 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1308 HANDLE hMidiOut;
1309 LPWINE_MIDI lpwm;
1310 UINT size;
1312 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1314 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1315 lpdwCallback, lpdwInstance, bFrom32);
1317 if (lphMidiOut != NULL)
1318 *lphMidiOut = hMidiOut;
1320 if (lpwm) {
1321 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1322 lpwm->mod.dwCallback = *lpdwCallback;
1323 lpwm->mod.dwInstance = *lpdwInstance;
1324 lpwm->mod.dnDevNode = 0;
1325 lpwm->mod.cIds = cIDs;
1326 if (cIDs)
1327 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1329 return lpwm;
1332 UINT MIDI_OutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback,
1333 DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32)
1335 HMIDIOUT hMidiOut;
1336 LPWINE_MIDI lpwm;
1337 UINT dwRet = 0;
1339 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1340 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1342 if (lphMidiOut != NULL) *lphMidiOut = 0;
1344 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1345 0, NULL, bFrom32);
1347 if (lpwm == NULL)
1348 return MMSYSERR_NOMEM;
1350 lpwm->mld.uDeviceID = uDeviceID;
1352 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1354 if (dwRet != MMSYSERR_NOERROR) {
1355 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1356 hMidiOut = 0;
1359 if (lphMidiOut) *lphMidiOut = hMidiOut;
1360 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
1362 return dwRet;
1365 /**************************************************************************
1366 * midiOutOpen [WINMM.@]
1368 UINT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
1369 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
1371 return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1374 /**************************************************************************
1375 * midiOutClose [WINMM.@]
1377 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1379 LPWINE_MLD wmld;
1380 DWORD dwRet;
1382 TRACE("(%p)\n", hMidiOut);
1384 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1385 return MMSYSERR_INVALHANDLE;
1387 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1388 MMDRV_Free(hMidiOut, wmld);
1390 return dwRet;
1393 /**************************************************************************
1394 * midiOutPrepareHeader [WINMM.@]
1396 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1397 MIDIHDR* lpMidiOutHdr, UINT uSize)
1399 LPWINE_MLD wmld;
1401 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1403 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
1404 return MMSYSERR_INVALPARAM;
1406 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1407 return MMSYSERR_INVALHANDLE;
1409 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1412 /**************************************************************************
1413 * midiOutUnprepareHeader [WINMM.@]
1415 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1416 MIDIHDR* lpMidiOutHdr, UINT uSize)
1418 LPWINE_MLD wmld;
1420 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1422 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
1423 return MMSYSERR_INVALPARAM;
1425 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1426 return MMSYSERR_NOERROR;
1429 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1430 return MMSYSERR_INVALHANDLE;
1432 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1435 /**************************************************************************
1436 * midiOutShortMsg [WINMM.@]
1438 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1440 LPWINE_MLD wmld;
1442 TRACE("(%p, %08lX)\n", hMidiOut, dwMsg);
1444 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1445 return MMSYSERR_INVALHANDLE;
1447 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE);
1450 /**************************************************************************
1451 * midiOutLongMsg [WINMM.@]
1453 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1454 MIDIHDR* lpMidiOutHdr, UINT uSize)
1456 LPWINE_MLD wmld;
1458 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1460 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1461 return MMSYSERR_INVALHANDLE;
1463 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1466 /**************************************************************************
1467 * midiOutReset [WINMM.@]
1469 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1471 LPWINE_MLD wmld;
1473 TRACE("(%p)\n", hMidiOut);
1475 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1476 return MMSYSERR_INVALHANDLE;
1478 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1481 /**************************************************************************
1482 * midiOutGetVolume [WINMM.@]
1484 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
1486 LPWINE_MLD wmld;
1488 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
1490 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1491 return MMSYSERR_INVALHANDLE;
1493 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE);
1496 /**************************************************************************
1497 * midiOutSetVolume [WINMM.@]
1499 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
1501 LPWINE_MLD wmld;
1503 TRACE("(%p, %ld);\n", hMidiOut, dwVolume);
1505 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1506 return MMSYSERR_INVALHANDLE;
1508 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1511 /**************************************************************************
1512 * midiOutCachePatches [WINMM.@]
1514 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1515 WORD* lpwPatchArray, UINT uFlags)
1517 /* not really necessary to support this */
1518 FIXME("not supported yet\n");
1519 return MMSYSERR_NOTSUPPORTED;
1522 /**************************************************************************
1523 * midiOutCacheDrumPatches [WINMM.@]
1525 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1526 WORD* lpwKeyArray, UINT uFlags)
1528 FIXME("not supported yet\n");
1529 return MMSYSERR_NOTSUPPORTED;
1532 /**************************************************************************
1533 * midiOutGetID [WINMM.@]
1535 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1537 LPWINE_MLD wmld;
1539 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
1541 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1542 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1543 return MMSYSERR_INVALHANDLE;
1545 *lpuDeviceID = wmld->uDeviceID;
1546 return MMSYSERR_NOERROR;
1549 /**************************************************************************
1550 * midiOutMessage [WINMM.@]
1552 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1553 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1555 LPWINE_MLD wmld;
1557 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1559 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1560 /* HACK... */
1561 if (uMessage == 0x0001) {
1562 *(LPDWORD)dwParam1 = 1;
1563 return 0;
1565 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1566 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1568 return MMSYSERR_INVALHANDLE;
1571 switch (uMessage) {
1572 case MODM_OPEN:
1573 case MODM_CLOSE:
1574 FIXME("can't handle OPEN or CLOSE message!\n");
1575 return MMSYSERR_NOTSUPPORTED;
1577 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1580 /**************************************************************************
1581 * midiInGetNumDevs [WINMM.@]
1583 UINT WINAPI midiInGetNumDevs(void)
1585 return MMDRV_GetNum(MMDRV_MIDIIN);
1588 /**************************************************************************
1589 * midiInGetDevCapsW [WINMM.@]
1591 UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1593 MIDIINCAPSA micA;
1594 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, sizeof(micA));
1596 if (ret == MMSYSERR_NOERROR) {
1597 MIDIINCAPSW micW;
1598 micW.wMid = micA.wMid;
1599 micW.wPid = micA.wPid;
1600 micW.vDriverVersion = micA.vDriverVersion;
1601 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
1602 sizeof(micW.szPname)/sizeof(WCHAR) );
1603 micW.dwSupport = micA.dwSupport;
1604 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
1606 return ret;
1609 /**************************************************************************
1610 * midiInGetDevCapsA [WINMM.@]
1612 UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1614 LPWINE_MLD wmld;
1616 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1618 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1620 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1621 return MMSYSERR_INVALHANDLE;
1623 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
1626 /**************************************************************************
1627 * midiInGetErrorTextW [WINMM.@]
1629 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1631 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1632 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1634 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1635 HeapFree(GetProcessHeap(), 0, xstr);
1636 return ret;
1639 /**************************************************************************
1640 * midiInGetErrorTextA [WINMM.@]
1642 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1644 return MIDI_GetErrorText(uError, lpText, uSize);
1647 UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1648 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1650 HANDLE hMidiIn;
1651 LPWINE_MIDI lpwm;
1652 DWORD dwRet = 0;
1654 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1655 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1657 if (lphMidiIn != NULL) *lphMidiIn = 0;
1659 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1660 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1662 if (lpwm == NULL)
1663 return MMSYSERR_NOMEM;
1665 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1666 lpwm->mod.dwCallback = dwCallback;
1667 lpwm->mod.dwInstance = dwInstance;
1669 lpwm->mld.uDeviceID = uDeviceID;
1670 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1672 if (dwRet != MMSYSERR_NOERROR) {
1673 MMDRV_Free(hMidiIn, &lpwm->mld);
1674 hMidiIn = 0;
1676 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1677 TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn);
1679 return dwRet;
1682 /**************************************************************************
1683 * midiInOpen [WINMM.@]
1685 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1686 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1688 return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1691 /**************************************************************************
1692 * midiInClose [WINMM.@]
1694 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1696 LPWINE_MLD wmld;
1697 DWORD dwRet;
1699 TRACE("(%p)\n", hMidiIn);
1701 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1702 return MMSYSERR_INVALHANDLE;
1704 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1705 MMDRV_Free(hMidiIn, wmld);
1706 return dwRet;
1709 /**************************************************************************
1710 * midiInPrepareHeader [WINMM.@]
1712 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1713 MIDIHDR* lpMidiInHdr, UINT uSize)
1715 LPWINE_MLD wmld;
1717 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1719 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
1720 return MMSYSERR_INVALPARAM;
1722 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1723 return MMSYSERR_INVALHANDLE;
1725 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1728 /**************************************************************************
1729 * midiInUnprepareHeader [WINMM.@]
1731 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1732 MIDIHDR* lpMidiInHdr, UINT uSize)
1734 LPWINE_MLD wmld;
1736 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1738 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
1739 return MMSYSERR_INVALPARAM;
1741 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1742 return MMSYSERR_NOERROR;
1745 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1746 return MMSYSERR_INVALHANDLE;
1748 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1751 /**************************************************************************
1752 * midiInAddBuffer [WINMM.@]
1754 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1755 MIDIHDR* lpMidiInHdr, UINT uSize)
1757 LPWINE_MLD wmld;
1759 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1761 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1762 return MMSYSERR_INVALHANDLE;
1764 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1767 /**************************************************************************
1768 * midiInStart [WINMM.@]
1770 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1772 LPWINE_MLD wmld;
1774 TRACE("(%p)\n", hMidiIn);
1776 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1777 return MMSYSERR_INVALHANDLE;
1779 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1782 /**************************************************************************
1783 * midiInStop [WINMM.@]
1785 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1787 LPWINE_MLD wmld;
1789 TRACE("(%p)\n", hMidiIn);
1791 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1792 return MMSYSERR_INVALHANDLE;
1794 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1797 /**************************************************************************
1798 * midiInReset [WINMM.@]
1800 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1802 LPWINE_MLD wmld;
1804 TRACE("(%p)\n", hMidiIn);
1806 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1807 return MMSYSERR_INVALHANDLE;
1809 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1812 /**************************************************************************
1813 * midiInGetID [WINMM.@]
1815 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1817 LPWINE_MLD wmld;
1819 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
1821 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1823 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1824 return MMSYSERR_INVALHANDLE;
1826 *lpuDeviceID = wmld->uDeviceID;
1828 return MMSYSERR_NOERROR;
1831 /**************************************************************************
1832 * midiInMessage [WINMM.@]
1834 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1835 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1837 LPWINE_MLD wmld;
1839 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1841 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1842 return MMSYSERR_INVALHANDLE;
1844 switch (uMessage) {
1845 case MIDM_OPEN:
1846 case MIDM_CLOSE:
1847 FIXME("can't handle OPEN or CLOSE message!\n");
1848 return MMSYSERR_NOTSUPPORTED;
1850 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1853 typedef struct WINE_MIDIStream {
1854 HMIDIOUT hDevice;
1855 HANDLE hThread;
1856 DWORD dwThreadID;
1857 DWORD dwTempo;
1858 DWORD dwTimeDiv;
1859 DWORD dwPositionMS;
1860 DWORD dwPulses;
1861 DWORD dwStartTicks;
1862 WORD wFlags;
1863 HANDLE hEvent;
1864 LPMIDIHDR lpMidiHdr;
1865 } WINE_MIDIStream;
1867 #define WINE_MSM_HEADER (WM_USER+0)
1868 #define WINE_MSM_STOP (WM_USER+1)
1870 /**************************************************************************
1871 * MMSYSTEM_GetMidiStream [internal]
1873 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1875 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1877 if (lplpwm)
1878 *lplpwm = lpwm;
1880 if (lpwm == NULL) {
1881 return FALSE;
1884 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1886 return *lpMidiStrm != NULL;
1889 /**************************************************************************
1890 * MMSYSTEM_MidiStream_Convert [internal]
1892 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1894 DWORD ret = 0;
1896 if (lpMidiStrm->dwTimeDiv == 0) {
1897 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1898 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1899 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1900 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1901 ret = (pulse * 1000) / (nf * nsf);
1902 } else {
1903 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1904 (double)lpMidiStrm->dwTimeDiv);
1907 return ret;
1910 /**************************************************************************
1911 * MMSYSTEM_MidiStream_MessageHandler [internal]
1913 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1915 LPMIDIHDR lpMidiHdr;
1916 LPMIDIHDR* lpmh;
1917 LPBYTE lpData;
1919 switch (msg->message) {
1920 case WM_QUIT:
1921 SetEvent(lpMidiStrm->hEvent);
1922 return FALSE;
1923 case WINE_MSM_STOP:
1924 TRACE("STOP\n");
1925 /* this is not quite what MS doc says... */
1926 midiOutReset(lpMidiStrm->hDevice);
1927 /* empty list of already submitted buffers */
1928 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1929 lpMidiHdr->dwFlags |= MHDR_DONE;
1930 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1932 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1933 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1934 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1936 lpMidiStrm->lpMidiHdr = 0;
1937 SetEvent(lpMidiStrm->hEvent);
1938 break;
1939 case WINE_MSM_HEADER:
1940 /* sets initial tick count for first MIDIHDR */
1941 if (!lpMidiStrm->dwStartTicks)
1942 lpMidiStrm->dwStartTicks = GetTickCount();
1944 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1945 * by native mcimidi, it doesn't look like a correct one".
1946 * this trick allows to throw it away... but I don't like it.
1947 * It looks like part of the file I'm trying to play and definitively looks
1948 * like raw midi content
1949 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1950 * synchronization issue where native mcimidi is still processing raw MIDI
1951 * content before generating MIDIEVENTs ?
1953 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1954 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1955 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1956 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1957 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1958 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1959 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1960 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1961 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1962 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1963 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1964 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1965 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1966 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1967 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1968 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1969 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1971 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1972 lpData = lpMidiHdr->lpData;
1973 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1974 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1975 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1976 lpMidiHdr->dwFlags, msg->wParam);
1977 #if 0
1978 /* dumps content of lpMidiHdr->lpData
1979 * FIXME: there should be a debug routine somewhere that already does this
1980 * I hate spreading this type of shit all around the code
1982 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
1983 DWORD i;
1984 BYTE ch;
1986 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1987 printf("%02x ", lpData[dwToGo + i]);
1988 for (; i < 16; i++)
1989 printf(" ");
1990 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
1991 ch = lpData[dwToGo + i];
1992 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
1994 printf("\n");
1996 #endif
1997 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
1998 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
1999 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
2000 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
2001 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
2002 ((LPMIDIEVENT)lpData)->dwStreamID);
2003 lpMidiHdr->dwFlags |= MHDR_DONE;
2004 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2006 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2007 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
2008 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
2009 break;
2012 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
2013 *lpmh = lpMidiHdr;
2014 lpMidiHdr = (LPMIDIHDR)msg->lParam;
2015 lpMidiHdr->lpNext = 0;
2016 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
2017 lpMidiHdr->dwFlags &= ~MHDR_DONE;
2018 lpMidiHdr->dwOffset = 0;
2020 break;
2021 default:
2022 FIXME("Unknown message %d\n", msg->message);
2023 break;
2025 return TRUE;
2028 /**************************************************************************
2029 * MMSYSTEM_MidiStream_Player [internal]
2031 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
2033 WINE_MIDIStream* lpMidiStrm = pmt;
2034 WINE_MIDI* lpwm;
2035 MSG msg;
2036 DWORD dwToGo;
2037 DWORD dwCurrTC;
2038 LPMIDIHDR lpMidiHdr;
2039 LPMIDIEVENT me;
2040 LPBYTE lpData = 0;
2042 TRACE("(%p)!\n", lpMidiStrm);
2044 if (!lpMidiStrm ||
2045 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
2046 goto the_end;
2048 /* force thread's queue creation */
2049 /* Used to be InitThreadInput16(0, 5); */
2050 /* but following works also with hack in midiStreamOpen */
2051 PeekMessageA(&msg, 0, 0, 0, 0);
2053 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
2054 SetEvent(lpMidiStrm->hEvent);
2055 TRACE("Ready to go 1\n");
2056 /* thread is started in paused mode */
2057 SuspendThread(lpMidiStrm->hThread);
2058 TRACE("Ready to go 2\n");
2060 lpMidiStrm->dwStartTicks = 0;
2061 lpMidiStrm->dwPulses = 0;
2063 lpMidiStrm->lpMidiHdr = 0;
2065 for (;;) {
2066 lpMidiHdr = lpMidiStrm->lpMidiHdr;
2067 if (!lpMidiHdr) {
2068 /* for first message, block until one arrives, then process all that are available */
2069 GetMessageA(&msg, 0, 0, 0);
2070 do {
2071 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
2072 goto the_end;
2073 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
2074 lpData = 0;
2075 continue;
2078 if (!lpData)
2079 lpData = lpMidiHdr->lpData;
2081 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
2083 /* do we have to wait ? */
2084 if (me->dwDeltaTime) {
2085 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
2086 lpMidiStrm->dwPulses += me->dwDeltaTime;
2088 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
2090 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
2091 while ((dwCurrTC = GetTickCount()) < dwToGo) {
2092 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
2093 /* got a message, handle it */
2094 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
2095 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
2096 goto the_end;
2098 lpData = 0;
2099 } else {
2100 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
2101 break;
2105 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
2106 case MEVT_COMMENT:
2107 FIXME("NIY: MEVT_COMMENT\n");
2108 /* do nothing, skip bytes */
2109 break;
2110 case MEVT_LONGMSG:
2111 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
2112 break;
2113 case MEVT_NOP:
2114 break;
2115 case MEVT_SHORTMSG:
2116 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
2117 break;
2118 case MEVT_TEMPO:
2119 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
2120 break;
2121 case MEVT_VERSION:
2122 break;
2123 default:
2124 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
2125 break;
2127 if (me->dwEvent & MEVT_F_CALLBACK) {
2128 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2129 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
2130 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
2132 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
2133 if (me->dwEvent & MEVT_F_LONG)
2134 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
2135 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
2136 /* done with this header */
2137 lpMidiHdr->dwFlags |= MHDR_DONE;
2138 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2140 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
2141 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2142 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
2143 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
2144 lpData = 0;
2147 the_end:
2148 TRACE("End of thread\n");
2149 ExitThread(0);
2150 return 0; /* for removing the warning, never executed */
2153 /**************************************************************************
2154 * MMSYSTEM_MidiStream_PostMessage [internal]
2156 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
2158 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
2159 DWORD count;
2161 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
2162 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
2163 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
2164 } else {
2165 WARN("bad PostThreadMessageA\n");
2166 return FALSE;
2168 return TRUE;
2171 /**************************************************************************
2172 * midiStreamClose [WINMM.@]
2174 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
2176 WINE_MIDIStream* lpMidiStrm;
2178 TRACE("(%p)!\n", hMidiStrm);
2180 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
2181 return MMSYSERR_INVALHANDLE;
2183 midiStreamStop(hMidiStrm);
2184 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
2185 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
2186 CloseHandle(lpMidiStrm->hEvent);
2188 return midiOutClose((HMIDIOUT)hMidiStrm);
2191 /**************************************************************************
2192 * MMSYSTEM_MidiStream_Open [internal]
2194 MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi,
2195 DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen,
2196 BOOL bFrom32)
2198 WINE_MIDIStream* lpMidiStrm;
2199 MMRESULT ret;
2200 MIDIOPENSTRMID mosm;
2201 LPWINE_MIDI lpwm;
2202 HMIDIOUT hMidiOut;
2204 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
2205 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
2207 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
2208 return MMSYSERR_INVALPARAM;
2210 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
2211 if (!lpMidiStrm)
2212 return MMSYSERR_NOMEM;
2214 lpMidiStrm->dwTempo = 500000;
2215 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
2216 lpMidiStrm->dwPositionMS = 0;
2218 mosm.dwStreamID = (DWORD)lpMidiStrm;
2219 /* FIXME: the correct value is not allocated yet for MAPPER */
2220 mosm.wDeviceID = *lpuDeviceID;
2221 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
2222 lpMidiStrm->hDevice = hMidiOut;
2223 if (lphMidiStrm)
2224 *lphMidiStrm = (HMIDISTRM)hMidiOut;
2226 lpwm->mld.uDeviceID = *lpuDeviceID;
2228 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
2229 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2230 lpMidiStrm->wFlags = HIWORD(fdwOpen);
2232 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
2233 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
2235 if (!lpMidiStrm->hThread) {
2236 midiStreamClose((HMIDISTRM)hMidiOut);
2237 return MMSYSERR_NOMEM;
2240 /* wait for thread to have started, and for its queue to be created */
2242 DWORD count;
2244 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
2245 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
2246 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
2248 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
2249 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
2250 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
2253 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
2254 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
2255 return ret;
2258 /**************************************************************************
2259 * midiStreamOpen [WINMM.@]
2261 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
2262 DWORD cMidi, DWORD dwCallback,
2263 DWORD dwInstance, DWORD fdwOpen)
2265 return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
2266 dwInstance, fdwOpen, TRUE);
2269 /**************************************************************************
2270 * midiStreamOut [WINMM.@]
2272 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
2273 UINT cbMidiHdr)
2275 WINE_MIDIStream* lpMidiStrm;
2276 DWORD ret = MMSYSERR_NOERROR;
2278 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
2280 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2281 ret = MMSYSERR_INVALHANDLE;
2282 } else if (!lpMidiHdr) {
2283 ret = MMSYSERR_INVALPARAM;
2284 } else {
2285 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
2286 WINE_MSM_HEADER, cbMidiHdr,
2287 (DWORD)lpMidiHdr)) {
2288 WARN("bad PostThreadMessageA\n");
2289 ret = MMSYSERR_ERROR;
2292 return ret;
2295 /**************************************************************************
2296 * midiStreamPause [WINMM.@]
2298 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
2300 WINE_MIDIStream* lpMidiStrm;
2301 DWORD ret = MMSYSERR_NOERROR;
2303 TRACE("(%p)!\n", hMidiStrm);
2305 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2306 ret = MMSYSERR_INVALHANDLE;
2307 } else {
2308 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2309 WARN("bad Suspend (%ld)\n", GetLastError());
2310 ret = MMSYSERR_ERROR;
2313 return ret;
2316 /**************************************************************************
2317 * midiStreamPosition [WINMM.@]
2319 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2321 WINE_MIDIStream* lpMidiStrm;
2322 DWORD ret = MMSYSERR_NOERROR;
2324 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2326 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2327 ret = MMSYSERR_INVALHANDLE;
2328 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2329 ret = MMSYSERR_INVALPARAM;
2330 } else {
2331 switch (lpMMT->wType) {
2332 case TIME_MS:
2333 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2334 TRACE("=> %ld ms\n", lpMMT->u.ms);
2335 break;
2336 case TIME_TICKS:
2337 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2338 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2339 break;
2340 default:
2341 WARN("Unsupported time type %d\n", lpMMT->wType);
2342 lpMMT->wType = TIME_MS;
2343 ret = MMSYSERR_INVALPARAM;
2344 break;
2347 return ret;
2350 /**************************************************************************
2351 * midiStreamProperty [WINMM.@]
2353 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2355 WINE_MIDIStream* lpMidiStrm;
2356 MMRESULT ret = MMSYSERR_NOERROR;
2358 TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2360 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2361 ret = MMSYSERR_INVALHANDLE;
2362 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2363 ret = MMSYSERR_INVALPARAM;
2364 } else if (dwProperty & MIDIPROP_TEMPO) {
2365 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2367 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2368 ret = MMSYSERR_INVALPARAM;
2369 } else if (dwProperty & MIDIPROP_SET) {
2370 lpMidiStrm->dwTempo = mpt->dwTempo;
2371 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2372 } else if (dwProperty & MIDIPROP_GET) {
2373 mpt->dwTempo = lpMidiStrm->dwTempo;
2374 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2376 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2377 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2379 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2380 ret = MMSYSERR_INVALPARAM;
2381 } else if (dwProperty & MIDIPROP_SET) {
2382 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2383 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2384 } else if (dwProperty & MIDIPROP_GET) {
2385 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2386 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2388 } else {
2389 ret = MMSYSERR_INVALPARAM;
2392 return ret;
2395 /**************************************************************************
2396 * midiStreamRestart [WINMM.@]
2398 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2400 WINE_MIDIStream* lpMidiStrm;
2401 MMRESULT ret = MMSYSERR_NOERROR;
2403 TRACE("(%p)!\n", hMidiStrm);
2405 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2406 ret = MMSYSERR_INVALHANDLE;
2407 } else {
2408 DWORD ret;
2410 /* since we increase the thread suspend count on each midiStreamPause
2411 * there may be a need for several midiStreamResume
2413 do {
2414 ret = ResumeThread(lpMidiStrm->hThread);
2415 } while (ret != 0xFFFFFFFF && ret != 0);
2416 if (ret == 0xFFFFFFFF) {
2417 WARN("bad Resume (%ld)\n", GetLastError());
2418 ret = MMSYSERR_ERROR;
2419 } else {
2420 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2423 return ret;
2426 /**************************************************************************
2427 * midiStreamStop [WINMM.@]
2429 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2431 WINE_MIDIStream* lpMidiStrm;
2432 MMRESULT ret = MMSYSERR_NOERROR;
2434 TRACE("(%p)!\n", hMidiStrm);
2436 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2437 ret = MMSYSERR_INVALHANDLE;
2438 } else {
2439 /* in case stream has been paused... FIXME is the current state correct ? */
2440 midiStreamRestart(hMidiStrm);
2441 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2443 return ret;
2446 UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2447 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2448 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2450 HANDLE handle;
2451 LPWINE_MLD wmld;
2452 DWORD dwRet = MMSYSERR_NOERROR;
2453 WAVEOPENDESC wod;
2455 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2456 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2457 dwInstance, dwFlags, bFrom32?32:16);
2459 if (dwFlags & WAVE_FORMAT_QUERY)
2460 TRACE("WAVE_FORMAT_QUERY requested !\n");
2462 if (lpFormat == NULL) {
2463 WARN("bad format\n");
2464 return WAVERR_BADFORMAT;
2467 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) {
2468 WARN("invalid parameter\n");
2469 return MMSYSERR_INVALPARAM;
2472 /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */
2473 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u\n",
2474 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2475 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample);
2477 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2478 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL) {
2479 WARN("no memory\n");
2480 return MMSYSERR_NOMEM;
2483 wod.hWave = handle;
2484 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2485 wod.dwCallback = dwCallback;
2486 wod.dwInstance = dwInstance;
2487 wod.dnDevNode = 0L;
2489 TRACE("cb=%08lx\n", wod.dwCallback);
2491 for (;;) {
2492 if (dwFlags & WAVE_MAPPED) {
2493 wod.uMappedDeviceID = uDeviceID;
2494 uDeviceID = WAVE_MAPPER;
2495 } else {
2496 wod.uMappedDeviceID = -1;
2498 wmld->uDeviceID = uDeviceID;
2500 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2501 (DWORD)&wod, dwFlags);
2503 TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet));
2504 if (dwRet != WAVERR_BADFORMAT ||
2505 ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break;
2506 /* if we ask for a format which isn't supported by the physical driver,
2507 * let's try to map it through the wave mapper (except, if we already tried
2508 * or user didn't allow us to use acm codecs or the device is already the mapper)
2510 dwFlags |= WAVE_MAPPED;
2511 /* we shall loop only one */
2514 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2515 MMDRV_Free(handle, wmld);
2516 handle = 0;
2519 if (lphndl != NULL) *lphndl = handle;
2520 TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle);
2522 return dwRet;
2525 /**************************************************************************
2526 * waveOutGetNumDevs [WINMM.@]
2528 UINT WINAPI waveOutGetNumDevs(void)
2530 return MMDRV_GetNum(MMDRV_WAVEOUT);
2533 /**************************************************************************
2534 * waveOutGetDevCapsA [WINMM.@]
2536 UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps,
2537 UINT uSize)
2539 LPWINE_MLD wmld;
2541 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2543 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2545 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2546 return MMSYSERR_BADDEVICEID;
2548 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
2552 /**************************************************************************
2553 * waveOutGetDevCapsW [WINMM.@]
2555 UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps,
2556 UINT uSize)
2558 WAVEOUTCAPSA wocA;
2559 UINT ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2561 if (ret == MMSYSERR_NOERROR) {
2562 WAVEOUTCAPSW wocW;
2563 wocW.wMid = wocA.wMid;
2564 wocW.wPid = wocA.wPid;
2565 wocW.vDriverVersion = wocA.vDriverVersion;
2566 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, wocW.szPname,
2567 sizeof(wocW.szPname)/sizeof(WCHAR) );
2568 wocW.dwFormats = wocA.dwFormats;
2569 wocW.wChannels = wocA.wChannels;
2570 wocW.dwSupport = wocA.dwSupport;
2571 memcpy(lpCaps, &wocW, min(uSize, sizeof(wocW)));
2573 return ret;
2576 /**************************************************************************
2577 * WAVE_GetErrorText [internal]
2579 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2581 UINT16 ret = MMSYSERR_BADERRNUM;
2583 if (lpText == NULL) {
2584 ret = MMSYSERR_INVALPARAM;
2585 } else if (uSize == 0) {
2586 ret = MMSYSERR_NOERROR;
2587 } else if (
2588 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2589 * a warning for the test was always true */
2590 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2591 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2593 if (LoadStringA(WINMM_IData->hWinMM32Instance,
2594 uError, lpText, uSize) > 0) {
2595 ret = MMSYSERR_NOERROR;
2598 return ret;
2601 /**************************************************************************
2602 * waveOutGetErrorTextA [WINMM.@]
2604 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2606 return WAVE_GetErrorText(uError, lpText, uSize);
2609 /**************************************************************************
2610 * waveOutGetErrorTextW [WINMM.@]
2612 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2614 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2615 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2617 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2618 HeapFree(GetProcessHeap(), 0, xstr);
2619 return ret;
2622 /**************************************************************************
2623 * waveOutOpen [WINMM.@]
2624 * All the args/structs have the same layout as the win16 equivalents
2626 UINT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
2627 const LPWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
2628 DWORD_PTR dwInstance, DWORD dwFlags)
2630 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2631 dwCallback, dwInstance, dwFlags, TRUE);
2634 /**************************************************************************
2635 * waveOutClose [WINMM.@]
2637 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2639 LPWINE_MLD wmld;
2640 DWORD dwRet;
2642 TRACE("(%p)\n", hWaveOut);
2644 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2645 return MMSYSERR_INVALHANDLE;
2647 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2648 if (dwRet != WAVERR_STILLPLAYING)
2649 MMDRV_Free(hWaveOut, wmld);
2651 return dwRet;
2654 /**************************************************************************
2655 * waveOutPrepareHeader [WINMM.@]
2657 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2658 WAVEHDR* lpWaveOutHdr, UINT uSize)
2660 LPWINE_MLD wmld;
2662 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2664 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
2665 return MMSYSERR_INVALPARAM;
2667 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2668 return MMSYSERR_INVALHANDLE;
2670 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, uSize, TRUE);
2673 /**************************************************************************
2674 * waveOutUnprepareHeader [WINMM.@]
2676 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2677 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2679 LPWINE_MLD wmld;
2681 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2683 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
2684 return MMSYSERR_INVALPARAM;
2686 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2687 return MMSYSERR_NOERROR;
2690 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2691 return MMSYSERR_INVALHANDLE;
2693 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, uSize, TRUE);
2696 /**************************************************************************
2697 * waveOutWrite [WINMM.@]
2699 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2700 UINT uSize)
2702 LPWINE_MLD wmld;
2704 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2706 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2707 return MMSYSERR_INVALHANDLE;
2709 return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize, TRUE);
2712 /**************************************************************************
2713 * waveOutBreakLoop [WINMM.@]
2715 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2717 LPWINE_MLD wmld;
2719 TRACE("(%p);\n", hWaveOut);
2721 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2722 return MMSYSERR_INVALHANDLE;
2723 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2726 /**************************************************************************
2727 * waveOutPause [WINMM.@]
2729 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2731 LPWINE_MLD wmld;
2733 TRACE("(%p);\n", hWaveOut);
2735 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2736 return MMSYSERR_INVALHANDLE;
2737 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2740 /**************************************************************************
2741 * waveOutReset [WINMM.@]
2743 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2745 LPWINE_MLD wmld;
2747 TRACE("(%p);\n", hWaveOut);
2749 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2750 return MMSYSERR_INVALHANDLE;
2751 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2754 /**************************************************************************
2755 * waveOutRestart [WINMM.@]
2757 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2759 LPWINE_MLD wmld;
2761 TRACE("(%p);\n", hWaveOut);
2763 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2764 return MMSYSERR_INVALHANDLE;
2765 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2768 /**************************************************************************
2769 * waveOutGetPosition [WINMM.@]
2771 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2772 UINT uSize)
2774 LPWINE_MLD wmld;
2776 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
2778 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2779 return MMSYSERR_INVALHANDLE;
2781 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE);
2784 /**************************************************************************
2785 * waveOutGetPitch [WINMM.@]
2787 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2789 LPWINE_MLD wmld;
2791 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2793 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2794 return MMSYSERR_INVALHANDLE;
2795 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L, TRUE);
2798 /**************************************************************************
2799 * waveOutSetPitch [WINMM.@]
2801 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2803 LPWINE_MLD wmld;
2805 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2807 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2808 return MMSYSERR_INVALHANDLE;
2809 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2812 /**************************************************************************
2813 * waveOutGetPlaybackRate [WINMM.@]
2815 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2817 LPWINE_MLD wmld;
2819 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2821 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2822 return MMSYSERR_INVALHANDLE;
2823 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L, TRUE);
2826 /**************************************************************************
2827 * waveOutSetPlaybackRate [WINMM.@]
2829 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2831 LPWINE_MLD wmld;
2833 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2835 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2836 return MMSYSERR_INVALHANDLE;
2837 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2840 /**************************************************************************
2841 * waveOutGetVolume [WINMM.@]
2843 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
2845 LPWINE_MLD wmld;
2847 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2849 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2850 return MMSYSERR_INVALHANDLE;
2852 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L, TRUE);
2855 /**************************************************************************
2856 * waveOutSetVolume [WINMM.@]
2858 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
2860 LPWINE_MLD wmld;
2862 TRACE("(%p, %08lx);\n", hWaveOut, dw);
2864 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2865 return MMSYSERR_INVALHANDLE;
2867 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2870 /**************************************************************************
2871 * waveOutGetID [WINMM.@]
2873 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2875 LPWINE_MLD wmld;
2877 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
2879 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2881 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2882 return MMSYSERR_INVALHANDLE;
2884 *lpuDeviceID = wmld->uDeviceID;
2885 return 0;
2888 /**************************************************************************
2889 * waveOutMessage [WINMM.@]
2891 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2892 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
2894 LPWINE_MLD wmld;
2896 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2898 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2899 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2900 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2902 WARN("invalid handle\n");
2903 return MMSYSERR_INVALHANDLE;
2906 /* from M$ KB */
2907 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) {
2908 WARN("invalid parameter\n");
2909 return MMSYSERR_INVALPARAM;
2912 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2915 /**************************************************************************
2916 * waveInGetNumDevs [WINMM.@]
2918 UINT WINAPI waveInGetNumDevs(void)
2920 return MMDRV_GetNum(MMDRV_WAVEIN);
2923 /**************************************************************************
2924 * waveInGetDevCapsW [WINMM.@]
2926 UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2928 WAVEINCAPSA wicA;
2929 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
2931 if (ret == MMSYSERR_NOERROR) {
2932 WAVEINCAPSW wicW;
2933 wicW.wMid = wicA.wMid;
2934 wicW.wPid = wicA.wPid;
2935 wicW.vDriverVersion = wicA.vDriverVersion;
2936 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, wicW.szPname,
2937 sizeof(wicW.szPname)/sizeof(WCHAR) );
2938 wicW.dwFormats = wicA.dwFormats;
2939 wicW.wChannels = wicA.wChannels;
2940 memcpy(lpCaps, &wicW, min(uSize, sizeof(wicW)));
2942 return ret;
2945 /**************************************************************************
2946 * waveInGetDevCapsA [WINMM.@]
2948 UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2950 LPWINE_MLD wmld;
2952 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2954 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2956 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
2957 return MMSYSERR_BADDEVICEID;
2959 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
2962 /**************************************************************************
2963 * waveInGetErrorTextA [WINMM.@]
2965 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2967 return WAVE_GetErrorText(uError, lpText, uSize);
2970 /**************************************************************************
2971 * waveInGetErrorTextW [WINMM.@]
2973 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2975 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
2976 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
2978 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
2979 HeapFree(GetProcessHeap(), 0, txt);
2980 return ret;
2983 /**************************************************************************
2984 * waveInOpen [WINMM.@]
2986 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
2987 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2988 DWORD dwInstance, DWORD dwFlags)
2990 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
2991 dwCallback, dwInstance, dwFlags, TRUE);
2994 /**************************************************************************
2995 * waveInClose [WINMM.@]
2997 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
2999 LPWINE_MLD wmld;
3000 DWORD dwRet;
3002 TRACE("(%p)\n", hWaveIn);
3004 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3005 return MMSYSERR_INVALHANDLE;
3007 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
3008 if (dwRet != WAVERR_STILLPLAYING)
3009 MMDRV_Free(hWaveIn, wmld);
3010 return dwRet;
3013 /**************************************************************************
3014 * waveInPrepareHeader [WINMM.@]
3016 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
3017 UINT uSize)
3019 LPWINE_MLD wmld;
3021 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3023 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
3024 return MMSYSERR_INVALPARAM;
3026 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3027 return MMSYSERR_INVALHANDLE;
3029 lpWaveInHdr->dwBytesRecorded = 0;
3031 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3034 /**************************************************************************
3035 * waveInUnprepareHeader [WINMM.@]
3037 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
3038 UINT uSize)
3040 LPWINE_MLD wmld;
3042 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3044 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
3045 return MMSYSERR_INVALPARAM;
3047 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
3048 return MMSYSERR_NOERROR;
3051 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3052 return MMSYSERR_INVALHANDLE;
3054 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3057 /**************************************************************************
3058 * waveInAddBuffer [WINMM.@]
3060 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
3061 WAVEHDR* lpWaveInHdr, UINT uSize)
3063 LPWINE_MLD wmld;
3065 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3067 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
3068 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3069 return MMSYSERR_INVALHANDLE;
3071 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3074 /**************************************************************************
3075 * waveInReset [WINMM.@]
3077 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
3079 LPWINE_MLD wmld;
3081 TRACE("(%p);\n", hWaveIn);
3083 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3084 return MMSYSERR_INVALHANDLE;
3086 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
3089 /**************************************************************************
3090 * waveInStart [WINMM.@]
3092 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
3094 LPWINE_MLD wmld;
3096 TRACE("(%p);\n", hWaveIn);
3098 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3099 return MMSYSERR_INVALHANDLE;
3101 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
3104 /**************************************************************************
3105 * waveInStop [WINMM.@]
3107 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
3109 LPWINE_MLD wmld;
3111 TRACE("(%p);\n", hWaveIn);
3113 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3114 return MMSYSERR_INVALHANDLE;
3116 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
3119 /**************************************************************************
3120 * waveInGetPosition [WINMM.@]
3122 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
3123 UINT uSize)
3125 LPWINE_MLD wmld;
3127 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
3129 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3130 return MMSYSERR_INVALHANDLE;
3132 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE);
3135 /**************************************************************************
3136 * waveInGetID [WINMM.@]
3138 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
3140 LPWINE_MLD wmld;
3142 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
3144 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3146 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3147 return MMSYSERR_INVALHANDLE;
3149 *lpuDeviceID = wmld->uDeviceID;
3150 return MMSYSERR_NOERROR;
3153 /**************************************************************************
3154 * waveInMessage [WINMM.@]
3156 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
3157 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
3159 LPWINE_MLD wmld;
3161 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
3163 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
3164 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
3165 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
3167 return MMSYSERR_INVALHANDLE;
3170 /* from M$ KB */
3171 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
3172 return MMSYSERR_INVALPARAM;
3175 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);