/* -*- 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 & ACM_DRIVERADDF_TYPEMASK); 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; }