| /* |
| * Copyright 1993 Martin Ayotte |
| * 1998-2002 Eric Pouech |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <string.h> |
| |
| #define NONAMELESSUNION |
| #define NONAMELESSSTRUCT |
| #include "windef.h" |
| #include "winbase.h" |
| #include "mmsystem.h" |
| #include "winuser.h" |
| #include "winnls.h" |
| #include "winternl.h" |
| #include "winemm.h" |
| |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(winmm); |
| |
| static UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, |
| LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, |
| DWORD_PTR dwInstance, DWORD dwFlags) |
| { |
| HANDLE handle; |
| LPWINE_MLD wmld; |
| DWORD dwRet; |
| WAVEOPENDESC wod; |
| |
| TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08X);\n", |
| lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback, |
| dwInstance, dwFlags); |
| |
| if (dwFlags & WAVE_FORMAT_QUERY) |
| TRACE("WAVE_FORMAT_QUERY requested !\n"); |
| |
| dwRet = WINMM_CheckCallback(dwCallback, dwFlags, FALSE); |
| if (dwRet != MMSYSERR_NOERROR) |
| return dwRet; |
| |
| if (lpFormat == NULL) { |
| WARN("bad format\n"); |
| return WAVERR_BADFORMAT; |
| } |
| |
| if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) { |
| WARN("invalid parameter\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| |
| /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */ |
| TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u\n", |
| lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec, |
| lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample); |
| |
| if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle, |
| &dwFlags, &dwCallback, &dwInstance)) == NULL) { |
| return MMSYSERR_NOMEM; |
| } |
| |
| wod.hWave = handle; |
| wod.lpFormat = (LPWAVEFORMATEX)lpFormat; /* should the struct be copied iso pointer? */ |
| wod.dwCallback = dwCallback; |
| wod.dwInstance = dwInstance; |
| wod.dnDevNode = 0L; |
| |
| TRACE("cb=%08lx\n", wod.dwCallback); |
| |
| for (;;) { |
| if (dwFlags & WAVE_MAPPED) { |
| wod.uMappedDeviceID = uDeviceID; |
| uDeviceID = WAVE_MAPPER; |
| } else { |
| wod.uMappedDeviceID = -1; |
| } |
| wmld->uDeviceID = uDeviceID; |
| |
| dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, |
| (DWORD_PTR)&wod, dwFlags); |
| |
| TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet)); |
| if (dwRet != WAVERR_BADFORMAT || |
| ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break; |
| /* if we ask for a format which isn't supported by the physical driver, |
| * let's try to map it through the wave mapper (except, if we already tried |
| * or user didn't allow us to use acm codecs or the device is already the mapper) |
| */ |
| dwFlags |= WAVE_MAPPED; |
| /* we shall loop only one */ |
| } |
| |
| if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) { |
| MMDRV_Free(handle, wmld); |
| handle = 0; |
| } |
| |
| if (lphndl != NULL) *lphndl = handle; |
| TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle); |
| |
| return dwRet; |
| } |
| |
| /************************************************************************** |
| * waveOutGetNumDevs [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetNumDevs(void) |
| { |
| return MMDRV_GetNum(MMDRV_WAVEOUT); |
| } |
| |
| /************************************************************************** |
| * waveOutGetDevCapsA [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps, |
| UINT uSize) |
| { |
| WAVEOUTCAPSW wocW; |
| UINT ret; |
| |
| if (lpCaps == NULL) return MMSYSERR_INVALPARAM; |
| |
| ret = waveOutGetDevCapsW(uDeviceID, &wocW, sizeof(wocW)); |
| |
| if (ret == MMSYSERR_NOERROR) { |
| WAVEOUTCAPSA wocA; |
| wocA.wMid = wocW.wMid; |
| wocA.wPid = wocW.wPid; |
| wocA.vDriverVersion = wocW.vDriverVersion; |
| WideCharToMultiByte( CP_ACP, 0, wocW.szPname, -1, wocA.szPname, |
| sizeof(wocA.szPname), NULL, NULL ); |
| wocA.dwFormats = wocW.dwFormats; |
| wocA.wChannels = wocW.wChannels; |
| wocA.dwSupport = wocW.dwSupport; |
| memcpy(lpCaps, &wocA, min(uSize, sizeof(wocA))); |
| } |
| return ret; |
| } |
| |
| /************************************************************************** |
| * waveOutGetDevCapsW [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps, |
| UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize); |
| |
| if (lpCaps == NULL) return MMSYSERR_INVALPARAM; |
| |
| if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL) |
| return MMSYSERR_BADDEVICEID; |
| |
| return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); |
| } |
| |
| /************************************************************************** |
| * waveOutGetErrorTextA [WINMM.@] |
| * waveInGetErrorTextA [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) |
| { |
| UINT ret; |
| |
| if (lpText == NULL) ret = MMSYSERR_INVALPARAM; |
| else if (uSize == 0) ret = MMSYSERR_NOERROR; |
| else |
| { |
| LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); |
| if (!xstr) ret = MMSYSERR_NOMEM; |
| else |
| { |
| ret = waveOutGetErrorTextW(uError, xstr, uSize); |
| if (ret == MMSYSERR_NOERROR) |
| WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); |
| HeapFree(GetProcessHeap(), 0, xstr); |
| } |
| } |
| return ret; |
| } |
| |
| /************************************************************************** |
| * waveOutGetErrorTextW [WINMM.@] |
| * waveInGetErrorTextW [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) |
| { |
| UINT ret = MMSYSERR_BADERRNUM; |
| |
| if (lpText == NULL) ret = MMSYSERR_INVALPARAM; |
| else if (uSize == 0) ret = MMSYSERR_NOERROR; |
| else if ( |
| /* test has been removed because MMSYSERR_BASE is 0, and gcc did emit |
| * a warning for the test was always true */ |
| (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || |
| (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) { |
| if (LoadStringW(hWinMM32Instance, |
| uError, lpText, uSize) > 0) { |
| ret = MMSYSERR_NOERROR; |
| } |
| } |
| return ret; |
| } |
| |
| /************************************************************************** |
| * waveOutOpen [WINMM.@] |
| * All the args/structs have the same layout as the win16 equivalents |
| */ |
| MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID, |
| LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, |
| DWORD_PTR dwInstance, DWORD dwFlags) |
| { |
| return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat, |
| dwCallback, dwInstance, dwFlags); |
| } |
| |
| /************************************************************************** |
| * waveOutClose [WINMM.@] |
| */ |
| UINT WINAPI waveOutClose(HWAVEOUT hWaveOut) |
| { |
| LPWINE_MLD wmld; |
| DWORD dwRet; |
| |
| TRACE("(%p)\n", hWaveOut); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| dwRet = MMDRV_Close(wmld, WODM_CLOSE); |
| if (dwRet != WAVERR_STILLPLAYING) |
| MMDRV_Free(hWaveOut, wmld); |
| |
| return dwRet; |
| } |
| |
| /************************************************************************** |
| * waveOutPrepareHeader [WINMM.@] |
| */ |
| UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, |
| WAVEHDR* lpWaveOutHdr, UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| UINT result; |
| |
| TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); |
| |
| if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) |
| return MMSYSERR_INVALPARAM; |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, |
| uSize)) != MMSYSERR_NOTSUPPORTED) |
| return result; |
| |
| if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) |
| return WAVERR_STILLPLAYING; |
| |
| lpWaveOutHdr->dwFlags |= WHDR_PREPARED; |
| lpWaveOutHdr->dwFlags &= ~WHDR_DONE; |
| |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * waveOutUnprepareHeader [WINMM.@] |
| */ |
| UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, |
| LPWAVEHDR lpWaveOutHdr, UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| UINT result; |
| |
| TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); |
| |
| if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) |
| return MMSYSERR_INVALPARAM; |
| |
| if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { |
| return MMSYSERR_NOERROR; |
| } |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, |
| uSize)) != MMSYSERR_NOTSUPPORTED) |
| return result; |
| |
| if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) |
| return WAVERR_STILLPLAYING; |
| |
| lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED; |
| lpWaveOutHdr->dwFlags |= WHDR_DONE; |
| |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * waveOutWrite [WINMM.@] |
| */ |
| UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, |
| UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize); |
| } |
| |
| /************************************************************************** |
| * waveOutBreakLoop [WINMM.@] |
| */ |
| UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p);\n", hWaveOut); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutPause [WINMM.@] |
| */ |
| UINT WINAPI waveOutPause(HWAVEOUT hWaveOut) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p);\n", hWaveOut); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutReset [WINMM.@] |
| */ |
| UINT WINAPI waveOutReset(HWAVEOUT hWaveOut) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p);\n", hWaveOut); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| return MMDRV_Message(wmld, WODM_RESET, 0L, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutRestart [WINMM.@] |
| */ |
| UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p);\n", hWaveOut); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutGetPosition [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime, |
| UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize); |
| } |
| |
| /************************************************************************** |
| * waveOutGetPitch [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p);\n", hWaveOut, lpdw); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutSetPitch [WINMM.@] |
| */ |
| UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %08x);\n", hWaveOut, dw); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutGetPlaybackRate [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p);\n", hWaveOut, lpdw); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutSetPlaybackRate [WINMM.@] |
| */ |
| UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %08x);\n", hWaveOut, dw); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutGetVolume [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p);\n", hWaveOut, lpdw); |
| |
| if (lpdw == NULL) { |
| WARN("invalid parameter\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutSetVolume [WINMM.@] |
| */ |
| UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %08x);\n", hWaveOut, dw); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L); |
| } |
| |
| /************************************************************************** |
| * waveOutGetID [WINMM.@] |
| */ |
| UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID); |
| |
| if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| *lpuDeviceID = wmld->uDeviceID; |
| return 0; |
| } |
| |
| /************************************************************************** |
| * waveOutMessage [WINMM.@] |
| */ |
| UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, |
| DWORD_PTR dwParam1, DWORD_PTR dwParam2) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); |
| |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) { |
| if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) { |
| return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); |
| } |
| WARN("invalid handle\n"); |
| return MMSYSERR_INVALHANDLE; |
| } |
| |
| /* from M$ KB */ |
| if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) { |
| WARN("invalid parameter\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| |
| return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); |
| } |
| |
| /************************************************************************** |
| * waveInGetNumDevs [WINMM.@] |
| */ |
| UINT WINAPI waveInGetNumDevs(void) |
| { |
| return MMDRV_GetNum(MMDRV_WAVEIN); |
| } |
| |
| /************************************************************************** |
| * waveInGetDevCapsW [WINMM.@] |
| */ |
| UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize); |
| |
| if (lpCaps == NULL) return MMSYSERR_INVALPARAM; |
| |
| if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL) |
| return MMSYSERR_BADDEVICEID; |
| |
| return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); |
| } |
| |
| /************************************************************************** |
| * waveInGetDevCapsA [WINMM.@] |
| */ |
| UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize) |
| { |
| WAVEINCAPSW wicW; |
| UINT ret; |
| |
| if (lpCaps == NULL) return MMSYSERR_INVALPARAM; |
| |
| ret = waveInGetDevCapsW(uDeviceID, &wicW, sizeof(wicW)); |
| |
| if (ret == MMSYSERR_NOERROR) { |
| WAVEINCAPSA wicA; |
| wicA.wMid = wicW.wMid; |
| wicA.wPid = wicW.wPid; |
| wicA.vDriverVersion = wicW.vDriverVersion; |
| WideCharToMultiByte( CP_ACP, 0, wicW.szPname, -1, wicA.szPname, |
| sizeof(wicA.szPname), NULL, NULL ); |
| wicA.dwFormats = wicW.dwFormats; |
| wicA.wChannels = wicW.wChannels; |
| memcpy(lpCaps, &wicA, min(uSize, sizeof(wicA))); |
| } |
| return ret; |
| } |
| |
| /************************************************************************** |
| * waveInOpen [WINMM.@] |
| */ |
| MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID, |
| LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, |
| DWORD_PTR dwInstance, DWORD dwFlags) |
| { |
| return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat, |
| dwCallback, dwInstance, dwFlags); |
| } |
| |
| /************************************************************************** |
| * waveInClose [WINMM.@] |
| */ |
| UINT WINAPI waveInClose(HWAVEIN hWaveIn) |
| { |
| LPWINE_MLD wmld; |
| DWORD dwRet; |
| |
| TRACE("(%p)\n", hWaveIn); |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L); |
| if (dwRet != WAVERR_STILLPLAYING) |
| MMDRV_Free(hWaveIn, wmld); |
| return dwRet; |
| } |
| |
| /************************************************************************** |
| * waveInPrepareHeader [WINMM.@] |
| */ |
| UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, |
| UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| UINT result; |
| |
| TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); |
| |
| if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) |
| return MMSYSERR_INVALPARAM; |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| if ((result = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, |
| uSize)) != MMSYSERR_NOTSUPPORTED) |
| return result; |
| |
| if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) |
| return WAVERR_STILLPLAYING; |
| |
| lpWaveInHdr->dwFlags |= WHDR_PREPARED; |
| lpWaveInHdr->dwFlags &= ~WHDR_DONE; |
| lpWaveInHdr->dwBytesRecorded = 0; |
| |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * waveInUnprepareHeader [WINMM.@] |
| */ |
| UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, |
| UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| UINT result; |
| |
| TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); |
| |
| if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) |
| return MMSYSERR_INVALPARAM; |
| |
| if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) |
| return MMSYSERR_NOERROR; |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| if ((result = MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, |
| uSize)) != MMSYSERR_NOTSUPPORTED) |
| return result; |
| |
| if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) |
| return WAVERR_STILLPLAYING; |
| |
| lpWaveInHdr->dwFlags &= ~WHDR_PREPARED; |
| lpWaveInHdr->dwFlags |= WHDR_DONE; |
| |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * waveInAddBuffer [WINMM.@] |
| */ |
| UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, |
| WAVEHDR* lpWaveInHdr, UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); |
| |
| if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize); |
| } |
| |
| /************************************************************************** |
| * waveInReset [WINMM.@] |
| */ |
| UINT WINAPI waveInReset(HWAVEIN hWaveIn) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p);\n", hWaveIn); |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L); |
| } |
| |
| /************************************************************************** |
| * waveInStart [WINMM.@] |
| */ |
| UINT WINAPI waveInStart(HWAVEIN hWaveIn) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p);\n", hWaveIn); |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, WIDM_START, 0L, 0L); |
| } |
| |
| /************************************************************************** |
| * waveInStop [WINMM.@] |
| */ |
| UINT WINAPI waveInStop(HWAVEIN hWaveIn) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p);\n", hWaveIn); |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L); |
| } |
| |
| /************************************************************************** |
| * waveInGetPosition [WINMM.@] |
| */ |
| UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime, |
| UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize); |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize); |
| } |
| |
| /************************************************************************** |
| * waveInGetID [WINMM.@] |
| */ |
| UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID); |
| |
| if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| *lpuDeviceID = wmld->uDeviceID; |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * waveInMessage [WINMM.@] |
| */ |
| UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage, |
| DWORD_PTR dwParam1, DWORD_PTR dwParam2) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); |
| |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) { |
| if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) { |
| return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); |
| } |
| return MMSYSERR_INVALHANDLE; |
| } |
| |
| /* from M$ KB */ |
| if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) |
| return MMSYSERR_INVALPARAM; |
| |
| |
| return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2); |
| } |
| |
| /************************************************************************** |
| * find out the real mixer ID depending on hmix (depends on dwFlags) |
| */ |
| static UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm) |
| { |
| LPWINE_MIXER lpwm = NULL; |
| UINT uRet = MMSYSERR_NOERROR; |
| |
| switch (dwFlags & 0xF0000000ul) { |
| case MIXER_OBJECTF_MIXER: |
| lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE); |
| break; |
| case MIXER_OBJECTF_HMIXER: |
| lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE); |
| break; |
| case MIXER_OBJECTF_WAVEOUT: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER); |
| break; |
| case MIXER_OBJECTF_HWAVEOUT: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER); |
| break; |
| case MIXER_OBJECTF_WAVEIN: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER); |
| break; |
| case MIXER_OBJECTF_HWAVEIN: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER); |
| break; |
| case MIXER_OBJECTF_MIDIOUT: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER); |
| break; |
| case MIXER_OBJECTF_HMIDIOUT: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER); |
| break; |
| case MIXER_OBJECTF_MIDIIN: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER); |
| break; |
| case MIXER_OBJECTF_HMIDIIN: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER); |
| break; |
| case MIXER_OBJECTF_AUX: |
| lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER); |
| break; |
| default: |
| WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul); |
| lpwm = 0; |
| uRet = MMSYSERR_INVALFLAG; |
| break; |
| } |
| *lplpwm = lpwm; |
| if (lpwm == 0 && uRet == MMSYSERR_NOERROR) |
| uRet = MMSYSERR_INVALPARAM; |
| return uRet; |
| } |
| |
| /************************************************************************** |
| * mixerGetNumDevs [WINMM.@] |
| */ |
| UINT WINAPI mixerGetNumDevs(void) |
| { |
| return MMDRV_GetNum(MMDRV_MIXER); |
| } |
| |
| /************************************************************************** |
| * mixerGetDevCapsA [WINMM.@] |
| */ |
| UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize) |
| { |
| MIXERCAPSW micW; |
| UINT ret; |
| |
| if (lpCaps == NULL) return MMSYSERR_INVALPARAM; |
| |
| ret = mixerGetDevCapsW(uDeviceID, &micW, sizeof(micW)); |
| |
| if (ret == MMSYSERR_NOERROR) { |
| MIXERCAPSA micA; |
| micA.wMid = micW.wMid; |
| micA.wPid = micW.wPid; |
| micA.vDriverVersion = micW.vDriverVersion; |
| WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, |
| sizeof(micA.szPname), NULL, NULL ); |
| micA.fdwSupport = micW.fdwSupport; |
| micA.cDestinations = micW.cDestinations; |
| memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); |
| } |
| return ret; |
| } |
| |
| /************************************************************************** |
| * mixerGetDevCapsW [WINMM.@] |
| */ |
| UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize) |
| { |
| LPWINE_MLD wmld; |
| |
| if (lpCaps == NULL) return MMSYSERR_INVALPARAM; |
| |
| if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL) |
| return MMSYSERR_BADDEVICEID; |
| |
| return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize); |
| } |
| |
| static void CALLBACK MIXER_WCallback(HMIXEROBJ hmx, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam, DWORD_PTR param2) |
| { |
| HWND hWnd = (HWND)dwInstance; |
| |
| if (!dwInstance) |
| return; |
| |
| PostMessageW(hWnd, uMsg, (WPARAM)hmx, (LPARAM)dwParam); |
| } |
| |
| /************************************************************************** |
| * mixerOpen [WINMM.@] |
| */ |
| UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, |
| DWORD_PTR dwInstance, DWORD fdwOpen) |
| { |
| HANDLE hMix; |
| LPWINE_MLD wmld; |
| DWORD dwRet; |
| MIXEROPENDESC mod; |
| |
| TRACE("(%p, %d, %08lx, %08lx, %08x)\n", |
| lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen); |
| |
| dwRet = WINMM_CheckCallback(dwCallback, fdwOpen, TRUE); |
| if (dwRet != MMSYSERR_NOERROR) |
| return dwRet; |
| |
| mod.dwCallback = (DWORD_PTR)MIXER_WCallback; |
| if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_WINDOW) |
| mod.dwInstance = dwCallback; |
| else |
| mod.dwInstance = 0; |
| |
| /* We're remapping to CALLBACK_FUNCTION because that's what old winmm is |
| * documented to do when opening the mixer driver. |
| * FIXME: Native supports CALLBACK_EVENT + CALLBACK_THREAD flags since w2k. |
| * FIXME: The non ALSA drivers ignore callback requests - bug. |
| */ |
| |
| wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen, |
| &dwCallback, &dwInstance); |
| wmld->uDeviceID = uDeviceID; |
| mod.hmx = hMix; |
| |
| dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD_PTR)&mod, CALLBACK_FUNCTION); |
| |
| if (dwRet != MMSYSERR_NOERROR) { |
| MMDRV_Free(hMix, wmld); |
| hMix = 0; |
| } |
| if (lphMix) *lphMix = hMix; |
| TRACE("=> %d hMixer=%p\n", dwRet, hMix); |
| |
| return dwRet; |
| } |
| |
| /************************************************************************** |
| * mixerClose [WINMM.@] |
| */ |
| UINT WINAPI mixerClose(HMIXER hMix) |
| { |
| LPWINE_MLD wmld; |
| DWORD dwRet; |
| |
| TRACE("(%p)\n", hMix); |
| |
| if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE; |
| |
| dwRet = MMDRV_Close(wmld, MXDM_CLOSE); |
| MMDRV_Free(hMix, wmld); |
| |
| return dwRet; |
| } |
| |
| /************************************************************************** |
| * mixerGetID [WINMM.@] |
| */ |
| UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID) |
| { |
| LPWINE_MIXER lpwm; |
| UINT uRet = MMSYSERR_NOERROR; |
| |
| TRACE("(%p %p %08x)\n", hmix, lpid, fdwID); |
| |
| if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR) |
| return uRet; |
| |
| if (lpid) |
| *lpid = lpwm->mld.uDeviceID; |
| |
| return uRet; |
| } |
| |
| /************************************************************************** |
| * mixerGetControlDetailsW [WINMM.@] |
| */ |
| UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW, |
| DWORD fdwDetails) |
| { |
| LPWINE_MIXER lpwm; |
| UINT uRet = MMSYSERR_NOERROR; |
| |
| TRACE("(%p, %p, %08x)\n", hmix, lpmcdW, fdwDetails); |
| |
| if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) |
| return uRet; |
| |
| if (lpmcdW == NULL || lpmcdW->cbStruct != sizeof(*lpmcdW)) |
| return MMSYSERR_INVALPARAM; |
| |
| return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdW, |
| fdwDetails); |
| } |
| |
| /************************************************************************** |
| * mixerGetControlDetailsA [WINMM.@] |
| */ |
| UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, |
| DWORD fdwDetails) |
| { |
| DWORD ret = MMSYSERR_NOTENABLED; |
| |
| TRACE("(%p, %p, %08x)\n", hmix, lpmcdA, fdwDetails); |
| |
| if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA)) |
| return MMSYSERR_INVALPARAM; |
| |
| switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) { |
| case MIXER_GETCONTROLDETAILSF_VALUE: |
| /* can safely use A structure as it is, no string inside */ |
| ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); |
| break; |
| case MIXER_GETCONTROLDETAILSF_LISTTEXT: |
| { |
| MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA = lpmcdA->paDetails; |
| MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW; |
| int size = max(1, lpmcdA->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTW); |
| unsigned int i; |
| |
| if (lpmcdA->u.cMultipleItems != 0) { |
| size *= lpmcdA->u.cMultipleItems; |
| } |
| pDetailsW = HeapAlloc(GetProcessHeap(), 0, size); |
| lpmcdA->paDetails = pDetailsW; |
| lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW); |
| /* set up lpmcd->paDetails */ |
| ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); |
| /* copy from lpmcd->paDetails back to paDetailsW; */ |
| if (ret == MMSYSERR_NOERROR) { |
| for (i = 0; i < lpmcdA->u.cMultipleItems * lpmcdA->cChannels; i++) { |
| pDetailsA->dwParam1 = pDetailsW->dwParam1; |
| pDetailsA->dwParam2 = pDetailsW->dwParam2; |
| WideCharToMultiByte( CP_ACP, 0, pDetailsW->szName, -1, |
| pDetailsA->szName, |
| sizeof(pDetailsA->szName), NULL, NULL ); |
| pDetailsA++; |
| pDetailsW++; |
| } |
| pDetailsA -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; |
| pDetailsW -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; |
| } |
| HeapFree(GetProcessHeap(), 0, pDetailsW); |
| lpmcdA->paDetails = pDetailsA; |
| lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA); |
| } |
| break; |
| default: |
| ERR("Unsupported fdwDetails=0x%08x\n", fdwDetails); |
| } |
| |
| return ret; |
| } |
| |
| /************************************************************************** |
| * mixerGetLineControlsA [WINMM.@] |
| */ |
| UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA, |
| DWORD fdwControls) |
| { |
| MIXERLINECONTROLSW mlcW; |
| DWORD ret; |
| unsigned int i; |
| |
| TRACE("(%p, %p, %08x)\n", hmix, lpmlcA, fdwControls); |
| |
| if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA) || |
| lpmlcA->cbmxctrl != sizeof(MIXERCONTROLA)) |
| return MMSYSERR_INVALPARAM; |
| |
| mlcW.cbStruct = sizeof(mlcW); |
| mlcW.dwLineID = lpmlcA->dwLineID; |
| mlcW.u.dwControlID = lpmlcA->u.dwControlID; |
| mlcW.u.dwControlType = lpmlcA->u.dwControlType; |
| |
| /* Debugging on Windows shows for MIXER_GETLINECONTROLSF_ONEBYTYPE only, |
| the control count is assumed to be 1 - This is relied upon by a game, |
| "Dynomite Deluze" */ |
| if (MIXER_GETLINECONTROLSF_ONEBYTYPE == (fdwControls & MIXER_GETLINECONTROLSF_QUERYMASK)) { |
| mlcW.cControls = 1; |
| } else { |
| mlcW.cControls = lpmlcA->cControls; |
| } |
| mlcW.cbmxctrl = sizeof(MIXERCONTROLW); |
| mlcW.pamxctrl = HeapAlloc(GetProcessHeap(), 0, |
| mlcW.cControls * mlcW.cbmxctrl); |
| |
| ret = mixerGetLineControlsW(hmix, &mlcW, fdwControls); |
| |
| if (ret == MMSYSERR_NOERROR) { |
| lpmlcA->dwLineID = mlcW.dwLineID; |
| lpmlcA->u.dwControlID = mlcW.u.dwControlID; |
| lpmlcA->u.dwControlType = mlcW.u.dwControlType; |
| |
| for (i = 0; i < mlcW.cControls; i++) { |
| lpmlcA->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLA); |
| lpmlcA->pamxctrl[i].dwControlID = mlcW.pamxctrl[i].dwControlID; |
| lpmlcA->pamxctrl[i].dwControlType = mlcW.pamxctrl[i].dwControlType; |
| lpmlcA->pamxctrl[i].fdwControl = mlcW.pamxctrl[i].fdwControl; |
| lpmlcA->pamxctrl[i].cMultipleItems = mlcW.pamxctrl[i].cMultipleItems; |
| WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szShortName, -1, |
| lpmlcA->pamxctrl[i].szShortName, |
| sizeof(lpmlcA->pamxctrl[i].szShortName), NULL, NULL ); |
| WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szName, -1, |
| lpmlcA->pamxctrl[i].szName, |
| sizeof(lpmlcA->pamxctrl[i].szName), NULL, NULL ); |
| /* sizeof(lpmlcA->pamxctrl[i].Bounds) == |
| * sizeof(mlcW.pamxctrl[i].Bounds) */ |
| memcpy(&lpmlcA->pamxctrl[i].Bounds, &mlcW.pamxctrl[i].Bounds, |
| sizeof(mlcW.pamxctrl[i].Bounds)); |
| /* sizeof(lpmlcA->pamxctrl[i].Metrics) == |
| * sizeof(mlcW.pamxctrl[i].Metrics) */ |
| memcpy(&lpmlcA->pamxctrl[i].Metrics, &mlcW.pamxctrl[i].Metrics, |
| sizeof(mlcW.pamxctrl[i].Metrics)); |
| } |
| } |
| |
| HeapFree(GetProcessHeap(), 0, mlcW.pamxctrl); |
| |
| return ret; |
| } |
| |
| /************************************************************************** |
| * mixerGetLineControlsW [WINMM.@] |
| */ |
| UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, |
| DWORD fdwControls) |
| { |
| LPWINE_MIXER lpwm; |
| UINT uRet = MMSYSERR_NOERROR; |
| |
| TRACE("(%p, %p, %08x)\n", hmix, lpmlcW, fdwControls); |
| |
| if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR) |
| return uRet; |
| |
| if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW)) |
| return MMSYSERR_INVALPARAM; |
| |
| return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcW, |
| fdwControls); |
| } |
| |
| /************************************************************************** |
| * mixerGetLineInfoW [WINMM.@] |
| */ |
| UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo) |
| { |
| LPWINE_MIXER lpwm; |
| UINT uRet = MMSYSERR_NOERROR; |
| |
| TRACE("(%p, %p, %08x)\n", hmix, lpmliW, fdwInfo); |
| |
| if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR) |
| return uRet; |
| |
| return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW, |
| fdwInfo); |
| } |
| |
| /************************************************************************** |
| * mixerGetLineInfoA [WINMM.@] |
| */ |
| UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliA, |
| DWORD fdwInfo) |
| { |
| MIXERLINEW mliW; |
| UINT ret; |
| |
| TRACE("(%p, %p, %08x)\n", hmix, lpmliA, fdwInfo); |
| |
| if (lpmliA == NULL || lpmliA->cbStruct != sizeof(*lpmliA)) |
| return MMSYSERR_INVALPARAM; |
| |
| mliW.cbStruct = sizeof(mliW); |
| switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { |
| case MIXER_GETLINEINFOF_COMPONENTTYPE: |
| mliW.dwComponentType = lpmliA->dwComponentType; |
| break; |
| case MIXER_GETLINEINFOF_DESTINATION: |
| mliW.dwDestination = lpmliA->dwDestination; |
| break; |
| case MIXER_GETLINEINFOF_LINEID: |
| mliW.dwLineID = lpmliA->dwLineID; |
| break; |
| case MIXER_GETLINEINFOF_SOURCE: |
| mliW.dwDestination = lpmliA->dwDestination; |
| mliW.dwSource = lpmliA->dwSource; |
| break; |
| case MIXER_GETLINEINFOF_TARGETTYPE: |
| mliW.Target.dwType = lpmliA->Target.dwType; |
| mliW.Target.wMid = lpmliA->Target.wMid; |
| mliW.Target.wPid = lpmliA->Target.wPid; |
| mliW.Target.vDriverVersion = lpmliA->Target.vDriverVersion; |
| MultiByteToWideChar( CP_ACP, 0, lpmliA->Target.szPname, -1, mliW.Target.szPname, sizeof(mliW.Target.szPname)/sizeof(WCHAR)); |
| break; |
| default: |
| WARN("Unsupported fdwControls=0x%08x\n", fdwInfo); |
| return MMSYSERR_INVALFLAG; |
| } |
| |
| ret = mixerGetLineInfoW(hmix, &mliW, fdwInfo); |
| |
| if(ret == MMSYSERR_NOERROR) |
| { |
| lpmliA->dwDestination = mliW.dwDestination; |
| lpmliA->dwSource = mliW.dwSource; |
| lpmliA->dwLineID = mliW.dwLineID; |
| lpmliA->fdwLine = mliW.fdwLine; |
| lpmliA->dwUser = mliW.dwUser; |
| lpmliA->dwComponentType = mliW.dwComponentType; |
| lpmliA->cChannels = mliW.cChannels; |
| lpmliA->cConnections = mliW.cConnections; |
| lpmliA->cControls = mliW.cControls; |
| WideCharToMultiByte( CP_ACP, 0, mliW.szShortName, -1, lpmliA->szShortName, |
| sizeof(lpmliA->szShortName), NULL, NULL); |
| WideCharToMultiByte( CP_ACP, 0, mliW.szName, -1, lpmliA->szName, |
| sizeof(lpmliA->szName), NULL, NULL ); |
| lpmliA->Target.dwType = mliW.Target.dwType; |
| lpmliA->Target.dwDeviceID = mliW.Target.dwDeviceID; |
| lpmliA->Target.wMid = mliW.Target.wMid; |
| lpmliA->Target.wPid = mliW.Target.wPid; |
| lpmliA->Target.vDriverVersion = mliW.Target.vDriverVersion; |
| WideCharToMultiByte( CP_ACP, 0, mliW.Target.szPname, -1, lpmliA->Target.szPname, |
| sizeof(lpmliA->Target.szPname), NULL, NULL ); |
| } |
| return ret; |
| } |
| |
| /************************************************************************** |
| * mixerSetControlDetails [WINMM.@] |
| */ |
| UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, |
| DWORD fdwDetails) |
| { |
| LPWINE_MIXER lpwm; |
| UINT uRet = MMSYSERR_NOERROR; |
| |
| TRACE("(%p, %p, %08x)\n", hmix, lpmcd, fdwDetails); |
| |
| if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) |
| return uRet; |
| |
| return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcd, |
| fdwDetails); |
| } |
| |
| /************************************************************************** |
| * mixerMessage [WINMM.@] |
| */ |
| DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) |
| { |
| LPWINE_MLD wmld; |
| |
| TRACE("(%p, %d, %08lx, %08lx): semi-stub?\n", |
| hmix, uMsg, dwParam1, dwParam2); |
| |
| if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL) |
| return MMSYSERR_INVALHANDLE; |
| |
| return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2); |
| } |