Avoid local WINAPI function pointers.
[wine/hacks.git] / dlls / winmm / winmm.c
blob5f5cdd45ef0e6136b4cf3d32518ab15c1bbfc3a7
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 <string.h>
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "mmsystem.h"
36 #include "winbase.h"
37 #include "wine/winuser16.h" /* FIXME: should be removed, only used for UserYield16 */
38 #include "heap.h"
39 #include "winternl.h"
40 #include "winemm.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
46 /* ========================================================================
47 * G L O B A L S E T T I N G S
48 * ========================================================================*/
50 LPWINE_MM_IDATA WINMM_IData /* = NULL */;
52 /**************************************************************************
53 * WINMM_CreateIData [internal]
55 static BOOL WINMM_CreateIData(HINSTANCE hInstDLL)
57 WINMM_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA));
59 if (!WINMM_IData)
60 return FALSE;
61 WINMM_IData->hWinMM32Instance = hInstDLL;
62 InitializeCriticalSection(&WINMM_IData->cs);
63 WINMM_IData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
64 WINMM_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
65 WINMM_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
66 TRACE("Created IData (%p)\n", WINMM_IData);
67 return TRUE;
70 /**************************************************************************
71 * WINMM_DeleteIData [internal]
73 static void WINMM_DeleteIData(void)
75 if (WINMM_IData) {
76 TIME_MMTimeStop();
78 /* FIXME: should also free content and resources allocated
79 * inside WINMM_IData */
80 CloseHandle(WINMM_IData->psStopEvent);
81 CloseHandle(WINMM_IData->psLastEvent);
82 DeleteCriticalSection(&WINMM_IData->cs);
83 HeapFree(GetProcessHeap(), 0, WINMM_IData);
84 WINMM_IData = NULL;
88 /******************************************************************
89 * WINMM_LoadMMSystem
92 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR);
93 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR);
95 BOOL WINMM_CheckForMMSystem(void)
97 /* 0 is not checked yet, -1 is not present, 1 is present */
98 static int loaded /* = 0 */;
100 if (loaded == 0)
102 HANDLE h = GetModuleHandleA("kernel32");
103 loaded = -1;
104 if (h)
106 pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16");
107 pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16");
108 if (pGetModuleHandle16 && pLoadLibrary16 &&
109 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
110 loaded = 1;
113 return loaded > 0;
116 /**************************************************************************
117 * DllMain (WINMM.init)
119 * WINMM DLL entry point
122 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
124 TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
126 switch (fdwReason) {
127 case DLL_PROCESS_ATTACH:
128 if (!WINMM_CreateIData(hInstDLL))
129 return FALSE;
130 if (!MCI_Init() || !MMDRV_Init()) {
131 WINMM_DeleteIData();
132 return FALSE;
134 break;
135 case DLL_PROCESS_DETACH:
136 /* close all opened MCI drivers */
137 MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE);
138 MMDRV_Exit();
139 /* now unload all remaining drivers... */
140 DRIVER_UnloadAll();
142 WINMM_DeleteIData();
143 break;
144 case DLL_THREAD_ATTACH:
145 case DLL_THREAD_DETACH:
146 break;
148 return TRUE;
151 /**************************************************************************
152 * Mixer devices. New to Win95
155 /**************************************************************************
156 * find out the real mixer ID depending on hmix (depends on dwFlags)
158 static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags)
160 LPWINE_MIXER lpwm = NULL;
162 switch (dwFlags & 0xF0000000ul) {
163 case MIXER_OBJECTF_MIXER:
164 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
165 break;
166 case MIXER_OBJECTF_HMIXER:
167 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
168 break;
169 case MIXER_OBJECTF_WAVEOUT:
170 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
171 break;
172 case MIXER_OBJECTF_HWAVEOUT:
173 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
174 break;
175 case MIXER_OBJECTF_WAVEIN:
176 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
177 break;
178 case MIXER_OBJECTF_HWAVEIN:
179 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
180 break;
181 case MIXER_OBJECTF_MIDIOUT:
182 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
183 break;
184 case MIXER_OBJECTF_HMIDIOUT:
185 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
186 break;
187 case MIXER_OBJECTF_MIDIIN:
188 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
189 break;
190 case MIXER_OBJECTF_HMIDIIN:
191 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
192 break;
193 case MIXER_OBJECTF_AUX:
194 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
195 break;
196 default:
197 FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
198 break;
200 return lpwm;
203 /**************************************************************************
204 * mixerGetNumDevs [WINMM.@]
206 UINT WINAPI mixerGetNumDevs(void)
208 return MMDRV_GetNum(MMDRV_MIXER);
211 /**************************************************************************
212 * mixerGetDevCapsA [WINMM.@]
214 UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size)
216 LPWINE_MLD wmld;
218 if ((wmld = MMDRV_Get((HANDLE)devid, MMDRV_MIXER, TRUE)) == NULL)
219 return MMSYSERR_BADDEVICEID;
221 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE);
224 /**************************************************************************
225 * mixerGetDevCapsW [WINMM.@]
227 UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size)
229 MIXERCAPSA micA;
230 UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA));
232 if (ret == MMSYSERR_NOERROR) {
233 mixcaps->wMid = micA.wMid;
234 mixcaps->wPid = micA.wPid;
235 mixcaps->vDriverVersion = micA.vDriverVersion;
236 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname,
237 sizeof(mixcaps->szPname)/sizeof(WCHAR) );
238 mixcaps->fdwSupport = micA.fdwSupport;
239 mixcaps->cDestinations = micA.cDestinations;
241 return ret;
244 UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
245 DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32)
247 HANDLE hMix;
248 LPWINE_MLD wmld;
249 DWORD dwRet = 0;
250 MIXEROPENDESC mod;
252 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
253 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
255 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
256 &dwCallback, &dwInstance, bFrom32);
258 wmld->uDeviceID = uDeviceID;
259 mod.hmx = (HMIXEROBJ)hMix;
260 mod.dwCallback = dwCallback;
261 mod.dwInstance = dwInstance;
263 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
265 if (dwRet != MMSYSERR_NOERROR) {
266 MMDRV_Free(hMix, wmld);
267 hMix = 0;
269 if (lphMix) *lphMix = hMix;
270 TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
272 return dwRet;
275 /**************************************************************************
276 * mixerOpen [WINMM.@]
278 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback,
279 DWORD dwInstance, DWORD fdwOpen)
281 return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
284 /**************************************************************************
285 * mixerClose [WINMM.@]
287 UINT WINAPI mixerClose(HMIXER hMix)
289 LPWINE_MLD wmld;
290 DWORD dwRet;
292 TRACE("(%p)\n", hMix);
294 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
296 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
297 MMDRV_Free(hMix, wmld);
299 return dwRet;
302 /**************************************************************************
303 * mixerGetID [WINMM.@]
305 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
307 LPWINE_MIXER lpwm;
309 TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID);
311 if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) {
312 return MMSYSERR_INVALHANDLE;
315 if (lpid)
316 *lpid = lpwm->mld.uDeviceID;
318 return MMSYSERR_NOERROR;
321 /**************************************************************************
322 * mixerGetControlDetailsA [WINMM.@]
324 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
325 DWORD fdwDetails)
327 LPWINE_MIXER lpwm;
329 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
331 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
332 return MMSYSERR_INVALHANDLE;
334 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
335 return MMSYSERR_INVALPARAM;
337 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA,
338 fdwDetails, TRUE);
341 /**************************************************************************
342 * mixerGetControlDetailsW [WINMM.@]
344 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
346 DWORD ret = MMSYSERR_NOTENABLED;
348 TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
350 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
351 return MMSYSERR_INVALPARAM;
353 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
354 case MIXER_GETCONTROLDETAILSF_VALUE:
355 /* can savely use W structure as it is, no string inside */
356 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
357 break;
358 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
360 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
361 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
362 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
363 int i;
365 if (lpmcd->u.cMultipleItems != 0) {
366 size *= lpmcd->u.cMultipleItems;
368 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
369 lpmcd->paDetails = pDetailsA;
370 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
371 /* set up lpmcd->paDetails */
372 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
373 /* copy from lpmcd->paDetails back to paDetailsW; */
374 if(ret == MMSYSERR_NOERROR) {
375 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
376 pDetailsW->dwParam1 = pDetailsA->dwParam1;
377 pDetailsW->dwParam2 = pDetailsA->dwParam2;
378 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
379 pDetailsW->szName,
380 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
381 pDetailsA++;
382 pDetailsW++;
384 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
385 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
387 HeapFree(GetProcessHeap(), 0, pDetailsA);
388 lpmcd->paDetails = pDetailsW;
389 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
391 break;
392 default:
393 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
396 return ret;
399 /**************************************************************************
400 * mixerGetLineControlsA [WINMM.@]
402 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
403 DWORD fdwControls)
405 LPWINE_MIXER lpwm;
407 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
409 if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL)
410 return MMSYSERR_INVALHANDLE;
412 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
413 return MMSYSERR_INVALPARAM;
415 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA,
416 fdwControls, TRUE);
419 /**************************************************************************
420 * mixerGetLineControlsW [WINMM.@]
422 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
423 DWORD fdwControls)
425 MIXERLINECONTROLSA mlcA;
426 DWORD ret;
427 int i;
429 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
431 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
432 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
433 return MMSYSERR_INVALPARAM;
435 mlcA.cbStruct = sizeof(mlcA);
436 mlcA.dwLineID = lpmlcW->dwLineID;
437 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
438 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
439 mlcA.cControls = lpmlcW->cControls;
440 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
441 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
442 mlcA.cControls * mlcA.cbmxctrl);
444 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
446 if (ret == MMSYSERR_NOERROR) {
447 lpmlcW->dwLineID = mlcA.dwLineID;
448 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
449 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
450 lpmlcW->cControls = mlcA.cControls;
452 for (i = 0; i < mlcA.cControls; i++) {
453 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
454 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
455 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
456 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
457 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
458 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
459 lpmlcW->pamxctrl[i].szShortName,
460 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
461 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
462 lpmlcW->pamxctrl[i].szName,
463 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
464 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
465 * sizeof(mlcA.pamxctrl[i].Bounds) */
466 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
467 sizeof(mlcA.pamxctrl[i].Bounds));
468 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
469 * sizeof(mlcA.pamxctrl[i].Metrics) */
470 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
471 sizeof(mlcA.pamxctrl[i].Metrics));
475 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
477 return ret;
480 /**************************************************************************
481 * mixerGetLineInfoA [WINMM.@]
483 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
485 LPWINE_MIXER lpwm;
487 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
489 if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL)
490 return MMSYSERR_INVALHANDLE;
492 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW,
493 fdwInfo, TRUE);
496 /**************************************************************************
497 * mixerGetLineInfoW [WINMM.@]
499 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
500 DWORD fdwInfo)
502 MIXERLINEA mliA;
503 UINT ret;
505 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
507 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
508 return MMSYSERR_INVALPARAM;
510 mliA.cbStruct = sizeof(mliA);
511 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
512 case MIXER_GETLINEINFOF_COMPONENTTYPE:
513 mliA.dwComponentType = lpmliW->dwComponentType;
514 break;
515 case MIXER_GETLINEINFOF_DESTINATION:
516 mliA.dwDestination = lpmliW->dwDestination;
517 break;
518 case MIXER_GETLINEINFOF_LINEID:
519 mliA.dwLineID = lpmliW->dwLineID;
520 break;
521 case MIXER_GETLINEINFOF_SOURCE:
522 mliA.dwDestination = lpmliW->dwDestination;
523 mliA.dwSource = lpmliW->dwSource;
524 break;
525 case MIXER_GETLINEINFOF_TARGETTYPE:
526 mliA.Target.dwType = lpmliW->Target.dwType;
527 mliA.Target.wMid = lpmliW->Target.wMid;
528 mliA.Target.wPid = lpmliW->Target.wPid;
529 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
530 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
531 break;
532 default:
533 FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo);
536 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
538 lpmliW->dwDestination = mliA.dwDestination;
539 lpmliW->dwSource = mliA.dwSource;
540 lpmliW->dwLineID = mliA.dwLineID;
541 lpmliW->fdwLine = mliA.fdwLine;
542 lpmliW->dwUser = mliA.dwUser;
543 lpmliW->dwComponentType = mliA.dwComponentType;
544 lpmliW->cChannels = mliA.cChannels;
545 lpmliW->cConnections = mliA.cConnections;
546 lpmliW->cControls = mliA.cControls;
547 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
548 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
549 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
550 sizeof(lpmliW->szName)/sizeof(WCHAR) );
551 lpmliW->Target.dwType = mliA.Target.dwType;
552 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
553 lpmliW->Target.wMid = mliA.Target.wMid;
554 lpmliW->Target.wPid = mliA.Target.wPid;
555 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
556 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
557 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
559 return ret;
562 /**************************************************************************
563 * mixerSetControlDetails [WINMM.@]
565 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
566 DWORD fdwDetails)
568 LPWINE_MIXER lpwm;
570 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
572 if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL)
573 return MMSYSERR_INVALHANDLE;
575 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA,
576 fdwDetails, TRUE);
579 /**************************************************************************
580 * mixerMessage [WINMM.@]
582 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
584 LPWINE_MLD wmld;
586 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
587 (DWORD)hmix, uMsg, dwParam1, dwParam2);
589 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
590 return MMSYSERR_INVALHANDLE;
592 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
595 /**************************************************************************
596 * auxGetNumDevs [WINMM.@]
598 UINT WINAPI auxGetNumDevs(void)
600 return MMDRV_GetNum(MMDRV_AUX);
603 /**************************************************************************
604 * auxGetDevCapsW [WINMM.@]
606 UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
608 AUXCAPSA acA;
609 UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
611 lpCaps->wMid = acA.wMid;
612 lpCaps->wPid = acA.wPid;
613 lpCaps->vDriverVersion = acA.vDriverVersion;
614 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname,
615 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
616 lpCaps->wTechnology = acA.wTechnology;
617 lpCaps->dwSupport = acA.dwSupport;
618 return ret;
621 /**************************************************************************
622 * auxGetDevCapsA [WINMM.@]
624 UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
626 LPWINE_MLD wmld;
628 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
630 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
631 return MMSYSERR_INVALHANDLE;
632 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
635 /**************************************************************************
636 * auxGetVolume [WINMM.@]
638 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
640 LPWINE_MLD wmld;
642 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
644 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
645 return MMSYSERR_INVALHANDLE;
646 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
649 /**************************************************************************
650 * auxSetVolume [WINMM.@]
652 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
654 LPWINE_MLD wmld;
656 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
658 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
659 return MMSYSERR_INVALHANDLE;
660 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
663 /**************************************************************************
664 * auxOutMessage [WINMM.@]
666 DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2)
668 LPWINE_MLD wmld;
670 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
671 return MMSYSERR_INVALHANDLE;
673 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
676 /**************************************************************************
677 * mciGetErrorStringW [WINMM.@]
679 BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength)
681 LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength);
682 BOOL ret = mciGetErrorStringA(wError, bufstr, uLength);
684 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
685 HeapFree(GetProcessHeap(), 0, bufstr);
686 return ret;
689 /**************************************************************************
690 * mciGetErrorStringA [WINMM.@]
692 BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength)
694 BOOL16 ret = FALSE;
696 if (lpstrBuffer != NULL && uLength > 0 &&
697 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
699 if (LoadStringA(WINMM_IData->hWinMM32Instance,
700 dwError, lpstrBuffer, uLength) > 0) {
701 ret = TRUE;
704 return ret;
707 /**************************************************************************
708 * mciDriverNotify [WINMM.@]
710 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
713 TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
715 return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
718 /**************************************************************************
719 * mciGetDriverData [WINMM.@]
721 DWORD WINAPI mciGetDriverData(UINT uDeviceID)
723 LPWINE_MCIDRIVER wmd;
725 TRACE("(%04x)\n", uDeviceID);
727 wmd = MCI_GetDriver(uDeviceID);
729 if (!wmd) {
730 WARN("Bad uDeviceID\n");
731 return 0L;
734 return wmd->dwPrivate;
737 /**************************************************************************
738 * mciSetDriverData [WINMM.@]
740 BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data)
742 LPWINE_MCIDRIVER wmd;
744 TRACE("(%04x, %08lx)\n", uDeviceID, data);
746 wmd = MCI_GetDriver(uDeviceID);
748 if (!wmd) {
749 WARN("Bad uDeviceID\n");
750 return FALSE;
753 wmd->dwPrivate = data;
754 return TRUE;
757 /**************************************************************************
758 * mciSendCommandA [WINMM.@]
760 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
762 DWORD dwRet;
764 TRACE("(%08x, %s, %08lx, %08lx)\n",
765 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
767 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
768 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
769 TRACE("=> %08lx\n", dwRet);
770 return dwRet;
773 /**************************************************************************
774 * mciSendCommandW [WINMM.@]
776 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
778 FIXME("(%08x, %s, %08lx, %08lx): stub\n",
779 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
780 return MCIERR_UNSUPPORTED_FUNCTION;
783 /**************************************************************************
784 * mciGetDeviceIDA [WINMM.@]
786 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
788 return MCI_GetDriverFromString(lpstrName);
791 /**************************************************************************
792 * mciGetDeviceIDW [WINMM.@]
794 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
796 LPSTR lpstrName;
797 UINT ret;
799 lpstrName = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName);
800 ret = MCI_GetDriverFromString(lpstrName);
801 HeapFree(GetProcessHeap(), 0, lpstrName);
802 return ret;
805 /**************************************************************************
806 * MCI_DefYieldProc [internal]
808 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
810 INT16 ret;
812 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
814 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
815 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
816 UserYield16();
817 ret = 0;
818 } else {
819 MSG msg;
821 msg.hwnd = HWND_32(HIWORD(data));
822 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
823 ret = -1;
825 return ret;
828 /**************************************************************************
829 * mciSetYieldProc [WINMM.@]
831 BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
833 LPWINE_MCIDRIVER wmd;
835 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
837 if (!(wmd = MCI_GetDriver(uDeviceID))) {
838 WARN("Bad uDeviceID\n");
839 return FALSE;
842 wmd->lpfnYieldProc = fpYieldProc;
843 wmd->dwYieldData = dwYieldData;
844 wmd->bIs32 = TRUE;
846 return TRUE;
849 /**************************************************************************
850 * mciGetDeviceIDFromElementIDW [WINMM.@]
852 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
854 /* FIXME: that's rather strange, there is no
855 * mciGetDeviceIDFromElementID32A in winmm.spec
857 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
858 return 0;
861 /**************************************************************************
862 * mciGetYieldProc [WINMM.@]
864 YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData)
866 LPWINE_MCIDRIVER wmd;
868 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
870 if (!(wmd = MCI_GetDriver(uDeviceID))) {
871 WARN("Bad uDeviceID\n");
872 return NULL;
874 if (!wmd->lpfnYieldProc) {
875 WARN("No proc set\n");
876 return NULL;
878 if (!wmd->bIs32) {
879 WARN("Proc is 32 bit\n");
880 return NULL;
882 return wmd->lpfnYieldProc;
885 /**************************************************************************
886 * mciGetCreatorTask [WINMM.@]
888 HTASK WINAPI mciGetCreatorTask(UINT uDeviceID)
890 LPWINE_MCIDRIVER wmd;
891 HTASK ret = 0;
893 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
895 TRACE("(%u) => %p\n", uDeviceID, ret);
896 return ret;
899 /**************************************************************************
900 * mciDriverYield [WINMM.@]
902 UINT WINAPI mciDriverYield(UINT uDeviceID)
904 LPWINE_MCIDRIVER wmd;
905 UINT ret = 0;
907 TRACE("(%04x)\n", uDeviceID);
909 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
910 UserYield16();
911 } else {
912 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
915 return ret;
918 /**************************************************************************
919 * midiOutGetNumDevs [WINMM.@]
921 UINT WINAPI midiOutGetNumDevs(void)
923 return MMDRV_GetNum(MMDRV_MIDIOUT);
926 /**************************************************************************
927 * midiOutGetDevCapsW [WINMM.@]
929 UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps,
930 UINT uSize)
932 MIDIOUTCAPSA mocA;
933 UINT ret;
935 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
936 lpCaps->wMid = mocA.wMid;
937 lpCaps->wPid = mocA.wPid;
938 lpCaps->vDriverVersion = mocA.vDriverVersion;
939 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname,
940 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
941 lpCaps->wTechnology = mocA.wTechnology;
942 lpCaps->wVoices = mocA.wVoices;
943 lpCaps->wNotes = mocA.wNotes;
944 lpCaps->wChannelMask = mocA.wChannelMask;
945 lpCaps->dwSupport = mocA.dwSupport;
946 return ret;
949 /**************************************************************************
950 * midiOutGetDevCapsA [WINMM.@]
952 UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps,
953 UINT uSize)
955 LPWINE_MLD wmld;
957 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
959 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
961 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
962 return MMSYSERR_INVALHANDLE;
964 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
967 /**************************************************************************
968 * MIDI_GetErrorText [internal]
970 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
972 UINT16 ret = MMSYSERR_BADERRNUM;
974 if (lpText == NULL) {
975 ret = MMSYSERR_INVALPARAM;
976 } else if (uSize == 0) {
977 ret = MMSYSERR_NOERROR;
978 } else if (
979 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
980 * a warning for the test was always true */
981 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
982 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
984 if (LoadStringA(WINMM_IData->hWinMM32Instance,
985 uError, lpText, uSize) > 0) {
986 ret = MMSYSERR_NOERROR;
989 return ret;
992 /**************************************************************************
993 * midiOutGetErrorTextA [WINMM.@]
995 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
997 return MIDI_GetErrorText(uError, lpText, uSize);
1000 /**************************************************************************
1001 * midiOutGetErrorTextW [WINMM.@]
1003 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1005 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1006 UINT ret;
1008 ret = MIDI_GetErrorText(uError, xstr, uSize);
1009 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1010 HeapFree(GetProcessHeap(), 0, xstr);
1011 return ret;
1014 /**************************************************************************
1015 * MIDI_OutAlloc [internal]
1017 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1018 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1019 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1021 HANDLE hMidiOut;
1022 LPWINE_MIDI lpwm;
1023 UINT size;
1025 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1027 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1028 lpdwCallback, lpdwInstance, bFrom32);
1030 if (lphMidiOut != NULL)
1031 *lphMidiOut = hMidiOut;
1033 if (lpwm) {
1034 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1035 lpwm->mod.dwCallback = *lpdwCallback;
1036 lpwm->mod.dwInstance = *lpdwInstance;
1037 lpwm->mod.dnDevNode = 0;
1038 lpwm->mod.cIds = cIDs;
1039 if (cIDs)
1040 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1042 return lpwm;
1045 UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback,
1046 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1048 HMIDIOUT hMidiOut;
1049 LPWINE_MIDI lpwm;
1050 UINT dwRet = 0;
1052 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1053 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1055 if (lphMidiOut != NULL) *lphMidiOut = 0;
1057 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1058 0, NULL, bFrom32);
1060 if (lpwm == NULL)
1061 return MMSYSERR_NOMEM;
1063 lpwm->mld.uDeviceID = uDeviceID;
1065 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1067 if (dwRet != MMSYSERR_NOERROR) {
1068 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1069 hMidiOut = 0;
1072 if (lphMidiOut) *lphMidiOut = hMidiOut;
1073 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
1075 return dwRet;
1078 /**************************************************************************
1079 * midiOutOpen [WINMM.@]
1081 UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID,
1082 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1084 return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1087 /**************************************************************************
1088 * midiOutClose [WINMM.@]
1090 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1092 LPWINE_MLD wmld;
1093 DWORD dwRet;
1095 TRACE("(%p)\n", hMidiOut);
1097 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1098 return MMSYSERR_INVALHANDLE;
1100 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1101 MMDRV_Free(hMidiOut, wmld);
1103 return dwRet;
1106 /**************************************************************************
1107 * midiOutPrepareHeader [WINMM.@]
1109 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1110 MIDIHDR* lpMidiOutHdr, UINT uSize)
1112 LPWINE_MLD wmld;
1114 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1116 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1117 return MMSYSERR_INVALHANDLE;
1119 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1122 /**************************************************************************
1123 * midiOutUnprepareHeader [WINMM.@]
1125 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1126 MIDIHDR* lpMidiOutHdr, UINT uSize)
1128 LPWINE_MLD wmld;
1130 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1132 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1133 return MMSYSERR_NOERROR;
1136 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1137 return MMSYSERR_INVALHANDLE;
1139 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE);
1142 /**************************************************************************
1143 * midiOutShortMsg [WINMM.@]
1145 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1147 LPWINE_MLD wmld;
1149 TRACE("(%p, %08lX)\n", hMidiOut, dwMsg);
1151 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1152 return MMSYSERR_INVALHANDLE;
1154 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE);
1157 /**************************************************************************
1158 * midiOutLongMsg [WINMM.@]
1160 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1161 MIDIHDR* lpMidiOutHdr, UINT uSize)
1163 LPWINE_MLD wmld;
1165 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1167 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1168 return MMSYSERR_INVALHANDLE;
1170 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE);
1173 /**************************************************************************
1174 * midiOutReset [WINMM.@]
1176 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1178 LPWINE_MLD wmld;
1180 TRACE("(%p)\n", hMidiOut);
1182 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1183 return MMSYSERR_INVALHANDLE;
1185 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1188 /**************************************************************************
1189 * midiOutGetVolume [WINMM.@]
1191 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
1193 LPWINE_MLD wmld;
1195 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
1197 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1198 return MMSYSERR_INVALHANDLE;
1200 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE);
1203 /**************************************************************************
1204 * midiOutSetVolume [WINMM.@]
1206 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
1208 LPWINE_MLD wmld;
1210 TRACE("(%p, %ld);\n", hMidiOut, dwVolume);
1212 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1213 return MMSYSERR_INVALHANDLE;
1215 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1218 /**************************************************************************
1219 * midiOutCachePatches [WINMM.@]
1221 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1222 WORD* lpwPatchArray, UINT uFlags)
1224 /* not really necessary to support this */
1225 FIXME("not supported yet\n");
1226 return MMSYSERR_NOTSUPPORTED;
1229 /**************************************************************************
1230 * midiOutCacheDrumPatches [WINMM.@]
1232 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1233 WORD* lpwKeyArray, UINT uFlags)
1235 FIXME("not supported yet\n");
1236 return MMSYSERR_NOTSUPPORTED;
1239 /**************************************************************************
1240 * midiOutGetID [WINMM.@]
1242 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1244 LPWINE_MLD wmld;
1246 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
1248 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1249 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1250 return MMSYSERR_INVALHANDLE;
1252 *lpuDeviceID = wmld->uDeviceID;
1253 return MMSYSERR_NOERROR;
1256 /**************************************************************************
1257 * midiOutMessage [WINMM.@]
1259 DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1260 DWORD dwParam1, DWORD dwParam2)
1262 LPWINE_MLD wmld;
1264 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1266 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1267 /* HACK... */
1268 if (uMessage == 0x0001) {
1269 *(LPDWORD)dwParam1 = 1;
1270 return 0;
1272 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1273 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1275 return MMSYSERR_INVALHANDLE;
1278 switch (uMessage) {
1279 case MODM_OPEN:
1280 case MODM_CLOSE:
1281 FIXME("can't handle OPEN or CLOSE message!\n");
1282 return MMSYSERR_NOTSUPPORTED;
1284 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1287 /**************************************************************************
1288 * midiInGetNumDevs [WINMM.@]
1290 UINT WINAPI midiInGetNumDevs(void)
1292 return MMDRV_GetNum(MMDRV_MIDIIN);
1295 /**************************************************************************
1296 * midiInGetDevCapsW [WINMM.@]
1298 UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1300 MIDIINCAPSA micA;
1301 UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize);
1303 if (ret == MMSYSERR_NOERROR) {
1304 lpCaps->wMid = micA.wMid;
1305 lpCaps->wPid = micA.wPid;
1306 lpCaps->vDriverVersion = micA.vDriverVersion;
1307 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname,
1308 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
1309 lpCaps->dwSupport = micA.dwSupport;
1311 return ret;
1314 /**************************************************************************
1315 * midiInGetDevCapsA [WINMM.@]
1317 UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1319 LPWINE_MLD wmld;
1321 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1323 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1324 return MMSYSERR_INVALHANDLE;
1326 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
1329 /**************************************************************************
1330 * midiInGetErrorTextW [WINMM.@]
1332 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1334 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1335 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1337 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1338 HeapFree(GetProcessHeap(), 0, xstr);
1339 return ret;
1342 /**************************************************************************
1343 * midiInGetErrorTextA [WINMM.@]
1345 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1347 return MIDI_GetErrorText(uError, lpText, uSize);
1350 UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1351 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1353 HANDLE hMidiIn;
1354 LPWINE_MIDI lpwm;
1355 DWORD dwRet = 0;
1357 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1358 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1360 if (lphMidiIn != NULL) *lphMidiIn = 0;
1362 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1363 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1365 if (lpwm == NULL)
1366 return MMSYSERR_NOMEM;
1368 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1369 lpwm->mod.dwCallback = dwCallback;
1370 lpwm->mod.dwInstance = dwInstance;
1372 lpwm->mld.uDeviceID = uDeviceID;
1373 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1375 if (dwRet != MMSYSERR_NOERROR) {
1376 MMDRV_Free(hMidiIn, &lpwm->mld);
1377 hMidiIn = 0;
1379 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1380 TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn);
1382 return dwRet;
1385 /**************************************************************************
1386 * midiInOpen [WINMM.@]
1388 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1389 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1391 return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1394 /**************************************************************************
1395 * midiInClose [WINMM.@]
1397 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1399 LPWINE_MLD wmld;
1400 DWORD dwRet;
1402 TRACE("(%p)\n", hMidiIn);
1404 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1405 return MMSYSERR_INVALHANDLE;
1407 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1408 MMDRV_Free(hMidiIn, wmld);
1409 return dwRet;
1412 /**************************************************************************
1413 * midiInPrepareHeader [WINMM.@]
1415 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1416 MIDIHDR* lpMidiInHdr, UINT uSize)
1418 LPWINE_MLD wmld;
1420 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1422 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1423 return MMSYSERR_INVALHANDLE;
1425 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1428 /**************************************************************************
1429 * midiInUnprepareHeader [WINMM.@]
1431 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1432 MIDIHDR* lpMidiInHdr, UINT uSize)
1434 LPWINE_MLD wmld;
1436 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1438 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1439 return MMSYSERR_NOERROR;
1442 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1443 return MMSYSERR_INVALHANDLE;
1445 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE);
1448 /**************************************************************************
1449 * midiInAddBuffer [WINMM.@]
1451 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1452 MIDIHDR* lpMidiInHdr, UINT uSize)
1454 LPWINE_MLD wmld;
1456 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1458 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1459 return MMSYSERR_INVALHANDLE;
1461 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE);
1464 /**************************************************************************
1465 * midiInStart [WINMM.@]
1467 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1469 LPWINE_MLD wmld;
1471 TRACE("(%p)\n", hMidiIn);
1473 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1474 return MMSYSERR_INVALHANDLE;
1476 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1479 /**************************************************************************
1480 * midiInStop [WINMM.@]
1482 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1484 LPWINE_MLD wmld;
1486 TRACE("(%p)\n", hMidiIn);
1488 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1489 return MMSYSERR_INVALHANDLE;
1491 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1494 /**************************************************************************
1495 * midiInReset [WINMM.@]
1497 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1499 LPWINE_MLD wmld;
1501 TRACE("(%p)\n", hMidiIn);
1503 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1504 return MMSYSERR_INVALHANDLE;
1506 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1509 /**************************************************************************
1510 * midiInGetID [WINMM.@]
1512 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1514 LPWINE_MLD wmld;
1516 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
1518 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1520 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1521 return MMSYSERR_INVALHANDLE;
1523 *lpuDeviceID = wmld->uDeviceID;
1525 return MMSYSERR_NOERROR;
1528 /**************************************************************************
1529 * midiInMessage [WINMM.@]
1531 DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1532 DWORD dwParam1, DWORD dwParam2)
1534 LPWINE_MLD wmld;
1536 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1538 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1539 return MMSYSERR_INVALHANDLE;
1541 switch (uMessage) {
1542 case MIDM_OPEN:
1543 case MIDM_CLOSE:
1544 FIXME("can't handle OPEN or CLOSE message!\n");
1545 return MMSYSERR_NOTSUPPORTED;
1547 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1550 typedef struct WINE_MIDIStream {
1551 HMIDIOUT hDevice;
1552 HANDLE hThread;
1553 DWORD dwThreadID;
1554 DWORD dwTempo;
1555 DWORD dwTimeDiv;
1556 DWORD dwPositionMS;
1557 DWORD dwPulses;
1558 DWORD dwStartTicks;
1559 WORD wFlags;
1560 HANDLE hEvent;
1561 LPMIDIHDR lpMidiHdr;
1562 } WINE_MIDIStream;
1564 #define WINE_MSM_HEADER (WM_USER+0)
1565 #define WINE_MSM_STOP (WM_USER+1)
1567 /**************************************************************************
1568 * MMSYSTEM_GetMidiStream [internal]
1570 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1572 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1574 if (lplpwm)
1575 *lplpwm = lpwm;
1577 if (lpwm == NULL) {
1578 return FALSE;
1581 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1583 return *lpMidiStrm != NULL;
1586 /**************************************************************************
1587 * MMSYSTEM_MidiStream_Convert [internal]
1589 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1591 DWORD ret = 0;
1593 if (lpMidiStrm->dwTimeDiv == 0) {
1594 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1595 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1596 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1597 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1598 ret = (pulse * 1000) / (nf * nsf);
1599 } else {
1600 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1601 (double)lpMidiStrm->dwTimeDiv);
1604 return ret;
1607 /**************************************************************************
1608 * MMSYSTEM_MidiStream_MessageHandler [internal]
1610 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1612 LPMIDIHDR lpMidiHdr;
1613 LPMIDIHDR* lpmh;
1614 LPBYTE lpData;
1616 switch (msg->message) {
1617 case WM_QUIT:
1618 SetEvent(lpMidiStrm->hEvent);
1619 return FALSE;
1620 case WINE_MSM_STOP:
1621 TRACE("STOP\n");
1622 /* this is not quite what MS doc says... */
1623 midiOutReset(lpMidiStrm->hDevice);
1624 /* empty list of already submitted buffers */
1625 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1626 lpMidiHdr->dwFlags |= MHDR_DONE;
1627 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1629 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1630 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1631 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1633 lpMidiStrm->lpMidiHdr = 0;
1634 SetEvent(lpMidiStrm->hEvent);
1635 break;
1636 case WINE_MSM_HEADER:
1637 /* sets initial tick count for first MIDIHDR */
1638 if (!lpMidiStrm->dwStartTicks)
1639 lpMidiStrm->dwStartTicks = GetTickCount();
1641 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1642 * by native mcimidi, it doesn't look like a correct one".
1643 * this trick allows to throw it away... but I don't like it.
1644 * It looks like part of the file I'm trying to play and definitively looks
1645 * like raw midi content
1646 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1647 * synchronization issue where native mcimidi is still processing raw MIDI
1648 * content before generating MIDIEVENTs ?
1650 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1651 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1652 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1653 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1654 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1655 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1656 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1657 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1658 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1659 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1660 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1661 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1662 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1663 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1664 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1665 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1666 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1668 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1669 lpData = lpMidiHdr->lpData;
1670 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1671 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1672 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1673 lpMidiHdr->dwFlags, msg->wParam);
1674 #if 0
1675 /* dumps content of lpMidiHdr->lpData
1676 * FIXME: there should be a debug routine somewhere that already does this
1677 * I hate spreading this type of shit all around the code
1679 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
1680 DWORD i;
1681 BYTE ch;
1683 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
1684 printf("%02x ", lpData[dwToGo + i]);
1685 for (; i < 16; i++)
1686 printf(" ");
1687 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
1688 ch = lpData[dwToGo + i];
1689 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
1691 printf("\n");
1693 #endif
1694 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
1695 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
1696 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
1697 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
1698 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
1699 ((LPMIDIEVENT)lpData)->dwStreamID);
1700 lpMidiHdr->dwFlags |= MHDR_DONE;
1701 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1703 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1704 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1705 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1706 break;
1709 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
1710 *lpmh = lpMidiHdr;
1711 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1712 lpMidiHdr->lpNext = 0;
1713 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1714 lpMidiHdr->dwFlags &= MHDR_DONE;
1715 lpMidiHdr->dwOffset = 0;
1717 break;
1718 default:
1719 FIXME("Unknown message %d\n", msg->message);
1720 break;
1722 return TRUE;
1725 /**************************************************************************
1726 * MMSYSTEM_MidiStream_Player [internal]
1728 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
1730 WINE_MIDIStream* lpMidiStrm = pmt;
1731 WINE_MIDI* lpwm;
1732 MSG msg;
1733 DWORD dwToGo;
1734 DWORD dwCurrTC;
1735 LPMIDIHDR lpMidiHdr;
1736 LPMIDIEVENT me;
1737 LPBYTE lpData = 0;
1739 TRACE("(%p)!\n", lpMidiStrm);
1741 if (!lpMidiStrm ||
1742 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
1743 goto the_end;
1745 /* force thread's queue creation */
1746 /* Used to be InitThreadInput16(0, 5); */
1747 /* but following works also with hack in midiStreamOpen */
1748 PeekMessageA(&msg, 0, 0, 0, 0);
1750 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
1751 SetEvent(lpMidiStrm->hEvent);
1752 TRACE("Ready to go 1\n");
1753 /* thread is started in paused mode */
1754 SuspendThread(lpMidiStrm->hThread);
1755 TRACE("Ready to go 2\n");
1757 lpMidiStrm->dwStartTicks = 0;
1758 lpMidiStrm->dwPulses = 0;
1760 lpMidiStrm->lpMidiHdr = 0;
1762 for (;;) {
1763 lpMidiHdr = lpMidiStrm->lpMidiHdr;
1764 if (!lpMidiHdr) {
1765 /* for first message, block until one arrives, then process all that are available */
1766 GetMessageA(&msg, 0, 0, 0);
1767 do {
1768 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1769 goto the_end;
1770 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
1771 lpData = 0;
1772 continue;
1775 if (!lpData)
1776 lpData = lpMidiHdr->lpData;
1778 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
1780 /* do we have to wait ? */
1781 if (me->dwDeltaTime) {
1782 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
1783 lpMidiStrm->dwPulses += me->dwDeltaTime;
1785 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
1787 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
1788 while ((dwCurrTC = GetTickCount()) < dwToGo) {
1789 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
1790 /* got a message, handle it */
1791 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
1792 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
1793 goto the_end;
1795 lpData = 0;
1796 } else {
1797 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
1798 break;
1802 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
1803 case MEVT_COMMENT:
1804 FIXME("NIY: MEVT_COMMENT\n");
1805 /* do nothing, skip bytes */
1806 break;
1807 case MEVT_LONGMSG:
1808 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
1809 break;
1810 case MEVT_NOP:
1811 break;
1812 case MEVT_SHORTMSG:
1813 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
1814 break;
1815 case MEVT_TEMPO:
1816 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
1817 break;
1818 case MEVT_VERSION:
1819 break;
1820 default:
1821 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
1822 break;
1824 if (me->dwEvent & MEVT_F_CALLBACK) {
1825 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1826 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
1827 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
1829 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
1830 if (me->dwEvent & MEVT_F_LONG)
1831 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
1832 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
1833 /* done with this header */
1834 lpMidiHdr->dwFlags |= MHDR_DONE;
1835 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1837 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
1838 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1839 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1840 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1841 lpData = 0;
1844 the_end:
1845 TRACE("End of thread\n");
1846 ExitThread(0);
1847 return 0; /* for removing the warning, never executed */
1850 /**************************************************************************
1851 * MMSYSTEM_MidiStream_PostMessage [internal]
1853 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
1855 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
1856 DWORD count;
1858 ReleaseThunkLock(&count);
1859 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1860 RestoreThunkLock(count);
1861 } else {
1862 WARN("bad PostThreadMessageA\n");
1863 return FALSE;
1865 return TRUE;
1868 /**************************************************************************
1869 * midiStreamClose [WINMM.@]
1871 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
1873 WINE_MIDIStream* lpMidiStrm;
1875 TRACE("(%p)!\n", hMidiStrm);
1877 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
1878 return MMSYSERR_INVALHANDLE;
1880 midiStreamStop(hMidiStrm);
1881 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
1882 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
1883 CloseHandle(lpMidiStrm->hEvent);
1885 return midiOutClose((HMIDIOUT)hMidiStrm);
1888 /**************************************************************************
1889 * MMSYSTEM_MidiStream_Open [internal]
1891 MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi,
1892 DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen,
1893 BOOL bFrom32)
1895 WINE_MIDIStream* lpMidiStrm;
1896 MMRESULT ret;
1897 MIDIOPENSTRMID mosm;
1898 LPWINE_MIDI lpwm;
1899 HMIDIOUT hMidiOut;
1901 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
1902 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
1904 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
1905 return MMSYSERR_INVALPARAM;
1907 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
1908 if (!lpMidiStrm)
1909 return MMSYSERR_NOMEM;
1911 lpMidiStrm->dwTempo = 500000;
1912 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
1913 lpMidiStrm->dwPositionMS = 0;
1915 mosm.dwStreamID = (DWORD)lpMidiStrm;
1916 /* FIXME: the correct value is not allocated yet for MAPPER */
1917 mosm.wDeviceID = *lpuDeviceID;
1918 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
1919 lpMidiStrm->hDevice = hMidiOut;
1920 if (lphMidiStrm)
1921 *lphMidiStrm = (HMIDISTRM)hMidiOut;
1923 /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */
1924 FIXME("*lpuDeviceID=%x\n", *lpuDeviceID);
1925 lpwm->mld.uDeviceID = *lpuDeviceID = 0;
1927 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
1928 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1929 lpMidiStrm->wFlags = HIWORD(fdwOpen);
1931 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
1932 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
1934 if (!lpMidiStrm->hThread) {
1935 midiStreamClose((HMIDISTRM)hMidiOut);
1936 return MMSYSERR_NOMEM;
1939 /* wait for thread to have started, and for its queue to be created */
1941 DWORD count;
1943 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
1944 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
1945 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
1947 ReleaseThunkLock(&count);
1948 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
1949 RestoreThunkLock(count);
1952 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
1953 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
1954 return ret;
1957 /**************************************************************************
1958 * midiStreamOpen [WINMM.@]
1960 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
1961 DWORD cMidi, DWORD dwCallback,
1962 DWORD dwInstance, DWORD fdwOpen)
1964 return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
1965 dwInstance, fdwOpen, TRUE);
1968 /**************************************************************************
1969 * midiStreamOut [WINMM.@]
1971 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
1972 UINT cbMidiHdr)
1974 WINE_MIDIStream* lpMidiStrm;
1975 DWORD ret = MMSYSERR_NOERROR;
1977 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
1979 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
1980 ret = MMSYSERR_INVALHANDLE;
1981 } else if (!lpMidiHdr) {
1982 ret = MMSYSERR_INVALPARAM;
1983 } else {
1984 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
1985 WINE_MSM_HEADER, cbMidiHdr,
1986 (DWORD)lpMidiHdr)) {
1987 WARN("bad PostThreadMessageA\n");
1988 ret = MMSYSERR_ERROR;
1991 return ret;
1994 /**************************************************************************
1995 * midiStreamPause [WINMM.@]
1997 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
1999 WINE_MIDIStream* lpMidiStrm;
2000 DWORD ret = MMSYSERR_NOERROR;
2002 TRACE("(%p)!\n", hMidiStrm);
2004 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2005 ret = MMSYSERR_INVALHANDLE;
2006 } else {
2007 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2008 WARN("bad Suspend (%ld)\n", GetLastError());
2009 ret = MMSYSERR_ERROR;
2012 return ret;
2015 /**************************************************************************
2016 * midiStreamPosition [WINMM.@]
2018 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2020 WINE_MIDIStream* lpMidiStrm;
2021 DWORD ret = MMSYSERR_NOERROR;
2023 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2025 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2026 ret = MMSYSERR_INVALHANDLE;
2027 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2028 ret = MMSYSERR_INVALPARAM;
2029 } else {
2030 switch (lpMMT->wType) {
2031 case TIME_MS:
2032 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2033 TRACE("=> %ld ms\n", lpMMT->u.ms);
2034 break;
2035 case TIME_TICKS:
2036 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2037 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2038 break;
2039 default:
2040 WARN("Unsupported time type %d\n", lpMMT->wType);
2041 lpMMT->wType = TIME_MS;
2042 ret = MMSYSERR_INVALPARAM;
2043 break;
2046 return ret;
2049 /**************************************************************************
2050 * midiStreamProperty [WINMM.@]
2052 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2054 WINE_MIDIStream* lpMidiStrm;
2055 MMRESULT ret = MMSYSERR_NOERROR;
2057 TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2059 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2060 ret = MMSYSERR_INVALHANDLE;
2061 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2062 ret = MMSYSERR_INVALPARAM;
2063 } else if (dwProperty & MIDIPROP_TEMPO) {
2064 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2066 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2067 ret = MMSYSERR_INVALPARAM;
2068 } else if (dwProperty & MIDIPROP_SET) {
2069 lpMidiStrm->dwTempo = mpt->dwTempo;
2070 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2071 } else if (dwProperty & MIDIPROP_GET) {
2072 mpt->dwTempo = lpMidiStrm->dwTempo;
2073 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2075 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2076 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2078 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2079 ret = MMSYSERR_INVALPARAM;
2080 } else if (dwProperty & MIDIPROP_SET) {
2081 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2082 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2083 } else if (dwProperty & MIDIPROP_GET) {
2084 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2085 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2087 } else {
2088 ret = MMSYSERR_INVALPARAM;
2091 return ret;
2094 /**************************************************************************
2095 * midiStreamRestart [WINMM.@]
2097 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2099 WINE_MIDIStream* lpMidiStrm;
2100 MMRESULT ret = MMSYSERR_NOERROR;
2102 TRACE("(%p)!\n", hMidiStrm);
2104 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2105 ret = MMSYSERR_INVALHANDLE;
2106 } else {
2107 DWORD ret;
2109 /* since we increase the thread suspend count on each midiStreamPause
2110 * there may be a need for several midiStreamResume
2112 do {
2113 ret = ResumeThread(lpMidiStrm->hThread);
2114 } while (ret != 0xFFFFFFFF && ret != 0);
2115 if (ret == 0xFFFFFFFF) {
2116 WARN("bad Resume (%ld)\n", GetLastError());
2117 ret = MMSYSERR_ERROR;
2118 } else {
2119 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2122 return ret;
2125 /**************************************************************************
2126 * midiStreamStop [WINMM.@]
2128 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2130 WINE_MIDIStream* lpMidiStrm;
2131 MMRESULT ret = MMSYSERR_NOERROR;
2133 TRACE("(%p)!\n", hMidiStrm);
2135 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2136 ret = MMSYSERR_INVALHANDLE;
2137 } else {
2138 /* in case stream has been paused... FIXME is the current state correct ? */
2139 midiStreamRestart(hMidiStrm);
2140 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2142 return ret;
2145 UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2146 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2147 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2149 HANDLE handle;
2150 LPWINE_MLD wmld;
2151 DWORD dwRet = MMSYSERR_NOERROR;
2152 WAVEOPENDESC wod;
2154 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2155 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2156 dwInstance, dwFlags, bFrom32?32:16);
2158 if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n");
2160 if (lpFormat == NULL) return WAVERR_BADFORMAT;
2161 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1))
2162 return MMSYSERR_INVALPARAM;
2164 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n",
2165 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2166 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize);
2168 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2169 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL)
2170 return MMSYSERR_NOMEM;
2172 wod.hWave = handle;
2173 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2174 wod.dwCallback = dwCallback;
2175 wod.dwInstance = dwInstance;
2176 wod.dnDevNode = 0L;
2178 TRACE("cb=%08lx\n", wod.dwCallback);
2180 for (;;) {
2181 if (dwFlags & WAVE_MAPPED) {
2182 wod.uMappedDeviceID = uDeviceID;
2183 uDeviceID = WAVE_MAPPER;
2184 } else {
2185 wod.uMappedDeviceID = -1;
2187 wmld->uDeviceID = uDeviceID;
2189 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2190 (DWORD)&wod, dwFlags);
2192 if (dwRet != WAVERR_BADFORMAT ||
2193 (dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) break;
2194 /* if we ask for a format which isn't supported by the physical driver,
2195 * let's try to map it through the wave mapper (except, if we already tried
2196 * or user didn't allow us to use acm codecs)
2198 dwFlags |= WAVE_MAPPED;
2199 /* we shall loop only one */
2202 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2203 MMDRV_Free(handle, wmld);
2204 handle = 0;
2207 if (lphndl != NULL) *lphndl = handle;
2208 TRACE("=> %ld hWave=%p\n", dwRet, handle);
2210 return dwRet;
2213 /**************************************************************************
2214 * waveOutGetNumDevs [WINMM.@]
2216 UINT WINAPI waveOutGetNumDevs(void)
2218 return MMDRV_GetNum(MMDRV_WAVEOUT);
2221 /**************************************************************************
2222 * waveOutGetDevCapsA [WINMM.@]
2224 UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps,
2225 UINT uSize)
2227 LPWINE_MLD wmld;
2229 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2231 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2233 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2234 return MMSYSERR_BADDEVICEID;
2236 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2240 /**************************************************************************
2241 * waveOutGetDevCapsW [WINMM.@]
2243 UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps,
2244 UINT uSize)
2246 WAVEOUTCAPSA wocA;
2247 UINT ret;
2249 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2251 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2253 if (ret == MMSYSERR_NOERROR) {
2254 lpCaps->wMid = wocA.wMid;
2255 lpCaps->wPid = wocA.wPid;
2256 lpCaps->vDriverVersion = wocA.vDriverVersion;
2257 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname,
2258 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2259 lpCaps->dwFormats = wocA.dwFormats;
2260 lpCaps->wChannels = wocA.wChannels;
2261 lpCaps->dwSupport = wocA.dwSupport;
2263 return ret;
2266 /**************************************************************************
2267 * WAVE_GetErrorText [internal]
2269 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2271 UINT16 ret = MMSYSERR_BADERRNUM;
2273 if (lpText == NULL) {
2274 ret = MMSYSERR_INVALPARAM;
2275 } else if (uSize == 0) {
2276 ret = MMSYSERR_NOERROR;
2277 } else if (
2278 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2279 * a warning for the test was always true */
2280 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2281 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2283 if (LoadStringA(WINMM_IData->hWinMM32Instance,
2284 uError, lpText, uSize) > 0) {
2285 ret = MMSYSERR_NOERROR;
2288 return ret;
2291 /**************************************************************************
2292 * waveOutGetErrorTextA [WINMM.@]
2294 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2296 return WAVE_GetErrorText(uError, lpText, uSize);
2299 /**************************************************************************
2300 * waveOutGetErrorTextW [WINMM.@]
2302 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2304 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2305 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2307 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2308 HeapFree(GetProcessHeap(), 0, xstr);
2309 return ret;
2312 /**************************************************************************
2313 * waveOutOpen [WINMM.@]
2314 * All the args/structs have the same layout as the win16 equivalents
2316 UINT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID,
2317 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2318 DWORD dwInstance, DWORD dwFlags)
2320 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2321 dwCallback, dwInstance, dwFlags, TRUE);
2324 /**************************************************************************
2325 * waveOutClose [WINMM.@]
2327 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2329 LPWINE_MLD wmld;
2330 DWORD dwRet;
2332 TRACE("(%p)\n", hWaveOut);
2334 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2335 return MMSYSERR_INVALHANDLE;
2337 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2338 MMDRV_Free(hWaveOut, wmld);
2340 return dwRet;
2343 /**************************************************************************
2344 * waveOutPrepareHeader [WINMM.@]
2346 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2347 WAVEHDR* lpWaveOutHdr, UINT uSize)
2349 LPWINE_MLD wmld;
2351 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2353 if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM;
2355 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2356 return MMSYSERR_INVALHANDLE;
2358 return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2361 /**************************************************************************
2362 * waveOutUnprepareHeader [WINMM.@]
2364 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2365 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2367 LPWINE_MLD wmld;
2369 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2371 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2372 return MMSYSERR_NOERROR;
2375 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2376 return MMSYSERR_INVALHANDLE;
2378 return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2381 /**************************************************************************
2382 * waveOutWrite [WINMM.@]
2384 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2385 UINT uSize)
2387 LPWINE_MLD wmld;
2389 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2391 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2392 return MMSYSERR_INVALHANDLE;
2394 return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE);
2397 /**************************************************************************
2398 * waveOutBreakLoop [WINMM.@]
2400 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2402 LPWINE_MLD wmld;
2404 TRACE("(%p);\n", hWaveOut);
2406 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2407 return MMSYSERR_INVALHANDLE;
2408 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2411 /**************************************************************************
2412 * waveOutPause [WINMM.@]
2414 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2416 LPWINE_MLD wmld;
2418 TRACE("(%p);\n", hWaveOut);
2420 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2421 return MMSYSERR_INVALHANDLE;
2422 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2425 /**************************************************************************
2426 * waveOutReset [WINMM.@]
2428 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2430 LPWINE_MLD wmld;
2432 TRACE("(%p);\n", hWaveOut);
2434 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2435 return MMSYSERR_INVALHANDLE;
2436 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2439 /**************************************************************************
2440 * waveOutRestart [WINMM.@]
2442 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2444 LPWINE_MLD wmld;
2446 TRACE("(%p);\n", hWaveOut);
2448 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2449 return MMSYSERR_INVALHANDLE;
2450 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2453 /**************************************************************************
2454 * waveOutGetPosition [WINMM.@]
2456 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2457 UINT uSize)
2459 LPWINE_MLD wmld;
2461 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
2463 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2464 return MMSYSERR_INVALHANDLE;
2466 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2469 /**************************************************************************
2470 * waveOutGetPitch [WINMM.@]
2472 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2474 LPWINE_MLD wmld;
2476 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2478 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2479 return MMSYSERR_INVALHANDLE;
2480 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE);
2483 /**************************************************************************
2484 * waveOutSetPitch [WINMM.@]
2486 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2488 LPWINE_MLD wmld;
2490 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2492 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2493 return MMSYSERR_INVALHANDLE;
2494 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2497 /**************************************************************************
2498 * waveOutGetPlaybackRate [WINMM.@]
2500 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2502 LPWINE_MLD wmld;
2504 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2506 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2507 return MMSYSERR_INVALHANDLE;
2508 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE);
2511 /**************************************************************************
2512 * waveOutSetPlaybackRate [WINMM.@]
2514 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2516 LPWINE_MLD wmld;
2518 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2520 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2521 return MMSYSERR_INVALHANDLE;
2522 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2525 /**************************************************************************
2526 * waveOutGetVolume [WINMM.@]
2528 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
2530 LPWINE_MLD wmld;
2532 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2534 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2535 return MMSYSERR_INVALHANDLE;
2537 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE);
2540 /**************************************************************************
2541 * waveOutSetVolume [WINMM.@]
2543 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
2545 LPWINE_MLD wmld;
2547 TRACE("(%p, %08lx);\n", hWaveOut, dw);
2549 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2550 return MMSYSERR_INVALHANDLE;
2552 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2555 /**************************************************************************
2556 * waveOutGetID [WINMM.@]
2558 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2560 LPWINE_MLD wmld;
2562 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
2564 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2566 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2567 return MMSYSERR_INVALHANDLE;
2569 *lpuDeviceID = wmld->uDeviceID;
2570 return 0;
2573 /**************************************************************************
2574 * waveOutMessage [WINMM.@]
2576 DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2577 DWORD dwParam1, DWORD dwParam2)
2579 LPWINE_MLD wmld;
2581 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2583 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2584 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2585 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2587 return MMSYSERR_INVALHANDLE;
2590 /* from M$ KB */
2591 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2592 return MMSYSERR_INVALPARAM;
2594 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2597 /**************************************************************************
2598 * waveInGetNumDevs [WINMM.@]
2600 UINT WINAPI waveInGetNumDevs(void)
2602 return MMDRV_GetNum(MMDRV_WAVEIN);
2605 /**************************************************************************
2606 * waveInGetDevCapsW [WINMM.@]
2608 UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2610 WAVEINCAPSA wicA;
2611 UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize);
2613 if (ret == MMSYSERR_NOERROR) {
2614 lpCaps->wMid = wicA.wMid;
2615 lpCaps->wPid = wicA.wPid;
2616 lpCaps->vDriverVersion = wicA.vDriverVersion;
2617 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname,
2618 sizeof(lpCaps->szPname)/sizeof(WCHAR) );
2619 lpCaps->dwFormats = wicA.dwFormats;
2620 lpCaps->wChannels = wicA.wChannels;
2623 return ret;
2626 /**************************************************************************
2627 * waveInGetDevCapsA [WINMM.@]
2629 UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
2631 LPWINE_MLD wmld;
2633 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2635 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
2636 return MMSYSERR_BADDEVICEID;
2638 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE);
2641 /**************************************************************************
2642 * waveInGetErrorTextA [WINMM.@]
2644 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2646 return WAVE_GetErrorText(uError, lpText, uSize);
2649 /**************************************************************************
2650 * waveInGetErrorTextW [WINMM.@]
2652 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2654 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
2655 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
2657 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
2658 HeapFree(GetProcessHeap(), 0, txt);
2659 return ret;
2662 /**************************************************************************
2663 * waveInOpen [WINMM.@]
2665 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
2666 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2667 DWORD dwInstance, DWORD dwFlags)
2669 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
2670 dwCallback, dwInstance, dwFlags, TRUE);
2673 /**************************************************************************
2674 * waveInClose [WINMM.@]
2676 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
2678 LPWINE_MLD wmld;
2679 DWORD dwRet;
2681 TRACE("(%p)\n", hWaveIn);
2683 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2684 return MMSYSERR_INVALHANDLE;
2686 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
2687 MMDRV_Free(hWaveIn, wmld);
2688 return dwRet;
2691 /**************************************************************************
2692 * waveInPrepareHeader [WINMM.@]
2694 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2695 UINT uSize)
2697 LPWINE_MLD wmld;
2699 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2701 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2702 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2703 return MMSYSERR_INVALHANDLE;
2705 lpWaveInHdr->dwBytesRecorded = 0;
2707 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2710 /**************************************************************************
2711 * waveInUnprepareHeader [WINMM.@]
2713 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
2714 UINT uSize)
2716 LPWINE_MLD wmld;
2718 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2720 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2721 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
2722 return MMSYSERR_NOERROR;
2725 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2726 return MMSYSERR_INVALHANDLE;
2728 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE);
2731 /**************************************************************************
2732 * waveInAddBuffer [WINMM.@]
2734 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
2735 WAVEHDR* lpWaveInHdr, UINT uSize)
2737 LPWINE_MLD wmld;
2739 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
2741 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
2742 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2743 return MMSYSERR_INVALHANDLE;
2745 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE);
2748 /**************************************************************************
2749 * waveInReset [WINMM.@]
2751 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
2753 LPWINE_MLD wmld;
2755 TRACE("(%p);\n", hWaveIn);
2757 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2758 return MMSYSERR_INVALHANDLE;
2760 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
2763 /**************************************************************************
2764 * waveInStart [WINMM.@]
2766 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
2768 LPWINE_MLD wmld;
2770 TRACE("(%p);\n", hWaveIn);
2772 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2773 return MMSYSERR_INVALHANDLE;
2775 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
2778 /**************************************************************************
2779 * waveInStop [WINMM.@]
2781 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
2783 LPWINE_MLD wmld;
2785 TRACE("(%p);\n", hWaveIn);
2787 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2788 return MMSYSERR_INVALHANDLE;
2790 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
2793 /**************************************************************************
2794 * waveInGetPosition [WINMM.@]
2796 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
2797 UINT uSize)
2799 LPWINE_MLD wmld;
2801 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
2803 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2804 return MMSYSERR_INVALHANDLE;
2806 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE);
2809 /**************************************************************************
2810 * waveInGetID [WINMM.@]
2812 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
2814 LPWINE_MLD wmld;
2816 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
2818 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2820 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
2821 return MMSYSERR_INVALHANDLE;
2823 *lpuDeviceID = wmld->uDeviceID;
2824 return MMSYSERR_NOERROR;
2827 /**************************************************************************
2828 * waveInMessage [WINMM.@]
2830 DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
2831 DWORD dwParam1, DWORD dwParam2)
2833 LPWINE_MLD wmld;
2835 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
2837 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
2838 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
2839 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2841 return MMSYSERR_INVALHANDLE;
2844 /* from M$ KB */
2845 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
2846 return MMSYSERR_INVALPARAM;
2849 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);