1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */ 2 3 /* 4 * WINMM functions 5 * 6 * Copyright 1993 Martin Ayotte 7 * 1998-2002 Eric Pouech 8 * 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. 13 * 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. 18 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24 /* 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 29 */ 30 31 /* TODO 32 * + it seems that some programs check what's installed in 33 * registry against the value returned by drivers. Wine is 34 * currently broken regarding this point. 35 * + check thread-safeness for MMSYSTEM and WINMM entry points 36 * + unicode entry points are badly supported (would require 37 * moving 32 bit drivers as Unicode as they are supposed to be) 38 * + allow joystick and timer external calls as we do for wave, 39 * midi, mixer and aux 40 */ 41 42 #include "winemm.h" 43 44 WINE_DEFAULT_DEBUG_CHANNEL(winmm); 45 46 /* ======================================================================== 47 * G L O B A L S E T T I N G S 48 * ========================================================================*/ 49 50 HINSTANCE hWinMM32Instance; 51 HANDLE psLastEvent; 52 53 CRITICAL_SECTION WINMM_cs; 54 55 /************************************************************************** 56 * WINMM_CreateIData [internal] 57 */ 58 static BOOL WINMM_CreateIData(HINSTANCE hInstDLL) 59 { 60 hWinMM32Instance = hInstDLL; 61 psLastEvent = CreateEventW(NULL, TRUE, FALSE, NULL); 62 InitializeCriticalSection(&WINMM_cs); 63 return TRUE; 64 } 65 66 /************************************************************************** 67 * WINMM_DeleteIData [internal] 68 */ 69 static void WINMM_DeleteIData(void) 70 { 71 TIME_MMTimeStop(); 72 73 /* FIXME: should also free content and resources allocated 74 * inside WINMM_IData */ 75 CloseHandle(psLastEvent); 76 DeleteCriticalSection(&WINMM_cs); 77 } 78 79 /****************************************************************** 80 * WINMM_LoadMMSystem 81 * 82 */ 83 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR); 84 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR); 85 86 BOOL WINMM_CheckForMMSystem(void) 87 { 88 /* 0 is not checked yet, -1 is not present, 1 is present */ 89 static int loaded /* = 0 */; 90 91 if (loaded == 0) 92 { 93 HANDLE h = GetModuleHandleA("kernel32"); 94 loaded = -1; 95 if (h) 96 { 97 pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16"); 98 pLoadLibrary16 = (void*)GetProcAddress(h, (LPCSTR)35); /* ordinal for LoadLibrary16 */ 99 if (pGetModuleHandle16 && pLoadLibrary16 && 100 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL"))) 101 loaded = 1; 102 } 103 } 104 return loaded > 0; 105 } 106 107 /****************************************************************** 108 * WINMM_ErrorToString 109 */ 110 const char* WINMM_ErrorToString(MMRESULT error) 111 { 112 #define ERR_TO_STR(dev) case dev: return #dev 113 static char unknown[32]; 114 switch (error) { 115 ERR_TO_STR(MMSYSERR_NOERROR); 116 ERR_TO_STR(MMSYSERR_ERROR); 117 ERR_TO_STR(MMSYSERR_BADDEVICEID); 118 ERR_TO_STR(MMSYSERR_NOTENABLED); 119 ERR_TO_STR(MMSYSERR_ALLOCATED); 120 ERR_TO_STR(MMSYSERR_INVALHANDLE); 121 ERR_TO_STR(MMSYSERR_NODRIVER); 122 ERR_TO_STR(MMSYSERR_NOMEM); 123 ERR_TO_STR(MMSYSERR_NOTSUPPORTED); 124 ERR_TO_STR(MMSYSERR_BADERRNUM); 125 ERR_TO_STR(MMSYSERR_INVALFLAG); 126 ERR_TO_STR(MMSYSERR_INVALPARAM); 127 ERR_TO_STR(MMSYSERR_HANDLEBUSY); 128 ERR_TO_STR(MMSYSERR_INVALIDALIAS); 129 ERR_TO_STR(MMSYSERR_BADDB); 130 ERR_TO_STR(MMSYSERR_KEYNOTFOUND); 131 ERR_TO_STR(MMSYSERR_READERROR); 132 ERR_TO_STR(MMSYSERR_WRITEERROR); 133 ERR_TO_STR(MMSYSERR_DELETEERROR); 134 ERR_TO_STR(MMSYSERR_VALNOTFOUND); 135 ERR_TO_STR(MMSYSERR_NODRIVERCB); 136 ERR_TO_STR(WAVERR_BADFORMAT); 137 ERR_TO_STR(WAVERR_STILLPLAYING); 138 ERR_TO_STR(WAVERR_UNPREPARED); 139 ERR_TO_STR(WAVERR_SYNC); 140 ERR_TO_STR(MIDIERR_INVALIDSETUP); 141 ERR_TO_STR(MIDIERR_NODEVICE); 142 ERR_TO_STR(MIDIERR_STILLPLAYING); 143 ERR_TO_STR(MIDIERR_UNPREPARED); 144 } 145 sprintf(unknown, "Unknown(0x%08x)", error); 146 return unknown; 147 #undef ERR_TO_STR 148 } 149 150 /************************************************************************** 151 * DllMain (WINMM.init) 152 * 153 * WINMM DLL entry point 154 * 155 */ 156 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad) 157 { 158 TRACE("%p 0x%x %p\n", hInstDLL, fdwReason, fImpLoad); 159 160 switch (fdwReason) { 161 case DLL_PROCESS_ATTACH: 162 DisableThreadLibraryCalls(hInstDLL); 163 164 if (!WINMM_CreateIData(hInstDLL)) 165 return FALSE; 166 if (!MMDRV_Init()) { 167 WINMM_DeleteIData(); 168 return FALSE; 169 } 170 break; 171 case DLL_PROCESS_DETACH: 172 /* close all opened MCI drivers */ 173 MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L); 174 MMDRV_Exit(); 175 /* There's no guarantee the drivers haven't already been unloaded on 176 * process shutdown. 177 */ 178 if (!fImpLoad) 179 { 180 /* now unload all remaining drivers... */ 181 DRIVER_UnloadAll(); 182 } 183 184 WINMM_DeleteIData(); 185 break; 186 } 187 return TRUE; 188 } 189 190 /************************************************************************** 191 * WINMM_CheckCallback [internal] 192 */ 193 MMRESULT WINMM_CheckCallback(DWORD_PTR dwCallback, DWORD fdwOpen, BOOL mixer) 194 { 195 switch (fdwOpen & CALLBACK_TYPEMASK) { 196 case CALLBACK_NULL: /* dwCallback need not be NULL */ 197 break; 198 case CALLBACK_WINDOW: 199 if (dwCallback && !IsWindow((HWND)dwCallback)) 200 return MMSYSERR_INVALPARAM; 201 break; 202 203 case CALLBACK_FUNCTION: 204 /* a NULL cb is acceptable since w2k, MMSYSERR_INVALPARAM earlier */ 205 if (mixer) 206 return MMSYSERR_INVALFLAG; /* since w2k, MMSYSERR_NOTSUPPORTED earlier */ 207 break; 208 case CALLBACK_THREAD: 209 case CALLBACK_EVENT: 210 if (mixer) /* FIXME: mixer supports THREAD+EVENT since w2k */ 211 return MMSYSERR_NOTSUPPORTED; /* w9X */ 212 break; 213 default: 214 WARN("Unknown callback type %d\n", HIWORD(fdwOpen)); 215 } 216 return MMSYSERR_NOERROR; 217 } 218 219 /************************************************************************** 220 * Mixer devices. New to Win95 221 */ 222 223 /************************************************************************** 224 * find out the real mixer ID depending on hmix (depends on dwFlags) 225 */ 226 static UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm) 227 { 228 LPWINE_MIXER lpwm = NULL; 229 UINT uRet = MMSYSERR_NOERROR; 230 231 switch (dwFlags & 0xF0000000ul) { 232 case MIXER_OBJECTF_MIXER: 233 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE); 234 break; 235 case MIXER_OBJECTF_HMIXER: 236 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE); 237 break; 238 case MIXER_OBJECTF_WAVEOUT: 239 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER); 240 break; 241 case MIXER_OBJECTF_HWAVEOUT: 242 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER); 243 break; 244 case MIXER_OBJECTF_WAVEIN: 245 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER); 246 break; 247 case MIXER_OBJECTF_HWAVEIN: 248 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER); 249 break; 250 case MIXER_OBJECTF_MIDIOUT: 251 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER); 252 break; 253 case MIXER_OBJECTF_HMIDIOUT: 254 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER); 255 break; 256 case MIXER_OBJECTF_MIDIIN: 257 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER); 258 break; 259 case MIXER_OBJECTF_HMIDIIN: 260 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER); 261 break; 262 case MIXER_OBJECTF_AUX: 263 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER); 264 break; 265 default: 266 WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul); 267 lpwm = 0; 268 uRet = MMSYSERR_INVALFLAG; 269 break; 270 } 271 *lplpwm = lpwm; 272 if (lpwm == 0 && uRet == MMSYSERR_NOERROR) 273 uRet = MMSYSERR_INVALPARAM; 274 return uRet; 275 } 276 277 /************************************************************************** 278 * mixerGetNumDevs [WINMM.@] 279 */ 280 UINT WINAPI mixerGetNumDevs(void) 281 { 282 return MMDRV_GetNum(MMDRV_MIXER); 283 } 284 285 /************************************************************************** 286 * mixerGetDevCapsA [WINMM.@] 287 */ 288 UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize) 289 { 290 MIXERCAPSW micW; 291 UINT ret; 292 293 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 294 295 ret = mixerGetDevCapsW(uDeviceID, &micW, sizeof(micW)); 296 297 if (ret == MMSYSERR_NOERROR) { 298 MIXERCAPSA micA; 299 micA.wMid = micW.wMid; 300 micA.wPid = micW.wPid; 301 micA.vDriverVersion = micW.vDriverVersion; 302 WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, 303 sizeof(micA.szPname), NULL, NULL ); 304 micA.fdwSupport = micW.fdwSupport; 305 micA.cDestinations = micW.cDestinations; 306 memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); 307 } 308 return ret; 309 } 310 311 /************************************************************************** 312 * mixerGetDevCapsW [WINMM.@] 313 */ 314 UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize) 315 { 316 LPWINE_MLD wmld; 317 318 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 319 320 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL) 321 return MMSYSERR_BADDEVICEID; 322 323 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 324 } 325 326 static void CALLBACK MIXER_WCallback(HMIXEROBJ hmx, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam, DWORD_PTR param2) 327 { 328 HWND hWnd = (HWND)dwInstance; 329 330 if (!dwInstance) 331 return; 332 333 PostMessageW(hWnd, uMsg, (WPARAM)hmx, (LPARAM)dwParam); 334 } 335 336 /************************************************************************** 337 * mixerOpen [WINMM.@] 338 */ 339 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, 340 DWORD_PTR dwInstance, DWORD fdwOpen) 341 { 342 HANDLE hMix; 343 LPWINE_MLD wmld; 344 DWORD dwRet; 345 MIXEROPENDESC mod; 346 347 TRACE("(%p, %d, %08lx, %08lx, %08x)\n", 348 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen); 349 350 dwRet = WINMM_CheckCallback(dwCallback, fdwOpen, TRUE); 351 if(dwRet != MMSYSERR_NOERROR) 352 return dwRet; 353 354 mod.dwCallback = (DWORD_PTR)MIXER_WCallback; 355 if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_WINDOW) 356 mod.dwInstance = dwCallback; 357 else 358 mod.dwInstance = 0; 359 360 /* We're remapping to CALLBACK_FUNCTION because that's what old winmm is 361 * documented to do when opening the mixer driver. 362 * FIXME: Native supports CALLBACK_EVENT + CALLBACK_THREAD flags since w2k. 363 * FIXME: The non ALSA drivers ignore callback requests - bug. 364 */ 365 366 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen, 367 &dwCallback, &dwInstance); 368 wmld->uDeviceID = uDeviceID; 369 mod.hmx = hMix; 370 371 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD_PTR)&mod, CALLBACK_FUNCTION); 372 373 if (dwRet != MMSYSERR_NOERROR) { 374 MMDRV_Free(hMix, wmld); 375 hMix = 0; 376 } 377 if (lphMix) *lphMix = hMix; 378 TRACE("=> %d hMixer=%p\n", dwRet, hMix); 379 380 return dwRet; 381 } 382 383 /************************************************************************** 384 * mixerClose [WINMM.@] 385 */ 386 UINT WINAPI mixerClose(HMIXER hMix) 387 { 388 LPWINE_MLD wmld; 389 DWORD dwRet; 390 391 TRACE("(%p)\n", hMix); 392 393 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE; 394 395 dwRet = MMDRV_Close(wmld, MXDM_CLOSE); 396 MMDRV_Free(hMix, wmld); 397 398 return dwRet; 399 } 400 401 /************************************************************************** 402 * mixerGetID [WINMM.@] 403 */ 404 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID) 405 { 406 LPWINE_MIXER lpwm; 407 UINT uRet = MMSYSERR_NOERROR; 408 409 TRACE("(%p %p %08x)\n", hmix, lpid, fdwID); 410 411 if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR) 412 return uRet; 413 414 if (lpid) 415 *lpid = lpwm->mld.uDeviceID; 416 417 return uRet; 418 } 419 420 /************************************************************************** 421 * mixerGetControlDetailsW [WINMM.@] 422 */ 423 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW, 424 DWORD fdwDetails) 425 { 426 LPWINE_MIXER lpwm; 427 UINT uRet = MMSYSERR_NOERROR; 428 429 TRACE("(%p, %p, %08x)\n", hmix, lpmcdW, fdwDetails); 430 431 if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) 432 return uRet; 433 434 if (lpmcdW == NULL || lpmcdW->cbStruct != sizeof(*lpmcdW)) 435 return MMSYSERR_INVALPARAM; 436 437 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdW, 438 fdwDetails); 439 } 440 441 /************************************************************************** 442 * mixerGetControlDetailsA [WINMM.@] 443 */ 444 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, 445 DWORD fdwDetails) 446 { 447 DWORD ret = MMSYSERR_NOTENABLED; 448 449 TRACE("(%p, %p, %08x)\n", hmix, lpmcdA, fdwDetails); 450 451 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA)) 452 return MMSYSERR_INVALPARAM; 453 454 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) { 455 case MIXER_GETCONTROLDETAILSF_VALUE: 456 /* can safely use A structure as it is, no string inside */ 457 ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); 458 break; 459 case MIXER_GETCONTROLDETAILSF_LISTTEXT: 460 { 461 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA = lpmcdA->paDetails; 462 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW; 463 int size = max(1, lpmcdA->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTW); 464 unsigned int i; 465 466 if (lpmcdA->u.cMultipleItems != 0) { 467 size *= lpmcdA->u.cMultipleItems; 468 } 469 pDetailsW = HeapAlloc(GetProcessHeap(), 0, size); 470 lpmcdA->paDetails = pDetailsW; 471 lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW); 472 /* set up lpmcd->paDetails */ 473 ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); 474 /* copy from lpmcd->paDetails back to paDetailsW; */ 475 if (ret == MMSYSERR_NOERROR) { 476 for (i = 0; i < lpmcdA->u.cMultipleItems * lpmcdA->cChannels; i++) { 477 pDetailsA->dwParam1 = pDetailsW->dwParam1; 478 pDetailsA->dwParam2 = pDetailsW->dwParam2; 479 WideCharToMultiByte( CP_ACP, 0, pDetailsW->szName, -1, 480 pDetailsA->szName, 481 sizeof(pDetailsA->szName), NULL, NULL ); 482 pDetailsA++; 483 pDetailsW++; 484 } 485 pDetailsA -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; 486 pDetailsW -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; 487 } 488 HeapFree(GetProcessHeap(), 0, pDetailsW); 489 lpmcdA->paDetails = pDetailsA; 490 lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA); 491 } 492 break; 493 default: 494 ERR("Unsupported fdwDetails=0x%08x\n", fdwDetails); 495 } 496 497 return ret; 498 } 499 500 /************************************************************************** 501 * mixerGetLineControlsA [WINMM.@] 502 */ 503 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA, 504 DWORD fdwControls) 505 { 506 MIXERLINECONTROLSW mlcW; 507 DWORD ret; 508 unsigned int i; 509 510 TRACE("(%p, %p, %08x)\n", hmix, lpmlcA, fdwControls); 511 512 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA) || 513 lpmlcA->cbmxctrl != sizeof(MIXERCONTROLA)) 514 return MMSYSERR_INVALPARAM; 515 516 mlcW.cbStruct = sizeof(mlcW); 517 mlcW.dwLineID = lpmlcA->dwLineID; 518 mlcW.u.dwControlID = lpmlcA->u.dwControlID; 519 mlcW.u.dwControlType = lpmlcA->u.dwControlType; 520 521 /* Debugging on Windows shows for MIXER_GETLINECONTROLSF_ONEBYTYPE only, 522 the control count is assumed to be 1 - This is relied upon by a game, 523 "Dynomite Deluze" */ 524 if (MIXER_GETLINECONTROLSF_ONEBYTYPE == (fdwControls & MIXER_GETLINECONTROLSF_QUERYMASK)) { 525 mlcW.cControls = 1; 526 } else { 527 mlcW.cControls = lpmlcA->cControls; 528 } 529 mlcW.cbmxctrl = sizeof(MIXERCONTROLW); 530 mlcW.pamxctrl = HeapAlloc(GetProcessHeap(), 0, 531 mlcW.cControls * mlcW.cbmxctrl); 532 533 ret = mixerGetLineControlsW(hmix, &mlcW, fdwControls); 534 535 if (ret == MMSYSERR_NOERROR) { 536 lpmlcA->dwLineID = mlcW.dwLineID; 537 lpmlcA->u.dwControlID = mlcW.u.dwControlID; 538 lpmlcA->u.dwControlType = mlcW.u.dwControlType; 539 540 for (i = 0; i < mlcW.cControls; i++) { 541 lpmlcA->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLA); 542 lpmlcA->pamxctrl[i].dwControlID = mlcW.pamxctrl[i].dwControlID; 543 lpmlcA->pamxctrl[i].dwControlType = mlcW.pamxctrl[i].dwControlType; 544 lpmlcA->pamxctrl[i].fdwControl = mlcW.pamxctrl[i].fdwControl; 545 lpmlcA->pamxctrl[i].cMultipleItems = mlcW.pamxctrl[i].cMultipleItems; 546 WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szShortName, -1, 547 lpmlcA->pamxctrl[i].szShortName, 548 sizeof(lpmlcA->pamxctrl[i].szShortName), NULL, NULL ); 549 WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szName, -1, 550 lpmlcA->pamxctrl[i].szName, 551 sizeof(lpmlcA->pamxctrl[i].szName), NULL, NULL ); 552 /* sizeof(lpmlcA->pamxctrl[i].Bounds) == 553 * sizeof(mlcW.pamxctrl[i].Bounds) */ 554 memcpy(&lpmlcA->pamxctrl[i].Bounds, &mlcW.pamxctrl[i].Bounds, 555 sizeof(mlcW.pamxctrl[i].Bounds)); 556 /* sizeof(lpmlcA->pamxctrl[i].Metrics) == 557 * sizeof(mlcW.pamxctrl[i].Metrics) */ 558 memcpy(&lpmlcA->pamxctrl[i].Metrics, &mlcW.pamxctrl[i].Metrics, 559 sizeof(mlcW.pamxctrl[i].Metrics)); 560 } 561 } 562 563 HeapFree(GetProcessHeap(), 0, mlcW.pamxctrl); 564 565 return ret; 566 } 567 568 /************************************************************************** 569 * mixerGetLineControlsW [WINMM.@] 570 */ 571 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, 572 DWORD fdwControls) 573 { 574 LPWINE_MIXER lpwm; 575 UINT uRet = MMSYSERR_NOERROR; 576 577 TRACE("(%p, %p, %08x)\n", hmix, lpmlcW, fdwControls); 578 579 if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR) 580 return uRet; 581 582 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW)) 583 return MMSYSERR_INVALPARAM; 584 585 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcW, 586 fdwControls); 587 } 588 589 /************************************************************************** 590 * mixerGetLineInfoW [WINMM.@] 591 */ 592 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo) 593 { 594 LPWINE_MIXER lpwm; 595 UINT uRet = MMSYSERR_NOERROR; 596 597 TRACE("(%p, %p, %08x)\n", hmix, lpmliW, fdwInfo); 598 599 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW)) 600 return MMSYSERR_INVALPARAM; 601 602 if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR) 603 return uRet; 604 605 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW, 606 fdwInfo); 607 } 608 609 /************************************************************************** 610 * mixerGetLineInfoA [WINMM.@] 611 */ 612 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliA, 613 DWORD fdwInfo) 614 { 615 MIXERLINEW mliW; 616 UINT ret; 617 618 TRACE("(%p, %p, %08x)\n", hmix, lpmliA, fdwInfo); 619 620 if (lpmliA == NULL || lpmliA->cbStruct != sizeof(*lpmliA)) 621 return MMSYSERR_INVALPARAM; 622 623 mliW.cbStruct = sizeof(mliW); 624 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { 625 case MIXER_GETLINEINFOF_COMPONENTTYPE: 626 mliW.dwComponentType = lpmliA->dwComponentType; 627 break; 628 case MIXER_GETLINEINFOF_DESTINATION: 629 mliW.dwDestination = lpmliA->dwDestination; 630 break; 631 case MIXER_GETLINEINFOF_LINEID: 632 mliW.dwLineID = lpmliA->dwLineID; 633 break; 634 case MIXER_GETLINEINFOF_SOURCE: 635 mliW.dwDestination = lpmliA->dwDestination; 636 mliW.dwSource = lpmliA->dwSource; 637 break; 638 case MIXER_GETLINEINFOF_TARGETTYPE: 639 mliW.Target.dwType = lpmliA->Target.dwType; 640 mliW.Target.wMid = lpmliA->Target.wMid; 641 mliW.Target.wPid = lpmliA->Target.wPid; 642 mliW.Target.vDriverVersion = lpmliA->Target.vDriverVersion; 643 MultiByteToWideChar( CP_ACP, 0, lpmliA->Target.szPname, -1, mliW.Target.szPname, sizeof(mliW.Target.szPname)/sizeof(WCHAR)); 644 break; 645 default: 646 WARN("Unsupported fdwControls=0x%08x\n", fdwInfo); 647 return MMSYSERR_INVALFLAG; 648 } 649 650 ret = mixerGetLineInfoW(hmix, &mliW, fdwInfo); 651 652 if(ret == MMSYSERR_NOERROR) 653 { 654 lpmliA->dwDestination = mliW.dwDestination; 655 lpmliA->dwSource = mliW.dwSource; 656 lpmliA->dwLineID = mliW.dwLineID; 657 lpmliA->fdwLine = mliW.fdwLine; 658 lpmliA->dwUser = mliW.dwUser; 659 lpmliA->dwComponentType = mliW.dwComponentType; 660 lpmliA->cChannels = mliW.cChannels; 661 lpmliA->cConnections = mliW.cConnections; 662 lpmliA->cControls = mliW.cControls; 663 WideCharToMultiByte( CP_ACP, 0, mliW.szShortName, -1, lpmliA->szShortName, 664 sizeof(lpmliA->szShortName), NULL, NULL); 665 WideCharToMultiByte( CP_ACP, 0, mliW.szName, -1, lpmliA->szName, 666 sizeof(lpmliA->szName), NULL, NULL ); 667 lpmliA->Target.dwType = mliW.Target.dwType; 668 lpmliA->Target.dwDeviceID = mliW.Target.dwDeviceID; 669 lpmliA->Target.wMid = mliW.Target.wMid; 670 lpmliA->Target.wPid = mliW.Target.wPid; 671 lpmliA->Target.vDriverVersion = mliW.Target.vDriverVersion; 672 WideCharToMultiByte( CP_ACP, 0, mliW.Target.szPname, -1, lpmliA->Target.szPname, 673 sizeof(lpmliA->Target.szPname), NULL, NULL ); 674 } 675 return ret; 676 } 677 678 /************************************************************************** 679 * mixerSetControlDetails [WINMM.@] 680 */ 681 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, 682 DWORD fdwDetails) 683 { 684 LPWINE_MIXER lpwm; 685 UINT uRet = MMSYSERR_NOERROR; 686 687 TRACE("(%p, %p, %08x)\n", hmix, lpmcd, fdwDetails); 688 689 if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) 690 return uRet; 691 692 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcd, 693 fdwDetails); 694 } 695 696 /************************************************************************** 697 * mixerMessage [WINMM.@] 698 */ 699 DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 700 { 701 LPWINE_MLD wmld; 702 703 TRACE("(%p, %d, %08lx, %08lx): semi-stub?\n", 704 hmix, uMsg, dwParam1, dwParam2); 705 706 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL) 707 return MMSYSERR_INVALHANDLE; 708 709 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2); 710 } 711 712 /************************************************************************** 713 * auxGetNumDevs [WINMM.@] 714 */ 715 UINT WINAPI auxGetNumDevs(void) 716 { 717 return MMDRV_GetNum(MMDRV_AUX); 718 } 719 720 /************************************************************************** 721 * auxGetDevCapsW [WINMM.@] 722 */ 723 UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize) 724 { 725 LPWINE_MLD wmld; 726 727 TRACE("(%04lX, %p, %d) !\n", uDeviceID, lpCaps, uSize); 728 729 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 730 731 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) 732 return MMSYSERR_INVALHANDLE; 733 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 734 } 735 736 /************************************************************************** 737 * auxGetDevCapsA [WINMM.@] 738 */ 739 UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize) 740 { 741 AUXCAPSW acW; 742 UINT ret; 743 744 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 745 746 ret = auxGetDevCapsW(uDeviceID, &acW, sizeof(acW)); 747 748 if (ret == MMSYSERR_NOERROR) { 749 AUXCAPSA acA; 750 acA.wMid = acW.wMid; 751 acA.wPid = acW.wPid; 752 acA.vDriverVersion = acW.vDriverVersion; 753 WideCharToMultiByte( CP_ACP, 0, acW.szPname, -1, acA.szPname, 754 sizeof(acA.szPname), NULL, NULL ); 755 acA.wTechnology = acW.wTechnology; 756 acA.dwSupport = acW.dwSupport; 757 memcpy(lpCaps, &acA, min(uSize, sizeof(acA))); 758 } 759 return ret; 760 } 761 762 /************************************************************************** 763 * auxGetVolume [WINMM.@] 764 */ 765 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume) 766 { 767 LPWINE_MLD wmld; 768 769 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume); 770 771 if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL) 772 return MMSYSERR_INVALHANDLE; 773 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L); 774 } 775 776 /************************************************************************** 777 * auxSetVolume [WINMM.@] 778 */ 779 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume) 780 { 781 LPWINE_MLD wmld; 782 783 TRACE("(%04X, %u) !\n", uDeviceID, dwVolume); 784 785 if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL) 786 return MMSYSERR_INVALHANDLE; 787 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L); 788 } 789 790 /************************************************************************** 791 * auxOutMessage [WINMM.@] 792 */ 793 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2) 794 { 795 LPWINE_MLD wmld; 796 797 if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL) 798 return MMSYSERR_INVALHANDLE; 799 800 return MMDRV_Message(wmld, uMessage, dw1, dw2); 801 } 802 803 /************************************************************************** 804 * midiOutGetNumDevs [WINMM.@] 805 */ 806 UINT WINAPI midiOutGetNumDevs(void) 807 { 808 return MMDRV_GetNum(MMDRV_MIDIOUT); 809 } 810 811 /************************************************************************** 812 * midiOutGetDevCapsW [WINMM.@] 813 */ 814 UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps, 815 UINT uSize) 816 { 817 LPWINE_MLD wmld; 818 819 TRACE("(%lu, %p, %u);\n", uDeviceID, lpCaps, uSize); 820 821 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 822 823 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL) 824 return MMSYSERR_INVALHANDLE; 825 826 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 827 } 828 829 /************************************************************************** 830 * midiOutGetDevCapsA [WINMM.@] 831 */ 832 UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps, 833 UINT uSize) 834 { 835 MIDIOUTCAPSW mocW; 836 UINT ret; 837 838 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 839 840 ret = midiOutGetDevCapsW(uDeviceID, &mocW, sizeof(mocW)); 841 842 if (ret == MMSYSERR_NOERROR) { 843 MIDIOUTCAPSA mocA; 844 mocA.wMid = mocW.wMid; 845 mocA.wPid = mocW.wPid; 846 mocA.vDriverVersion = mocW.vDriverVersion; 847 WideCharToMultiByte( CP_ACP, 0, mocW.szPname, -1, mocA.szPname, 848 sizeof(mocA.szPname), NULL, NULL ); 849 mocA.wTechnology = mocW.wTechnology; 850 mocA.wVoices = mocW.wVoices; 851 mocA.wNotes = mocW.wNotes; 852 mocA.wChannelMask = mocW.wChannelMask; 853 mocA.dwSupport = mocW.dwSupport; 854 memcpy(lpCaps, &mocA, min(uSize, sizeof(mocA))); 855 } 856 return ret; 857 } 858 859 /************************************************************************** 860 * midiOutGetErrorTextA [WINMM.@] 861 * midiInGetErrorTextA [WINMM.@] 862 */ 863 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) 864 { 865 UINT ret; 866 867 if (lpText == NULL) ret = MMSYSERR_INVALPARAM; 868 else if (uSize == 0) ret = MMSYSERR_NOERROR; 869 else 870 { 871 LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); 872 if (!xstr) ret = MMSYSERR_NOMEM; 873 else 874 { 875 ret = midiOutGetErrorTextW(uError, xstr, uSize); 876 if (ret == MMSYSERR_NOERROR) 877 WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); 878 HeapFree(GetProcessHeap(), 0, xstr); 879 } 880 } 881 return ret; 882 } 883 884 /************************************************************************** 885 * midiOutGetErrorTextW [WINMM.@] 886 * midiInGetErrorTextW [WINMM.@] 887 */ 888 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) 889 { 890 UINT ret = MMSYSERR_BADERRNUM; 891 892 if (lpText == NULL) ret = MMSYSERR_INVALPARAM; 893 else if (uSize == 0) ret = MMSYSERR_NOERROR; 894 else if ( 895 /* test has been removed because MMSYSERR_BASE is 0, and gcc did emit 896 * a warning for the test was always true */ 897 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || 898 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) { 899 if (LoadStringW(hWinMM32Instance, uError, lpText, uSize) > 0) { 900 ret = MMSYSERR_NOERROR; 901 } 902 } 903 return ret; 904 } 905 906 /************************************************************************** 907 * MIDI_OutAlloc [internal] 908 */ 909 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, DWORD_PTR* lpdwCallback, 910 DWORD_PTR* lpdwInstance, LPDWORD lpdwFlags, 911 DWORD cIDs, MIDIOPENSTRMID* lpIDs) 912 { 913 HANDLE hMidiOut; 914 LPWINE_MIDI lpwm; 915 UINT size; 916 917 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID); 918 919 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags, 920 lpdwCallback, lpdwInstance); 921 922 *lphMidiOut = hMidiOut; 923 924 if (lpwm) { 925 lpwm->mod.hMidi = hMidiOut; 926 lpwm->mod.dwCallback = *lpdwCallback; 927 lpwm->mod.dwInstance = *lpdwInstance; 928 lpwm->mod.dnDevNode = 0; 929 lpwm->mod.cIds = cIDs; 930 if (cIDs) 931 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID)); 932 } 933 return lpwm; 934 } 935 936 /************************************************************************** 937 * midiOutOpen [WINMM.@] 938 */ 939 MMRESULT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, 940 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags) 941 { 942 HMIDIOUT hMidiOut; 943 LPWINE_MIDI lpwm; 944 UINT dwRet; 945 946 TRACE("(%p, %d, %08lX, %08lX, %08X);\n", 947 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags); 948 949 if (lphMidiOut != NULL) *lphMidiOut = 0; 950 951 dwRet = WINMM_CheckCallback(dwCallback, dwFlags, FALSE); 952 if (dwRet != MMSYSERR_NOERROR) 953 return dwRet; 954 955 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags, 0, NULL); 956 957 if (lpwm == NULL) 958 return MMSYSERR_NOMEM; 959 960 lpwm->mld.uDeviceID = uDeviceID; 961 962 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD_PTR)&lpwm->mod, dwFlags); 963 964 if (dwRet != MMSYSERR_NOERROR) { 965 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm); 966 hMidiOut = 0; 967 } 968 969 if (lphMidiOut) *lphMidiOut = hMidiOut; 970 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut); 971 972 return dwRet; 973 } 974 975 /************************************************************************** 976 * midiOutClose [WINMM.@] 977 */ 978 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut) 979 { 980 LPWINE_MLD wmld; 981 DWORD dwRet; 982 983 TRACE("(%p)\n", hMidiOut); 984 985 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 986 return MMSYSERR_INVALHANDLE; 987 988 dwRet = MMDRV_Close(wmld, MODM_CLOSE); 989 MMDRV_Free(hMidiOut, wmld); 990 991 return dwRet; 992 } 993 994 /************************************************************************** 995 * midiOutPrepareHeader [WINMM.@] 996 */ 997 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut, 998 MIDIHDR* lpMidiOutHdr, UINT uSize) 999 { 1000 LPWINE_MLD wmld; 1001 1002 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); 1003 1004 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) 1005 return MMSYSERR_INVALPARAM; 1006 1007 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 1008 return MMSYSERR_INVALHANDLE; 1009 1010 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize); 1011 } 1012 1013 /************************************************************************** 1014 * midiOutUnprepareHeader [WINMM.@] 1015 */ 1016 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut, 1017 MIDIHDR* lpMidiOutHdr, UINT uSize) 1018 { 1019 LPWINE_MLD wmld; 1020 1021 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); 1022 1023 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) 1024 return MMSYSERR_INVALPARAM; 1025 1026 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) { 1027 return MMSYSERR_NOERROR; 1028 } 1029 1030 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 1031 return MMSYSERR_INVALHANDLE; 1032 1033 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize); 1034 } 1035 1036 /************************************************************************** 1037 * midiOutShortMsg [WINMM.@] 1038 */ 1039 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg) 1040 { 1041 LPWINE_MLD wmld; 1042 1043 TRACE("(%p, %08X)\n", hMidiOut, dwMsg); 1044 1045 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 1046 return MMSYSERR_INVALHANDLE; 1047 1048 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L); 1049 } 1050 1051 /************************************************************************** 1052 * midiOutLongMsg [WINMM.@] 1053 */ 1054 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut, 1055 MIDIHDR* lpMidiOutHdr, UINT uSize) 1056 { 1057 LPWINE_MLD wmld; 1058 1059 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); 1060 1061 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 1062 return MMSYSERR_INVALHANDLE; 1063 1064 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize); 1065 } 1066 1067 /************************************************************************** 1068 * midiOutReset [WINMM.@] 1069 */ 1070 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut) 1071 { 1072 LPWINE_MLD wmld; 1073 1074 TRACE("(%p)\n", hMidiOut); 1075 1076 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 1077 return MMSYSERR_INVALHANDLE; 1078 1079 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L); 1080 } 1081 1082 /************************************************************************** 1083 * midiOutGetVolume [WINMM.@] 1084 */ 1085 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume) 1086 { 1087 LPWINE_MLD wmld; 1088 1089 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume); 1090 1091 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) 1092 return MMSYSERR_INVALHANDLE; 1093 1094 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L); 1095 } 1096 1097 /************************************************************************** 1098 * midiOutSetVolume [WINMM.@] 1099 */ 1100 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume) 1101 { 1102 LPWINE_MLD wmld; 1103 1104 TRACE("(%p, %d);\n", hMidiOut, dwVolume); 1105 1106 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) 1107 return MMSYSERR_INVALHANDLE; 1108 1109 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L); 1110 } 1111 1112 /************************************************************************** 1113 * midiOutCachePatches [WINMM.@] 1114 */ 1115 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank, 1116 WORD* lpwPatchArray, UINT uFlags) 1117 { 1118 /* not really necessary to support this */ 1119 FIXME("not supported yet\n"); 1120 return MMSYSERR_NOTSUPPORTED; 1121 } 1122 1123 /************************************************************************** 1124 * midiOutCacheDrumPatches [WINMM.@] 1125 */ 1126 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch, 1127 WORD* lpwKeyArray, UINT uFlags) 1128 { 1129 FIXME("not supported yet\n"); 1130 return MMSYSERR_NOTSUPPORTED; 1131 } 1132 1133 /************************************************************************** 1134 * midiOutGetID [WINMM.@] 1135 */ 1136 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID) 1137 { 1138 LPWINE_MLD wmld; 1139 1140 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID); 1141 1142 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; 1143 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 1144 return MMSYSERR_INVALHANDLE; 1145 1146 *lpuDeviceID = wmld->uDeviceID; 1147 return MMSYSERR_NOERROR; 1148 } 1149 1150 /************************************************************************** 1151 * midiOutMessage [WINMM.@] 1152 */ 1153 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, 1154 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 1155 { 1156 LPWINE_MLD wmld; 1157 1158 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2); 1159 1160 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) { 1161 /* HACK... */ 1162 if (uMessage == 0x0001) { 1163 *(LPDWORD)dwParam1 = 1; 1164 return 0; 1165 } 1166 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) { 1167 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); 1168 } 1169 return MMSYSERR_INVALHANDLE; 1170 } 1171 1172 switch (uMessage) { 1173 case MODM_OPEN: 1174 case MODM_CLOSE: 1175 FIXME("can't handle OPEN or CLOSE message!\n"); 1176 return MMSYSERR_NOTSUPPORTED; 1177 } 1178 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); 1179 } 1180 1181 /************************************************************************** 1182 * midiInGetNumDevs [WINMM.@] 1183 */ 1184 UINT WINAPI midiInGetNumDevs(void) 1185 { 1186 return MMDRV_GetNum(MMDRV_MIDIIN); 1187 } 1188 1189 /************************************************************************** 1190 * midiInGetDevCapsW [WINMM.@] 1191 */ 1192 UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize) 1193 { 1194 LPWINE_MLD wmld; 1195 1196 TRACE("(%ld, %p, %d);\n", uDeviceID, lpCaps, uSize); 1197 1198 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 1199 1200 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL) 1201 return MMSYSERR_INVALHANDLE; 1202 1203 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 1204 } 1205 1206 /************************************************************************** 1207 * midiInGetDevCapsA [WINMM.@] 1208 */ 1209 UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize) 1210 { 1211 MIDIINCAPSW micW; 1212 UINT ret; 1213 1214 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 1215 1216 ret = midiInGetDevCapsW(uDeviceID, &micW, sizeof(micW)); 1217 1218 if (ret == MMSYSERR_NOERROR) { 1219 MIDIINCAPSA micA; 1220 micA.wMid = micW.wMid; 1221 micA.wPid = micW.wPid; 1222 micA.vDriverVersion = micW.vDriverVersion; 1223 WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, 1224 sizeof(micA.szPname), NULL, NULL ); 1225 micA.dwSupport = micW.dwSupport; 1226 memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); 1227 } 1228 return ret; 1229 } 1230 1231 /************************************************************************** 1232 * midiInOpen [WINMM.@] 1233 */ 1234 MMRESULT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, 1235 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags) 1236 { 1237 HANDLE hMidiIn; 1238 LPWINE_MIDI lpwm; 1239 DWORD dwRet; 1240 1241 TRACE("(%p, %d, %08lX, %08lX, %08X);\n", 1242 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags); 1243 1244 if (lphMidiIn != NULL) *lphMidiIn = 0; 1245 1246 dwRet = WINMM_CheckCallback(dwCallback, dwFlags, FALSE); 1247 if (dwRet != MMSYSERR_NOERROR) 1248 return dwRet; 1249 1250 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn, 1251 &dwFlags, &dwCallback, &dwInstance); 1252 1253 if (lpwm == NULL) 1254 return MMSYSERR_NOMEM; 1255 1256 lpwm->mod.hMidi = hMidiIn; 1257 lpwm->mod.dwCallback = dwCallback; 1258 lpwm->mod.dwInstance = dwInstance; 1259 1260 lpwm->mld.uDeviceID = uDeviceID; 1261 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD_PTR)&lpwm->mod, dwFlags); 1262 1263 if (dwRet != MMSYSERR_NOERROR) { 1264 MMDRV_Free(hMidiIn, &lpwm->mld); 1265 hMidiIn = 0; 1266 } 1267 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn; 1268 TRACE("=> %d hMidi=%p\n", dwRet, hMidiIn); 1269 1270 return dwRet; 1271 } 1272 1273 /************************************************************************** 1274 * midiInClose [WINMM.@] 1275 */ 1276 UINT WINAPI midiInClose(HMIDIIN hMidiIn) 1277 { 1278 LPWINE_MLD wmld; 1279 DWORD dwRet; 1280 1281 TRACE("(%p)\n", hMidiIn); 1282 1283 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 1284 return MMSYSERR_INVALHANDLE; 1285 1286 dwRet = MMDRV_Close(wmld, MIDM_CLOSE); 1287 MMDRV_Free(hMidiIn, wmld); 1288 return dwRet; 1289 } 1290 1291 /************************************************************************** 1292 * midiInPrepareHeader [WINMM.@] 1293 */ 1294 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn, 1295 MIDIHDR* lpMidiInHdr, UINT uSize) 1296 { 1297 LPWINE_MLD wmld; 1298 1299 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); 1300 1301 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) 1302 return MMSYSERR_INVALPARAM; 1303 1304 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 1305 return MMSYSERR_INVALHANDLE; 1306 1307 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize); 1308 } 1309 1310 /************************************************************************** 1311 * midiInUnprepareHeader [WINMM.@] 1312 */ 1313 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn, 1314 MIDIHDR* lpMidiInHdr, UINT uSize) 1315 { 1316 LPWINE_MLD wmld; 1317 1318 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); 1319 1320 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) 1321 return MMSYSERR_INVALPARAM; 1322 1323 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) { 1324 return MMSYSERR_NOERROR; 1325 } 1326 1327 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 1328 return MMSYSERR_INVALHANDLE; 1329 1330 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize); 1331 } 1332 1333 /************************************************************************** 1334 * midiInAddBuffer [WINMM.@] 1335 */ 1336 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn, 1337 MIDIHDR* lpMidiInHdr, UINT uSize) 1338 { 1339 LPWINE_MLD wmld; 1340 1341 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); 1342 1343 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 1344 return MMSYSERR_INVALHANDLE; 1345 1346 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize); 1347 } 1348 1349 /************************************************************************** 1350 * midiInStart [WINMM.@] 1351 */ 1352 UINT WINAPI midiInStart(HMIDIIN hMidiIn) 1353 { 1354 LPWINE_MLD wmld; 1355 1356 TRACE("(%p)\n", hMidiIn); 1357 1358 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 1359 return MMSYSERR_INVALHANDLE; 1360 1361 return MMDRV_Message(wmld, MIDM_START, 0L, 0L); 1362 } 1363 1364 /************************************************************************** 1365 * midiInStop [WINMM.@] 1366 */ 1367 UINT WINAPI midiInStop(HMIDIIN hMidiIn) 1368 { 1369 LPWINE_MLD wmld; 1370 1371 TRACE("(%p)\n", hMidiIn); 1372 1373 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 1374 return MMSYSERR_INVALHANDLE; 1375 1376 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L); 1377 } 1378 1379 /************************************************************************** 1380 * midiInReset [WINMM.@] 1381 */ 1382 UINT WINAPI midiInReset(HMIDIIN hMidiIn) 1383 { 1384 LPWINE_MLD wmld; 1385 1386 TRACE("(%p)\n", hMidiIn); 1387 1388 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 1389 return MMSYSERR_INVALHANDLE; 1390 1391 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L); 1392 } 1393 1394 /************************************************************************** 1395 * midiInGetID [WINMM.@] 1396 */ 1397 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID) 1398 { 1399 LPWINE_MLD wmld; 1400 1401 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID); 1402 1403 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; 1404 1405 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL) 1406 return MMSYSERR_INVALHANDLE; 1407 1408 *lpuDeviceID = wmld->uDeviceID; 1409 1410 return MMSYSERR_NOERROR; 1411 } 1412 1413 /************************************************************************** 1414 * midiInMessage [WINMM.@] 1415 */ 1416 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, 1417 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 1418 { 1419 LPWINE_MLD wmld; 1420 1421 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2); 1422 1423 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 1424 return MMSYSERR_INVALHANDLE; 1425 1426 switch (uMessage) { 1427 case MIDM_OPEN: 1428 case MIDM_CLOSE: 1429 FIXME("can't handle OPEN or CLOSE message!\n"); 1430 return MMSYSERR_NOTSUPPORTED; 1431 } 1432 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); 1433 } 1434 1435 /************************************************************************** 1436 * midiConnect [WINMM.@] 1437 */ 1438 MMRESULT WINAPI midiConnect(HMIDI hMidi, HMIDIOUT hmo, LPVOID pReserved) 1439 { 1440 FIXME("(%p, %p, %p): Stub\n", hMidi, hmo, pReserved); 1441 return MMSYSERR_ERROR; 1442 } 1443 1444 /************************************************************************** 1445 * midiDisconnect [WINMM.@] 1446 */ 1447 MMRESULT WINAPI midiDisconnect(HMIDI hMidi, HMIDIOUT hmo, LPVOID pReserved) 1448 { 1449 FIXME("(%p, %p, %p): Stub\n", hMidi, hmo, pReserved); 1450 return MMSYSERR_ERROR; 1451 } 1452 1453 typedef struct WINE_MIDIStream { 1454 HMIDIOUT hDevice; 1455 HANDLE hThread; 1456 DWORD dwThreadID; 1457 DWORD dwTempo; 1458 DWORD dwTimeDiv; 1459 DWORD dwPositionMS; 1460 DWORD dwPulses; 1461 DWORD dwStartTicks; 1462 WORD wFlags; 1463 HANDLE hEvent; 1464 LPMIDIHDR lpMidiHdr; 1465 } WINE_MIDIStream; 1466 1467 #define WINE_MSM_HEADER (WM_USER+0) 1468 #define WINE_MSM_STOP (WM_USER+1) 1469 1470 /************************************************************************** 1471 * MMSYSTEM_GetMidiStream [internal] 1472 */ 1473 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm) 1474 { 1475 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE); 1476 1477 if (lplpwm) 1478 *lplpwm = lpwm; 1479 1480 if (lpwm == NULL) { 1481 return FALSE; 1482 } 1483 1484 *lpMidiStrm = (WINE_MIDIStream*)(ULONG_PTR)lpwm->mod.rgIds.dwStreamID; // FIXME: not 64 bit safe 1485 1486 return *lpMidiStrm != NULL; 1487 } 1488 1489 /************************************************************************** 1490 * MMSYSTEM_MidiStream_Convert [internal] 1491 */ 1492 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse) 1493 { 1494 DWORD ret = 0; 1495 1496 if (lpMidiStrm->dwTimeDiv == 0) { 1497 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n"); 1498 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */ 1499 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */ 1500 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */ 1501 ret = (pulse * 1000) / (nf * nsf); 1502 } else { 1503 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) / 1504 (double)lpMidiStrm->dwTimeDiv); 1505 } 1506 1507 return ret; 1508 } 1509 1510 /************************************************************************** 1511 * MMSYSTEM_MidiStream_MessageHandler [internal] 1512 */ 1513 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg) 1514 { 1515 LPMIDIHDR lpMidiHdr; 1516 LPMIDIHDR* lpmh; 1517 LPBYTE lpData; 1518 1519 switch (msg->message) { 1520 case WM_QUIT: 1521 SetEvent(lpMidiStrm->hEvent); 1522 return FALSE; 1523 case WINE_MSM_STOP: 1524 TRACE("STOP\n"); 1525 /* this is not quite what MS doc says... */ 1526 midiOutReset(lpMidiStrm->hDevice); 1527 /* empty list of already submitted buffers */ 1528 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = lpMidiHdr->lpNext) { 1529 lpMidiHdr->dwFlags |= MHDR_DONE; 1530 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; 1531 1532 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, 1533 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, 1534 lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0); 1535 } 1536 lpMidiStrm->lpMidiHdr = 0; 1537 SetEvent(lpMidiStrm->hEvent); 1538 break; 1539 case WINE_MSM_HEADER: 1540 /* sets initial tick count for first MIDIHDR */ 1541 if (!lpMidiStrm->dwStartTicks) 1542 lpMidiStrm->dwStartTicks = GetTickCount(); 1543 1544 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent 1545 * by native mcimidi, it doesn't look like a correct one". 1546 * this trick allows to throw it away... but I don't like it. 1547 * It looks like part of the file I'm trying to play and definitively looks 1548 * like raw midi content 1549 * I'd really like to understand why native mcimidi sends it. Perhaps a bad 1550 * synchronization issue where native mcimidi is still processing raw MIDI 1551 * content before generating MIDIEVENTs ? 1552 * 1553 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^.. 1554 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b.. 1555 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^. 1556 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x. 1557 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^ 1558 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b 1559 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..# 1560 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L.. 1561 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H.. 1562 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?. 1563 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E. 1564 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F 1565 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H 1566 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.; 1567 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.; 1568 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|. 1569 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|. 1570 */ 1571 lpMidiHdr = (LPMIDIHDR)msg->lParam; 1572 lpData = (LPBYTE)lpMidiHdr->lpData; 1573 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%p dwBufferLength=%u/%u dwFlags=0x%08x size=%lu]\n", 1574 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr, 1575 lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded, 1576 lpMidiHdr->dwFlags, msg->wParam); 1577 #if 0 1578 /* dumps content of lpMidiHdr->lpData 1579 * FIXME: there should be a debug routine somewhere that already does this 1580 * I hate spreading this type of shit all around the code 1581 */ 1582 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) { 1583 DWORD i; 1584 BYTE ch; 1585 1586 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) 1587 printf("%02x ", lpData[dwToGo + i]); 1588 for (; i < 16; i++) 1589 printf(" "); 1590 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) { 1591 ch = lpData[dwToGo + i]; 1592 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.'); 1593 } 1594 printf("\n"); 1595 } 1596 #endif 1597 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 && 1598 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF && 1599 /* FIXME: not 64 bit safe */ 1600 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD_PTR)lpMidiStrm) { 1601 FIXME("Dropping bad %s lpMidiHdr (streamID=%08x)\n", 1602 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", 1603 ((LPMIDIEVENT)lpData)->dwStreamID); 1604 lpMidiHdr->dwFlags |= MHDR_DONE; 1605 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; 1606 1607 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, 1608 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, 1609 lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0); 1610 break; 1611 } 1612 1613 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = &(*lpmh)->lpNext); 1614 *lpmh = lpMidiHdr; 1615 lpMidiHdr = (LPMIDIHDR)msg->lParam; 1616 lpMidiHdr->lpNext = 0; 1617 lpMidiHdr->dwFlags |= MHDR_INQUEUE; 1618 lpMidiHdr->dwFlags &= ~MHDR_DONE; 1619 lpMidiHdr->dwOffset = 0; 1620 1621 break; 1622 default: 1623 FIXME("Unknown message %d\n", msg->message); 1624 break; 1625 } 1626 return TRUE; 1627 } 1628 1629 /************************************************************************** 1630 * MMSYSTEM_MidiStream_Player [internal] 1631 */ 1632 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt) 1633 { 1634 WINE_MIDIStream* lpMidiStrm = pmt; 1635 WINE_MIDI* lpwm; 1636 MSG msg; 1637 DWORD dwToGo; 1638 DWORD dwCurrTC; 1639 LPMIDIHDR lpMidiHdr; 1640 LPMIDIEVENT me; 1641 LPBYTE lpData = 0; 1642 1643 TRACE("(%p)!\n", lpMidiStrm); 1644 1645 if (!lpMidiStrm || 1646 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL) 1647 goto the_end; 1648 1649 /* force thread's queue creation */ 1650 /* Used to be InitThreadInput16(0, 5); */ 1651 /* but following works also with hack in midiStreamOpen */ 1652 PeekMessageA(&msg, 0, 0, 0, 0); 1653 1654 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */ 1655 SetEvent(lpMidiStrm->hEvent); 1656 TRACE("Ready to go 1\n"); 1657 /* thread is started in paused mode */ 1658 SuspendThread(lpMidiStrm->hThread); 1659 TRACE("Ready to go 2\n"); 1660 1661 lpMidiStrm->dwStartTicks = 0; 1662 lpMidiStrm->dwPulses = 0; 1663 1664 lpMidiStrm->lpMidiHdr = 0; 1665 1666 for (;;) { 1667 lpMidiHdr = lpMidiStrm->lpMidiHdr; 1668 if (!lpMidiHdr) { 1669 /* for first message, block until one arrives, then process all that are available */ 1670 GetMessageA(&msg, 0, 0, 0); 1671 do { 1672 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) 1673 goto the_end; 1674 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)); 1675 lpData = 0; 1676 continue; 1677 } 1678 1679 if (!lpData) 1680 lpData = (LPBYTE)lpMidiHdr->lpData; 1681 1682 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset); 1683 1684 /* do we have to wait ? */ 1685 if (me->dwDeltaTime) { 1686 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime); 1687 lpMidiStrm->dwPulses += me->dwDeltaTime; 1688 1689 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS; 1690 1691 TRACE("%d/%d/%d\n", dwToGo, GetTickCount(), me->dwDeltaTime); 1692 while ((dwCurrTC = GetTickCount()) < dwToGo) { 1693 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) { 1694 /* got a message, handle it */ 1695 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { 1696 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) 1697 goto the_end; 1698 } 1699 lpData = 0; 1700 } else { 1701 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */ 1702 break; 1703 } 1704 } 1705 } 1706 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) { 1707 case MEVT_COMMENT: 1708 FIXME("NIY: MEVT_COMMENT\n"); 1709 /* do nothing, skip bytes */ 1710 break; 1711 case MEVT_LONGMSG: 1712 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n"); 1713 break; 1714 case MEVT_NOP: 1715 break; 1716 case MEVT_SHORTMSG: 1717 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent)); 1718 break; 1719 case MEVT_TEMPO: 1720 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent); 1721 break; 1722 case MEVT_VERSION: 1723 break; 1724 default: 1725 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)); 1726 break; 1727 } 1728 if (me->dwEvent & MEVT_F_CALLBACK) { 1729 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, 1730 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB, 1731 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L); 1732 } 1733 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms); 1734 if (me->dwEvent & MEVT_F_LONG) 1735 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3; 1736 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) { 1737 /* done with this header */ 1738 lpMidiHdr->dwFlags |= MHDR_DONE; 1739 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; 1740 1741 lpMidiStrm->lpMidiHdr = lpMidiHdr->lpNext; 1742 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, 1743 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, 1744 lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0); 1745 lpData = 0; 1746 } 1747 } 1748 the_end: 1749 TRACE("End of thread\n"); 1750 ExitThread(0); 1751 return 0; /* for removing the warning, never executed */ 1752 } 1753 1754 /************************************************************************** 1755 * MMSYSTEM_MidiStream_PostMessage [internal] 1756 */ 1757 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2) 1758 { 1759 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) { 1760 //DWORD count; 1761 1762 //ReleaseThunkLock(&count); 1763 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); 1764 //RestoreThunkLock(count); 1765 } else { 1766 WARN("bad PostThreadMessageA\n"); 1767 return FALSE; 1768 } 1769 return TRUE; 1770 } 1771 1772 /************************************************************************** 1773 * midiStreamClose [WINMM.@] 1774 */ 1775 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm) 1776 { 1777 WINE_MIDIStream* lpMidiStrm; 1778 1779 TRACE("(%p)!\n", hMidiStrm); 1780 1781 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) 1782 return MMSYSERR_INVALHANDLE; 1783 1784 midiStreamStop(hMidiStrm); 1785 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0); 1786 HeapFree(GetProcessHeap(), 0, lpMidiStrm); 1787 CloseHandle(lpMidiStrm->hEvent); 1788 1789 return midiOutClose((HMIDIOUT)hMidiStrm); 1790 } 1791 1792 /************************************************************************** 1793 * midiStreamOpen [WINMM.@] 1794 */ 1795 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, 1796 DWORD cMidi, DWORD_PTR dwCallback, 1797 DWORD_PTR dwInstance, DWORD fdwOpen) 1798 { 1799 WINE_MIDIStream* lpMidiStrm; 1800 MMRESULT ret; 1801 MIDIOPENSTRMID mosm; 1802 LPWINE_MIDI lpwm; 1803 HMIDIOUT hMidiOut; 1804 1805 TRACE("(%p, %p, %d, 0x%08lx, 0x%08lx, 0x%08x)!\n", 1806 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen); 1807 1808 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL) 1809 return MMSYSERR_INVALPARAM; 1810 1811 ret = WINMM_CheckCallback(dwCallback, fdwOpen, FALSE); 1812 if (ret != MMSYSERR_NOERROR) 1813 return ret; 1814 1815 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream)); 1816 if (!lpMidiStrm) 1817 return MMSYSERR_NOMEM; 1818 1819 lpMidiStrm->dwTempo = 500000; 1820 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quarter notes per minute *//* FIXME ??*/ 1821 lpMidiStrm->dwPositionMS = 0; 1822 1823 mosm.dwStreamID = (DWORD_PTR)lpMidiStrm; // FIXME: not 64 bit safe 1824 /* FIXME: the correct value is not allocated yet for MAPPER */ 1825 mosm.wDeviceID = *lpuDeviceID; 1826 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm); 1827 lpMidiStrm->hDevice = hMidiOut; 1828 *lphMidiStrm = (HMIDISTRM)hMidiOut; 1829 1830 lpwm->mld.uDeviceID = *lpuDeviceID; 1831 1832 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD_PTR)&lpwm->mod, fdwOpen); 1833 lpMidiStrm->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); 1834 lpMidiStrm->wFlags = HIWORD(fdwOpen); 1835 1836 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player, 1837 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID)); 1838 1839 if (!lpMidiStrm->hThread) { 1840 midiStreamClose((HMIDISTRM)hMidiOut); 1841 return MMSYSERR_NOMEM; 1842 } 1843 SetThreadPriority(lpMidiStrm->hThread, THREAD_PRIORITY_TIME_CRITICAL); 1844 1845 /* wait for thread to have started, and for its queue to be created */ 1846 { 1847 //DWORD count; 1848 1849 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code, 1850 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running 1851 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue. 1852 */ 1853 //ReleaseThunkLock(&count); 1854 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); 1855 //RestoreThunkLock(count); 1856 } 1857 1858 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n", 1859 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm); 1860 return ret; 1861 } 1862 1863 /************************************************************************** 1864 * midiStreamOut [WINMM.@] 1865 */ 1866 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, 1867 UINT cbMidiHdr) 1868 { 1869 WINE_MIDIStream* lpMidiStrm; 1870 DWORD ret = MMSYSERR_NOERROR; 1871 1872 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr); 1873 1874 if (cbMidiHdr < offsetof(MIDIHDR,dwOffset) || !lpMidiHdr || !lpMidiHdr->lpData 1875 || lpMidiHdr->dwBufferLength < lpMidiHdr->dwBytesRecorded 1876 || lpMidiHdr->dwBytesRecorded % 4 /* player expects DWORD padding */) 1877 return MMSYSERR_INVALPARAM; 1878 /* FIXME: Native additionally checks if the MIDIEVENTs in lpData 1879 * exactly fit dwBytesRecorded. */ 1880 1881 if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) 1882 return MIDIERR_UNPREPARED; 1883 1884 if (lpMidiHdr->dwFlags & MHDR_INQUEUE) 1885 return MIDIERR_STILLPLAYING; 1886 1887 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 1888 ret = MMSYSERR_INVALHANDLE; 1889 } else { 1890 lpMidiHdr->dwFlags |= MHDR_ISSTRM; 1891 if (!PostThreadMessageA(lpMidiStrm->dwThreadID, 1892 WINE_MSM_HEADER, cbMidiHdr, 1893 (LPARAM)lpMidiHdr)) { 1894 WARN("bad PostThreadMessageA\n"); 1895 ret = MMSYSERR_ERROR; 1896 } 1897 } 1898 return ret; 1899 } 1900 1901 /************************************************************************** 1902 * midiStreamPause [WINMM.@] 1903 */ 1904 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm) 1905 { 1906 WINE_MIDIStream* lpMidiStrm; 1907 DWORD ret = MMSYSERR_NOERROR; 1908 1909 TRACE("(%p)!\n", hMidiStrm); 1910 1911 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 1912 ret = MMSYSERR_INVALHANDLE; 1913 } else { 1914 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) { 1915 WARN("bad Suspend (%d)\n", GetLastError()); 1916 ret = MMSYSERR_ERROR; 1917 } 1918 } 1919 return ret; 1920 } 1921 1922 /************************************************************************** 1923 * midiStreamPosition [WINMM.@] 1924 */ 1925 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt) 1926 { 1927 WINE_MIDIStream* lpMidiStrm; 1928 DWORD ret = MMSYSERR_NOERROR; 1929 1930 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt); 1931 1932 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 1933 ret = MMSYSERR_INVALHANDLE; 1934 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) { 1935 ret = MMSYSERR_INVALPARAM; 1936 } else { 1937 switch (lpMMT->wType) { 1938 case TIME_MS: 1939 lpMMT->u.ms = lpMidiStrm->dwPositionMS; 1940 TRACE("=> %d ms\n", lpMMT->u.ms); 1941 break; 1942 case TIME_TICKS: 1943 lpMMT->u.ticks = lpMidiStrm->dwPulses; 1944 TRACE("=> %d ticks\n", lpMMT->u.ticks); 1945 break; 1946 default: 1947 WARN("Unsupported time type %d\n", lpMMT->wType); 1948 lpMMT->wType = TIME_MS; 1949 ret = MMSYSERR_INVALPARAM; 1950 break; 1951 } 1952 } 1953 return ret; 1954 } 1955 1956 /************************************************************************** 1957 * midiStreamProperty [WINMM.@] 1958 */ 1959 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) 1960 { 1961 WINE_MIDIStream* lpMidiStrm; 1962 MMRESULT ret = MMSYSERR_NOERROR; 1963 1964 TRACE("(%p, %p, %x)\n", hMidiStrm, lpPropData, dwProperty); 1965 1966 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 1967 ret = MMSYSERR_INVALHANDLE; 1968 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) { 1969 ret = MMSYSERR_INVALPARAM; 1970 } else if (dwProperty & MIDIPROP_TEMPO) { 1971 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData; 1972 1973 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) { 1974 ret = MMSYSERR_INVALPARAM; 1975 } else if (dwProperty & MIDIPROP_SET) { 1976 lpMidiStrm->dwTempo = mpt->dwTempo; 1977 TRACE("Setting tempo to %d\n", mpt->dwTempo); 1978 } else if (dwProperty & MIDIPROP_GET) { 1979 mpt->dwTempo = lpMidiStrm->dwTempo; 1980 TRACE("Getting tempo <= %d\n", mpt->dwTempo); 1981 } 1982 } else if (dwProperty & MIDIPROP_TIMEDIV) { 1983 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData; 1984 1985 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) { 1986 ret = MMSYSERR_INVALPARAM; 1987 } else if (dwProperty & MIDIPROP_SET) { 1988 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv; 1989 TRACE("Setting time div to %d\n", mptd->dwTimeDiv); 1990 } else if (dwProperty & MIDIPROP_GET) { 1991 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv; 1992 TRACE("Getting time div <= %d\n", mptd->dwTimeDiv); 1993 } 1994 } else { 1995 ret = MMSYSERR_INVALPARAM; 1996 } 1997 1998 return ret; 1999 } 2000 2001 /************************************************************************** 2002 * midiStreamRestart [WINMM.@] 2003 */ 2004 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm) 2005 { 2006 WINE_MIDIStream* lpMidiStrm; 2007 MMRESULT ret = MMSYSERR_NOERROR; 2008 2009 TRACE("(%p)!\n", hMidiStrm); 2010 2011 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 2012 ret = MMSYSERR_INVALHANDLE; 2013 } else { 2014 DWORD ret; 2015 2016 /* since we increase the thread suspend count on each midiStreamPause 2017 * there may be a need for several midiStreamResume 2018 */ 2019 do { 2020 ret = ResumeThread(lpMidiStrm->hThread); 2021 } while (ret != 0xFFFFFFFF && ret != 0); 2022 if (ret == 0xFFFFFFFF) { 2023 WARN("bad Resume (%d)\n", GetLastError()); 2024 ret = MMSYSERR_ERROR; 2025 } else { 2026 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS; 2027 } 2028 } 2029 return ret; 2030 } 2031 2032 /************************************************************************** 2033 * midiStreamStop [WINMM.@] 2034 */ 2035 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm) 2036 { 2037 WINE_MIDIStream* lpMidiStrm; 2038 MMRESULT ret = MMSYSERR_NOERROR; 2039 2040 TRACE("(%p)!\n", hMidiStrm); 2041 2042 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 2043 ret = MMSYSERR_INVALHANDLE; 2044 } else { 2045 /* in case stream has been paused... FIXME is the current state correct ? */ 2046 midiStreamRestart(hMidiStrm); 2047 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0); 2048 } 2049 return ret; 2050 } 2051 2052 static UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, 2053 LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, 2054 DWORD_PTR dwInstance, DWORD dwFlags) 2055 { 2056 HANDLE handle; 2057 LPWINE_MLD wmld; 2058 DWORD dwRet; 2059 WAVEOPENDESC wod; 2060 2061 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08X);\n", 2062 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback, 2063 dwInstance, dwFlags); 2064 2065 if (dwFlags & WAVE_FORMAT_QUERY) 2066 TRACE("WAVE_FORMAT_QUERY requested !\n"); 2067 2068 dwRet = WINMM_CheckCallback(dwCallback, dwFlags, FALSE); 2069 if (dwRet != MMSYSERR_NOERROR) 2070 return dwRet; 2071 2072 if (lpFormat == NULL) { 2073 WARN("bad format\n"); 2074 return WAVERR_BADFORMAT; 2075 } 2076 2077 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) { 2078 WARN("invalid parameter\n"); 2079 return MMSYSERR_INVALPARAM; 2080 } 2081 2082 /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */ 2083 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u\n", 2084 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec, 2085 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample); 2086 2087 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle, 2088 &dwFlags, &dwCallback, &dwInstance)) == NULL) { 2089 return MMSYSERR_NOMEM; 2090 } 2091 2092 wod.hWave = handle; 2093 wod.lpFormat = (LPWAVEFORMATEX)lpFormat; /* should the struct be copied iso pointer? */ 2094 wod.dwCallback = dwCallback; 2095 wod.dwInstance = dwInstance; 2096 wod.dnDevNode = 0L; 2097 2098 TRACE("cb=%08lx\n", wod.dwCallback); 2099 2100 for (;;) { 2101 if (dwFlags & WAVE_MAPPED) { 2102 wod.uMappedDeviceID = uDeviceID; 2103 uDeviceID = WAVE_MAPPER; 2104 } else { 2105 wod.uMappedDeviceID = -1; 2106 } 2107 wmld->uDeviceID = uDeviceID; 2108 2109 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, 2110 (DWORD_PTR)&wod, dwFlags); 2111 2112 TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet)); 2113 if (dwRet != WAVERR_BADFORMAT || 2114 ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break; 2115 /* if we ask for a format which isn't supported by the physical driver, 2116 * let's try to map it through the wave mapper (except, if we already tried 2117 * or user didn't allow us to use acm codecs or the device is already the mapper) 2118 */ 2119 dwFlags |= WAVE_MAPPED; 2120 /* we shall loop only one */ 2121 } 2122 2123 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) { 2124 MMDRV_Free(handle, wmld); 2125 handle = 0; 2126 } 2127 2128 if (lphndl != NULL) *lphndl = handle; 2129 TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle); 2130 2131 return dwRet; 2132 } 2133 2134 /************************************************************************** 2135 * waveOutGetNumDevs [WINMM.@] 2136 */ 2137 UINT WINAPI waveOutGetNumDevs(void) 2138 { 2139 return MMDRV_GetNum(MMDRV_WAVEOUT); 2140 } 2141 2142 /************************************************************************** 2143 * waveOutGetDevCapsA [WINMM.@] 2144 */ 2145 UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps, 2146 UINT uSize) 2147 { 2148 WAVEOUTCAPSW wocW; 2149 UINT ret; 2150 2151 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 2152 2153 ret = waveOutGetDevCapsW(uDeviceID, &wocW, sizeof(wocW)); 2154 2155 if (ret == MMSYSERR_NOERROR) { 2156 WAVEOUTCAPSA wocA; 2157 wocA.wMid = wocW.wMid; 2158 wocA.wPid = wocW.wPid; 2159 wocA.vDriverVersion = wocW.vDriverVersion; 2160 WideCharToMultiByte( CP_ACP, 0, wocW.szPname, -1, wocA.szPname, 2161 sizeof(wocA.szPname), NULL, NULL ); 2162 wocA.dwFormats = wocW.dwFormats; 2163 wocA.wChannels = wocW.wChannels; 2164 wocA.dwSupport = wocW.dwSupport; 2165 memcpy(lpCaps, &wocA, min(uSize, sizeof(wocA))); 2166 } 2167 return ret; 2168 } 2169 2170 /************************************************************************** 2171 * waveOutGetDevCapsW [WINMM.@] 2172 */ 2173 UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps, 2174 UINT uSize) 2175 { 2176 LPWINE_MLD wmld; 2177 2178 TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize); 2179 2180 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 2181 2182 if (uDeviceID == WAVE_MAPPER) 2183 { 2184 FIXME("Support WAVE_MAPPER\n"); 2185 uDeviceID = 0; 2186 } 2187 2188 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL) 2189 return MMSYSERR_BADDEVICEID; 2190 2191 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 2192 } 2193 2194 /************************************************************************** 2195 * waveOutGetErrorTextA [WINMM.@] 2196 * waveInGetErrorTextA [WINMM.@] 2197 */ 2198 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) 2199 { 2200 UINT ret; 2201 2202 if (lpText == NULL) ret = MMSYSERR_INVALPARAM; 2203 else if (uSize == 0) ret = MMSYSERR_NOERROR; 2204 else 2205 { 2206 LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); 2207 if (!xstr) ret = MMSYSERR_NOMEM; 2208 else 2209 { 2210 ret = waveOutGetErrorTextW(uError, xstr, uSize); 2211 if (ret == MMSYSERR_NOERROR) 2212 WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); 2213 HeapFree(GetProcessHeap(), 0, xstr); 2214 } 2215 } 2216 return ret; 2217 } 2218 2219 /************************************************************************** 2220 * waveOutGetErrorTextW [WINMM.@] 2221 * waveInGetErrorTextW [WINMM.@] 2222 */ 2223 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) 2224 { 2225 UINT ret = MMSYSERR_BADERRNUM; 2226 2227 if (lpText == NULL) ret = MMSYSERR_INVALPARAM; 2228 else if (uSize == 0) ret = MMSYSERR_NOERROR; 2229 else if ( 2230 /* test has been removed because MMSYSERR_BASE is 0, and gcc did emit 2231 * a warning for the test was always true */ 2232 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || 2233 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) { 2234 if (LoadStringW(hWinMM32Instance, 2235 uError, lpText, uSize) > 0) { 2236 ret = MMSYSERR_NOERROR; 2237 } 2238 } 2239 return ret; 2240 } 2241 2242 /************************************************************************** 2243 * waveOutOpen [WINMM.@] 2244 * All the args/structs have the same layout as the win16 equivalents 2245 */ 2246 MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID, 2247 LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, 2248 DWORD_PTR dwInstance, DWORD dwFlags) 2249 { 2250 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat, 2251 dwCallback, dwInstance, dwFlags); 2252 } 2253 2254 /************************************************************************** 2255 * waveOutClose [WINMM.@] 2256 */ 2257 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut) 2258 { 2259 LPWINE_MLD wmld; 2260 DWORD dwRet; 2261 2262 TRACE("(%p)\n", hWaveOut); 2263 2264 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2265 return MMSYSERR_INVALHANDLE; 2266 2267 dwRet = MMDRV_Close(wmld, WODM_CLOSE); 2268 if (dwRet != WAVERR_STILLPLAYING) 2269 MMDRV_Free(hWaveOut, wmld); 2270 2271 return dwRet; 2272 } 2273 2274 /************************************************************************** 2275 * waveOutPrepareHeader [WINMM.@] 2276 */ 2277 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, 2278 WAVEHDR* lpWaveOutHdr, UINT uSize) 2279 { 2280 LPWINE_MLD wmld; 2281 UINT result; 2282 2283 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); 2284 2285 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) 2286 return MMSYSERR_INVALPARAM; 2287 2288 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2289 return MMSYSERR_INVALHANDLE; 2290 2291 if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, 2292 uSize)) != MMSYSERR_NOTSUPPORTED) 2293 return result; 2294 2295 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) 2296 return WAVERR_STILLPLAYING; 2297 2298 lpWaveOutHdr->dwFlags |= WHDR_PREPARED; 2299 lpWaveOutHdr->dwFlags &= ~WHDR_DONE; 2300 2301 return MMSYSERR_NOERROR; 2302 } 2303 2304 /************************************************************************** 2305 * waveOutUnprepareHeader [WINMM.@] 2306 */ 2307 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, 2308 LPWAVEHDR lpWaveOutHdr, UINT uSize) 2309 { 2310 LPWINE_MLD wmld; 2311 UINT result; 2312 2313 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); 2314 2315 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) 2316 return MMSYSERR_INVALPARAM; 2317 2318 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { 2319 return MMSYSERR_NOERROR; 2320 } 2321 2322 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2323 return MMSYSERR_INVALHANDLE; 2324 2325 if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, 2326 uSize)) != MMSYSERR_NOTSUPPORTED) 2327 return result; 2328 2329 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) 2330 return WAVERR_STILLPLAYING; 2331 2332 lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED; 2333 lpWaveOutHdr->dwFlags |= WHDR_DONE; 2334 2335 return MMSYSERR_NOERROR; 2336 } 2337 2338 /************************************************************************** 2339 * waveOutWrite [WINMM.@] 2340 */ 2341 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, 2342 UINT uSize) 2343 { 2344 LPWINE_MLD wmld; 2345 2346 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); 2347 2348 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2349 return MMSYSERR_INVALHANDLE; 2350 2351 return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize); 2352 } 2353 2354 /************************************************************************** 2355 * waveOutBreakLoop [WINMM.@] 2356 */ 2357 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut) 2358 { 2359 LPWINE_MLD wmld; 2360 2361 TRACE("(%p);\n", hWaveOut); 2362 2363 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2364 return MMSYSERR_INVALHANDLE; 2365 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L); 2366 } 2367 2368 /************************************************************************** 2369 * waveOutPause [WINMM.@] 2370 */ 2371 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut) 2372 { 2373 LPWINE_MLD wmld; 2374 2375 TRACE("(%p);\n", hWaveOut); 2376 2377 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2378 return MMSYSERR_INVALHANDLE; 2379 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L); 2380 } 2381 2382 /************************************************************************** 2383 * waveOutReset [WINMM.@] 2384 */ 2385 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut) 2386 { 2387 LPWINE_MLD wmld; 2388 2389 TRACE("(%p);\n", hWaveOut); 2390 2391 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2392 return MMSYSERR_INVALHANDLE; 2393 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L); 2394 } 2395 2396 /************************************************************************** 2397 * waveOutRestart [WINMM.@] 2398 */ 2399 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut) 2400 { 2401 LPWINE_MLD wmld; 2402 2403 TRACE("(%p);\n", hWaveOut); 2404 2405 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2406 return MMSYSERR_INVALHANDLE; 2407 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L); 2408 } 2409 2410 /************************************************************************** 2411 * waveOutGetPosition [WINMM.@] 2412 */ 2413 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime, 2414 UINT uSize) 2415 { 2416 LPWINE_MLD wmld; 2417 2418 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize); 2419 2420 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2421 return MMSYSERR_INVALHANDLE; 2422 2423 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize); 2424 } 2425 2426 /************************************************************************** 2427 * waveOutGetPitch [WINMM.@] 2428 */ 2429 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw) 2430 { 2431 LPWINE_MLD wmld; 2432 2433 TRACE("(%p, %p);\n", hWaveOut, lpdw); 2434 2435 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2436 return MMSYSERR_INVALHANDLE; 2437 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L); 2438 } 2439 2440 /************************************************************************** 2441 * waveOutSetPitch [WINMM.@] 2442 */ 2443 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw) 2444 { 2445 LPWINE_MLD wmld; 2446 2447 TRACE("(%p, %08x);\n", hWaveOut, dw); 2448 2449 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2450 return MMSYSERR_INVALHANDLE; 2451 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L); 2452 } 2453 2454 /************************************************************************** 2455 * waveOutGetPlaybackRate [WINMM.@] 2456 */ 2457 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw) 2458 { 2459 LPWINE_MLD wmld; 2460 2461 TRACE("(%p, %p);\n", hWaveOut, lpdw); 2462 2463 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2464 return MMSYSERR_INVALHANDLE; 2465 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L); 2466 } 2467 2468 /************************************************************************** 2469 * waveOutSetPlaybackRate [WINMM.@] 2470 */ 2471 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw) 2472 { 2473 LPWINE_MLD wmld; 2474 2475 TRACE("(%p, %08x);\n", hWaveOut, dw); 2476 2477 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2478 return MMSYSERR_INVALHANDLE; 2479 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L); 2480 } 2481 2482 /************************************************************************** 2483 * waveOutGetVolume [WINMM.@] 2484 */ 2485 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw) 2486 { 2487 LPWINE_MLD wmld; 2488 2489 TRACE("(%p, %p);\n", hWaveOut, lpdw); 2490 2491 if (lpdw == NULL) { 2492 WARN("invalid parameter\n"); 2493 return MMSYSERR_INVALPARAM; 2494 } 2495 2496 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) 2497 return MMSYSERR_INVALHANDLE; 2498 2499 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L); 2500 } 2501 2502 /************************************************************************** 2503 * waveOutSetVolume [WINMM.@] 2504 */ 2505 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw) 2506 { 2507 LPWINE_MLD wmld; 2508 2509 TRACE("(%p, %08x);\n", hWaveOut, dw); 2510 2511 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) 2512 return MMSYSERR_INVALHANDLE; 2513 2514 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L); 2515 } 2516 2517 /************************************************************************** 2518 * waveOutGetID [WINMM.@] 2519 */ 2520 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID) 2521 { 2522 LPWINE_MLD wmld; 2523 2524 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID); 2525 2526 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; 2527 2528 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 2529 return MMSYSERR_INVALHANDLE; 2530 2531 *lpuDeviceID = wmld->uDeviceID; 2532 return 0; 2533 } 2534 2535 /************************************************************************** 2536 * waveOutMessage [WINMM.@] 2537 */ 2538 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, 2539 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 2540 { 2541 LPWINE_MLD wmld; 2542 2543 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); 2544 2545 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) { 2546 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) { 2547 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); 2548 } 2549 WARN("invalid handle\n"); 2550 return MMSYSERR_INVALHANDLE; 2551 } 2552 2553 /* from M$ KB */ 2554 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) { 2555 WARN("invalid parameter\n"); 2556 return MMSYSERR_INVALPARAM; 2557 } 2558 2559 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); 2560 } 2561 2562 /************************************************************************** 2563 * waveInGetNumDevs [WINMM.@] 2564 */ 2565 UINT WINAPI waveInGetNumDevs(void) 2566 { 2567 return MMDRV_GetNum(MMDRV_WAVEIN); 2568 } 2569 2570 /************************************************************************** 2571 * waveInGetDevCapsW [WINMM.@] 2572 */ 2573 UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize) 2574 { 2575 LPWINE_MLD wmld; 2576 2577 TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize); 2578 2579 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 2580 2581 if (uDeviceID == WAVE_MAPPER) 2582 { 2583 FIXME("Support WAVE_MAPPER\n"); 2584 uDeviceID = 0; 2585 } 2586 2587 2588 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL) 2589 return MMSYSERR_BADDEVICEID; 2590 2591 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 2592 } 2593 2594 /************************************************************************** 2595 * waveInGetDevCapsA [WINMM.@] 2596 */ 2597 UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize) 2598 { 2599 WAVEINCAPSW wicW; 2600 UINT ret; 2601 2602 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 2603 2604 ret = waveInGetDevCapsW(uDeviceID, &wicW, sizeof(wicW)); 2605 2606 if (ret == MMSYSERR_NOERROR) { 2607 WAVEINCAPSA wicA; 2608 wicA.wMid = wicW.wMid; 2609 wicA.wPid = wicW.wPid; 2610 wicA.vDriverVersion = wicW.vDriverVersion; 2611 WideCharToMultiByte( CP_ACP, 0, wicW.szPname, -1, wicA.szPname, 2612 sizeof(wicA.szPname), NULL, NULL ); 2613 wicA.dwFormats = wicW.dwFormats; 2614 wicA.wChannels = wicW.wChannels; 2615 memcpy(lpCaps, &wicA, min(uSize, sizeof(wicA))); 2616 } 2617 return ret; 2618 } 2619 2620 /************************************************************************** 2621 * waveInOpen [WINMM.@] 2622 */ 2623 MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID, 2624 LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, 2625 DWORD_PTR dwInstance, DWORD dwFlags) 2626 { 2627 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat, 2628 dwCallback, dwInstance, dwFlags); 2629 } 2630 2631 /************************************************************************** 2632 * waveInClose [WINMM.@] 2633 */ 2634 UINT WINAPI waveInClose(HWAVEIN hWaveIn) 2635 { 2636 LPWINE_MLD wmld; 2637 DWORD dwRet; 2638 2639 TRACE("(%p)\n", hWaveIn); 2640 2641 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2642 return MMSYSERR_INVALHANDLE; 2643 2644 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L); 2645 if (dwRet != WAVERR_STILLPLAYING) 2646 MMDRV_Free(hWaveIn, wmld); 2647 return dwRet; 2648 } 2649 2650 /************************************************************************** 2651 * waveInPrepareHeader [WINMM.@] 2652 */ 2653 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, 2654 UINT uSize) 2655 { 2656 LPWINE_MLD wmld; 2657 UINT result; 2658 2659 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); 2660 2661 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) 2662 return MMSYSERR_INVALPARAM; 2663 2664 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2665 return MMSYSERR_INVALHANDLE; 2666 2667 if ((result = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, 2668 uSize)) != MMSYSERR_NOTSUPPORTED) 2669 return result; 2670 2671 if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) 2672 return WAVERR_STILLPLAYING; 2673 2674 lpWaveInHdr->dwFlags |= WHDR_PREPARED; 2675 lpWaveInHdr->dwFlags &= ~WHDR_DONE; 2676 lpWaveInHdr->dwBytesRecorded = 0; 2677 2678 return MMSYSERR_NOERROR; 2679 } 2680 2681 /************************************************************************** 2682 * waveInUnprepareHeader [WINMM.@] 2683 */ 2684 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, 2685 UINT uSize) 2686 { 2687 LPWINE_MLD wmld; 2688 UINT result; 2689 2690 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); 2691 2692 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) 2693 return MMSYSERR_INVALPARAM; 2694 2695 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) 2696 return MMSYSERR_NOERROR; 2697 2698 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2699 return MMSYSERR_INVALHANDLE; 2700 2701 if ((result = MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, 2702 uSize)) != MMSYSERR_NOTSUPPORTED) 2703 return result; 2704 2705 if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) 2706 return WAVERR_STILLPLAYING; 2707 2708 lpWaveInHdr->dwFlags &= ~WHDR_PREPARED; 2709 lpWaveInHdr->dwFlags |= WHDR_DONE; 2710 2711 return MMSYSERR_NOERROR; 2712 } 2713 2714 /************************************************************************** 2715 * waveInAddBuffer [WINMM.@] 2716 */ 2717 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, 2718 WAVEHDR* lpWaveInHdr, UINT uSize) 2719 { 2720 LPWINE_MLD wmld; 2721 2722 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); 2723 2724 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; 2725 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2726 return MMSYSERR_INVALHANDLE; 2727 2728 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize); 2729 } 2730 2731 /************************************************************************** 2732 * waveInReset [WINMM.@] 2733 */ 2734 UINT WINAPI waveInReset(HWAVEIN hWaveIn) 2735 { 2736 LPWINE_MLD wmld; 2737 2738 TRACE("(%p);\n", hWaveIn); 2739 2740 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2741 return MMSYSERR_INVALHANDLE; 2742 2743 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L); 2744 } 2745 2746 /************************************************************************** 2747 * waveInStart [WINMM.@] 2748 */ 2749 UINT WINAPI waveInStart(HWAVEIN hWaveIn) 2750 { 2751 LPWINE_MLD wmld; 2752 2753 TRACE("(%p);\n", hWaveIn); 2754 2755 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2756 return MMSYSERR_INVALHANDLE; 2757 2758 return MMDRV_Message(wmld, WIDM_START, 0L, 0L); 2759 } 2760 2761 /************************************************************************** 2762 * waveInStop [WINMM.@] 2763 */ 2764 UINT WINAPI waveInStop(HWAVEIN hWaveIn) 2765 { 2766 LPWINE_MLD wmld; 2767 2768 TRACE("(%p);\n", hWaveIn); 2769 2770 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2771 return MMSYSERR_INVALHANDLE; 2772 2773 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L); 2774 } 2775 2776 /************************************************************************** 2777 * waveInGetPosition [WINMM.@] 2778 */ 2779 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime, 2780 UINT uSize) 2781 { 2782 LPWINE_MLD wmld; 2783 2784 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize); 2785 2786 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2787 return MMSYSERR_INVALHANDLE; 2788 2789 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize); 2790 } 2791 2792 /************************************************************************** 2793 * waveInGetID [WINMM.@] 2794 */ 2795 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID) 2796 { 2797 LPWINE_MLD wmld; 2798 2799 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID); 2800 2801 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; 2802 2803 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 2804 return MMSYSERR_INVALHANDLE; 2805 2806 *lpuDeviceID = wmld->uDeviceID; 2807 return MMSYSERR_NOERROR; 2808 } 2809 2810 /************************************************************************** 2811 * waveInMessage [WINMM.@] 2812 */ 2813 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage, 2814 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 2815 { 2816 LPWINE_MLD wmld; 2817 2818 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); 2819 2820 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) { 2821 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) { 2822 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); 2823 } 2824 return MMSYSERR_INVALHANDLE; 2825 } 2826 2827 /* from M$ KB */ 2828 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) 2829 return MMSYSERR_INVALPARAM; 2830 2831 2832 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); 2833 } 2834 2835 struct mm_starter 2836 { 2837 LPTASKCALLBACK cb; 2838 DWORD client; 2839 HANDLE event; 2840 }; 2841 2842 static DWORD WINAPI mmTaskRun(void* pmt) 2843 { 2844 struct mm_starter mms; 2845 2846 memcpy(&mms, pmt, sizeof(struct mm_starter)); 2847 HeapFree(GetProcessHeap(), 0, pmt); 2848 mms.cb(mms.client); 2849 if (mms.event) SetEvent(mms.event); 2850 return 0; 2851 } 2852 2853 /****************************************************************** 2854 * mmTaskCreate (WINMM.@) 2855 */ 2856 UINT WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD_PTR client) 2857 { 2858 HANDLE hThread; 2859 HANDLE hEvent = 0; 2860 struct mm_starter *mms; 2861 2862 mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter)); 2863 if (mms == NULL) return TASKERR_OUTOFMEMORY; 2864 2865 mms->cb = cb; 2866 mms->client = client; 2867 if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); 2868 mms->event = hEvent; 2869 2870 hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL); 2871 if (!hThread) { 2872 HeapFree(GetProcessHeap(), 0, mms); 2873 if (hEvent) CloseHandle(hEvent); 2874 return TASKERR_OUTOFMEMORY; 2875 } 2876 SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); 2877 if (ph) *ph = hEvent; 2878 CloseHandle(hThread); 2879 return 0; 2880 } 2881 2882 /****************************************************************** 2883 * mmTaskBlock (WINMM.@) 2884 */ 2885 VOID WINAPI mmTaskBlock(DWORD tid) 2886 { 2887 MSG msg; 2888 2889 do 2890 { 2891 GetMessageA(&msg, 0, 0, 0); 2892 if (msg.hwnd) DispatchMessageA(&msg); 2893 } while (msg.message != WM_USER); 2894 } 2895 2896 /****************************************************************** 2897 * mmTaskSignal (WINMM.@) 2898 */ 2899 BOOL WINAPI mmTaskSignal(DWORD tid) 2900 { 2901 return PostThreadMessageW(tid, WM_USER, 0, 0); 2902 } 2903 2904 /****************************************************************** 2905 * mmTaskYield (WINMM.@) 2906 */ 2907 VOID WINAPI mmTaskYield(VOID) {} 2908 2909 /****************************************************************** 2910 * mmGetCurrentTask (WINMM.@) 2911 */ 2912 DWORD WINAPI mmGetCurrentTask(VOID) 2913 { 2914 return GetCurrentThreadId(); 2915 } 2916