1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1998 Patrik Stridvall
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msacm
);
42 /**********************************************************************/
44 HANDLE MSACM_hHeap
= NULL
;
45 PWINE_ACMDRIVERID MSACM_pFirstACMDriverID
= NULL
;
46 static PWINE_ACMDRIVERID MSACM_pLastACMDriverID
;
48 static DWORD MSACM_suspendBroadcastCount
= 0;
49 static BOOL MSACM_pendingBroadcast
= FALSE
;
50 static PWINE_ACMNOTIFYWND MSACM_pFirstACMNotifyWnd
= NULL
;
51 static PWINE_ACMNOTIFYWND MSACM_pLastACMNotifyWnd
= NULL
;
53 static void MSACM_ReorderDriversByPriority(void);
55 static const WCHAR drvkey
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32";
56 static const WCHAR baseKey
[] = L
"Software\\Microsoft\\AudioCompressionManager\\DriverCache\\";
57 static const WCHAR basePriorityKey
[] =
58 L
"Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00";
60 /***********************************************************************
61 * MSACM_RegisterDriverFromRegistry()
63 PWINE_ACMDRIVERID
MSACM_RegisterDriverFromRegistry(LPCWSTR pszRegEntry
)
65 static const WCHAR msacmW
[] = {'M','S','A','C','M','.'};
69 PWINE_ACMDRIVERID padid
= NULL
;
71 /* The requested registry entry must have the format msacm.XXXXX in order to
72 be recognized in any future sessions of msacm
74 if (0 == wcsnicmp(pszRegEntry
, msacmW
, ARRAY_SIZE(msacmW
))) {
75 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, drvkey
, 0, KEY_QUERY_VALUE
, &hKey
);
76 if (lRet
!= ERROR_SUCCESS
) {
77 WARN("unable to open registry key - 0x%08x\n", lRet
);
80 lRet
= RegQueryValueExW(hKey
, pszRegEntry
, NULL
, NULL
, (LPBYTE
)buf
, &bufLen
);
81 if (lRet
!= ERROR_SUCCESS
) {
82 WARN("unable to query requested subkey %s - 0x%08x\n", debugstr_w(pszRegEntry
), lRet
);
84 MSACM_RegisterDriver(pszRegEntry
, buf
, 0);
93 /***********************************************************************
96 static void MSACM_DumpCache(PWINE_ACMDRIVERID padid
)
100 TRACE("cFilterTags=%lu cFormatTags=%lu fdwSupport=%08lx\n",
101 padid
->cFilterTags
, padid
->cFormatTags
, padid
->fdwSupport
);
102 for (i
= 0; i
< padid
->cache
->cFormatTags
; i
++) {
103 TRACE("\tdwFormatTag=%lu cbwfx=%lu\n",
104 padid
->aFormatTag
[i
].dwFormatTag
, padid
->aFormatTag
[i
].cbwfx
);
109 /***********************************************************************
110 * MSACM_FindFormatTagInCache [internal]
112 * Returns TRUE is the format tag fmtTag is present in the cache.
113 * If so, idx is set to its index.
115 BOOL
MSACM_FindFormatTagInCache(const WINE_ACMDRIVERID
* padid
, DWORD fmtTag
, LPDWORD idx
)
119 for (i
= 0; i
< padid
->cFormatTags
; i
++) {
120 if (padid
->aFormatTag
[i
].dwFormatTag
== fmtTag
) {
128 /***********************************************************************
131 static BOOL
MSACM_FillCache(PWINE_ACMDRIVERID padid
)
135 ACMDRIVERDETAILSW add
;
136 ACMFORMATTAGDETAILSW aftd
;
138 if (acmDriverOpen(&had
, (HACMDRIVERID
)padid
, 0) != 0)
141 padid
->aFormatTag
= NULL
;
142 add
.cbStruct
= sizeof(add
);
143 if (MSACM_Message(had
, ACMDM_DRIVER_DETAILS
, (LPARAM
)&add
, 0))
146 if (add
.cFormatTags
> 0) {
147 padid
->aFormatTag
= HeapAlloc(MSACM_hHeap
, HEAP_ZERO_MEMORY
,
148 add
.cFormatTags
* sizeof(padid
->aFormatTag
[0]));
149 if (!padid
->aFormatTag
) goto errCleanUp
;
152 padid
->cFormatTags
= add
.cFormatTags
;
153 padid
->cFilterTags
= add
.cFilterTags
;
154 padid
->fdwSupport
= add
.fdwSupport
;
156 aftd
.cbStruct
= sizeof(aftd
);
158 for (ntag
= 0; ntag
< add
.cFormatTags
; ntag
++) {
159 aftd
.dwFormatTagIndex
= ntag
;
160 if (MSACM_Message(had
, ACMDM_FORMATTAG_DETAILS
, (LPARAM
)&aftd
, ACM_FORMATTAGDETAILSF_INDEX
)) {
161 TRACE("IIOs (%s)\n", debugstr_w(padid
->pszDriverAlias
));
164 padid
->aFormatTag
[ntag
].dwFormatTag
= aftd
.dwFormatTag
;
165 padid
->aFormatTag
[ntag
].cbwfx
= aftd
.cbFormatSize
;
168 acmDriverClose(had
, 0);
173 if (had
) acmDriverClose(had
, 0);
174 HeapFree(MSACM_hHeap
, 0, padid
->aFormatTag
);
175 padid
->aFormatTag
= NULL
;
179 /***********************************************************************
180 * MSACM_GetRegistryKey
182 static LPWSTR
MSACM_GetRegistryKey(const WINE_ACMDRIVERID
* padid
)
187 if (!padid
->pszDriverAlias
) {
188 ERR("No alias needed for registry entry\n");
191 len
= lstrlenW(baseKey
);
192 ret
= HeapAlloc(MSACM_hHeap
, 0, (len
+ lstrlenW(padid
->pszDriverAlias
) + 1) * sizeof(WCHAR
));
193 if (!ret
) return NULL
;
195 lstrcpyW(ret
, baseKey
);
196 lstrcpyW(ret
+ len
, padid
->pszDriverAlias
);
197 CharLowerW(ret
+ len
);
201 /***********************************************************************
204 static BOOL
MSACM_ReadCache(PWINE_ACMDRIVERID padid
)
206 LPWSTR key
= MSACM_GetRegistryKey(padid
);
210 if (!key
) return FALSE
;
212 padid
->aFormatTag
= NULL
;
214 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, key
, &hKey
))
217 size
= sizeof(padid
->cFormatTags
);
218 if (RegQueryValueExA(hKey
, "cFormatTags", 0, &type
, (void*)&padid
->cFormatTags
, &size
))
220 size
= sizeof(padid
->cFilterTags
);
221 if (RegQueryValueExA(hKey
, "cFilterTags", 0, &type
, (void*)&padid
->cFilterTags
, &size
))
223 size
= sizeof(padid
->fdwSupport
);
224 if (RegQueryValueExA(hKey
, "fdwSupport", 0, &type
, (void*)&padid
->fdwSupport
, &size
))
227 if (padid
->cFormatTags
> 0) {
228 size
= padid
->cFormatTags
* sizeof(padid
->aFormatTag
[0]);
229 padid
->aFormatTag
= HeapAlloc(MSACM_hHeap
, HEAP_ZERO_MEMORY
, size
);
230 if (!padid
->aFormatTag
) goto errCleanUp
;
231 if (RegQueryValueExA(hKey
, "aFormatTagCache", 0, &type
, (void*)padid
->aFormatTag
, &size
))
234 HeapFree(MSACM_hHeap
, 0, key
);
238 HeapFree(MSACM_hHeap
, 0, key
);
239 HeapFree(MSACM_hHeap
, 0, padid
->aFormatTag
);
240 padid
->aFormatTag
= NULL
;
245 /***********************************************************************
248 static BOOL
MSACM_WriteCache(const WINE_ACMDRIVERID
*padid
)
250 LPWSTR key
= MSACM_GetRegistryKey(padid
);
253 if (!key
) return FALSE
;
255 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, key
, &hKey
))
258 if (RegSetValueExA(hKey
, "cFormatTags", 0, REG_DWORD
, (const void*)&padid
->cFormatTags
, sizeof(DWORD
)))
260 if (RegSetValueExA(hKey
, "cFilterTags", 0, REG_DWORD
, (const void*)&padid
->cFilterTags
, sizeof(DWORD
)))
262 if (RegSetValueExA(hKey
, "fdwSupport", 0, REG_DWORD
, (const void*)&padid
->fdwSupport
, sizeof(DWORD
)))
264 if (RegSetValueExA(hKey
, "aFormatTagCache", 0, REG_BINARY
,
265 (void*)padid
->aFormatTag
,
266 padid
->cFormatTags
* sizeof(padid
->aFormatTag
[0])))
268 HeapFree(MSACM_hHeap
, 0, key
);
272 HeapFree(MSACM_hHeap
, 0, key
);
276 /***********************************************************************
277 * MSACM_RegisterDriver()
279 PWINE_ACMDRIVERID
MSACM_RegisterDriver(LPCWSTR pszDriverAlias
, LPCWSTR pszFileName
,
280 PWINE_ACMLOCALDRIVER pLocalDriver
)
282 PWINE_ACMDRIVERID padid
;
284 TRACE("(%s, %s, %p)\n",
285 debugstr_w(pszDriverAlias
), debugstr_w(pszFileName
), pLocalDriver
);
287 padid
= HeapAlloc(MSACM_hHeap
, 0, sizeof(WINE_ACMDRIVERID
));
290 padid
->obj
.dwType
= WINE_ACMOBJ_DRIVERID
;
291 padid
->obj
.pACMDriverID
= padid
;
292 padid
->pszDriverAlias
= NULL
;
295 padid
->pszDriverAlias
= HeapAlloc( MSACM_hHeap
, 0, (lstrlenW(pszDriverAlias
)+1) * sizeof(WCHAR
) );
296 if (!padid
->pszDriverAlias
) {
297 HeapFree(MSACM_hHeap
, 0, padid
);
300 lstrcpyW( padid
->pszDriverAlias
, pszDriverAlias
);
302 padid
->pszFileName
= NULL
;
305 padid
->pszFileName
= HeapAlloc( MSACM_hHeap
, 0, (lstrlenW(pszFileName
)+1) * sizeof(WCHAR
) );
306 if (!padid
->pszFileName
) {
307 HeapFree(MSACM_hHeap
, 0, padid
->pszDriverAlias
);
308 HeapFree(MSACM_hHeap
, 0, padid
);
311 lstrcpyW( padid
->pszFileName
, pszFileName
);
313 padid
->pLocalDriver
= pLocalDriver
;
315 padid
->pACMDriverList
= NULL
;
318 padid
->pPrevACMDriverID
= NULL
;
319 padid
->pNextACMDriverID
= MSACM_pFirstACMDriverID
;
320 if (MSACM_pFirstACMDriverID
)
321 MSACM_pFirstACMDriverID
->pPrevACMDriverID
= padid
;
322 MSACM_pFirstACMDriverID
= padid
;
323 if (!MSACM_pLastACMDriverID
)
324 MSACM_pLastACMDriverID
= padid
;
326 padid
->pNextACMDriverID
= NULL
;
327 padid
->pPrevACMDriverID
= MSACM_pLastACMDriverID
;
328 if (MSACM_pLastACMDriverID
)
329 MSACM_pLastACMDriverID
->pNextACMDriverID
= padid
;
330 MSACM_pLastACMDriverID
= padid
;
331 if (!MSACM_pFirstACMDriverID
)
332 MSACM_pFirstACMDriverID
= padid
;
334 /* disable the driver if we cannot load the cache */
335 if ((!padid
->pszDriverAlias
|| !MSACM_ReadCache(padid
)) && !MSACM_FillCache(padid
)) {
336 WARN("Couldn't load cache for ACM driver (%s)\n", debugstr_w(pszFileName
));
337 MSACM_UnregisterDriver(padid
);
341 if (pLocalDriver
) padid
->fdwSupport
|= ACMDRIVERDETAILS_SUPPORTF_LOCAL
;
345 /***********************************************************************
346 * MSACM_RegisterAllDrivers()
348 void MSACM_RegisterAllDrivers(void)
350 static const WCHAR msacmW
[] = {'M','S','A','C','M','.'};
351 DWORD i
, cnt
, bufLen
, lRet
, type
;
352 WCHAR buf
[2048], valname
[64], *name
, *s
;
356 /* FIXME: What if the user edits system.ini while the program is running?
357 * Does Windows handle that? */
358 if (MSACM_pFirstACMDriverID
) return;
360 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, drvkey
, 0, KEY_QUERY_VALUE
, &hKey
);
361 if (lRet
== ERROR_SUCCESS
) {
362 RegQueryInfoKeyW( hKey
, 0, 0, 0, &cnt
, 0, 0, 0, 0, 0, 0, 0);
363 for (i
= 0; i
< cnt
; i
++) {
364 bufLen
= ARRAY_SIZE(buf
);
365 lRet
= RegEnumKeyExW(hKey
, i
, buf
, &bufLen
, 0, 0, 0, &lastWrite
);
366 if (lRet
!= ERROR_SUCCESS
) continue;
367 if (wcsnicmp(buf
, msacmW
, ARRAY_SIZE(msacmW
))) continue;
368 if (!(name
= wcschr(buf
, '='))) continue;
370 MSACM_RegisterDriver(buf
, name
+ 1, 0);
373 cnt
= ARRAY_SIZE(valname
);
374 bufLen
= sizeof(buf
);
375 while(RegEnumValueW(hKey
, i
, valname
, &cnt
, 0,
376 &type
, (BYTE
*)buf
, &bufLen
) == ERROR_SUCCESS
){
377 if (!wcsnicmp(valname
, msacmW
, ARRAY_SIZE(msacmW
)))
378 MSACM_RegisterDriver(valname
, buf
, 0);
384 if (GetPrivateProfileSectionW(L
"drivers32", buf
, ARRAY_SIZE(buf
), L
"system.ini"))
386 for(s
= buf
; *s
; s
+= lstrlenW(s
) + 1)
388 if (wcsnicmp(s
, msacmW
, ARRAY_SIZE(msacmW
))) continue;
389 if (!(name
= wcschr(s
, '='))) continue;
391 MSACM_RegisterDriver(s
, name
+ 1, 0);
395 MSACM_ReorderDriversByPriority();
396 MSACM_RegisterDriver(L
"msacm32.dll", L
"msacm32.dll", 0);
399 /***********************************************************************
400 * MSACM_RegisterNotificationWindow()
402 PWINE_ACMNOTIFYWND
MSACM_RegisterNotificationWindow(HWND hNotifyWnd
, DWORD dwNotifyMsg
)
404 PWINE_ACMNOTIFYWND panwnd
;
406 TRACE("(%p,0x%08x)\n", hNotifyWnd
, dwNotifyMsg
);
408 panwnd
= HeapAlloc(MSACM_hHeap
, 0, sizeof(WINE_ACMNOTIFYWND
));
409 panwnd
->obj
.dwType
= WINE_ACMOBJ_NOTIFYWND
;
410 panwnd
->obj
.pACMDriverID
= 0;
411 panwnd
->hNotifyWnd
= hNotifyWnd
;
412 panwnd
->dwNotifyMsg
= dwNotifyMsg
;
413 panwnd
->fdwSupport
= 0;
415 panwnd
->pNextACMNotifyWnd
= NULL
;
416 panwnd
->pPrevACMNotifyWnd
= MSACM_pLastACMNotifyWnd
;
417 if (MSACM_pLastACMNotifyWnd
)
418 MSACM_pLastACMNotifyWnd
->pNextACMNotifyWnd
= panwnd
;
419 MSACM_pLastACMNotifyWnd
= panwnd
;
420 if (!MSACM_pFirstACMNotifyWnd
)
421 MSACM_pFirstACMNotifyWnd
= panwnd
;
426 /***********************************************************************
427 * MSACM_BroadcastNotification()
429 void MSACM_BroadcastNotification(void)
431 if (MSACM_suspendBroadcastCount
<= 0) {
432 PWINE_ACMNOTIFYWND panwnd
;
434 for (panwnd
= MSACM_pFirstACMNotifyWnd
; panwnd
; panwnd
= panwnd
->pNextACMNotifyWnd
)
435 if (!(panwnd
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
))
436 SendMessageW(panwnd
->hNotifyWnd
, panwnd
->dwNotifyMsg
, 0, 0);
438 MSACM_pendingBroadcast
= TRUE
;
442 /***********************************************************************
443 * MSACM_DisableNotifications()
445 void MSACM_DisableNotifications(void)
447 MSACM_suspendBroadcastCount
++;
450 /***********************************************************************
451 * MSACM_EnableNotifications()
453 void MSACM_EnableNotifications(void)
455 if (MSACM_suspendBroadcastCount
> 0) {
456 MSACM_suspendBroadcastCount
--;
457 if (MSACM_suspendBroadcastCount
== 0 && MSACM_pendingBroadcast
) {
458 MSACM_pendingBroadcast
= FALSE
;
459 MSACM_BroadcastNotification();
464 /***********************************************************************
465 * MSACM_UnRegisterNotificationWindow()
467 PWINE_ACMNOTIFYWND
MSACM_UnRegisterNotificationWindow(const WINE_ACMNOTIFYWND
*panwnd
)
469 PWINE_ACMNOTIFYWND p
;
471 for (p
= MSACM_pFirstACMNotifyWnd
; p
; p
= p
->pNextACMNotifyWnd
) {
473 PWINE_ACMNOTIFYWND pNext
= p
->pNextACMNotifyWnd
;
475 if (p
->pPrevACMNotifyWnd
) p
->pPrevACMNotifyWnd
->pNextACMNotifyWnd
= p
->pNextACMNotifyWnd
;
476 if (p
->pNextACMNotifyWnd
) p
->pNextACMNotifyWnd
->pPrevACMNotifyWnd
= p
->pPrevACMNotifyWnd
;
477 if (MSACM_pFirstACMNotifyWnd
== p
) MSACM_pFirstACMNotifyWnd
= p
->pNextACMNotifyWnd
;
478 if (MSACM_pLastACMNotifyWnd
== p
) MSACM_pLastACMNotifyWnd
= p
->pPrevACMNotifyWnd
;
479 HeapFree(MSACM_hHeap
, 0, p
);
487 /***********************************************************************
488 * MSACM_RePositionDriver()
490 void MSACM_RePositionDriver(PWINE_ACMDRIVERID padid
, DWORD dwPriority
)
492 PWINE_ACMDRIVERID pTargetPosition
= NULL
;
494 /* Remove selected driver from linked list */
495 if (MSACM_pFirstACMDriverID
== padid
) {
496 MSACM_pFirstACMDriverID
= padid
->pNextACMDriverID
;
498 if (MSACM_pLastACMDriverID
== padid
) {
499 MSACM_pLastACMDriverID
= padid
->pPrevACMDriverID
;
501 if (padid
->pPrevACMDriverID
!= NULL
) {
502 padid
->pPrevACMDriverID
->pNextACMDriverID
= padid
->pNextACMDriverID
;
504 if (padid
->pNextACMDriverID
!= NULL
) {
505 padid
->pNextACMDriverID
->pPrevACMDriverID
= padid
->pPrevACMDriverID
;
508 /* Look up position where selected driver should be */
509 if (dwPriority
== 1) {
510 pTargetPosition
= padid
->pPrevACMDriverID
;
511 while (pTargetPosition
->pPrevACMDriverID
!= NULL
&&
512 !(pTargetPosition
->pPrevACMDriverID
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_LOCAL
)) {
513 pTargetPosition
= pTargetPosition
->pPrevACMDriverID
;
515 } else if (dwPriority
== -1) {
516 pTargetPosition
= padid
->pNextACMDriverID
;
517 while (pTargetPosition
->pNextACMDriverID
!= NULL
) {
518 pTargetPosition
= pTargetPosition
->pNextACMDriverID
;
522 /* Place selected driver in selected position */
523 padid
->pPrevACMDriverID
= pTargetPosition
->pPrevACMDriverID
;
524 padid
->pNextACMDriverID
= pTargetPosition
;
525 if (padid
->pPrevACMDriverID
!= NULL
) {
526 padid
->pPrevACMDriverID
->pNextACMDriverID
= padid
;
528 MSACM_pFirstACMDriverID
= padid
;
530 if (padid
->pNextACMDriverID
!= NULL
) {
531 padid
->pNextACMDriverID
->pPrevACMDriverID
= padid
;
533 MSACM_pLastACMDriverID
= padid
;
537 /***********************************************************************
538 * MSACM_ReorderDriversByPriority()
539 * Reorders all drivers based on the priority list indicated by the registry key:
540 * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
542 static void MSACM_ReorderDriversByPriority(void)
544 PWINE_ACMDRIVERID padid
;
545 unsigned int iNumDrivers
;
546 PWINE_ACMDRIVERID
* driverList
= NULL
;
547 HKEY hPriorityKey
= NULL
;
551 /* Count drivers && alloc corresponding memory for list */
553 for (padid
= MSACM_pFirstACMDriverID
; padid
; padid
= padid
->pNextACMDriverID
) iNumDrivers
++;
561 driverList
= HeapAlloc(MSACM_hHeap
, 0, iNumDrivers
* sizeof(PWINE_ACMDRIVERID
));
564 ERR("out of memory\n");
568 lError
= RegOpenKeyW(HKEY_CURRENT_USER
, basePriorityKey
, &hPriorityKey
);
569 if (lError
!= ERROR_SUCCESS
) {
570 TRACE("RegOpenKeyW failed, possibly key does not exist yet\n");
575 /* Copy drivers into list to simplify linked list modification */
576 for (i
= 0, padid
= MSACM_pFirstACMDriverID
; padid
; padid
= padid
->pNextACMDriverID
, i
++)
578 driverList
[i
] = padid
;
581 /* Query each of the priorities in turn. Alias key is in lowercase.
582 The general form of the priority record is the following:
583 "PriorityN" --> "1, msacm.driveralias"
584 where N is an integer, and the value is a string of the driver
585 alias, prefixed by "1, " for an enabled driver, or "0, " for a
588 for (i
= 0; i
< iNumDrivers
; i
++)
591 unsigned int iTargetPosition
;
592 unsigned int iCurrentPosition
;
595 /* Build expected entry name */
596 swprintf(szSubKey
, 17, L
"Priority%ld", i
+ 1);
597 lBufferLength
= sizeof(szBuffer
);
598 lError
= RegQueryValueExW(hPriorityKey
, szSubKey
, NULL
, NULL
, (LPBYTE
)szBuffer
, (LPDWORD
)&lBufferLength
);
599 if (lError
!= ERROR_SUCCESS
) continue;
601 /* Recovered driver alias should be at this position */
604 /* Locate driver alias in driver list */
605 pAlias
= wcsstr(szBuffer
, L
"msacm.");
606 if (pAlias
== NULL
) continue;
608 for (iCurrentPosition
= 0; iCurrentPosition
< iNumDrivers
; iCurrentPosition
++) {
609 if (wcsicmp(driverList
[iCurrentPosition
]->pszDriverAlias
, pAlias
) == 0)
612 if (iCurrentPosition
< iNumDrivers
&& iTargetPosition
!= iCurrentPosition
) {
613 padid
= driverList
[iTargetPosition
];
614 driverList
[iTargetPosition
] = driverList
[iCurrentPosition
];
615 driverList
[iCurrentPosition
] = padid
;
617 /* Locate enabled status */
618 if (szBuffer
[0] == '1') {
619 driverList
[iTargetPosition
]->fdwSupport
&= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED
;
620 } else if (szBuffer
[0] == '0') {
621 driverList
[iTargetPosition
]->fdwSupport
|= ACMDRIVERDETAILS_SUPPORTF_DISABLED
;
626 /* Re-assign pointers so that linked list traverses the ordered array */
627 for (i
= 0; i
< iNumDrivers
; i
++) {
628 driverList
[i
]->pPrevACMDriverID
= (i
> 0) ? driverList
[i
- 1] : NULL
;
629 driverList
[i
]->pNextACMDriverID
= (i
< iNumDrivers
- 1) ? driverList
[i
+ 1] : NULL
;
631 MSACM_pFirstACMDriverID
= driverList
[0];
632 MSACM_pLastACMDriverID
= driverList
[iNumDrivers
- 1];
636 if (hPriorityKey
!= NULL
) RegCloseKey(hPriorityKey
);
637 HeapFree(MSACM_hHeap
, 0, driverList
);
640 /***********************************************************************
641 * MSACM_WriteCurrentPriorities()
642 * Writes out current order of driver priorities to registry key:
643 * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
645 void MSACM_WriteCurrentPriorities(void)
649 PWINE_ACMDRIVERID padid
;
650 DWORD dwPriorityCounter
;
654 /* Delete ACM priority key and create it anew */
655 lError
= RegDeleteKeyW(HKEY_CURRENT_USER
, basePriorityKey
);
656 if (lError
!= ERROR_SUCCESS
&& lError
!= ERROR_FILE_NOT_FOUND
) {
657 ERR("unable to remove current key %s (0x%08x) - priority changes won't persist past application end.\n",
658 debugstr_w(basePriorityKey
), lError
);
661 lError
= RegCreateKeyW(HKEY_CURRENT_USER
, basePriorityKey
, &hPriorityKey
);
662 if (lError
!= ERROR_SUCCESS
) {
663 ERR("unable to create key %s (0x%08x) - priority changes won't persist past application end.\n",
664 debugstr_w(basePriorityKey
), lError
);
668 /* Write current list of priorities */
669 for (dwPriorityCounter
= 0, padid
= MSACM_pFirstACMDriverID
; padid
; padid
= padid
->pNextACMDriverID
) {
670 if (padid
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_LOCAL
) continue;
671 if (padid
->pszDriverAlias
== NULL
) continue; /* internal PCM converter is last */
673 /* Build required value name */
675 swprintf(szSubKey
, 17, L
"Priority%ld", dwPriorityCounter
);
677 /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */
678 swprintf(szBuffer
, 256, L
"%c, %s", (padid
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
) ? '0' : '1', padid
->pszDriverAlias
);
681 lError
= RegSetValueExW(hPriorityKey
, szSubKey
, 0, REG_SZ
, (BYTE
*)szBuffer
, (lstrlenW(szBuffer
) + 1) * sizeof(WCHAR
));
682 if (lError
!= ERROR_SUCCESS
) {
683 ERR("unable to write value for %s under key %s (0x%08x)\n",
684 debugstr_w(padid
->pszDriverAlias
), debugstr_w(basePriorityKey
), lError
);
688 /* Build required value name */
690 swprintf(szSubKey
, 17, L
"Priority%ld", dwPriorityCounter
);
692 /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */
693 swprintf(szBuffer
, 256, L
"%c, %s", '1', L
"Internal PCM Converter");
695 lError
= RegSetValueExW(hPriorityKey
, szSubKey
, 0, REG_SZ
, (BYTE
*)szBuffer
, (lstrlenW(szBuffer
) + 1) * sizeof(WCHAR
));
696 if (lError
!= ERROR_SUCCESS
) {
697 ERR("unable to write value for Internal PCM Converter under key %s (0x%08x)\n",
698 debugstr_w(basePriorityKey
), lError
);
700 RegCloseKey(hPriorityKey
);
703 static PWINE_ACMLOCALDRIVER MSACM_pFirstACMLocalDriver
;
704 static PWINE_ACMLOCALDRIVER MSACM_pLastACMLocalDriver
;
706 static PWINE_ACMLOCALDRIVER
MSACM_UnregisterLocalDriver(PWINE_ACMLOCALDRIVER paldrv
)
708 PWINE_ACMLOCALDRIVER pNextACMLocalDriver
;
711 if (paldrv
->pACMInstList
) {
712 ERR("local driver instances still present after closing all drivers - memory leak\n");
716 ref
= InterlockedDecrement(&paldrv
->ref
);
720 if (paldrv
== MSACM_pFirstACMLocalDriver
)
721 MSACM_pFirstACMLocalDriver
= paldrv
->pNextACMLocalDrv
;
722 if (paldrv
== MSACM_pLastACMLocalDriver
)
723 MSACM_pLastACMLocalDriver
= paldrv
->pPrevACMLocalDrv
;
725 if (paldrv
->pPrevACMLocalDrv
)
726 paldrv
->pPrevACMLocalDrv
->pNextACMLocalDrv
= paldrv
->pNextACMLocalDrv
;
727 if (paldrv
->pNextACMLocalDrv
)
728 paldrv
->pNextACMLocalDrv
->pPrevACMLocalDrv
= paldrv
->pPrevACMLocalDrv
;
730 pNextACMLocalDriver
= paldrv
->pNextACMLocalDrv
;
732 HeapFree(MSACM_hHeap
, 0, paldrv
);
734 return pNextACMLocalDriver
;
737 /***********************************************************************
738 * MSACM_UnregisterDriver()
740 PWINE_ACMDRIVERID
MSACM_UnregisterDriver(PWINE_ACMDRIVERID p
)
742 PWINE_ACMDRIVERID pNextACMDriverID
;
744 while (p
->pACMDriverList
)
745 acmDriverClose((HACMDRIVER
) p
->pACMDriverList
, 0);
747 HeapFree(MSACM_hHeap
, 0, p
->pszDriverAlias
);
748 HeapFree(MSACM_hHeap
, 0, p
->pszFileName
);
749 HeapFree(MSACM_hHeap
, 0, p
->aFormatTag
);
751 if (p
== MSACM_pFirstACMDriverID
)
752 MSACM_pFirstACMDriverID
= p
->pNextACMDriverID
;
753 if (p
== MSACM_pLastACMDriverID
)
754 MSACM_pLastACMDriverID
= p
->pPrevACMDriverID
;
756 if (p
->pPrevACMDriverID
)
757 p
->pPrevACMDriverID
->pNextACMDriverID
= p
->pNextACMDriverID
;
758 if (p
->pNextACMDriverID
)
759 p
->pNextACMDriverID
->pPrevACMDriverID
= p
->pPrevACMDriverID
;
761 pNextACMDriverID
= p
->pNextACMDriverID
;
763 if (p
->pLocalDriver
) MSACM_UnregisterLocalDriver(p
->pLocalDriver
);
764 HeapFree(MSACM_hHeap
, 0, p
);
766 return pNextACMDriverID
;
769 /***********************************************************************
770 * MSACM_UnregisterAllDrivers()
772 void MSACM_UnregisterAllDrivers(void)
774 PWINE_ACMNOTIFYWND panwnd
= MSACM_pFirstACMNotifyWnd
;
775 PWINE_ACMDRIVERID p
= MSACM_pFirstACMDriverID
;
779 p
= MSACM_UnregisterDriver(p
);
783 panwnd
= MSACM_UnRegisterNotificationWindow(panwnd
);
787 /***********************************************************************
790 PWINE_ACMOBJ
MSACM_GetObj(HACMOBJ hObj
, DWORD type
)
792 PWINE_ACMOBJ pao
= (PWINE_ACMOBJ
)hObj
;
794 if (pao
== NULL
|| IsBadReadPtr(pao
, sizeof(WINE_ACMOBJ
)) ||
795 ((type
!= WINE_ACMOBJ_DONTCARE
) && (type
!= pao
->dwType
)))
800 /***********************************************************************
801 * MSACM_GetDriverID()
803 PWINE_ACMDRIVERID
MSACM_GetDriverID(HACMDRIVERID hDriverID
)
805 return (PWINE_ACMDRIVERID
)MSACM_GetObj((HACMOBJ
)hDriverID
, WINE_ACMOBJ_DRIVERID
);
808 /***********************************************************************
811 PWINE_ACMDRIVER
MSACM_GetDriver(HACMDRIVER hDriver
)
813 return (PWINE_ACMDRIVER
)MSACM_GetObj((HACMOBJ
)hDriver
, WINE_ACMOBJ_DRIVER
);
816 /***********************************************************************
817 * MSACM_GetNotifyWnd()
819 PWINE_ACMNOTIFYWND
MSACM_GetNotifyWnd(HACMDRIVERID hDriver
)
821 return (PWINE_ACMNOTIFYWND
)MSACM_GetObj((HACMOBJ
)hDriver
, WINE_ACMOBJ_NOTIFYWND
);
824 /***********************************************************************
825 * MSACM_GetLocalDriver()
828 PWINE_ACMLOCALDRIVER MSACM_GetLocalDriver(HACMDRIVER hDriver)
830 return (PWINE_ACMLOCALDRIVER)MSACM_GetObj((HACMOBJ)hDriver, WINE_ACMOBJ_LOCALDRIVER);
833 #define MSACM_DRIVER_SendMessage(PDRVRINST, msg, lParam1, lParam2) \
834 (PDRVRINST)->pLocalDriver->lpDrvProc((PDRVRINST)->dwDriverID, (HDRVR)(PDRVRINST), msg, lParam1, lParam2)
836 /***********************************************************************
839 MMRESULT
MSACM_Message(HACMDRIVER had
, UINT uMsg
, LPARAM lParam1
, LPARAM lParam2
)
841 PWINE_ACMDRIVER pad
= MSACM_GetDriver(had
);
843 if (!pad
) return MMSYSERR_INVALHANDLE
;
844 if (pad
->hDrvr
) return SendDriverMessage(pad
->hDrvr
, uMsg
, lParam1
, lParam2
);
845 if (pad
->pLocalDrvrInst
) return MSACM_DRIVER_SendMessage(pad
->pLocalDrvrInst
, uMsg
, lParam1
, lParam2
);
847 return MMSYSERR_INVALHANDLE
;
850 PWINE_ACMLOCALDRIVER
MSACM_RegisterLocalDriver(HMODULE hModule
, DRIVERPROC lpDriverProc
)
852 PWINE_ACMLOCALDRIVER paldrv
;
854 TRACE("(%p, %p)\n", hModule
, lpDriverProc
);
855 if (!hModule
|| !lpDriverProc
) return NULL
;
857 /* look up previous instance of local driver module */
858 for (paldrv
= MSACM_pFirstACMLocalDriver
; paldrv
; paldrv
= paldrv
->pNextACMLocalDrv
)
860 if (paldrv
->hModule
== hModule
&& paldrv
->lpDrvProc
== lpDriverProc
)
862 InterlockedIncrement(&paldrv
->ref
);
867 paldrv
= HeapAlloc(MSACM_hHeap
, 0, sizeof(WINE_ACMLOCALDRIVER
));
868 paldrv
->obj
.dwType
= WINE_ACMOBJ_LOCALDRIVER
;
869 paldrv
->obj
.pACMDriverID
= 0;
870 paldrv
->hModule
= hModule
;
871 paldrv
->lpDrvProc
= lpDriverProc
;
872 paldrv
->pACMInstList
= NULL
;
875 paldrv
->pNextACMLocalDrv
= NULL
;
876 paldrv
->pPrevACMLocalDrv
= MSACM_pLastACMLocalDriver
;
877 if (MSACM_pLastACMLocalDriver
)
878 MSACM_pLastACMLocalDriver
->pNextACMLocalDrv
= paldrv
;
879 MSACM_pLastACMLocalDriver
= paldrv
;
880 if (!MSACM_pFirstACMLocalDriver
)
881 MSACM_pFirstACMLocalDriver
= paldrv
;
886 /**************************************************************************
887 * MSACM_GetNumberOfModuleRefs [internal]
889 * Returns the number of open drivers which share the same module.
890 * Inspired from implementation in dlls/winmm/driver.c
892 static unsigned MSACM_GetNumberOfModuleRefs(HMODULE hModule
, DRIVERPROC lpDrvProc
, WINE_ACMLOCALDRIVERINST
** found
)
894 PWINE_ACMLOCALDRIVER lpDrv
;
897 if (found
) *found
= NULL
;
898 for (lpDrv
= MSACM_pFirstACMLocalDriver
; lpDrv
; lpDrv
= lpDrv
->pNextACMLocalDrv
)
900 if (lpDrv
->hModule
== hModule
&& lpDrv
->lpDrvProc
== lpDrvProc
)
902 PWINE_ACMLOCALDRIVERINST pInst
= lpDrv
->pACMInstList
;
905 if (found
&& !*found
) *found
= pInst
;
907 pInst
= pInst
->pNextACMInst
;
914 /**************************************************************************
915 * MSACM_RemoveFromList [internal]
917 * Generates all the logic to handle driver closure / deletion
918 * Removes a driver struct to the list of open drivers.
920 static BOOL
MSACM_RemoveFromList(PWINE_ACMLOCALDRIVERINST lpDrv
)
922 PWINE_ACMLOCALDRIVER pDriverBase
= lpDrv
->pLocalDriver
;
923 PWINE_ACMLOCALDRIVERINST pPrevInst
;
925 /* last of this driver in list ? */
926 if (MSACM_GetNumberOfModuleRefs(pDriverBase
->hModule
, pDriverBase
->lpDrvProc
, NULL
) == 1) {
927 MSACM_DRIVER_SendMessage(lpDrv
, DRV_DISABLE
, 0L, 0L);
928 MSACM_DRIVER_SendMessage(lpDrv
, DRV_FREE
, 0L, 0L);
932 if (pDriverBase
->pACMInstList
!= lpDrv
) {
933 pPrevInst
= pDriverBase
->pACMInstList
;
934 while (pPrevInst
&& pPrevInst
->pNextACMInst
!= lpDrv
)
935 pPrevInst
= pPrevInst
->pNextACMInst
;
937 ERR("requested to remove invalid instance %p\n", pPrevInst
);
942 /* first driver instance on list */
943 pDriverBase
->pACMInstList
= lpDrv
->pNextACMInst
;
945 pPrevInst
->pNextACMInst
= lpDrv
->pNextACMInst
;
950 /**************************************************************************
951 * MSACM_AddToList [internal]
953 * Adds a driver struct to the list of open drivers.
954 * Generates all the logic to handle driver creation / open.
956 static BOOL
MSACM_AddToList(PWINE_ACMLOCALDRIVERINST lpNewDrv
, LPARAM lParam2
)
958 PWINE_ACMLOCALDRIVER pDriverBase
= lpNewDrv
->pLocalDriver
;
960 /* first of this driver in list ? */
961 if (MSACM_GetNumberOfModuleRefs(pDriverBase
->hModule
, pDriverBase
->lpDrvProc
, NULL
) == 0) {
962 if (MSACM_DRIVER_SendMessage(lpNewDrv
, DRV_LOAD
, 0L, 0L) != DRV_SUCCESS
) {
963 FIXME("DRV_LOAD failed on driver %p\n", lpNewDrv
);
966 /* returned value is not checked */
967 MSACM_DRIVER_SendMessage(lpNewDrv
, DRV_ENABLE
, 0L, 0L);
970 lpNewDrv
->pNextACMInst
= NULL
;
971 if (pDriverBase
->pACMInstList
== NULL
) {
972 pDriverBase
->pACMInstList
= lpNewDrv
;
974 PWINE_ACMLOCALDRIVERINST lpDrvInst
= pDriverBase
->pACMInstList
;
976 while (lpDrvInst
->pNextACMInst
!= NULL
)
977 lpDrvInst
= lpDrvInst
->pNextACMInst
;
979 lpDrvInst
->pNextACMInst
= lpNewDrv
;
982 /* Now just open a new instance of a driver on this module */
983 lpNewDrv
->dwDriverID
= MSACM_DRIVER_SendMessage(lpNewDrv
, DRV_OPEN
, 0, lParam2
);
985 if (lpNewDrv
->dwDriverID
== 0) {
986 FIXME("DRV_OPEN failed on driver %p\n", lpNewDrv
);
987 MSACM_RemoveFromList(lpNewDrv
);
993 PWINE_ACMLOCALDRIVERINST
MSACM_OpenLocalDriver(PWINE_ACMLOCALDRIVER paldrv
, LPARAM lParam2
)
995 PWINE_ACMLOCALDRIVERINST pDrvInst
;
997 pDrvInst
= HeapAlloc(MSACM_hHeap
, 0, sizeof(WINE_ACMLOCALDRIVERINST
));
1001 pDrvInst
->pLocalDriver
= paldrv
;
1002 pDrvInst
->dwDriverID
= 0;
1003 pDrvInst
->pNextACMInst
= NULL
;
1004 pDrvInst
->bSession
= FALSE
;
1006 /* Win32 installable drivers must support a two phase opening scheme:
1007 * + first open with NULL as lParam2 (session instance),
1008 * + then do a second open with the real non null lParam2)
1010 if (MSACM_GetNumberOfModuleRefs(paldrv
->hModule
, paldrv
->lpDrvProc
, NULL
) == 0 && lParam2
)
1012 PWINE_ACMLOCALDRIVERINST ret
;
1014 if (!MSACM_AddToList(pDrvInst
, 0L))
1016 ERR("load0 failed\n");
1019 ret
= MSACM_OpenLocalDriver(paldrv
, lParam2
);
1022 ERR("load1 failed\n");
1023 /* If MSACM_CloseLocalDriver returns TRUE,
1024 * then pDrvInst has been freed
1026 if (!MSACM_CloseLocalDriver(pDrvInst
))
1031 pDrvInst
->bSession
= TRUE
;
1035 if (!MSACM_AddToList(pDrvInst
, lParam2
))
1037 ERR("load failed\n");
1041 TRACE("=> %p\n", pDrvInst
);
1044 HeapFree(MSACM_hHeap
, 0, pDrvInst
);
1048 LRESULT
MSACM_CloseLocalDriver(PWINE_ACMLOCALDRIVERINST paldrv
)
1050 if (MSACM_RemoveFromList(paldrv
)) {
1051 PWINE_ACMLOCALDRIVERINST lpDrv0
;
1052 PWINE_ACMLOCALDRIVER pDriverBase
= paldrv
->pLocalDriver
;
1054 MSACM_DRIVER_SendMessage(paldrv
, DRV_CLOSE
, 0, 0);
1055 paldrv
->dwDriverID
= 0;
1057 if (paldrv
->bSession
)
1058 ERR("should not directly close session instance (%p)\n", paldrv
);
1060 /* if driver has an opened session instance, we have to close it too */
1061 if (MSACM_GetNumberOfModuleRefs(pDriverBase
->hModule
, pDriverBase
->lpDrvProc
, &lpDrv0
) == 1 &&
1064 MSACM_DRIVER_SendMessage(lpDrv0
, DRV_CLOSE
, 0L, 0L);
1065 lpDrv0
->dwDriverID
= 0;
1066 MSACM_RemoveFromList(lpDrv0
);
1067 HeapFree(MSACM_hHeap
, 0, lpDrv0
);
1070 HeapFree(MSACM_hHeap
, 0, paldrv
);
1073 ERR("unable to close driver instance\n");