msacm: acmDriverAdd() support for ACM_DRIVERADDF_FUNCTION, implemented
local drivers.
diff --git a/dlls/msacm/driver.c b/dlls/msacm/driver.c
index 5cb56c5..98430a5 100644
--- a/dlls/msacm/driver.c
+++ b/dlls/msacm/driver.c
@@ -101,6 +101,8 @@
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 @@
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 @@
}
/* 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 @@
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 @@
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 6e1f9ba..78ecb14 100644
--- a/dlls/msacm/internal.c
+++ b/dlls/msacm/internal.c
@@ -281,12 +281,12 @@
* 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 @@
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 @@
pNextACMDriverID = p->pNextACMDriverID;
+ if (p->pLocalDriver) MSACM_UnregisterLocalDriver(p->pLocalDriver);
HeapFree(MSACM_hHeap, 0, p);
return pNextACMDriverID;
@@ -744,7 +758,7 @@
while (panwnd) {
panwnd = MSACM_UnRegisterNotificationWindow(panwnd);
- }
+ }
}
/***********************************************************************
@@ -784,6 +798,17 @@
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 @@
{
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 1a56b1a..abbb4f8 100644
--- a/dlls/msacm/wineacm.h
+++ b/dlls/msacm/wineacm.h
@@ -292,6 +292,7 @@
#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 @@
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 @@
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 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_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;