📄 winmm.c
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
/*
* WINMM functions
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Eric POUECH :
* 98/9 added Win32 MCI support
* 99/4 added midiStream support
* 99/9 added support for loadable low level drivers
*/
/* TODO
* + it seems that some programs check what's installed in
* registry against the value returned by drivers. Wine is
* currently broken regarding this point.
* + check thread-safeness for MMSYSTEM and WINMM entry points
* + unicode entry points are badly supported (would require
* moving 32 bit drivers as Unicode as they are supposed to be)
* + allow joystick and timer external calls as we do for wave,
* midi, mixer and aux
*/
#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 "winreg.h"
#include "winternl.h"
#include "winemm.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winmm);
void (WINAPI *pFnReleaseThunkLock)(DWORD*);
void (WINAPI *pFnRestoreThunkLock)(DWORD);
/* ========================================================================
* G L O B A L S E T T I N G S
* ========================================================================*/
WINE_MM_IDATA WINMM_IData;
/**************************************************************************
* WINMM_CreateIData [internal]
*/
static BOOL WINMM_CreateIData(HINSTANCE hInstDLL)
{
memset( &WINMM_IData, 0, sizeof WINMM_IData );
WINMM_IData.hWinMM32Instance = hInstDLL;
InitializeCriticalSection(&WINMM_IData.cs);
/* FIXME crashes in ReactOS
WINMM_IData.cs.DebugInfo->Spare[1] = (DWORD)"WINMM_IData";
*/
WINMM_IData.psStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
WINMM_IData.psLastEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
TRACE("Initialized IData (%p)\n", &WINMM_IData);
return TRUE;
}
/**************************************************************************
* WINMM_DeleteIData [internal]
*/
static void WINMM_DeleteIData(void)
{
TIME_MMTimeStop();
/* FIXME: should also free content and resources allocated
* inside WINMM_IData */
CloseHandle(WINMM_IData.psStopEvent);
CloseHandle(WINMM_IData.psLastEvent);
DeleteCriticalSection(&WINMM_IData.cs);
}
/******************************************************************
* WINMM_LoadMMSystem
*
*/
#ifndef __REACTOS__
static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR);
static DWORD (WINAPI *pLoadLibrary16)(LPCSTR);
#endif
BOOL WINMM_CheckForMMSystem(void)
{
/* 0 is not checked yet, -1 is not present, 1 is present */
static int loaded /* = 0 */;
if (loaded == 0)
{
HANDLE h = GetModuleHandleA("kernel32");
loaded = -1;
if (h)
{
#ifndef __REACTOS__
pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16");
pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16");
if (pGetModuleHandle16 && pLoadLibrary16 &&
(pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
#endif /* __REACTOS__ */
loaded = 1;
}
}
return loaded > 0;
}
/******************************************************************
* WINMM_ErrorToString
*/
const char* WINMM_ErrorToString(MMRESULT error)
{
#define ERR_TO_STR(dev) case dev: return #dev
static char unknown[32];
switch (error) {
ERR_TO_STR(MMSYSERR_NOERROR);
ERR_TO_STR(MMSYSERR_ERROR);
ERR_TO_STR(MMSYSERR_BADDEVICEID);
ERR_TO_STR(MMSYSERR_NOTENABLED);
ERR_TO_STR(MMSYSERR_ALLOCATED);
ERR_TO_STR(MMSYSERR_INVALHANDLE);
ERR_TO_STR(MMSYSERR_NODRIVER);
ERR_TO_STR(MMSYSERR_NOMEM);
ERR_TO_STR(MMSYSERR_NOTSUPPORTED);
ERR_TO_STR(MMSYSERR_BADERRNUM);
ERR_TO_STR(MMSYSERR_INVALFLAG);
ERR_TO_STR(MMSYSERR_INVALPARAM);
ERR_TO_STR(MMSYSERR_HANDLEBUSY);
ERR_TO_STR(MMSYSERR_INVALIDALIAS);
ERR_TO_STR(MMSYSERR_BADDB);
ERR_TO_STR(MMSYSERR_KEYNOTFOUND);
ERR_TO_STR(MMSYSERR_READERROR);
ERR_TO_STR(MMSYSERR_WRITEERROR);
ERR_TO_STR(MMSYSERR_DELETEERROR);
ERR_TO_STR(MMSYSERR_VALNOTFOUND);
ERR_TO_STR(MMSYSERR_NODRIVERCB);
ERR_TO_STR(WAVERR_BADFORMAT);
ERR_TO_STR(WAVERR_STILLPLAYING);
ERR_TO_STR(WAVERR_UNPREPARED);
ERR_TO_STR(WAVERR_SYNC);
}
sprintf(unknown, "Unknown(0x%08x)", error);
return unknown;
#undef ERR_TO_STR
}
/**************************************************************************
* DllMain (WINMM.init)
*
* WINMM DLL entry point
*
*/
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
{
TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInstDLL);
if (!WINMM_CreateIData(hInstDLL))
return FALSE;
if (!MMDRV_Init()) {
WINMM_DeleteIData();
return FALSE;
}
break;
case DLL_PROCESS_DETACH:
/* close all opened MCI drivers */
MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE);
MMDRV_Exit();
/* now unload all remaining drivers... */
DRIVER_UnloadAll();
WINMM_DeleteIData();
break;
}
return TRUE;
}
/**************************************************************************
* Mixer devices. New to Win95
*/
/**************************************************************************
* 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, TRUE);
}
UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32)
{
HANDLE hMix;
LPWINE_MLD wmld;
DWORD dwRet = 0;
MIXEROPENDESC mod;
TRACE("(%p, %d, %08lx, %08lx, %08lx)\n",
lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
&dwCallback, &dwInstance, bFrom32);
wmld->uDeviceID = uDeviceID;
mod.hmx = (HMIXEROBJ)hMix;
mod.dwCallback = dwCallback;
mod.dwInstance = dwInstance;
dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen);
if (dwRet != MMSYSERR_NOERROR) {
MMDRV_Free(hMix, wmld);
hMix = 0;
}
if (lphMix) *lphMix = hMix;
TRACE("=> %ld hMixer=%p\n", dwRet, hMix);
return dwRet;
}
/**************************************************************************
* mixerOpen [WINMM.@]
*/
UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
DWORD_PTR dwInstance, DWORD fdwOpen)
{
return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE);
}
/**************************************************************************
* 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 %08lx)\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, %08lx)\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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -