Added the ability to open several streams on the same driver.
Added a few acmMetrics options.

diff --git a/dlls/msacm32/driver.c b/dlls/msacm32/driver.c
index e1027c1..e22be5e 100644
--- a/dlls/msacm32/driver.c
+++ b/dlls/msacm32/driver.c
@@ -73,7 +73,8 @@
  */
 MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
 {
-    PWINE_ACMDRIVER p;
+    PWINE_ACMDRIVER  p;
+    PWINE_ACMDRIVER* tp;
     
     if (fdwClose)
 	return MMSYSERR_INVALFLAG;
@@ -81,10 +82,15 @@
     p = MSACM_GetDriver(had);
     if (!p)
 	return MMSYSERR_INVALHANDLE;
+
+    for (tp = &(p->obj.pACMDriverID->pACMDriverList); *tp; *tp = (*tp)->pNextACMDriver) {
+	if (*tp == p) {
+	    *tp = (*tp)->pNextACMDriver;
+	    break;
+	}
+    }
     
-    p->obj.pACMDriverID->pACMDriver = NULL;
-    
-    if (p->hDrvr)
+    if (p->hDrvr && !p->obj.pACMDriverID->pACMDriverList)
 	CloseDriver(p->hDrvr, 0, 0);
     
     HeapFree(MSACM_hHeap, 0, p);
@@ -127,29 +133,17 @@
  */
 MMRESULT WINAPI acmDriverDetailsW(HACMDRIVERID hadid, PACMDRIVERDETAILSW padd, DWORD fdwDetails)
 {
-    PWINE_ACMDRIVERID p;
+    HACMDRIVER acmDrvr;
     MMRESULT mmr;
-    BOOL bOpenTemporary;
-    
-    p = MSACM_GetDriverID(hadid);
-    if (!p)
-	return MMSYSERR_INVALHANDLE;
     
     if (fdwDetails)
 	return MMSYSERR_INVALFLAG;
     
-    bOpenTemporary = !p->pACMDriver;
-    if (bOpenTemporary) {
-	bOpenTemporary = TRUE;
-	acmDriverOpen((PHACMDRIVER) &p->pACMDriver, hadid, 0);
-    }
+    mmr = acmDriverOpen(&acmDrvr, hadid, 0);
+    if (mmr == 0) {
+	mmr = (MMRESULT)acmDriverMessage(acmDrvr, ACMDM_DRIVER_DETAILS, (LPARAM) padd,  0);
     
-    mmr = (MMRESULT) acmDriverMessage((HACMDRIVER) p->pACMDriver, ACMDM_DRIVER_DETAILS, 
-				      (LPARAM) padd,  0);
-    
-    if (bOpenTemporary) {
-	acmDriverClose((HACMDRIVER) p->pACMDriver, 0);
-	p->pACMDriver = NULL;
+	acmDriverClose(acmDrvr, 0);
     }
     
     return mmr;
@@ -160,8 +154,9 @@
  */
 MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum)
 {
-    PWINE_ACMDRIVERID p;
-    
+    PWINE_ACMDRIVERID	p;
+    DWORD		fdwSupport;
+
     if (!fnCallback) {
 	return MMSYSERR_INVALPARAM;
     }
@@ -170,10 +165,15 @@
 	return MMSYSERR_INVALFLAG;
     }
     
-    p = MSACM_pFirstACMDriverID;
-    while (p) {
-	(*fnCallback)((HACMDRIVERID) p, dwInstance, ACMDRIVERDETAILS_SUPPORTF_CODEC);
-	p = p->pNextACMDriverID;
+    for (p = MSACM_pFirstACMDriverID; p; p = p->pNextACMDriverID) {
+	fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
+	if (!p->bEnabled) {
+	    if (fdwEnum & ACM_DRIVERENUMF_DISABLED)
+		fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
+	    else
+		continue;
+	}
+	(*fnCallback)((HACMDRIVERID) p, dwInstance, fdwSupport);
     }
     
     return MMSYSERR_NOERROR;
@@ -226,7 +226,8 @@
  */
 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
 {
-    PWINE_ACMDRIVERID padid;
+    PWINE_ACMDRIVERID	padid;
+    PWINE_ACMDRIVER	pad;
 
     TRACE("(%p, %x, %08lu)\n", phad, hadid, fdwOpen);
 
@@ -240,30 +241,29 @@
     if (fdwOpen)
 	return MMSYSERR_INVALFLAG;
     
-    if (padid->pACMDriver) {
-	/* FIXME: Is it allowed? */
-	ERR("Can't open driver '%s' twice\n", padid->pszDriverAlias);
-	return MMSYSERR_ERROR;
-    }
-    
-    padid->pACMDriver = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
-    padid->pACMDriver->obj.pACMDriverID = padid;
+    pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
+    if (!pad) return MMSYSERR_NOMEM;
+
+    pad->obj.pACMDriverID = padid;
     
     if (!padid->hInstModule)
-	padid->pACMDriver->hDrvr = OpenDriverA(padid->pszDriverAlias, "drivers32", 0);
+	pad->hDrvr = OpenDriverA(padid->pszDriverAlias, "drivers32", 0);
     else
-	padid->pACMDriver->hDrvr = padid->hInstModule;
+	pad->hDrvr = padid->hInstModule;
     
-    if (!padid->pACMDriver->hDrvr) {
-	HeapFree(MSACM_hHeap, 0, padid->pACMDriver);
-	padid->pACMDriver = NULL;
+    if (!pad->hDrvr) {
+	HeapFree(MSACM_hHeap, 0, pad);
 	return MMSYSERR_ERROR;
     }
     
-    padid->pACMDriver->pfnDriverProc = GetProcAddress(padid->pACMDriver->hDrvr, "DriverProc");
-    
+    pad->pfnDriverProc = GetProcAddress(pad->hDrvr, "DriverProc");
+
+    /* insert new pad at beg of list */
+    pad->pNextACMDriver = padid->pACMDriverList;
+    padid->pACMDriverList = pad;
+
     /* FIXME: Create a WINE_ACMDRIVER32 */
-    *phad = (HACMDRIVER) padid->pACMDriver;
+    *phad = (HACMDRIVER)pad;
     
     return MMSYSERR_NOERROR;
 }
diff --git a/dlls/msacm32/internal.c b/dlls/msacm32/internal.c
index 8b2c7e5..c179f3b 100644
--- a/dlls/msacm32/internal.c
+++ b/dlls/msacm32/internal.c
@@ -43,9 +43,9 @@
     padid->pszFileName = HEAP_strdupA(MSACM_hHeap, 0, pszFileName);
     padid->hInstModule = hinstModule;
     padid->bEnabled = TRUE;
-    padid->pACMDriver = NULL;
+    padid->pACMDriverList = NULL;
     padid->pNextACMDriverID = NULL;
-    padid->pPreviousACMDriverID = MSACM_pLastACMDriverID;
+    padid->pPrevACMDriverID = MSACM_pLastACMDriverID;
     if (MSACM_pLastACMDriverID)
 	MSACM_pLastACMDriverID->pNextACMDriverID = padid;
     MSACM_pLastACMDriverID = padid;
@@ -100,8 +100,8 @@
 {
     PWINE_ACMDRIVERID pNextACMDriverID;
     
-    if (p->pACMDriver)
-	acmDriverClose((HACMDRIVER) p->pACMDriver, 0);
+    while (p->pACMDriverList)
+	acmDriverClose((HACMDRIVER) p->pACMDriverList, 0);
     
     if (p->pszDriverAlias)
 	HeapFree(MSACM_hHeap, 0, p->pszDriverAlias);
@@ -111,12 +111,12 @@
     if (p == MSACM_pFirstACMDriverID)
 	MSACM_pFirstACMDriverID = p->pNextACMDriverID;
     if (p == MSACM_pLastACMDriverID)
-	MSACM_pLastACMDriverID = p->pPreviousACMDriverID;
+	MSACM_pLastACMDriverID = p->pPrevACMDriverID;
 
-    if (p->pPreviousACMDriverID)
-	p->pPreviousACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
+    if (p->pPrevACMDriverID)
+	p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
     if (p->pNextACMDriverID)
-	p->pNextACMDriverID->pPreviousACMDriverID = p->pPreviousACMDriverID;
+	p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID;
     
     pNextACMDriverID = p->pNextACMDriverID;
     
diff --git a/dlls/msacm32/msacm32_main.c b/dlls/msacm32/msacm32_main.c
index d46ce27..86437b3 100644
--- a/dlls/msacm32/msacm32_main.c
+++ b/dlls/msacm32/msacm32_main.c
@@ -87,36 +87,73 @@
  */
 MMRESULT WINAPI acmMetrics(HACMOBJ hao, UINT uMetric, LPVOID  pMetric)
 {
-    PWINE_ACMOBJ pao = MSACM_GetObj(hao);
-    BOOL bLocal = TRUE;
-    
+    PWINE_ACMOBJ 	pao = MSACM_GetObj(hao);
+    BOOL 		bLocal = TRUE;
+    PWINE_ACMDRIVERID	padid;
+    DWORD		val = 0;
+
     FIXME("(0x%08x, %d, %p): stub\n", hao, uMetric, pMetric);
     
     switch (uMetric) {
     case ACM_METRIC_COUNT_DRIVERS:
 	bLocal = FALSE;
+	/* fall thru */
     case ACM_METRIC_COUNT_LOCAL_DRIVERS:
 	if (!pao)
-	    return MMSYSERR_INVALHANDLE;  
-	return MMSYSERR_NOTSUPPORTED;
+	    return MMSYSERR_INVALHANDLE;
+	for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID)
+	    if (padid->bEnabled /* && (local(padid) || !bLocal) */)
+		val++;
+	*(LPDWORD)pMetric = val;
+	return 0;
+
     case ACM_METRIC_COUNT_CODECS:
+	if (!pao)
+	    return MMSYSERR_INVALHANDLE;
 	bLocal = FALSE;
+	/* fall thru */
     case ACM_METRIC_COUNT_LOCAL_CODECS:
-	return MMSYSERR_NOTSUPPORTED;
+	/* FIXME: don't know how to differentiate codec, converters & filters yet */
+	for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID)
+	    if (padid->bEnabled /* && (local(padid) || !bLocal) */)
+		val++;
+	*(LPDWORD)pMetric = val;
+	return 0;
+
     case ACM_METRIC_COUNT_CONVERTERS:
 	bLocal = FALSE;
+	/* fall thru */
     case ACM_METRIC_COUNT_LOCAL_CONVERTERS:
-	return MMSYSERR_NOTSUPPORTED;
+	/* FIXME: don't know how to differentiate codec, converters & filters yet */
+	for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID)
+	    if (padid->bEnabled /* && (local(padid) || !bLocal) */)
+		val++;
+	*(LPDWORD)pMetric = val;
+	return 0;
+
     case ACM_METRIC_COUNT_FILTERS:
 	bLocal = FALSE;
+	/* fall thru */
     case ACM_METRIC_COUNT_LOCAL_FILTERS:
-	return MMSYSERR_NOTSUPPORTED;
+	/* FIXME: don't know how to differentiate codec, converters & filters yet */
+	for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID)
+	    if (padid->bEnabled /* && (local(padid) || !bLocal) */)
+		val++;
+	*(LPDWORD)pMetric = val;
+	return 0;
+
     case ACM_METRIC_COUNT_DISABLED:
 	bLocal = FALSE;
+	/* fall thru */
     case ACM_METRIC_COUNT_LOCAL_DISABLED:
 	if (!pao)
 	    return MMSYSERR_INVALHANDLE;  
-	return MMSYSERR_NOTSUPPORTED;
+	for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID)
+	    if (!padid->bEnabled /* && (local(padid) || !bLocal) */)
+		val++;
+	*(LPDWORD)pMetric = val;
+	return 0;
+
     case ACM_METRIC_COUNT_HARDWARE:
     case ACM_METRIC_HARDWARE_WAVE_INPUT:
     case ACM_METRIC_HARDWARE_WAVE_OUTPUT:
diff --git a/dlls/msacm32/wineacm.h b/dlls/msacm32/wineacm.h
index dfe1730..b86641c 100644
--- a/dlls/msacm32/wineacm.h
+++ b/dlls/msacm32/wineacm.h
@@ -4,6 +4,7 @@
  * Wine specific - Win32
  */
 typedef struct _WINE_ACMDRIVERID *PWINE_ACMDRIVERID;
+typedef struct _WINE_ACMDRIVER   *PWINE_ACMDRIVER;
 
 typedef struct _WINE_ACMOBJ
 {
@@ -15,7 +16,8 @@
     WINE_ACMOBJ		obj;
     HDRVR      		hDrvr;
     DRIVERPROC		pfnDriverProc;
-} WINE_ACMDRIVER, *PWINE_ACMDRIVER;
+    PWINE_ACMDRIVER	pNextACMDriver;
+} WINE_ACMDRIVER;
 
 typedef struct _WINE_ACMSTREAM
 {
@@ -32,9 +34,9 @@
     HINSTANCE		hInstModule;          /* NULL if global */
     DWORD		dwProcessID;	      /* ID of process which installed a local driver */
     BOOL                bEnabled;
-    PWINE_ACMDRIVER     pACMDriver;           /* NULL if not open; shouldn't this be a list ? */
+    PWINE_ACMDRIVER     pACMDriverList;
     PWINE_ACMDRIVERID   pNextACMDriverID;
-    PWINE_ACMDRIVERID	pPreviousACMDriverID;
+    PWINE_ACMDRIVERID	pPrevACMDriverID;
 } WINE_ACMDRIVERID;
 
 /* From internal.c */