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"
39 #include "wine/unicode.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msacm
);
43 /**********************************************************************/
45 HANDLE MSACM_hHeap
= NULL
;
46 PWINE_ACMDRIVERID MSACM_pFirstACMDriverID
= NULL
;
47 static PWINE_ACMDRIVERID MSACM_pLastACMDriverID
;
49 static DWORD MSACM_suspendBroadcastCount
= 0;
50 static BOOL MSACM_pendingBroadcast
= FALSE
;
51 static PWINE_ACMNOTIFYWND MSACM_pFirstACMNotifyWnd
= NULL
;
52 static PWINE_ACMNOTIFYWND MSACM_pLastACMNotifyWnd
= NULL
;
54 static void MSACM_ReorderDriversByPriority(void);
56 /***********************************************************************
57 * MSACM_RegisterDriverFromRegistry()
59 PWINE_ACMDRIVERID
MSACM_RegisterDriverFromRegistry(LPCWSTR pszRegEntry
)
61 static const WCHAR msacmW
[] = {'M','S','A','C','M','.'};
62 static const WCHAR drvkey
[] = {'S','o','f','t','w','a','r','e','\\',
63 'M','i','c','r','o','s','o','f','t','\\',
64 'W','i','n','d','o','w','s',' ','N','T','\\',
65 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
66 'D','r','i','v','e','r','s','3','2','\0'};
70 PWINE_ACMDRIVERID padid
= NULL
;
72 /* The requested registry entry must have the format msacm.XXXXX in order to
73 be recognized in any future sessions of msacm
75 if (0 == strncmpiW(pszRegEntry
, msacmW
, sizeof(msacmW
)/sizeof(WCHAR
))) {
76 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, drvkey
, 0, KEY_QUERY_VALUE
, &hKey
);
77 if (lRet
!= ERROR_SUCCESS
) {
78 WARN("unable to open registry key - 0x%08x\n", lRet
);
81 lRet
= RegQueryValueExW(hKey
, pszRegEntry
, NULL
, NULL
, (LPBYTE
)buf
, &bufLen
);
82 if (lRet
!= ERROR_SUCCESS
) {
83 WARN("unable to query requested subkey %s - 0x%08x\n", debugstr_w(pszRegEntry
), lRet
);
85 MSACM_RegisterDriver(pszRegEntry
, buf
, 0);
94 /***********************************************************************
97 static void MSACM_DumpCache(PWINE_ACMDRIVERID padid
)
101 TRACE("cFilterTags=%lu cFormatTags=%lu fdwSupport=%08lx\n",
102 padid
->cFilterTags
, padid
->cFormatTags
, padid
->fdwSupport
);
103 for (i
= 0; i
< padid
->cache
->cFormatTags
; i
++) {
104 TRACE("\tdwFormatTag=%lu cbwfx=%lu\n",
105 padid
->aFormatTag
[i
].dwFormatTag
, padid
->aFormatTag
[i
].cbwfx
);
110 /***********************************************************************
111 * MSACM_FindFormatTagInCache [internal]
113 * Returns TRUE is the format tag fmtTag is present in the cache.
114 * If so, idx is set to its index.
116 BOOL
MSACM_FindFormatTagInCache(const WINE_ACMDRIVERID
* padid
, DWORD fmtTag
, LPDWORD idx
)
120 for (i
= 0; i
< padid
->cFormatTags
; i
++) {
121 if (padid
->aFormatTag
[i
].dwFormatTag
== fmtTag
) {
129 /***********************************************************************
132 static BOOL
MSACM_FillCache(PWINE_ACMDRIVERID padid
)
136 ACMDRIVERDETAILSW add
;
137 ACMFORMATTAGDETAILSW aftd
;
139 if (acmDriverOpen(&had
, (HACMDRIVERID
)padid
, 0) != 0)
142 padid
->aFormatTag
= NULL
;
143 add
.cbStruct
= sizeof(add
);
144 if (MSACM_Message(had
, ACMDM_DRIVER_DETAILS
, (LPARAM
)&add
, 0))
147 if (add
.cFormatTags
> 0) {
148 padid
->aFormatTag
= HeapAlloc(MSACM_hHeap
, HEAP_ZERO_MEMORY
,
149 add
.cFormatTags
* sizeof(padid
->aFormatTag
[0]));
150 if (!padid
->aFormatTag
) goto errCleanUp
;
153 padid
->cFormatTags
= add
.cFormatTags
;
154 padid
->cFilterTags
= add
.cFilterTags
;
155 padid
->fdwSupport
= add
.fdwSupport
;
157 aftd
.cbStruct
= sizeof(aftd
);
159 for (ntag
= 0; ntag
< add
.cFormatTags
; ntag
++) {
160 aftd
.dwFormatTagIndex
= ntag
;
161 if (MSACM_Message(had
, ACMDM_FORMATTAG_DETAILS
, (LPARAM
)&aftd
, ACM_FORMATTAGDETAILSF_INDEX
)) {
162 TRACE("IIOs (%s)\n", debugstr_w(padid
->pszDriverAlias
));
165 padid
->aFormatTag
[ntag
].dwFormatTag
= aftd
.dwFormatTag
;
166 padid
->aFormatTag
[ntag
].cbwfx
= aftd
.cbFormatSize
;
169 acmDriverClose(had
, 0);
174 if (had
) acmDriverClose(had
, 0);
175 HeapFree(MSACM_hHeap
, 0, padid
->aFormatTag
);
176 padid
->aFormatTag
= NULL
;
180 /***********************************************************************
181 * MSACM_GetRegistryKey
183 static LPWSTR
MSACM_GetRegistryKey(const WINE_ACMDRIVERID
* padid
)
185 static const WCHAR baseKey
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
186 'A','u','d','i','o','C','o','m','p','r','e','s','s','i','o','n','M','a','n','a','g','e','r','\\',
187 'D','r','i','v','e','r','C','a','c','h','e','\\','\0'};
191 if (!padid
->pszDriverAlias
) {
192 ERR("No alias needed for registry entry\n");
195 len
= strlenW(baseKey
);
196 ret
= HeapAlloc(MSACM_hHeap
, 0, (len
+ strlenW(padid
->pszDriverAlias
) + 1) * sizeof(WCHAR
));
197 if (!ret
) return NULL
;
199 strcpyW(ret
, baseKey
);
200 strcpyW(ret
+ len
, padid
->pszDriverAlias
);
201 CharLowerW(ret
+ len
);
205 /***********************************************************************
208 static BOOL
MSACM_ReadCache(PWINE_ACMDRIVERID padid
)
210 LPWSTR key
= MSACM_GetRegistryKey(padid
);
214 if (!key
) return FALSE
;
216 padid
->aFormatTag
= NULL
;
218 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, key
, &hKey
))
221 size
= sizeof(padid
->cFormatTags
);
222 if (RegQueryValueExA(hKey
, "cFormatTags", 0, &type
, (void*)&padid
->cFormatTags
, &size
))
224 size
= sizeof(padid
->cFilterTags
);
225 if (RegQueryValueExA(hKey
, "cFilterTags", 0, &type
, (void*)&padid
->cFilterTags
, &size
))
227 size
= sizeof(padid
->fdwSupport
);
228 if (RegQueryValueExA(hKey
, "fdwSupport", 0, &type
, (void*)&padid
->fdwSupport
, &size
))
231 if (padid
->cFormatTags
> 0) {
232 size
= padid
->cFormatTags
* sizeof(padid
->aFormatTag
[0]);
233 padid
->aFormatTag
= HeapAlloc(MSACM_hHeap
, HEAP_ZERO_MEMORY
, size
);
234 if (!padid
->aFormatTag
) goto errCleanUp
;
235 if (RegQueryValueExA(hKey
, "aFormatTagCache", 0, &type
, (void*)padid
->aFormatTag
, &size
))
238 HeapFree(MSACM_hHeap
, 0, key
);
242 HeapFree(MSACM_hHeap
, 0, key
);
243 HeapFree(MSACM_hHeap
, 0, padid
->aFormatTag
);
244 padid
->aFormatTag
= NULL
;
249 /***********************************************************************
252 static BOOL
MSACM_WriteCache(const WINE_ACMDRIVERID
*padid
)
254 LPWSTR key
= MSACM_GetRegistryKey(padid
);
257 if (!key
) return FALSE
;
259 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, key
, &hKey
))
262 if (RegSetValueExA(hKey
, "cFormatTags", 0, REG_DWORD
, (const void*)&padid
->cFormatTags
, sizeof(DWORD
)))
264 if (RegSetValueExA(hKey
, "cFilterTags", 0, REG_DWORD
, (const void*)&padid
->cFilterTags
, sizeof(DWORD
)))
266 if (RegSetValueExA(hKey
, "fdwSupport", 0, REG_DWORD
, (const void*)&padid
->fdwSupport
, sizeof(DWORD
)))
268 if (RegSetValueExA(hKey
, "aFormatTagCache", 0, REG_BINARY
,
269 (void*)padid
->aFormatTag
,
270 padid
->cFormatTags
* sizeof(padid
->aFormatTag
[0])))
272 HeapFree(MSACM_hHeap
, 0, key
);
276 HeapFree(MSACM_hHeap
, 0, key
);
280 /***********************************************************************
281 * MSACM_RegisterDriver()
283 PWINE_ACMDRIVERID
MSACM_RegisterDriver(LPCWSTR pszDriverAlias
, LPCWSTR pszFileName
,
284 PWINE_ACMLOCALDRIVER pLocalDriver
)
286 PWINE_ACMDRIVERID padid
;
288 TRACE("(%s, %s, %p)\n",
289 debugstr_w(pszDriverAlias
), debugstr_w(pszFileName
), pLocalDriver
);
291 padid
= HeapAlloc(MSACM_hHeap
, 0, sizeof(WINE_ACMDRIVERID
));
294 padid
->obj
.dwType
= WINE_ACMOBJ_DRIVERID
;
295 padid
->obj
.pACMDriverID
= padid
;
296 padid
->pszDriverAlias
= NULL
;
299 padid
->pszDriverAlias
= HeapAlloc( MSACM_hHeap
, 0, (strlenW(pszDriverAlias
)+1) * sizeof(WCHAR
) );
300 if (!padid
->pszDriverAlias
) {
301 HeapFree(MSACM_hHeap
, 0, padid
);
304 strcpyW( padid
->pszDriverAlias
, pszDriverAlias
);
306 padid
->pszFileName
= NULL
;
309 padid
->pszFileName
= HeapAlloc( MSACM_hHeap
, 0, (strlenW(pszFileName
)+1) * sizeof(WCHAR
) );
310 if (!padid
->pszFileName
) {
311 HeapFree(MSACM_hHeap
, 0, padid
->pszDriverAlias
);
312 HeapFree(MSACM_hHeap
, 0, padid
);
315 strcpyW( padid
->pszFileName
, pszFileName
);
317 padid
->pLocalDriver
= pLocalDriver
;
319 padid
->pACMDriverList
= NULL
;
322 padid
->pPrevACMDriverID
= NULL
;
323 padid
->pNextACMDriverID
= MSACM_pFirstACMDriverID
;
324 if (MSACM_pFirstACMDriverID
)
325 MSACM_pFirstACMDriverID
->pPrevACMDriverID
= padid
;
326 MSACM_pFirstACMDriverID
= padid
;
327 if (!MSACM_pLastACMDriverID
)
328 MSACM_pLastACMDriverID
= padid
;
330 padid
->pNextACMDriverID
= NULL
;
331 padid
->pPrevACMDriverID
= MSACM_pLastACMDriverID
;
332 if (MSACM_pLastACMDriverID
)
333 MSACM_pLastACMDriverID
->pNextACMDriverID
= padid
;
334 MSACM_pLastACMDriverID
= padid
;
335 if (!MSACM_pFirstACMDriverID
)
336 MSACM_pFirstACMDriverID
= padid
;
338 /* disable the driver if we cannot load the cache */
339 if ((!padid
->pszDriverAlias
|| !MSACM_ReadCache(padid
)) && !MSACM_FillCache(padid
)) {
340 WARN("Couldn't load cache for ACM driver (%s)\n", debugstr_w(pszFileName
));
341 MSACM_UnregisterDriver(padid
);
345 if (pLocalDriver
) padid
->fdwSupport
|= ACMDRIVERDETAILS_SUPPORTF_LOCAL
;
349 /***********************************************************************
350 * MSACM_RegisterAllDrivers()
352 void MSACM_RegisterAllDrivers(void)
354 static const WCHAR msacm32
[] = {'m','s','a','c','m','3','2','.','d','l','l','\0'};
355 static const WCHAR msacmW
[] = {'M','S','A','C','M','.'};
356 static const WCHAR drv32
[] = {'d','r','i','v','e','r','s','3','2','\0'};
357 static const WCHAR sys
[] = {'s','y','s','t','e','m','.','i','n','i','\0'};
358 static const WCHAR drvkey
[] = {'S','o','f','t','w','a','r','e','\\',
359 'M','i','c','r','o','s','o','f','t','\\',
360 'W','i','n','d','o','w','s',' ','N','T','\\',
361 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
362 'D','r','i','v','e','r','s','3','2','\0'};
363 DWORD i
, cnt
, bufLen
, lRet
, type
;
364 WCHAR buf
[2048], valname
[64], *name
, *s
;
368 /* FIXME: What if the user edits system.ini while the program is running?
369 * Does Windows handle that? */
370 if (MSACM_pFirstACMDriverID
) return;
372 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, drvkey
, 0, KEY_QUERY_VALUE
, &hKey
);
373 if (lRet
== ERROR_SUCCESS
) {
374 RegQueryInfoKeyW( hKey
, 0, 0, 0, &cnt
, 0, 0, 0, 0, 0, 0, 0);
375 for (i
= 0; i
< cnt
; i
++) {
376 bufLen
= sizeof(buf
) / sizeof(buf
[0]);
377 lRet
= RegEnumKeyExW(hKey
, i
, buf
, &bufLen
, 0, 0, 0, &lastWrite
);
378 if (lRet
!= ERROR_SUCCESS
) continue;
379 if (strncmpiW(buf
, msacmW
, sizeof(msacmW
)/sizeof(msacmW
[0]))) continue;
380 if (!(name
= strchrW(buf
, '='))) continue;
382 MSACM_RegisterDriver(buf
, name
+ 1, 0);
385 cnt
= sizeof(valname
) / sizeof(*valname
);
386 bufLen
= sizeof(buf
);
387 while(RegEnumValueW(hKey
, i
, valname
, &cnt
, 0,
388 &type
, (BYTE
*)buf
, &bufLen
) == ERROR_SUCCESS
){
389 if(!strncmpiW(valname
, msacmW
, sizeof(msacmW
) / sizeof(*msacmW
)))
390 MSACM_RegisterDriver(valname
, buf
, 0);
396 if (GetPrivateProfileSectionW(drv32
, buf
, sizeof(buf
)/sizeof(buf
[0]), sys
))
398 for(s
= buf
; *s
; s
+= strlenW(s
) + 1)
400 if (strncmpiW(s
, msacmW
, sizeof(msacmW
)/sizeof(msacmW
[0]))) continue;
401 if (!(name
= strchrW(s
, '='))) continue;
403 MSACM_RegisterDriver(s
, name
+ 1, 0);
407 MSACM_ReorderDriversByPriority();
408 MSACM_RegisterDriver(msacm32
, msacm32
, 0);
411 /***********************************************************************
412 * MSACM_RegisterNotificationWindow()
414 PWINE_ACMNOTIFYWND
MSACM_RegisterNotificationWindow(HWND hNotifyWnd
, DWORD dwNotifyMsg
)
416 PWINE_ACMNOTIFYWND panwnd
;
418 TRACE("(%p,0x%08x)\n", hNotifyWnd
, dwNotifyMsg
);
420 panwnd
= HeapAlloc(MSACM_hHeap
, 0, sizeof(WINE_ACMNOTIFYWND
));
421 panwnd
->obj
.dwType
= WINE_ACMOBJ_NOTIFYWND
;
422 panwnd
->obj
.pACMDriverID
= 0;
423 panwnd
->hNotifyWnd
= hNotifyWnd
;
424 panwnd
->dwNotifyMsg
= dwNotifyMsg
;
425 panwnd
->fdwSupport
= 0;
427 panwnd
->pNextACMNotifyWnd
= NULL
;
428 panwnd
->pPrevACMNotifyWnd
= MSACM_pLastACMNotifyWnd
;
429 if (MSACM_pLastACMNotifyWnd
)
430 MSACM_pLastACMNotifyWnd
->pNextACMNotifyWnd
= panwnd
;
431 MSACM_pLastACMNotifyWnd
= panwnd
;
432 if (!MSACM_pFirstACMNotifyWnd
)
433 MSACM_pFirstACMNotifyWnd
= panwnd
;
438 /***********************************************************************
439 * MSACM_BroadcastNotification()
441 void MSACM_BroadcastNotification(void)
443 if (MSACM_suspendBroadcastCount
<= 0) {
444 PWINE_ACMNOTIFYWND panwnd
;
446 for (panwnd
= MSACM_pFirstACMNotifyWnd
; panwnd
; panwnd
= panwnd
->pNextACMNotifyWnd
)
447 if (!(panwnd
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
))
448 SendMessageW(panwnd
->hNotifyWnd
, panwnd
->dwNotifyMsg
, 0, 0);
450 MSACM_pendingBroadcast
= TRUE
;
454 /***********************************************************************
455 * MSACM_DisableNotifications()
457 void MSACM_DisableNotifications(void)
459 MSACM_suspendBroadcastCount
++;
462 /***********************************************************************
463 * MSACM_EnableNotifications()
465 void MSACM_EnableNotifications(void)
467 if (MSACM_suspendBroadcastCount
> 0) {
468 MSACM_suspendBroadcastCount
--;
469 if (MSACM_suspendBroadcastCount
== 0 && MSACM_pendingBroadcast
) {
470 MSACM_pendingBroadcast
= FALSE
;
471 MSACM_BroadcastNotification();
476 /***********************************************************************
477 * MSACM_UnRegisterNotificationWindow()
479 PWINE_ACMNOTIFYWND
MSACM_UnRegisterNotificationWindow(const WINE_ACMNOTIFYWND
*panwnd
)
481 PWINE_ACMNOTIFYWND p
;
483 for (p
= MSACM_pFirstACMNotifyWnd
; p
; p
= p
->pNextACMNotifyWnd
) {
485 PWINE_ACMNOTIFYWND pNext
= p
->pNextACMNotifyWnd
;
487 if (p
->pPrevACMNotifyWnd
) p
->pPrevACMNotifyWnd
->pNextACMNotifyWnd
= p
->pNextACMNotifyWnd
;
488 if (p
->pNextACMNotifyWnd
) p
->pNextACMNotifyWnd
->pPrevACMNotifyWnd
= p
->pPrevACMNotifyWnd
;
489 if (MSACM_pFirstACMNotifyWnd
== p
) MSACM_pFirstACMNotifyWnd
= p
->pNextACMNotifyWnd
;
490 if (MSACM_pLastACMNotifyWnd
== p
) MSACM_pLastACMNotifyWnd
= p
->pPrevACMNotifyWnd
;
491 HeapFree(MSACM_hHeap
, 0, p
);
499 /***********************************************************************
500 * MSACM_RePositionDriver()
502 void MSACM_RePositionDriver(PWINE_ACMDRIVERID padid
, DWORD dwPriority
)
504 PWINE_ACMDRIVERID pTargetPosition
= NULL
;
506 /* Remove selected driver from linked list */
507 if (MSACM_pFirstACMDriverID
== padid
) {
508 MSACM_pFirstACMDriverID
= padid
->pNextACMDriverID
;
510 if (MSACM_pLastACMDriverID
== padid
) {
511 MSACM_pLastACMDriverID
= padid
->pPrevACMDriverID
;
513 if (padid
->pPrevACMDriverID
!= NULL
) {
514 padid
->pPrevACMDriverID
->pNextACMDriverID
= padid
->pNextACMDriverID
;
516 if (padid
->pNextACMDriverID
!= NULL
) {
517 padid
->pNextACMDriverID
->pPrevACMDriverID
= padid
->pPrevACMDriverID
;
520 /* Look up position where selected driver should be */
521 if (dwPriority
== 1) {
522 pTargetPosition
= padid
->pPrevACMDriverID
;
523 while (pTargetPosition
->pPrevACMDriverID
!= NULL
&&
524 !(pTargetPosition
->pPrevACMDriverID
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_LOCAL
)) {
525 pTargetPosition
= pTargetPosition
->pPrevACMDriverID
;
527 } else if (dwPriority
== -1) {
528 pTargetPosition
= padid
->pNextACMDriverID
;
529 while (pTargetPosition
->pNextACMDriverID
!= NULL
) {
530 pTargetPosition
= pTargetPosition
->pNextACMDriverID
;
534 /* Place selected driver in selected position */
535 padid
->pPrevACMDriverID
= pTargetPosition
->pPrevACMDriverID
;
536 padid
->pNextACMDriverID
= pTargetPosition
;
537 if (padid
->pPrevACMDriverID
!= NULL
) {
538 padid
->pPrevACMDriverID
->pNextACMDriverID
= padid
;
540 MSACM_pFirstACMDriverID
= padid
;
542 if (padid
->pNextACMDriverID
!= NULL
) {
543 padid
->pNextACMDriverID
->pPrevACMDriverID
= padid
;
545 MSACM_pLastACMDriverID
= padid
;
549 /***********************************************************************
550 * MSACM_ReorderDriversByPriority()
551 * Reorders all drivers based on the priority list indicated by the registry key:
552 * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
554 static void MSACM_ReorderDriversByPriority(void)
556 PWINE_ACMDRIVERID padid
;
557 unsigned int iNumDrivers
;
558 PWINE_ACMDRIVERID
* driverList
= NULL
;
559 HKEY hPriorityKey
= NULL
;
563 /* Count drivers && alloc corresponding memory for list */
565 for (padid
= MSACM_pFirstACMDriverID
; padid
; padid
= padid
->pNextACMDriverID
) iNumDrivers
++;
569 static const WCHAR basePriorityKey
[] = {
570 'S','o','f','t','w','a','r','e','\\',
571 'M','i','c','r','o','s','o','f','t','\\',
572 'M','u','l','t','i','m','e','d','i','a','\\',
573 'A','u','d','i','o',' ','C','o','m','p','r','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
574 'P','r','i','o','r','i','t','y',' ','v','4','.','0','0','\0'
580 driverList
= HeapAlloc(MSACM_hHeap
, 0, iNumDrivers
* sizeof(PWINE_ACMDRIVERID
));
583 ERR("out of memory\n");
587 lError
= RegOpenKeyW(HKEY_CURRENT_USER
, basePriorityKey
, &hPriorityKey
);
588 if (lError
!= ERROR_SUCCESS
) {
589 TRACE("RegOpenKeyW failed, possibly key does not exist yet\n");
594 /* Copy drivers into list to simplify linked list modification */
595 for (i
= 0, padid
= MSACM_pFirstACMDriverID
; padid
; padid
= padid
->pNextACMDriverID
, i
++)
597 driverList
[i
] = padid
;
600 /* Query each of the priorities in turn. Alias key is in lowercase.
601 The general form of the priority record is the following:
602 "PriorityN" --> "1, msacm.driveralias"
603 where N is an integer, and the value is a string of the driver
604 alias, prefixed by "1, " for an enabled driver, or "0, " for a
607 for (i
= 0; i
< iNumDrivers
; i
++)
609 static const WCHAR priorityTmpl
[] = {'P','r','i','o','r','i','t','y','%','l','d','\0'};
611 unsigned int iTargetPosition
;
612 unsigned int iCurrentPosition
;
614 static const WCHAR sPrefix
[] = {'m','s','a','c','m','.','\0'};
616 /* Build expected entry name */
617 snprintfW(szSubKey
, 17, priorityTmpl
, i
+ 1);
618 lBufferLength
= sizeof(szBuffer
);
619 lError
= RegQueryValueExW(hPriorityKey
, szSubKey
, NULL
, NULL
, (LPBYTE
)szBuffer
, (LPDWORD
)&lBufferLength
);
620 if (lError
!= ERROR_SUCCESS
) continue;
622 /* Recovered driver alias should be at this position */
625 /* Locate driver alias in driver list */
626 pAlias
= strstrW(szBuffer
, sPrefix
);
627 if (pAlias
== NULL
) continue;
629 for (iCurrentPosition
= 0; iCurrentPosition
< iNumDrivers
; iCurrentPosition
++) {
630 if (strcmpiW(driverList
[iCurrentPosition
]->pszDriverAlias
, pAlias
) == 0)
633 if (iCurrentPosition
< iNumDrivers
&& iTargetPosition
!= iCurrentPosition
) {
634 padid
= driverList
[iTargetPosition
];
635 driverList
[iTargetPosition
] = driverList
[iCurrentPosition
];
636 driverList
[iCurrentPosition
] = padid
;
638 /* Locate enabled status */
639 if (szBuffer
[0] == '1') {
640 driverList
[iTargetPosition
]->fdwSupport
&= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED
;
641 } else if (szBuffer
[0] == '0') {
642 driverList
[iTargetPosition
]->fdwSupport
|= ACMDRIVERDETAILS_SUPPORTF_DISABLED
;
647 /* Re-assign pointers so that linked list traverses the ordered array */
648 for (i
= 0; i
< iNumDrivers
; i
++) {
649 driverList
[i
]->pPrevACMDriverID
= (i
> 0) ? driverList
[i
- 1] : NULL
;
650 driverList
[i
]->pNextACMDriverID
= (i
< iNumDrivers
- 1) ? driverList
[i
+ 1] : NULL
;
652 MSACM_pFirstACMDriverID
= driverList
[0];
653 MSACM_pLastACMDriverID
= driverList
[iNumDrivers
- 1];
657 if (hPriorityKey
!= NULL
) RegCloseKey(hPriorityKey
);
658 HeapFree(MSACM_hHeap
, 0, driverList
);
661 /***********************************************************************
662 * MSACM_WriteCurrentPriorities()
663 * Writes out current order of driver priorities to registry key:
664 * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
666 void MSACM_WriteCurrentPriorities(void)
670 static const WCHAR basePriorityKey
[] = {
671 'S','o','f','t','w','a','r','e','\\',
672 'M','i','c','r','o','s','o','f','t','\\',
673 'M','u','l','t','i','m','e','d','i','a','\\',
674 'A','u','d','i','o',' ','C','o','m','p','r','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
675 'P','r','i','o','r','i','t','y',' ','v','4','.','0','0','\0'
677 PWINE_ACMDRIVERID padid
;
678 DWORD dwPriorityCounter
;
679 static const WCHAR priorityTmpl
[] = {'P','r','i','o','r','i','t','y','%','l','d','\0'};
680 static const WCHAR valueTmpl
[] = {'%','c',',',' ','%','s','\0'};
681 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'};
685 /* Delete ACM priority key and create it anew */
686 lError
= RegDeleteKeyW(HKEY_CURRENT_USER
, basePriorityKey
);
687 if (lError
!= ERROR_SUCCESS
&& lError
!= ERROR_FILE_NOT_FOUND
) {
688 ERR("unable to remove current key %s (0x%08x) - priority changes won't persist past application end.\n",
689 debugstr_w(basePriorityKey
), lError
);
692 lError
= RegCreateKeyW(HKEY_CURRENT_USER
, basePriorityKey
, &hPriorityKey
);
693 if (lError
!= ERROR_SUCCESS
) {
694 ERR("unable to create key %s (0x%08x) - priority changes won't persist past application end.\n",
695 debugstr_w(basePriorityKey
), lError
);
699 /* Write current list of priorities */
700 for (dwPriorityCounter
= 0, padid
= MSACM_pFirstACMDriverID
; padid
; padid
= padid
->pNextACMDriverID
) {
701 if (padid
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_LOCAL
) continue;
702 if (padid
->pszDriverAlias
== NULL
) continue; /* internal PCM converter is last */
704 /* Build required value name */
706 snprintfW(szSubKey
, 17, priorityTmpl
, dwPriorityCounter
);
708 /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */
709 snprintfW(szBuffer
, 256, valueTmpl
, (padid
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
) ? '0' : '1', padid
->pszDriverAlias
);
712 lError
= RegSetValueExW(hPriorityKey
, szSubKey
, 0, REG_SZ
, (BYTE
*)szBuffer
, (strlenW(szBuffer
) + 1) * sizeof(WCHAR
));
713 if (lError
!= ERROR_SUCCESS
) {
714 ERR("unable to write value for %s under key %s (0x%08x)\n",
715 debugstr_w(padid
->pszDriverAlias
), debugstr_w(basePriorityKey
), lError
);
719 /* Build required value name */
721 snprintfW(szSubKey
, 17, priorityTmpl
, dwPriorityCounter
);
723 /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */
724 snprintfW(szBuffer
, 256, valueTmpl
, '1', converterAlias
);
726 lError
= RegSetValueExW(hPriorityKey
, szSubKey
, 0, REG_SZ
, (BYTE
*)szBuffer
, (strlenW(szBuffer
) + 1) * sizeof(WCHAR
));
727 if (lError
!= ERROR_SUCCESS
) {
728 ERR("unable to write value for %s under key %s (0x%08x)\n",
729 debugstr_w(converterAlias
), debugstr_w(basePriorityKey
), lError
);
731 RegCloseKey(hPriorityKey
);
734 static PWINE_ACMLOCALDRIVER MSACM_pFirstACMLocalDriver
;
735 static PWINE_ACMLOCALDRIVER MSACM_pLastACMLocalDriver
;
737 static PWINE_ACMLOCALDRIVER
MSACM_UnregisterLocalDriver(PWINE_ACMLOCALDRIVER paldrv
)
739 PWINE_ACMLOCALDRIVER pNextACMLocalDriver
;
741 if (paldrv
->pACMInstList
) {
742 ERR("local driver instances still present after closing all drivers - memory leak\n");
746 if (paldrv
== MSACM_pFirstACMLocalDriver
)
747 MSACM_pFirstACMLocalDriver
= paldrv
->pNextACMLocalDrv
;
748 if (paldrv
== MSACM_pLastACMLocalDriver
)
749 MSACM_pLastACMLocalDriver
= paldrv
->pPrevACMLocalDrv
;
751 if (paldrv
->pPrevACMLocalDrv
)
752 paldrv
->pPrevACMLocalDrv
->pNextACMLocalDrv
= paldrv
->pNextACMLocalDrv
;
753 if (paldrv
->pNextACMLocalDrv
)
754 paldrv
->pNextACMLocalDrv
->pPrevACMLocalDrv
= paldrv
->pPrevACMLocalDrv
;
756 pNextACMLocalDriver
= paldrv
->pNextACMLocalDrv
;
758 HeapFree(MSACM_hHeap
, 0, paldrv
);
760 return pNextACMLocalDriver
;
763 /***********************************************************************
764 * MSACM_UnregisterDriver()
766 PWINE_ACMDRIVERID
MSACM_UnregisterDriver(PWINE_ACMDRIVERID p
)
768 PWINE_ACMDRIVERID pNextACMDriverID
;
770 while (p
->pACMDriverList
)
771 acmDriverClose((HACMDRIVER
) p
->pACMDriverList
, 0);
773 HeapFree(MSACM_hHeap
, 0, p
->pszDriverAlias
);
774 HeapFree(MSACM_hHeap
, 0, p
->pszFileName
);
775 HeapFree(MSACM_hHeap
, 0, p
->aFormatTag
);
777 if (p
== MSACM_pFirstACMDriverID
)
778 MSACM_pFirstACMDriverID
= p
->pNextACMDriverID
;
779 if (p
== MSACM_pLastACMDriverID
)
780 MSACM_pLastACMDriverID
= p
->pPrevACMDriverID
;
782 if (p
->pPrevACMDriverID
)
783 p
->pPrevACMDriverID
->pNextACMDriverID
= p
->pNextACMDriverID
;
784 if (p
->pNextACMDriverID
)
785 p
->pNextACMDriverID
->pPrevACMDriverID
= p
->pPrevACMDriverID
;
787 pNextACMDriverID
= p
->pNextACMDriverID
;
789 if (p
->pLocalDriver
) MSACM_UnregisterLocalDriver(p
->pLocalDriver
);
790 HeapFree(MSACM_hHeap
, 0, p
);
792 return pNextACMDriverID
;
795 /***********************************************************************
796 * MSACM_UnregisterAllDrivers()
798 void MSACM_UnregisterAllDrivers(void)
800 PWINE_ACMNOTIFYWND panwnd
= MSACM_pFirstACMNotifyWnd
;
801 PWINE_ACMDRIVERID p
= MSACM_pFirstACMDriverID
;
805 p
= MSACM_UnregisterDriver(p
);
809 panwnd
= MSACM_UnRegisterNotificationWindow(panwnd
);
813 /***********************************************************************
816 PWINE_ACMOBJ
MSACM_GetObj(HACMOBJ hObj
, DWORD type
)
818 PWINE_ACMOBJ pao
= (PWINE_ACMOBJ
)hObj
;
820 if (pao
== NULL
|| IsBadReadPtr(pao
, sizeof(WINE_ACMOBJ
)) ||
821 ((type
!= WINE_ACMOBJ_DONTCARE
) && (type
!= pao
->dwType
)))
826 /***********************************************************************
827 * MSACM_GetDriverID()
829 PWINE_ACMDRIVERID
MSACM_GetDriverID(HACMDRIVERID hDriverID
)
831 return (PWINE_ACMDRIVERID
)MSACM_GetObj((HACMOBJ
)hDriverID
, WINE_ACMOBJ_DRIVERID
);
834 /***********************************************************************
837 PWINE_ACMDRIVER
MSACM_GetDriver(HACMDRIVER hDriver
)
839 return (PWINE_ACMDRIVER
)MSACM_GetObj((HACMOBJ
)hDriver
, WINE_ACMOBJ_DRIVER
);
842 /***********************************************************************
843 * MSACM_GetNotifyWnd()
845 PWINE_ACMNOTIFYWND
MSACM_GetNotifyWnd(HACMDRIVERID hDriver
)
847 return (PWINE_ACMNOTIFYWND
)MSACM_GetObj((HACMOBJ
)hDriver
, WINE_ACMOBJ_NOTIFYWND
);
850 /***********************************************************************
851 * MSACM_GetLocalDriver()
854 PWINE_ACMLOCALDRIVER MSACM_GetLocalDriver(HACMDRIVER hDriver)
856 return (PWINE_ACMLOCALDRIVER)MSACM_GetObj((HACMOBJ)hDriver, WINE_ACMOBJ_LOCALDRIVER);
859 #define MSACM_DRIVER_SendMessage(PDRVRINST, msg, lParam1, lParam2) \
860 (PDRVRINST)->pLocalDriver->lpDrvProc((PDRVRINST)->dwDriverID, (HDRVR)(PDRVRINST), msg, lParam1, lParam2)
862 /***********************************************************************
865 MMRESULT
MSACM_Message(HACMDRIVER had
, UINT uMsg
, LPARAM lParam1
, LPARAM lParam2
)
867 PWINE_ACMDRIVER pad
= MSACM_GetDriver(had
);
869 if (!pad
) return MMSYSERR_INVALHANDLE
;
870 if (pad
->hDrvr
) return SendDriverMessage(pad
->hDrvr
, uMsg
, lParam1
, lParam2
);
871 if (pad
->pLocalDrvrInst
) return MSACM_DRIVER_SendMessage(pad
->pLocalDrvrInst
, uMsg
, lParam1
, lParam2
);
873 return MMSYSERR_INVALHANDLE
;
876 PWINE_ACMLOCALDRIVER
MSACM_RegisterLocalDriver(HMODULE hModule
, DRIVERPROC lpDriverProc
)
878 PWINE_ACMLOCALDRIVER paldrv
;
880 TRACE("(%p, %p)\n", hModule
, lpDriverProc
);
881 if (!hModule
|| !lpDriverProc
) return NULL
;
883 /* look up previous instance of local driver module */
884 for (paldrv
= MSACM_pFirstACMLocalDriver
; paldrv
; paldrv
= paldrv
->pNextACMLocalDrv
)
886 if (paldrv
->hModule
== hModule
&& paldrv
->lpDrvProc
== lpDriverProc
) return paldrv
;
889 paldrv
= HeapAlloc(MSACM_hHeap
, 0, sizeof(WINE_ACMLOCALDRIVER
));
890 paldrv
->obj
.dwType
= WINE_ACMOBJ_LOCALDRIVER
;
891 paldrv
->obj
.pACMDriverID
= 0;
892 paldrv
->hModule
= hModule
;
893 paldrv
->lpDrvProc
= lpDriverProc
;
894 paldrv
->pACMInstList
= NULL
;
896 paldrv
->pNextACMLocalDrv
= NULL
;
897 paldrv
->pPrevACMLocalDrv
= MSACM_pLastACMLocalDriver
;
898 if (MSACM_pLastACMLocalDriver
)
899 MSACM_pLastACMLocalDriver
->pNextACMLocalDrv
= paldrv
;
900 MSACM_pLastACMLocalDriver
= paldrv
;
901 if (!MSACM_pFirstACMLocalDriver
)
902 MSACM_pFirstACMLocalDriver
= paldrv
;
907 /**************************************************************************
908 * MSACM_GetNumberOfModuleRefs [internal]
910 * Returns the number of open drivers which share the same module.
911 * Inspired from implementation in dlls/winmm/driver.c
913 static unsigned MSACM_GetNumberOfModuleRefs(HMODULE hModule
, DRIVERPROC lpDrvProc
, WINE_ACMLOCALDRIVERINST
** found
)
915 PWINE_ACMLOCALDRIVER lpDrv
;
918 if (found
) *found
= NULL
;
919 for (lpDrv
= MSACM_pFirstACMLocalDriver
; lpDrv
; lpDrv
= lpDrv
->pNextACMLocalDrv
)
921 if (lpDrv
->hModule
== hModule
&& lpDrv
->lpDrvProc
== lpDrvProc
)
923 PWINE_ACMLOCALDRIVERINST pInst
= lpDrv
->pACMInstList
;
926 if (found
&& !*found
) *found
= pInst
;
928 pInst
= pInst
->pNextACMInst
;
935 /**************************************************************************
936 * MSACM_RemoveFromList [internal]
938 * Generates all the logic to handle driver closure / deletion
939 * Removes a driver struct to the list of open drivers.
941 static BOOL
MSACM_RemoveFromList(PWINE_ACMLOCALDRIVERINST lpDrv
)
943 PWINE_ACMLOCALDRIVER pDriverBase
= lpDrv
->pLocalDriver
;
944 PWINE_ACMLOCALDRIVERINST pPrevInst
;
946 /* last of this driver in list ? */
947 if (MSACM_GetNumberOfModuleRefs(pDriverBase
->hModule
, pDriverBase
->lpDrvProc
, NULL
) == 1) {
948 MSACM_DRIVER_SendMessage(lpDrv
, DRV_DISABLE
, 0L, 0L);
949 MSACM_DRIVER_SendMessage(lpDrv
, DRV_FREE
, 0L, 0L);
953 if (pDriverBase
->pACMInstList
!= lpDrv
) {
954 pPrevInst
= pDriverBase
->pACMInstList
;
955 while (pPrevInst
&& pPrevInst
->pNextACMInst
!= lpDrv
)
956 pPrevInst
= pPrevInst
->pNextACMInst
;
958 ERR("requested to remove invalid instance %p\n", pPrevInst
);
963 /* first driver instance on list */
964 pDriverBase
->pACMInstList
= lpDrv
->pNextACMInst
;
966 pPrevInst
->pNextACMInst
= lpDrv
->pNextACMInst
;
971 /**************************************************************************
972 * MSACM_AddToList [internal]
974 * Adds a driver struct to the list of open drivers.
975 * Generates all the logic to handle driver creation / open.
977 static BOOL
MSACM_AddToList(PWINE_ACMLOCALDRIVERINST lpNewDrv
, LPARAM lParam2
)
979 PWINE_ACMLOCALDRIVER pDriverBase
= lpNewDrv
->pLocalDriver
;
981 /* first of this driver in list ? */
982 if (MSACM_GetNumberOfModuleRefs(pDriverBase
->hModule
, pDriverBase
->lpDrvProc
, NULL
) == 0) {
983 if (MSACM_DRIVER_SendMessage(lpNewDrv
, DRV_LOAD
, 0L, 0L) != DRV_SUCCESS
) {
984 FIXME("DRV_LOAD failed on driver %p\n", lpNewDrv
);
987 /* returned value is not checked */
988 MSACM_DRIVER_SendMessage(lpNewDrv
, DRV_ENABLE
, 0L, 0L);
991 lpNewDrv
->pNextACMInst
= NULL
;
992 if (pDriverBase
->pACMInstList
== NULL
) {
993 pDriverBase
->pACMInstList
= lpNewDrv
;
995 PWINE_ACMLOCALDRIVERINST lpDrvInst
= pDriverBase
->pACMInstList
;
997 while (lpDrvInst
->pNextACMInst
!= NULL
)
998 lpDrvInst
= lpDrvInst
->pNextACMInst
;
1000 lpDrvInst
->pNextACMInst
= lpNewDrv
;
1003 /* Now just open a new instance of a driver on this module */
1004 lpNewDrv
->dwDriverID
= MSACM_DRIVER_SendMessage(lpNewDrv
, DRV_OPEN
, 0, lParam2
);
1006 if (lpNewDrv
->dwDriverID
== 0) {
1007 FIXME("DRV_OPEN failed on driver %p\n", lpNewDrv
);
1008 MSACM_RemoveFromList(lpNewDrv
);
1014 PWINE_ACMLOCALDRIVERINST
MSACM_OpenLocalDriver(PWINE_ACMLOCALDRIVER paldrv
, LPARAM lParam2
)
1016 PWINE_ACMLOCALDRIVERINST pDrvInst
;
1018 pDrvInst
= HeapAlloc(MSACM_hHeap
, 0, sizeof(WINE_ACMLOCALDRIVERINST
));
1022 pDrvInst
->pLocalDriver
= paldrv
;
1023 pDrvInst
->dwDriverID
= 0;
1024 pDrvInst
->pNextACMInst
= NULL
;
1025 pDrvInst
->bSession
= FALSE
;
1027 /* Win32 installable drivers must support a two phase opening scheme:
1028 * + first open with NULL as lParam2 (session instance),
1029 * + then do a second open with the real non null lParam2)
1031 if (MSACM_GetNumberOfModuleRefs(paldrv
->hModule
, paldrv
->lpDrvProc
, NULL
) == 0 && lParam2
)
1033 PWINE_ACMLOCALDRIVERINST ret
;
1035 if (!MSACM_AddToList(pDrvInst
, 0L))
1037 ERR("load0 failed\n");
1040 ret
= MSACM_OpenLocalDriver(paldrv
, lParam2
);
1043 ERR("load1 failed\n");
1044 /* If MSACM_CloseLocalDriver returns TRUE,
1045 * then pDrvInst has been freed
1047 if (!MSACM_CloseLocalDriver(pDrvInst
))
1052 pDrvInst
->bSession
= TRUE
;
1056 if (!MSACM_AddToList(pDrvInst
, lParam2
))
1058 ERR("load failed\n");
1062 TRACE("=> %p\n", pDrvInst
);
1065 HeapFree(MSACM_hHeap
, 0, pDrvInst
);
1069 LRESULT
MSACM_CloseLocalDriver(PWINE_ACMLOCALDRIVERINST paldrv
)
1071 if (MSACM_RemoveFromList(paldrv
)) {
1072 PWINE_ACMLOCALDRIVERINST lpDrv0
;
1073 PWINE_ACMLOCALDRIVER pDriverBase
= paldrv
->pLocalDriver
;
1075 MSACM_DRIVER_SendMessage(paldrv
, DRV_CLOSE
, 0, 0);
1076 paldrv
->dwDriverID
= 0;
1078 if (paldrv
->bSession
)
1079 ERR("should not directly close session instance (%p)\n", paldrv
);
1081 /* if driver has an opened session instance, we have to close it too */
1082 if (MSACM_GetNumberOfModuleRefs(pDriverBase
->hModule
, pDriverBase
->lpDrvProc
, &lpDrv0
) == 1 &&
1085 MSACM_DRIVER_SendMessage(lpDrv0
, DRV_CLOSE
, 0L, 0L);
1086 lpDrv0
->dwDriverID
= 0;
1087 MSACM_RemoveFromList(lpDrv0
);
1088 HeapFree(GetProcessHeap(), 0, lpDrv0
);
1091 HeapFree(MSACM_hHeap
, 0, paldrv
);
1094 ERR("unable to close driver instance\n");