This patch is the preliminary result of some work I have been doing in
order to add missing functionality to builtin msacm32.dll. I am
submitting this to wine-devel rather than wine-patches, and in one big
patch rather than several because I would like comments on some choices
I made while adding features. The following is the list of features
added by the patch:
* Implementation of acmDriverAddW(), and delegation of acmDriverAddA()
to acmDriverAddW()
* Working implementation of modes of operation of acmDriverAdd[AW]: add
driver by new registry entry (ACM_DRIVERADDF_NAME), add (local) driver
by combination of hModule/acmDriverProc (ACM_DRIVERADDF_FUNCTION), add
notification window for event broadcasts (ACM_DRIVERADDF_NOTIFYHWND)
* Implementation of broadcasts to notification windows on driver
add/remove, enabling/disabling, and priority changes
* Fix for implementation quirks of acmDriverMessage() in order to allow
native codecs to display configuration dialogs
* Working implementation of acmDriverPriority(), with support of delayed
notification broadcasts (for one process only). Includes saving new
priorities and enabled status to registry
* Loading of codec priorities and enabled status from registry
* Support for ACM_METRIC_DRIVER_SUPPORT in acmMetrics()
I must note that in order to provide support for acmDriverAddW() in
ACM_DRIVERADDF_FUNCTION mode, it is necessary to treat an
application-supplied module with an application-supplied driverProc as a
full-blown winmm driver. Therefore, the patch includes a new procedure
in winmm called wineAddDriver(), that instructs winmm to build a hDrvr
from a supplied hModule/driverProc pair, rather than loading both from a
DLL, as OpenDriver() does. This allows the rest of the code to continue
using SendDriverMessage() as usual.
Alex Villacís Lasso
diff -ur wine-0.9.5-cvs/dlls/msacm/driver.c wine-0.9.5-cvs-patch/dlls/msacm/driver.c
--- wine-0.9.5-cvs/dlls/msacm/driver.c 2005-12-20 10:17:52.000000000 -0500
+++ wine-0.9.5-cvs-patch/dlls/msacm/driver.c 2006-01-09 21:59:49.000000000 -0500
@@ -40,6 +40,7 @@
#include "msacmdrv.h"
#include "wineacm.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(msacm);
@@ -49,6 +50,10 @@
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, %08lx, %08lx)\n",
phadid, hinstModule, lParam, dwPriority, fdwAdd);
@@ -72,30 +77,100 @@
return MMSYSERR_INVALFLAG;
}
- /* FIXME: in fact, should GetModuleFileName(hinstModule) and do a
- * LoadDriver on it, to be sure we can call SendDriverMessage on the
- * hDrvr handle.
- */
- *phadid = (HACMDRIVERID) MSACM_RegisterDriver(NULL, NULL, hinstModule);
-
- /* FIXME: lParam, dwPriority and fdwAdd ignored */
+ /* A->W translation of name */
+ if ((fdwAdd & ACM_DRIVERADDF_TYPEMASK) == ACM_DRIVERADDF_NAME) {
+ unsigned long len = strlen((LPSTR)lParam) + 1;
+ 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;
+ }
- return MMSYSERR_NOERROR;
-}
+ resultW = acmDriverAddW(phadid, hinstModule, lParamW, dwPriority, fdwAdd);
+ if ((WCHAR *)lParamW != NULL) HeapFree(MSACM_hHeap, 0, driverW);
+ return resultW;
+}
/***********************************************************************
* acmDriverAddW (MSACM32.@)
- * FIXME
- * Not implemented
+ *
*/
MMRESULT WINAPI acmDriverAddW(PHACMDRIVERID phadid, HINSTANCE hinstModule,
LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
{
- FIXME("(%p, %p, %ld, %ld, %ld): stub\n",
- phadid, hinstModule, lParam, dwPriority, fdwAdd);
+ TRACE("(%p, %p, %08lx, %08lx, %08lx)\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;
+ }
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return MMSYSERR_ERROR;
+ /* 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
+ */
+ *phadid = (HACMDRIVERID) MSACM_RegisterDriver(NULL, NULL, hinstModule, (DRIVERPROC)lParam, (fdwAdd & ACM_DRIVERADDF_GLOBAL) ? FALSE : TRUE);
+ 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 %lu for fdwAdd\n", fdwAdd & ACM_DRIVERADDF_TYPEMASK);
+ return MMSYSERR_INVALFLAG;
+ break;
+ }
+
+ MSACM_BroadcastNotification();
+ return MMSYSERR_NOERROR;
}
/***********************************************************************
@@ -250,6 +325,7 @@
}
for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
+ if (padid->hNotifyWnd) continue; /* skip over notification windows */
fdwSupport = padid->fdwSupport;
if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
@@ -298,6 +374,15 @@
/***********************************************************************
* 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)
{
@@ -307,12 +392,91 @@
uMsg == ACMDM_DRIVER_ABOUT ||
uMsg == DRV_QUERYCONFIGURE ||
uMsg == DRV_CONFIGURE)
- return MSACM_Message(had, uMsg, lParam1, lParam2);
-
+ {
+ PWINE_ACMDRIVERID padid;
+ LRESULT lResult;
+ LPDRVCONFIGINFO pConfigInfo = 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) {
+ unsigned int iStructSize = 16;
+ /* This verification is required because DRVCONFIGINFO is 12 bytes
+ long, yet native msacm reports a 16-byte structure to codecs.
+ */
+ if (iStructSize < sizeof(DRVCONFIGINFO)) iStructSize = sizeof(DRVCONFIGINFO);
+ 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;
+
+ pConfigInfo->lpszDCISectionName = HeapAlloc(MSACM_hHeap, 0, (strlenW(drivers32) + 1) * sizeof(WCHAR));
+ if (pConfigInfo->lpszDCISectionName) strcpyW((WCHAR *)pConfigInfo->lpszDCISectionName, drivers32);
+ pConfigInfo->lpszDCIAliasName = HeapAlloc(MSACM_hHeap, 0, (strlenW(pAlias) + 1) * sizeof(WCHAR));
+ if (pConfigInfo->lpszDCIAliasName) strcpyW((WCHAR *)pConfigInfo->lpszDCIAliasName, pAlias);
+
+ if (pConfigInfo->lpszDCISectionName == NULL || pConfigInfo->lpszDCIAliasName == NULL) {
+ if (pConfigInfo->lpszDCIAliasName) HeapFree(MSACM_hHeap, 0, (void *)pConfigInfo->lpszDCIAliasName);
+ if (pConfigInfo->lpszDCISectionName) HeapFree(MSACM_hHeap, 0, (void *)pConfigInfo->lpszDCISectionName);
+ 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 = SendDriverMessage(padid->pACMDriverList->hDrvr, 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, (void *)pConfigInfo->lpszDCIAliasName);
+ HeapFree(MSACM_hHeap, 0, (void *)pConfigInfo->lpszDCISectionName);
+ HeapFree(MSACM_hHeap, 0, pConfigInfo);
+ }
+ return lResult;
+ }
WARN("invalid parameter\n");
return MMSYSERR_INVALPARAM;
}
+HDRVR WINAPI wineAddDriver(HMODULE hModule, DRIVERPROC lpDriverProc, LPARAM lParam2);
+
/***********************************************************************
* acmDriverOpen (MSACM32.@)
*/
@@ -382,6 +546,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->hDrvr = wineAddDriver(padid->hInstModule, padid->lpDriverProc, (DWORD)&adod);
+ if (!pad->hDrvr)
+ {
+ ret = adod.dwError;
+ goto gotError;
+ }
+ }
/* insert new pad at beg of list */
pad->pNextACMDriver = padid->pACMDriverList;
@@ -404,22 +591,9 @@
*/
MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fdwPriority)
{
- PWINE_ACMDRIVERID padid;
- CHAR szSubKey[17];
- CHAR szBuffer[256];
- LONG lBufferLength = sizeof(szBuffer);
- LONG lError;
- HKEY hPriorityKey;
- DWORD dwPriorityCounter;
TRACE("(%p, %08lx, %08lx)\n", hadid, dwPriority, fdwPriority);
- padid = MSACM_GetDriverID(hadid);
- if (!padid) {
- WARN("invalid handle\n");
- return MMSYSERR_INVALHANDLE;
- }
-
/* Check for unknown flags */
if (fdwPriority &
~(ACM_DRIVERPRIORITYF_ENABLE|ACM_DRIVERPRIORITYF_DISABLE|
@@ -441,33 +615,91 @@
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 BOOL flag. 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;
+ BOOL bPerformBroadcast = FALSE;
+
+ /* Fetch driver ID */
+ padid = MSACM_GetDriverID(hadid);
+ if (!padid) {
+ WARN("invalid handle\n");
+ return MMSYSERR_INVALHANDLE;
+ }
+
+ /* Check whether driver ID is appropriate for requested op */
+ if (dwPriority) {
+ if (padid->hNotifyWnd || (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL)) {
+ return MMSYSERR_NOTSUPPORTED;
+ }
+ if (dwPriority != 1 && dwPriority != -1) {
+ FIXME("unexpected priority %ld, using sign only\n", dwPriority);
+ if (dwPriority < 0) dwPriority = -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 == -1 && padid->pNextACMDriverID == NULL) {
+ /* do nothing - driver is last of list */
+ } else {
+ MSACM_RePositionDriver(padid, dwPriority);
+ bPerformBroadcast = TRUE;
+ }
+ }
- lError = RegOpenKeyA(HKEY_CURRENT_USER,
- "Software\\Microsoft\\Multimedia\\"
- "Audio Compression Manager\\Priority v4.00",
- &hPriorityKey
- );
- /* FIXME: Create key */
- if (lError != ERROR_SUCCESS) {
- WARN("RegOpenKeyA failed\n");
- return MMSYSERR_ERROR;
- }
-
- for (dwPriorityCounter = 1; ; dwPriorityCounter++) {
- snprintf(szSubKey, 17, "Priority%ld", dwPriorityCounter);
- lError = RegQueryValueA(hPriorityKey, szSubKey, szBuffer, &lBufferLength);
- if (lError != ERROR_SUCCESS)
- break;
-
- FIXME("(%p, %ld, %ld): stub (partial)\n",
- hadid, dwPriority, fdwPriority);
- break;
+ /* 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;
+ }
+ }
+
+ /* Perform broadcast of changes */
+ if (bPerformBroadcast) {
+ MSACM_WriteCurrentPriorities();
+ MSACM_BroadcastNotification();
+ }
+ return MMSYSERR_NOERROR;
}
-
- RegCloseKey(hPriorityKey);
-
- WARN("RegQueryValueA failed\n");
- return MMSYSERR_ERROR;
}
/***********************************************************************
@@ -491,6 +723,7 @@
}
MSACM_UnregisterDriver(padid);
+ MSACM_BroadcastNotification();
return MMSYSERR_NOERROR;
}
diff -ur wine-0.9.5-cvs/dlls/msacm/format.c wine-0.9.5-cvs-patch/dlls/msacm/format.c
--- wine-0.9.5-cvs/dlls/msacm/format.c 2005-09-12 10:35:53.000000000 -0500
+++ wine-0.9.5-cvs-patch/dlls/msacm/format.c 2006-01-09 21:17:07.000000000 -0500
@@ -527,6 +527,7 @@
return MMSYSERR_NOERROR;
}
for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
+ if (padid->hNotifyWnd) continue; /* skip over notification windows */
/* should check for codec only */
if ((padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
acmDriverOpen(&had, (HACMDRIVERID)padid, 0) != MMSYSERR_NOERROR)
diff -ur wine-0.9.5-cvs/dlls/msacm/internal.c wine-0.9.5-cvs-patch/dlls/msacm/internal.c
--- wine-0.9.5-cvs/dlls/msacm/internal.c 2005-03-24 16:01:38.000000000 -0500
+++ wine-0.9.5-cvs-patch/dlls/msacm/internal.c 2006-01-09 22:35:31.000000000 -0500
@@ -23,6 +23,7 @@
#include <stdarg.h>
#include <string.h>
+#include <assert.h>
#include "windef.h"
#include "winbase.h"
@@ -45,6 +46,8 @@
HANDLE MSACM_hHeap = NULL;
PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL;
+BOOL MSACM_suspendBroadcast = FALSE;
+BOOL MSACM_pendingBroadcast = FALSE;
#if 0
/***********************************************************************
@@ -237,17 +240,20 @@
* MSACM_RegisterDriver()
*/
PWINE_ACMDRIVERID MSACM_RegisterDriver(LPCWSTR pszDriverAlias, LPCWSTR pszFileName,
- HINSTANCE hinstModule)
+ HINSTANCE hinstModule, DRIVERPROC lpDriverProc,
+ BOOL bLocalDriver)
{
PWINE_ACMDRIVERID padid;
- TRACE("(%s, %s, %p)\n",
- debugstr_w(pszDriverAlias), debugstr_w(pszFileName), hinstModule);
+ TRACE("(%s, %s, %p, %p, %s)\n",
+ debugstr_w(pszDriverAlias), debugstr_w(pszFileName), hinstModule, lpDriverProc, bLocalDriver ? "(local)" : "(global)");
padid = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
padid->obj.dwType = WINE_ACMOBJ_DRIVERID;
padid->obj.pACMDriverID = padid;
padid->pszDriverAlias = NULL;
+ padid->hNotifyWnd = NULL;
+ padid->dwNotifyMsg = 0;
if (pszDriverAlias)
{
padid->pszDriverAlias = HeapAlloc( MSACM_hHeap, 0, (strlenW(pszDriverAlias)+1) * sizeof(WCHAR) );
@@ -260,6 +266,54 @@
strcpyW( padid->pszFileName, pszFileName );
}
padid->hInstModule = hinstModule;
+ padid->lpDriverProc = lpDriverProc;
+
+ padid->pACMDriverList = NULL;
+ if (bLocalDriver) {
+ 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 ((bLocalDriver || !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 (bLocalDriver) padid->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_LOCAL;
+ return padid;
+}
+
+/***********************************************************************
+ * MSACM_RegisterNotificationWindow()
+ */
+PWINE_ACMDRIVERID MSACM_RegisterNotificationWindow(HWND hNotifyWnd, DWORD dwNotifyMsg)
+{
+ PWINE_ACMDRIVERID padid;
+
+ TRACE("(%p,0x%08lx)\n",
+ hNotifyWnd, dwNotifyMsg);
+
+ padid = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
+ padid->obj.dwType = WINE_ACMOBJ_DRIVERID;
+ padid->obj.pACMDriverID = padid;
+ padid->pszDriverAlias = NULL;
+ padid->hNotifyWnd = hNotifyWnd;
+ padid->dwNotifyMsg = dwNotifyMsg;
+ padid->pszFileName = NULL;
+ padid->hInstModule = 0;
padid->pACMDriverList = NULL;
padid->pNextACMDriverID = NULL;
@@ -269,15 +323,142 @@
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)) {
- WARN("Couldn't load cache for ACM driver (%s)\n", debugstr_w(pszFileName));
- MSACM_UnregisterDriver(padid);
- return NULL;
+
+
+ padid->aFormatTag = NULL;
+ padid->cFormatTags = 0;
+ padid->cFilterTags = 0;
+ padid->fdwSupport = 0;
+
+ return padid;
+}
+
+/***********************************************************************
+ * MSACM_BroadcastNotification()
+ */
+void MSACM_BroadcastNotification(void)
+{
+ if (!MSACM_suspendBroadcast) {
+ PWINE_ACMDRIVERID padid;
+
+ for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
+ if (padid->hNotifyWnd && !(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED)) {
+ SendMessageW(padid->hNotifyWnd, padid->dwNotifyMsg, 0, 0);
+ }
+ }
+ } else {
+ MSACM_pendingBroadcast = TRUE;
+ }
+}
+
+/***********************************************************************
+ * MSACM_DisableNotifications()
+ */
+void MSACM_DisableNotifications(void)
+{
+ MSACM_suspendBroadcast = TRUE;
+}
+
+/***********************************************************************
+ * MSACM_EnableNotifications()
+ */
+void MSACM_EnableNotifications(void)
+{
+ MSACM_suspendBroadcast = FALSE;
+ if (MSACM_pendingBroadcast) {
+ MSACM_pendingBroadcast = FALSE;
+ MSACM_BroadcastNotification();
+ }
+}
+
+/***********************************************************************
+ * MSACM_RePositionDriver()
+ */
+void MSACM_RePositionDriver(PWINE_ACMDRIVERID padid, DWORD dwPriority)
+{
+ PWINE_ACMDRIVERID pTargetPosition = NULL;
+
+ /* Remove selected driver from linked list */
+ if (MSACM_pFirstACMDriverID == padid) {
+ MSACM_pFirstACMDriverID = padid->pNextACMDriverID;
+ }
+ if (MSACM_pLastACMDriverID == padid) {
+ MSACM_pLastACMDriverID = padid->pPrevACMDriverID;
+ }
+ if (padid->pPrevACMDriverID != NULL) {
+ padid->pPrevACMDriverID->pNextACMDriverID = padid->pNextACMDriverID;
+ }
+ if (padid->pNextACMDriverID != NULL) {
+ padid->pNextACMDriverID->pPrevACMDriverID = padid->pPrevACMDriverID;
+ }
+
+ /* Look up position where selected driver should be */
+ if (dwPriority == 1) {
+ pTargetPosition = padid->pPrevACMDriverID;
+ while (pTargetPosition->pPrevACMDriverID != NULL &&
+ !(pTargetPosition->pPrevACMDriverID->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL)) {
+ pTargetPosition = pTargetPosition->pPrevACMDriverID;
+ }
+ } else if (dwPriority == -1) {
+ pTargetPosition = padid->pNextACMDriverID;
+ while (pTargetPosition->pNextACMDriverID != NULL) {
+ pTargetPosition = pTargetPosition->pNextACMDriverID;
+ }
+ }
+
+ /* Place selected driver in selected position */
+ padid->pPrevACMDriverID = pTargetPosition->pPrevACMDriverID;
+ padid->pNextACMDriverID = pTargetPosition;
+ if (padid->pPrevACMDriverID != NULL) {
+ padid->pPrevACMDriverID->pNextACMDriverID = padid;
+ } else {
+ MSACM_pFirstACMDriverID = padid;
+ }
+ if (padid->pNextACMDriverID != NULL) {
+ padid->pNextACMDriverID->pPrevACMDriverID = padid;
+ } else {
+ MSACM_pLastACMDriverID = padid;
+ }
+}
+
+/***********************************************************************
+ * MSACM_RegisterDriverFromRegistry()
+ */
+PWINE_ACMDRIVERID MSACM_RegisterDriverFromRegistry(LPCWSTR pszRegEntry)
+{
+ static const WCHAR msacmW[] = {'M','S','A','C','M','.'};
+ static const WCHAR drvkey[] = {'S','o','f','t','w','a','r','e','\\',
+ 'M','i','c','r','o','s','o','f','t','\\',
+ 'W','i','n','d','o','w','s',' ','N','T','\\',
+ 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+ 'D','r','i','v','e','r','s','3','2','\0'};
+ WCHAR buf[2048];
+ DWORD bufLen, lRet;
+ HKEY hKey;
+ PWINE_ACMDRIVERID padid = NULL;
+
+ /* The requested registry entry must have the format msacm.XXXXX in order to
+ be recognized in any future sessions of msacm
+ */
+ if (0 == strncmpiW(buf, msacmW, sizeof(msacmW)/sizeof(WCHAR))) {
+ lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, drvkey, 0, KEY_QUERY_VALUE, &hKey);
+ if (lRet != ERROR_SUCCESS) {
+ WARN("unable to open registry key - 0x%08lx\n", lRet);
+ } else {
+ bufLen = sizeof(buf) / sizeof(WCHAR);
+ lRet = RegQueryValueExW(hKey, pszRegEntry, NULL, NULL, (LPBYTE)buf, (LPDWORD)&bufLen);
+ if (lRet != ERROR_SUCCESS) {
+ WARN("unable to query requested subkey %s - 0x%08lx\n", debugstr_w(pszRegEntry), lRet);
+ } else {
+ MSACM_RegisterDriver(pszRegEntry, buf, 0, NULL, FALSE);
+ }
+ RegCloseKey( hKey );
+ }
}
return padid;
}
+static void MSACM_ReorderDriversByPriority(void);
/***********************************************************************
* MSACM_RegisterAllDrivers()
*/
@@ -311,7 +492,7 @@
if (strncmpiW(buf, msacmW, sizeof(msacmW)/sizeof(msacmW[0]))) continue;
if (!(name = strchrW(buf, '='))) continue;
*name = 0;
- MSACM_RegisterDriver(buf, name + 1, 0);
+ MSACM_RegisterDriver(buf, name + 1, 0, NULL, FALSE);
}
RegCloseKey( hKey );
}
@@ -323,12 +504,202 @@
if (strncmpiW(s, msacmW, sizeof(msacmW)/sizeof(msacmW[0]))) continue;
if (!(name = strchrW(s, '='))) continue;
*name = 0;
- MSACM_RegisterDriver(s, name + 1, 0);
+ MSACM_RegisterDriver(s, name + 1, 0, NULL, FALSE);
*name = '=';
}
}
+ MSACM_ReorderDriversByPriority();
+ MSACM_RegisterDriver(msacm32, msacm32, 0, NULL, FALSE);
+}
- MSACM_RegisterDriver(msacm32, msacm32, 0);
+/***********************************************************************
+ * MSACM_ReorderDriversByPriority()
+ * Reorders all drivers based on the priority list indicated by the registry key:
+ * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
+ */
+static void MSACM_ReorderDriversByPriority(void)
+{
+ PWINE_ACMDRIVERID padid;
+ unsigned int iNumDrivers;
+
+ TRACE("\n");
+
+ /* Count drivers && alloc corresponding memory for list */
+ iNumDrivers = 0;
+ for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID, iNumDrivers++);
+ if (iNumDrivers > 1)
+ {
+ PWINE_ACMDRIVERID * driverList;
+
+ driverList = HeapAlloc(MSACM_hHeap, 0, iNumDrivers * sizeof(PWINE_ACMDRIVERID));
+ if (!driverList)
+ {
+ ERR("out of memory\n");
+ }
+ else
+ {
+ LONG lError;
+ HKEY hPriorityKey;
+ static const WCHAR basePriorityKey[] = {
+ 'S','o','f','t','w','a','r','e','\\',
+ 'M','i','c','r','o','s','o','f','t','\\',
+ 'M','u','l','t','i','m','e','d','i','a','\\',
+ 'A','u','d','i','o',' ','C','o','m','p','r','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
+ 'P','r','i','o','r','i','t','y',' ','v','4','.','0','0','\0'
+ };
+
+ lError = RegOpenKeyW(HKEY_CURRENT_USER,
+ basePriorityKey,
+ &hPriorityKey);
+ if (lError != ERROR_SUCCESS) {
+ TRACE("RegOpenKeyW failed, possibly key does not exist yet\n");
+ } else {
+ unsigned int i;
+ LONG lBufferLength;
+ WCHAR szBuffer[256];
+
+ /* Copy drivers into list to simplify linked list modification */
+ for (i = 0, padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID, i++)
+ {
+ /* at startup, all three conditions are true for all drivers in list */
+ assert(padid->hNotifyWnd == NULL);
+ assert(padid->hInstModule == NULL);
+ assert(padid->lpDriverProc == NULL);
+ driverList[i] = padid;
+ }
+
+ /* Query each of the priorities in turn. Alias key is in lowercase.
+ The general form of the priority record is the following:
+ "PriorityN" --> "1, msacm.driveralias"
+ where N is an integer, and the value is a string of the driver
+ alias, prefixed by "1, " for an enabled driver, or "0, " for a
+ disabled driver.
+ */
+ for (i = 0; i < iNumDrivers; i++)
+ {
+ static const WCHAR priorityTmpl[] = {'P','r','i','o','r','i','t','y','%','l','d','\0'};
+ WCHAR szSubKey[17];
+
+ snprintfW(szSubKey, 17, priorityTmpl, i + 1);
+ lBufferLength = sizeof(szBuffer);
+ lError = RegQueryValueExW(hPriorityKey, szSubKey, NULL, NULL, (LPBYTE)szBuffer, (LPDWORD)&lBufferLength);
+ if (lError == ERROR_SUCCESS) {
+ unsigned int iTargetPosition = i;
+ unsigned int iCurrentPosition;
+ WCHAR * pAlias;
+ static const WCHAR sPrefix[] = {'m','s','a','c','m','.','\0'};
+
+ /* Locate driver alias */
+ pAlias = strstrW(szBuffer, sPrefix);
+ if (pAlias != NULL) {
+ for (iCurrentPosition = 0; iCurrentPosition < iNumDrivers; iCurrentPosition++) {
+ if (strcmpiW(driverList[iCurrentPosition]->pszDriverAlias, pAlias) == 0)
+ break;
+ }
+ if (iCurrentPosition < iNumDrivers && iTargetPosition != iCurrentPosition) {
+ padid = driverList[iTargetPosition];
+ driverList[iTargetPosition] = driverList[iCurrentPosition];
+ driverList[iCurrentPosition] = padid;
+
+ /* Locate enabled status */
+ if (szBuffer[0] == '1') {
+ driverList[iTargetPosition]->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED;
+ } else if (szBuffer[0] == '0') {
+ driverList[iTargetPosition]->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
+ }
+ }
+ }
+ }
+ }
+
+ RegCloseKey(hPriorityKey);
+
+ /* Re-assign pointers so that linked list traverses the ordered array */
+ for (i = 0; i < iNumDrivers; i++) {
+ driverList[i]->pPrevACMDriverID = (i > 0) ? driverList[i - 1] : NULL;
+ driverList[i]->pNextACMDriverID = (i < iNumDrivers - 1) ? driverList[i + 1] : NULL;
+ }
+ MSACM_pFirstACMDriverID = driverList[0];
+ MSACM_pLastACMDriverID = driverList[iNumDrivers - 1];
+ }
+
+ HeapFree(MSACM_hHeap, 0, driverList);
+ }
+ }
+}
+
+/***********************************************************************
+ * MSACM_WriteCurrentPriorities()
+ * Writes out current order of driver priorities to registry key:
+ * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
+ */
+void MSACM_WriteCurrentPriorities(void)
+{
+ LONG lError;
+ HKEY hPriorityKey;
+ static const WCHAR basePriorityKey[] = {
+ 'S','o','f','t','w','a','r','e','\\',
+ 'M','i','c','r','o','s','o','f','t','\\',
+ 'M','u','l','t','i','m','e','d','i','a','\\',
+ 'A','u','d','i','o',' ','C','o','m','p','r','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
+ 'P','r','i','o','r','i','t','y',' ','v','4','.','0','0','\0'
+ };
+ PWINE_ACMDRIVERID padid;
+ DWORD dwPriorityCounter;
+ static const WCHAR priorityTmpl[] = {'P','r','i','o','r','i','t','y','%','l','d','\0'};
+ static const WCHAR valueTmpl[] = {'%','c',',',' ','%','s','\0'};
+ static const WCHAR converterAlias[] = {'I','n','t','e','r','n','a','l',' ','P','C','M',' ','C','o','n','v','e','r','t','e','r','\0'};
+ WCHAR szSubKey[17];
+ WCHAR szBuffer[256];
+
+ /* Delete ACM priority key and create it anew */
+ lError = RegDeleteKeyW(HKEY_CURRENT_USER, basePriorityKey);
+ if (lError != ERROR_SUCCESS && lError != ERROR_FILE_NOT_FOUND) {
+ ERR("unable to remove current key %s (0x%08lx) - priority changes won't persist past application end.\n",
+ debugstr_w(basePriorityKey), lError);
+ return;
+ }
+ lError = RegCreateKeyW(HKEY_CURRENT_USER, basePriorityKey, &hPriorityKey);
+ if (lError != ERROR_SUCCESS) {
+ ERR("unable to create key %s (0x%08lx) - priority changes won't persist past application end.\n",
+ debugstr_w(basePriorityKey), lError);
+ return;
+ }
+
+ /* Write current list of priorities */
+ for (dwPriorityCounter = 0, padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
+ if (padid->hNotifyWnd) continue;
+ if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL) continue;
+ if (padid->pszDriverAlias == NULL) continue; /* internal PCM converter is last */
+
+ /* Build required value name */
+ dwPriorityCounter++;
+ snprintfW(szSubKey, 17, priorityTmpl, dwPriorityCounter);
+
+ /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */
+ snprintfW(szBuffer, 256, valueTmpl, (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ? '0' : '1', padid->pszDriverAlias);
+ strlwrW(szBuffer);
+
+ lError = RegSetValueExW(hPriorityKey, szSubKey, 0, REG_SZ, (BYTE *)szBuffer, (strlenW(szBuffer) + 1) * sizeof(WCHAR));
+ if (lError != ERROR_SUCCESS) {
+ ERR("unable to write value for %s under key %s (0x%08lx)\n",
+ debugstr_w(padid->pszDriverAlias), debugstr_w(basePriorityKey), lError);
+ }
+ }
+
+ /* Build required value name */
+ dwPriorityCounter++;
+ snprintfW(szSubKey, 17, priorityTmpl, dwPriorityCounter);
+
+ /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */
+ snprintfW(szBuffer, 256, valueTmpl, '1', converterAlias);
+
+ lError = RegSetValueExW(hPriorityKey, szSubKey, 0, REG_SZ, (BYTE *)szBuffer, (strlenW(szBuffer) + 1) * sizeof(WCHAR));
+ if (lError != ERROR_SUCCESS) {
+ ERR("unable to write value for %s under key %s (0x%08lx)\n",
+ debugstr_w(converterAlias), debugstr_w(basePriorityKey), lError);
+ }
+ RegCloseKey(hPriorityKey);
}
/***********************************************************************
diff -ur wine-0.9.5-cvs/dlls/msacm/msacm32_main.c wine-0.9.5-cvs-patch/dlls/msacm/msacm32_main.c
--- wine-0.9.5-cvs/dlls/msacm/msacm32_main.c 2006-01-03 10:17:18.000000000 -0500
+++ wine-0.9.5-cvs-patch/dlls/msacm/msacm32_main.c 2006-01-09 21:17:07.000000000 -0500
@@ -123,7 +123,8 @@
if (hao) return MMSYSERR_INVALHANDLE;
if (!pMetric) return MMSYSERR_INVALPARAM;
for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID)
- if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) && CheckLocal(padid))
+ if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) && CheckLocal(padid)
+ && !(!bLocal && ((padid)->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL)))
val++;
*(LPDWORD)pMetric = val;
break;
@@ -235,10 +236,23 @@
}
break;
+ case ACM_METRIC_DRIVER_SUPPORT:
+ /* Return fdwSupport for driver */
+ if (!hao) return MMSYSERR_INVALHANDLE;
+ if (!pMetric) return MMSYSERR_INVALPARAM;
+ mmr = MMSYSERR_INVALHANDLE;
+ for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
+ if (padid == (PWINE_ACMDRIVERID)hao) {
+ *(LPDWORD)pMetric = padid->fdwSupport;
+ mmr = MMSYSERR_NOERROR;
+ break;
+ }
+ }
+ break;
+
case ACM_METRIC_HARDWARE_WAVE_INPUT:
case ACM_METRIC_HARDWARE_WAVE_OUTPUT:
case ACM_METRIC_MAX_SIZE_FILTER:
- case ACM_METRIC_DRIVER_SUPPORT:
default:
FIXME("(%p, %d, %p): stub\n", hao, uMetric, pMetric);
mmr = MMSYSERR_NOTSUPPORTED;
diff -ur wine-0.9.5-cvs/dlls/msacm/pcmconverter.c wine-0.9.5-cvs-patch/dlls/msacm/pcmconverter.c
--- wine-0.9.5-cvs/dlls/msacm/pcmconverter.c 2005-11-28 15:57:25.000000000 -0500
+++ wine-0.9.5-cvs-patch/dlls/msacm/pcmconverter.c 2006-01-09 21:17:07.000000000 -0500
@@ -945,12 +945,20 @@
switch (adss->fdwSize) {
case ACM_STREAMSIZEF_DESTINATION:
/* cbDstLength => cbSrcLength */
+ if (!adsi->pwfxDst->nAvgBytesPerSec) {
+ ERR("adsi->pwfxDst->nAvgBytesPerSec == %lu\n", adsi->pwfxDst->nAvgBytesPerSec);
+ return MMSYSERR_INVALPARAM;
+ }
adss->cbSrcLength = PCM_round(adss->cbDstLength & dstMask,
adsi->pwfxSrc->nAvgBytesPerSec,
adsi->pwfxDst->nAvgBytesPerSec) & srcMask;
break;
case ACM_STREAMSIZEF_SOURCE:
/* cbSrcLength => cbDstLength */
+ if (!adsi->pwfxSrc->nAvgBytesPerSec) {
+ ERR("adsi->pwfxSrc->nAvgBytesPerSec == %lu\n", adsi->pwfxSrc->nAvgBytesPerSec);
+ return MMSYSERR_INVALPARAM;
+ }
adss->cbDstLength = PCM_round(adss->cbSrcLength & srcMask,
adsi->pwfxDst->nAvgBytesPerSec,
adsi->pwfxSrc->nAvgBytesPerSec) & dstMask;
diff -ur wine-0.9.5-cvs/dlls/msacm/wineacm.h wine-0.9.5-cvs-patch/dlls/msacm/wineacm.h
--- wine-0.9.5-cvs/dlls/msacm/wineacm.h 2004-12-13 16:19:02.000000000 -0500
+++ wine-0.9.5-cvs-patch/dlls/msacm/wineacm.h 2006-01-09 21:58:12.000000000 -0500
@@ -319,6 +319,12 @@
LPWSTR pszDriverAlias;
LPWSTR pszFileName;
HINSTANCE hInstModule; /* NULL if global */
+ DRIVERPROC lpDriverProc; /* acmDriverProc supplied by application, if any */
+
+ /* fields used in the case of ACM_DRIVERADDF_NOTIFYHWND */
+ HWND hNotifyWnd; /* Window to notify on ACM events: driver add, driver removal, priority change */
+ DWORD dwNotifyMsg; /* Notification message to send to window */
+
PWINE_ACMDRIVER pACMDriverList;
PWINE_ACMDRIVERID pNextACMDriverID;
PWINE_ACMDRIVERID pPrevACMDriverID;
@@ -337,7 +343,8 @@
extern PWINE_ACMDRIVERID MSACM_pFirstACMDriverID;
extern PWINE_ACMDRIVERID MSACM_pLastACMDriverID;
extern PWINE_ACMDRIVERID MSACM_RegisterDriver(LPCWSTR pszDriverAlias, LPCWSTR pszFileName,
- HINSTANCE hinstModule);
+ HINSTANCE hinstModule, DRIVERPROC lpDriverProc,
+ BOOL bLocalDriver);
extern void MSACM_RegisterAllDrivers(void);
extern PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p);
extern void MSACM_UnregisterAllDrivers(void);
@@ -348,6 +355,16 @@
extern MMRESULT MSACM_Message(HACMDRIVER, UINT, LPARAM, LPARAM);
extern BOOL MSACM_FindFormatTagInCache(WINE_ACMDRIVERID*, DWORD, LPDWORD);
+extern PWINE_ACMDRIVERID MSACM_RegisterNotificationWindow(HWND hNotifyWnd, DWORD dwNotifyMsg);
+extern void MSACM_BroadcastNotification(void);
+extern void MSACM_DisableNotifications(void);
+extern void MSACM_EnableNotifications(void);
+
+extern void MSACM_RePositionDriver(PWINE_ACMDRIVERID, DWORD);
+extern void MSACM_WriteCurrentPriorities(void);
+
+extern PWINE_ACMDRIVERID MSACM_RegisterDriverFromRegistry(LPCWSTR pszRegEntry);
+
/* From msacm32.c */
extern HINSTANCE MSACM_hInstance32;
diff -ur wine-0.9.5-cvs/dlls/winmm/driver.c wine-0.9.5-cvs-patch/dlls/winmm/driver.c
--- wine-0.9.5-cvs/dlls/winmm/driver.c 2005-12-19 09:54:38.000000000 -0500
+++ wine-0.9.5-cvs-patch/dlls/winmm/driver.c 2006-01-09 21:17:08.000000000 -0500
@@ -308,6 +308,80 @@
}
/**************************************************************************
+ * wineAddDriver [WINE specific]
+ *
+ * Tries to create a driver from an existing hModule, with an specified DriverProc
+ */
+HDRVR WINAPI wineAddDriver(HMODULE hModule, DRIVERPROC lpDriverProc, LPARAM lParam2)
+{
+ LPWINE_DRIVER lpDrv = NULL;
+ LPWSTR ptr = NULL;
+ LPCSTR cause = 0;
+ HMODULE hModuleRef2 = NULL;
+
+ TRACE("(%p, %p, %08lX);\n", hModule, lpDriverProc, lParam2);
+
+ lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER));
+ if (lpDrv == NULL) {cause = "OOM"; goto exit;}
+
+ lpDrv->d.d32.lpDrvProc = lpDriverProc;
+ if (lpDrv->d.d32.lpDrvProc == NULL) {cause = "no DriverProc"; goto exit;}
+
+ lpDrv->dwFlags = 0;
+ lpDrv->d.d32.hModule = hModule;
+ lpDrv->d.d32.dwDriverID = 0;
+
+ /* Roundabout way to increment the reference count for the module */
+ ptr = HeapAlloc(GetProcessHeap(), 0, 1024 * sizeof(WCHAR));
+ if (lpDrv == NULL) {cause = "OOM"; goto exit;}
+ if (!GetModuleFileNameW(hModule, ptr, 1024 * sizeof(WCHAR)))
+ {
+ cause = "GetModuleFileNameW failed"; goto exit;
+ }
+ if ((hModuleRef2 = LoadLibraryW(ptr)) == NULL)
+ {
+ cause = "LoadLibraryW failed"; goto exit;
+ }
+
+ /* 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 (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 0 && lParam2)
+ {
+ LPWINE_DRIVER ret;
+
+ if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L))
+ {
+ cause = "load0 failed";
+ goto exit;
+ }
+ ret = (LPWINE_DRIVER)wineAddDriver(hModule, lpDriverProc, lParam2);
+ if (!ret)
+ {
+ CloseDriver((HDRVR)lpDrv, 0L, 0L);
+ cause = "load1 failed";
+ goto exit;
+ }
+ lpDrv->dwFlags |= WINE_GDF_SESSION;
+ return (HDRVR)ret;
+ }
+
+ if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2))
+ {cause = "load failed"; goto exit;}
+
+ if (ptr != NULL) HeapFree(GetProcessHeap(), 0, ptr);
+ TRACE("=> %p\n", lpDrv);
+ return (HDRVR)lpDrv;
+ exit:
+ if (hModuleRef2 != NULL) FreeLibrary(hModuleRef2);
+ if (ptr != NULL) HeapFree(GetProcessHeap(), 0, ptr);
+ HeapFree(GetProcessHeap(), 0, lpDrv);
+ ERR("Unable to load 32 bit module %p: %s\n", hModule, cause);
+ return NULL;
+}
+
+/**************************************************************************
* OpenDriverA [EMAIL PROTECTED]
* DrvOpenA [EMAIL PROTECTED]
* (0,1,DRV_LOAD ,0 ,0)
diff -ur wine-0.9.5-cvs/dlls/winmm/winmm.spec wine-0.9.5-cvs-patch/dlls/winmm/winmm.spec
--- wine-0.9.5-cvs/dlls/winmm/winmm.spec 2005-06-22 13:38:23.000000000 -0500
+++ wine-0.9.5-cvs-patch/dlls/winmm/winmm.spec 2006-01-09 21:17:08.000000000 -0500
@@ -209,3 +209,4 @@
# winmmDbgOut
# winmmSetDebugLevel
# wod32Message
+@ stdcall wineAddDriver(long long long)
diff -ur wine-0.9.5-cvs/include/msacm.h wine-0.9.5-cvs-patch/include/msacm.h
--- wine-0.9.5-cvs/include/msacm.h 2003-09-05 18:15:44.000000000 -0500
+++ wine-0.9.5-cvs-patch/include/msacm.h 2006-01-09 21:17:08.000000000 -0500
@@ -40,6 +40,7 @@
#define MM_ACM_CLOSE MM_STREAM_CLOSE
#define MM_ACM_DONE MM_STREAM_DONE
+#define ACM_DRIVERADDF_NAME 0x00000001L
#define ACM_DRIVERADDF_FUNCTION 0x00000003L
#define ACM_DRIVERADDF_NOTIFYHWND 0x00000004L
#define ACM_DRIVERADDF_TYPEMASK 0x00000007L