* Sync up to trunk head (r64894).
[reactos.git] / dll / win32 / msacm32 / internal.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4 * MSACM32 library
5 *
6 * Copyright 1998 Patrik Stridvall
7 * 1999 Eric Pouech
8 *
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.
13 *
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.
18 *
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
22 */
23
24 #include "wineacm.h"
25
26 #include <winreg.h>
27
28 /**********************************************************************/
29
30 HANDLE MSACM_hHeap = NULL;
31 PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
32 static PWINE_ACMDRIVERID MSACM_pLastACMDriverID;
33
34 static DWORD MSACM_suspendBroadcastCount = 0;
35 static BOOL MSACM_pendingBroadcast = FALSE;
36 static PWINE_ACMNOTIFYWND MSACM_pFirstACMNotifyWnd = NULL;
37 static PWINE_ACMNOTIFYWND MSACM_pLastACMNotifyWnd = NULL;
38
39 static void MSACM_ReorderDriversByPriority(void);
40
41 /***********************************************************************
42 * MSACM_RegisterDriverFromRegistry()
43 */
44 PWINE_ACMDRIVERID MSACM_RegisterDriverFromRegistry(LPCWSTR pszRegEntry)
45 {
46 static const WCHAR msacmW[] = {'M','S','A','C','M','.'};
47 static const WCHAR drvkey[] = {'S','o','f','t','w','a','r','e','\\',
48 'M','i','c','r','o','s','o','f','t','\\',
49 'W','i','n','d','o','w','s',' ','N','T','\\',
50 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
51 'D','r','i','v','e','r','s','3','2','\0'};
52 WCHAR buf[2048];
53 DWORD bufLen, lRet;
54 HKEY hKey;
55 PWINE_ACMDRIVERID padid = NULL;
56
57 /* The requested registry entry must have the format msacm.XXXXX in order to
58 be recognized in any future sessions of msacm
59 */
60 if (0 == strncmpiW(pszRegEntry, msacmW, sizeof(msacmW)/sizeof(WCHAR))) {
61 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, drvkey, 0, KEY_QUERY_VALUE, &hKey);
62 if (lRet != ERROR_SUCCESS) {
63 WARN("unable to open registry key - 0x%08x\n", lRet);
64 } else {
65 bufLen = sizeof(buf);
66 lRet = RegQueryValueExW(hKey, pszRegEntry, NULL, NULL, (LPBYTE)buf, &bufLen);
67 if (lRet != ERROR_SUCCESS) {
68 WARN("unable to query requested subkey %s - 0x%08x\n", debugstr_w(pszRegEntry), lRet);
69 } else {
70 MSACM_RegisterDriver(pszRegEntry, buf, 0);
71 }
72 RegCloseKey( hKey );
73 }
74 }
75 return padid;
76 }
77
78 #if 0
79 /***********************************************************************
80 * MSACM_DumpCache
81 */
82 static void MSACM_DumpCache(PWINE_ACMDRIVERID padid)
83 {
84 unsigned i;
85
86 TRACE("cFilterTags=%lu cFormatTags=%lu fdwSupport=%08lx\n",
87 padid->cFilterTags, padid->cFormatTags, padid->fdwSupport);
88 for (i = 0; i < padid->cache->cFormatTags; i++) {
89 TRACE("\tdwFormatTag=%lu cbwfx=%lu\n",
90 padid->aFormatTag[i].dwFormatTag, padid->aFormatTag[i].cbwfx);
91 }
92 }
93 #endif
94
95 /***********************************************************************
96 * MSACM_FindFormatTagInCache [internal]
97 *
98 * Returns TRUE is the format tag fmtTag is present in the cache.
99 * If so, idx is set to its index.
100 */
101 BOOL MSACM_FindFormatTagInCache(const WINE_ACMDRIVERID* padid, DWORD fmtTag, LPDWORD idx)
102 {
103 unsigned i;
104
105 for (i = 0; i < padid->cFormatTags; i++) {
106 if (padid->aFormatTag[i].dwFormatTag == fmtTag) {
107 if (idx) *idx = i;
108 return TRUE;
109 }
110 }
111 return FALSE;
112 }
113
114 /***********************************************************************
115 * MSACM_FillCache
116 */
117 static BOOL MSACM_FillCache(PWINE_ACMDRIVERID padid)
118 {
119 HACMDRIVER had = 0;
120 unsigned int ntag;
121 ACMDRIVERDETAILSW add;
122 ACMFORMATTAGDETAILSW aftd;
123
124 if (acmDriverOpen(&had, (HACMDRIVERID)padid, 0) != 0)
125 return FALSE;
126
127 padid->aFormatTag = NULL;
128 add.cbStruct = sizeof(add);
129 if (MSACM_Message(had, ACMDM_DRIVER_DETAILS, (LPARAM)&add, 0))
130 goto errCleanUp;
131
132 if (add.cFormatTags > 0) {
133 padid->aFormatTag = HeapAlloc(MSACM_hHeap, HEAP_ZERO_MEMORY,
134 add.cFormatTags * sizeof(padid->aFormatTag[0]));
135 if (!padid->aFormatTag) goto errCleanUp;
136 }
137
138 padid->cFormatTags = add.cFormatTags;
139 padid->cFilterTags = add.cFilterTags;
140 padid->fdwSupport = add.fdwSupport;
141
142 aftd.cbStruct = sizeof(aftd);
143
144 for (ntag = 0; ntag < add.cFormatTags; ntag++) {
145 aftd.dwFormatTagIndex = ntag;
146 if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)&aftd, ACM_FORMATTAGDETAILSF_INDEX)) {
147 TRACE("IIOs (%s)\n", debugstr_w(padid->pszDriverAlias));
148 goto errCleanUp;
149 }
150 padid->aFormatTag[ntag].dwFormatTag = aftd.dwFormatTag;
151 padid->aFormatTag[ntag].cbwfx = aftd.cbFormatSize;
152 }
153
154 acmDriverClose(had, 0);
155
156 return TRUE;
157
158 errCleanUp:
159 if (had) acmDriverClose(had, 0);
160 HeapFree(MSACM_hHeap, 0, padid->aFormatTag);
161 padid->aFormatTag = NULL;
162 return FALSE;
163 }
164
165 /***********************************************************************
166 * MSACM_GetRegistryKey
167 */
168 static LPWSTR MSACM_GetRegistryKey(const WINE_ACMDRIVERID* padid)
169 {
170 static const WCHAR baseKey[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
171 'A','u','d','i','o','C','o','m','p','r','e','s','s','i','o','n','M','a','n','a','g','e','r','\\',
172 'D','r','i','v','e','r','C','a','c','h','e','\\','\0'};
173 LPWSTR ret;
174 int len;
175
176 if (!padid->pszDriverAlias) {
177 ERR("No alias needed for registry entry\n");
178 return NULL;
179 }
180 len = strlenW(baseKey);
181 ret = HeapAlloc(MSACM_hHeap, 0, (len + strlenW(padid->pszDriverAlias) + 1) * sizeof(WCHAR));
182 if (!ret) return NULL;
183
184 strcpyW(ret, baseKey);
185 strcpyW(ret + len, padid->pszDriverAlias);
186 CharLowerW(ret + len);
187 return ret;
188 }
189
190 /***********************************************************************
191 * MSACM_ReadCache
192 */
193 static BOOL MSACM_ReadCache(PWINE_ACMDRIVERID padid)
194 {
195 LPWSTR key = MSACM_GetRegistryKey(padid);
196 HKEY hKey;
197 DWORD type, size;
198
199 if (!key) return FALSE;
200
201 padid->aFormatTag = NULL;
202
203 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, key, &hKey))
204 goto errCleanUp;
205
206 size = sizeof(padid->cFormatTags);
207 if (RegQueryValueExA(hKey, "cFormatTags", 0, &type, (void*)&padid->cFormatTags, &size))
208 goto errCleanUp;
209 size = sizeof(padid->cFilterTags);
210 if (RegQueryValueExA(hKey, "cFilterTags", 0, &type, (void*)&padid->cFilterTags, &size))
211 goto errCleanUp;
212 size = sizeof(padid->fdwSupport);
213 if (RegQueryValueExA(hKey, "fdwSupport", 0, &type, (void*)&padid->fdwSupport, &size))
214 goto errCleanUp;
215
216 if (padid->cFormatTags > 0) {
217 size = padid->cFormatTags * sizeof(padid->aFormatTag[0]);
218 padid->aFormatTag = HeapAlloc(MSACM_hHeap, HEAP_ZERO_MEMORY, size);
219 if (!padid->aFormatTag) goto errCleanUp;
220 if (RegQueryValueExA(hKey, "aFormatTagCache", 0, &type, (void*)padid->aFormatTag, &size))
221 goto errCleanUp;
222 }
223 HeapFree(MSACM_hHeap, 0, key);
224 return TRUE;
225
226 errCleanUp:
227 HeapFree(MSACM_hHeap, 0, key);
228 HeapFree(MSACM_hHeap, 0, padid->aFormatTag);
229 padid->aFormatTag = NULL;
230 RegCloseKey(hKey);
231 return FALSE;
232 }
233
234 /***********************************************************************
235 * MSACM_WriteCache
236 */
237 static BOOL MSACM_WriteCache(const WINE_ACMDRIVERID *padid)
238 {
239 LPWSTR key = MSACM_GetRegistryKey(padid);
240 HKEY hKey;
241
242 if (!key) return FALSE;
243
244 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, key, &hKey))
245 goto errCleanUp;
246
247 if (RegSetValueExA(hKey, "cFormatTags", 0, REG_DWORD, (const void*)&padid->cFormatTags, sizeof(DWORD)))
248 goto errCleanUp;
249 if (RegSetValueExA(hKey, "cFilterTags", 0, REG_DWORD, (const void*)&padid->cFilterTags, sizeof(DWORD)))
250 goto errCleanUp;
251 if (RegSetValueExA(hKey, "fdwSupport", 0, REG_DWORD, (const void*)&padid->fdwSupport, sizeof(DWORD)))
252 goto errCleanUp;
253 if (RegSetValueExA(hKey, "aFormatTagCache", 0, REG_BINARY,
254 (void*)padid->aFormatTag,
255 padid->cFormatTags * sizeof(padid->aFormatTag[0])))
256 goto errCleanUp;
257 HeapFree(MSACM_hHeap, 0, key);
258 return TRUE;
259
260 errCleanUp:
261 HeapFree(MSACM_hHeap, 0, key);
262 return FALSE;
263 }
264
265 /***********************************************************************
266 * MSACM_RegisterDriver()
267 */
268 PWINE_ACMDRIVERID MSACM_RegisterDriver(LPCWSTR pszDriverAlias, LPCWSTR pszFileName,
269 PWINE_ACMLOCALDRIVER pLocalDriver)
270 {
271 PWINE_ACMDRIVERID padid;
272
273 TRACE("(%s, %s, %p)\n",
274 debugstr_w(pszDriverAlias), debugstr_w(pszFileName), pLocalDriver);
275
276 padid = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
277 if (!padid)
278 return NULL;
279 padid->obj.dwType = WINE_ACMOBJ_DRIVERID;
280 padid->obj.pACMDriverID = padid;
281 padid->pszDriverAlias = NULL;
282 if (pszDriverAlias)
283 {
284 padid->pszDriverAlias = HeapAlloc( MSACM_hHeap, 0, (strlenW(pszDriverAlias)+1) * sizeof(WCHAR) );
285 if (!padid->pszDriverAlias) {
286 HeapFree(MSACM_hHeap, 0, padid);
287 return NULL;
288 }
289 strcpyW( padid->pszDriverAlias, pszDriverAlias );
290 }
291 padid->pszFileName = NULL;
292 if (pszFileName)
293 {
294 padid->pszFileName = HeapAlloc( MSACM_hHeap, 0, (strlenW(pszFileName)+1) * sizeof(WCHAR) );
295 if (!padid->pszFileName) {
296 HeapFree(MSACM_hHeap, 0, padid->pszDriverAlias);
297 HeapFree(MSACM_hHeap, 0, padid);
298 return NULL;
299 }
300 strcpyW( padid->pszFileName, pszFileName );
301 }
302 padid->pLocalDriver = pLocalDriver;
303
304 padid->pACMDriverList = NULL;
305
306 if (pLocalDriver) {
307 padid->pPrevACMDriverID = NULL;
308 padid->pNextACMDriverID = MSACM_pFirstACMDriverID;
309 if (MSACM_pFirstACMDriverID)
310 MSACM_pFirstACMDriverID->pPrevACMDriverID = padid;
311 MSACM_pFirstACMDriverID = padid;
312 if (!MSACM_pLastACMDriverID)
313 MSACM_pLastACMDriverID = padid;
314 } else {
315 padid->pNextACMDriverID = NULL;
316 padid->pPrevACMDriverID = MSACM_pLastACMDriverID;
317 if (MSACM_pLastACMDriverID)
318 MSACM_pLastACMDriverID->pNextACMDriverID = padid;
319 MSACM_pLastACMDriverID = padid;
320 if (!MSACM_pFirstACMDriverID)
321 MSACM_pFirstACMDriverID = padid;
322 }
323 /* disable the driver if we cannot load the cache */
324 if ((!padid->pszDriverAlias || !MSACM_ReadCache(padid)) && !MSACM_FillCache(padid)) {
325 WARN("Couldn't load cache for ACM driver (%s)\n", debugstr_w(pszFileName));
326 MSACM_UnregisterDriver(padid);
327 return NULL;
328 }
329
330 if (pLocalDriver) padid->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_LOCAL;
331 return padid;
332 }
333
334 /***********************************************************************
335 * MSACM_RegisterAllDrivers()
336 */
337 void MSACM_RegisterAllDrivers(void)
338 {
339 static const WCHAR msacm32[] = {'m','s','a','c','m','3','2','.','d','l','l','\0'};
340 static const WCHAR msacmW[] = {'M','S','A','C','M','.'};
341 static const WCHAR drv32[] = {'d','r','i','v','e','r','s','3','2','\0'};
342 static const WCHAR sys[] = {'s','y','s','t','e','m','.','i','n','i','\0'};
343 static const WCHAR drvkey[] = {'S','o','f','t','w','a','r','e','\\',
344 'M','i','c','r','o','s','o','f','t','\\',
345 'W','i','n','d','o','w','s',' ','N','T','\\',
346 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
347 'D','r','i','v','e','r','s','3','2','\0'};
348 DWORD i, cnt, bufLen, lRet, type;
349 WCHAR buf[2048], valname[64], *name, *s;
350 FILETIME lastWrite;
351 HKEY hKey;
352
353 /* FIXME: What if the user edits system.ini while the program is running?
354 * Does Windows handle that? */
355 if (MSACM_pFirstACMDriverID) return;
356
357 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, drvkey, 0, KEY_QUERY_VALUE, &hKey);
358 if (lRet == ERROR_SUCCESS) {
359 RegQueryInfoKeyW( hKey, 0, 0, 0, &cnt, 0, 0, 0, 0, 0, 0, 0);
360 for (i = 0; i < cnt; i++) {
361 bufLen = sizeof(buf) / sizeof(buf[0]);
362 lRet = RegEnumKeyExW(hKey, i, buf, &bufLen, 0, 0, 0, &lastWrite);
363 if (lRet != ERROR_SUCCESS) continue;
364 if (strncmpiW(buf, msacmW, sizeof(msacmW)/sizeof(msacmW[0]))) continue;
365 if (!(name = strchrW(buf, '='))) continue;
366 *name = 0;
367 MSACM_RegisterDriver(buf, name + 1, 0);
368 }
369 i = 0;
370 cnt = sizeof(valname) / sizeof(*valname);
371 bufLen = sizeof(buf);
372 while(RegEnumValueW(hKey, i, valname, &cnt, 0,
373 &type, (BYTE*)buf, &bufLen) == ERROR_SUCCESS){
374 if(!strncmpiW(valname, msacmW, sizeof(msacmW) / sizeof(*msacmW)))
375 MSACM_RegisterDriver(valname, buf, 0);
376 ++i;
377 }
378 RegCloseKey( hKey );
379 }
380
381 if (GetPrivateProfileSectionW(drv32, buf, sizeof(buf)/sizeof(buf[0]), sys))
382 {
383 for(s = buf; *s; s += strlenW(s) + 1)
384 {
385 if (strncmpiW(s, msacmW, sizeof(msacmW)/sizeof(msacmW[0]))) continue;
386 if (!(name = strchrW(s, '='))) continue;
387 *name = 0;
388 MSACM_RegisterDriver(s, name + 1, 0);
389 *name = '=';
390 }
391 }
392 MSACM_ReorderDriversByPriority();
393 MSACM_RegisterDriver(msacm32, msacm32, 0);
394 }
395
396 /***********************************************************************
397 * MSACM_RegisterNotificationWindow()
398 */
399 PWINE_ACMNOTIFYWND MSACM_RegisterNotificationWindow(HWND hNotifyWnd, DWORD dwNotifyMsg)
400 {
401 PWINE_ACMNOTIFYWND panwnd;
402
403 TRACE("(%p,0x%08x)\n", hNotifyWnd, dwNotifyMsg);
404
405 panwnd = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMNOTIFYWND));
406 panwnd->obj.dwType = WINE_ACMOBJ_NOTIFYWND;
407 panwnd->obj.pACMDriverID = 0;
408 panwnd->hNotifyWnd = hNotifyWnd;
409 panwnd->dwNotifyMsg = dwNotifyMsg;
410 panwnd->fdwSupport = 0;
411
412 panwnd->pNextACMNotifyWnd = NULL;
413 panwnd->pPrevACMNotifyWnd = MSACM_pLastACMNotifyWnd;
414 if (MSACM_pLastACMNotifyWnd)
415 MSACM_pLastACMNotifyWnd->pNextACMNotifyWnd = panwnd;
416 MSACM_pLastACMNotifyWnd = panwnd;
417 if (!MSACM_pFirstACMNotifyWnd)
418 MSACM_pFirstACMNotifyWnd = panwnd;
419
420 return panwnd;
421 }
422
423 /***********************************************************************
424 * MSACM_BroadcastNotification()
425 */
426 void MSACM_BroadcastNotification(void)
427 {
428 if (MSACM_suspendBroadcastCount <= 0) {
429 PWINE_ACMNOTIFYWND panwnd;
430
431 for (panwnd = MSACM_pFirstACMNotifyWnd; panwnd; panwnd = panwnd->pNextACMNotifyWnd)
432 if (!(panwnd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED))
433 SendMessageW(panwnd->hNotifyWnd, panwnd->dwNotifyMsg, 0, 0);
434 } else {
435 MSACM_pendingBroadcast = TRUE;
436 }
437 }
438
439 /***********************************************************************
440 * MSACM_DisableNotifications()
441 */
442 void MSACM_DisableNotifications(void)
443 {
444 MSACM_suspendBroadcastCount++;
445 }
446
447 /***********************************************************************
448 * MSACM_EnableNotifications()
449 */
450 void MSACM_EnableNotifications(void)
451 {
452 if (MSACM_suspendBroadcastCount > 0) {
453 MSACM_suspendBroadcastCount--;
454 if (MSACM_suspendBroadcastCount == 0 && MSACM_pendingBroadcast) {
455 MSACM_pendingBroadcast = FALSE;
456 MSACM_BroadcastNotification();
457 }
458 }
459 }
460
461 /***********************************************************************
462 * MSACM_UnRegisterNotificationWindow()
463 */
464 PWINE_ACMNOTIFYWND MSACM_UnRegisterNotificationWindow(const WINE_ACMNOTIFYWND *panwnd)
465 {
466 PWINE_ACMNOTIFYWND p;
467
468 for (p = MSACM_pFirstACMNotifyWnd; p; p = p->pNextACMNotifyWnd) {
469 if (p == panwnd) {
470 PWINE_ACMNOTIFYWND pNext = p->pNextACMNotifyWnd;
471
472 if (p->pPrevACMNotifyWnd) p->pPrevACMNotifyWnd->pNextACMNotifyWnd = p->pNextACMNotifyWnd;
473 if (p->pNextACMNotifyWnd) p->pNextACMNotifyWnd->pPrevACMNotifyWnd = p->pPrevACMNotifyWnd;
474 if (MSACM_pFirstACMNotifyWnd == p) MSACM_pFirstACMNotifyWnd = p->pNextACMNotifyWnd;
475 if (MSACM_pLastACMNotifyWnd == p) MSACM_pLastACMNotifyWnd = p->pPrevACMNotifyWnd;
476 HeapFree(MSACM_hHeap, 0, p);
477
478 return pNext;
479 }
480 }
481 return NULL;
482 }
483
484 /***********************************************************************
485 * MSACM_RePositionDriver()
486 */
487 void MSACM_RePositionDriver(PWINE_ACMDRIVERID padid, DWORD dwPriority)
488 {
489 PWINE_ACMDRIVERID pTargetPosition = NULL;
490
491 /* Remove selected driver from linked list */
492 if (MSACM_pFirstACMDriverID == padid) {
493 MSACM_pFirstACMDriverID = padid->pNextACMDriverID;
494 }
495 if (MSACM_pLastACMDriverID == padid) {
496 MSACM_pLastACMDriverID = padid->pPrevACMDriverID;
497 }
498 if (padid->pPrevACMDriverID != NULL) {
499 padid->pPrevACMDriverID->pNextACMDriverID = padid->pNextACMDriverID;
500 }
501 if (padid->pNextACMDriverID != NULL) {
502 padid->pNextACMDriverID->pPrevACMDriverID = padid->pPrevACMDriverID;
503 }
504
505 /* Look up position where selected driver should be */
506 if (dwPriority == 1) {
507 pTargetPosition = padid->pPrevACMDriverID;
508 while (pTargetPosition->pPrevACMDriverID != NULL &&
509 !(pTargetPosition->pPrevACMDriverID->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL)) {
510 pTargetPosition = pTargetPosition->pPrevACMDriverID;
511 }
512 } else if (dwPriority == -1) {
513 pTargetPosition = padid->pNextACMDriverID;
514 while (pTargetPosition->pNextACMDriverID != NULL) {
515 pTargetPosition = pTargetPosition->pNextACMDriverID;
516 }
517 }
518
519 /* Place selected driver in selected position */
520 padid->pPrevACMDriverID = pTargetPosition->pPrevACMDriverID;
521 padid->pNextACMDriverID = pTargetPosition;
522 if (padid->pPrevACMDriverID != NULL) {
523 padid->pPrevACMDriverID->pNextACMDriverID = padid;
524 } else {
525 MSACM_pFirstACMDriverID = padid;
526 }
527 if (padid->pNextACMDriverID != NULL) {
528 padid->pNextACMDriverID->pPrevACMDriverID = padid;
529 } else {
530 MSACM_pLastACMDriverID = padid;
531 }
532 }
533
534 /***********************************************************************
535 * MSACM_ReorderDriversByPriority()
536 * Reorders all drivers based on the priority list indicated by the registry key:
537 * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
538 */
539 static void MSACM_ReorderDriversByPriority(void)
540 {
541 PWINE_ACMDRIVERID padid;
542 unsigned int iNumDrivers;
543 PWINE_ACMDRIVERID * driverList = NULL;
544 HKEY hPriorityKey = NULL;
545
546 TRACE("\n");
547
548 /* Count drivers && alloc corresponding memory for list */
549 iNumDrivers = 0;
550 for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) iNumDrivers++;
551 if (iNumDrivers > 1)
552 {
553 LONG lError;
554 static const WCHAR basePriorityKey[] = {
555 'S','o','f','t','w','a','r','e','\\',
556 'M','i','c','r','o','s','o','f','t','\\',
557 'M','u','l','t','i','m','e','d','i','a','\\',
558 'A','u','d','i','o',' ','C','o','m','p','r','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
559 'P','r','i','o','r','i','t','y',' ','v','4','.','0','0','\0'
560 };
561 unsigned int i;
562 LONG lBufferLength;
563 WCHAR szBuffer[256];
564
565 driverList = HeapAlloc(MSACM_hHeap, 0, iNumDrivers * sizeof(PWINE_ACMDRIVERID));
566 if (!driverList)
567 {
568 ERR("out of memory\n");
569 goto errCleanUp;
570 }
571
572 lError = RegOpenKeyW(HKEY_CURRENT_USER, basePriorityKey, &hPriorityKey);
573 if (lError != ERROR_SUCCESS) {
574 TRACE("RegOpenKeyW failed, possibly key does not exist yet\n");
575 hPriorityKey = NULL;
576 goto errCleanUp;
577 }
578
579 /* Copy drivers into list to simplify linked list modification */
580 for (i = 0, padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID, i++)
581 {
582 driverList[i] = padid;
583 }
584
585 /* Query each of the priorities in turn. Alias key is in lowercase.
586 The general form of the priority record is the following:
587 "PriorityN" --> "1, msacm.driveralias"
588 where N is an integer, and the value is a string of the driver
589 alias, prefixed by "1, " for an enabled driver, or "0, " for a
590 disabled driver.
591 */
592 for (i = 0; i < iNumDrivers; i++)
593 {
594 static const WCHAR priorityTmpl[] = {'P','r','i','o','r','i','t','y','%','l','d','\0'};
595 WCHAR szSubKey[17];
596 unsigned int iTargetPosition;
597 unsigned int iCurrentPosition;
598 WCHAR * pAlias;
599 static const WCHAR sPrefix[] = {'m','s','a','c','m','.','\0'};
600
601 /* Build expected entry name */
602 snprintfW(szSubKey, 17, priorityTmpl, i + 1);
603 lBufferLength = sizeof(szBuffer);
604 lError = RegQueryValueExW(hPriorityKey, szSubKey, NULL, NULL, (LPBYTE)szBuffer, (LPDWORD)&lBufferLength);
605 if (lError != ERROR_SUCCESS) continue;
606
607 /* Recovered driver alias should be at this position */
608 iTargetPosition = i;
609
610 /* Locate driver alias in driver list */
611 pAlias = strstrW(szBuffer, sPrefix);
612 if (pAlias == NULL) continue;
613
614 for (iCurrentPosition = 0; iCurrentPosition < iNumDrivers; iCurrentPosition++) {
615 if (strcmpiW(driverList[iCurrentPosition]->pszDriverAlias, pAlias) == 0)
616 break;
617 }
618 if (iCurrentPosition < iNumDrivers && iTargetPosition != iCurrentPosition) {
619 padid = driverList[iTargetPosition];
620 driverList[iTargetPosition] = driverList[iCurrentPosition];
621 driverList[iCurrentPosition] = padid;
622
623 /* Locate enabled status */
624 if (szBuffer[0] == '1') {
625 driverList[iTargetPosition]->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED;
626 } else if (szBuffer[0] == '0') {
627 driverList[iTargetPosition]->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
628 }
629 }
630 }
631
632 /* Re-assign pointers so that linked list traverses the ordered array */
633 for (i = 0; i < iNumDrivers; i++) {
634 driverList[i]->pPrevACMDriverID = (i > 0) ? driverList[i - 1] : NULL;
635 driverList[i]->pNextACMDriverID = (i < iNumDrivers - 1) ? driverList[i + 1] : NULL;
636 }
637 MSACM_pFirstACMDriverID = driverList[0];
638 MSACM_pLastACMDriverID = driverList[iNumDrivers - 1];
639 }
640
641 errCleanUp:
642 if (hPriorityKey != NULL) RegCloseKey(hPriorityKey);
643 HeapFree(MSACM_hHeap, 0, driverList);
644 }
645
646 /***********************************************************************
647 * MSACM_WriteCurrentPriorities()
648 * Writes out current order of driver priorities to registry key:
649 * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00
650 */
651 void MSACM_WriteCurrentPriorities(void)
652 {
653 LONG lError;
654 HKEY hPriorityKey;
655 static const WCHAR basePriorityKey[] = {
656 'S','o','f','t','w','a','r','e','\\',
657 'M','i','c','r','o','s','o','f','t','\\',
658 'M','u','l','t','i','m','e','d','i','a','\\',
659 'A','u','d','i','o',' ','C','o','m','p','r','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
660 'P','r','i','o','r','i','t','y',' ','v','4','.','0','0','\0'
661 };
662 PWINE_ACMDRIVERID padid;
663 DWORD dwPriorityCounter;
664 static const WCHAR priorityTmpl[] = {'P','r','i','o','r','i','t','y','%','l','d','\0'};
665 static const WCHAR valueTmpl[] = {'%','c',',',' ','%','s','\0'};
666 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'};
667 WCHAR szSubKey[17];
668 WCHAR szBuffer[256];
669
670 /* Delete ACM priority key and create it anew */
671 lError = RegDeleteKeyW(HKEY_CURRENT_USER, basePriorityKey);
672 if (lError != ERROR_SUCCESS && lError != ERROR_FILE_NOT_FOUND) {
673 ERR("unable to remove current key %s (0x%08x) - priority changes won't persist past application end.\n",
674 debugstr_w(basePriorityKey), lError);
675 return;
676 }
677 lError = RegCreateKeyW(HKEY_CURRENT_USER, basePriorityKey, &hPriorityKey);
678 if (lError != ERROR_SUCCESS) {
679 ERR("unable to create key %s (0x%08x) - priority changes won't persist past application end.\n",
680 debugstr_w(basePriorityKey), lError);
681 return;
682 }
683
684 /* Write current list of priorities */
685 for (dwPriorityCounter = 0, padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
686 if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL) continue;
687 if (padid->pszDriverAlias == NULL) continue; /* internal PCM converter is last */
688
689 /* Build required value name */
690 dwPriorityCounter++;
691 snprintfW(szSubKey, 17, priorityTmpl, dwPriorityCounter);
692
693 /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */
694 snprintfW(szBuffer, 256, valueTmpl, (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ? '0' : '1', padid->pszDriverAlias);
695 strlwrW(szBuffer);
696
697 lError = RegSetValueExW(hPriorityKey, szSubKey, 0, REG_SZ, (BYTE *)szBuffer, (strlenW(szBuffer) + 1) * sizeof(WCHAR));
698 if (lError != ERROR_SUCCESS) {
699 ERR("unable to write value for %s under key %s (0x%08x)\n",
700 debugstr_w(padid->pszDriverAlias), debugstr_w(basePriorityKey), lError);
701 }
702 }
703
704 /* Build required value name */
705 dwPriorityCounter++;
706 snprintfW(szSubKey, 17, priorityTmpl, dwPriorityCounter);
707
708 /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */
709 snprintfW(szBuffer, 256, valueTmpl, '1', converterAlias);
710
711 lError = RegSetValueExW(hPriorityKey, szSubKey, 0, REG_SZ, (BYTE *)szBuffer, (strlenW(szBuffer) + 1) * sizeof(WCHAR));
712 if (lError != ERROR_SUCCESS) {
713 ERR("unable to write value for %s under key %s (0x%08x)\n",
714 debugstr_w(converterAlias), debugstr_w(basePriorityKey), lError);
715 }
716 RegCloseKey(hPriorityKey);
717 }
718
719 static PWINE_ACMLOCALDRIVER MSACM_pFirstACMLocalDriver;
720 static PWINE_ACMLOCALDRIVER MSACM_pLastACMLocalDriver;
721
722 static PWINE_ACMLOCALDRIVER MSACM_UnregisterLocalDriver(PWINE_ACMLOCALDRIVER paldrv)
723 {
724 PWINE_ACMLOCALDRIVER pNextACMLocalDriver;
725
726 if (paldrv->pACMInstList) {
727 ERR("local driver instances still present after closing all drivers - memory leak\n");
728 return NULL;
729 }
730
731 if (paldrv == MSACM_pFirstACMLocalDriver)
732 MSACM_pFirstACMLocalDriver = paldrv->pNextACMLocalDrv;
733 if (paldrv == MSACM_pLastACMLocalDriver)
734 MSACM_pLastACMLocalDriver = paldrv->pPrevACMLocalDrv;
735
736 if (paldrv->pPrevACMLocalDrv)
737 paldrv->pPrevACMLocalDrv->pNextACMLocalDrv = paldrv->pNextACMLocalDrv;
738 if (paldrv->pNextACMLocalDrv)
739 paldrv->pNextACMLocalDrv->pPrevACMLocalDrv = paldrv->pPrevACMLocalDrv;
740
741 pNextACMLocalDriver = paldrv->pNextACMLocalDrv;
742
743 HeapFree(MSACM_hHeap, 0, paldrv);
744
745 return pNextACMLocalDriver;
746 }
747
748 /***********************************************************************
749 * MSACM_UnregisterDriver()
750 */
751 PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
752 {
753 PWINE_ACMDRIVERID pNextACMDriverID;
754
755 while (p->pACMDriverList)
756 acmDriverClose((HACMDRIVER) p->pACMDriverList, 0);
757
758 HeapFree(MSACM_hHeap, 0, p->pszDriverAlias);
759 HeapFree(MSACM_hHeap, 0, p->pszFileName);
760 HeapFree(MSACM_hHeap, 0, p->aFormatTag);
761
762 if (p == MSACM_pFirstACMDriverID)
763 MSACM_pFirstACMDriverID = p->pNextACMDriverID;
764 if (p == MSACM_pLastACMDriverID)
765 MSACM_pLastACMDriverID = p->pPrevACMDriverID;
766
767 if (p->pPrevACMDriverID)
768 p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
769 if (p->pNextACMDriverID)
770 p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID;
771
772 pNextACMDriverID = p->pNextACMDriverID;
773
774 if (p->pLocalDriver) MSACM_UnregisterLocalDriver(p->pLocalDriver);
775 HeapFree(MSACM_hHeap, 0, p);
776
777 return pNextACMDriverID;
778 }
779
780 /***********************************************************************
781 * MSACM_UnregisterAllDrivers()
782 */
783 void MSACM_UnregisterAllDrivers(void)
784 {
785 PWINE_ACMNOTIFYWND panwnd = MSACM_pFirstACMNotifyWnd;
786 PWINE_ACMDRIVERID p = MSACM_pFirstACMDriverID;
787
788 while (p) {
789 MSACM_WriteCache(p);
790 p = MSACM_UnregisterDriver(p);
791 }
792
793 while (panwnd) {
794 panwnd = MSACM_UnRegisterNotificationWindow(panwnd);
795 }
796 }
797
798 /***********************************************************************
799 * MSACM_GetObj()
800 */
801 PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj, DWORD type)
802 {
803 PWINE_ACMOBJ pao = (PWINE_ACMOBJ)hObj;
804
805 if (pao == NULL || IsBadReadPtr(pao, sizeof(WINE_ACMOBJ)) ||
806 ((type != WINE_ACMOBJ_DONTCARE) && (type != pao->dwType)))
807 return NULL;
808 return pao;
809 }
810
811 /***********************************************************************
812 * MSACM_GetDriverID()
813 */
814 PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID)
815 {
816 return (PWINE_ACMDRIVERID)MSACM_GetObj((HACMOBJ)hDriverID, WINE_ACMOBJ_DRIVERID);
817 }
818
819 /***********************************************************************
820 * MSACM_GetDriver()
821 */
822 PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver)
823 {
824 return (PWINE_ACMDRIVER)MSACM_GetObj((HACMOBJ)hDriver, WINE_ACMOBJ_DRIVER);
825 }
826
827 /***********************************************************************
828 * MSACM_GetNotifyWnd()
829 */
830 PWINE_ACMNOTIFYWND MSACM_GetNotifyWnd(HACMDRIVERID hDriver)
831 {
832 return (PWINE_ACMNOTIFYWND)MSACM_GetObj((HACMOBJ)hDriver, WINE_ACMOBJ_NOTIFYWND);
833 }
834
835 /***********************************************************************
836 * MSACM_GetLocalDriver()
837 */
838 /*
839 PWINE_ACMLOCALDRIVER MSACM_GetLocalDriver(HACMDRIVER hDriver)
840 {
841 return (PWINE_ACMLOCALDRIVER)MSACM_GetObj((HACMOBJ)hDriver, WINE_ACMOBJ_LOCALDRIVER);
842 }
843 */
844 #define MSACM_DRIVER_SendMessage(PDRVRINST, msg, lParam1, lParam2) \
845 (PDRVRINST)->pLocalDriver->lpDrvProc((PDRVRINST)->dwDriverID, (HDRVR)(PDRVRINST), msg, lParam1, lParam2)
846
847 /***********************************************************************
848 * MSACM_Message()
849 */
850 MMRESULT MSACM_Message(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
851 {
852 PWINE_ACMDRIVER pad = MSACM_GetDriver(had);
853
854 if (!pad) return MMSYSERR_INVALHANDLE;
855 if (pad->hDrvr) return SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2);
856 if (pad->pLocalDrvrInst) return MSACM_DRIVER_SendMessage(pad->pLocalDrvrInst, uMsg, lParam1, lParam2);
857
858 return MMSYSERR_INVALHANDLE;
859 }
860
861 PWINE_ACMLOCALDRIVER MSACM_RegisterLocalDriver(HMODULE hModule, DRIVERPROC lpDriverProc)
862 {
863 PWINE_ACMLOCALDRIVER paldrv;
864
865 TRACE("(%p, %p)\n", hModule, lpDriverProc);
866 if (!hModule || !lpDriverProc) return NULL;
867
868 /* look up previous instance of local driver module */
869 for (paldrv = MSACM_pFirstACMLocalDriver; paldrv; paldrv = paldrv->pNextACMLocalDrv)
870 {
871 if (paldrv->hModule == hModule && paldrv->lpDrvProc == lpDriverProc) return paldrv;
872 }
873
874 paldrv = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMLOCALDRIVER));
875 paldrv->obj.dwType = WINE_ACMOBJ_LOCALDRIVER;
876 paldrv->obj.pACMDriverID = 0;
877 paldrv->hModule = hModule;
878 paldrv->lpDrvProc = lpDriverProc;
879 paldrv->pACMInstList = NULL;
880
881 paldrv->pNextACMLocalDrv = NULL;
882 paldrv->pPrevACMLocalDrv = MSACM_pLastACMLocalDriver;
883 if (MSACM_pLastACMLocalDriver)
884 MSACM_pLastACMLocalDriver->pNextACMLocalDrv = paldrv;
885 MSACM_pLastACMLocalDriver = paldrv;
886 if (!MSACM_pFirstACMLocalDriver)
887 MSACM_pFirstACMLocalDriver = paldrv;
888
889 return paldrv;
890 }
891
892 /**************************************************************************
893 * MSACM_GetNumberOfModuleRefs [internal]
894 *
895 * Returns the number of open drivers which share the same module.
896 * Inspired from implementation in dlls/winmm/driver.c
897 */
898 static unsigned MSACM_GetNumberOfModuleRefs(HMODULE hModule, DRIVERPROC lpDrvProc, WINE_ACMLOCALDRIVERINST ** found)
899 {
900 PWINE_ACMLOCALDRIVER lpDrv;
901 unsigned count = 0;
902
903 if (found) *found = NULL;
904 for (lpDrv = MSACM_pFirstACMLocalDriver; lpDrv; lpDrv = lpDrv->pNextACMLocalDrv)
905 {
906 if (lpDrv->hModule == hModule && lpDrv->lpDrvProc == lpDrvProc)
907 {
908 PWINE_ACMLOCALDRIVERINST pInst = lpDrv->pACMInstList;
909
910 while (pInst) {
911 if (found && !*found) *found = pInst;
912 count++;
913 pInst = pInst->pNextACMInst;
914 }
915 }
916 }
917 return count;
918 }
919
920 /**************************************************************************
921 * MSACM_RemoveFromList [internal]
922 *
923 * Generates all the logic to handle driver closure / deletion
924 * Removes a driver struct to the list of open drivers.
925 */
926 static BOOL MSACM_RemoveFromList(PWINE_ACMLOCALDRIVERINST lpDrv)
927 {
928 PWINE_ACMLOCALDRIVER pDriverBase = lpDrv->pLocalDriver;
929 PWINE_ACMLOCALDRIVERINST pPrevInst;
930
931 /* last of this driver in list ? */
932 if (MSACM_GetNumberOfModuleRefs(pDriverBase->hModule, pDriverBase->lpDrvProc, NULL) == 1) {
933 MSACM_DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L);
934 MSACM_DRIVER_SendMessage(lpDrv, DRV_FREE, 0L, 0L);
935 }
936
937 pPrevInst = NULL;
938 if (pDriverBase->pACMInstList != lpDrv) {
939 pPrevInst = pDriverBase->pACMInstList;
940 while (pPrevInst && pPrevInst->pNextACMInst != lpDrv)
941 pPrevInst = pPrevInst->pNextACMInst;
942 if (!pPrevInst) {
943 ERR("requested to remove invalid instance %p\n", pPrevInst);
944 return FALSE;
945 }
946 }
947 if (!pPrevInst) {
948 /* first driver instance on list */
949 pDriverBase->pACMInstList = lpDrv->pNextACMInst;
950 } else {
951 pPrevInst->pNextACMInst = lpDrv->pNextACMInst;
952 }
953 return TRUE;
954 }
955
956 /**************************************************************************
957 * MSACM_AddToList [internal]
958 *
959 * Adds a driver struct to the list of open drivers.
960 * Generates all the logic to handle driver creation / open.
961 */
962 static BOOL MSACM_AddToList(PWINE_ACMLOCALDRIVERINST lpNewDrv, LPARAM lParam2)
963 {
964 PWINE_ACMLOCALDRIVER pDriverBase = lpNewDrv->pLocalDriver;
965
966 /* first of this driver in list ? */
967 if (MSACM_GetNumberOfModuleRefs(pDriverBase->hModule, pDriverBase->lpDrvProc, NULL) == 0) {
968 if (MSACM_DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) {
969 FIXME("DRV_LOAD failed on driver %p\n", lpNewDrv);
970 return FALSE;
971 }
972 /* returned value is not checked */
973 MSACM_DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L);
974 }
975
976 lpNewDrv->pNextACMInst = NULL;
977 if (pDriverBase->pACMInstList == NULL) {
978 pDriverBase->pACMInstList = lpNewDrv;
979 } else {
980 PWINE_ACMLOCALDRIVERINST lpDrvInst = pDriverBase->pACMInstList;
981
982 while (lpDrvInst->pNextACMInst != NULL)
983 lpDrvInst = lpDrvInst->pNextACMInst;
984
985 lpDrvInst->pNextACMInst = lpNewDrv;
986 }
987
988 /* Now just open a new instance of a driver on this module */
989 lpNewDrv->dwDriverID = MSACM_DRIVER_SendMessage(lpNewDrv, DRV_OPEN, 0, lParam2);
990
991 if (lpNewDrv->dwDriverID == 0) {
992 FIXME("DRV_OPEN failed on driver %p\n", lpNewDrv);
993 MSACM_RemoveFromList(lpNewDrv);
994 return FALSE;
995 }
996 return TRUE;
997 }
998
999 PWINE_ACMLOCALDRIVERINST MSACM_OpenLocalDriver(PWINE_ACMLOCALDRIVER paldrv, LPARAM lParam2)
1000 {
1001 PWINE_ACMLOCALDRIVERINST pDrvInst;
1002
1003 pDrvInst = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMLOCALDRIVERINST));
1004 if (!pDrvInst)
1005 return NULL;
1006
1007 pDrvInst->pLocalDriver = paldrv;
1008 pDrvInst->dwDriverID = 0;
1009 pDrvInst->pNextACMInst = NULL;
1010 pDrvInst->bSession = FALSE;
1011
1012 /* Win32 installable drivers must support a two phase opening scheme:
1013 * + first open with NULL as lParam2 (session instance),
1014 * + then do a second open with the real non null lParam2)
1015 */
1016 if (MSACM_GetNumberOfModuleRefs(paldrv->hModule, paldrv->lpDrvProc, NULL) == 0 && lParam2)
1017 {
1018 PWINE_ACMLOCALDRIVERINST ret;
1019
1020 if (!MSACM_AddToList(pDrvInst, 0L))
1021 {
1022 ERR("load0 failed\n");
1023 goto exit;
1024 }
1025 ret = MSACM_OpenLocalDriver(paldrv, lParam2);
1026 if (!ret)
1027 {
1028 ERR("load1 failed\n");
1029 /* If MSACM_CloseLocalDriver returns TRUE,
1030 * then pDrvInst has been freed
1031 */
1032 if (!MSACM_CloseLocalDriver(pDrvInst))
1033 goto exit;
1034
1035 return NULL;
1036 }
1037 pDrvInst->bSession = TRUE;
1038 return ret;
1039 }
1040
1041 if (!MSACM_AddToList(pDrvInst, lParam2))
1042 {
1043 ERR("load failed\n");
1044 goto exit;
1045 }
1046
1047 TRACE("=> %p\n", pDrvInst);
1048 return pDrvInst;
1049 exit:
1050 HeapFree(MSACM_hHeap, 0, pDrvInst);
1051 return NULL;
1052 }
1053
1054 LRESULT MSACM_CloseLocalDriver(PWINE_ACMLOCALDRIVERINST paldrv)
1055 {
1056 if (MSACM_RemoveFromList(paldrv)) {
1057 PWINE_ACMLOCALDRIVERINST lpDrv0;
1058 PWINE_ACMLOCALDRIVER pDriverBase = paldrv->pLocalDriver;
1059
1060 MSACM_DRIVER_SendMessage(paldrv, DRV_CLOSE, 0, 0);
1061 paldrv->dwDriverID = 0;
1062
1063 if (paldrv->bSession)
1064 ERR("should not directly close session instance (%p)\n", paldrv);
1065
1066 /* if driver has an opened session instance, we have to close it too */
1067 if (MSACM_GetNumberOfModuleRefs(pDriverBase->hModule, pDriverBase->lpDrvProc, &lpDrv0) == 1 &&
1068 lpDrv0->bSession)
1069 {
1070 MSACM_DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0L, 0L);
1071 lpDrv0->dwDriverID = 0;
1072 MSACM_RemoveFromList(lpDrv0);
1073 HeapFree(GetProcessHeap(), 0, lpDrv0);
1074 }
1075
1076 HeapFree(MSACM_hHeap, 0, paldrv);
1077 return TRUE;
1078 }
1079 ERR("unable to close driver instance\n");
1080 return FALSE;
1081 }