Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenwinmm.c
Go to the documentation of this file.
00001 /* -*- tab-width: 8; c-basic-offset: 4 -*- */ 00002 00003 /* 00004 * WINMM functions 00005 * 00006 * Copyright 1993 Martin Ayotte 00007 * 1998-2002 Eric Pouech 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00022 */ 00023 00024 /* 00025 * Eric POUECH : 00026 * 98/9 added Win32 MCI support 00027 * 99/4 added midiStream support 00028 * 99/9 added support for loadable low level drivers 00029 */ 00030 00031 /* TODO 00032 * + it seems that some programs check what's installed in 00033 * registry against the value returned by drivers. Wine is 00034 * currently broken regarding this point. 00035 * + check thread-safeness for MMSYSTEM and WINMM entry points 00036 * + unicode entry points are badly supported (would require 00037 * moving 32 bit drivers as Unicode as they are supposed to be) 00038 * + allow joystick and timer external calls as we do for wave, 00039 * midi, mixer and aux 00040 */ 00041 00042 #include <stdio.h> 00043 #include <stdarg.h> 00044 #include <string.h> 00045 00046 #define NONAMELESSUNION 00047 #define NONAMELESSSTRUCT 00048 #include "windef.h" 00049 #include "winbase.h" 00050 #include "mmsystem.h" 00051 #include "winuser.h" 00052 #include "winnls.h" 00053 #include "winternl.h" 00054 #include "winemm.h" 00055 00056 #include "wine/debug.h" 00057 00058 WINE_DEFAULT_DEBUG_CHANNEL(winmm); 00059 00060 /* ======================================================================== 00061 * G L O B A L S E T T I N G S 00062 * ========================================================================*/ 00063 00064 HINSTANCE hWinMM32Instance; 00065 HANDLE psLastEvent; 00066 HANDLE psStopEvent; 00067 00068 CRITICAL_SECTION WINMM_cs; 00069 00070 /************************************************************************** 00071 * WINMM_CreateIData [internal] 00072 */ 00073 static BOOL WINMM_CreateIData(HINSTANCE hInstDLL) 00074 { 00075 hWinMM32Instance = hInstDLL; 00076 psStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL); 00077 psLastEvent = CreateEventW(NULL, TRUE, FALSE, NULL); 00078 InitializeCriticalSection(&WINMM_cs); 00079 return TRUE; 00080 } 00081 00082 /************************************************************************** 00083 * WINMM_DeleteIData [internal] 00084 */ 00085 static void WINMM_DeleteIData(void) 00086 { 00087 TIME_MMTimeStop(); 00088 00089 /* FIXME: should also free content and resources allocated 00090 * inside WINMM_IData */ 00091 CloseHandle(psStopEvent); 00092 CloseHandle(psLastEvent); 00093 DeleteCriticalSection(&WINMM_cs); 00094 } 00095 00096 /****************************************************************** 00097 * WINMM_LoadMMSystem 00098 * 00099 */ 00100 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR); 00101 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR); 00102 00103 BOOL WINMM_CheckForMMSystem(void) 00104 { 00105 /* 0 is not checked yet, -1 is not present, 1 is present */ 00106 static int loaded /* = 0 */; 00107 00108 if (loaded == 0) 00109 { 00110 HANDLE h = GetModuleHandleA("kernel32"); 00111 loaded = -1; 00112 if (h) 00113 { 00114 pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16"); 00115 pLoadLibrary16 = (void*)GetProcAddress(h, (LPCSTR)35); /* ordinal for LoadLibrary16 */ 00116 if (pGetModuleHandle16 && pLoadLibrary16 && 00117 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL"))) 00118 loaded = 1; 00119 } 00120 } 00121 return loaded > 0; 00122 } 00123 00124 /****************************************************************** 00125 * WINMM_ErrorToString 00126 */ 00127 const char* WINMM_ErrorToString(MMRESULT error) 00128 { 00129 #define ERR_TO_STR(dev) case dev: return #dev 00130 static char unknown[32]; 00131 switch (error) { 00132 ERR_TO_STR(MMSYSERR_NOERROR); 00133 ERR_TO_STR(MMSYSERR_ERROR); 00134 ERR_TO_STR(MMSYSERR_BADDEVICEID); 00135 ERR_TO_STR(MMSYSERR_NOTENABLED); 00136 ERR_TO_STR(MMSYSERR_ALLOCATED); 00137 ERR_TO_STR(MMSYSERR_INVALHANDLE); 00138 ERR_TO_STR(MMSYSERR_NODRIVER); 00139 ERR_TO_STR(MMSYSERR_NOMEM); 00140 ERR_TO_STR(MMSYSERR_NOTSUPPORTED); 00141 ERR_TO_STR(MMSYSERR_BADERRNUM); 00142 ERR_TO_STR(MMSYSERR_INVALFLAG); 00143 ERR_TO_STR(MMSYSERR_INVALPARAM); 00144 ERR_TO_STR(MMSYSERR_HANDLEBUSY); 00145 ERR_TO_STR(MMSYSERR_INVALIDALIAS); 00146 ERR_TO_STR(MMSYSERR_BADDB); 00147 ERR_TO_STR(MMSYSERR_KEYNOTFOUND); 00148 ERR_TO_STR(MMSYSERR_READERROR); 00149 ERR_TO_STR(MMSYSERR_WRITEERROR); 00150 ERR_TO_STR(MMSYSERR_DELETEERROR); 00151 ERR_TO_STR(MMSYSERR_VALNOTFOUND); 00152 ERR_TO_STR(MMSYSERR_NODRIVERCB); 00153 ERR_TO_STR(WAVERR_BADFORMAT); 00154 ERR_TO_STR(WAVERR_STILLPLAYING); 00155 ERR_TO_STR(WAVERR_UNPREPARED); 00156 ERR_TO_STR(WAVERR_SYNC); 00157 } 00158 sprintf(unknown, "Unknown(0x%08x)", error); 00159 return unknown; 00160 #undef ERR_TO_STR 00161 } 00162 00163 /************************************************************************** 00164 * DllMain (WINMM.init) 00165 * 00166 * WINMM DLL entry point 00167 * 00168 */ 00169 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad) 00170 { 00171 TRACE("%p 0x%x %p\n", hInstDLL, fdwReason, fImpLoad); 00172 00173 switch (fdwReason) { 00174 case DLL_PROCESS_ATTACH: 00175 DisableThreadLibraryCalls(hInstDLL); 00176 00177 if (!WINMM_CreateIData(hInstDLL)) 00178 return FALSE; 00179 if (!MMDRV_Init()) { 00180 WINMM_DeleteIData(); 00181 return FALSE; 00182 } 00183 break; 00184 case DLL_PROCESS_DETACH: 00185 /* close all opened MCI drivers */ 00186 MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L); 00187 MMDRV_Exit(); 00188 /* There's no guarantee the drivers haven't already been unloaded on 00189 * process shutdown. 00190 */ 00191 if (!fImpLoad) 00192 { 00193 /* now unload all remaining drivers... */ 00194 DRIVER_UnloadAll(); 00195 } 00196 00197 WINMM_DeleteIData(); 00198 break; 00199 } 00200 return TRUE; 00201 } 00202 00203 /************************************************************************** 00204 * Mixer devices. New to Win95 00205 */ 00206 00207 /************************************************************************** 00208 * find out the real mixer ID depending on hmix (depends on dwFlags) 00209 */ 00210 static UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm) 00211 { 00212 LPWINE_MIXER lpwm = NULL; 00213 UINT uRet = MMSYSERR_NOERROR; 00214 00215 switch (dwFlags & 0xF0000000ul) { 00216 case MIXER_OBJECTF_MIXER: 00217 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE); 00218 break; 00219 case MIXER_OBJECTF_HMIXER: 00220 lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE); 00221 break; 00222 case MIXER_OBJECTF_WAVEOUT: 00223 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER); 00224 break; 00225 case MIXER_OBJECTF_HWAVEOUT: 00226 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER); 00227 break; 00228 case MIXER_OBJECTF_WAVEIN: 00229 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER); 00230 break; 00231 case MIXER_OBJECTF_HWAVEIN: 00232 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER); 00233 break; 00234 case MIXER_OBJECTF_MIDIOUT: 00235 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER); 00236 break; 00237 case MIXER_OBJECTF_HMIDIOUT: 00238 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER); 00239 break; 00240 case MIXER_OBJECTF_MIDIIN: 00241 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER); 00242 break; 00243 case MIXER_OBJECTF_HMIDIIN: 00244 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER); 00245 break; 00246 case MIXER_OBJECTF_AUX: 00247 lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER); 00248 break; 00249 default: 00250 WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul); 00251 lpwm = 0; 00252 uRet = MMSYSERR_INVALFLAG; 00253 break; 00254 } 00255 *lplpwm = lpwm; 00256 if (lpwm == 0 && uRet == MMSYSERR_NOERROR) 00257 uRet = MMSYSERR_INVALPARAM; 00258 return uRet; 00259 } 00260 00261 /************************************************************************** 00262 * mixerGetNumDevs [WINMM.@] 00263 */ 00264 UINT WINAPI mixerGetNumDevs(void) 00265 { 00266 return MMDRV_GetNum(MMDRV_MIXER); 00267 } 00268 00269 /************************************************************************** 00270 * mixerGetDevCapsA [WINMM.@] 00271 */ 00272 UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize) 00273 { 00274 MIXERCAPSW micW; 00275 UINT ret; 00276 00277 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 00278 00279 ret = mixerGetDevCapsW(uDeviceID, &micW, sizeof(micW)); 00280 00281 if (ret == MMSYSERR_NOERROR) { 00282 MIXERCAPSA micA; 00283 micA.wMid = micW.wMid; 00284 micA.wPid = micW.wPid; 00285 micA.vDriverVersion = micW.vDriverVersion; 00286 WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, 00287 sizeof(micA.szPname), NULL, NULL ); 00288 micA.fdwSupport = micW.fdwSupport; 00289 micA.cDestinations = micW.cDestinations; 00290 memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); 00291 } 00292 return ret; 00293 } 00294 00295 /************************************************************************** 00296 * mixerGetDevCapsW [WINMM.@] 00297 */ 00298 UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize) 00299 { 00300 LPWINE_MLD wmld; 00301 00302 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 00303 00304 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL) 00305 return MMSYSERR_BADDEVICEID; 00306 00307 return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 00308 } 00309 00310 static void CALLBACK MIXER_WCallback(HMIXEROBJ hmx, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam, DWORD_PTR param2) 00311 { 00312 HWND hWnd = (HWND)dwInstance; 00313 00314 if (!dwInstance) 00315 return; 00316 00317 PostMessageW(hWnd, uMsg, (WPARAM)hmx, (LPARAM)dwParam); 00318 } 00319 00320 /************************************************************************** 00321 * mixerOpen [WINMM.@] 00322 */ 00323 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, 00324 DWORD_PTR dwInstance, DWORD fdwOpen) 00325 { 00326 HANDLE hMix; 00327 LPWINE_MLD wmld; 00328 DWORD dwRet = 0; 00329 MIXEROPENDESC mod; 00330 00331 TRACE("(%p, %d, %08lx, %08lx, %08x)\n", 00332 lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen); 00333 00334 mod.dwCallback = (DWORD_PTR)MIXER_WCallback; 00335 mod.dwInstance = 0; 00336 00337 /* If callback is a function, 00338 * dwCallback contains function pointer 00339 * dwInstance private data 00340 * 00341 * if callback is a window 00342 * dwCallback contains a window handle 00343 */ 00344 switch (fdwOpen & CALLBACK_TYPEMASK) { 00345 default: 00346 return MMSYSERR_INVALFLAG; 00347 00348 case CALLBACK_NULL: 00349 break; 00350 00351 case CALLBACK_WINDOW: 00352 mod.dwInstance = dwCallback; 00353 if (dwCallback && !IsWindow((HWND)dwCallback)) 00354 return MMSYSERR_INVALPARAM; 00355 break; 00356 } 00357 00358 wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen, 00359 &dwCallback, &dwInstance); 00360 wmld->uDeviceID = uDeviceID; 00361 mod.hmx = hMix; 00362 00363 dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD_PTR)&mod, CALLBACK_FUNCTION); 00364 00365 if (dwRet != MMSYSERR_NOERROR) { 00366 MMDRV_Free(hMix, wmld); 00367 hMix = 0; 00368 } 00369 if (lphMix) *lphMix = hMix; 00370 TRACE("=> %d hMixer=%p\n", dwRet, hMix); 00371 00372 return dwRet; 00373 } 00374 00375 /************************************************************************** 00376 * mixerClose [WINMM.@] 00377 */ 00378 UINT WINAPI mixerClose(HMIXER hMix) 00379 { 00380 LPWINE_MLD wmld; 00381 DWORD dwRet; 00382 00383 TRACE("(%p)\n", hMix); 00384 00385 if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE; 00386 00387 dwRet = MMDRV_Close(wmld, MXDM_CLOSE); 00388 MMDRV_Free(hMix, wmld); 00389 00390 return dwRet; 00391 } 00392 00393 /************************************************************************** 00394 * mixerGetID [WINMM.@] 00395 */ 00396 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID) 00397 { 00398 LPWINE_MIXER lpwm; 00399 UINT uRet = MMSYSERR_NOERROR; 00400 00401 TRACE("(%p %p %08x)\n", hmix, lpid, fdwID); 00402 00403 if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR) 00404 return uRet; 00405 00406 if (lpid) 00407 *lpid = lpwm->mld.uDeviceID; 00408 00409 return uRet; 00410 } 00411 00412 /************************************************************************** 00413 * mixerGetControlDetailsW [WINMM.@] 00414 */ 00415 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW, 00416 DWORD fdwDetails) 00417 { 00418 LPWINE_MIXER lpwm; 00419 UINT uRet = MMSYSERR_NOERROR; 00420 00421 TRACE("(%p, %p, %08x)\n", hmix, lpmcdW, fdwDetails); 00422 00423 if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) 00424 return uRet; 00425 00426 if (lpmcdW == NULL || lpmcdW->cbStruct != sizeof(*lpmcdW)) 00427 return MMSYSERR_INVALPARAM; 00428 00429 return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdW, 00430 fdwDetails); 00431 } 00432 00433 /************************************************************************** 00434 * mixerGetControlDetailsA [WINMM.@] 00435 */ 00436 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, 00437 DWORD fdwDetails) 00438 { 00439 DWORD ret = MMSYSERR_NOTENABLED; 00440 00441 TRACE("(%p, %p, %08x)\n", hmix, lpmcdA, fdwDetails); 00442 00443 if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA)) 00444 return MMSYSERR_INVALPARAM; 00445 00446 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) { 00447 case MIXER_GETCONTROLDETAILSF_VALUE: 00448 /* can safely use A structure as it is, no string inside */ 00449 ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); 00450 break; 00451 case MIXER_GETCONTROLDETAILSF_LISTTEXT: 00452 { 00453 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA = lpmcdA->paDetails; 00454 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW; 00455 int size = max(1, lpmcdA->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTW); 00456 unsigned int i; 00457 00458 if (lpmcdA->u.cMultipleItems != 0) { 00459 size *= lpmcdA->u.cMultipleItems; 00460 } 00461 pDetailsW = HeapAlloc(GetProcessHeap(), 0, size); 00462 lpmcdA->paDetails = pDetailsW; 00463 lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW); 00464 /* set up lpmcd->paDetails */ 00465 ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); 00466 /* copy from lpmcd->paDetails back to paDetailsW; */ 00467 if (ret == MMSYSERR_NOERROR) { 00468 for (i = 0; i < lpmcdA->u.cMultipleItems * lpmcdA->cChannels; i++) { 00469 pDetailsA->dwParam1 = pDetailsW->dwParam1; 00470 pDetailsA->dwParam2 = pDetailsW->dwParam2; 00471 WideCharToMultiByte( CP_ACP, 0, pDetailsW->szName, -1, 00472 pDetailsA->szName, 00473 sizeof(pDetailsA->szName), NULL, NULL ); 00474 pDetailsA++; 00475 pDetailsW++; 00476 } 00477 pDetailsA -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; 00478 pDetailsW -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; 00479 } 00480 HeapFree(GetProcessHeap(), 0, pDetailsW); 00481 lpmcdA->paDetails = pDetailsA; 00482 lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA); 00483 } 00484 break; 00485 default: 00486 ERR("Unsupported fdwDetails=0x%08x\n", fdwDetails); 00487 } 00488 00489 return ret; 00490 } 00491 00492 /************************************************************************** 00493 * mixerGetLineControlsA [WINMM.@] 00494 */ 00495 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA, 00496 DWORD fdwControls) 00497 { 00498 MIXERLINECONTROLSW mlcW; 00499 DWORD ret; 00500 unsigned int i; 00501 00502 TRACE("(%p, %p, %08x)\n", hmix, lpmlcA, fdwControls); 00503 00504 if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA) || 00505 lpmlcA->cbmxctrl != sizeof(MIXERCONTROLA)) 00506 return MMSYSERR_INVALPARAM; 00507 00508 mlcW.cbStruct = sizeof(mlcW); 00509 mlcW.dwLineID = lpmlcA->dwLineID; 00510 mlcW.u.dwControlID = lpmlcA->u.dwControlID; 00511 mlcW.u.dwControlType = lpmlcA->u.dwControlType; 00512 00513 /* Debugging on Windows shows for MIXER_GETLINECONTROLSF_ONEBYTYPE only, 00514 the control count is assumed to be 1 - This is relied upon by a game, 00515 "Dynomite Deluze" */ 00516 if (MIXER_GETLINECONTROLSF_ONEBYTYPE == (fdwControls & MIXER_GETLINECONTROLSF_QUERYMASK)) { 00517 mlcW.cControls = 1; 00518 } else { 00519 mlcW.cControls = lpmlcA->cControls; 00520 } 00521 mlcW.cbmxctrl = sizeof(MIXERCONTROLW); 00522 mlcW.pamxctrl = HeapAlloc(GetProcessHeap(), 0, 00523 mlcW.cControls * mlcW.cbmxctrl); 00524 00525 ret = mixerGetLineControlsW(hmix, &mlcW, fdwControls); 00526 00527 if (ret == MMSYSERR_NOERROR) { 00528 lpmlcA->dwLineID = mlcW.dwLineID; 00529 lpmlcA->u.dwControlID = mlcW.u.dwControlID; 00530 lpmlcA->u.dwControlType = mlcW.u.dwControlType; 00531 00532 for (i = 0; i < mlcW.cControls; i++) { 00533 lpmlcA->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLA); 00534 lpmlcA->pamxctrl[i].dwControlID = mlcW.pamxctrl[i].dwControlID; 00535 lpmlcA->pamxctrl[i].dwControlType = mlcW.pamxctrl[i].dwControlType; 00536 lpmlcA->pamxctrl[i].fdwControl = mlcW.pamxctrl[i].fdwControl; 00537 lpmlcA->pamxctrl[i].cMultipleItems = mlcW.pamxctrl[i].cMultipleItems; 00538 WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szShortName, -1, 00539 lpmlcA->pamxctrl[i].szShortName, 00540 sizeof(lpmlcA->pamxctrl[i].szShortName), NULL, NULL ); 00541 WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szName, -1, 00542 lpmlcA->pamxctrl[i].szName, 00543 sizeof(lpmlcA->pamxctrl[i].szName), NULL, NULL ); 00544 /* sizeof(lpmlcA->pamxctrl[i].Bounds) == 00545 * sizeof(mlcW.pamxctrl[i].Bounds) */ 00546 memcpy(&lpmlcA->pamxctrl[i].Bounds, &mlcW.pamxctrl[i].Bounds, 00547 sizeof(mlcW.pamxctrl[i].Bounds)); 00548 /* sizeof(lpmlcA->pamxctrl[i].Metrics) == 00549 * sizeof(mlcW.pamxctrl[i].Metrics) */ 00550 memcpy(&lpmlcA->pamxctrl[i].Metrics, &mlcW.pamxctrl[i].Metrics, 00551 sizeof(mlcW.pamxctrl[i].Metrics)); 00552 } 00553 } 00554 00555 HeapFree(GetProcessHeap(), 0, mlcW.pamxctrl); 00556 00557 return ret; 00558 } 00559 00560 /************************************************************************** 00561 * mixerGetLineControlsW [WINMM.@] 00562 */ 00563 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, 00564 DWORD fdwControls) 00565 { 00566 LPWINE_MIXER lpwm; 00567 UINT uRet = MMSYSERR_NOERROR; 00568 00569 TRACE("(%p, %p, %08x)\n", hmix, lpmlcW, fdwControls); 00570 00571 if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR) 00572 return uRet; 00573 00574 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW)) 00575 return MMSYSERR_INVALPARAM; 00576 00577 return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcW, 00578 fdwControls); 00579 } 00580 00581 /************************************************************************** 00582 * mixerGetLineInfoW [WINMM.@] 00583 */ 00584 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo) 00585 { 00586 LPWINE_MIXER lpwm; 00587 UINT uRet = MMSYSERR_NOERROR; 00588 00589 TRACE("(%p, %p, %08x)\n", hmix, lpmliW, fdwInfo); 00590 00591 if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW)) 00592 return MMSYSERR_INVALPARAM; 00593 00594 if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR) 00595 return uRet; 00596 00597 return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW, 00598 fdwInfo); 00599 } 00600 00601 /************************************************************************** 00602 * mixerGetLineInfoA [WINMM.@] 00603 */ 00604 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliA, 00605 DWORD fdwInfo) 00606 { 00607 MIXERLINEW mliW; 00608 UINT ret; 00609 00610 TRACE("(%p, %p, %08x)\n", hmix, lpmliA, fdwInfo); 00611 00612 if (lpmliA == NULL || lpmliA->cbStruct != sizeof(*lpmliA)) 00613 return MMSYSERR_INVALPARAM; 00614 00615 mliW.cbStruct = sizeof(mliW); 00616 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { 00617 case MIXER_GETLINEINFOF_COMPONENTTYPE: 00618 mliW.dwComponentType = lpmliA->dwComponentType; 00619 break; 00620 case MIXER_GETLINEINFOF_DESTINATION: 00621 mliW.dwDestination = lpmliA->dwDestination; 00622 break; 00623 case MIXER_GETLINEINFOF_LINEID: 00624 mliW.dwLineID = lpmliA->dwLineID; 00625 break; 00626 case MIXER_GETLINEINFOF_SOURCE: 00627 mliW.dwDestination = lpmliA->dwDestination; 00628 mliW.dwSource = lpmliA->dwSource; 00629 break; 00630 case MIXER_GETLINEINFOF_TARGETTYPE: 00631 mliW.Target.dwType = lpmliA->Target.dwType; 00632 mliW.Target.wMid = lpmliA->Target.wMid; 00633 mliW.Target.wPid = lpmliA->Target.wPid; 00634 mliW.Target.vDriverVersion = lpmliA->Target.vDriverVersion; 00635 MultiByteToWideChar( CP_ACP, 0, lpmliA->Target.szPname, -1, mliW.Target.szPname, sizeof(mliW.Target.szPname)/sizeof(WCHAR)); 00636 break; 00637 default: 00638 WARN("Unsupported fdwControls=0x%08x\n", fdwInfo); 00639 return MMSYSERR_INVALFLAG; 00640 } 00641 00642 ret = mixerGetLineInfoW(hmix, &mliW, fdwInfo); 00643 00644 if(ret == MMSYSERR_NOERROR) 00645 { 00646 lpmliA->dwDestination = mliW.dwDestination; 00647 lpmliA->dwSource = mliW.dwSource; 00648 lpmliA->dwLineID = mliW.dwLineID; 00649 lpmliA->fdwLine = mliW.fdwLine; 00650 lpmliA->dwUser = mliW.dwUser; 00651 lpmliA->dwComponentType = mliW.dwComponentType; 00652 lpmliA->cChannels = mliW.cChannels; 00653 lpmliA->cConnections = mliW.cConnections; 00654 lpmliA->cControls = mliW.cControls; 00655 WideCharToMultiByte( CP_ACP, 0, mliW.szShortName, -1, lpmliA->szShortName, 00656 sizeof(lpmliA->szShortName), NULL, NULL); 00657 WideCharToMultiByte( CP_ACP, 0, mliW.szName, -1, lpmliA->szName, 00658 sizeof(lpmliA->szName), NULL, NULL ); 00659 lpmliA->Target.dwType = mliW.Target.dwType; 00660 lpmliA->Target.dwDeviceID = mliW.Target.dwDeviceID; 00661 lpmliA->Target.wMid = mliW.Target.wMid; 00662 lpmliA->Target.wPid = mliW.Target.wPid; 00663 lpmliA->Target.vDriverVersion = mliW.Target.vDriverVersion; 00664 WideCharToMultiByte( CP_ACP, 0, mliW.Target.szPname, -1, lpmliA->Target.szPname, 00665 sizeof(lpmliA->Target.szPname), NULL, NULL ); 00666 } 00667 return ret; 00668 } 00669 00670 /************************************************************************** 00671 * mixerSetControlDetails [WINMM.@] 00672 */ 00673 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, 00674 DWORD fdwDetails) 00675 { 00676 LPWINE_MIXER lpwm; 00677 UINT uRet = MMSYSERR_NOERROR; 00678 00679 TRACE("(%p, %p, %08x)\n", hmix, lpmcd, fdwDetails); 00680 00681 if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) 00682 return uRet; 00683 00684 return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcd, 00685 fdwDetails); 00686 } 00687 00688 /************************************************************************** 00689 * mixerMessage [WINMM.@] 00690 */ 00691 DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 00692 { 00693 LPWINE_MLD wmld; 00694 00695 TRACE("(%p, %d, %08lx, %08lx): semi-stub?\n", 00696 hmix, uMsg, dwParam1, dwParam2); 00697 00698 if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL) 00699 return MMSYSERR_INVALHANDLE; 00700 00701 return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2); 00702 } 00703 00704 /************************************************************************** 00705 * auxGetNumDevs [WINMM.@] 00706 */ 00707 UINT WINAPI auxGetNumDevs(void) 00708 { 00709 return MMDRV_GetNum(MMDRV_AUX); 00710 } 00711 00712 /************************************************************************** 00713 * auxGetDevCapsW [WINMM.@] 00714 */ 00715 UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize) 00716 { 00717 LPWINE_MLD wmld; 00718 00719 TRACE("(%04lX, %p, %d) !\n", uDeviceID, lpCaps, uSize); 00720 00721 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 00722 00723 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) 00724 return MMSYSERR_INVALHANDLE; 00725 return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 00726 } 00727 00728 /************************************************************************** 00729 * auxGetDevCapsA [WINMM.@] 00730 */ 00731 UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize) 00732 { 00733 AUXCAPSW acW; 00734 UINT ret; 00735 00736 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 00737 00738 ret = auxGetDevCapsW(uDeviceID, &acW, sizeof(acW)); 00739 00740 if (ret == MMSYSERR_NOERROR) { 00741 AUXCAPSA acA; 00742 acA.wMid = acW.wMid; 00743 acA.wPid = acW.wPid; 00744 acA.vDriverVersion = acW.vDriverVersion; 00745 WideCharToMultiByte( CP_ACP, 0, acW.szPname, -1, acA.szPname, 00746 sizeof(acA.szPname), NULL, NULL ); 00747 acA.wTechnology = acW.wTechnology; 00748 acA.dwSupport = acW.dwSupport; 00749 memcpy(lpCaps, &acA, min(uSize, sizeof(acA))); 00750 } 00751 return ret; 00752 } 00753 00754 /************************************************************************** 00755 * auxGetVolume [WINMM.@] 00756 */ 00757 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume) 00758 { 00759 LPWINE_MLD wmld; 00760 00761 TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume); 00762 00763 if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL) 00764 return MMSYSERR_INVALHANDLE; 00765 return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L); 00766 } 00767 00768 /************************************************************************** 00769 * auxSetVolume [WINMM.@] 00770 */ 00771 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume) 00772 { 00773 LPWINE_MLD wmld; 00774 00775 TRACE("(%04X, %u) !\n", uDeviceID, dwVolume); 00776 00777 if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL) 00778 return MMSYSERR_INVALHANDLE; 00779 return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L); 00780 } 00781 00782 /************************************************************************** 00783 * auxOutMessage [WINMM.@] 00784 */ 00785 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2) 00786 { 00787 LPWINE_MLD wmld; 00788 00789 if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL) 00790 return MMSYSERR_INVALHANDLE; 00791 00792 return MMDRV_Message(wmld, uMessage, dw1, dw2); 00793 } 00794 00795 /************************************************************************** 00796 * midiOutGetNumDevs [WINMM.@] 00797 */ 00798 UINT WINAPI midiOutGetNumDevs(void) 00799 { 00800 return MMDRV_GetNum(MMDRV_MIDIOUT); 00801 } 00802 00803 /************************************************************************** 00804 * midiOutGetDevCapsW [WINMM.@] 00805 */ 00806 UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps, 00807 UINT uSize) 00808 { 00809 LPWINE_MLD wmld; 00810 00811 TRACE("(%lu, %p, %u);\n", uDeviceID, lpCaps, uSize); 00812 00813 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 00814 00815 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL) 00816 return MMSYSERR_INVALHANDLE; 00817 00818 return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 00819 } 00820 00821 /************************************************************************** 00822 * midiOutGetDevCapsA [WINMM.@] 00823 */ 00824 UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps, 00825 UINT uSize) 00826 { 00827 MIDIOUTCAPSW mocW; 00828 UINT ret; 00829 00830 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 00831 00832 ret = midiOutGetDevCapsW(uDeviceID, &mocW, sizeof(mocW)); 00833 00834 if (ret == MMSYSERR_NOERROR) { 00835 MIDIOUTCAPSA mocA; 00836 mocA.wMid = mocW.wMid; 00837 mocA.wPid = mocW.wPid; 00838 mocA.vDriverVersion = mocW.vDriverVersion; 00839 WideCharToMultiByte( CP_ACP, 0, mocW.szPname, -1, mocA.szPname, 00840 sizeof(mocA.szPname), NULL, NULL ); 00841 mocA.wTechnology = mocW.wTechnology; 00842 mocA.wVoices = mocW.wVoices; 00843 mocA.wNotes = mocW.wNotes; 00844 mocA.wChannelMask = mocW.wChannelMask; 00845 mocA.dwSupport = mocW.dwSupport; 00846 memcpy(lpCaps, &mocA, min(uSize, sizeof(mocA))); 00847 } 00848 return ret; 00849 } 00850 00851 /************************************************************************** 00852 * midiOutGetErrorTextA [WINMM.@] 00853 * midiInGetErrorTextA [WINMM.@] 00854 */ 00855 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) 00856 { 00857 UINT ret; 00858 00859 if (lpText == NULL) ret = MMSYSERR_INVALPARAM; 00860 else if (uSize == 0) ret = MMSYSERR_NOERROR; 00861 else 00862 { 00863 LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); 00864 if (!xstr) ret = MMSYSERR_NOMEM; 00865 else 00866 { 00867 ret = midiOutGetErrorTextW(uError, xstr, uSize); 00868 if (ret == MMSYSERR_NOERROR) 00869 WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); 00870 HeapFree(GetProcessHeap(), 0, xstr); 00871 } 00872 } 00873 return ret; 00874 } 00875 00876 /************************************************************************** 00877 * midiOutGetErrorTextW [WINMM.@] 00878 * midiInGetErrorTextW [WINMM.@] 00879 */ 00880 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) 00881 { 00882 UINT ret = MMSYSERR_BADERRNUM; 00883 00884 if (lpText == NULL) ret = MMSYSERR_INVALPARAM; 00885 else if (uSize == 0) ret = MMSYSERR_NOERROR; 00886 else if ( 00887 /* test has been removed because MMSYSERR_BASE is 0, and gcc did emit 00888 * a warning for the test was always true */ 00889 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || 00890 (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) { 00891 if (LoadStringW(hWinMM32Instance, uError, lpText, uSize) > 0) { 00892 ret = MMSYSERR_NOERROR; 00893 } 00894 } 00895 return ret; 00896 } 00897 00898 /************************************************************************** 00899 * MIDI_OutAlloc [internal] 00900 */ 00901 static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, DWORD_PTR* lpdwCallback, 00902 DWORD_PTR* lpdwInstance, LPDWORD lpdwFlags, 00903 DWORD cIDs, MIDIOPENSTRMID* lpIDs) 00904 { 00905 HANDLE hMidiOut; 00906 LPWINE_MIDI lpwm; 00907 UINT size; 00908 00909 size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID); 00910 00911 lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags, 00912 lpdwCallback, lpdwInstance); 00913 00914 if (lphMidiOut != NULL) 00915 *lphMidiOut = hMidiOut; 00916 00917 if (lpwm) { 00918 lpwm->mod.hMidi = hMidiOut; 00919 lpwm->mod.dwCallback = *lpdwCallback; 00920 lpwm->mod.dwInstance = *lpdwInstance; 00921 lpwm->mod.dnDevNode = 0; 00922 lpwm->mod.cIds = cIDs; 00923 if (cIDs) 00924 memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID)); 00925 } 00926 return lpwm; 00927 } 00928 00929 /************************************************************************** 00930 * midiOutOpen [WINMM.@] 00931 */ 00932 MMRESULT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, 00933 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags) 00934 { 00935 HMIDIOUT hMidiOut; 00936 LPWINE_MIDI lpwm; 00937 UINT dwRet = 0; 00938 00939 TRACE("(%p, %d, %08lX, %08lX, %08X);\n", 00940 lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags); 00941 00942 if (lphMidiOut != NULL) *lphMidiOut = 0; 00943 00944 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags, 0, NULL); 00945 00946 if (lpwm == NULL) 00947 return MMSYSERR_NOMEM; 00948 00949 lpwm->mld.uDeviceID = uDeviceID; 00950 00951 dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD_PTR)&lpwm->mod, dwFlags); 00952 00953 if (dwRet != MMSYSERR_NOERROR) { 00954 MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm); 00955 hMidiOut = 0; 00956 } 00957 00958 if (lphMidiOut) *lphMidiOut = hMidiOut; 00959 TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut); 00960 00961 return dwRet; 00962 } 00963 00964 /************************************************************************** 00965 * midiOutClose [WINMM.@] 00966 */ 00967 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut) 00968 { 00969 LPWINE_MLD wmld; 00970 DWORD dwRet; 00971 00972 TRACE("(%p)\n", hMidiOut); 00973 00974 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 00975 return MMSYSERR_INVALHANDLE; 00976 00977 dwRet = MMDRV_Close(wmld, MODM_CLOSE); 00978 MMDRV_Free(hMidiOut, wmld); 00979 00980 return dwRet; 00981 } 00982 00983 /************************************************************************** 00984 * midiOutPrepareHeader [WINMM.@] 00985 */ 00986 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut, 00987 MIDIHDR* lpMidiOutHdr, UINT uSize) 00988 { 00989 LPWINE_MLD wmld; 00990 00991 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); 00992 00993 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) 00994 return MMSYSERR_INVALPARAM; 00995 00996 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 00997 return MMSYSERR_INVALHANDLE; 00998 00999 return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize); 01000 } 01001 01002 /************************************************************************** 01003 * midiOutUnprepareHeader [WINMM.@] 01004 */ 01005 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut, 01006 MIDIHDR* lpMidiOutHdr, UINT uSize) 01007 { 01008 LPWINE_MLD wmld; 01009 01010 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); 01011 01012 if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) 01013 return MMSYSERR_INVALPARAM; 01014 01015 if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) { 01016 return MMSYSERR_NOERROR; 01017 } 01018 01019 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 01020 return MMSYSERR_INVALHANDLE; 01021 01022 return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize); 01023 } 01024 01025 /************************************************************************** 01026 * midiOutShortMsg [WINMM.@] 01027 */ 01028 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg) 01029 { 01030 LPWINE_MLD wmld; 01031 01032 TRACE("(%p, %08X)\n", hMidiOut, dwMsg); 01033 01034 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 01035 return MMSYSERR_INVALHANDLE; 01036 01037 return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L); 01038 } 01039 01040 /************************************************************************** 01041 * midiOutLongMsg [WINMM.@] 01042 */ 01043 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut, 01044 MIDIHDR* lpMidiOutHdr, UINT uSize) 01045 { 01046 LPWINE_MLD wmld; 01047 01048 TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); 01049 01050 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 01051 return MMSYSERR_INVALHANDLE; 01052 01053 return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize); 01054 } 01055 01056 /************************************************************************** 01057 * midiOutReset [WINMM.@] 01058 */ 01059 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut) 01060 { 01061 LPWINE_MLD wmld; 01062 01063 TRACE("(%p)\n", hMidiOut); 01064 01065 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 01066 return MMSYSERR_INVALHANDLE; 01067 01068 return MMDRV_Message(wmld, MODM_RESET, 0L, 0L); 01069 } 01070 01071 /************************************************************************** 01072 * midiOutGetVolume [WINMM.@] 01073 */ 01074 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume) 01075 { 01076 LPWINE_MLD wmld; 01077 01078 TRACE("(%p, %p);\n", hMidiOut, lpdwVolume); 01079 01080 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) 01081 return MMSYSERR_INVALHANDLE; 01082 01083 return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L); 01084 } 01085 01086 /************************************************************************** 01087 * midiOutSetVolume [WINMM.@] 01088 */ 01089 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume) 01090 { 01091 LPWINE_MLD wmld; 01092 01093 TRACE("(%p, %d);\n", hMidiOut, dwVolume); 01094 01095 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) 01096 return MMSYSERR_INVALHANDLE; 01097 01098 return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L); 01099 } 01100 01101 /************************************************************************** 01102 * midiOutCachePatches [WINMM.@] 01103 */ 01104 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank, 01105 WORD* lpwPatchArray, UINT uFlags) 01106 { 01107 /* not really necessary to support this */ 01108 FIXME("not supported yet\n"); 01109 return MMSYSERR_NOTSUPPORTED; 01110 } 01111 01112 /************************************************************************** 01113 * midiOutCacheDrumPatches [WINMM.@] 01114 */ 01115 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch, 01116 WORD* lpwKeyArray, UINT uFlags) 01117 { 01118 FIXME("not supported yet\n"); 01119 return MMSYSERR_NOTSUPPORTED; 01120 } 01121 01122 /************************************************************************** 01123 * midiOutGetID [WINMM.@] 01124 */ 01125 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID) 01126 { 01127 LPWINE_MLD wmld; 01128 01129 TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID); 01130 01131 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; 01132 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) 01133 return MMSYSERR_INVALHANDLE; 01134 01135 *lpuDeviceID = wmld->uDeviceID; 01136 return MMSYSERR_NOERROR; 01137 } 01138 01139 /************************************************************************** 01140 * midiOutMessage [WINMM.@] 01141 */ 01142 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, 01143 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 01144 { 01145 LPWINE_MLD wmld; 01146 01147 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2); 01148 01149 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) { 01150 /* HACK... */ 01151 if (uMessage == 0x0001) { 01152 *(LPDWORD)dwParam1 = 1; 01153 return 0; 01154 } 01155 if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) { 01156 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); 01157 } 01158 return MMSYSERR_INVALHANDLE; 01159 } 01160 01161 switch (uMessage) { 01162 case MODM_OPEN: 01163 case MODM_CLOSE: 01164 FIXME("can't handle OPEN or CLOSE message!\n"); 01165 return MMSYSERR_NOTSUPPORTED; 01166 } 01167 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); 01168 } 01169 01170 /************************************************************************** 01171 * midiInGetNumDevs [WINMM.@] 01172 */ 01173 UINT WINAPI midiInGetNumDevs(void) 01174 { 01175 return MMDRV_GetNum(MMDRV_MIDIIN); 01176 } 01177 01178 /************************************************************************** 01179 * midiInGetDevCapsW [WINMM.@] 01180 */ 01181 UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize) 01182 { 01183 LPWINE_MLD wmld; 01184 01185 TRACE("(%ld, %p, %d);\n", uDeviceID, lpCaps, uSize); 01186 01187 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 01188 01189 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL) 01190 return MMSYSERR_INVALHANDLE; 01191 01192 return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 01193 } 01194 01195 /************************************************************************** 01196 * midiInGetDevCapsA [WINMM.@] 01197 */ 01198 UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize) 01199 { 01200 MIDIINCAPSW micW; 01201 UINT ret; 01202 01203 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 01204 01205 ret = midiInGetDevCapsW(uDeviceID, &micW, sizeof(micW)); 01206 01207 if (ret == MMSYSERR_NOERROR) { 01208 MIDIINCAPSA micA; 01209 micA.wMid = micW.wMid; 01210 micA.wPid = micW.wPid; 01211 micA.vDriverVersion = micW.vDriverVersion; 01212 WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, 01213 sizeof(micA.szPname), NULL, NULL ); 01214 micA.dwSupport = micW.dwSupport; 01215 memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); 01216 } 01217 return ret; 01218 } 01219 01220 /************************************************************************** 01221 * midiInOpen [WINMM.@] 01222 */ 01223 MMRESULT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, 01224 DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags) 01225 { 01226 HANDLE hMidiIn; 01227 LPWINE_MIDI lpwm; 01228 DWORD dwRet = 0; 01229 01230 TRACE("(%p, %d, %08lX, %08lX, %08X);\n", 01231 lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags); 01232 01233 if (lphMidiIn != NULL) *lphMidiIn = 0; 01234 01235 lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn, 01236 &dwFlags, &dwCallback, &dwInstance); 01237 01238 if (lpwm == NULL) 01239 return MMSYSERR_NOMEM; 01240 01241 lpwm->mod.hMidi = hMidiIn; 01242 lpwm->mod.dwCallback = dwCallback; 01243 lpwm->mod.dwInstance = dwInstance; 01244 01245 lpwm->mld.uDeviceID = uDeviceID; 01246 dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD_PTR)&lpwm->mod, dwFlags); 01247 01248 if (dwRet != MMSYSERR_NOERROR) { 01249 MMDRV_Free(hMidiIn, &lpwm->mld); 01250 hMidiIn = 0; 01251 } 01252 if (lphMidiIn != NULL) *lphMidiIn = hMidiIn; 01253 TRACE("=> %d hMidi=%p\n", dwRet, hMidiIn); 01254 01255 return dwRet; 01256 } 01257 01258 /************************************************************************** 01259 * midiInClose [WINMM.@] 01260 */ 01261 UINT WINAPI midiInClose(HMIDIIN hMidiIn) 01262 { 01263 LPWINE_MLD wmld; 01264 DWORD dwRet; 01265 01266 TRACE("(%p)\n", hMidiIn); 01267 01268 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 01269 return MMSYSERR_INVALHANDLE; 01270 01271 dwRet = MMDRV_Close(wmld, MIDM_CLOSE); 01272 MMDRV_Free(hMidiIn, wmld); 01273 return dwRet; 01274 } 01275 01276 /************************************************************************** 01277 * midiInPrepareHeader [WINMM.@] 01278 */ 01279 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn, 01280 MIDIHDR* lpMidiInHdr, UINT uSize) 01281 { 01282 LPWINE_MLD wmld; 01283 01284 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); 01285 01286 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) 01287 return MMSYSERR_INVALPARAM; 01288 01289 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 01290 return MMSYSERR_INVALHANDLE; 01291 01292 return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize); 01293 } 01294 01295 /************************************************************************** 01296 * midiInUnprepareHeader [WINMM.@] 01297 */ 01298 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn, 01299 MIDIHDR* lpMidiInHdr, UINT uSize) 01300 { 01301 LPWINE_MLD wmld; 01302 01303 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); 01304 01305 if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) 01306 return MMSYSERR_INVALPARAM; 01307 01308 if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) { 01309 return MMSYSERR_NOERROR; 01310 } 01311 01312 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 01313 return MMSYSERR_INVALHANDLE; 01314 01315 return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize); 01316 } 01317 01318 /************************************************************************** 01319 * midiInAddBuffer [WINMM.@] 01320 */ 01321 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn, 01322 MIDIHDR* lpMidiInHdr, UINT uSize) 01323 { 01324 LPWINE_MLD wmld; 01325 01326 TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); 01327 01328 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 01329 return MMSYSERR_INVALHANDLE; 01330 01331 return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize); 01332 } 01333 01334 /************************************************************************** 01335 * midiInStart [WINMM.@] 01336 */ 01337 UINT WINAPI midiInStart(HMIDIIN hMidiIn) 01338 { 01339 LPWINE_MLD wmld; 01340 01341 TRACE("(%p)\n", hMidiIn); 01342 01343 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 01344 return MMSYSERR_INVALHANDLE; 01345 01346 return MMDRV_Message(wmld, MIDM_START, 0L, 0L); 01347 } 01348 01349 /************************************************************************** 01350 * midiInStop [WINMM.@] 01351 */ 01352 UINT WINAPI midiInStop(HMIDIIN hMidiIn) 01353 { 01354 LPWINE_MLD wmld; 01355 01356 TRACE("(%p)\n", hMidiIn); 01357 01358 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 01359 return MMSYSERR_INVALHANDLE; 01360 01361 return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L); 01362 } 01363 01364 /************************************************************************** 01365 * midiInReset [WINMM.@] 01366 */ 01367 UINT WINAPI midiInReset(HMIDIIN hMidiIn) 01368 { 01369 LPWINE_MLD wmld; 01370 01371 TRACE("(%p)\n", hMidiIn); 01372 01373 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 01374 return MMSYSERR_INVALHANDLE; 01375 01376 return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L); 01377 } 01378 01379 /************************************************************************** 01380 * midiInGetID [WINMM.@] 01381 */ 01382 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID) 01383 { 01384 LPWINE_MLD wmld; 01385 01386 TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID); 01387 01388 if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; 01389 01390 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL) 01391 return MMSYSERR_INVALHANDLE; 01392 01393 *lpuDeviceID = wmld->uDeviceID; 01394 01395 return MMSYSERR_NOERROR; 01396 } 01397 01398 /************************************************************************** 01399 * midiInMessage [WINMM.@] 01400 */ 01401 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, 01402 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 01403 { 01404 LPWINE_MLD wmld; 01405 01406 TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2); 01407 01408 if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) 01409 return MMSYSERR_INVALHANDLE; 01410 01411 switch (uMessage) { 01412 case MIDM_OPEN: 01413 case MIDM_CLOSE: 01414 FIXME("can't handle OPEN or CLOSE message!\n"); 01415 return MMSYSERR_NOTSUPPORTED; 01416 } 01417 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); 01418 } 01419 01420 /************************************************************************** 01421 * midiConnect [WINMM.@] 01422 */ 01423 MMRESULT WINAPI midiConnect(HMIDI hMidi, HMIDIOUT hmo, LPVOID pReserved) 01424 { 01425 FIXME("(%p, %p, %p): Stub\n", hMidi, hmo, pReserved); 01426 return MMSYSERR_ERROR; 01427 } 01428 01429 /************************************************************************** 01430 * midiDisconnect [WINMM.@] 01431 */ 01432 MMRESULT WINAPI midiDisconnect(HMIDI hMidi, HMIDIOUT hmo, LPVOID pReserved) 01433 { 01434 FIXME("(%p, %p, %p): Stub\n", hMidi, hmo, pReserved); 01435 return MMSYSERR_ERROR; 01436 } 01437 01438 typedef struct WINE_MIDIStream { 01439 HMIDIOUT hDevice; 01440 HANDLE hThread; 01441 DWORD dwThreadID; 01442 DWORD dwTempo; 01443 DWORD dwTimeDiv; 01444 DWORD dwPositionMS; 01445 DWORD dwPulses; 01446 DWORD dwStartTicks; 01447 WORD wFlags; 01448 HANDLE hEvent; 01449 LPMIDIHDR lpMidiHdr; 01450 } WINE_MIDIStream; 01451 01452 #define WINE_MSM_HEADER (WM_USER+0) 01453 #define WINE_MSM_STOP (WM_USER+1) 01454 01455 /************************************************************************** 01456 * MMSYSTEM_GetMidiStream [internal] 01457 */ 01458 static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm) 01459 { 01460 WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE); 01461 01462 if (lplpwm) 01463 *lplpwm = lpwm; 01464 01465 if (lpwm == NULL) { 01466 return FALSE; 01467 } 01468 01469 *lpMidiStrm = (WINE_MIDIStream*)(ULONG_PTR)lpwm->mod.rgIds.dwStreamID; // FIXME: not 64 bit safe 01470 01471 return *lpMidiStrm != NULL; 01472 } 01473 01474 /************************************************************************** 01475 * MMSYSTEM_MidiStream_Convert [internal] 01476 */ 01477 static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse) 01478 { 01479 DWORD ret = 0; 01480 01481 if (lpMidiStrm->dwTimeDiv == 0) { 01482 FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n"); 01483 } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */ 01484 int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */ 01485 int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */ 01486 ret = (pulse * 1000) / (nf * nsf); 01487 } else { 01488 ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) / 01489 (double)lpMidiStrm->dwTimeDiv); 01490 } 01491 01492 return ret; 01493 } 01494 01495 /************************************************************************** 01496 * MMSYSTEM_MidiStream_MessageHandler [internal] 01497 */ 01498 static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg) 01499 { 01500 LPMIDIHDR lpMidiHdr; 01501 LPMIDIHDR* lpmh; 01502 LPBYTE lpData; 01503 01504 switch (msg->message) { 01505 case WM_QUIT: 01506 SetEvent(lpMidiStrm->hEvent); 01507 return FALSE; 01508 case WINE_MSM_STOP: 01509 TRACE("STOP\n"); 01510 /* this is not quite what MS doc says... */ 01511 midiOutReset(lpMidiStrm->hDevice); 01512 /* empty list of already submitted buffers */ 01513 for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = lpMidiHdr->lpNext) { 01514 lpMidiHdr->dwFlags |= MHDR_DONE; 01515 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; 01516 01517 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, 01518 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, 01519 lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0); 01520 } 01521 lpMidiStrm->lpMidiHdr = 0; 01522 SetEvent(lpMidiStrm->hEvent); 01523 break; 01524 case WINE_MSM_HEADER: 01525 /* sets initial tick count for first MIDIHDR */ 01526 if (!lpMidiStrm->dwStartTicks) 01527 lpMidiStrm->dwStartTicks = GetTickCount(); 01528 01529 /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent 01530 * by native mcimidi, it doesn't look like a correct one". 01531 * this trick allows to throw it away... but I don't like it. 01532 * It looks like part of the file I'm trying to play and definitively looks 01533 * like raw midi content 01534 * I'd really like to understand why native mcimidi sends it. Perhaps a bad 01535 * synchronization issue where native mcimidi is still processing raw MIDI 01536 * content before generating MIDIEVENTs ? 01537 * 01538 * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^.. 01539 * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b.. 01540 * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^. 01541 * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x. 01542 * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^ 01543 * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b 01544 * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..# 01545 * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L.. 01546 * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H.. 01547 * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?. 01548 * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E. 01549 * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F 01550 * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H 01551 * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.; 01552 * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.; 01553 * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|. 01554 * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|. 01555 */ 01556 lpMidiHdr = (LPMIDIHDR)msg->lParam; 01557 lpData = (LPBYTE)lpMidiHdr->lpData; 01558 TRACE("Adding %s lpMidiHdr=%p [lpData=0x%p dwBufferLength=%u/%u dwFlags=0x%08x size=%lu]\n", 01559 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr, 01560 lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded, 01561 lpMidiHdr->dwFlags, msg->wParam); 01562 #if 0 01563 /* dumps content of lpMidiHdr->lpData 01564 * FIXME: there should be a debug routine somewhere that already does this 01565 * I hate spreading this type of shit all around the code 01566 */ 01567 for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) { 01568 DWORD i; 01569 BYTE ch; 01570 01571 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) 01572 printf("%02x ", lpData[dwToGo + i]); 01573 for (; i < 16; i++) 01574 printf(" "); 01575 for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) { 01576 ch = lpData[dwToGo + i]; 01577 printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.'); 01578 } 01579 printf("\n"); 01580 } 01581 #endif 01582 if (((LPMIDIEVENT)lpData)->dwStreamID != 0 && 01583 ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF && 01584 /* FIXME: not 64 bit safe */ 01585 ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD_PTR)lpMidiStrm) { 01586 FIXME("Dropping bad %s lpMidiHdr (streamID=%08x)\n", 01587 (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", 01588 ((LPMIDIEVENT)lpData)->dwStreamID); 01589 lpMidiHdr->dwFlags |= MHDR_DONE; 01590 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; 01591 01592 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, 01593 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, 01594 lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0); 01595 break; 01596 } 01597 01598 for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = &(*lpmh)->lpNext); 01599 *lpmh = lpMidiHdr; 01600 lpMidiHdr = (LPMIDIHDR)msg->lParam; 01601 lpMidiHdr->lpNext = 0; 01602 lpMidiHdr->dwFlags |= MHDR_INQUEUE; 01603 lpMidiHdr->dwFlags &= ~MHDR_DONE; 01604 lpMidiHdr->dwOffset = 0; 01605 01606 break; 01607 default: 01608 FIXME("Unknown message %d\n", msg->message); 01609 break; 01610 } 01611 return TRUE; 01612 } 01613 01614 /************************************************************************** 01615 * MMSYSTEM_MidiStream_Player [internal] 01616 */ 01617 static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt) 01618 { 01619 WINE_MIDIStream* lpMidiStrm = pmt; 01620 WINE_MIDI* lpwm; 01621 MSG msg; 01622 DWORD dwToGo; 01623 DWORD dwCurrTC; 01624 LPMIDIHDR lpMidiHdr; 01625 LPMIDIEVENT me; 01626 LPBYTE lpData = 0; 01627 01628 TRACE("(%p)!\n", lpMidiStrm); 01629 01630 if (!lpMidiStrm || 01631 (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL) 01632 goto the_end; 01633 01634 /* force thread's queue creation */ 01635 /* Used to be InitThreadInput16(0, 5); */ 01636 /* but following works also with hack in midiStreamOpen */ 01637 PeekMessageA(&msg, 0, 0, 0, 0); 01638 01639 /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */ 01640 SetEvent(lpMidiStrm->hEvent); 01641 TRACE("Ready to go 1\n"); 01642 /* thread is started in paused mode */ 01643 SuspendThread(lpMidiStrm->hThread); 01644 TRACE("Ready to go 2\n"); 01645 01646 lpMidiStrm->dwStartTicks = 0; 01647 lpMidiStrm->dwPulses = 0; 01648 01649 lpMidiStrm->lpMidiHdr = 0; 01650 01651 for (;;) { 01652 lpMidiHdr = lpMidiStrm->lpMidiHdr; 01653 if (!lpMidiHdr) { 01654 /* for first message, block until one arrives, then process all that are available */ 01655 GetMessageA(&msg, 0, 0, 0); 01656 do { 01657 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) 01658 goto the_end; 01659 } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)); 01660 lpData = 0; 01661 continue; 01662 } 01663 01664 if (!lpData) 01665 lpData = (LPBYTE)lpMidiHdr->lpData; 01666 01667 me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset); 01668 01669 /* do we have to wait ? */ 01670 if (me->dwDeltaTime) { 01671 lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime); 01672 lpMidiStrm->dwPulses += me->dwDeltaTime; 01673 01674 dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS; 01675 01676 TRACE("%d/%d/%d\n", dwToGo, GetTickCount(), me->dwDeltaTime); 01677 while ((dwCurrTC = GetTickCount()) < dwToGo) { 01678 if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) { 01679 /* got a message, handle it */ 01680 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { 01681 if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) 01682 goto the_end; 01683 } 01684 lpData = 0; 01685 } else { 01686 /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */ 01687 break; 01688 } 01689 } 01690 } 01691 switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) { 01692 case MEVT_COMMENT: 01693 FIXME("NIY: MEVT_COMMENT\n"); 01694 /* do nothing, skip bytes */ 01695 break; 01696 case MEVT_LONGMSG: 01697 FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n"); 01698 break; 01699 case MEVT_NOP: 01700 break; 01701 case MEVT_SHORTMSG: 01702 midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent)); 01703 break; 01704 case MEVT_TEMPO: 01705 lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent); 01706 break; 01707 case MEVT_VERSION: 01708 break; 01709 default: 01710 FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)); 01711 break; 01712 } 01713 if (me->dwEvent & MEVT_F_CALLBACK) { 01714 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, 01715 (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB, 01716 lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L); 01717 } 01718 lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms); 01719 if (me->dwEvent & MEVT_F_LONG) 01720 lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3; 01721 if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) { 01722 /* done with this header */ 01723 lpMidiHdr->dwFlags |= MHDR_DONE; 01724 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; 01725 01726 lpMidiStrm->lpMidiHdr = lpMidiHdr->lpNext; 01727 DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, 01728 (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, 01729 lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0); 01730 lpData = 0; 01731 } 01732 } 01733 the_end: 01734 TRACE("End of thread\n"); 01735 ExitThread(0); 01736 return 0; /* for removing the warning, never executed */ 01737 } 01738 01739 /************************************************************************** 01740 * MMSYSTEM_MidiStream_PostMessage [internal] 01741 */ 01742 static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2) 01743 { 01744 if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) { 01745 //DWORD count; 01746 01747 //ReleaseThunkLock(&count); 01748 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); 01749 //RestoreThunkLock(count); 01750 } else { 01751 WARN("bad PostThreadMessageA\n"); 01752 return FALSE; 01753 } 01754 return TRUE; 01755 } 01756 01757 /************************************************************************** 01758 * midiStreamClose [WINMM.@] 01759 */ 01760 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm) 01761 { 01762 WINE_MIDIStream* lpMidiStrm; 01763 01764 TRACE("(%p)!\n", hMidiStrm); 01765 01766 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) 01767 return MMSYSERR_INVALHANDLE; 01768 01769 midiStreamStop(hMidiStrm); 01770 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0); 01771 HeapFree(GetProcessHeap(), 0, lpMidiStrm); 01772 CloseHandle(lpMidiStrm->hEvent); 01773 01774 return midiOutClose((HMIDIOUT)hMidiStrm); 01775 } 01776 01777 /************************************************************************** 01778 * midiStreamOpen [WINMM.@] 01779 */ 01780 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, 01781 DWORD cMidi, DWORD_PTR dwCallback, 01782 DWORD_PTR dwInstance, DWORD fdwOpen) 01783 { 01784 WINE_MIDIStream* lpMidiStrm; 01785 MMRESULT ret; 01786 MIDIOPENSTRMID mosm; 01787 LPWINE_MIDI lpwm; 01788 HMIDIOUT hMidiOut; 01789 01790 TRACE("(%p, %p, %d, 0x%08lx, 0x%08lx, 0x%08x)!\n", 01791 lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen); 01792 01793 if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL) 01794 return MMSYSERR_INVALPARAM; 01795 01796 lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream)); 01797 if (!lpMidiStrm) 01798 return MMSYSERR_NOMEM; 01799 01800 lpMidiStrm->dwTempo = 500000; 01801 lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quarter notes per minute *//* FIXME ??*/ 01802 lpMidiStrm->dwPositionMS = 0; 01803 01804 mosm.dwStreamID = (DWORD_PTR)lpMidiStrm; // FIXME: not 64 bit safe 01805 /* FIXME: the correct value is not allocated yet for MAPPER */ 01806 mosm.wDeviceID = *lpuDeviceID; 01807 lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm); 01808 lpMidiStrm->hDevice = hMidiOut; 01809 if (lphMidiStrm) 01810 *lphMidiStrm = (HMIDISTRM)hMidiOut; 01811 01812 lpwm->mld.uDeviceID = *lpuDeviceID; 01813 01814 ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD_PTR)&lpwm->mod, fdwOpen); 01815 lpMidiStrm->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); 01816 lpMidiStrm->wFlags = HIWORD(fdwOpen); 01817 01818 lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player, 01819 lpMidiStrm, 0, &(lpMidiStrm->dwThreadID)); 01820 01821 if (!lpMidiStrm->hThread) { 01822 midiStreamClose((HMIDISTRM)hMidiOut); 01823 return MMSYSERR_NOMEM; 01824 } 01825 SetThreadPriority(lpMidiStrm->hThread, THREAD_PRIORITY_TIME_CRITICAL); 01826 01827 /* wait for thread to have started, and for its queue to be created */ 01828 { 01829 //DWORD count; 01830 01831 /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code, 01832 * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running 01833 * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue. 01834 */ 01835 //ReleaseThunkLock(&count); 01836 WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); 01837 //RestoreThunkLock(count); 01838 } 01839 01840 TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n", 01841 *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm); 01842 return ret; 01843 } 01844 01845 /************************************************************************** 01846 * midiStreamOut [WINMM.@] 01847 */ 01848 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, 01849 UINT cbMidiHdr) 01850 { 01851 WINE_MIDIStream* lpMidiStrm; 01852 DWORD ret = MMSYSERR_NOERROR; 01853 01854 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr); 01855 01856 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 01857 ret = MMSYSERR_INVALHANDLE; 01858 } else if (!lpMidiHdr) { 01859 ret = MMSYSERR_INVALPARAM; 01860 } else { 01861 if (!PostThreadMessageA(lpMidiStrm->dwThreadID, 01862 WINE_MSM_HEADER, cbMidiHdr, 01863 (LPARAM)lpMidiHdr)) { 01864 WARN("bad PostThreadMessageA\n"); 01865 ret = MMSYSERR_ERROR; 01866 } 01867 } 01868 return ret; 01869 } 01870 01871 /************************************************************************** 01872 * midiStreamPause [WINMM.@] 01873 */ 01874 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm) 01875 { 01876 WINE_MIDIStream* lpMidiStrm; 01877 DWORD ret = MMSYSERR_NOERROR; 01878 01879 TRACE("(%p)!\n", hMidiStrm); 01880 01881 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 01882 ret = MMSYSERR_INVALHANDLE; 01883 } else { 01884 if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) { 01885 WARN("bad Suspend (%d)\n", GetLastError()); 01886 ret = MMSYSERR_ERROR; 01887 } 01888 } 01889 return ret; 01890 } 01891 01892 /************************************************************************** 01893 * midiStreamPosition [WINMM.@] 01894 */ 01895 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt) 01896 { 01897 WINE_MIDIStream* lpMidiStrm; 01898 DWORD ret = MMSYSERR_NOERROR; 01899 01900 TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt); 01901 01902 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 01903 ret = MMSYSERR_INVALHANDLE; 01904 } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) { 01905 ret = MMSYSERR_INVALPARAM; 01906 } else { 01907 switch (lpMMT->wType) { 01908 case TIME_MS: 01909 lpMMT->u.ms = lpMidiStrm->dwPositionMS; 01910 TRACE("=> %d ms\n", lpMMT->u.ms); 01911 break; 01912 case TIME_TICKS: 01913 lpMMT->u.ticks = lpMidiStrm->dwPulses; 01914 TRACE("=> %d ticks\n", lpMMT->u.ticks); 01915 break; 01916 default: 01917 WARN("Unsupported time type %d\n", lpMMT->wType); 01918 lpMMT->wType = TIME_MS; 01919 ret = MMSYSERR_INVALPARAM; 01920 break; 01921 } 01922 } 01923 return ret; 01924 } 01925 01926 /************************************************************************** 01927 * midiStreamProperty [WINMM.@] 01928 */ 01929 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) 01930 { 01931 WINE_MIDIStream* lpMidiStrm; 01932 MMRESULT ret = MMSYSERR_NOERROR; 01933 01934 TRACE("(%p, %p, %x)\n", hMidiStrm, lpPropData, dwProperty); 01935 01936 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 01937 ret = MMSYSERR_INVALHANDLE; 01938 } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) { 01939 ret = MMSYSERR_INVALPARAM; 01940 } else if (dwProperty & MIDIPROP_TEMPO) { 01941 MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData; 01942 01943 if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) { 01944 ret = MMSYSERR_INVALPARAM; 01945 } else if (dwProperty & MIDIPROP_SET) { 01946 lpMidiStrm->dwTempo = mpt->dwTempo; 01947 TRACE("Setting tempo to %d\n", mpt->dwTempo); 01948 } else if (dwProperty & MIDIPROP_GET) { 01949 mpt->dwTempo = lpMidiStrm->dwTempo; 01950 TRACE("Getting tempo <= %d\n", mpt->dwTempo); 01951 } 01952 } else if (dwProperty & MIDIPROP_TIMEDIV) { 01953 MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData; 01954 01955 if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) { 01956 ret = MMSYSERR_INVALPARAM; 01957 } else if (dwProperty & MIDIPROP_SET) { 01958 lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv; 01959 TRACE("Setting time div to %d\n", mptd->dwTimeDiv); 01960 } else if (dwProperty & MIDIPROP_GET) { 01961 mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv; 01962 TRACE("Getting time div <= %d\n", mptd->dwTimeDiv); 01963 } 01964 } else { 01965 ret = MMSYSERR_INVALPARAM; 01966 } 01967 01968 return ret; 01969 } 01970 01971 /************************************************************************** 01972 * midiStreamRestart [WINMM.@] 01973 */ 01974 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm) 01975 { 01976 WINE_MIDIStream* lpMidiStrm; 01977 MMRESULT ret = MMSYSERR_NOERROR; 01978 01979 TRACE("(%p)!\n", hMidiStrm); 01980 01981 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 01982 ret = MMSYSERR_INVALHANDLE; 01983 } else { 01984 DWORD ret; 01985 01986 /* since we increase the thread suspend count on each midiStreamPause 01987 * there may be a need for several midiStreamResume 01988 */ 01989 do { 01990 ret = ResumeThread(lpMidiStrm->hThread); 01991 } while (ret != 0xFFFFFFFF && ret != 0); 01992 if (ret == 0xFFFFFFFF) { 01993 WARN("bad Resume (%d)\n", GetLastError()); 01994 ret = MMSYSERR_ERROR; 01995 } else { 01996 lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS; 01997 } 01998 } 01999 return ret; 02000 } 02001 02002 /************************************************************************** 02003 * midiStreamStop [WINMM.@] 02004 */ 02005 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm) 02006 { 02007 WINE_MIDIStream* lpMidiStrm; 02008 MMRESULT ret = MMSYSERR_NOERROR; 02009 02010 TRACE("(%p)!\n", hMidiStrm); 02011 02012 if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { 02013 ret = MMSYSERR_INVALHANDLE; 02014 } else { 02015 /* in case stream has been paused... FIXME is the current state correct ? */ 02016 midiStreamRestart(hMidiStrm); 02017 MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0); 02018 } 02019 return ret; 02020 } 02021 02022 static UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, 02023 LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, 02024 DWORD_PTR dwInstance, DWORD dwFlags) 02025 { 02026 HANDLE handle; 02027 LPWINE_MLD wmld; 02028 DWORD dwRet = MMSYSERR_NOERROR; 02029 WAVEOPENDESC wod; 02030 02031 TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08X);\n", 02032 lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback, 02033 dwInstance, dwFlags); 02034 02035 if (dwFlags & WAVE_FORMAT_QUERY) 02036 TRACE("WAVE_FORMAT_QUERY requested !\n"); 02037 02038 if (lpFormat == NULL) { 02039 WARN("bad format\n"); 02040 return WAVERR_BADFORMAT; 02041 } 02042 02043 if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) { 02044 WARN("invalid parameter\n"); 02045 return MMSYSERR_INVALPARAM; 02046 } 02047 02048 /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */ 02049 TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u\n", 02050 lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec, 02051 lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample); 02052 02053 if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle, 02054 &dwFlags, &dwCallback, &dwInstance)) == NULL) { 02055 WARN("no memory\n"); 02056 return MMSYSERR_NOMEM; 02057 } 02058 02059 wod.hWave = handle; 02060 wod.lpFormat = (LPWAVEFORMATEX)lpFormat; /* should the struct be copied iso pointer? */ 02061 wod.dwCallback = dwCallback; 02062 wod.dwInstance = dwInstance; 02063 wod.dnDevNode = 0L; 02064 02065 TRACE("cb=%08lx\n", wod.dwCallback); 02066 02067 for (;;) { 02068 if (dwFlags & WAVE_MAPPED) { 02069 wod.uMappedDeviceID = uDeviceID; 02070 uDeviceID = WAVE_MAPPER; 02071 } else { 02072 wod.uMappedDeviceID = -1; 02073 } 02074 wmld->uDeviceID = uDeviceID; 02075 02076 dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, 02077 (DWORD_PTR)&wod, dwFlags); 02078 02079 TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet)); 02080 if (dwRet != WAVERR_BADFORMAT || 02081 ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break; 02082 /* if we ask for a format which isn't supported by the physical driver, 02083 * let's try to map it through the wave mapper (except, if we already tried 02084 * or user didn't allow us to use acm codecs or the device is already the mapper) 02085 */ 02086 dwFlags |= WAVE_MAPPED; 02087 /* we shall loop only one */ 02088 } 02089 02090 if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) { 02091 MMDRV_Free(handle, wmld); 02092 handle = 0; 02093 } 02094 02095 if (lphndl != NULL) *lphndl = handle; 02096 TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle); 02097 02098 return dwRet; 02099 } 02100 02101 /************************************************************************** 02102 * waveOutGetNumDevs [WINMM.@] 02103 */ 02104 UINT WINAPI waveOutGetNumDevs(void) 02105 { 02106 return MMDRV_GetNum(MMDRV_WAVEOUT); 02107 } 02108 02109 /************************************************************************** 02110 * waveOutGetDevCapsA [WINMM.@] 02111 */ 02112 UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps, 02113 UINT uSize) 02114 { 02115 WAVEOUTCAPSW wocW; 02116 UINT ret; 02117 02118 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 02119 02120 ret = waveOutGetDevCapsW(uDeviceID, &wocW, sizeof(wocW)); 02121 02122 if (ret == MMSYSERR_NOERROR) { 02123 WAVEOUTCAPSA wocA; 02124 wocA.wMid = wocW.wMid; 02125 wocA.wPid = wocW.wPid; 02126 wocA.vDriverVersion = wocW.vDriverVersion; 02127 WideCharToMultiByte( CP_ACP, 0, wocW.szPname, -1, wocA.szPname, 02128 sizeof(wocA.szPname), NULL, NULL ); 02129 wocA.dwFormats = wocW.dwFormats; 02130 wocA.wChannels = wocW.wChannels; 02131 wocA.dwSupport = wocW.dwSupport; 02132 memcpy(lpCaps, &wocA, min(uSize, sizeof(wocA))); 02133 } 02134 return ret; 02135 } 02136 02137 /************************************************************************** 02138 * waveOutGetDevCapsW [WINMM.@] 02139 */ 02140 UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps, 02141 UINT uSize) 02142 { 02143 LPWINE_MLD wmld; 02144 02145 TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize); 02146 02147 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 02148 02149 if (uDeviceID == WAVE_MAPPER) 02150 { 02151 FIXME("Support WAVE_MAPPER\n"); 02152 uDeviceID = 0; 02153 } 02154 02155 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL) 02156 return MMSYSERR_BADDEVICEID; 02157 02158 return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 02159 } 02160 02161 /************************************************************************** 02162 * waveOutGetErrorTextA [WINMM.@] 02163 * waveInGetErrorTextA [WINMM.@] 02164 */ 02165 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) 02166 { 02167 UINT ret; 02168 02169 if (lpText == NULL) ret = MMSYSERR_INVALPARAM; 02170 else if (uSize == 0) ret = MMSYSERR_NOERROR; 02171 else 02172 { 02173 LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); 02174 if (!xstr) ret = MMSYSERR_NOMEM; 02175 else 02176 { 02177 ret = waveOutGetErrorTextW(uError, xstr, uSize); 02178 if (ret == MMSYSERR_NOERROR) 02179 WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); 02180 HeapFree(GetProcessHeap(), 0, xstr); 02181 } 02182 } 02183 return ret; 02184 } 02185 02186 /************************************************************************** 02187 * waveOutGetErrorTextW [WINMM.@] 02188 * waveInGetErrorTextW [WINMM.@] 02189 */ 02190 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) 02191 { 02192 UINT ret = MMSYSERR_BADERRNUM; 02193 02194 if (lpText == NULL) ret = MMSYSERR_INVALPARAM; 02195 else if (uSize == 0) ret = MMSYSERR_NOERROR; 02196 else if ( 02197 /* test has been removed because MMSYSERR_BASE is 0, and gcc did emit 02198 * a warning for the test was always true */ 02199 (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || 02200 (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) { 02201 if (LoadStringW(hWinMM32Instance, 02202 uError, lpText, uSize) > 0) { 02203 ret = MMSYSERR_NOERROR; 02204 } 02205 } 02206 return ret; 02207 } 02208 02209 /************************************************************************** 02210 * waveOutOpen [WINMM.@] 02211 * All the args/structs have the same layout as the win16 equivalents 02212 */ 02213 MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID, 02214 LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, 02215 DWORD_PTR dwInstance, DWORD dwFlags) 02216 { 02217 return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat, 02218 dwCallback, dwInstance, dwFlags); 02219 } 02220 02221 /************************************************************************** 02222 * waveOutClose [WINMM.@] 02223 */ 02224 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut) 02225 { 02226 LPWINE_MLD wmld; 02227 DWORD dwRet; 02228 02229 TRACE("(%p)\n", hWaveOut); 02230 02231 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02232 return MMSYSERR_INVALHANDLE; 02233 02234 dwRet = MMDRV_Close(wmld, WODM_CLOSE); 02235 if (dwRet != WAVERR_STILLPLAYING) 02236 MMDRV_Free(hWaveOut, wmld); 02237 02238 return dwRet; 02239 } 02240 02241 /************************************************************************** 02242 * waveOutPrepareHeader [WINMM.@] 02243 */ 02244 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, 02245 WAVEHDR* lpWaveOutHdr, UINT uSize) 02246 { 02247 LPWINE_MLD wmld; 02248 UINT result; 02249 02250 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); 02251 02252 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) 02253 return MMSYSERR_INVALPARAM; 02254 02255 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02256 return MMSYSERR_INVALHANDLE; 02257 02258 if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, 02259 uSize)) != MMSYSERR_NOTSUPPORTED) 02260 return result; 02261 02262 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) 02263 return WAVERR_STILLPLAYING; 02264 02265 lpWaveOutHdr->dwFlags |= WHDR_PREPARED; 02266 lpWaveOutHdr->dwFlags &= ~WHDR_DONE; 02267 02268 return MMSYSERR_NOERROR; 02269 } 02270 02271 /************************************************************************** 02272 * waveOutUnprepareHeader [WINMM.@] 02273 */ 02274 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, 02275 LPWAVEHDR lpWaveOutHdr, UINT uSize) 02276 { 02277 LPWINE_MLD wmld; 02278 UINT result; 02279 02280 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); 02281 02282 if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) 02283 return MMSYSERR_INVALPARAM; 02284 02285 if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { 02286 return MMSYSERR_NOERROR; 02287 } 02288 02289 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02290 return MMSYSERR_INVALHANDLE; 02291 02292 if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, 02293 uSize)) != MMSYSERR_NOTSUPPORTED) 02294 return result; 02295 02296 if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) 02297 return WAVERR_STILLPLAYING; 02298 02299 lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED; 02300 lpWaveOutHdr->dwFlags |= WHDR_DONE; 02301 02302 return MMSYSERR_NOERROR; 02303 } 02304 02305 /************************************************************************** 02306 * waveOutWrite [WINMM.@] 02307 */ 02308 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, 02309 UINT uSize) 02310 { 02311 LPWINE_MLD wmld; 02312 02313 TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); 02314 02315 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02316 return MMSYSERR_INVALHANDLE; 02317 02318 return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize); 02319 } 02320 02321 /************************************************************************** 02322 * waveOutBreakLoop [WINMM.@] 02323 */ 02324 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut) 02325 { 02326 LPWINE_MLD wmld; 02327 02328 TRACE("(%p);\n", hWaveOut); 02329 02330 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02331 return MMSYSERR_INVALHANDLE; 02332 return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L); 02333 } 02334 02335 /************************************************************************** 02336 * waveOutPause [WINMM.@] 02337 */ 02338 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut) 02339 { 02340 LPWINE_MLD wmld; 02341 02342 TRACE("(%p);\n", hWaveOut); 02343 02344 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02345 return MMSYSERR_INVALHANDLE; 02346 return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L); 02347 } 02348 02349 /************************************************************************** 02350 * waveOutReset [WINMM.@] 02351 */ 02352 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut) 02353 { 02354 LPWINE_MLD wmld; 02355 02356 TRACE("(%p);\n", hWaveOut); 02357 02358 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02359 return MMSYSERR_INVALHANDLE; 02360 return MMDRV_Message(wmld, WODM_RESET, 0L, 0L); 02361 } 02362 02363 /************************************************************************** 02364 * waveOutRestart [WINMM.@] 02365 */ 02366 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut) 02367 { 02368 LPWINE_MLD wmld; 02369 02370 TRACE("(%p);\n", hWaveOut); 02371 02372 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02373 return MMSYSERR_INVALHANDLE; 02374 return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L); 02375 } 02376 02377 /************************************************************************** 02378 * waveOutGetPosition [WINMM.@] 02379 */ 02380 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime, 02381 UINT uSize) 02382 { 02383 LPWINE_MLD wmld; 02384 02385 TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize); 02386 02387 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02388 return MMSYSERR_INVALHANDLE; 02389 02390 return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize); 02391 } 02392 02393 /************************************************************************** 02394 * waveOutGetPitch [WINMM.@] 02395 */ 02396 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw) 02397 { 02398 LPWINE_MLD wmld; 02399 02400 TRACE("(%p, %p);\n", hWaveOut, lpdw); 02401 02402 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02403 return MMSYSERR_INVALHANDLE; 02404 return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L); 02405 } 02406 02407 /************************************************************************** 02408 * waveOutSetPitch [WINMM.@] 02409 */ 02410 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw) 02411 { 02412 LPWINE_MLD wmld; 02413 02414 TRACE("(%p, %08x);\n", hWaveOut, dw); 02415 02416 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02417 return MMSYSERR_INVALHANDLE; 02418 return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L); 02419 } 02420 02421 /************************************************************************** 02422 * waveOutGetPlaybackRate [WINMM.@] 02423 */ 02424 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw) 02425 { 02426 LPWINE_MLD wmld; 02427 02428 TRACE("(%p, %p);\n", hWaveOut, lpdw); 02429 02430 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02431 return MMSYSERR_INVALHANDLE; 02432 return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L); 02433 } 02434 02435 /************************************************************************** 02436 * waveOutSetPlaybackRate [WINMM.@] 02437 */ 02438 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw) 02439 { 02440 LPWINE_MLD wmld; 02441 02442 TRACE("(%p, %08x);\n", hWaveOut, dw); 02443 02444 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02445 return MMSYSERR_INVALHANDLE; 02446 return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L); 02447 } 02448 02449 /************************************************************************** 02450 * waveOutGetVolume [WINMM.@] 02451 */ 02452 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw) 02453 { 02454 LPWINE_MLD wmld; 02455 02456 TRACE("(%p, %p);\n", hWaveOut, lpdw); 02457 02458 if (lpdw == NULL) { 02459 WARN("invalid parameter\n"); 02460 return MMSYSERR_INVALPARAM; 02461 } 02462 02463 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) 02464 return MMSYSERR_INVALHANDLE; 02465 02466 return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L); 02467 } 02468 02469 /************************************************************************** 02470 * waveOutSetVolume [WINMM.@] 02471 */ 02472 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw) 02473 { 02474 LPWINE_MLD wmld; 02475 02476 TRACE("(%p, %08x);\n", hWaveOut, dw); 02477 02478 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) 02479 return MMSYSERR_INVALHANDLE; 02480 02481 return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L); 02482 } 02483 02484 /************************************************************************** 02485 * waveOutGetID [WINMM.@] 02486 */ 02487 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID) 02488 { 02489 LPWINE_MLD wmld; 02490 02491 TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID); 02492 02493 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; 02494 02495 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) 02496 return MMSYSERR_INVALHANDLE; 02497 02498 *lpuDeviceID = wmld->uDeviceID; 02499 return 0; 02500 } 02501 02502 /************************************************************************** 02503 * waveOutMessage [WINMM.@] 02504 */ 02505 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, 02506 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 02507 { 02508 LPWINE_MLD wmld; 02509 02510 TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); 02511 02512 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) { 02513 if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) { 02514 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); 02515 } 02516 WARN("invalid handle\n"); 02517 return MMSYSERR_INVALHANDLE; 02518 } 02519 02520 /* from M$ KB */ 02521 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) { 02522 WARN("invalid parameter\n"); 02523 return MMSYSERR_INVALPARAM; 02524 } 02525 02526 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); 02527 } 02528 02529 /************************************************************************** 02530 * waveInGetNumDevs [WINMM.@] 02531 */ 02532 UINT WINAPI waveInGetNumDevs(void) 02533 { 02534 return MMDRV_GetNum(MMDRV_WAVEIN); 02535 } 02536 02537 /************************************************************************** 02538 * waveInGetDevCapsW [WINMM.@] 02539 */ 02540 UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize) 02541 { 02542 LPWINE_MLD wmld; 02543 02544 TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize); 02545 02546 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 02547 02548 if (uDeviceID == WAVE_MAPPER) 02549 { 02550 FIXME("Support WAVE_MAPPER\n"); 02551 uDeviceID = 0; 02552 } 02553 02554 02555 if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL) 02556 return MMSYSERR_BADDEVICEID; 02557 02558 return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); 02559 } 02560 02561 /************************************************************************** 02562 * waveInGetDevCapsA [WINMM.@] 02563 */ 02564 UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize) 02565 { 02566 WAVEINCAPSW wicW; 02567 UINT ret; 02568 02569 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 02570 02571 ret = waveInGetDevCapsW(uDeviceID, &wicW, sizeof(wicW)); 02572 02573 if (ret == MMSYSERR_NOERROR) { 02574 WAVEINCAPSA wicA; 02575 wicA.wMid = wicW.wMid; 02576 wicA.wPid = wicW.wPid; 02577 wicA.vDriverVersion = wicW.vDriverVersion; 02578 WideCharToMultiByte( CP_ACP, 0, wicW.szPname, -1, wicA.szPname, 02579 sizeof(wicA.szPname), NULL, NULL ); 02580 wicA.dwFormats = wicW.dwFormats; 02581 wicA.wChannels = wicW.wChannels; 02582 memcpy(lpCaps, &wicA, min(uSize, sizeof(wicA))); 02583 } 02584 return ret; 02585 } 02586 02587 /************************************************************************** 02588 * waveInOpen [WINMM.@] 02589 */ 02590 MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID, 02591 LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, 02592 DWORD_PTR dwInstance, DWORD dwFlags) 02593 { 02594 return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat, 02595 dwCallback, dwInstance, dwFlags); 02596 } 02597 02598 /************************************************************************** 02599 * waveInClose [WINMM.@] 02600 */ 02601 UINT WINAPI waveInClose(HWAVEIN hWaveIn) 02602 { 02603 LPWINE_MLD wmld; 02604 DWORD dwRet; 02605 02606 TRACE("(%p)\n", hWaveIn); 02607 02608 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02609 return MMSYSERR_INVALHANDLE; 02610 02611 dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L); 02612 if (dwRet != WAVERR_STILLPLAYING) 02613 MMDRV_Free(hWaveIn, wmld); 02614 return dwRet; 02615 } 02616 02617 /************************************************************************** 02618 * waveInPrepareHeader [WINMM.@] 02619 */ 02620 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, 02621 UINT uSize) 02622 { 02623 LPWINE_MLD wmld; 02624 UINT result; 02625 02626 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); 02627 02628 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) 02629 return MMSYSERR_INVALPARAM; 02630 02631 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02632 return MMSYSERR_INVALHANDLE; 02633 02634 if ((result = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, 02635 uSize)) != MMSYSERR_NOTSUPPORTED) 02636 return result; 02637 02638 if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) 02639 return WAVERR_STILLPLAYING; 02640 02641 lpWaveInHdr->dwFlags |= WHDR_PREPARED; 02642 lpWaveInHdr->dwFlags &= ~WHDR_DONE; 02643 lpWaveInHdr->dwBytesRecorded = 0; 02644 02645 return MMSYSERR_NOERROR; 02646 } 02647 02648 /************************************************************************** 02649 * waveInUnprepareHeader [WINMM.@] 02650 */ 02651 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, 02652 UINT uSize) 02653 { 02654 LPWINE_MLD wmld; 02655 UINT result; 02656 02657 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); 02658 02659 if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) 02660 return MMSYSERR_INVALPARAM; 02661 02662 if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) 02663 return MMSYSERR_NOERROR; 02664 02665 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02666 return MMSYSERR_INVALHANDLE; 02667 02668 if ((result = MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, 02669 uSize)) != MMSYSERR_NOTSUPPORTED) 02670 return result; 02671 02672 if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) 02673 return WAVERR_STILLPLAYING; 02674 02675 lpWaveInHdr->dwFlags &= ~WHDR_PREPARED; 02676 lpWaveInHdr->dwFlags |= WHDR_DONE; 02677 02678 return MMSYSERR_NOERROR; 02679 } 02680 02681 /************************************************************************** 02682 * waveInAddBuffer [WINMM.@] 02683 */ 02684 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, 02685 WAVEHDR* lpWaveInHdr, UINT uSize) 02686 { 02687 LPWINE_MLD wmld; 02688 02689 TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); 02690 02691 if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; 02692 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02693 return MMSYSERR_INVALHANDLE; 02694 02695 return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize); 02696 } 02697 02698 /************************************************************************** 02699 * waveInReset [WINMM.@] 02700 */ 02701 UINT WINAPI waveInReset(HWAVEIN hWaveIn) 02702 { 02703 LPWINE_MLD wmld; 02704 02705 TRACE("(%p);\n", hWaveIn); 02706 02707 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02708 return MMSYSERR_INVALHANDLE; 02709 02710 return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L); 02711 } 02712 02713 /************************************************************************** 02714 * waveInStart [WINMM.@] 02715 */ 02716 UINT WINAPI waveInStart(HWAVEIN hWaveIn) 02717 { 02718 LPWINE_MLD wmld; 02719 02720 TRACE("(%p);\n", hWaveIn); 02721 02722 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02723 return MMSYSERR_INVALHANDLE; 02724 02725 return MMDRV_Message(wmld, WIDM_START, 0L, 0L); 02726 } 02727 02728 /************************************************************************** 02729 * waveInStop [WINMM.@] 02730 */ 02731 UINT WINAPI waveInStop(HWAVEIN hWaveIn) 02732 { 02733 LPWINE_MLD wmld; 02734 02735 TRACE("(%p);\n", hWaveIn); 02736 02737 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02738 return MMSYSERR_INVALHANDLE; 02739 02740 return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L); 02741 } 02742 02743 /************************************************************************** 02744 * waveInGetPosition [WINMM.@] 02745 */ 02746 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime, 02747 UINT uSize) 02748 { 02749 LPWINE_MLD wmld; 02750 02751 TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize); 02752 02753 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02754 return MMSYSERR_INVALHANDLE; 02755 02756 return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize); 02757 } 02758 02759 /************************************************************************** 02760 * waveInGetID [WINMM.@] 02761 */ 02762 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID) 02763 { 02764 LPWINE_MLD wmld; 02765 02766 TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID); 02767 02768 if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; 02769 02770 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) 02771 return MMSYSERR_INVALHANDLE; 02772 02773 *lpuDeviceID = wmld->uDeviceID; 02774 return MMSYSERR_NOERROR; 02775 } 02776 02777 /************************************************************************** 02778 * waveInMessage [WINMM.@] 02779 */ 02780 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage, 02781 DWORD_PTR dwParam1, DWORD_PTR dwParam2) 02782 { 02783 LPWINE_MLD wmld; 02784 02785 TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); 02786 02787 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) { 02788 if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) { 02789 return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); 02790 } 02791 return MMSYSERR_INVALHANDLE; 02792 } 02793 02794 /* from M$ KB */ 02795 if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) 02796 return MMSYSERR_INVALPARAM; 02797 02798 02799 return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); 02800 } 02801 02802 struct mm_starter 02803 { 02804 LPTASKCALLBACK cb; 02805 DWORD client; 02806 HANDLE event; 02807 }; 02808 02809 static DWORD WINAPI mmTaskRun(void* pmt) 02810 { 02811 struct mm_starter mms; 02812 02813 memcpy(&mms, pmt, sizeof(struct mm_starter)); 02814 HeapFree(GetProcessHeap(), 0, pmt); 02815 mms.cb(mms.client); 02816 if (mms.event) SetEvent(mms.event); 02817 return 0; 02818 } 02819 02820 /****************************************************************** 02821 * mmTaskCreate (WINMM.@) 02822 */ 02823 UINT WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD_PTR client) 02824 { 02825 HANDLE hThread; 02826 HANDLE hEvent = 0; 02827 struct mm_starter *mms; 02828 02829 mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter)); 02830 if (mms == NULL) return TASKERR_OUTOFMEMORY; 02831 02832 mms->cb = cb; 02833 mms->client = client; 02834 if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); 02835 mms->event = hEvent; 02836 02837 hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL); 02838 if (!hThread) { 02839 HeapFree(GetProcessHeap(), 0, mms); 02840 if (hEvent) CloseHandle(hEvent); 02841 return TASKERR_OUTOFMEMORY; 02842 } 02843 SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); 02844 if (ph) *ph = hEvent; 02845 CloseHandle(hThread); 02846 return 0; 02847 } 02848 02849 /****************************************************************** 02850 * mmTaskBlock (WINMM.@) 02851 */ 02852 VOID WINAPI mmTaskBlock(DWORD tid) 02853 { 02854 MSG msg; 02855 02856 do 02857 { 02858 GetMessageA(&msg, 0, 0, 0); 02859 if (msg.hwnd) DispatchMessageA(&msg); 02860 } while (msg.message != WM_USER); 02861 } 02862 02863 /****************************************************************** 02864 * mmTaskSignal (WINMM.@) 02865 */ 02866 BOOL WINAPI mmTaskSignal(DWORD tid) 02867 { 02868 return PostThreadMessageW(tid, WM_USER, 0, 0); 02869 } 02870 02871 /****************************************************************** 02872 * mmTaskYield (WINMM.@) 02873 */ 02874 VOID WINAPI mmTaskYield(VOID) {} 02875 02876 /****************************************************************** 02877 * mmGetCurrentTask (WINMM.@) 02878 */ 02879 DWORD WINAPI mmGetCurrentTask(VOID) 02880 { 02881 return GetCurrentThreadId(); 02882 } Generated on Sun May 27 2012 04:26:59 for ReactOS by
1.7.6.1
|