msacm: Implement acmDriverPriority with driver priority/enabled saving.
Foundation for notification broadcasts with support for deferred
notification.
diff --git a/dlls/msacm/driver.c b/dlls/msacm/driver.c
index eef7875..302cfee 100644
--- a/dlls/msacm/driver.c
+++ b/dlls/msacm/driver.c
@@ -404,22 +404,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 +428,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 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;
+ BOOL bPerformBroadcast = FALSE;
- 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;
+ /* 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->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;
+ }
+ }
+
+ /* 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;
}
-
- 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;
- }
-
- RegCloseKey(hPriorityKey);
-
- WARN("RegQueryValueA failed\n");
- return MMSYSERR_ERROR;
}
/***********************************************************************
@@ -491,6 +536,7 @@
}
MSACM_UnregisterDriver(padid);
+ MSACM_BroadcastNotification();
return MMSYSERR_NOERROR;
}
diff --git a/dlls/msacm/internal.c b/dlls/msacm/internal.c
index 19b64cb..a5eb350 100644
--- a/dlls/msacm/internal.c
+++ b/dlls/msacm/internal.c
@@ -46,6 +46,9 @@
PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL;
+static DWORD MSACM_suspendBroadcastCount = 0;
+static BOOL MSACM_pendingBroadcast = FALSE;
+
static void MSACM_ReorderDriversByPriority(void);
#if 0
@@ -334,6 +337,90 @@
}
/***********************************************************************
+ * MSACM_BroadcastNotification()
+ */
+void MSACM_BroadcastNotification(void)
+{
+ if (MSACM_suspendBroadcastCount <= 0) {
+ FIXME("notification broadcast not (yet) implemented\n");
+ } else {
+ MSACM_pendingBroadcast = TRUE;
+ }
+}
+
+/***********************************************************************
+ * MSACM_DisableNotifications()
+ */
+void MSACM_DisableNotifications(void)
+{
+ MSACM_suspendBroadcastCount++;
+}
+
+/***********************************************************************
+ * MSACM_EnableNotifications()
+ */
+void MSACM_EnableNotifications(void)
+{
+ if (MSACM_suspendBroadcastCount > 0) {
+ MSACM_suspendBroadcastCount--;
+ if (MSACM_suspendBroadcastCount == 0 && 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_ReorderDriversByPriority()
* Reorders all drivers based on the priority list indicated by the registry key:
* HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
@@ -446,6 +533,79 @@
}
/***********************************************************************
+ * 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->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);
+}
+
+/***********************************************************************
* MSACM_UnregisterDriver()
*/
PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
diff --git a/dlls/msacm/wineacm.h b/dlls/msacm/wineacm.h
index c844ab5..0a3af41 100644
--- a/dlls/msacm/wineacm.h
+++ b/dlls/msacm/wineacm.h
@@ -348,6 +348,12 @@
extern MMRESULT MSACM_Message(HACMDRIVER, UINT, LPARAM, LPARAM);
extern BOOL MSACM_FindFormatTagInCache(WINE_ACMDRIVERID*, DWORD, LPDWORD);
+extern void MSACM_RePositionDriver(PWINE_ACMDRIVERID, DWORD);
+extern void MSACM_WriteCurrentPriorities(void);
+extern void MSACM_BroadcastNotification(void);
+extern void MSACM_DisableNotifications(void);
+extern void MSACM_EnableNotifications(void);
+
/* From msacm32.c */
extern HINSTANCE MSACM_hInstance32;