| /* -*- tab-width: 8; c-basic-offset: 4 -*- */ | |
| /* | |
| * MSACM32 library | |
| * | |
| * Copyright 1998 Patrik Stridvall | |
| * 1999 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 "config.h" | |
| #include "wine/port.h" | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "winnls.h" | |
| #include "mmsystem.h" | |
| #include "mmreg.h" | |
| #include "msacm.h" | |
| #include "msacmdrv.h" | |
| #include "wineacm.h" | |
| #include "wine/debug.h" | |
| #include "wine/unicode.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(msacm); | |
| /*********************************************************************** | |
| * acmDriverAddA (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule, | |
| LPARAM lParam, DWORD dwPriority, DWORD fdwAdd) | |
| { | |
| MMRESULT resultW; | |
| WCHAR * driverW = NULL; | |
| LPARAM lParamW = lParam; | |
| TRACE("(%p, %p, %08lx, %08x, %08x)\n", | |
| phadid, hinstModule, lParam, dwPriority, fdwAdd); | |
| if (!phadid) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| /* Check if any unknown flags */ | |
| if (fdwAdd & | |
| ~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND| | |
| ACM_DRIVERADDF_GLOBAL)) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| /* Check if any incompatible flags */ | |
| if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) && | |
| (fdwAdd & ACM_DRIVERADDF_NOTIFYHWND)) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| /* A->W translation of name */ | |
| if ((fdwAdd & ACM_DRIVERADDF_TYPEMASK) == ACM_DRIVERADDF_NAME) { | |
| INT len; | |
| if (lParam == 0) return MMSYSERR_INVALPARAM; | |
| len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)lParam, -1, NULL, 0); | |
| driverW = HeapAlloc(MSACM_hHeap, 0, len * sizeof(WCHAR)); | |
| if (!driverW) return MMSYSERR_NOMEM; | |
| MultiByteToWideChar(CP_ACP, 0, (LPSTR)lParam, -1, driverW, len); | |
| lParamW = (LPARAM)driverW; | |
| } | |
| resultW = acmDriverAddW(phadid, hinstModule, lParamW, dwPriority, fdwAdd); | |
| HeapFree(MSACM_hHeap, 0, driverW); | |
| return resultW; | |
| } | |
| /*********************************************************************** | |
| * acmDriverAddW (MSACM32.@) | |
| * | |
| */ | |
| MMRESULT WINAPI acmDriverAddW(PHACMDRIVERID phadid, HINSTANCE hinstModule, | |
| LPARAM lParam, DWORD dwPriority, DWORD fdwAdd) | |
| { | |
| PWINE_ACMLOCALDRIVER pLocalDrv = NULL; | |
| TRACE("(%p, %p, %08lx, %08x, %08x)\n", | |
| phadid, hinstModule, lParam, dwPriority, fdwAdd); | |
| if (!phadid) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| /* Check if any unknown flags */ | |
| if (fdwAdd & | |
| ~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND| | |
| ACM_DRIVERADDF_GLOBAL)) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| /* Check if any incompatible flags */ | |
| if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) && | |
| (fdwAdd & ACM_DRIVERADDF_NOTIFYHWND)) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| switch (fdwAdd & ACM_DRIVERADDF_TYPEMASK) { | |
| case ACM_DRIVERADDF_NAME: | |
| /* | |
| hInstModule (unused) | |
| lParam name of value in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32 | |
| dwPriority (unused, set to 0) | |
| */ | |
| *phadid = (HACMDRIVERID) MSACM_RegisterDriverFromRegistry((LPCWSTR)lParam); | |
| if (!*phadid) { | |
| ERR("Unable to register driver via ACM_DRIVERADDF_NAME\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| break; | |
| case ACM_DRIVERADDF_FUNCTION: | |
| /* | |
| hInstModule Handle of module which contains driver entry proc | |
| lParam Driver function address | |
| dwPriority (unused, set to 0) | |
| */ | |
| fdwAdd &= ~ACM_DRIVERADDF_TYPEMASK; | |
| /* FIXME: fdwAdd ignored */ | |
| /* Application-supplied acmDriverProc's are placed at the top of the priority unless | |
| fdwAdd indicates ACM_DRIVERADDF_GLOBAL | |
| */ | |
| pLocalDrv = MSACM_RegisterLocalDriver(hinstModule, (DRIVERPROC)lParam); | |
| *phadid = pLocalDrv ? (HACMDRIVERID) MSACM_RegisterDriver(NULL, NULL, pLocalDrv) : NULL; | |
| if (!*phadid) { | |
| ERR("Unable to register driver via ACM_DRIVERADDF_FUNCTION\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| break; | |
| case ACM_DRIVERADDF_NOTIFYHWND: | |
| /* | |
| hInstModule (unused) | |
| lParam Handle of notification window | |
| dwPriority Window message to send for notification broadcasts | |
| */ | |
| *phadid = (HACMDRIVERID) MSACM_RegisterNotificationWindow((HWND)lParam, dwPriority); | |
| if (!*phadid) { | |
| ERR("Unable to register driver via ACM_DRIVERADDF_NOTIFYHWND\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| break; | |
| default: | |
| ERR("invalid flag value 0x%08x for fdwAdd\n", fdwAdd); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| MSACM_BroadcastNotification(); | |
| return MMSYSERR_NOERROR; | |
| } | |
| /*********************************************************************** | |
| * acmDriverClose (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose) | |
| { | |
| PWINE_ACMDRIVER pad; | |
| PWINE_ACMDRIVERID padid; | |
| PWINE_ACMDRIVER* tpad; | |
| TRACE("(%p, %08x)\n", had, fdwClose); | |
| if (fdwClose) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| pad = MSACM_GetDriver(had); | |
| if (!pad) { | |
| WARN("invalid handle\n"); | |
| return MMSYSERR_INVALHANDLE; | |
| } | |
| padid = pad->obj.pACMDriverID; | |
| /* remove driver from list */ | |
| for (tpad = &(padid->pACMDriverList); *tpad; tpad = &((*tpad)->pNextACMDriver)) { | |
| if (*tpad == pad) { | |
| *tpad = (*tpad)->pNextACMDriver; | |
| break; | |
| } | |
| } | |
| /* close driver if it has been opened */ | |
| if (pad->hDrvr && !pad->pLocalDrvrInst) | |
| CloseDriver(pad->hDrvr, 0, 0); | |
| else if (pad->pLocalDrvrInst) | |
| MSACM_CloseLocalDriver(pad->pLocalDrvrInst); | |
| pad->obj.dwType = 0; | |
| HeapFree(MSACM_hHeap, 0, pad); | |
| return MMSYSERR_NOERROR; | |
| } | |
| /*********************************************************************** | |
| * acmDriverDetailsA (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverDetailsA(HACMDRIVERID hadid, PACMDRIVERDETAILSA padd, DWORD fdwDetails) | |
| { | |
| MMRESULT mmr; | |
| ACMDRIVERDETAILSW addw; | |
| TRACE("(%p, %p, %08x)\n", hadid, padd, fdwDetails); | |
| if (!padd) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| if (padd->cbStruct < 4) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| addw.cbStruct = sizeof(addw); | |
| mmr = acmDriverDetailsW(hadid, &addw, fdwDetails); | |
| if (mmr == 0) { | |
| ACMDRIVERDETAILSA padda; | |
| padda.fccType = addw.fccType; | |
| padda.fccComp = addw.fccComp; | |
| padda.wMid = addw.wMid; | |
| padda.wPid = addw.wPid; | |
| padda.vdwACM = addw.vdwACM; | |
| padda.vdwDriver = addw.vdwDriver; | |
| padda.fdwSupport = addw.fdwSupport; | |
| padda.cFormatTags = addw.cFormatTags; | |
| padda.cFilterTags = addw.cFilterTags; | |
| padda.hicon = addw.hicon; | |
| WideCharToMultiByte( CP_ACP, 0, addw.szShortName, -1, padda.szShortName, | |
| sizeof(padda.szShortName), NULL, NULL ); | |
| WideCharToMultiByte( CP_ACP, 0, addw.szLongName, -1, padda.szLongName, | |
| sizeof(padda.szLongName), NULL, NULL ); | |
| WideCharToMultiByte( CP_ACP, 0, addw.szCopyright, -1, padda.szCopyright, | |
| sizeof(padda.szCopyright), NULL, NULL ); | |
| WideCharToMultiByte( CP_ACP, 0, addw.szLicensing, -1, padda.szLicensing, | |
| sizeof(padda.szLicensing), NULL, NULL ); | |
| WideCharToMultiByte( CP_ACP, 0, addw.szFeatures, -1, padda.szFeatures, | |
| sizeof(padda.szFeatures), NULL, NULL ); | |
| padda.cbStruct = min(padd->cbStruct, sizeof(*padd)); | |
| memcpy(padd, &padda, padda.cbStruct); | |
| } | |
| return mmr; | |
| } | |
| /*********************************************************************** | |
| * acmDriverDetailsW (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverDetailsW(HACMDRIVERID hadid, PACMDRIVERDETAILSW padd, DWORD fdwDetails) | |
| { | |
| HACMDRIVER acmDrvr; | |
| MMRESULT mmr; | |
| TRACE("(%p, %p, %08x)\n", hadid, padd, fdwDetails); | |
| if (!padd) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| if (padd->cbStruct < 4) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| if (fdwDetails) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| mmr = acmDriverOpen(&acmDrvr, hadid, 0); | |
| if (mmr == MMSYSERR_NOERROR) { | |
| ACMDRIVERDETAILSW paddw; | |
| paddw.cbStruct = sizeof(paddw); | |
| mmr = MSACM_Message(acmDrvr, ACMDM_DRIVER_DETAILS, (LPARAM)&paddw, 0); | |
| acmDriverClose(acmDrvr, 0); | |
| paddw.cbStruct = min(padd->cbStruct, sizeof(*padd)); | |
| memcpy(padd, &paddw, paddw.cbStruct); | |
| } | |
| else if (mmr == MMSYSERR_NODRIVER) | |
| return MMSYSERR_NOTSUPPORTED; | |
| return mmr; | |
| } | |
| /*********************************************************************** | |
| * acmDriverEnum (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD_PTR dwInstance, | |
| DWORD fdwEnum) | |
| { | |
| PWINE_ACMDRIVERID padid; | |
| DWORD fdwSupport; | |
| TRACE("(%p, %08lx, %08x)\n", fnCallback, dwInstance, fdwEnum); | |
| if (!fnCallback) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| if (fdwEnum & ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) { | |
| fdwSupport = padid->fdwSupport; | |
| if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) { | |
| if (fdwEnum & ACM_DRIVERENUMF_DISABLED) | |
| fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED; | |
| else | |
| continue; | |
| } | |
| if (!(*fnCallback)((HACMDRIVERID)padid, dwInstance, fdwSupport)) | |
| break; | |
| } | |
| return MMSYSERR_NOERROR; | |
| } | |
| /*********************************************************************** | |
| * acmDriverID (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID) | |
| { | |
| PWINE_ACMOBJ pao; | |
| TRACE("(%p, %p, %08x)\n", hao, phadid, fdwDriverID); | |
| if (fdwDriverID) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| pao = MSACM_GetObj(hao, WINE_ACMOBJ_DONTCARE); | |
| if (!pao) { | |
| WARN("invalid handle\n"); | |
| return MMSYSERR_INVALHANDLE; | |
| } | |
| if (!phadid) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| *phadid = (HACMDRIVERID) pao->pACMDriverID; | |
| return MMSYSERR_NOERROR; | |
| } | |
| /*********************************************************************** | |
| * acmDriverMessage (MSACM32.@) | |
| * | |
| * Note: MSDN documentation (July 2001) is incomplete. This function | |
| * accepts sending messages to an HACMDRIVERID in addition to the | |
| * documented HACMDRIVER. In fact, for DRV_QUERYCONFIGURE and DRV_CONFIGURE, | |
| * this might actually be the required mode of operation. | |
| * | |
| * Note: For DRV_CONFIGURE, msacm supplies its own DRVCONFIGINFO structure | |
| * when the application fails to supply one. Some native drivers depend on | |
| * this and refuse to display unless a valid DRVCONFIGINFO structure is | |
| * built and supplied. | |
| */ | |
| LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2) | |
| { | |
| TRACE("(%p, %04x, %08lx, %08lx\n", had, uMsg, lParam1, lParam2); | |
| if ((uMsg >= ACMDM_USER && uMsg < ACMDM_RESERVED_LOW) || | |
| uMsg == ACMDM_DRIVER_ABOUT || | |
| uMsg == DRV_QUERYCONFIGURE || | |
| uMsg == DRV_CONFIGURE) | |
| { | |
| PWINE_ACMDRIVERID padid; | |
| LRESULT lResult; | |
| LPDRVCONFIGINFO pConfigInfo = NULL; | |
| LPWSTR section_name = NULL; | |
| LPWSTR alias_name = NULL; | |
| /* Check whether handle is an HACMDRIVERID */ | |
| padid = MSACM_GetDriverID((HACMDRIVERID)had); | |
| /* If the message is DRV_CONFIGURE, and the application provides no | |
| DRVCONFIGINFO structure, msacm must supply its own. | |
| */ | |
| if (uMsg == DRV_CONFIGURE && lParam2 == 0) { | |
| LPWSTR pAlias; | |
| /* Get the alias from the HACMDRIVERID */ | |
| if (padid) { | |
| pAlias = padid->pszDriverAlias; | |
| if (pAlias == NULL) { | |
| WARN("DRV_CONFIGURE: no alias for this driver, cannot self-supply alias\n"); | |
| } | |
| } else { | |
| FIXME("DRV_CONFIGURE: reverse lookup HACMDRIVER -> HACMDRIVERID not implemented\n"); | |
| pAlias = NULL; | |
| } | |
| if (pAlias != NULL) { | |
| /* DRVCONFIGINFO is only 12 bytes long, but native msacm | |
| * reports a 16-byte structure to codecs, so allocate 16 bytes, | |
| * just to be on the safe side. | |
| */ | |
| const unsigned int iStructSize = 16; | |
| pConfigInfo = HeapAlloc(MSACM_hHeap, 0, iStructSize); | |
| if (!pConfigInfo) { | |
| ERR("OOM while supplying DRVCONFIGINFO for DRV_CONFIGURE, using NULL\n"); | |
| } else { | |
| static const WCHAR drivers32[] = {'D','r','i','v','e','r','s','3','2','\0'}; | |
| pConfigInfo->dwDCISize = iStructSize; | |
| section_name = HeapAlloc(MSACM_hHeap, 0, (strlenW(drivers32) + 1) * sizeof(WCHAR)); | |
| if (section_name) strcpyW(section_name, drivers32); | |
| pConfigInfo->lpszDCISectionName = section_name; | |
| alias_name = HeapAlloc(MSACM_hHeap, 0, (strlenW(pAlias) + 1) * sizeof(WCHAR)); | |
| if (alias_name) strcpyW(alias_name, pAlias); | |
| pConfigInfo->lpszDCIAliasName = alias_name; | |
| if (pConfigInfo->lpszDCISectionName == NULL || pConfigInfo->lpszDCIAliasName == NULL) { | |
| HeapFree(MSACM_hHeap, 0, alias_name); | |
| HeapFree(MSACM_hHeap, 0, section_name); | |
| HeapFree(MSACM_hHeap, 0, pConfigInfo); | |
| pConfigInfo = NULL; | |
| ERR("OOM while supplying DRVCONFIGINFO for DRV_CONFIGURE, using NULL\n"); | |
| } | |
| } | |
| } | |
| lParam2 = (LPARAM)pConfigInfo; | |
| } | |
| if (padid) { | |
| /* Handle is really an HACMDRIVERID, must have an open session to get an HACMDRIVER */ | |
| if (padid->pACMDriverList != NULL) { | |
| lResult = MSACM_Message((HACMDRIVER)padid->pACMDriverList, uMsg, lParam1, lParam2); | |
| } else { | |
| MMRESULT mmr = acmDriverOpen(&had, (HACMDRIVERID)padid, 0); | |
| if (mmr != MMSYSERR_NOERROR) { | |
| lResult = MMSYSERR_INVALPARAM; | |
| } else { | |
| lResult = acmDriverMessage(had, uMsg, lParam1, lParam2); | |
| acmDriverClose(had, 0); | |
| } | |
| } | |
| } else { | |
| lResult = MSACM_Message(had, uMsg, lParam1, lParam2); | |
| } | |
| if (pConfigInfo) { | |
| HeapFree(MSACM_hHeap, 0, alias_name); | |
| HeapFree(MSACM_hHeap, 0, section_name); | |
| HeapFree(MSACM_hHeap, 0, pConfigInfo); | |
| } | |
| return lResult; | |
| } | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| /*********************************************************************** | |
| * acmDriverOpen (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen) | |
| { | |
| PWINE_ACMDRIVERID padid; | |
| PWINE_ACMDRIVER pad = NULL; | |
| MMRESULT ret; | |
| TRACE("(%p, %p, %08u)\n", phad, hadid, fdwOpen); | |
| if (!phad) { | |
| WARN("invalid parameter\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| if (fdwOpen) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| padid = MSACM_GetDriverID(hadid); | |
| if (!padid) { | |
| WARN("invalid handle\n"); | |
| return MMSYSERR_INVALHANDLE; | |
| } | |
| pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER)); | |
| if (!pad) { | |
| WARN("no memory\n"); | |
| return MMSYSERR_NOMEM; | |
| } | |
| pad->obj.dwType = WINE_ACMOBJ_DRIVER; | |
| pad->obj.pACMDriverID = padid; | |
| pad->hDrvr = 0; | |
| pad->pLocalDrvrInst = NULL; | |
| if (padid->pLocalDriver == NULL) | |
| { | |
| ACMDRVOPENDESCW adod; | |
| int len; | |
| LPWSTR section_name; | |
| /* this is not an externally added driver... need to actually load it */ | |
| if (!padid->pszDriverAlias) | |
| { | |
| ret = MMSYSERR_ERROR; | |
| goto gotError; | |
| } | |
| adod.cbStruct = sizeof(adod); | |
| adod.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC; | |
| adod.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED; | |
| adod.dwVersion = acmGetVersion(); | |
| adod.dwFlags = fdwOpen; | |
| adod.dwError = 0; | |
| len = strlen("Drivers32") + 1; | |
| section_name = HeapAlloc(MSACM_hHeap, 0, len * sizeof(WCHAR)); | |
| MultiByteToWideChar(CP_ACP, 0, "Drivers32", -1, section_name, len); | |
| adod.pszSectionName = section_name; | |
| adod.pszAliasName = padid->pszDriverAlias; | |
| adod.dnDevNode = 0; | |
| pad->hDrvr = OpenDriver(padid->pszDriverAlias, NULL, (DWORD_PTR)&adod); | |
| HeapFree(MSACM_hHeap, 0, section_name); | |
| if (!pad->hDrvr) | |
| { | |
| ret = adod.dwError; | |
| if (ret == MMSYSERR_NOERROR) | |
| ret = MMSYSERR_NODRIVER; | |
| goto gotError; | |
| } | |
| } | |
| else | |
| { | |
| ACMDRVOPENDESCW adod; | |
| pad->hDrvr = NULL; | |
| adod.cbStruct = sizeof(adod); | |
| adod.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC; | |
| adod.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED; | |
| adod.dwVersion = acmGetVersion(); | |
| adod.dwFlags = fdwOpen; | |
| adod.dwError = 0; | |
| adod.pszSectionName = NULL; | |
| adod.pszAliasName = NULL; | |
| adod.dnDevNode = 0; | |
| pad->pLocalDrvrInst = MSACM_OpenLocalDriver(padid->pLocalDriver, (DWORD_PTR)&adod); | |
| if (!pad->pLocalDrvrInst) | |
| { | |
| ret = adod.dwError; | |
| if (ret == MMSYSERR_NOERROR) | |
| ret = MMSYSERR_NODRIVER; | |
| goto gotError; | |
| } | |
| } | |
| /* insert new pad at beg of list */ | |
| pad->pNextACMDriver = padid->pACMDriverList; | |
| padid->pACMDriverList = pad; | |
| /* FIXME: Create a WINE_ACMDRIVER32 */ | |
| *phad = (HACMDRIVER)pad; | |
| TRACE("%s => %p\n", debugstr_w(padid->pszDriverAlias), pad); | |
| return MMSYSERR_NOERROR; | |
| gotError: | |
| WARN("failed: ret = %08x\n", ret); | |
| if (pad && !pad->hDrvr) | |
| HeapFree(MSACM_hHeap, 0, pad); | |
| return ret; | |
| } | |
| /*********************************************************************** | |
| * acmDriverPriority (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fdwPriority) | |
| { | |
| TRACE("(%p, %08x, %08x)\n", hadid, dwPriority, fdwPriority); | |
| /* Check for unknown flags */ | |
| if (fdwPriority & | |
| ~(ACM_DRIVERPRIORITYF_ENABLE|ACM_DRIVERPRIORITYF_DISABLE| | |
| ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| /* Check for incompatible flags */ | |
| if ((fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) && | |
| (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE)) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| /* Check for incompatible flags */ | |
| if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) && | |
| (fdwPriority & ACM_DRIVERPRIORITYF_END)) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| /* According to MSDN, ACM_DRIVERPRIORITYF_BEGIN and ACM_DRIVERPRIORITYF_END | |
| may only appear by themselves, and in addition, hadid and dwPriority must | |
| both be zero */ | |
| if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) || | |
| (fdwPriority & ACM_DRIVERPRIORITYF_END)) { | |
| if (fdwPriority & ~(ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) { | |
| WARN("ACM_DRIVERPRIORITYF_[BEGIN|END] cannot be used with any other flags\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| if (dwPriority) { | |
| WARN("priority invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| if (hadid) { | |
| WARN("non-null hadid invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n"); | |
| return MMSYSERR_INVALPARAM; | |
| } | |
| /* FIXME: MSDN wording suggests that deferred notification should be | |
| implemented as a system-wide lock held by a calling task, and that | |
| re-enabling notifications should broadcast them across all processes. | |
| This implementation uses a simple DWORD counter. One consequence of the | |
| current implementation is that applications will never see | |
| MMSYSERR_ALLOCATED as a return error. | |
| */ | |
| if (fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) { | |
| MSACM_DisableNotifications(); | |
| } else if (fdwPriority & ACM_DRIVERPRIORITYF_END) { | |
| MSACM_EnableNotifications(); | |
| } | |
| return MMSYSERR_NOERROR; | |
| } else { | |
| PWINE_ACMDRIVERID padid; | |
| PWINE_ACMNOTIFYWND panwnd; | |
| BOOL bPerformBroadcast = FALSE; | |
| /* Fetch driver ID */ | |
| padid = MSACM_GetDriverID(hadid); | |
| panwnd = MSACM_GetNotifyWnd(hadid); | |
| if (!padid && !panwnd) { | |
| WARN("invalid handle\n"); | |
| return MMSYSERR_INVALHANDLE; | |
| } | |
| if (padid) { | |
| /* Check whether driver ID is appropriate for requested op */ | |
| if (dwPriority) { | |
| if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL) { | |
| return MMSYSERR_NOTSUPPORTED; | |
| } | |
| if (dwPriority != 1 && dwPriority != (DWORD)-1) { | |
| FIXME("unexpected priority %d, using sign only\n", dwPriority); | |
| if ((signed)dwPriority < 0) dwPriority = (DWORD)-1; | |
| if (dwPriority > 0) dwPriority = 1; | |
| } | |
| if (dwPriority == 1 && (padid->pPrevACMDriverID == NULL || | |
| (padid->pPrevACMDriverID->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL))) { | |
| /* do nothing - driver is first of list, or first after last | |
| local driver */ | |
| } else if (dwPriority == (DWORD)-1 && padid->pNextACMDriverID == NULL) { | |
| /* do nothing - driver is last of list */ | |
| } else { | |
| MSACM_RePositionDriver(padid, dwPriority); | |
| bPerformBroadcast = TRUE; | |
| } | |
| } | |
| /* Check whether driver ID should be enabled or disabled */ | |
| if (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE) { | |
| if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED)) { | |
| padid->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED; | |
| bPerformBroadcast = TRUE; | |
| } | |
| } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) { | |
| if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) { | |
| padid->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED; | |
| bPerformBroadcast = TRUE; | |
| } | |
| } | |
| } | |
| if (panwnd) { | |
| if (dwPriority) { | |
| return MMSYSERR_NOTSUPPORTED; | |
| } | |
| /* Check whether notify window should be enabled or disabled */ | |
| if (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE) { | |
| if (!(panwnd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED)) { | |
| panwnd->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED; | |
| bPerformBroadcast = TRUE; | |
| } | |
| } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) { | |
| if (panwnd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) { | |
| panwnd->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED; | |
| bPerformBroadcast = TRUE; | |
| } | |
| } | |
| } | |
| /* Perform broadcast of changes */ | |
| if (bPerformBroadcast) { | |
| MSACM_WriteCurrentPriorities(); | |
| MSACM_BroadcastNotification(); | |
| } | |
| return MMSYSERR_NOERROR; | |
| } | |
| } | |
| /*********************************************************************** | |
| * acmDriverRemove (MSACM32.@) | |
| */ | |
| MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove) | |
| { | |
| PWINE_ACMDRIVERID padid; | |
| PWINE_ACMNOTIFYWND panwnd; | |
| TRACE("(%p, %08x)\n", hadid, fdwRemove); | |
| padid = MSACM_GetDriverID(hadid); | |
| panwnd = MSACM_GetNotifyWnd(hadid); | |
| if (!padid && !panwnd) { | |
| WARN("invalid handle\n"); | |
| return MMSYSERR_INVALHANDLE; | |
| } | |
| if (fdwRemove) { | |
| WARN("invalid flag\n"); | |
| return MMSYSERR_INVALFLAG; | |
| } | |
| if (padid) MSACM_UnregisterDriver(padid); | |
| if (panwnd) MSACM_UnRegisterNotificationWindow(panwnd); | |
| MSACM_BroadcastNotification(); | |
| return MMSYSERR_NOERROR; | |
| } |