Adds *GetDevCapsW bad pointer check.
[wine.git] / dlls / winmm / winmm.c
blobb198f54c63215f7622919e9ed44574fd1f285d08
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->Spare[1] = (DWORD)"WINMM_IData";
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;
286 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
288 ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA));
289 if (ret == MMSYSERR_NOERROR) {
290 MIXERCAPSW micW;
291 micW.wMid = micA.wMid;
292 micW.wPid = micA.wPid;
293 micW.vDriverVersion = micA.vDriverVersion;
294 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
295 sizeof(micW.szPname)/sizeof(WCHAR) );
296 micW.fdwSupport = micA.fdwSupport;
297 micW.cDestinations = micA.cDestinations;
298 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
300 return ret;
303 UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
304 DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32)
306 HANDLE hMix;
307 LPWINE_MLD wmld;
308 DWORD dwRet = 0;
309 MIXEROPENDESC mod;
311 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
312 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
314 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
315 &dwCallback, &dwInstance, bFrom32);
317 wmld->uDeviceID = uDeviceID;
318 mod.hmx = (HMIXEROBJ)hMix;
319 mod.dwCallback = dwCallback;
320 mod.dwInstance = dwInstance;
322 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
324 if (dwRet != MMSYSERR_NOERROR) {
325 MMDRV_Free(hMix, wmld);
326 hMix = 0;
328 if (lphMix) *lphMix = hMix;
329 TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
331 return dwRet;
334 /**************************************************************************
335 * mixerOpen [WINMM.@]
337 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
338 DWORD_PTR dwInstance, DWORD fdwOpen)
340 return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
343 /**************************************************************************
344 * mixerClose [WINMM.@]
346 UINT WINAPI mixerClose(HMIXER hMix)
348 LPWINE_MLD wmld;
349 DWORD dwRet;
351 TRACE("(%p)\n", hMix);
353 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
355 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
356 MMDRV_Free(hMix, wmld);
358 return dwRet;
361 /**************************************************************************
362 * mixerGetID [WINMM.@]
364 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
366 LPWINE_MIXER lpwm;
368 TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID);
370 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
371 return MMSYSERR_INVALHANDLE;
374 if (lpid)
375 *lpid = lpwm->mld.uDeviceID;
377 return MMSYSERR_NOERROR;
380 /**************************************************************************
381 * mixerGetControlDetailsA [WINMM.@]
383 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
384 DWORD fdwDetails)
386 LPWINE_MIXER lpwm;
388 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
390 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
391 return MMSYSERR_INVALHANDLE;
393 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
394 return MMSYSERR_INVALPARAM;
396 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdA,
397 fdwDetails, TRUE);
400 /**************************************************************************
401 * mixerGetControlDetailsW [WINMM.@]
403 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
405 DWORD ret = MMSYSERR_NOTENABLED;
407 TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
409 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
410 return MMSYSERR_INVALPARAM;
412 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
413 case MIXER_GETCONTROLDETAILSF_VALUE:
414 /* can savely use W structure as it is, no string inside */
415 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
416 break;
417 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
419 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
420 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
421 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
422 int i;
424 if (lpmcd->u.cMultipleItems != 0) {
425 size *= lpmcd->u.cMultipleItems;
427 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
428 lpmcd->paDetails = pDetailsA;
429 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
430 /* set up lpmcd->paDetails */
431 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
432 /* copy from lpmcd->paDetails back to paDetailsW; */
433 if(ret == MMSYSERR_NOERROR) {
434 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
435 pDetailsW->dwParam1 = pDetailsA->dwParam1;
436 pDetailsW->dwParam2 = pDetailsA->dwParam2;
437 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
438 pDetailsW->szName,
439 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
440 pDetailsA++;
441 pDetailsW++;
443 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
444 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
446 HeapFree(GetProcessHeap(), 0, pDetailsA);
447 lpmcd->paDetails = pDetailsW;
448 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
450 break;
451 default:
452 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
455 return ret;
458 /**************************************************************************
459 * mixerGetLineControlsA [WINMM.@]
461 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
462 DWORD fdwControls)
464 LPWINE_MIXER lpwm;
466 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
468 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
469 return MMSYSERR_INVALHANDLE;
471 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
472 return MMSYSERR_INVALPARAM;
474 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcA,
475 fdwControls, TRUE);
478 /**************************************************************************
479 * mixerGetLineControlsW [WINMM.@]
481 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
482 DWORD fdwControls)
484 MIXERLINECONTROLSA mlcA;
485 DWORD ret;
486 int i;
488 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
490 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
491 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
492 return MMSYSERR_INVALPARAM;
494 mlcA.cbStruct = sizeof(mlcA);
495 mlcA.dwLineID = lpmlcW->dwLineID;
496 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
497 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
498 mlcA.cControls = lpmlcW->cControls;
499 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
500 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
501 mlcA.cControls * mlcA.cbmxctrl);
503 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
505 if (ret == MMSYSERR_NOERROR) {
506 lpmlcW->dwLineID = mlcA.dwLineID;
507 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
508 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
509 lpmlcW->cControls = mlcA.cControls;
511 for (i = 0; i < mlcA.cControls; i++) {
512 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
513 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
514 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
515 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
516 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
517 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
518 lpmlcW->pamxctrl[i].szShortName,
519 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
520 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
521 lpmlcW->pamxctrl[i].szName,
522 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
523 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
524 * sizeof(mlcA.pamxctrl[i].Bounds) */
525 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
526 sizeof(mlcA.pamxctrl[i].Bounds));
527 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
528 * sizeof(mlcA.pamxctrl[i].Metrics) */
529 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
530 sizeof(mlcA.pamxctrl[i].Metrics));
534 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
536 return ret;
539 /**************************************************************************
540 * mixerGetLineInfoA [WINMM.@]
542 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
544 LPWINE_MIXER lpwm;
546 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
548 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
549 return MMSYSERR_INVALHANDLE;
551 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW,
552 fdwInfo, TRUE);
555 /**************************************************************************
556 * mixerGetLineInfoW [WINMM.@]
558 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
559 DWORD fdwInfo)
561 MIXERLINEA mliA;
562 UINT ret;
564 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
566 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
567 return MMSYSERR_INVALPARAM;
569 mliA.cbStruct = sizeof(mliA);
570 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
571 case MIXER_GETLINEINFOF_COMPONENTTYPE:
572 mliA.dwComponentType = lpmliW->dwComponentType;
573 break;
574 case MIXER_GETLINEINFOF_DESTINATION:
575 mliA.dwDestination = lpmliW->dwDestination;
576 break;
577 case MIXER_GETLINEINFOF_LINEID:
578 mliA.dwLineID = lpmliW->dwLineID;
579 break;
580 case MIXER_GETLINEINFOF_SOURCE:
581 mliA.dwDestination = lpmliW->dwDestination;
582 mliA.dwSource = lpmliW->dwSource;
583 break;
584 case MIXER_GETLINEINFOF_TARGETTYPE:
585 mliA.Target.dwType = lpmliW->Target.dwType;
586 mliA.Target.wMid = lpmliW->Target.wMid;
587 mliA.Target.wPid = lpmliW->Target.wPid;
588 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
589 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
590 break;
591 default:
592 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
595 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
597 lpmliW->dwDestination = mliA.dwDestination;
598 lpmliW->dwSource = mliA.dwSource;
599 lpmliW->dwLineID = mliA.dwLineID;
600 lpmliW->fdwLine = mliA.fdwLine;
601 lpmliW->dwUser = mliA.dwUser;
602 lpmliW->dwComponentType = mliA.dwComponentType;
603 lpmliW->cChannels = mliA.cChannels;
604 lpmliW->cConnections = mliA.cConnections;
605 lpmliW->cControls = mliA.cControls;
606 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
607 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
608 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
609 sizeof(lpmliW->szName)/sizeof(WCHAR) );
610 lpmliW->Target.dwType = mliA.Target.dwType;
611 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
612 lpmliW->Target.wMid = mliA.Target.wMid;
613 lpmliW->Target.wPid = mliA.Target.wPid;
614 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
615 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
616 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
618 return ret;
621 /**************************************************************************
622 * mixerSetControlDetails [WINMM.@]
624 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
625 DWORD fdwDetails)
627 LPWINE_MIXER lpwm;
629 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
631 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
632 return MMSYSERR_INVALHANDLE;
634 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcdA,
635 fdwDetails, TRUE);
638 /**************************************************************************
639 * mixerMessage [WINMM.@]
641 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
643 LPWINE_MLD wmld;
645 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
646 (DWORD)hmix, uMsg, dwParam1, dwParam2);
648 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
649 return MMSYSERR_INVALHANDLE;
651 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
654 /**************************************************************************
655 * auxGetNumDevs [WINMM.@]
657 UINT WINAPI auxGetNumDevs(void)
659 return MMDRV_GetNum(MMDRV_AUX);
662 /**************************************************************************
663 * auxGetDevCapsW [WINMM.@]
665 UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
667 AUXCAPSA acA;
668 UINT ret;
670 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
672 ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
673 if (ret == MMSYSERR_NOERROR) {
674 AUXCAPSW acW;
675 acW.wMid = acA.wMid;
676 acW.wPid = acA.wPid;
677 acW.vDriverVersion = acA.vDriverVersion;
678 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, acW.szPname,
679 sizeof(acW.szPname)/sizeof(WCHAR) );
680 acW.wTechnology = acA.wTechnology;
681 acW.dwSupport = acA.dwSupport;
682 memcpy(lpCaps, &acW, min(uSize, sizeof(acW)));
684 return ret;
687 /**************************************************************************
688 * auxGetDevCapsA [WINMM.@]
690 UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
692 LPWINE_MLD wmld;
694 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
696 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
698 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
699 return MMSYSERR_INVALHANDLE;
700 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
703 /**************************************************************************
704 * auxGetVolume [WINMM.@]
706 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
708 LPWINE_MLD wmld;
710 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
712 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
713 return MMSYSERR_INVALHANDLE;
714 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE);
717 /**************************************************************************
718 * auxSetVolume [WINMM.@]
720 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
722 LPWINE_MLD wmld;
724 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
726 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
727 return MMSYSERR_INVALHANDLE;
728 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
731 /**************************************************************************
732 * auxOutMessage [WINMM.@]
734 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2)
736 LPWINE_MLD wmld;
738 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
739 return MMSYSERR_INVALHANDLE;
741 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
744 /**************************************************************************
745 * mciGetErrorStringW [WINMM.@]
747 BOOL WINAPI mciGetErrorStringW(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength)
749 char bufstr[MAXERRORLENGTH];
750 BOOL ret = mciGetErrorStringA(wError, bufstr, MAXERRORLENGTH);
752 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
753 return ret;
756 /**************************************************************************
757 * mciGetErrorStringA [WINMM.@]
759 BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength)
761 BOOL ret = FALSE;
763 if (lpstrBuffer != NULL && uLength > 0 &&
764 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
766 if (LoadStringA(WINMM_IData->hWinMM32Instance,
767 dwError, lpstrBuffer, uLength) > 0) {
768 ret = TRUE;
771 return ret;
774 /**************************************************************************
775 * mciDriverNotify [WINMM.@]
777 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, MCIDEVICEID wDevID, UINT wStatus)
779 TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
781 return PostMessageW(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
784 /**************************************************************************
785 * mciGetDriverData [WINMM.@]
787 DWORD WINAPI mciGetDriverData(MCIDEVICEID uDeviceID)
789 LPWINE_MCIDRIVER wmd;
791 TRACE("(%04x)\n", uDeviceID);
793 wmd = MCI_GetDriver(uDeviceID);
795 if (!wmd) {
796 WARN("Bad uDeviceID\n");
797 return 0L;
800 return wmd->dwPrivate;
803 /**************************************************************************
804 * mciSetDriverData [WINMM.@]
806 BOOL WINAPI mciSetDriverData(MCIDEVICEID uDeviceID, DWORD data)
808 LPWINE_MCIDRIVER wmd;
810 TRACE("(%04x, %08lx)\n", uDeviceID, data);
812 wmd = MCI_GetDriver(uDeviceID);
814 if (!wmd) {
815 WARN("Bad uDeviceID\n");
816 return FALSE;
819 wmd->dwPrivate = data;
820 return TRUE;
823 /**************************************************************************
824 * mciSendCommandA [WINMM.@]
826 DWORD WINAPI mciSendCommandA(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
828 DWORD dwRet;
830 TRACE("(%08x, %s, %08lx, %08lx)\n",
831 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
833 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
834 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
835 TRACE("=> %08lx\n", dwRet);
836 return dwRet;
839 inline static LPSTR strdupWtoA( LPCWSTR str )
841 LPSTR ret;
842 INT len;
844 if (!str) return NULL;
845 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
846 ret = HeapAlloc( GetProcessHeap(), 0, len );
847 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
848 return ret;
851 static int MCI_MapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2)
853 switch(msg)
855 case MCI_CLOSE:
856 case MCI_PLAY:
857 case MCI_SEEK:
858 case MCI_STOP:
859 case MCI_PAUSE:
860 case MCI_GETDEVCAPS:
861 case MCI_SPIN:
862 case MCI_SET:
863 case MCI_STEP:
864 case MCI_RECORD:
865 case MCI_BREAK:
866 case MCI_SOUND:
867 case MCI_STATUS:
868 case MCI_CUE:
869 case MCI_REALIZE:
870 case MCI_PUT:
871 case MCI_WHERE:
872 case MCI_FREEZE:
873 case MCI_UNFREEZE:
874 case MCI_CUT:
875 case MCI_COPY:
876 case MCI_PASTE:
877 case MCI_UPDATE:
878 case MCI_RESUME:
879 case MCI_DELETE:
880 return 0;
882 case MCI_OPEN:
884 MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*dwParam2;
885 MCI_OPEN_PARMSA *mci_openA;
886 DWORD_PTR *ptr;
888 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_openA) + sizeof(DWORD_PTR));
889 if (!ptr) return -1;
891 *ptr++ = *dwParam2; /* save the previous pointer */
892 *dwParam2 = (DWORD_PTR)ptr;
893 mci_openA = (MCI_OPEN_PARMSA *)ptr;
895 if (dwParam1 & MCI_NOTIFY)
896 mci_openA->dwCallback = mci_openW->dwCallback;
898 if (dwParam1 & MCI_OPEN_TYPE)
900 if (dwParam1 & MCI_OPEN_TYPE_ID)
901 mci_openA->lpstrDeviceType = (LPSTR)mci_openW->lpstrDeviceType;
902 else
903 mci_openA->lpstrDeviceType = strdupWtoA(mci_openW->lpstrDeviceType);
905 if (dwParam1 & MCI_OPEN_ELEMENT)
907 if (dwParam1 & MCI_OPEN_ELEMENT_ID)
908 mci_openA->lpstrElementName = (LPSTR)mci_openW->lpstrElementName;
909 else
910 mci_openA->lpstrElementName = strdupWtoA(mci_openW->lpstrElementName);
912 if (dwParam1 & MCI_OPEN_ALIAS)
913 mci_openA->lpstrAlias = strdupWtoA(mci_openW->lpstrAlias);
915 return 1;
917 case MCI_WINDOW:
918 if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
920 MCI_ANIM_WINDOW_PARMSW *mci_windowW = (MCI_ANIM_WINDOW_PARMSW *)*dwParam2;
921 MCI_ANIM_WINDOW_PARMSA *mci_windowA;
923 mci_windowA = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowA));
924 if (!mci_windowA) return -1;
926 *dwParam2 = (DWORD_PTR)mci_windowA;
928 mci_windowA->lpstrText = strdupWtoA(mci_windowW->lpstrText);
930 if (dwParam1 & MCI_NOTIFY)
931 mci_windowA->dwCallback = mci_windowW->dwCallback;
932 if (dwParam1 & MCI_ANIM_WINDOW_HWND)
933 mci_windowA->hWnd = mci_windowW->hWnd;
934 if (dwParam1 & MCI_ANIM_WINDOW_STATE)
935 mci_windowA->nCmdShow = mci_windowW->nCmdShow;
937 return 1;
939 return 0;
941 case MCI_SYSINFO:
943 MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*dwParam2;
944 MCI_SYSINFO_PARMSA *mci_sysinfoA;
945 DWORD_PTR *ptr;
947 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoA) + sizeof(DWORD_PTR));
948 if (!ptr) return -1;
950 *ptr++ = *dwParam2; /* save the previous pointer */
951 *dwParam2 = (DWORD_PTR)ptr;
952 mci_sysinfoA = (MCI_SYSINFO_PARMSA *)ptr;
954 if (dwParam1 & MCI_NOTIFY)
955 mci_sysinfoA->dwCallback = mci_sysinfoW->dwCallback;
957 mci_sysinfoA->dwRetSize = mci_sysinfoW->dwRetSize; /* FIXME */
958 mci_sysinfoA->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoA->dwRetSize);
960 return 1;
963 case MCI_INFO:
964 case MCI_SAVE:
965 case MCI_LOAD:
966 case MCI_ESCAPE:
967 default:
968 FIXME("Message 0x%04x needs translation\n", msg);
969 return -1;
971 return 0;
974 static DWORD MCI_UnmapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2,
975 DWORD result)
977 switch(msg)
979 case MCI_OPEN:
981 DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
982 MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*ptr;
983 MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA *)(ptr + 1);
985 mci_openW->wDeviceID = mci_openA->wDeviceID;
987 if (dwParam1 & MCI_OPEN_TYPE)
989 if (!(dwParam1 & MCI_OPEN_TYPE_ID))
990 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrDeviceType);
992 if (dwParam1 & MCI_OPEN_ELEMENT)
994 if (!(dwParam1 & MCI_OPEN_ELEMENT_ID))
995 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrElementName);
997 if (dwParam1 & MCI_OPEN_ALIAS)
998 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrAlias);
999 HeapFree(GetProcessHeap(), 0, ptr);
1001 break;
1003 case MCI_WINDOW:
1004 if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
1006 MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)dwParam2;
1008 HeapFree(GetProcessHeap(), 0, (void *)mci_windowA->lpstrText);
1009 HeapFree(GetProcessHeap(), 0, mci_windowA);
1011 break;
1013 case MCI_SYSINFO:
1015 DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
1016 MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*ptr;
1017 MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)(ptr + 1);
1019 if (!result)
1021 mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber;
1022 mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType;
1023 MultiByteToWideChar(CP_ACP, 0,
1024 mci_sysinfoA->lpstrReturn, mci_sysinfoA->dwRetSize,
1025 mci_sysinfoW->lpstrReturn, mci_sysinfoW->dwRetSize);
1028 HeapFree(GetProcessHeap(), 0, mci_sysinfoA->lpstrReturn);
1029 HeapFree(GetProcessHeap(), 0, ptr);
1031 break;
1033 default:
1034 FIXME("Message 0x%04x needs unmapping\n", msg);
1035 break;
1038 return result;
1042 /**************************************************************************
1043 * mciSendCommandW [WINMM.@]
1045 * FIXME: we should do the things other way around, but since our
1046 * MM subsystem is not unicode aware...
1048 DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1050 DWORD ret;
1051 int mapped;
1053 TRACE("(%08x, %s, %08lx, %08lx)\n",
1054 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1056 mapped = MCI_MapMsgWtoA(wMsg, dwParam1, &dwParam2);
1057 if (mapped == -1)
1059 FIXME("message %04x mapping failed\n", wMsg);
1060 return MMSYSERR_NOMEM;
1062 ret = mciSendCommandA(wDevID, wMsg, dwParam1, dwParam2);
1063 if (mapped)
1064 MCI_UnmapMsgWtoA(wMsg, dwParam1, dwParam2, ret);
1065 return ret;
1068 /**************************************************************************
1069 * mciGetDeviceIDA [WINMM.@]
1071 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1073 return MCI_GetDriverFromString(lpstrName);
1076 /**************************************************************************
1077 * mciGetDeviceIDW [WINMM.@]
1079 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1081 LPSTR lpstrName = NULL;
1082 UINT ret;
1083 INT len;
1085 if (lpwstrName) {
1086 len = WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, NULL, 0, NULL, NULL );
1087 lpstrName = HeapAlloc( GetProcessHeap(), 0, len );
1088 if (lpstrName) WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, lpstrName, len, NULL, NULL );
1090 ret = MCI_GetDriverFromString(lpstrName);
1091 HeapFree(GetProcessHeap(), 0, lpstrName);
1092 return ret;
1095 /**************************************************************************
1096 * MCI_DefYieldProc [internal]
1098 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1100 INT16 ret;
1102 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1104 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
1105 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1106 MyUserYield();
1107 ret = 0;
1108 } else {
1109 MSG msg;
1111 msg.hwnd = HWND_32(HIWORD(data));
1112 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1113 ret = -1;
1115 return ret;
1118 /**************************************************************************
1119 * mciSetYieldProc [WINMM.@]
1121 BOOL WINAPI mciSetYieldProc(MCIDEVICEID uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1123 LPWINE_MCIDRIVER wmd;
1125 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1127 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1128 WARN("Bad uDeviceID\n");
1129 return FALSE;
1132 wmd->lpfnYieldProc = fpYieldProc;
1133 wmd->dwYieldData = dwYieldData;
1134 wmd->bIs32 = TRUE;
1136 return TRUE;
1139 /**************************************************************************
1140 * mciGetDeviceIDFromElementIDW [WINMM.@]
1142 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1144 /* FIXME: that's rather strange, there is no
1145 * mciGetDeviceIDFromElementID32A in winmm.spec
1147 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1148 return 0;
1151 /**************************************************************************
1152 * mciGetYieldProc [WINMM.@]
1154 YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID uDeviceID, DWORD* lpdwYieldData)
1156 LPWINE_MCIDRIVER wmd;
1158 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1160 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1161 WARN("Bad uDeviceID\n");
1162 return NULL;
1164 if (!wmd->lpfnYieldProc) {
1165 WARN("No proc set\n");
1166 return NULL;
1168 if (!wmd->bIs32) {
1169 WARN("Proc is 32 bit\n");
1170 return NULL;
1172 return wmd->lpfnYieldProc;
1175 /**************************************************************************
1176 * mciGetCreatorTask [WINMM.@]
1178 HTASK WINAPI mciGetCreatorTask(MCIDEVICEID uDeviceID)
1180 LPWINE_MCIDRIVER wmd;
1181 HTASK ret = 0;
1183 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
1185 TRACE("(%u) => %p\n", uDeviceID, ret);
1186 return ret;
1189 /**************************************************************************
1190 * mciDriverYield [WINMM.@]
1192 UINT WINAPI mciDriverYield(MCIDEVICEID uDeviceID)
1194 LPWINE_MCIDRIVER wmd;
1195 UINT ret = 0;
1197 TRACE("(%04x)\n", uDeviceID);
1199 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
1200 MyUserYield();
1201 } else {
1202 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1205 return ret;
1208 /**************************************************************************
1209 * midiOutGetNumDevs [WINMM.@]
1211 UINT WINAPI midiOutGetNumDevs(void)
1213 return MMDRV_GetNum(MMDRV_MIDIOUT);
1216 /**************************************************************************
1217 * midiOutGetDevCapsW [WINMM.@]
1219 UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps,
1220 UINT uSize)
1222 MIDIOUTCAPSA mocA;
1223 UINT ret;
1225 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1227 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
1228 if (ret == MMSYSERR_NOERROR) {
1229 MIDIOUTCAPSW mocW;
1230 mocW.wMid = mocA.wMid;
1231 mocW.wPid = mocA.wPid;
1232 mocW.vDriverVersion = mocA.vDriverVersion;
1233 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, mocW.szPname,
1234 sizeof(mocW.szPname)/sizeof(WCHAR) );
1235 mocW.wTechnology = mocA.wTechnology;
1236 mocW.wVoices = mocA.wVoices;
1237 mocW.wNotes = mocA.wNotes;
1238 mocW.wChannelMask = mocA.wChannelMask;
1239 mocW.dwSupport = mocA.dwSupport;
1240 memcpy(lpCaps, &mocW, min(uSize, sizeof(mocW)));
1242 return ret;
1245 /**************************************************************************
1246 * midiOutGetDevCapsA [WINMM.@]
1248 UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps,
1249 UINT uSize)
1251 LPWINE_MLD wmld;
1253 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
1255 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1257 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1258 return MMSYSERR_INVALHANDLE;
1260 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
1263 /**************************************************************************
1264 * MIDI_GetErrorText [internal]
1266 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1268 UINT16 ret = MMSYSERR_BADERRNUM;
1270 if (lpText == NULL) {
1271 ret = MMSYSERR_INVALPARAM;
1272 } else if (uSize == 0) {
1273 ret = MMSYSERR_NOERROR;
1274 } else if (
1275 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
1276 * a warning for the test was always true */
1277 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
1278 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
1280 if (LoadStringA(WINMM_IData->hWinMM32Instance,
1281 uError, lpText, uSize) > 0) {
1282 ret = MMSYSERR_NOERROR;
1285 return ret;
1288 /**************************************************************************
1289 * midiOutGetErrorTextA [WINMM.@]
1291 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1293 return MIDI_GetErrorText(uError, lpText, uSize);
1296 /**************************************************************************
1297 * midiOutGetErrorTextW [WINMM.@]
1299 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1301 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1302 UINT ret;
1304 ret = MIDI_GetErrorText(uError, xstr, uSize);
1305 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1306 HeapFree(GetProcessHeap(), 0, xstr);
1307 return ret;
1310 /**************************************************************************
1311 * MIDI_OutAlloc [internal]
1313 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1314 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1315 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1317 HANDLE hMidiOut;
1318 LPWINE_MIDI lpwm;
1319 UINT size;
1321 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1323 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1324 lpdwCallback, lpdwInstance, bFrom32);
1326 if (lphMidiOut != NULL)
1327 *lphMidiOut = hMidiOut;
1329 if (lpwm) {
1330 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1331 lpwm->mod.dwCallback = *lpdwCallback;
1332 lpwm->mod.dwInstance = *lpdwInstance;
1333 lpwm->mod.dnDevNode = 0;
1334 lpwm->mod.cIds = cIDs;
1335 if (cIDs)
1336 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1338 return lpwm;
1341 UINT MIDI_OutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback,
1342 DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32)
1344 HMIDIOUT hMidiOut;
1345 LPWINE_MIDI lpwm;
1346 UINT dwRet = 0;
1348 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1349 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1351 if (lphMidiOut != NULL) *lphMidiOut = 0;
1353 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1354 0, NULL, bFrom32);
1356 if (lpwm == NULL)
1357 return MMSYSERR_NOMEM;
1359 lpwm->mld.uDeviceID = uDeviceID;
1361 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1363 if (dwRet != MMSYSERR_NOERROR) {
1364 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1365 hMidiOut = 0;
1368 if (lphMidiOut) *lphMidiOut = hMidiOut;
1369 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
1371 return dwRet;
1374 /**************************************************************************
1375 * midiOutOpen [WINMM.@]
1377 UINT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
1378 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
1380 return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1383 /**************************************************************************
1384 * midiOutClose [WINMM.@]
1386 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1388 LPWINE_MLD wmld;
1389 DWORD dwRet;
1391 TRACE("(%p)\n", hMidiOut);
1393 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1394 return MMSYSERR_INVALHANDLE;
1396 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1397 MMDRV_Free(hMidiOut, wmld);
1399 return dwRet;
1402 /**************************************************************************
1403 * midiOutPrepareHeader [WINMM.@]
1405 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1406 MIDIHDR* lpMidiOutHdr, UINT uSize)
1408 LPWINE_MLD wmld;
1410 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1412 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
1413 return MMSYSERR_INVALPARAM;
1415 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1416 return MMSYSERR_INVALHANDLE;
1418 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1421 /**************************************************************************
1422 * midiOutUnprepareHeader [WINMM.@]
1424 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1425 MIDIHDR* lpMidiOutHdr, UINT uSize)
1427 LPWINE_MLD wmld;
1429 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1431 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
1432 return MMSYSERR_INVALPARAM;
1434 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1435 return MMSYSERR_NOERROR;
1438 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1439 return MMSYSERR_INVALHANDLE;
1441 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1444 /**************************************************************************
1445 * midiOutShortMsg [WINMM.@]
1447 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1449 LPWINE_MLD wmld;
1451 TRACE("(%p, %08lX)\n", hMidiOut, dwMsg);
1453 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1454 return MMSYSERR_INVALHANDLE;
1456 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE);
1459 /**************************************************************************
1460 * midiOutLongMsg [WINMM.@]
1462 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1463 MIDIHDR* lpMidiOutHdr, UINT uSize)
1465 LPWINE_MLD wmld;
1467 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1469 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1470 return MMSYSERR_INVALHANDLE;
1472 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1475 /**************************************************************************
1476 * midiOutReset [WINMM.@]
1478 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1480 LPWINE_MLD wmld;
1482 TRACE("(%p)\n", hMidiOut);
1484 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1485 return MMSYSERR_INVALHANDLE;
1487 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1490 /**************************************************************************
1491 * midiOutGetVolume [WINMM.@]
1493 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
1495 LPWINE_MLD wmld;
1497 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
1499 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1500 return MMSYSERR_INVALHANDLE;
1502 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE);
1505 /**************************************************************************
1506 * midiOutSetVolume [WINMM.@]
1508 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
1510 LPWINE_MLD wmld;
1512 TRACE("(%p, %ld);\n", hMidiOut, dwVolume);
1514 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1515 return MMSYSERR_INVALHANDLE;
1517 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1520 /**************************************************************************
1521 * midiOutCachePatches [WINMM.@]
1523 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1524 WORD* lpwPatchArray, UINT uFlags)
1526 /* not really necessary to support this */
1527 FIXME("not supported yet\n");
1528 return MMSYSERR_NOTSUPPORTED;
1531 /**************************************************************************
1532 * midiOutCacheDrumPatches [WINMM.@]
1534 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1535 WORD* lpwKeyArray, UINT uFlags)
1537 FIXME("not supported yet\n");
1538 return MMSYSERR_NOTSUPPORTED;
1541 /**************************************************************************
1542 * midiOutGetID [WINMM.@]
1544 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1546 LPWINE_MLD wmld;
1548 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
1550 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1551 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1552 return MMSYSERR_INVALHANDLE;
1554 *lpuDeviceID = wmld->uDeviceID;
1555 return MMSYSERR_NOERROR;
1558 /**************************************************************************
1559 * midiOutMessage [WINMM.@]
1561 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1562 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1564 LPWINE_MLD wmld;
1566 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1568 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1569 /* HACK... */
1570 if (uMessage == 0x0001) {
1571 *(LPDWORD)dwParam1 = 1;
1572 return 0;
1574 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1575 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1577 return MMSYSERR_INVALHANDLE;
1580 switch (uMessage) {
1581 case MODM_OPEN:
1582 case MODM_CLOSE:
1583 FIXME("can't handle OPEN or CLOSE message!\n");
1584 return MMSYSERR_NOTSUPPORTED;
1586 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1589 /**************************************************************************
1590 * midiInGetNumDevs [WINMM.@]
1592 UINT WINAPI midiInGetNumDevs(void)
1594 return MMDRV_GetNum(MMDRV_MIDIIN);
1597 /**************************************************************************
1598 * midiInGetDevCapsW [WINMM.@]
1600 UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1602 MIDIINCAPSA micA;
1603 UINT ret;
1605 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1607 ret = midiInGetDevCapsA(uDeviceID, &micA, sizeof(micA));
1608 if (ret == MMSYSERR_NOERROR) {
1609 MIDIINCAPSW micW;
1610 micW.wMid = micA.wMid;
1611 micW.wPid = micA.wPid;
1612 micW.vDriverVersion = micA.vDriverVersion;
1613 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
1614 sizeof(micW.szPname)/sizeof(WCHAR) );
1615 micW.dwSupport = micA.dwSupport;
1616 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
1618 return ret;
1621 /**************************************************************************
1622 * midiInGetDevCapsA [WINMM.@]
1624 UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1626 LPWINE_MLD wmld;
1628 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1630 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1632 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1633 return MMSYSERR_INVALHANDLE;
1635 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
1638 /**************************************************************************
1639 * midiInGetErrorTextW [WINMM.@]
1641 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1643 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1644 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1646 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1647 HeapFree(GetProcessHeap(), 0, xstr);
1648 return ret;
1651 /**************************************************************************
1652 * midiInGetErrorTextA [WINMM.@]
1654 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1656 return MIDI_GetErrorText(uError, lpText, uSize);
1659 UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1660 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1662 HANDLE hMidiIn;
1663 LPWINE_MIDI lpwm;
1664 DWORD dwRet = 0;
1666 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1667 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1669 if (lphMidiIn != NULL) *lphMidiIn = 0;
1671 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1672 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1674 if (lpwm == NULL)
1675 return MMSYSERR_NOMEM;
1677 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1678 lpwm->mod.dwCallback = dwCallback;
1679 lpwm->mod.dwInstance = dwInstance;
1681 lpwm->mld.uDeviceID = uDeviceID;
1682 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1684 if (dwRet != MMSYSERR_NOERROR) {
1685 MMDRV_Free(hMidiIn, &lpwm->mld);
1686 hMidiIn = 0;
1688 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1689 TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn);
1691 return dwRet;
1694 /**************************************************************************
1695 * midiInOpen [WINMM.@]
1697 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1698 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1700 return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1703 /**************************************************************************
1704 * midiInClose [WINMM.@]
1706 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1708 LPWINE_MLD wmld;
1709 DWORD dwRet;
1711 TRACE("(%p)\n", hMidiIn);
1713 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1714 return MMSYSERR_INVALHANDLE;
1716 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1717 MMDRV_Free(hMidiIn, wmld);
1718 return dwRet;
1721 /**************************************************************************
1722 * midiInPrepareHeader [WINMM.@]
1724 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1725 MIDIHDR* lpMidiInHdr, UINT uSize)
1727 LPWINE_MLD wmld;
1729 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1731 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
1732 return MMSYSERR_INVALPARAM;
1734 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1735 return MMSYSERR_INVALHANDLE;
1737 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1740 /**************************************************************************
1741 * midiInUnprepareHeader [WINMM.@]
1743 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1744 MIDIHDR* lpMidiInHdr, UINT uSize)
1746 LPWINE_MLD wmld;
1748 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1750 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
1751 return MMSYSERR_INVALPARAM;
1753 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1754 return MMSYSERR_NOERROR;
1757 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1758 return MMSYSERR_INVALHANDLE;
1760 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1763 /**************************************************************************
1764 * midiInAddBuffer [WINMM.@]
1766 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1767 MIDIHDR* lpMidiInHdr, UINT uSize)
1769 LPWINE_MLD wmld;
1771 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1773 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1774 return MMSYSERR_INVALHANDLE;
1776 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1779 /**************************************************************************
1780 * midiInStart [WINMM.@]
1782 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1784 LPWINE_MLD wmld;
1786 TRACE("(%p)\n", hMidiIn);
1788 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1789 return MMSYSERR_INVALHANDLE;
1791 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1794 /**************************************************************************
1795 * midiInStop [WINMM.@]
1797 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1799 LPWINE_MLD wmld;
1801 TRACE("(%p)\n", hMidiIn);
1803 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1804 return MMSYSERR_INVALHANDLE;
1806 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1809 /**************************************************************************
1810 * midiInReset [WINMM.@]
1812 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1814 LPWINE_MLD wmld;
1816 TRACE("(%p)\n", hMidiIn);
1818 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1819 return MMSYSERR_INVALHANDLE;
1821 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1824 /**************************************************************************
1825 * midiInGetID [WINMM.@]
1827 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1829 LPWINE_MLD wmld;
1831 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
1833 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1835 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1836 return MMSYSERR_INVALHANDLE;
1838 *lpuDeviceID = wmld->uDeviceID;
1840 return MMSYSERR_NOERROR;
1843 /**************************************************************************
1844 * midiInMessage [WINMM.@]
1846 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1847 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1849 LPWINE_MLD wmld;
1851 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1853 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1854 return MMSYSERR_INVALHANDLE;
1856 switch (uMessage) {
1857 case MIDM_OPEN:
1858 case MIDM_CLOSE:
1859 FIXME("can't handle OPEN or CLOSE message!\n");
1860 return MMSYSERR_NOTSUPPORTED;
1862 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1865 typedef struct WINE_MIDIStream {
1866 HMIDIOUT hDevice;
1867 HANDLE hThread;
1868 DWORD dwThreadID;
1869 DWORD dwTempo;
1870 DWORD dwTimeDiv;
1871 DWORD dwPositionMS;
1872 DWORD dwPulses;
1873 DWORD dwStartTicks;
1874 WORD wFlags;
1875 HANDLE hEvent;
1876 LPMIDIHDR lpMidiHdr;
1877 } WINE_MIDIStream;
1879 #define WINE_MSM_HEADER (WM_USER+0)
1880 #define WINE_MSM_STOP (WM_USER+1)
1882 /**************************************************************************
1883 * MMSYSTEM_GetMidiStream [internal]
1885 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1887 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1889 if (lplpwm)
1890 *lplpwm = lpwm;
1892 if (lpwm == NULL) {
1893 return FALSE;
1896 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1898 return *lpMidiStrm != NULL;
1901 /**************************************************************************
1902 * MMSYSTEM_MidiStream_Convert [internal]
1904 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1906 DWORD ret = 0;
1908 if (lpMidiStrm->dwTimeDiv == 0) {
1909 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1910 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1911 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1912 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1913 ret = (pulse * 1000) / (nf * nsf);
1914 } else {
1915 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1916 (double)lpMidiStrm->dwTimeDiv);
1919 return ret;
1922 /**************************************************************************
1923 * MMSYSTEM_MidiStream_MessageHandler [internal]
1925 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1927 LPMIDIHDR lpMidiHdr;
1928 LPMIDIHDR* lpmh;
1929 LPBYTE lpData;
1931 switch (msg->message) {
1932 case WM_QUIT:
1933 SetEvent(lpMidiStrm->hEvent);
1934 return FALSE;
1935 case WINE_MSM_STOP:
1936 TRACE("STOP\n");
1937 /* this is not quite what MS doc says... */
1938 midiOutReset(lpMidiStrm->hDevice);
1939 /* empty list of already submitted buffers */
1940 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1941 lpMidiHdr->dwFlags |= MHDR_DONE;
1942 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1944 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1945 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1946 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1948 lpMidiStrm->lpMidiHdr = 0;
1949 SetEvent(lpMidiStrm->hEvent);
1950 break;
1951 case WINE_MSM_HEADER:
1952 /* sets initial tick count for first MIDIHDR */
1953 if (!lpMidiStrm->dwStartTicks)
1954 lpMidiStrm->dwStartTicks = GetTickCount();
1956 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1957 * by native mcimidi, it doesn't look like a correct one".
1958 * this trick allows to throw it away... but I don't like it.
1959 * It looks like part of the file I'm trying to play and definitively looks
1960 * like raw midi content
1961 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1962 * synchronization issue where native mcimidi is still processing raw MIDI
1963 * content before generating MIDIEVENTs ?
1965 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1966 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1967 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1968 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1969 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1970 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1971 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1972 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1973 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1974 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1975 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1976 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1977 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1978 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1979 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1980 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1981 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1983 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1984 lpData = lpMidiHdr->lpData;
1985 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1986 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1987 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1988 lpMidiHdr->dwFlags, msg->wParam);
1989 #if 0
1990 /* dumps content of lpMidiHdr->lpData
1991 * FIXME: there should be a debug routine somewhere that already does this
1992 * I hate spreading this type of shit all around the code
1994 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
1995 DWORD i;
1996 BYTE ch;
1998 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1999 printf("%02x ", lpData[dwToGo + i]);
2000 for (; i < 16; i++)
2001 printf(" ");
2002 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
2003 ch = lpData[dwToGo + i];
2004 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
2006 printf("\n");
2008 #endif
2009 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
2010 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
2011 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
2012 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
2013 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
2014 ((LPMIDIEVENT)lpData)->dwStreamID);
2015 lpMidiHdr->dwFlags |= MHDR_DONE;
2016 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2018 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2019 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
2020 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
2021 break;
2024 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
2025 *lpmh = lpMidiHdr;
2026 lpMidiHdr = (LPMIDIHDR)msg->lParam;
2027 lpMidiHdr->lpNext = 0;
2028 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
2029 lpMidiHdr->dwFlags &= ~MHDR_DONE;
2030 lpMidiHdr->dwOffset = 0;
2032 break;
2033 default:
2034 FIXME("Unknown message %d\n", msg->message);
2035 break;
2037 return TRUE;
2040 /**************************************************************************
2041 * MMSYSTEM_MidiStream_Player [internal]
2043 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
2045 WINE_MIDIStream* lpMidiStrm = pmt;
2046 WINE_MIDI* lpwm;
2047 MSG msg;
2048 DWORD dwToGo;
2049 DWORD dwCurrTC;
2050 LPMIDIHDR lpMidiHdr;
2051 LPMIDIEVENT me;
2052 LPBYTE lpData = 0;
2054 TRACE("(%p)!\n", lpMidiStrm);
2056 if (!lpMidiStrm ||
2057 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
2058 goto the_end;
2060 /* force thread's queue creation */
2061 /* Used to be InitThreadInput16(0, 5); */
2062 /* but following works also with hack in midiStreamOpen */
2063 PeekMessageA(&msg, 0, 0, 0, 0);
2065 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
2066 SetEvent(lpMidiStrm->hEvent);
2067 TRACE("Ready to go 1\n");
2068 /* thread is started in paused mode */
2069 SuspendThread(lpMidiStrm->hThread);
2070 TRACE("Ready to go 2\n");
2072 lpMidiStrm->dwStartTicks = 0;
2073 lpMidiStrm->dwPulses = 0;
2075 lpMidiStrm->lpMidiHdr = 0;
2077 for (;;) {
2078 lpMidiHdr = lpMidiStrm->lpMidiHdr;
2079 if (!lpMidiHdr) {
2080 /* for first message, block until one arrives, then process all that are available */
2081 GetMessageA(&msg, 0, 0, 0);
2082 do {
2083 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
2084 goto the_end;
2085 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
2086 lpData = 0;
2087 continue;
2090 if (!lpData)
2091 lpData = lpMidiHdr->lpData;
2093 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
2095 /* do we have to wait ? */
2096 if (me->dwDeltaTime) {
2097 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
2098 lpMidiStrm->dwPulses += me->dwDeltaTime;
2100 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
2102 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
2103 while ((dwCurrTC = GetTickCount()) < dwToGo) {
2104 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
2105 /* got a message, handle it */
2106 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
2107 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
2108 goto the_end;
2110 lpData = 0;
2111 } else {
2112 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
2113 break;
2117 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
2118 case MEVT_COMMENT:
2119 FIXME("NIY: MEVT_COMMENT\n");
2120 /* do nothing, skip bytes */
2121 break;
2122 case MEVT_LONGMSG:
2123 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
2124 break;
2125 case MEVT_NOP:
2126 break;
2127 case MEVT_SHORTMSG:
2128 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
2129 break;
2130 case MEVT_TEMPO:
2131 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
2132 break;
2133 case MEVT_VERSION:
2134 break;
2135 default:
2136 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
2137 break;
2139 if (me->dwEvent & MEVT_F_CALLBACK) {
2140 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2141 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
2142 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
2144 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
2145 if (me->dwEvent & MEVT_F_LONG)
2146 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
2147 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
2148 /* done with this header */
2149 lpMidiHdr->dwFlags |= MHDR_DONE;
2150 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2152 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
2153 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2154 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
2155 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
2156 lpData = 0;
2159 the_end:
2160 TRACE("End of thread\n");
2161 ExitThread(0);
2162 return 0; /* for removing the warning, never executed */
2165 /**************************************************************************
2166 * MMSYSTEM_MidiStream_PostMessage [internal]
2168 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
2170 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
2171 DWORD count;
2173 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
2174 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
2175 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
2176 } else {
2177 WARN("bad PostThreadMessageA\n");
2178 return FALSE;
2180 return TRUE;
2183 /**************************************************************************
2184 * midiStreamClose [WINMM.@]
2186 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
2188 WINE_MIDIStream* lpMidiStrm;
2190 TRACE("(%p)!\n", hMidiStrm);
2192 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
2193 return MMSYSERR_INVALHANDLE;
2195 midiStreamStop(hMidiStrm);
2196 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
2197 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
2198 CloseHandle(lpMidiStrm->hEvent);
2200 return midiOutClose((HMIDIOUT)hMidiStrm);
2203 /**************************************************************************
2204 * MMSYSTEM_MidiStream_Open [internal]
2206 MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi,
2207 DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen,
2208 BOOL bFrom32)
2210 WINE_MIDIStream* lpMidiStrm;
2211 MMRESULT ret;
2212 MIDIOPENSTRMID mosm;
2213 LPWINE_MIDI lpwm;
2214 HMIDIOUT hMidiOut;
2216 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
2217 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
2219 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
2220 return MMSYSERR_INVALPARAM;
2222 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
2223 if (!lpMidiStrm)
2224 return MMSYSERR_NOMEM;
2226 lpMidiStrm->dwTempo = 500000;
2227 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
2228 lpMidiStrm->dwPositionMS = 0;
2230 mosm.dwStreamID = (DWORD)lpMidiStrm;
2231 /* FIXME: the correct value is not allocated yet for MAPPER */
2232 mosm.wDeviceID = *lpuDeviceID;
2233 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
2234 lpMidiStrm->hDevice = hMidiOut;
2235 if (lphMidiStrm)
2236 *lphMidiStrm = (HMIDISTRM)hMidiOut;
2238 lpwm->mld.uDeviceID = *lpuDeviceID;
2240 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
2241 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2242 lpMidiStrm->wFlags = HIWORD(fdwOpen);
2244 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
2245 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
2247 if (!lpMidiStrm->hThread) {
2248 midiStreamClose((HMIDISTRM)hMidiOut);
2249 return MMSYSERR_NOMEM;
2252 /* wait for thread to have started, and for its queue to be created */
2254 DWORD count;
2256 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
2257 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
2258 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
2260 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
2261 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
2262 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
2265 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
2266 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
2267 return ret;
2270 /**************************************************************************
2271 * midiStreamOpen [WINMM.@]
2273 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
2274 DWORD cMidi, DWORD dwCallback,
2275 DWORD dwInstance, DWORD fdwOpen)
2277 return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
2278 dwInstance, fdwOpen, TRUE);
2281 /**************************************************************************
2282 * midiStreamOut [WINMM.@]
2284 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
2285 UINT cbMidiHdr)
2287 WINE_MIDIStream* lpMidiStrm;
2288 DWORD ret = MMSYSERR_NOERROR;
2290 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
2292 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2293 ret = MMSYSERR_INVALHANDLE;
2294 } else if (!lpMidiHdr) {
2295 ret = MMSYSERR_INVALPARAM;
2296 } else {
2297 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
2298 WINE_MSM_HEADER, cbMidiHdr,
2299 (DWORD)lpMidiHdr)) {
2300 WARN("bad PostThreadMessageA\n");
2301 ret = MMSYSERR_ERROR;
2304 return ret;
2307 /**************************************************************************
2308 * midiStreamPause [WINMM.@]
2310 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
2312 WINE_MIDIStream* lpMidiStrm;
2313 DWORD ret = MMSYSERR_NOERROR;
2315 TRACE("(%p)!\n", hMidiStrm);
2317 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2318 ret = MMSYSERR_INVALHANDLE;
2319 } else {
2320 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2321 WARN("bad Suspend (%ld)\n", GetLastError());
2322 ret = MMSYSERR_ERROR;
2325 return ret;
2328 /**************************************************************************
2329 * midiStreamPosition [WINMM.@]
2331 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2333 WINE_MIDIStream* lpMidiStrm;
2334 DWORD ret = MMSYSERR_NOERROR;
2336 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2338 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2339 ret = MMSYSERR_INVALHANDLE;
2340 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2341 ret = MMSYSERR_INVALPARAM;
2342 } else {
2343 switch (lpMMT->wType) {
2344 case TIME_MS:
2345 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2346 TRACE("=> %ld ms\n", lpMMT->u.ms);
2347 break;
2348 case TIME_TICKS:
2349 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2350 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2351 break;
2352 default:
2353 WARN("Unsupported time type %d\n", lpMMT->wType);
2354 lpMMT->wType = TIME_MS;
2355 ret = MMSYSERR_INVALPARAM;
2356 break;
2359 return ret;
2362 /**************************************************************************
2363 * midiStreamProperty [WINMM.@]
2365 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2367 WINE_MIDIStream* lpMidiStrm;
2368 MMRESULT ret = MMSYSERR_NOERROR;
2370 TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2372 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2373 ret = MMSYSERR_INVALHANDLE;
2374 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2375 ret = MMSYSERR_INVALPARAM;
2376 } else if (dwProperty & MIDIPROP_TEMPO) {
2377 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2379 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2380 ret = MMSYSERR_INVALPARAM;
2381 } else if (dwProperty & MIDIPROP_SET) {
2382 lpMidiStrm->dwTempo = mpt->dwTempo;
2383 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2384 } else if (dwProperty & MIDIPROP_GET) {
2385 mpt->dwTempo = lpMidiStrm->dwTempo;
2386 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2388 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2389 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2391 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2392 ret = MMSYSERR_INVALPARAM;
2393 } else if (dwProperty & MIDIPROP_SET) {
2394 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2395 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2396 } else if (dwProperty & MIDIPROP_GET) {
2397 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2398 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2400 } else {
2401 ret = MMSYSERR_INVALPARAM;
2404 return ret;
2407 /**************************************************************************
2408 * midiStreamRestart [WINMM.@]
2410 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2412 WINE_MIDIStream* lpMidiStrm;
2413 MMRESULT ret = MMSYSERR_NOERROR;
2415 TRACE("(%p)!\n", hMidiStrm);
2417 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2418 ret = MMSYSERR_INVALHANDLE;
2419 } else {
2420 DWORD ret;
2422 /* since we increase the thread suspend count on each midiStreamPause
2423 * there may be a need for several midiStreamResume
2425 do {
2426 ret = ResumeThread(lpMidiStrm->hThread);
2427 } while (ret != 0xFFFFFFFF && ret != 0);
2428 if (ret == 0xFFFFFFFF) {
2429 WARN("bad Resume (%ld)\n", GetLastError());
2430 ret = MMSYSERR_ERROR;
2431 } else {
2432 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2435 return ret;
2438 /**************************************************************************
2439 * midiStreamStop [WINMM.@]
2441 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2443 WINE_MIDIStream* lpMidiStrm;
2444 MMRESULT ret = MMSYSERR_NOERROR;
2446 TRACE("(%p)!\n", hMidiStrm);
2448 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2449 ret = MMSYSERR_INVALHANDLE;
2450 } else {
2451 /* in case stream has been paused... FIXME is the current state correct ? */
2452 midiStreamRestart(hMidiStrm);
2453 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2455 return ret;
2458 UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2459 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2460 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2462 HANDLE handle;
2463 LPWINE_MLD wmld;
2464 DWORD dwRet = MMSYSERR_NOERROR;
2465 WAVEOPENDESC wod;
2467 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2468 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2469 dwInstance, dwFlags, bFrom32?32:16);
2471 if (dwFlags & WAVE_FORMAT_QUERY)
2472 TRACE("WAVE_FORMAT_QUERY requested !\n");
2474 if (lpFormat == NULL) {
2475 WARN("bad format\n");
2476 return WAVERR_BADFORMAT;
2479 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) {
2480 WARN("invalid parameter\n");
2481 return MMSYSERR_INVALPARAM;
2484 /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */
2485 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u\n",
2486 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2487 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample);
2489 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2490 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL) {
2491 WARN("no memory\n");
2492 return MMSYSERR_NOMEM;
2495 wod.hWave = handle;
2496 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2497 wod.dwCallback = dwCallback;
2498 wod.dwInstance = dwInstance;
2499 wod.dnDevNode = 0L;
2501 TRACE("cb=%08lx\n", wod.dwCallback);
2503 for (;;) {
2504 if (dwFlags & WAVE_MAPPED) {
2505 wod.uMappedDeviceID = uDeviceID;
2506 uDeviceID = WAVE_MAPPER;
2507 } else {
2508 wod.uMappedDeviceID = -1;
2510 wmld->uDeviceID = uDeviceID;
2512 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2513 (DWORD)&wod, dwFlags);
2515 TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet));
2516 if (dwRet != WAVERR_BADFORMAT ||
2517 ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break;
2518 /* if we ask for a format which isn't supported by the physical driver,
2519 * let's try to map it through the wave mapper (except, if we already tried
2520 * or user didn't allow us to use acm codecs or the device is already the mapper)
2522 dwFlags |= WAVE_MAPPED;
2523 /* we shall loop only one */
2526 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2527 MMDRV_Free(handle, wmld);
2528 handle = 0;
2531 if (lphndl != NULL) *lphndl = handle;
2532 TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle);
2534 return dwRet;
2537 /**************************************************************************
2538 * waveOutGetNumDevs [WINMM.@]
2540 UINT WINAPI waveOutGetNumDevs(void)
2542 return MMDRV_GetNum(MMDRV_WAVEOUT);
2545 /**************************************************************************
2546 * waveOutGetDevCapsA [WINMM.@]
2548 UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps,
2549 UINT uSize)
2551 LPWINE_MLD wmld;
2553 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2555 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2557 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2558 return MMSYSERR_BADDEVICEID;
2560 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
2564 /**************************************************************************
2565 * waveOutGetDevCapsW [WINMM.@]
2567 UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps,
2568 UINT uSize)
2570 WAVEOUTCAPSA wocA;
2571 UINT ret;
2573 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2575 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2576 if (ret == MMSYSERR_NOERROR) {
2577 WAVEOUTCAPSW wocW;
2578 wocW.wMid = wocA.wMid;
2579 wocW.wPid = wocA.wPid;
2580 wocW.vDriverVersion = wocA.vDriverVersion;
2581 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, wocW.szPname,
2582 sizeof(wocW.szPname)/sizeof(WCHAR) );
2583 wocW.dwFormats = wocA.dwFormats;
2584 wocW.wChannels = wocA.wChannels;
2585 wocW.dwSupport = wocA.dwSupport;
2586 memcpy(lpCaps, &wocW, min(uSize, sizeof(wocW)));
2588 return ret;
2591 /**************************************************************************
2592 * WAVE_GetErrorText [internal]
2594 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2596 UINT16 ret = MMSYSERR_BADERRNUM;
2598 if (lpText == NULL) {
2599 ret = MMSYSERR_INVALPARAM;
2600 } else if (uSize == 0) {
2601 ret = MMSYSERR_NOERROR;
2602 } else if (
2603 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2604 * a warning for the test was always true */
2605 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2606 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2608 if (LoadStringA(WINMM_IData->hWinMM32Instance,
2609 uError, lpText, uSize) > 0) {
2610 ret = MMSYSERR_NOERROR;
2613 return ret;
2616 /**************************************************************************
2617 * waveOutGetErrorTextA [WINMM.@]
2619 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2621 return WAVE_GetErrorText(uError, lpText, uSize);
2624 /**************************************************************************
2625 * waveOutGetErrorTextW [WINMM.@]
2627 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2629 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2630 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2632 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2633 HeapFree(GetProcessHeap(), 0, xstr);
2634 return ret;
2637 /**************************************************************************
2638 * waveOutOpen [WINMM.@]
2639 * All the args/structs have the same layout as the win16 equivalents
2641 UINT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
2642 const LPWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
2643 DWORD_PTR dwInstance, DWORD dwFlags)
2645 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2646 dwCallback, dwInstance, dwFlags, TRUE);
2649 /**************************************************************************
2650 * waveOutClose [WINMM.@]
2652 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2654 LPWINE_MLD wmld;
2655 DWORD dwRet;
2657 TRACE("(%p)\n", hWaveOut);
2659 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2660 return MMSYSERR_INVALHANDLE;
2662 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2663 if (dwRet != WAVERR_STILLPLAYING)
2664 MMDRV_Free(hWaveOut, wmld);
2666 return dwRet;
2669 /**************************************************************************
2670 * waveOutPrepareHeader [WINMM.@]
2672 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2673 WAVEHDR* lpWaveOutHdr, UINT uSize)
2675 LPWINE_MLD wmld;
2676 UINT result;
2678 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2680 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
2681 return MMSYSERR_INVALPARAM;
2683 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2684 return MMSYSERR_INVALHANDLE;
2686 if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr,
2687 uSize, TRUE)) != MMSYSERR_NOTSUPPORTED)
2688 return result;
2690 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
2691 return WAVERR_STILLPLAYING;
2693 lpWaveOutHdr->dwFlags |= WHDR_PREPARED;
2694 lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
2696 return MMSYSERR_NOERROR;
2699 /**************************************************************************
2700 * waveOutUnprepareHeader [WINMM.@]
2702 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2703 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2705 LPWINE_MLD wmld;
2706 UINT result;
2708 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2710 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
2711 return MMSYSERR_INVALPARAM;
2713 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2714 return MMSYSERR_NOERROR;
2717 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2718 return MMSYSERR_INVALHANDLE;
2720 if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr,
2721 uSize, TRUE)) != MMSYSERR_NOTSUPPORTED)
2722 return result;
2724 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
2725 return WAVERR_STILLPLAYING;
2727 lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED;
2728 lpWaveOutHdr->dwFlags |= WHDR_DONE;
2730 return MMSYSERR_NOERROR;
2733 /**************************************************************************
2734 * waveOutWrite [WINMM.@]
2736 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2737 UINT uSize)
2739 LPWINE_MLD wmld;
2741 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2743 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2744 return MMSYSERR_INVALHANDLE;
2746 return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize, TRUE);
2749 /**************************************************************************
2750 * waveOutBreakLoop [WINMM.@]
2752 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2754 LPWINE_MLD wmld;
2756 TRACE("(%p);\n", hWaveOut);
2758 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2759 return MMSYSERR_INVALHANDLE;
2760 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2763 /**************************************************************************
2764 * waveOutPause [WINMM.@]
2766 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2768 LPWINE_MLD wmld;
2770 TRACE("(%p);\n", hWaveOut);
2772 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2773 return MMSYSERR_INVALHANDLE;
2774 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2777 /**************************************************************************
2778 * waveOutReset [WINMM.@]
2780 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2782 LPWINE_MLD wmld;
2784 TRACE("(%p);\n", hWaveOut);
2786 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2787 return MMSYSERR_INVALHANDLE;
2788 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2791 /**************************************************************************
2792 * waveOutRestart [WINMM.@]
2794 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2796 LPWINE_MLD wmld;
2798 TRACE("(%p);\n", hWaveOut);
2800 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2801 return MMSYSERR_INVALHANDLE;
2802 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2805 /**************************************************************************
2806 * waveOutGetPosition [WINMM.@]
2808 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2809 UINT uSize)
2811 LPWINE_MLD wmld;
2813 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
2815 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2816 return MMSYSERR_INVALHANDLE;
2818 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE);
2821 /**************************************************************************
2822 * waveOutGetPitch [WINMM.@]
2824 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2826 LPWINE_MLD wmld;
2828 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2830 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2831 return MMSYSERR_INVALHANDLE;
2832 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L, TRUE);
2835 /**************************************************************************
2836 * waveOutSetPitch [WINMM.@]
2838 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2840 LPWINE_MLD wmld;
2842 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2844 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2845 return MMSYSERR_INVALHANDLE;
2846 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2849 /**************************************************************************
2850 * waveOutGetPlaybackRate [WINMM.@]
2852 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2854 LPWINE_MLD wmld;
2856 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2858 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2859 return MMSYSERR_INVALHANDLE;
2860 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L, TRUE);
2863 /**************************************************************************
2864 * waveOutSetPlaybackRate [WINMM.@]
2866 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2868 LPWINE_MLD wmld;
2870 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2872 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2873 return MMSYSERR_INVALHANDLE;
2874 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2877 /**************************************************************************
2878 * waveOutGetVolume [WINMM.@]
2880 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
2882 LPWINE_MLD wmld;
2884 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2886 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2887 return MMSYSERR_INVALHANDLE;
2889 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L, TRUE);
2892 /**************************************************************************
2893 * waveOutSetVolume [WINMM.@]
2895 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
2897 LPWINE_MLD wmld;
2899 TRACE("(%p, %08lx);\n", hWaveOut, dw);
2901 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2902 return MMSYSERR_INVALHANDLE;
2904 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2907 /**************************************************************************
2908 * waveOutGetID [WINMM.@]
2910 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2912 LPWINE_MLD wmld;
2914 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
2916 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2918 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2919 return MMSYSERR_INVALHANDLE;
2921 *lpuDeviceID = wmld->uDeviceID;
2922 return 0;
2925 /**************************************************************************
2926 * waveOutMessage [WINMM.@]
2928 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2929 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
2931 LPWINE_MLD wmld;
2933 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2935 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2936 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2937 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2939 WARN("invalid handle\n");
2940 return MMSYSERR_INVALHANDLE;
2943 /* from M$ KB */
2944 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) {
2945 WARN("invalid parameter\n");
2946 return MMSYSERR_INVALPARAM;
2949 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2952 /**************************************************************************
2953 * waveInGetNumDevs [WINMM.@]
2955 UINT WINAPI waveInGetNumDevs(void)
2957 return MMDRV_GetNum(MMDRV_WAVEIN);
2960 /**************************************************************************
2961 * waveInGetDevCapsW [WINMM.@]
2963 UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2965 WAVEINCAPSA wicA;
2966 UINT ret;
2968 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2970 ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
2971 if (ret == MMSYSERR_NOERROR) {
2972 WAVEINCAPSW wicW;
2973 wicW.wMid = wicA.wMid;
2974 wicW.wPid = wicA.wPid;
2975 wicW.vDriverVersion = wicA.vDriverVersion;
2976 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, wicW.szPname,
2977 sizeof(wicW.szPname)/sizeof(WCHAR) );
2978 wicW.dwFormats = wicA.dwFormats;
2979 wicW.wChannels = wicA.wChannels;
2980 memcpy(lpCaps, &wicW, min(uSize, sizeof(wicW)));
2982 return ret;
2985 /**************************************************************************
2986 * waveInGetDevCapsA [WINMM.@]
2988 UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2990 LPWINE_MLD wmld;
2992 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2994 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2996 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
2997 return MMSYSERR_BADDEVICEID;
2999 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
3002 /**************************************************************************
3003 * waveInGetErrorTextA [WINMM.@]
3005 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3007 return WAVE_GetErrorText(uError, lpText, uSize);
3010 /**************************************************************************
3011 * waveInGetErrorTextW [WINMM.@]
3013 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3015 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
3016 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
3018 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
3019 HeapFree(GetProcessHeap(), 0, txt);
3020 return ret;
3023 /**************************************************************************
3024 * waveInOpen [WINMM.@]
3026 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
3027 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3028 DWORD dwInstance, DWORD dwFlags)
3030 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
3031 dwCallback, dwInstance, dwFlags, TRUE);
3034 /**************************************************************************
3035 * waveInClose [WINMM.@]
3037 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
3039 LPWINE_MLD wmld;
3040 DWORD dwRet;
3042 TRACE("(%p)\n", hWaveIn);
3044 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3045 return MMSYSERR_INVALHANDLE;
3047 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
3048 if (dwRet != WAVERR_STILLPLAYING)
3049 MMDRV_Free(hWaveIn, wmld);
3050 return dwRet;
3053 /**************************************************************************
3054 * waveInPrepareHeader [WINMM.@]
3056 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
3057 UINT uSize)
3059 LPWINE_MLD wmld;
3061 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3063 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
3064 return MMSYSERR_INVALPARAM;
3066 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3067 return MMSYSERR_INVALHANDLE;
3069 lpWaveInHdr->dwBytesRecorded = 0;
3071 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3074 /**************************************************************************
3075 * waveInUnprepareHeader [WINMM.@]
3077 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
3078 UINT uSize)
3080 LPWINE_MLD wmld;
3082 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3084 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
3085 return MMSYSERR_INVALPARAM;
3087 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
3088 return MMSYSERR_NOERROR;
3091 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3092 return MMSYSERR_INVALHANDLE;
3094 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3097 /**************************************************************************
3098 * waveInAddBuffer [WINMM.@]
3100 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
3101 WAVEHDR* lpWaveInHdr, UINT uSize)
3103 LPWINE_MLD wmld;
3105 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3107 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
3108 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3109 return MMSYSERR_INVALHANDLE;
3111 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3114 /**************************************************************************
3115 * waveInReset [WINMM.@]
3117 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
3119 LPWINE_MLD wmld;
3121 TRACE("(%p);\n", hWaveIn);
3123 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3124 return MMSYSERR_INVALHANDLE;
3126 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
3129 /**************************************************************************
3130 * waveInStart [WINMM.@]
3132 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
3134 LPWINE_MLD wmld;
3136 TRACE("(%p);\n", hWaveIn);
3138 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3139 return MMSYSERR_INVALHANDLE;
3141 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
3144 /**************************************************************************
3145 * waveInStop [WINMM.@]
3147 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
3149 LPWINE_MLD wmld;
3151 TRACE("(%p);\n", hWaveIn);
3153 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3154 return MMSYSERR_INVALHANDLE;
3156 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
3159 /**************************************************************************
3160 * waveInGetPosition [WINMM.@]
3162 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
3163 UINT uSize)
3165 LPWINE_MLD wmld;
3167 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
3169 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3170 return MMSYSERR_INVALHANDLE;
3172 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE);
3175 /**************************************************************************
3176 * waveInGetID [WINMM.@]
3178 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
3180 LPWINE_MLD wmld;
3182 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
3184 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3186 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3187 return MMSYSERR_INVALHANDLE;
3189 *lpuDeviceID = wmld->uDeviceID;
3190 return MMSYSERR_NOERROR;
3193 /**************************************************************************
3194 * waveInMessage [WINMM.@]
3196 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
3197 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
3199 LPWINE_MLD wmld;
3201 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
3203 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
3204 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
3205 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
3207 return MMSYSERR_INVALHANDLE;
3210 /* from M$ KB */
3211 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
3212 return MMSYSERR_INVALPARAM;
3215 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
3218 struct mm_starter
3220 LPTASKCALLBACK cb;
3221 DWORD client;
3222 HANDLE event;
3225 DWORD WINAPI mmTaskRun(void* pmt)
3227 struct mm_starter mms;
3229 memcpy(&mms, pmt, sizeof(struct mm_starter));
3230 HeapFree(GetProcessHeap(), 0, pmt);
3231 mms.cb(mms.client);
3232 if (mms.event) SetEvent(mms.event);
3233 return 0;
3236 MMRESULT WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD client)
3238 HANDLE hThread;
3239 HANDLE hEvent = 0;
3240 struct mm_starter *mms;
3242 mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter));
3243 if (mms == NULL) { return TASKERR_OUTOFMEMORY; }
3245 mms->cb = cb;
3246 mms->client = client;
3247 if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
3248 mms->event = hEvent;
3250 hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL);
3251 if (!hThread) {
3252 HeapFree(GetProcessHeap(), 0, mms);
3253 if (hEvent) CloseHandle(hEvent);
3254 return TASKERR_OUTOFMEMORY;
3256 if (ph) *ph = hEvent;
3257 CloseHandle(hThread);
3258 return 0;