diff --git a/dlls/msacm/driver.c b/dlls/msacm/driver.c index 5cb56c5574d..98430a5fa24 100644 --- a/dlls/msacm/driver.c +++ b/dlls/msacm/driver.c @@ -101,6 +101,8 @@ MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule, MMRESULT WINAPI acmDriverAddW(PHACMDRIVERID phadid, HINSTANCE hinstModule, LPARAM lParam, DWORD dwPriority, DWORD fdwAdd) { + PWINE_ACMLOCALDRIVER pLocalDrv = NULL; + TRACE("(%p, %p, %08lx, %08lx, %08lx)\n", phadid, hinstModule, lParam, dwPriority, fdwAdd); @@ -144,11 +146,17 @@ MMRESULT WINAPI acmDriverAddW(PHACMDRIVERID phadid, HINSTANCE hinstModule, dwPriority (unused, set to 0) */ fdwAdd &= ~ACM_DRIVERADDF_TYPEMASK; - - *phadid = 0; - FIXME("(%p, %p, %ld, %ld, %ld): ACM_DRIVERADDF_FUNCTION: stub\n", phadid, hinstModule, lParam, dwPriority, fdwAdd); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return MMSYSERR_ERROR; + /* 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) @@ -203,8 +211,10 @@ MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose) } /* close driver if it has been opened */ - if (pad->hDrvr && !padid->hInstModule) + if (pad->hDrvr && !pad->pLocalDrvrInst) CloseDriver(pad->hDrvr, 0, 0); + else if (pad->pLocalDrvrInst) + MSACM_CloseLocalDriver(pad->pLocalDrvrInst); HeapFree(MSACM_hHeap, 0, pad); @@ -506,8 +516,10 @@ MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpe pad->obj.dwType = WINE_ACMOBJ_DRIVER; pad->obj.pACMDriverID = padid; + pad->hDrvr = 0; + pad->pLocalDrvrInst = NULL; - if (!(pad->hDrvr = (HDRVR)padid->hInstModule)) + if (padid->pLocalDriver == NULL) { ACMDRVOPENDESCW adod; int len; @@ -540,6 +552,29 @@ MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpe 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)&adod); + if (!pad->pLocalDrvrInst) + { + ret = adod.dwError; + goto gotError; + } + } /* insert new pad at beg of list */ pad->pNextACMDriver = padid->pACMDriverList; diff --git a/dlls/msacm/internal.c b/dlls/msacm/internal.c index 6e1f9ba5638..78ecb14fe68 100644 --- a/dlls/msacm/internal.c +++ b/dlls/msacm/internal.c @@ -281,12 +281,12 @@ static BOOL MSACM_WriteCache(PWINE_ACMDRIVERID padid) * MSACM_RegisterDriver() */ PWINE_ACMDRIVERID MSACM_RegisterDriver(LPCWSTR pszDriverAlias, LPCWSTR pszFileName, - HINSTANCE hinstModule) + PWINE_ACMLOCALDRIVER pLocalDriver) { PWINE_ACMDRIVERID padid; TRACE("(%s, %s, %p)\n", - debugstr_w(pszDriverAlias), debugstr_w(pszFileName), hinstModule); + debugstr_w(pszDriverAlias), debugstr_w(pszFileName), pLocalDriver); padid = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID)); padid->obj.dwType = WINE_ACMOBJ_DRIVERID; @@ -303,22 +303,35 @@ PWINE_ACMDRIVERID MSACM_RegisterDriver(LPCWSTR pszDriverAlias, LPCWSTR pszFileNa padid->pszFileName = HeapAlloc( MSACM_hHeap, 0, (strlenW(pszFileName)+1) * sizeof(WCHAR) ); strcpyW( padid->pszFileName, pszFileName ); } - padid->hInstModule = hinstModule; + padid->pLocalDriver = pLocalDriver; padid->pACMDriverList = NULL; - padid->pNextACMDriverID = NULL; - padid->pPrevACMDriverID = MSACM_pLastACMDriverID; - if (MSACM_pLastACMDriverID) - MSACM_pLastACMDriverID->pNextACMDriverID = padid; - MSACM_pLastACMDriverID = padid; - if (!MSACM_pFirstACMDriverID) - MSACM_pFirstACMDriverID = padid; + + if (pLocalDriver) { + padid->pPrevACMDriverID = NULL; + padid->pNextACMDriverID = MSACM_pFirstACMDriverID; + if (MSACM_pFirstACMDriverID) + MSACM_pFirstACMDriverID->pPrevACMDriverID = padid; + MSACM_pFirstACMDriverID = padid; + if (!MSACM_pLastACMDriverID) + MSACM_pLastACMDriverID = padid; + } else { + padid->pNextACMDriverID = NULL; + padid->pPrevACMDriverID = MSACM_pLastACMDriverID; + if (MSACM_pLastACMDriverID) + MSACM_pLastACMDriverID->pNextACMDriverID = padid; + MSACM_pLastACMDriverID = padid; + if (!MSACM_pFirstACMDriverID) + MSACM_pFirstACMDriverID = padid; + } /* disable the driver if we cannot load the cache */ - if (!MSACM_ReadCache(padid) && !MSACM_FillCache(padid)) { + if ((!padid->pszDriverAlias || !MSACM_ReadCache(padid)) && !MSACM_FillCache(padid)) { WARN("Couldn't load cache for ACM driver (%s)\n", debugstr_w(pszFileName)); MSACM_UnregisterDriver(padid); return NULL; } + + if (pLocalDriver) padid->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_LOCAL; return padid; } @@ -724,6 +737,7 @@ PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p) pNextACMDriverID = p->pNextACMDriverID; + if (p->pLocalDriver) MSACM_UnregisterLocalDriver(p->pLocalDriver); HeapFree(MSACM_hHeap, 0, p); return pNextACMDriverID; @@ -744,7 +758,7 @@ void MSACM_UnregisterAllDrivers(void) while (panwnd) { panwnd = MSACM_UnRegisterNotificationWindow(panwnd); - } + } } /*********************************************************************** @@ -784,6 +798,17 @@ PWINE_ACMNOTIFYWND MSACM_GetNotifyWnd(HACMDRIVERID hDriver) return (PWINE_ACMNOTIFYWND)MSACM_GetObj((HACMOBJ)hDriver, WINE_ACMOBJ_NOTIFYWND); } +/*********************************************************************** + * MSACM_GetLocalDriver() + */ +/* +PWINE_ACMLOCALDRIVER MSACM_GetLocalDriver(HACMDRIVER hDriver) +{ + return (PWINE_ACMLOCALDRIVER)MSACM_GetObj((HACMOBJ)hDriver, WINE_ACMOBJ_LOCALDRIVER); +} +*/ +#define MSACM_DRIVER_SendMessage(PDRVRINST, msg, lParam1, lParam2) \ + (PDRVRINST)->pLocalDriver->lpDrvProc((PDRVRINST)->dwDriverID, (HDRVR)(PDRVRINST), msg, lParam1, lParam2) /*********************************************************************** * MSACM_Message() @@ -792,5 +817,252 @@ MMRESULT MSACM_Message(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2 { PWINE_ACMDRIVER pad = MSACM_GetDriver(had); - return pad ? SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2) : MMSYSERR_INVALHANDLE; + if (!pad) return MMSYSERR_INVALHANDLE; + if (pad->hDrvr) return SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2); + if (pad->pLocalDrvrInst) return MSACM_DRIVER_SendMessage(pad->pLocalDrvrInst, uMsg, lParam1, lParam2); + + return MMSYSERR_INVALHANDLE; +} + +PWINE_ACMLOCALDRIVER MSACM_pFirstACMLocalDriver = NULL; +PWINE_ACMLOCALDRIVER MSACM_pLastACMLocalDriver = NULL; + +PWINE_ACMLOCALDRIVER MSACM_RegisterLocalDriver(HMODULE hModule, DRIVERPROC lpDriverProc) +{ + PWINE_ACMLOCALDRIVER paldrv; + + TRACE("(%p, %p)\n", hModule, lpDriverProc); + if (!hModule || !lpDriverProc) return NULL; + + /* look up previous instance of local driver module */ + for (paldrv = MSACM_pFirstACMLocalDriver; paldrv; paldrv = paldrv->pNextACMLocalDrv) + { + if (paldrv->hModule == hModule && paldrv->lpDrvProc == lpDriverProc) return paldrv; + } + + paldrv = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMLOCALDRIVER)); + paldrv->obj.dwType = WINE_ACMOBJ_LOCALDRIVER; + paldrv->obj.pACMDriverID = 0; + paldrv->hModule = hModule; + paldrv->lpDrvProc = lpDriverProc; + paldrv->pACMInstList = NULL; + + paldrv->pNextACMLocalDrv = NULL; + paldrv->pPrevACMLocalDrv = MSACM_pLastACMLocalDriver; + if (MSACM_pLastACMLocalDriver) + MSACM_pLastACMLocalDriver->pNextACMLocalDrv = paldrv; + MSACM_pLastACMLocalDriver = paldrv; + if (!MSACM_pFirstACMLocalDriver) + MSACM_pFirstACMLocalDriver = paldrv; + + return paldrv; +} + +/************************************************************************** + * MSACM_GetNumberOfModuleRefs [internal] + * + * Returns the number of open drivers which share the same module. + * Inspired from implementation in dlls/winmm/driver.c + */ +static unsigned MSACM_GetNumberOfModuleRefs(HMODULE hModule, DRIVERPROC lpDrvProc, WINE_ACMLOCALDRIVERINST ** found) +{ + PWINE_ACMLOCALDRIVER lpDrv; + unsigned count = 0; + + if (found) *found = NULL; + for (lpDrv = MSACM_pFirstACMLocalDriver; lpDrv; lpDrv = lpDrv->pNextACMLocalDrv) + { + if (lpDrv->hModule == hModule && lpDrv->lpDrvProc == lpDrvProc) + { + PWINE_ACMLOCALDRIVERINST pInst = lpDrv->pACMInstList; + + while (pInst) { + if (found && !*found) *found = pInst; + count++; + pInst = pInst->pNextACMInst; + } + } + } + return count; +} + +/************************************************************************** + * MSACM_RemoveFromList [internal] + * + * Generates all the logic to handle driver closure / deletion + * Removes a driver struct to the list of open drivers. + */ +static BOOL MSACM_RemoveFromList(PWINE_ACMLOCALDRIVERINST lpDrv) +{ + PWINE_ACMLOCALDRIVER pDriverBase = lpDrv->pLocalDriver; + PWINE_ACMLOCALDRIVERINST pPrevInst; + + /* last of this driver in list ? */ + if (MSACM_GetNumberOfModuleRefs(pDriverBase->hModule, pDriverBase->lpDrvProc, NULL) == 1) { + MSACM_DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L); + MSACM_DRIVER_SendMessage(lpDrv, DRV_FREE, 0L, 0L); + } + + pPrevInst = NULL; + if (pDriverBase->pACMInstList != lpDrv) { + pPrevInst = pDriverBase->pACMInstList; + while (pPrevInst && pPrevInst->pNextACMInst != lpDrv) + pPrevInst = pPrevInst->pNextACMInst; + if (!pPrevInst) { + ERR("requested to remove invalid instance %p\n", pPrevInst); + return FALSE; + } + } + if (!pPrevInst) { + /* first driver instance on list */ + pDriverBase->pACMInstList = lpDrv->pNextACMInst; + } else { + pPrevInst->pNextACMInst = lpDrv->pNextACMInst; + } + return TRUE; +} + +/************************************************************************** + * MSACM_AddToList [internal] + * + * Adds a driver struct to the list of open drivers. + * Generates all the logic to handle driver creation / open. + */ +static BOOL MSACM_AddToList(PWINE_ACMLOCALDRIVERINST lpNewDrv, LPARAM lParam2) +{ + PWINE_ACMLOCALDRIVER pDriverBase = lpNewDrv->pLocalDriver; + + /* first of this driver in list ? */ + if (MSACM_GetNumberOfModuleRefs(pDriverBase->hModule, pDriverBase->lpDrvProc, NULL) == 0) { + if (MSACM_DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) { + FIXME("DRV_LOAD failed on driver %p\n", lpNewDrv); + return FALSE; + } + /* returned value is not checked */ + MSACM_DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L); + } + + lpNewDrv->pNextACMInst = NULL; + if (pDriverBase->pACMInstList == NULL) { + pDriverBase->pACMInstList = lpNewDrv; + } else { + PWINE_ACMLOCALDRIVERINST lpDrvInst = pDriverBase->pACMInstList; + + while (lpDrvInst->pNextACMInst != NULL) + lpDrvInst = lpDrvInst->pNextACMInst; + + lpDrvInst->pNextACMInst = lpNewDrv; + } + + /* Now just open a new instance of a driver on this module */ + lpNewDrv->dwDriverID = MSACM_DRIVER_SendMessage(lpNewDrv, DRV_OPEN, 0, lParam2); + + if (lpNewDrv->dwDriverID == 0) { + FIXME("DRV_OPEN failed on driver %p\n", lpNewDrv); + MSACM_RemoveFromList(lpNewDrv); + return FALSE; + } + return TRUE; +} + +PWINE_ACMLOCALDRIVERINST MSACM_OpenLocalDriver(PWINE_ACMLOCALDRIVER paldrv, LPARAM lParam2) +{ + PWINE_ACMLOCALDRIVERINST pDrvInst; + + pDrvInst = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMLOCALDRIVERINST)); + pDrvInst->pLocalDriver = paldrv; + pDrvInst->dwDriverID = 0; + pDrvInst->pNextACMInst = NULL; + pDrvInst->bSession = FALSE; + + /* Win32 installable drivers must support a two phase opening scheme: + * + first open with NULL as lParam2 (session instance), + * + then do a second open with the real non null lParam2) + */ + if (MSACM_GetNumberOfModuleRefs(paldrv->hModule, paldrv->lpDrvProc, NULL) == 0 && lParam2) + { + PWINE_ACMLOCALDRIVERINST ret; + + if (!MSACM_AddToList(pDrvInst, 0L)) + { + ERR("load0 failed\n"); + goto exit; + } + ret = MSACM_OpenLocalDriver(paldrv, lParam2); + if (!ret) + { + MSACM_CloseLocalDriver(pDrvInst); + ERR("load1 failed\n"); + goto exit; + } + pDrvInst->bSession = TRUE; + return ret; + } + + if (!MSACM_AddToList(pDrvInst, lParam2)) + { + ERR("load failed\n"); + goto exit; + } + + TRACE("=> %p\n", pDrvInst); + return pDrvInst; +exit: + HeapFree(MSACM_hHeap, 0, pDrvInst); + return NULL; +} + +LRESULT MSACM_CloseLocalDriver(PWINE_ACMLOCALDRIVERINST paldrv) +{ + if (MSACM_RemoveFromList(paldrv)) { + PWINE_ACMLOCALDRIVERINST lpDrv0; + PWINE_ACMLOCALDRIVER pDriverBase = paldrv->pLocalDriver; + + MSACM_DRIVER_SendMessage(paldrv, DRV_CLOSE, 0, 0); + paldrv->dwDriverID = 0; + + if (paldrv->bSession) + ERR("should not directly close session instance (%p)\n", paldrv); + + /* if driver has an opened session instance, we have to close it too */ + if (MSACM_GetNumberOfModuleRefs(pDriverBase->hModule, pDriverBase->lpDrvProc, &lpDrv0) == 1 && + lpDrv0->bSession) + { + MSACM_DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0L, 0L); + lpDrv0->dwDriverID = 0; + MSACM_RemoveFromList(lpDrv0); + HeapFree(GetProcessHeap(), 0, lpDrv0); + } + + HeapFree(MSACM_hHeap, 0, paldrv); + return TRUE; + } + ERR("unable to close driver instance\n"); + return FALSE; +} + +PWINE_ACMLOCALDRIVER MSACM_UnregisterLocalDriver(PWINE_ACMLOCALDRIVER paldrv) +{ + PWINE_ACMLOCALDRIVER pNextACMLocalDriver; + + if (paldrv->pACMInstList) { + ERR("local driver instances still present after closing all drivers - memory leak\n"); + return NULL; + } + + if (paldrv == MSACM_pFirstACMLocalDriver) + MSACM_pFirstACMLocalDriver = paldrv->pNextACMLocalDrv; + if (paldrv == MSACM_pLastACMLocalDriver) + MSACM_pLastACMLocalDriver = paldrv->pPrevACMLocalDrv; + + if (paldrv->pPrevACMLocalDrv) + paldrv->pPrevACMLocalDrv->pNextACMLocalDrv = paldrv->pNextACMLocalDrv; + if (paldrv->pNextACMLocalDrv) + paldrv->pNextACMLocalDrv->pPrevACMLocalDrv = paldrv->pPrevACMLocalDrv; + + pNextACMLocalDriver = paldrv->pNextACMLocalDrv; + + HeapFree(MSACM_hHeap, 0, paldrv); + + return pNextACMLocalDriver; } diff --git a/dlls/msacm/wineacm.h b/dlls/msacm/wineacm.h index 1a56b1a4e11..abbb4f8b6aa 100644 --- a/dlls/msacm/wineacm.h +++ b/dlls/msacm/wineacm.h @@ -292,6 +292,7 @@ typedef struct _WINE_ACMDRIVER *PWINE_ACMDRIVER; #define WINE_ACMOBJ_DRIVER 0x5EED0002 #define WINE_ACMOBJ_STREAM 0x5EED0003 #define WINE_ACMOBJ_NOTIFYWND 0x5EED0004 +#define WINE_ACMOBJ_LOCALDRIVER 0x5EED0005 typedef struct _WINE_ACMOBJ { @@ -299,10 +300,32 @@ typedef struct _WINE_ACMOBJ PWINE_ACMDRIVERID pACMDriverID; } WINE_ACMOBJ, *PWINE_ACMOBJ; +typedef struct _WINE_ACMLOCALDRIVER * PWINE_ACMLOCALDRIVER; +typedef struct _WINE_ACMLOCALDRIVERINST * PWINE_ACMLOCALDRIVERINST; +typedef struct _WINE_ACMLOCALDRIVER +{ + WINE_ACMOBJ obj; + HMODULE hModule; + DRIVERPROC lpDrvProc; + PWINE_ACMLOCALDRIVERINST pACMInstList; + PWINE_ACMLOCALDRIVER pNextACMLocalDrv; + PWINE_ACMLOCALDRIVER pPrevACMLocalDrv; +} WINE_ACMLOCALDRIVER; + +typedef struct _WINE_ACMLOCALDRIVERINST +{ + PWINE_ACMLOCALDRIVER pLocalDriver; + DWORD dwDriverID; + BOOL bSession; + PWINE_ACMLOCALDRIVERINST pNextACMInst; +} WINE_ACMLOCALDRIVERINST; + typedef struct _WINE_ACMDRIVER { WINE_ACMOBJ obj; HDRVR hDrvr; + PWINE_ACMLOCALDRIVERINST pLocalDrvrInst; + PWINE_ACMDRIVER pNextACMDriver; } WINE_ACMDRIVER; @@ -319,7 +342,7 @@ typedef struct _WINE_ACMDRIVERID WINE_ACMOBJ obj; LPWSTR pszDriverAlias; LPWSTR pszFileName; - HINSTANCE hInstModule; /* NULL if global */ + PWINE_ACMLOCALDRIVER pLocalDriver; /* NULL if global */ PWINE_ACMDRIVER pACMDriverList; PWINE_ACMDRIVERID pNextACMDriverID; PWINE_ACMDRIVERID pPrevACMDriverID; @@ -349,7 +372,7 @@ extern HANDLE MSACM_hHeap; extern PWINE_ACMDRIVERID MSACM_pFirstACMDriverID; extern PWINE_ACMDRIVERID MSACM_pLastACMDriverID; extern PWINE_ACMDRIVERID MSACM_RegisterDriver(LPCWSTR pszDriverAlias, LPCWSTR pszFileName, - HINSTANCE hinstModule); + PWINE_ACMLOCALDRIVER pLocalDriver); extern void MSACM_RegisterAllDrivers(void); extern PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p); extern void MSACM_UnregisterAllDrivers(void); @@ -371,6 +394,13 @@ extern PWINE_ACMNOTIFYWND MSACM_UnRegisterNotificationWindow(PWINE_ACMNOTIFYWND) extern PWINE_ACMDRIVERID MSACM_RegisterDriverFromRegistry(LPCWSTR pszRegEntry); +extern PWINE_ACMLOCALDRIVER MSACM_RegisterLocalDriver(HMODULE hModule, DRIVERPROC lpDriverProc); +extern PWINE_ACMLOCALDRIVERINST MSACM_OpenLocalDriver(PWINE_ACMLOCALDRIVER, LPARAM); +extern LRESULT MSACM_CloseLocalDriver(PWINE_ACMLOCALDRIVERINST); +extern PWINE_ACMLOCALDRIVER MSACM_UnregisterLocalDriver(PWINE_ACMLOCALDRIVER); +/* +extern PWINE_ACMLOCALDRIVER MSACM_GetLocalDriver(HACMDRIVER hDriver); +*/ /* From msacm32.c */ extern HINSTANCE MSACM_hInstance32;