Cleanup messages in supportedFormat.
[wine/wine-gecko.git] / dlls / winmm / winmm.c
blob10588c04a0a49482a0fa6ebad138c8af9c7b7fc4
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 UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm)
212 LPWINE_MIXER lpwm = NULL;
213 UINT uRet = MMSYSERR_NOERROR;
215 switch (dwFlags & 0xF0000000ul) {
216 case MIXER_OBJECTF_MIXER:
217 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
218 break;
219 case MIXER_OBJECTF_HMIXER:
220 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
221 break;
222 case MIXER_OBJECTF_WAVEOUT:
223 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER);
224 break;
225 case MIXER_OBJECTF_HWAVEOUT:
226 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
227 break;
228 case MIXER_OBJECTF_WAVEIN:
229 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER);
230 break;
231 case MIXER_OBJECTF_HWAVEIN:
232 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER);
233 break;
234 case MIXER_OBJECTF_MIDIOUT:
235 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER);
236 break;
237 case MIXER_OBJECTF_HMIDIOUT:
238 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
239 break;
240 case MIXER_OBJECTF_MIDIIN:
241 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER);
242 break;
243 case MIXER_OBJECTF_HMIDIIN:
244 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER);
245 break;
246 case MIXER_OBJECTF_AUX:
247 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER);
248 break;
249 default:
250 WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
251 lpwm = 0;
252 uRet = MMSYSERR_INVALFLAG;
253 break;
255 *lplpwm = lpwm;
256 if (lpwm == 0 && uRet == MMSYSERR_NOERROR)
257 uRet = MMSYSERR_INVALPARAM;
258 return uRet;
261 /**************************************************************************
262 * mixerGetNumDevs [WINMM.@]
264 UINT WINAPI mixerGetNumDevs(void)
266 return MMDRV_GetNum(MMDRV_MIXER);
269 /**************************************************************************
270 * mixerGetDevCapsA [WINMM.@]
272 UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize)
274 LPWINE_MLD wmld;
276 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
278 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL)
279 return MMSYSERR_BADDEVICEID;
281 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
284 /**************************************************************************
285 * mixerGetDevCapsW [WINMM.@]
287 UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize)
289 MIXERCAPSA micA;
290 UINT ret;
292 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
294 ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA));
295 if (ret == MMSYSERR_NOERROR) {
296 MIXERCAPSW micW;
297 micW.wMid = micA.wMid;
298 micW.wPid = micA.wPid;
299 micW.vDriverVersion = micA.vDriverVersion;
300 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
301 sizeof(micW.szPname)/sizeof(WCHAR) );
302 micW.fdwSupport = micA.fdwSupport;
303 micW.cDestinations = micA.cDestinations;
304 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
306 return ret;
309 UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
310 DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32)
312 HANDLE hMix;
313 LPWINE_MLD wmld;
314 DWORD dwRet = 0;
315 MIXEROPENDESC mod;
317 TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
318 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
320 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
321 &dwCallback, &dwInstance, bFrom32);
323 wmld->uDeviceID = uDeviceID;
324 mod.hmx = (HMIXEROBJ)hMix;
325 mod.dwCallback = dwCallback;
326 mod.dwInstance = dwInstance;
328 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
330 if (dwRet != MMSYSERR_NOERROR) {
331 MMDRV_Free(hMix, wmld);
332 hMix = 0;
334 if (lphMix) *lphMix = hMix;
335 TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
337 return dwRet;
340 /**************************************************************************
341 * mixerOpen [WINMM.@]
343 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
344 DWORD_PTR dwInstance, DWORD fdwOpen)
346 return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
349 /**************************************************************************
350 * mixerClose [WINMM.@]
352 UINT WINAPI mixerClose(HMIXER hMix)
354 LPWINE_MLD wmld;
355 DWORD dwRet;
357 TRACE("(%p)\n", hMix);
359 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
361 dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
362 MMDRV_Free(hMix, wmld);
364 return dwRet;
367 /**************************************************************************
368 * mixerGetID [WINMM.@]
370 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
372 LPWINE_MIXER lpwm;
373 UINT uRet = MMSYSERR_NOERROR;
375 TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID);
377 if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR)
378 return uRet;
380 if (lpid)
381 *lpid = lpwm->mld.uDeviceID;
383 return uRet;
386 /**************************************************************************
387 * mixerGetControlDetailsA [WINMM.@]
389 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
390 DWORD fdwDetails)
392 LPWINE_MIXER lpwm;
393 UINT uRet = MMSYSERR_NOERROR;
395 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
397 if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR)
398 return uRet;
400 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
401 return MMSYSERR_INVALPARAM;
403 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdA,
404 fdwDetails, TRUE);
407 /**************************************************************************
408 * mixerGetControlDetailsW [WINMM.@]
410 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
412 DWORD ret = MMSYSERR_NOTENABLED;
414 TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails);
416 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
417 return MMSYSERR_INVALPARAM;
419 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
420 case MIXER_GETCONTROLDETAILSF_VALUE:
421 /* can savely use W structure as it is, no string inside */
422 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
423 break;
424 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
426 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
427 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
428 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
429 int i;
431 if (lpmcd->u.cMultipleItems != 0) {
432 size *= lpmcd->u.cMultipleItems;
434 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
435 lpmcd->paDetails = pDetailsA;
436 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
437 /* set up lpmcd->paDetails */
438 ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails);
439 /* copy from lpmcd->paDetails back to paDetailsW; */
440 if(ret == MMSYSERR_NOERROR) {
441 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
442 pDetailsW->dwParam1 = pDetailsA->dwParam1;
443 pDetailsW->dwParam2 = pDetailsA->dwParam2;
444 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
445 pDetailsW->szName,
446 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
447 pDetailsA++;
448 pDetailsW++;
450 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
451 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
453 HeapFree(GetProcessHeap(), 0, pDetailsA);
454 lpmcd->paDetails = pDetailsW;
455 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
457 break;
458 default:
459 ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails);
462 return ret;
465 /**************************************************************************
466 * mixerGetLineControlsA [WINMM.@]
468 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
469 DWORD fdwControls)
471 LPWINE_MIXER lpwm;
472 UINT uRet = MMSYSERR_NOERROR;
474 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls);
476 if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR)
477 return uRet;
479 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA))
480 return MMSYSERR_INVALPARAM;
482 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcA,
483 fdwControls, TRUE);
486 /**************************************************************************
487 * mixerGetLineControlsW [WINMM.@]
489 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
490 DWORD fdwControls)
492 MIXERLINECONTROLSA mlcA;
493 DWORD ret;
494 int i;
496 TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls);
498 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) ||
499 lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
500 return MMSYSERR_INVALPARAM;
502 mlcA.cbStruct = sizeof(mlcA);
503 mlcA.dwLineID = lpmlcW->dwLineID;
504 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
505 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
506 mlcA.cControls = lpmlcW->cControls;
507 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
508 mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
509 mlcA.cControls * mlcA.cbmxctrl);
511 ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls);
513 if (ret == MMSYSERR_NOERROR) {
514 lpmlcW->dwLineID = mlcA.dwLineID;
515 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
516 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
517 lpmlcW->cControls = mlcA.cControls;
519 for (i = 0; i < mlcA.cControls; i++) {
520 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
521 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
522 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
523 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
524 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
525 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
526 lpmlcW->pamxctrl[i].szShortName,
527 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
528 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
529 lpmlcW->pamxctrl[i].szName,
530 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
531 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
532 * sizeof(mlcA.pamxctrl[i].Bounds) */
533 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
534 sizeof(mlcA.pamxctrl[i].Bounds));
535 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
536 * sizeof(mlcA.pamxctrl[i].Metrics) */
537 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
538 sizeof(mlcA.pamxctrl[i].Metrics));
542 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
544 return ret;
547 /**************************************************************************
548 * mixerGetLineInfoA [WINMM.@]
550 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo)
552 LPWINE_MIXER lpwm;
553 UINT uRet = MMSYSERR_NOERROR;
555 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
557 if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR)
558 return uRet;
560 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW,
561 fdwInfo, TRUE);
564 /**************************************************************************
565 * mixerGetLineInfoW [WINMM.@]
567 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW,
568 DWORD fdwInfo)
570 MIXERLINEA mliA;
571 UINT ret;
573 TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo);
575 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
576 return MMSYSERR_INVALPARAM;
578 mliA.cbStruct = sizeof(mliA);
579 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
580 case MIXER_GETLINEINFOF_COMPONENTTYPE:
581 mliA.dwComponentType = lpmliW->dwComponentType;
582 break;
583 case MIXER_GETLINEINFOF_DESTINATION:
584 mliA.dwDestination = lpmliW->dwDestination;
585 break;
586 case MIXER_GETLINEINFOF_LINEID:
587 mliA.dwLineID = lpmliW->dwLineID;
588 break;
589 case MIXER_GETLINEINFOF_SOURCE:
590 mliA.dwDestination = lpmliW->dwDestination;
591 mliA.dwSource = lpmliW->dwSource;
592 break;
593 case MIXER_GETLINEINFOF_TARGETTYPE:
594 mliA.Target.dwType = lpmliW->Target.dwType;
595 mliA.Target.wMid = lpmliW->Target.wMid;
596 mliA.Target.wPid = lpmliW->Target.wPid;
597 mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion;
598 WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL);
599 break;
600 default:
601 WARN("Unsupported fdwControls=0x%08lx\n", fdwInfo);
602 return MMSYSERR_INVALFLAG;
605 ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo);
607 lpmliW->dwDestination = mliA.dwDestination;
608 lpmliW->dwSource = mliA.dwSource;
609 lpmliW->dwLineID = mliA.dwLineID;
610 lpmliW->fdwLine = mliA.fdwLine;
611 lpmliW->dwUser = mliA.dwUser;
612 lpmliW->dwComponentType = mliA.dwComponentType;
613 lpmliW->cChannels = mliA.cChannels;
614 lpmliW->cConnections = mliA.cConnections;
615 lpmliW->cControls = mliA.cControls;
616 MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName,
617 sizeof(lpmliW->szShortName)/sizeof(WCHAR) );
618 MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName,
619 sizeof(lpmliW->szName)/sizeof(WCHAR) );
620 lpmliW->Target.dwType = mliA.Target.dwType;
621 lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID;
622 lpmliW->Target.wMid = mliA.Target.wMid;
623 lpmliW->Target.wPid = mliA.Target.wPid;
624 lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion;
625 MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname,
626 sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) );
628 return ret;
631 /**************************************************************************
632 * mixerSetControlDetails [WINMM.@]
634 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
635 DWORD fdwDetails)
637 LPWINE_MIXER lpwm;
638 UINT uRet = MMSYSERR_NOERROR;
640 TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails);
642 if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR)
643 return uRet;
645 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcdA,
646 fdwDetails, TRUE);
649 /**************************************************************************
650 * mixerMessage [WINMM.@]
652 UINT WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
654 LPWINE_MLD wmld;
656 TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n",
657 (DWORD)hmix, uMsg, dwParam1, dwParam2);
659 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
660 return MMSYSERR_INVALHANDLE;
662 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE);
665 /**************************************************************************
666 * auxGetNumDevs [WINMM.@]
668 UINT WINAPI auxGetNumDevs(void)
670 return MMDRV_GetNum(MMDRV_AUX);
673 /**************************************************************************
674 * auxGetDevCapsW [WINMM.@]
676 UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
678 AUXCAPSA acA;
679 UINT ret;
681 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
683 ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA));
684 if (ret == MMSYSERR_NOERROR) {
685 AUXCAPSW acW;
686 acW.wMid = acA.wMid;
687 acW.wPid = acA.wPid;
688 acW.vDriverVersion = acA.vDriverVersion;
689 MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, acW.szPname,
690 sizeof(acW.szPname)/sizeof(WCHAR) );
691 acW.wTechnology = acA.wTechnology;
692 acW.dwSupport = acA.dwSupport;
693 memcpy(lpCaps, &acW, min(uSize, sizeof(acW)));
695 return ret;
698 /**************************************************************************
699 * auxGetDevCapsA [WINMM.@]
701 UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
703 LPWINE_MLD wmld;
705 TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize);
707 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
709 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
710 return MMSYSERR_INVALHANDLE;
711 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
714 /**************************************************************************
715 * auxGetVolume [WINMM.@]
717 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
719 LPWINE_MLD wmld;
721 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
723 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
724 return MMSYSERR_INVALHANDLE;
725 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE);
728 /**************************************************************************
729 * auxSetVolume [WINMM.@]
731 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
733 LPWINE_MLD wmld;
735 TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume);
737 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
738 return MMSYSERR_INVALHANDLE;
739 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE);
742 /**************************************************************************
743 * auxOutMessage [WINMM.@]
745 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2)
747 LPWINE_MLD wmld;
749 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
750 return MMSYSERR_INVALHANDLE;
752 return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE);
755 /**************************************************************************
756 * mciGetErrorStringW [WINMM.@]
758 BOOL WINAPI mciGetErrorStringW(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength)
760 char bufstr[MAXERRORLENGTH];
761 BOOL ret = mciGetErrorStringA(wError, bufstr, MAXERRORLENGTH);
763 MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength );
764 return ret;
767 /**************************************************************************
768 * mciGetErrorStringA [WINMM.@]
770 BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength)
772 BOOL ret = FALSE;
774 if (lpstrBuffer != NULL && uLength > 0 &&
775 dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
777 if (LoadStringA(WINMM_IData->hWinMM32Instance,
778 dwError, lpstrBuffer, uLength) > 0) {
779 ret = TRUE;
782 return ret;
785 /**************************************************************************
786 * mciDriverNotify [WINMM.@]
788 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, MCIDEVICEID wDevID, UINT wStatus)
790 TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
792 return PostMessageW(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
795 /**************************************************************************
796 * mciGetDriverData [WINMM.@]
798 DWORD WINAPI mciGetDriverData(MCIDEVICEID uDeviceID)
800 LPWINE_MCIDRIVER wmd;
802 TRACE("(%04x)\n", uDeviceID);
804 wmd = MCI_GetDriver(uDeviceID);
806 if (!wmd) {
807 WARN("Bad uDeviceID\n");
808 return 0L;
811 return wmd->dwPrivate;
814 /**************************************************************************
815 * mciSetDriverData [WINMM.@]
817 BOOL WINAPI mciSetDriverData(MCIDEVICEID uDeviceID, DWORD data)
819 LPWINE_MCIDRIVER wmd;
821 TRACE("(%04x, %08lx)\n", uDeviceID, data);
823 wmd = MCI_GetDriver(uDeviceID);
825 if (!wmd) {
826 WARN("Bad uDeviceID\n");
827 return FALSE;
830 wmd->dwPrivate = data;
831 return TRUE;
834 /**************************************************************************
835 * mciSendCommandA [WINMM.@]
837 DWORD WINAPI mciSendCommandA(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
839 DWORD dwRet;
841 TRACE("(%08x, %s, %08lx, %08lx)\n",
842 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
844 dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE);
845 dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
846 TRACE("=> %08lx\n", dwRet);
847 return dwRet;
850 inline static LPSTR strdupWtoA( LPCWSTR str )
852 LPSTR ret;
853 INT len;
855 if (!str) return NULL;
856 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
857 ret = HeapAlloc( GetProcessHeap(), 0, len );
858 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
859 return ret;
862 static int MCI_MapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2)
864 switch(msg)
866 case MCI_CLOSE:
867 case MCI_PLAY:
868 case MCI_SEEK:
869 case MCI_STOP:
870 case MCI_PAUSE:
871 case MCI_GETDEVCAPS:
872 case MCI_SPIN:
873 case MCI_SET:
874 case MCI_STEP:
875 case MCI_RECORD:
876 case MCI_BREAK:
877 case MCI_SOUND:
878 case MCI_STATUS:
879 case MCI_CUE:
880 case MCI_REALIZE:
881 case MCI_PUT:
882 case MCI_WHERE:
883 case MCI_FREEZE:
884 case MCI_UNFREEZE:
885 case MCI_CUT:
886 case MCI_COPY:
887 case MCI_PASTE:
888 case MCI_UPDATE:
889 case MCI_RESUME:
890 case MCI_DELETE:
891 return 0;
893 case MCI_OPEN:
895 MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*dwParam2;
896 MCI_OPEN_PARMSA *mci_openA;
897 DWORD_PTR *ptr;
899 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_openA) + sizeof(DWORD_PTR));
900 if (!ptr) return -1;
902 *ptr++ = *dwParam2; /* save the previous pointer */
903 *dwParam2 = (DWORD_PTR)ptr;
904 mci_openA = (MCI_OPEN_PARMSA *)ptr;
906 if (dwParam1 & MCI_NOTIFY)
907 mci_openA->dwCallback = mci_openW->dwCallback;
909 if (dwParam1 & MCI_OPEN_TYPE)
911 if (dwParam1 & MCI_OPEN_TYPE_ID)
912 mci_openA->lpstrDeviceType = (LPSTR)mci_openW->lpstrDeviceType;
913 else
914 mci_openA->lpstrDeviceType = strdupWtoA(mci_openW->lpstrDeviceType);
916 if (dwParam1 & MCI_OPEN_ELEMENT)
918 if (dwParam1 & MCI_OPEN_ELEMENT_ID)
919 mci_openA->lpstrElementName = (LPSTR)mci_openW->lpstrElementName;
920 else
921 mci_openA->lpstrElementName = strdupWtoA(mci_openW->lpstrElementName);
923 if (dwParam1 & MCI_OPEN_ALIAS)
924 mci_openA->lpstrAlias = strdupWtoA(mci_openW->lpstrAlias);
926 return 1;
928 case MCI_WINDOW:
929 if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
931 MCI_ANIM_WINDOW_PARMSW *mci_windowW = (MCI_ANIM_WINDOW_PARMSW *)*dwParam2;
932 MCI_ANIM_WINDOW_PARMSA *mci_windowA;
934 mci_windowA = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowA));
935 if (!mci_windowA) return -1;
937 *dwParam2 = (DWORD_PTR)mci_windowA;
939 mci_windowA->lpstrText = strdupWtoA(mci_windowW->lpstrText);
941 if (dwParam1 & MCI_NOTIFY)
942 mci_windowA->dwCallback = mci_windowW->dwCallback;
943 if (dwParam1 & MCI_ANIM_WINDOW_HWND)
944 mci_windowA->hWnd = mci_windowW->hWnd;
945 if (dwParam1 & MCI_ANIM_WINDOW_STATE)
946 mci_windowA->nCmdShow = mci_windowW->nCmdShow;
948 return 1;
950 return 0;
952 case MCI_SYSINFO:
954 MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*dwParam2;
955 MCI_SYSINFO_PARMSA *mci_sysinfoA;
956 DWORD_PTR *ptr;
958 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoA) + sizeof(DWORD_PTR));
959 if (!ptr) return -1;
961 *ptr++ = *dwParam2; /* save the previous pointer */
962 *dwParam2 = (DWORD_PTR)ptr;
963 mci_sysinfoA = (MCI_SYSINFO_PARMSA *)ptr;
965 if (dwParam1 & MCI_NOTIFY)
966 mci_sysinfoA->dwCallback = mci_sysinfoW->dwCallback;
968 mci_sysinfoA->dwRetSize = mci_sysinfoW->dwRetSize; /* FIXME */
969 mci_sysinfoA->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoA->dwRetSize);
971 return 1;
974 case MCI_INFO:
975 case MCI_SAVE:
976 case MCI_LOAD:
977 case MCI_ESCAPE:
978 default:
979 FIXME("Message 0x%04x needs translation\n", msg);
980 return -1;
982 return 0;
985 static DWORD MCI_UnmapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2,
986 DWORD result)
988 switch(msg)
990 case MCI_OPEN:
992 DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
993 MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*ptr;
994 MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA *)(ptr + 1);
996 mci_openW->wDeviceID = mci_openA->wDeviceID;
998 if (dwParam1 & MCI_OPEN_TYPE)
1000 if (!(dwParam1 & MCI_OPEN_TYPE_ID))
1001 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrDeviceType);
1003 if (dwParam1 & MCI_OPEN_ELEMENT)
1005 if (!(dwParam1 & MCI_OPEN_ELEMENT_ID))
1006 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrElementName);
1008 if (dwParam1 & MCI_OPEN_ALIAS)
1009 HeapFree(GetProcessHeap(), 0, mci_openA->lpstrAlias);
1010 HeapFree(GetProcessHeap(), 0, ptr);
1012 break;
1014 case MCI_WINDOW:
1015 if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
1017 MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)dwParam2;
1019 HeapFree(GetProcessHeap(), 0, (void *)mci_windowA->lpstrText);
1020 HeapFree(GetProcessHeap(), 0, mci_windowA);
1022 break;
1024 case MCI_SYSINFO:
1026 DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
1027 MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*ptr;
1028 MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)(ptr + 1);
1030 if (!result)
1032 mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber;
1033 mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType;
1034 MultiByteToWideChar(CP_ACP, 0,
1035 mci_sysinfoA->lpstrReturn, mci_sysinfoA->dwRetSize,
1036 mci_sysinfoW->lpstrReturn, mci_sysinfoW->dwRetSize);
1039 HeapFree(GetProcessHeap(), 0, mci_sysinfoA->lpstrReturn);
1040 HeapFree(GetProcessHeap(), 0, ptr);
1042 break;
1044 default:
1045 FIXME("Message 0x%04x needs unmapping\n", msg);
1046 break;
1049 return result;
1053 /**************************************************************************
1054 * mciSendCommandW [WINMM.@]
1056 * FIXME: we should do the things other way around, but since our
1057 * MM subsystem is not unicode aware...
1059 DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1061 DWORD ret;
1062 int mapped;
1064 TRACE("(%08x, %s, %08lx, %08lx)\n",
1065 wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
1067 mapped = MCI_MapMsgWtoA(wMsg, dwParam1, &dwParam2);
1068 if (mapped == -1)
1070 FIXME("message %04x mapping failed\n", wMsg);
1071 return MMSYSERR_NOMEM;
1073 ret = mciSendCommandA(wDevID, wMsg, dwParam1, dwParam2);
1074 if (mapped)
1075 MCI_UnmapMsgWtoA(wMsg, dwParam1, dwParam2, ret);
1076 return ret;
1079 /**************************************************************************
1080 * mciGetDeviceIDA [WINMM.@]
1082 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
1084 return MCI_GetDriverFromString(lpstrName);
1087 /**************************************************************************
1088 * mciGetDeviceIDW [WINMM.@]
1090 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
1092 LPSTR lpstrName = NULL;
1093 UINT ret;
1094 INT len;
1096 if (lpwstrName) {
1097 len = WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, NULL, 0, NULL, NULL );
1098 lpstrName = HeapAlloc( GetProcessHeap(), 0, len );
1099 if (lpstrName) WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, lpstrName, len, NULL, NULL );
1101 ret = MCI_GetDriverFromString(lpstrName);
1102 HeapFree(GetProcessHeap(), 0, lpstrName);
1103 return ret;
1106 /**************************************************************************
1107 * MCI_DefYieldProc [internal]
1109 UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
1111 INT16 ret;
1113 TRACE("(0x%04x, 0x%08lx)\n", wDevID, data);
1115 if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
1116 (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
1117 MyUserYield();
1118 ret = 0;
1119 } else {
1120 MSG msg;
1122 msg.hwnd = HWND_32(HIWORD(data));
1123 while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
1124 ret = -1;
1126 return ret;
1129 /**************************************************************************
1130 * mciSetYieldProc [WINMM.@]
1132 BOOL WINAPI mciSetYieldProc(MCIDEVICEID uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
1134 LPWINE_MCIDRIVER wmd;
1136 TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData);
1138 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1139 WARN("Bad uDeviceID\n");
1140 return FALSE;
1143 wmd->lpfnYieldProc = fpYieldProc;
1144 wmd->dwYieldData = dwYieldData;
1145 wmd->bIs32 = TRUE;
1147 return TRUE;
1150 /**************************************************************************
1151 * mciGetDeviceIDFromElementIDW [WINMM.@]
1153 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
1155 /* FIXME: that's rather strange, there is no
1156 * mciGetDeviceIDFromElementID32A in winmm.spec
1158 FIXME("(%lu, %p) stub\n", dwElementID, lpstrType);
1159 return 0;
1162 /**************************************************************************
1163 * mciGetYieldProc [WINMM.@]
1165 YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID uDeviceID, DWORD* lpdwYieldData)
1167 LPWINE_MCIDRIVER wmd;
1169 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
1171 if (!(wmd = MCI_GetDriver(uDeviceID))) {
1172 WARN("Bad uDeviceID\n");
1173 return NULL;
1175 if (!wmd->lpfnYieldProc) {
1176 WARN("No proc set\n");
1177 return NULL;
1179 if (!wmd->bIs32) {
1180 WARN("Proc is 32 bit\n");
1181 return NULL;
1183 return wmd->lpfnYieldProc;
1186 /**************************************************************************
1187 * mciGetCreatorTask [WINMM.@]
1189 HTASK WINAPI mciGetCreatorTask(MCIDEVICEID uDeviceID)
1191 LPWINE_MCIDRIVER wmd;
1192 HTASK ret = 0;
1194 if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
1196 TRACE("(%u) => %p\n", uDeviceID, ret);
1197 return ret;
1200 /**************************************************************************
1201 * mciDriverYield [WINMM.@]
1203 UINT WINAPI mciDriverYield(MCIDEVICEID uDeviceID)
1205 LPWINE_MCIDRIVER wmd;
1206 UINT ret = 0;
1208 TRACE("(%04x)\n", uDeviceID);
1210 if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) {
1211 MyUserYield();
1212 } else {
1213 ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
1216 return ret;
1219 /**************************************************************************
1220 * midiOutGetNumDevs [WINMM.@]
1222 UINT WINAPI midiOutGetNumDevs(void)
1224 return MMDRV_GetNum(MMDRV_MIDIOUT);
1227 /**************************************************************************
1228 * midiOutGetDevCapsW [WINMM.@]
1230 UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps,
1231 UINT uSize)
1233 MIDIOUTCAPSA mocA;
1234 UINT ret;
1236 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1238 ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA));
1239 if (ret == MMSYSERR_NOERROR) {
1240 MIDIOUTCAPSW mocW;
1241 mocW.wMid = mocA.wMid;
1242 mocW.wPid = mocA.wPid;
1243 mocW.vDriverVersion = mocA.vDriverVersion;
1244 MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, mocW.szPname,
1245 sizeof(mocW.szPname)/sizeof(WCHAR) );
1246 mocW.wTechnology = mocA.wTechnology;
1247 mocW.wVoices = mocA.wVoices;
1248 mocW.wNotes = mocA.wNotes;
1249 mocW.wChannelMask = mocA.wChannelMask;
1250 mocW.dwSupport = mocA.dwSupport;
1251 memcpy(lpCaps, &mocW, min(uSize, sizeof(mocW)));
1253 return ret;
1256 /**************************************************************************
1257 * midiOutGetDevCapsA [WINMM.@]
1259 UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps,
1260 UINT uSize)
1262 LPWINE_MLD wmld;
1264 TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize);
1266 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1268 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
1269 return MMSYSERR_INVALHANDLE;
1271 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
1274 /**************************************************************************
1275 * MIDI_GetErrorText [internal]
1277 static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
1279 UINT16 ret = MMSYSERR_BADERRNUM;
1281 if (lpText == NULL) {
1282 ret = MMSYSERR_INVALPARAM;
1283 } else if (uSize == 0) {
1284 ret = MMSYSERR_NOERROR;
1285 } else if (
1286 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
1287 * a warning for the test was always true */
1288 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
1289 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) {
1291 if (LoadStringA(WINMM_IData->hWinMM32Instance,
1292 uError, lpText, uSize) > 0) {
1293 ret = MMSYSERR_NOERROR;
1296 return ret;
1299 /**************************************************************************
1300 * midiOutGetErrorTextA [WINMM.@]
1302 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1304 return MIDI_GetErrorText(uError, lpText, uSize);
1307 /**************************************************************************
1308 * midiOutGetErrorTextW [WINMM.@]
1310 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1312 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1313 UINT ret;
1315 ret = MIDI_GetErrorText(uError, xstr, uSize);
1316 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1317 HeapFree(GetProcessHeap(), 0, xstr);
1318 return ret;
1321 /**************************************************************************
1322 * MIDI_OutAlloc [internal]
1324 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback,
1325 LPDWORD lpdwInstance, LPDWORD lpdwFlags,
1326 DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32)
1328 HANDLE hMidiOut;
1329 LPWINE_MIDI lpwm;
1330 UINT size;
1332 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
1334 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
1335 lpdwCallback, lpdwInstance, bFrom32);
1337 if (lphMidiOut != NULL)
1338 *lphMidiOut = hMidiOut;
1340 if (lpwm) {
1341 lpwm->mod.hMidi = (HMIDI) hMidiOut;
1342 lpwm->mod.dwCallback = *lpdwCallback;
1343 lpwm->mod.dwInstance = *lpdwInstance;
1344 lpwm->mod.dnDevNode = 0;
1345 lpwm->mod.cIds = cIDs;
1346 if (cIDs)
1347 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
1349 return lpwm;
1352 UINT MIDI_OutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback,
1353 DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32)
1355 HMIDIOUT hMidiOut;
1356 LPWINE_MIDI lpwm;
1357 UINT dwRet = 0;
1359 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1360 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
1362 if (lphMidiOut != NULL) *lphMidiOut = 0;
1364 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags,
1365 0, NULL, bFrom32);
1367 if (lpwm == NULL)
1368 return MMSYSERR_NOMEM;
1370 lpwm->mld.uDeviceID = uDeviceID;
1372 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1374 if (dwRet != MMSYSERR_NOERROR) {
1375 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
1376 hMidiOut = 0;
1379 if (lphMidiOut) *lphMidiOut = hMidiOut;
1380 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
1382 return dwRet;
1385 /**************************************************************************
1386 * midiOutOpen [WINMM.@]
1388 UINT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
1389 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
1391 return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1394 /**************************************************************************
1395 * midiOutClose [WINMM.@]
1397 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
1399 LPWINE_MLD wmld;
1400 DWORD dwRet;
1402 TRACE("(%p)\n", hMidiOut);
1404 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1405 return MMSYSERR_INVALHANDLE;
1407 dwRet = MMDRV_Close(wmld, MODM_CLOSE);
1408 MMDRV_Free(hMidiOut, wmld);
1410 return dwRet;
1413 /**************************************************************************
1414 * midiOutPrepareHeader [WINMM.@]
1416 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
1417 MIDIHDR* lpMidiOutHdr, UINT uSize)
1419 LPWINE_MLD wmld;
1421 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1423 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
1424 return MMSYSERR_INVALPARAM;
1426 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1427 return MMSYSERR_INVALHANDLE;
1429 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1432 /**************************************************************************
1433 * midiOutUnprepareHeader [WINMM.@]
1435 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
1436 MIDIHDR* lpMidiOutHdr, UINT uSize)
1438 LPWINE_MLD wmld;
1440 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1442 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
1443 return MMSYSERR_INVALPARAM;
1445 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
1446 return MMSYSERR_NOERROR;
1449 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1450 return MMSYSERR_INVALHANDLE;
1452 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1455 /**************************************************************************
1456 * midiOutShortMsg [WINMM.@]
1458 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
1460 LPWINE_MLD wmld;
1462 TRACE("(%p, %08lX)\n", hMidiOut, dwMsg);
1464 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1465 return MMSYSERR_INVALHANDLE;
1467 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE);
1470 /**************************************************************************
1471 * midiOutLongMsg [WINMM.@]
1473 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
1474 MIDIHDR* lpMidiOutHdr, UINT uSize)
1476 LPWINE_MLD wmld;
1478 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
1480 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1481 return MMSYSERR_INVALHANDLE;
1483 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE);
1486 /**************************************************************************
1487 * midiOutReset [WINMM.@]
1489 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
1491 LPWINE_MLD wmld;
1493 TRACE("(%p)\n", hMidiOut);
1495 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1496 return MMSYSERR_INVALHANDLE;
1498 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE);
1501 /**************************************************************************
1502 * midiOutGetVolume [WINMM.@]
1504 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
1506 LPWINE_MLD wmld;
1508 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
1510 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1511 return MMSYSERR_INVALHANDLE;
1513 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE);
1516 /**************************************************************************
1517 * midiOutSetVolume [WINMM.@]
1519 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
1521 LPWINE_MLD wmld;
1523 TRACE("(%p, %ld);\n", hMidiOut, dwVolume);
1525 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
1526 return MMSYSERR_INVALHANDLE;
1528 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE);
1531 /**************************************************************************
1532 * midiOutCachePatches [WINMM.@]
1534 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
1535 WORD* lpwPatchArray, UINT uFlags)
1537 /* not really necessary to support this */
1538 FIXME("not supported yet\n");
1539 return MMSYSERR_NOTSUPPORTED;
1542 /**************************************************************************
1543 * midiOutCacheDrumPatches [WINMM.@]
1545 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
1546 WORD* lpwKeyArray, UINT uFlags)
1548 FIXME("not supported yet\n");
1549 return MMSYSERR_NOTSUPPORTED;
1552 /**************************************************************************
1553 * midiOutGetID [WINMM.@]
1555 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
1557 LPWINE_MLD wmld;
1559 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
1561 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1562 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
1563 return MMSYSERR_INVALHANDLE;
1565 *lpuDeviceID = wmld->uDeviceID;
1566 return MMSYSERR_NOERROR;
1569 /**************************************************************************
1570 * midiOutMessage [WINMM.@]
1572 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
1573 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1575 LPWINE_MLD wmld;
1577 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
1579 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
1580 /* HACK... */
1581 if (uMessage == 0x0001) {
1582 *(LPDWORD)dwParam1 = 1;
1583 return 0;
1585 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
1586 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
1588 return MMSYSERR_INVALHANDLE;
1591 switch (uMessage) {
1592 case MODM_OPEN:
1593 case MODM_CLOSE:
1594 FIXME("can't handle OPEN or CLOSE message!\n");
1595 return MMSYSERR_NOTSUPPORTED;
1597 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1600 /**************************************************************************
1601 * midiInGetNumDevs [WINMM.@]
1603 UINT WINAPI midiInGetNumDevs(void)
1605 return MMDRV_GetNum(MMDRV_MIDIIN);
1608 /**************************************************************************
1609 * midiInGetDevCapsW [WINMM.@]
1611 UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
1613 MIDIINCAPSA micA;
1614 UINT ret;
1616 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1618 ret = midiInGetDevCapsA(uDeviceID, &micA, sizeof(micA));
1619 if (ret == MMSYSERR_NOERROR) {
1620 MIDIINCAPSW micW;
1621 micW.wMid = micA.wMid;
1622 micW.wPid = micA.wPid;
1623 micW.vDriverVersion = micA.vDriverVersion;
1624 MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname,
1625 sizeof(micW.szPname)/sizeof(WCHAR) );
1626 micW.dwSupport = micA.dwSupport;
1627 memcpy(lpCaps, &micW, min(uSize, sizeof(micW)));
1629 return ret;
1632 /**************************************************************************
1633 * midiInGetDevCapsA [WINMM.@]
1635 UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
1637 LPWINE_MLD wmld;
1639 TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize);
1641 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
1643 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
1644 return MMSYSERR_INVALHANDLE;
1646 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
1649 /**************************************************************************
1650 * midiInGetErrorTextW [WINMM.@]
1652 UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
1654 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
1655 UINT ret = MIDI_GetErrorText(uError, xstr, uSize);
1657 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
1658 HeapFree(GetProcessHeap(), 0, xstr);
1659 return ret;
1662 /**************************************************************************
1663 * midiInGetErrorTextA [WINMM.@]
1665 UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
1667 return MIDI_GetErrorText(uError, lpText, uSize);
1670 UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback,
1671 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
1673 HANDLE hMidiIn;
1674 LPWINE_MIDI lpwm;
1675 DWORD dwRet = 0;
1677 TRACE("(%p, %d, %08lX, %08lX, %08lX);\n",
1678 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
1680 if (lphMidiIn != NULL) *lphMidiIn = 0;
1682 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
1683 &dwFlags, &dwCallback, &dwInstance, bFrom32);
1685 if (lpwm == NULL)
1686 return MMSYSERR_NOMEM;
1688 lpwm->mod.hMidi = (HMIDI) hMidiIn;
1689 lpwm->mod.dwCallback = dwCallback;
1690 lpwm->mod.dwInstance = dwInstance;
1692 lpwm->mld.uDeviceID = uDeviceID;
1693 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags);
1695 if (dwRet != MMSYSERR_NOERROR) {
1696 MMDRV_Free(hMidiIn, &lpwm->mld);
1697 hMidiIn = 0;
1699 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
1700 TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn);
1702 return dwRet;
1705 /**************************************************************************
1706 * midiInOpen [WINMM.@]
1708 UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
1709 DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
1711 return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE);
1714 /**************************************************************************
1715 * midiInClose [WINMM.@]
1717 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
1719 LPWINE_MLD wmld;
1720 DWORD dwRet;
1722 TRACE("(%p)\n", hMidiIn);
1724 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1725 return MMSYSERR_INVALHANDLE;
1727 dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
1728 MMDRV_Free(hMidiIn, wmld);
1729 return dwRet;
1732 /**************************************************************************
1733 * midiInPrepareHeader [WINMM.@]
1735 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
1736 MIDIHDR* lpMidiInHdr, UINT uSize)
1738 LPWINE_MLD wmld;
1740 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1742 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
1743 return MMSYSERR_INVALPARAM;
1745 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1746 return MMSYSERR_INVALHANDLE;
1748 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1751 /**************************************************************************
1752 * midiInUnprepareHeader [WINMM.@]
1754 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
1755 MIDIHDR* lpMidiInHdr, UINT uSize)
1757 LPWINE_MLD wmld;
1759 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1761 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
1762 return MMSYSERR_INVALPARAM;
1764 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
1765 return MMSYSERR_NOERROR;
1768 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1769 return MMSYSERR_INVALHANDLE;
1771 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1774 /**************************************************************************
1775 * midiInAddBuffer [WINMM.@]
1777 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
1778 MIDIHDR* lpMidiInHdr, UINT uSize)
1780 LPWINE_MLD wmld;
1782 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
1784 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1785 return MMSYSERR_INVALHANDLE;
1787 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize, TRUE);
1790 /**************************************************************************
1791 * midiInStart [WINMM.@]
1793 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
1795 LPWINE_MLD wmld;
1797 TRACE("(%p)\n", hMidiIn);
1799 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1800 return MMSYSERR_INVALHANDLE;
1802 return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE);
1805 /**************************************************************************
1806 * midiInStop [WINMM.@]
1808 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
1810 LPWINE_MLD wmld;
1812 TRACE("(%p)\n", hMidiIn);
1814 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1815 return MMSYSERR_INVALHANDLE;
1817 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE);
1820 /**************************************************************************
1821 * midiInReset [WINMM.@]
1823 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
1825 LPWINE_MLD wmld;
1827 TRACE("(%p)\n", hMidiIn);
1829 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1830 return MMSYSERR_INVALHANDLE;
1832 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE);
1835 /**************************************************************************
1836 * midiInGetID [WINMM.@]
1838 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
1840 LPWINE_MLD wmld;
1842 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
1844 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
1846 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
1847 return MMSYSERR_INVALHANDLE;
1849 *lpuDeviceID = wmld->uDeviceID;
1851 return MMSYSERR_NOERROR;
1854 /**************************************************************************
1855 * midiInMessage [WINMM.@]
1857 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
1858 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1860 LPWINE_MLD wmld;
1862 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
1864 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
1865 return MMSYSERR_INVALHANDLE;
1867 switch (uMessage) {
1868 case MIDM_OPEN:
1869 case MIDM_CLOSE:
1870 FIXME("can't handle OPEN or CLOSE message!\n");
1871 return MMSYSERR_NOTSUPPORTED;
1873 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
1876 typedef struct WINE_MIDIStream {
1877 HMIDIOUT hDevice;
1878 HANDLE hThread;
1879 DWORD dwThreadID;
1880 DWORD dwTempo;
1881 DWORD dwTimeDiv;
1882 DWORD dwPositionMS;
1883 DWORD dwPulses;
1884 DWORD dwStartTicks;
1885 WORD wFlags;
1886 HANDLE hEvent;
1887 LPMIDIHDR lpMidiHdr;
1888 } WINE_MIDIStream;
1890 #define WINE_MSM_HEADER (WM_USER+0)
1891 #define WINE_MSM_STOP (WM_USER+1)
1893 /**************************************************************************
1894 * MMSYSTEM_GetMidiStream [internal]
1896 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
1898 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
1900 if (lplpwm)
1901 *lplpwm = lpwm;
1903 if (lpwm == NULL) {
1904 return FALSE;
1907 *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID;
1909 return *lpMidiStrm != NULL;
1912 /**************************************************************************
1913 * MMSYSTEM_MidiStream_Convert [internal]
1915 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
1917 DWORD ret = 0;
1919 if (lpMidiStrm->dwTimeDiv == 0) {
1920 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
1921 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
1922 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */
1923 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */
1924 ret = (pulse * 1000) / (nf * nsf);
1925 } else {
1926 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
1927 (double)lpMidiStrm->dwTimeDiv);
1930 return ret;
1933 /**************************************************************************
1934 * MMSYSTEM_MidiStream_MessageHandler [internal]
1936 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
1938 LPMIDIHDR lpMidiHdr;
1939 LPMIDIHDR* lpmh;
1940 LPBYTE lpData;
1942 switch (msg->message) {
1943 case WM_QUIT:
1944 SetEvent(lpMidiStrm->hEvent);
1945 return FALSE;
1946 case WINE_MSM_STOP:
1947 TRACE("STOP\n");
1948 /* this is not quite what MS doc says... */
1949 midiOutReset(lpMidiStrm->hDevice);
1950 /* empty list of already submitted buffers */
1951 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) {
1952 lpMidiHdr->dwFlags |= MHDR_DONE;
1953 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1955 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
1956 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
1957 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
1959 lpMidiStrm->lpMidiHdr = 0;
1960 SetEvent(lpMidiStrm->hEvent);
1961 break;
1962 case WINE_MSM_HEADER:
1963 /* sets initial tick count for first MIDIHDR */
1964 if (!lpMidiStrm->dwStartTicks)
1965 lpMidiStrm->dwStartTicks = GetTickCount();
1967 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
1968 * by native mcimidi, it doesn't look like a correct one".
1969 * this trick allows to throw it away... but I don't like it.
1970 * It looks like part of the file I'm trying to play and definitively looks
1971 * like raw midi content
1972 * I'd really like to understand why native mcimidi sends it. Perhaps a bad
1973 * synchronization issue where native mcimidi is still processing raw MIDI
1974 * content before generating MIDIEVENTs ?
1976 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
1977 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
1978 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
1979 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
1980 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
1981 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
1982 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
1983 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
1984 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
1985 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
1986 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
1987 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
1988 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
1989 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
1990 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
1991 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
1992 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
1994 lpMidiHdr = (LPMIDIHDR)msg->lParam;
1995 lpData = lpMidiHdr->lpData;
1996 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n",
1997 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
1998 (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
1999 lpMidiHdr->dwFlags, msg->wParam);
2000 #if 0
2001 /* dumps content of lpMidiHdr->lpData
2002 * FIXME: there should be a debug routine somewhere that already does this
2003 * I hate spreading this type of shit all around the code
2005 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
2006 DWORD i;
2007 BYTE ch;
2009 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
2010 printf("%02x ", lpData[dwToGo + i]);
2011 for (; i < 16; i++)
2012 printf(" ");
2013 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
2014 ch = lpData[dwToGo + i];
2015 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
2017 printf("\n");
2019 #endif
2020 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
2021 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
2022 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) {
2023 FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n",
2024 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
2025 ((LPMIDIEVENT)lpData)->dwStreamID);
2026 lpMidiHdr->dwFlags |= MHDR_DONE;
2027 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2029 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2030 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
2031 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
2032 break;
2035 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext));
2036 *lpmh = lpMidiHdr;
2037 lpMidiHdr = (LPMIDIHDR)msg->lParam;
2038 lpMidiHdr->lpNext = 0;
2039 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
2040 lpMidiHdr->dwFlags &= ~MHDR_DONE;
2041 lpMidiHdr->dwOffset = 0;
2043 break;
2044 default:
2045 FIXME("Unknown message %d\n", msg->message);
2046 break;
2048 return TRUE;
2051 /**************************************************************************
2052 * MMSYSTEM_MidiStream_Player [internal]
2054 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt)
2056 WINE_MIDIStream* lpMidiStrm = pmt;
2057 WINE_MIDI* lpwm;
2058 MSG msg;
2059 DWORD dwToGo;
2060 DWORD dwCurrTC;
2061 LPMIDIHDR lpMidiHdr;
2062 LPMIDIEVENT me;
2063 LPBYTE lpData = 0;
2065 TRACE("(%p)!\n", lpMidiStrm);
2067 if (!lpMidiStrm ||
2068 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
2069 goto the_end;
2071 /* force thread's queue creation */
2072 /* Used to be InitThreadInput16(0, 5); */
2073 /* but following works also with hack in midiStreamOpen */
2074 PeekMessageA(&msg, 0, 0, 0, 0);
2076 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
2077 SetEvent(lpMidiStrm->hEvent);
2078 TRACE("Ready to go 1\n");
2079 /* thread is started in paused mode */
2080 SuspendThread(lpMidiStrm->hThread);
2081 TRACE("Ready to go 2\n");
2083 lpMidiStrm->dwStartTicks = 0;
2084 lpMidiStrm->dwPulses = 0;
2086 lpMidiStrm->lpMidiHdr = 0;
2088 for (;;) {
2089 lpMidiHdr = lpMidiStrm->lpMidiHdr;
2090 if (!lpMidiHdr) {
2091 /* for first message, block until one arrives, then process all that are available */
2092 GetMessageA(&msg, 0, 0, 0);
2093 do {
2094 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
2095 goto the_end;
2096 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
2097 lpData = 0;
2098 continue;
2101 if (!lpData)
2102 lpData = lpMidiHdr->lpData;
2104 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
2106 /* do we have to wait ? */
2107 if (me->dwDeltaTime) {
2108 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
2109 lpMidiStrm->dwPulses += me->dwDeltaTime;
2111 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
2113 TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime);
2114 while ((dwCurrTC = GetTickCount()) < dwToGo) {
2115 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
2116 /* got a message, handle it */
2117 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
2118 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
2119 goto the_end;
2121 lpData = 0;
2122 } else {
2123 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
2124 break;
2128 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
2129 case MEVT_COMMENT:
2130 FIXME("NIY: MEVT_COMMENT\n");
2131 /* do nothing, skip bytes */
2132 break;
2133 case MEVT_LONGMSG:
2134 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
2135 break;
2136 case MEVT_NOP:
2137 break;
2138 case MEVT_SHORTMSG:
2139 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
2140 break;
2141 case MEVT_TEMPO:
2142 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
2143 break;
2144 case MEVT_VERSION:
2145 break;
2146 default:
2147 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
2148 break;
2150 if (me->dwEvent & MEVT_F_CALLBACK) {
2151 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2152 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
2153 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
2155 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
2156 if (me->dwEvent & MEVT_F_LONG)
2157 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
2158 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
2159 /* done with this header */
2160 lpMidiHdr->dwFlags |= MHDR_DONE;
2161 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
2163 lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
2164 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
2165 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
2166 lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L);
2167 lpData = 0;
2170 the_end:
2171 TRACE("End of thread\n");
2172 ExitThread(0);
2173 return 0; /* for removing the warning, never executed */
2176 /**************************************************************************
2177 * MMSYSTEM_MidiStream_PostMessage [internal]
2179 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
2181 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
2182 DWORD count;
2184 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
2185 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
2186 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
2187 } else {
2188 WARN("bad PostThreadMessageA\n");
2189 return FALSE;
2191 return TRUE;
2194 /**************************************************************************
2195 * midiStreamClose [WINMM.@]
2197 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
2199 WINE_MIDIStream* lpMidiStrm;
2201 TRACE("(%p)!\n", hMidiStrm);
2203 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
2204 return MMSYSERR_INVALHANDLE;
2206 midiStreamStop(hMidiStrm);
2207 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
2208 HeapFree(GetProcessHeap(), 0, lpMidiStrm);
2209 CloseHandle(lpMidiStrm->hEvent);
2211 return midiOutClose((HMIDIOUT)hMidiStrm);
2214 /**************************************************************************
2215 * MMSYSTEM_MidiStream_Open [internal]
2217 MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi,
2218 DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen,
2219 BOOL bFrom32)
2221 WINE_MIDIStream* lpMidiStrm;
2222 MMRESULT ret;
2223 MIDIOPENSTRMID mosm;
2224 LPWINE_MIDI lpwm;
2225 HMIDIOUT hMidiOut;
2227 TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n",
2228 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
2230 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
2231 return MMSYSERR_INVALPARAM;
2233 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
2234 if (!lpMidiStrm)
2235 return MMSYSERR_NOMEM;
2237 lpMidiStrm->dwTempo = 500000;
2238 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/
2239 lpMidiStrm->dwPositionMS = 0;
2241 mosm.dwStreamID = (DWORD)lpMidiStrm;
2242 /* FIXME: the correct value is not allocated yet for MAPPER */
2243 mosm.wDeviceID = *lpuDeviceID;
2244 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32);
2245 lpMidiStrm->hDevice = hMidiOut;
2246 if (lphMidiStrm)
2247 *lphMidiStrm = (HMIDISTRM)hMidiOut;
2249 lpwm->mld.uDeviceID = *lpuDeviceID;
2251 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen);
2252 lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2253 lpMidiStrm->wFlags = HIWORD(fdwOpen);
2255 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
2256 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
2258 if (!lpMidiStrm->hThread) {
2259 midiStreamClose((HMIDISTRM)hMidiOut);
2260 return MMSYSERR_NOMEM;
2263 /* wait for thread to have started, and for its queue to be created */
2265 DWORD count;
2267 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
2268 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
2269 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
2271 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
2272 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
2273 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
2276 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
2277 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
2278 return ret;
2281 /**************************************************************************
2282 * midiStreamOpen [WINMM.@]
2284 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
2285 DWORD cMidi, DWORD dwCallback,
2286 DWORD dwInstance, DWORD fdwOpen)
2288 return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback,
2289 dwInstance, fdwOpen, TRUE);
2292 /**************************************************************************
2293 * midiStreamOut [WINMM.@]
2295 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
2296 UINT cbMidiHdr)
2298 WINE_MIDIStream* lpMidiStrm;
2299 DWORD ret = MMSYSERR_NOERROR;
2301 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
2303 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2304 ret = MMSYSERR_INVALHANDLE;
2305 } else if (!lpMidiHdr) {
2306 ret = MMSYSERR_INVALPARAM;
2307 } else {
2308 if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
2309 WINE_MSM_HEADER, cbMidiHdr,
2310 (DWORD)lpMidiHdr)) {
2311 WARN("bad PostThreadMessageA\n");
2312 ret = MMSYSERR_ERROR;
2315 return ret;
2318 /**************************************************************************
2319 * midiStreamPause [WINMM.@]
2321 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
2323 WINE_MIDIStream* lpMidiStrm;
2324 DWORD ret = MMSYSERR_NOERROR;
2326 TRACE("(%p)!\n", hMidiStrm);
2328 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2329 ret = MMSYSERR_INVALHANDLE;
2330 } else {
2331 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
2332 WARN("bad Suspend (%ld)\n", GetLastError());
2333 ret = MMSYSERR_ERROR;
2336 return ret;
2339 /**************************************************************************
2340 * midiStreamPosition [WINMM.@]
2342 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
2344 WINE_MIDIStream* lpMidiStrm;
2345 DWORD ret = MMSYSERR_NOERROR;
2347 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
2349 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2350 ret = MMSYSERR_INVALHANDLE;
2351 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
2352 ret = MMSYSERR_INVALPARAM;
2353 } else {
2354 switch (lpMMT->wType) {
2355 case TIME_MS:
2356 lpMMT->u.ms = lpMidiStrm->dwPositionMS;
2357 TRACE("=> %ld ms\n", lpMMT->u.ms);
2358 break;
2359 case TIME_TICKS:
2360 lpMMT->u.ticks = lpMidiStrm->dwPulses;
2361 TRACE("=> %ld ticks\n", lpMMT->u.ticks);
2362 break;
2363 default:
2364 WARN("Unsupported time type %d\n", lpMMT->wType);
2365 lpMMT->wType = TIME_MS;
2366 ret = MMSYSERR_INVALPARAM;
2367 break;
2370 return ret;
2373 /**************************************************************************
2374 * midiStreamProperty [WINMM.@]
2376 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
2378 WINE_MIDIStream* lpMidiStrm;
2379 MMRESULT ret = MMSYSERR_NOERROR;
2381 TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty);
2383 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2384 ret = MMSYSERR_INVALHANDLE;
2385 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
2386 ret = MMSYSERR_INVALPARAM;
2387 } else if (dwProperty & MIDIPROP_TEMPO) {
2388 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData;
2390 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
2391 ret = MMSYSERR_INVALPARAM;
2392 } else if (dwProperty & MIDIPROP_SET) {
2393 lpMidiStrm->dwTempo = mpt->dwTempo;
2394 TRACE("Setting tempo to %ld\n", mpt->dwTempo);
2395 } else if (dwProperty & MIDIPROP_GET) {
2396 mpt->dwTempo = lpMidiStrm->dwTempo;
2397 TRACE("Getting tempo <= %ld\n", mpt->dwTempo);
2399 } else if (dwProperty & MIDIPROP_TIMEDIV) {
2400 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData;
2402 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
2403 ret = MMSYSERR_INVALPARAM;
2404 } else if (dwProperty & MIDIPROP_SET) {
2405 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
2406 TRACE("Setting time div to %ld\n", mptd->dwTimeDiv);
2407 } else if (dwProperty & MIDIPROP_GET) {
2408 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
2409 TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv);
2411 } else {
2412 ret = MMSYSERR_INVALPARAM;
2415 return ret;
2418 /**************************************************************************
2419 * midiStreamRestart [WINMM.@]
2421 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
2423 WINE_MIDIStream* lpMidiStrm;
2424 MMRESULT ret = MMSYSERR_NOERROR;
2426 TRACE("(%p)!\n", hMidiStrm);
2428 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2429 ret = MMSYSERR_INVALHANDLE;
2430 } else {
2431 DWORD ret;
2433 /* since we increase the thread suspend count on each midiStreamPause
2434 * there may be a need for several midiStreamResume
2436 do {
2437 ret = ResumeThread(lpMidiStrm->hThread);
2438 } while (ret != 0xFFFFFFFF && ret != 0);
2439 if (ret == 0xFFFFFFFF) {
2440 WARN("bad Resume (%ld)\n", GetLastError());
2441 ret = MMSYSERR_ERROR;
2442 } else {
2443 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
2446 return ret;
2449 /**************************************************************************
2450 * midiStreamStop [WINMM.@]
2452 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
2454 WINE_MIDIStream* lpMidiStrm;
2455 MMRESULT ret = MMSYSERR_NOERROR;
2457 TRACE("(%p)!\n", hMidiStrm);
2459 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
2460 ret = MMSYSERR_INVALHANDLE;
2461 } else {
2462 /* in case stream has been paused... FIXME is the current state correct ? */
2463 midiStreamRestart(hMidiStrm);
2464 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
2466 return ret;
2469 UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
2470 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
2471 DWORD dwInstance, DWORD dwFlags, BOOL bFrom32)
2473 HANDLE handle;
2474 LPWINE_MLD wmld;
2475 DWORD dwRet = MMSYSERR_NOERROR;
2476 WAVEOPENDESC wod;
2478 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n",
2479 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
2480 dwInstance, dwFlags, bFrom32?32:16);
2482 if (dwFlags & WAVE_FORMAT_QUERY)
2483 TRACE("WAVE_FORMAT_QUERY requested !\n");
2485 if (lpFormat == NULL) {
2486 WARN("bad format\n");
2487 return WAVERR_BADFORMAT;
2490 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) {
2491 WARN("invalid parameter\n");
2492 return MMSYSERR_INVALPARAM;
2495 /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */
2496 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u\n",
2497 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
2498 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample);
2500 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
2501 &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL) {
2502 WARN("no memory\n");
2503 return MMSYSERR_NOMEM;
2506 wod.hWave = handle;
2507 wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */
2508 wod.dwCallback = dwCallback;
2509 wod.dwInstance = dwInstance;
2510 wod.dnDevNode = 0L;
2512 TRACE("cb=%08lx\n", wod.dwCallback);
2514 for (;;) {
2515 if (dwFlags & WAVE_MAPPED) {
2516 wod.uMappedDeviceID = uDeviceID;
2517 uDeviceID = WAVE_MAPPER;
2518 } else {
2519 wod.uMappedDeviceID = -1;
2521 wmld->uDeviceID = uDeviceID;
2523 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
2524 (DWORD)&wod, dwFlags);
2526 TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet));
2527 if (dwRet != WAVERR_BADFORMAT ||
2528 ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break;
2529 /* if we ask for a format which isn't supported by the physical driver,
2530 * let's try to map it through the wave mapper (except, if we already tried
2531 * or user didn't allow us to use acm codecs or the device is already the mapper)
2533 dwFlags |= WAVE_MAPPED;
2534 /* we shall loop only one */
2537 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
2538 MMDRV_Free(handle, wmld);
2539 handle = 0;
2542 if (lphndl != NULL) *lphndl = handle;
2543 TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle);
2545 return dwRet;
2548 /**************************************************************************
2549 * waveOutGetNumDevs [WINMM.@]
2551 UINT WINAPI waveOutGetNumDevs(void)
2553 return MMDRV_GetNum(MMDRV_WAVEOUT);
2556 /**************************************************************************
2557 * waveOutGetDevCapsA [WINMM.@]
2559 UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps,
2560 UINT uSize)
2562 LPWINE_MLD wmld;
2564 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
2566 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2568 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
2569 return MMSYSERR_BADDEVICEID;
2571 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
2575 /**************************************************************************
2576 * waveOutGetDevCapsW [WINMM.@]
2578 UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps,
2579 UINT uSize)
2581 WAVEOUTCAPSA wocA;
2582 UINT ret;
2584 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2586 ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA));
2587 if (ret == MMSYSERR_NOERROR) {
2588 WAVEOUTCAPSW wocW;
2589 wocW.wMid = wocA.wMid;
2590 wocW.wPid = wocA.wPid;
2591 wocW.vDriverVersion = wocA.vDriverVersion;
2592 MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, wocW.szPname,
2593 sizeof(wocW.szPname)/sizeof(WCHAR) );
2594 wocW.dwFormats = wocA.dwFormats;
2595 wocW.wChannels = wocA.wChannels;
2596 wocW.dwSupport = wocA.dwSupport;
2597 memcpy(lpCaps, &wocW, min(uSize, sizeof(wocW)));
2599 return ret;
2602 /**************************************************************************
2603 * WAVE_GetErrorText [internal]
2605 static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize)
2607 UINT16 ret = MMSYSERR_BADERRNUM;
2609 if (lpText == NULL) {
2610 ret = MMSYSERR_INVALPARAM;
2611 } else if (uSize == 0) {
2612 ret = MMSYSERR_NOERROR;
2613 } else if (
2614 /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit
2615 * a warning for the test was always true */
2616 (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) ||
2617 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) {
2619 if (LoadStringA(WINMM_IData->hWinMM32Instance,
2620 uError, lpText, uSize) > 0) {
2621 ret = MMSYSERR_NOERROR;
2624 return ret;
2627 /**************************************************************************
2628 * waveOutGetErrorTextA [WINMM.@]
2630 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
2632 return WAVE_GetErrorText(uError, lpText, uSize);
2635 /**************************************************************************
2636 * waveOutGetErrorTextW [WINMM.@]
2638 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
2640 LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize);
2641 UINT ret = WAVE_GetErrorText(uError, xstr, uSize);
2643 MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize );
2644 HeapFree(GetProcessHeap(), 0, xstr);
2645 return ret;
2648 /**************************************************************************
2649 * waveOutOpen [WINMM.@]
2650 * All the args/structs have the same layout as the win16 equivalents
2652 UINT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
2653 const LPWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
2654 DWORD_PTR dwInstance, DWORD dwFlags)
2656 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
2657 dwCallback, dwInstance, dwFlags, TRUE);
2660 /**************************************************************************
2661 * waveOutClose [WINMM.@]
2663 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
2665 LPWINE_MLD wmld;
2666 DWORD dwRet;
2668 TRACE("(%p)\n", hWaveOut);
2670 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2671 return MMSYSERR_INVALHANDLE;
2673 dwRet = MMDRV_Close(wmld, WODM_CLOSE);
2674 if (dwRet != WAVERR_STILLPLAYING)
2675 MMDRV_Free(hWaveOut, wmld);
2677 return dwRet;
2680 /**************************************************************************
2681 * waveOutPrepareHeader [WINMM.@]
2683 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
2684 WAVEHDR* lpWaveOutHdr, UINT uSize)
2686 LPWINE_MLD wmld;
2687 UINT result;
2689 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2691 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
2692 return MMSYSERR_INVALPARAM;
2694 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2695 return MMSYSERR_INVALHANDLE;
2697 if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr,
2698 uSize, TRUE)) != MMSYSERR_NOTSUPPORTED)
2699 return result;
2701 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
2702 return WAVERR_STILLPLAYING;
2704 lpWaveOutHdr->dwFlags |= WHDR_PREPARED;
2705 lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
2707 return MMSYSERR_NOERROR;
2710 /**************************************************************************
2711 * waveOutUnprepareHeader [WINMM.@]
2713 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
2714 LPWAVEHDR lpWaveOutHdr, UINT uSize)
2716 LPWINE_MLD wmld;
2717 UINT result;
2719 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2721 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
2722 return MMSYSERR_INVALPARAM;
2724 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
2725 return MMSYSERR_NOERROR;
2728 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2729 return MMSYSERR_INVALHANDLE;
2731 if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr,
2732 uSize, TRUE)) != MMSYSERR_NOTSUPPORTED)
2733 return result;
2735 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
2736 return WAVERR_STILLPLAYING;
2738 lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED;
2739 lpWaveOutHdr->dwFlags |= WHDR_DONE;
2741 return MMSYSERR_NOERROR;
2744 /**************************************************************************
2745 * waveOutWrite [WINMM.@]
2747 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
2748 UINT uSize)
2750 LPWINE_MLD wmld;
2752 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
2754 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2755 return MMSYSERR_INVALHANDLE;
2757 return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize, TRUE);
2760 /**************************************************************************
2761 * waveOutBreakLoop [WINMM.@]
2763 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
2765 LPWINE_MLD wmld;
2767 TRACE("(%p);\n", hWaveOut);
2769 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2770 return MMSYSERR_INVALHANDLE;
2771 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE);
2774 /**************************************************************************
2775 * waveOutPause [WINMM.@]
2777 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
2779 LPWINE_MLD wmld;
2781 TRACE("(%p);\n", hWaveOut);
2783 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2784 return MMSYSERR_INVALHANDLE;
2785 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE);
2788 /**************************************************************************
2789 * waveOutReset [WINMM.@]
2791 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
2793 LPWINE_MLD wmld;
2795 TRACE("(%p);\n", hWaveOut);
2797 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2798 return MMSYSERR_INVALHANDLE;
2799 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE);
2802 /**************************************************************************
2803 * waveOutRestart [WINMM.@]
2805 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
2807 LPWINE_MLD wmld;
2809 TRACE("(%p);\n", hWaveOut);
2811 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2812 return MMSYSERR_INVALHANDLE;
2813 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE);
2816 /**************************************************************************
2817 * waveOutGetPosition [WINMM.@]
2819 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
2820 UINT uSize)
2822 LPWINE_MLD wmld;
2824 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
2826 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2827 return MMSYSERR_INVALHANDLE;
2829 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE);
2832 /**************************************************************************
2833 * waveOutGetPitch [WINMM.@]
2835 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
2837 LPWINE_MLD wmld;
2839 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2841 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2842 return MMSYSERR_INVALHANDLE;
2843 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L, TRUE);
2846 /**************************************************************************
2847 * waveOutSetPitch [WINMM.@]
2849 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
2851 LPWINE_MLD wmld;
2853 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2855 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2856 return MMSYSERR_INVALHANDLE;
2857 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE);
2860 /**************************************************************************
2861 * waveOutGetPlaybackRate [WINMM.@]
2863 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
2865 LPWINE_MLD wmld;
2867 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2869 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2870 return MMSYSERR_INVALHANDLE;
2871 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L, TRUE);
2874 /**************************************************************************
2875 * waveOutSetPlaybackRate [WINMM.@]
2877 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
2879 LPWINE_MLD wmld;
2881 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw);
2883 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2884 return MMSYSERR_INVALHANDLE;
2885 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE);
2888 /**************************************************************************
2889 * waveOutGetVolume [WINMM.@]
2891 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
2893 LPWINE_MLD wmld;
2895 TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw);
2897 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2898 return MMSYSERR_INVALHANDLE;
2900 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L, TRUE);
2903 /**************************************************************************
2904 * waveOutSetVolume [WINMM.@]
2906 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
2908 LPWINE_MLD wmld;
2910 TRACE("(%p, %08lx);\n", hWaveOut, dw);
2912 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
2913 return MMSYSERR_INVALHANDLE;
2915 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE);
2918 /**************************************************************************
2919 * waveOutGetID [WINMM.@]
2921 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
2923 LPWINE_MLD wmld;
2925 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
2927 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
2929 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
2930 return MMSYSERR_INVALHANDLE;
2932 *lpuDeviceID = wmld->uDeviceID;
2933 return 0;
2936 /**************************************************************************
2937 * waveOutMessage [WINMM.@]
2939 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
2940 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
2942 LPWINE_MLD wmld;
2944 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
2946 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
2947 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
2948 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
2950 WARN("invalid handle\n");
2951 return MMSYSERR_INVALHANDLE;
2954 /* from M$ KB */
2955 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) {
2956 WARN("invalid parameter\n");
2957 return MMSYSERR_INVALPARAM;
2960 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
2963 /**************************************************************************
2964 * waveInGetNumDevs [WINMM.@]
2966 UINT WINAPI waveInGetNumDevs(void)
2968 return MMDRV_GetNum(MMDRV_WAVEIN);
2971 /**************************************************************************
2972 * waveInGetDevCapsW [WINMM.@]
2974 UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
2976 WAVEINCAPSA wicA;
2977 UINT ret;
2979 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
2981 ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA));
2982 if (ret == MMSYSERR_NOERROR) {
2983 WAVEINCAPSW wicW;
2984 wicW.wMid = wicA.wMid;
2985 wicW.wPid = wicA.wPid;
2986 wicW.vDriverVersion = wicA.vDriverVersion;
2987 MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, wicW.szPname,
2988 sizeof(wicW.szPname)/sizeof(WCHAR) );
2989 wicW.dwFormats = wicA.dwFormats;
2990 wicW.wChannels = wicA.wChannels;
2991 memcpy(lpCaps, &wicW, min(uSize, sizeof(wicW)));
2993 return ret;
2996 /**************************************************************************
2997 * waveInGetDevCapsA [WINMM.@]
2999 UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
3001 LPWINE_MLD wmld;
3003 TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize);
3005 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
3007 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
3008 return MMSYSERR_BADDEVICEID;
3010 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE);
3013 /**************************************************************************
3014 * waveInGetErrorTextA [WINMM.@]
3016 UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
3018 return WAVE_GetErrorText(uError, lpText, uSize);
3021 /**************************************************************************
3022 * waveInGetErrorTextW [WINMM.@]
3024 UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
3026 LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize);
3027 UINT ret = WAVE_GetErrorText(uError, txt, uSize);
3029 MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize );
3030 HeapFree(GetProcessHeap(), 0, txt);
3031 return ret;
3034 /**************************************************************************
3035 * waveInOpen [WINMM.@]
3037 UINT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
3038 const LPWAVEFORMATEX lpFormat, DWORD dwCallback,
3039 DWORD dwInstance, DWORD dwFlags)
3041 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
3042 dwCallback, dwInstance, dwFlags, TRUE);
3045 /**************************************************************************
3046 * waveInClose [WINMM.@]
3048 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
3050 LPWINE_MLD wmld;
3051 DWORD dwRet;
3053 TRACE("(%p)\n", hWaveIn);
3055 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3056 return MMSYSERR_INVALHANDLE;
3058 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE);
3059 if (dwRet != WAVERR_STILLPLAYING)
3060 MMDRV_Free(hWaveIn, wmld);
3061 return dwRet;
3064 /**************************************************************************
3065 * waveInPrepareHeader [WINMM.@]
3067 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
3068 UINT uSize)
3070 LPWINE_MLD wmld;
3072 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3074 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
3075 return MMSYSERR_INVALPARAM;
3077 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3078 return MMSYSERR_INVALHANDLE;
3080 lpWaveInHdr->dwBytesRecorded = 0;
3082 return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3085 /**************************************************************************
3086 * waveInUnprepareHeader [WINMM.@]
3088 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
3089 UINT uSize)
3091 LPWINE_MLD wmld;
3093 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3095 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
3096 return MMSYSERR_INVALPARAM;
3098 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) {
3099 return MMSYSERR_NOERROR;
3102 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3103 return MMSYSERR_INVALHANDLE;
3105 return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3108 /**************************************************************************
3109 * waveInAddBuffer [WINMM.@]
3111 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
3112 WAVEHDR* lpWaveInHdr, UINT uSize)
3114 LPWINE_MLD wmld;
3116 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
3118 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
3119 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3120 return MMSYSERR_INVALHANDLE;
3122 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize, TRUE);
3125 /**************************************************************************
3126 * waveInReset [WINMM.@]
3128 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
3130 LPWINE_MLD wmld;
3132 TRACE("(%p);\n", hWaveIn);
3134 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3135 return MMSYSERR_INVALHANDLE;
3137 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE);
3140 /**************************************************************************
3141 * waveInStart [WINMM.@]
3143 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
3145 LPWINE_MLD wmld;
3147 TRACE("(%p);\n", hWaveIn);
3149 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3150 return MMSYSERR_INVALHANDLE;
3152 return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE);
3155 /**************************************************************************
3156 * waveInStop [WINMM.@]
3158 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
3160 LPWINE_MLD wmld;
3162 TRACE("(%p);\n", hWaveIn);
3164 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3165 return MMSYSERR_INVALHANDLE;
3167 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE);
3170 /**************************************************************************
3171 * waveInGetPosition [WINMM.@]
3173 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
3174 UINT uSize)
3176 LPWINE_MLD wmld;
3178 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
3180 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3181 return MMSYSERR_INVALHANDLE;
3183 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE);
3186 /**************************************************************************
3187 * waveInGetID [WINMM.@]
3189 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
3191 LPWINE_MLD wmld;
3193 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
3195 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
3197 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
3198 return MMSYSERR_INVALHANDLE;
3200 *lpuDeviceID = wmld->uDeviceID;
3201 return MMSYSERR_NOERROR;
3204 /**************************************************************************
3205 * waveInMessage [WINMM.@]
3207 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
3208 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
3210 LPWINE_MLD wmld;
3212 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
3214 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
3215 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
3216 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
3218 return MMSYSERR_INVALHANDLE;
3221 /* from M$ KB */
3222 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
3223 return MMSYSERR_INVALPARAM;
3226 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE);
3229 struct mm_starter
3231 LPTASKCALLBACK cb;
3232 DWORD client;
3233 HANDLE event;
3236 static DWORD WINAPI mmTaskRun(void* pmt)
3238 struct mm_starter mms;
3240 memcpy(&mms, pmt, sizeof(struct mm_starter));
3241 HeapFree(GetProcessHeap(), 0, pmt);
3242 mms.cb(mms.client);
3243 if (mms.event) SetEvent(mms.event);
3244 return 0;
3247 /******************************************************************
3248 * mmTaskCreate (WINMM.@)
3250 MMRESULT WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD client)
3252 HANDLE hThread;
3253 HANDLE hEvent = 0;
3254 struct mm_starter *mms;
3256 mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter));
3257 if (mms == NULL) return TASKERR_OUTOFMEMORY;
3259 mms->cb = cb;
3260 mms->client = client;
3261 if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
3262 mms->event = hEvent;
3264 hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL);
3265 if (!hThread) {
3266 HeapFree(GetProcessHeap(), 0, mms);
3267 if (hEvent) CloseHandle(hEvent);
3268 return TASKERR_OUTOFMEMORY;
3270 if (ph) *ph = hEvent;
3271 CloseHandle(hThread);
3272 return 0;
3275 /******************************************************************
3276 * mmTaskBlock (WINMM.@)
3278 void WINAPI mmTaskBlock(HANDLE tid)
3280 MSG msg;
3284 GetMessageA(&msg, 0, 0, 0);
3285 if (msg.hwnd) DispatchMessageA(&msg);
3286 } while (msg.message != WM_USER);
3289 /******************************************************************
3290 * mmTaskSignal (WINMM.@)
3292 BOOL WINAPI mmTaskSignal(HANDLE tid)
3294 return PostThreadMessageW((DWORD)tid, WM_USER, 0, 0);
3297 /******************************************************************
3298 * mmTaskYield (WINMM.@)
3300 void WINAPI mmTaskYield(void) {}
3302 /******************************************************************
3303 * mmGetCurrentTask (WINMM.@)
3305 HANDLE WINAPI mmGetCurrentTask(void)
3307 return (HANDLE)GetCurrentThreadId();