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
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "mmsystem.h"
34 #include "mmreg.h"
35 #include "msacm.h"
36 #include "msacmdrv.h"
37 #include "wineacm.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
41
42 /***********************************************************************
43 * acmDriverAddA (MSACM32.@)
44 */
acmDriverAddA(PHACMDRIVERID phadid,HINSTANCE hinstModule,LPARAM lParam,DWORD dwPriority,DWORD fdwAdd)45 MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule,
46 LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
47 {
48 MMRESULT resultW;
49 WCHAR * driverW = NULL;
50 LPARAM lParamW = lParam;
51
52 TRACE("(%p, %p, %08lx, %08x, %08x)\n",
53 phadid, hinstModule, lParam, dwPriority, fdwAdd);
54
55 if (!phadid) {
56 WARN("invalid parameter\n");
57 return MMSYSERR_INVALPARAM;
58 }
59
60 /* Check if any unknown flags */
61 if (fdwAdd &
62 ~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND|
63 ACM_DRIVERADDF_GLOBAL)) {
64 WARN("invalid flag\n");
65 return MMSYSERR_INVALFLAG;
66 }
67
68 /* Check if any incompatible flags */
69 if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) &&
70 (fdwAdd & ACM_DRIVERADDF_NOTIFYHWND)) {
71 WARN("invalid flag\n");
72 return MMSYSERR_INVALFLAG;
73 }
74
75 /* A->W translation of name */
76 if ((fdwAdd & ACM_DRIVERADDF_TYPEMASK) == ACM_DRIVERADDF_NAME) {
77 INT len;
78
79 if (lParam == 0) return MMSYSERR_INVALPARAM;
80 len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)lParam, -1, NULL, 0);
81 driverW = HeapAlloc(MSACM_hHeap, 0, len * sizeof(WCHAR));
82 if (!driverW) return MMSYSERR_NOMEM;
83 MultiByteToWideChar(CP_ACP, 0, (LPSTR)lParam, -1, driverW, len);
84 lParamW = (LPARAM)driverW;
85 }
86
87 resultW = acmDriverAddW(phadid, hinstModule, lParamW, dwPriority, fdwAdd);
88 HeapFree(MSACM_hHeap, 0, driverW);
89 return resultW;
90 }
91
92 /***********************************************************************
93 * acmDriverAddW (MSACM32.@)
94 *
95 */
acmDriverAddW(PHACMDRIVERID phadid,HINSTANCE hinstModule,LPARAM lParam,DWORD dwPriority,DWORD fdwAdd)96 MMRESULT WINAPI acmDriverAddW(PHACMDRIVERID phadid, HINSTANCE hinstModule,
97 LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
98 {
99 PWINE_ACMLOCALDRIVER pLocalDrv = NULL;
100
101 TRACE("(%p, %p, %08lx, %08x, %08x)\n",
102 phadid, hinstModule, lParam, dwPriority, fdwAdd);
103
104 if (!phadid) {
105 WARN("invalid parameter\n");
106 return MMSYSERR_INVALPARAM;
107 }
108
109 /* Check if any unknown flags */
110 if (fdwAdd &
111 ~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND|
112 ACM_DRIVERADDF_GLOBAL)) {
113 WARN("invalid flag\n");
114 return MMSYSERR_INVALFLAG;
115 }
116
117 /* Check if any incompatible flags */
118 if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) &&
119 (fdwAdd & ACM_DRIVERADDF_NOTIFYHWND)) {
120 WARN("invalid flag\n");
121 return MMSYSERR_INVALFLAG;
122 }
123
124 switch (fdwAdd & ACM_DRIVERADDF_TYPEMASK) {
125 case ACM_DRIVERADDF_NAME:
126 /*
127 hInstModule (unused)
128 lParam name of value in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32
129 dwPriority (unused, set to 0)
130 */
131 *phadid = (HACMDRIVERID) MSACM_RegisterDriverFromRegistry((LPCWSTR)lParam);
132 if (!*phadid) {
133 ERR("Unable to register driver via ACM_DRIVERADDF_NAME\n");
134 return MMSYSERR_INVALPARAM;
135 }
136 break;
137 case ACM_DRIVERADDF_FUNCTION:
138 /*
139 hInstModule Handle of module which contains driver entry proc
140 lParam Driver function address
141 dwPriority (unused, set to 0)
142 */
143 fdwAdd &= ~ACM_DRIVERADDF_TYPEMASK;
144 /* FIXME: fdwAdd ignored */
145 /* Application-supplied acmDriverProc's are placed at the top of the priority unless
146 fdwAdd indicates ACM_DRIVERADDF_GLOBAL
147 */
148 pLocalDrv = MSACM_RegisterLocalDriver(hinstModule, (DRIVERPROC)lParam);
149 *phadid = pLocalDrv ? (HACMDRIVERID) MSACM_RegisterDriver(NULL, NULL, pLocalDrv) : NULL;
150 if (!*phadid) {
151 ERR("Unable to register driver via ACM_DRIVERADDF_FUNCTION\n");
152 return MMSYSERR_INVALPARAM;
153 }
154 break;
155 case ACM_DRIVERADDF_NOTIFYHWND:
156 /*
157 hInstModule (unused)
158 lParam Handle of notification window
159 dwPriority Window message to send for notification broadcasts
160 */
161 *phadid = (HACMDRIVERID) MSACM_RegisterNotificationWindow((HWND)lParam, dwPriority);
162 if (!*phadid) {
163 ERR("Unable to register driver via ACM_DRIVERADDF_NOTIFYHWND\n");
164 return MMSYSERR_INVALPARAM;
165 }
166 break;
167 default:
168 ERR("invalid flag value 0x%08x for fdwAdd\n", fdwAdd);
169 return MMSYSERR_INVALFLAG;
170 }
171
172 MSACM_BroadcastNotification();
173 return MMSYSERR_NOERROR;
174 }
175
176 /***********************************************************************
177 * acmDriverClose (MSACM32.@)
178 */
acmDriverClose(HACMDRIVER had,DWORD fdwClose)179 MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
180 {
181 PWINE_ACMDRIVER pad;
182 PWINE_ACMDRIVERID padid;
183 PWINE_ACMDRIVER* tpad;
184
185 TRACE("(%p, %08x)\n", had, fdwClose);
186
187 if (fdwClose) {
188 WARN("invalid flag\n");
189 return MMSYSERR_INVALFLAG;
190 }
191
192 pad = MSACM_GetDriver(had);
193 if (!pad) {
194 WARN("invalid handle\n");
195 return MMSYSERR_INVALHANDLE;
196 }
197
198 padid = pad->obj.pACMDriverID;
199
200 /* remove driver from list */
201 for (tpad = &(padid->pACMDriverList); *tpad; tpad = &((*tpad)->pNextACMDriver)) {
202 if (*tpad == pad) {
203 *tpad = (*tpad)->pNextACMDriver;
204 break;
205 }
206 }
207
208 /* close driver if it has been opened */
209 if (pad->hDrvr && !pad->pLocalDrvrInst)
210 CloseDriver(pad->hDrvr, 0, 0);
211 else if (pad->pLocalDrvrInst)
212 MSACM_CloseLocalDriver(pad->pLocalDrvrInst);
213
214 pad->obj.dwType = 0;
215 HeapFree(MSACM_hHeap, 0, pad);
216
217 return MMSYSERR_NOERROR;
218 }
219
220 /***********************************************************************
221 * acmDriverDetailsA (MSACM32.@)
222 */
acmDriverDetailsA(HACMDRIVERID hadid,PACMDRIVERDETAILSA padd,DWORD fdwDetails)223 MMRESULT WINAPI acmDriverDetailsA(HACMDRIVERID hadid, PACMDRIVERDETAILSA padd, DWORD fdwDetails)
224 {
225 MMRESULT mmr;
226 ACMDRIVERDETAILSW addw;
227
228 TRACE("(%p, %p, %08x)\n", hadid, padd, fdwDetails);
229
230 if (!padd) {
231 WARN("invalid parameter\n");
232 return MMSYSERR_INVALPARAM;
233 }
234
235 if (padd->cbStruct < 4) {
236 WARN("invalid parameter\n");
237 return MMSYSERR_INVALPARAM;
238 }
239
240 addw.cbStruct = sizeof(addw);
241 mmr = acmDriverDetailsW(hadid, &addw, fdwDetails);
242 if (mmr == 0) {
243 ACMDRIVERDETAILSA padda;
244
245 padda.fccType = addw.fccType;
246 padda.fccComp = addw.fccComp;
247 padda.wMid = addw.wMid;
248 padda.wPid = addw.wPid;
249 padda.vdwACM = addw.vdwACM;
250 padda.vdwDriver = addw.vdwDriver;
251 padda.fdwSupport = addw.fdwSupport;
252 padda.cFormatTags = addw.cFormatTags;
253 padda.cFilterTags = addw.cFilterTags;
254 padda.hicon = addw.hicon;
255 WideCharToMultiByte( CP_ACP, 0, addw.szShortName, -1, padda.szShortName,
256 sizeof(padda.szShortName), NULL, NULL );
257 WideCharToMultiByte( CP_ACP, 0, addw.szLongName, -1, padda.szLongName,
258 sizeof(padda.szLongName), NULL, NULL );
259 WideCharToMultiByte( CP_ACP, 0, addw.szCopyright, -1, padda.szCopyright,
260 sizeof(padda.szCopyright), NULL, NULL );
261 WideCharToMultiByte( CP_ACP, 0, addw.szLicensing, -1, padda.szLicensing,
262 sizeof(padda.szLicensing), NULL, NULL );
263 WideCharToMultiByte( CP_ACP, 0, addw.szFeatures, -1, padda.szFeatures,
264 sizeof(padda.szFeatures), NULL, NULL );
265 padda.cbStruct = min(padd->cbStruct, sizeof(*padd));
266 memcpy(padd, &padda, padda.cbStruct);
267 }
268 return mmr;
269 }
270
271 /***********************************************************************
272 * acmDriverDetailsW (MSACM32.@)
273 */
acmDriverDetailsW(HACMDRIVERID hadid,PACMDRIVERDETAILSW padd,DWORD fdwDetails)274 MMRESULT WINAPI acmDriverDetailsW(HACMDRIVERID hadid, PACMDRIVERDETAILSW padd, DWORD fdwDetails)
275 {
276 HACMDRIVER acmDrvr;
277 MMRESULT mmr;
278
279 TRACE("(%p, %p, %08x)\n", hadid, padd, fdwDetails);
280
281 if (!padd) {
282 WARN("invalid parameter\n");
283 return MMSYSERR_INVALPARAM;
284 }
285
286 if (padd->cbStruct < 4) {
287 WARN("invalid parameter\n");
288 return MMSYSERR_INVALPARAM;
289 }
290
291 if (fdwDetails) {
292 WARN("invalid flag\n");
293 return MMSYSERR_INVALFLAG;
294 }
295
296 mmr = acmDriverOpen(&acmDrvr, hadid, 0);
297 if (mmr == MMSYSERR_NOERROR) {
298 ACMDRIVERDETAILSW paddw;
299 paddw.cbStruct = sizeof(paddw);
300 mmr = MSACM_Message(acmDrvr, ACMDM_DRIVER_DETAILS, (LPARAM)&paddw, 0);
301
302 acmDriverClose(acmDrvr, 0);
303 paddw.cbStruct = min(padd->cbStruct, sizeof(*padd));
304 memcpy(padd, &paddw, paddw.cbStruct);
305 }
306 else if (mmr == MMSYSERR_NODRIVER)
307 return MMSYSERR_NOTSUPPORTED;
308
309 return mmr;
310 }
311
312 /***********************************************************************
313 * acmDriverEnum (MSACM32.@)
314 */
acmDriverEnum(ACMDRIVERENUMCB fnCallback,DWORD_PTR dwInstance,DWORD fdwEnum)315 MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD_PTR dwInstance,
316 DWORD fdwEnum)
317 {
318 PWINE_ACMDRIVERID padid;
319 DWORD fdwSupport;
320
321 TRACE("(%p, %08lx, %08x)\n", fnCallback, dwInstance, fdwEnum);
322
323 if (!fnCallback) {
324 WARN("invalid parameter\n");
325 return MMSYSERR_INVALPARAM;
326 }
327
328 if (fdwEnum & ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) {
329 WARN("invalid flag\n");
330 return MMSYSERR_INVALFLAG;
331 }
332
333 for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
334 fdwSupport = padid->fdwSupport;
335
336 if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
337 if (fdwEnum & ACM_DRIVERENUMF_DISABLED)
338 fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
339 else
340 continue;
341 }
342 if (!(*fnCallback)((HACMDRIVERID)padid, dwInstance, fdwSupport))
343 break;
344 }
345
346 return MMSYSERR_NOERROR;
347 }
348
349 /***********************************************************************
350 * acmDriverID (MSACM32.@)
351 */
acmDriverID(HACMOBJ hao,PHACMDRIVERID phadid,DWORD fdwDriverID)352 MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID)
353 {
354 PWINE_ACMOBJ pao;
355
356 TRACE("(%p, %p, %08x)\n", hao, phadid, fdwDriverID);
357
358 if (fdwDriverID) {
359 WARN("invalid flag\n");
360 return MMSYSERR_INVALFLAG;
361 }
362
363 pao = MSACM_GetObj(hao, WINE_ACMOBJ_DONTCARE);
364 if (!pao) {
365 WARN("invalid handle\n");
366 return MMSYSERR_INVALHANDLE;
367 }
368
369 if (!phadid) {
370 WARN("invalid parameter\n");
371 return MMSYSERR_INVALPARAM;
372 }
373
374 *phadid = (HACMDRIVERID) pao->pACMDriverID;
375
376 return MMSYSERR_NOERROR;
377 }
378
379 /***********************************************************************
380 * acmDriverMessage (MSACM32.@)
381 *
382 * Note: MSDN documentation (July 2001) is incomplete. This function
383 * accepts sending messages to an HACMDRIVERID in addition to the
384 * documented HACMDRIVER. In fact, for DRV_QUERYCONFIGURE and DRV_CONFIGURE,
385 * this might actually be the required mode of operation.
386 *
387 * Note: For DRV_CONFIGURE, msacm supplies its own DRVCONFIGINFO structure
388 * when the application fails to supply one. Some native drivers depend on
389 * this and refuse to display unless a valid DRVCONFIGINFO structure is
390 * built and supplied.
391 */
acmDriverMessage(HACMDRIVER had,UINT uMsg,LPARAM lParam1,LPARAM lParam2)392 LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
393 {
394 TRACE("(%p, %04x, %08lx, %08lx\n", had, uMsg, lParam1, lParam2);
395
396 if ((uMsg >= ACMDM_USER && uMsg < ACMDM_RESERVED_LOW) ||
397 uMsg == ACMDM_DRIVER_ABOUT ||
398 uMsg == DRV_QUERYCONFIGURE ||
399 uMsg == DRV_CONFIGURE)
400 {
401 PWINE_ACMDRIVERID padid;
402 LRESULT lResult;
403 LPDRVCONFIGINFO pConfigInfo = NULL;
404 LPWSTR section_name = NULL;
405 LPWSTR alias_name = NULL;
406
407 /* Check whether handle is an HACMDRIVERID */
408 padid = MSACM_GetDriverID((HACMDRIVERID)had);
409
410 /* If the message is DRV_CONFIGURE, and the application provides no
411 DRVCONFIGINFO structure, msacm must supply its own.
412 */
413 if (uMsg == DRV_CONFIGURE && lParam2 == 0) {
414 LPWSTR pAlias;
415
416 /* Get the alias from the HACMDRIVERID */
417 if (padid) {
418 pAlias = padid->pszDriverAlias;
419 if (pAlias == NULL) {
420 WARN("DRV_CONFIGURE: no alias for this driver, cannot self-supply alias\n");
421 }
422 } else {
423 FIXME("DRV_CONFIGURE: reverse lookup HACMDRIVER -> HACMDRIVERID not implemented\n");
424 pAlias = NULL;
425 }
426
427 if (pAlias != NULL) {
428 /* DRVCONFIGINFO is only 12 bytes long, but native msacm
429 * reports a 16-byte structure to codecs, so allocate 16 bytes,
430 * just to be on the safe side.
431 */
432 const unsigned int iStructSize = 16;
433 pConfigInfo = HeapAlloc(MSACM_hHeap, 0, iStructSize);
434 if (!pConfigInfo) {
435 ERR("OOM while supplying DRVCONFIGINFO for DRV_CONFIGURE, using NULL\n");
436 } else {
437 static const WCHAR drivers32[] = {'D','r','i','v','e','r','s','3','2','\0'};
438
439 pConfigInfo->dwDCISize = iStructSize;
440
441 section_name = HeapAlloc(MSACM_hHeap, 0, (lstrlenW(drivers32) + 1) * sizeof(WCHAR));
442 if (section_name) lstrcpyW(section_name, drivers32);
443 pConfigInfo->lpszDCISectionName = section_name;
444 alias_name = HeapAlloc(MSACM_hHeap, 0, (lstrlenW(pAlias) + 1) * sizeof(WCHAR));
445 if (alias_name) lstrcpyW(alias_name, pAlias);
446 pConfigInfo->lpszDCIAliasName = alias_name;
447
448 if (pConfigInfo->lpszDCISectionName == NULL || pConfigInfo->lpszDCIAliasName == NULL) {
449 HeapFree(MSACM_hHeap, 0, alias_name);
450 HeapFree(MSACM_hHeap, 0, section_name);
451 HeapFree(MSACM_hHeap, 0, pConfigInfo);
452 pConfigInfo = NULL;
453 ERR("OOM while supplying DRVCONFIGINFO for DRV_CONFIGURE, using NULL\n");
454 }
455 }
456 }
457
458 lParam2 = (LPARAM)pConfigInfo;
459 }
460
461 if (padid) {
462 /* Handle is really an HACMDRIVERID, must have an open session to get an HACMDRIVER */
463 if (padid->pACMDriverList != NULL) {
464 lResult = MSACM_Message((HACMDRIVER)padid->pACMDriverList, uMsg, lParam1, lParam2);
465 } else {
466 MMRESULT mmr = acmDriverOpen(&had, (HACMDRIVERID)padid, 0);
467 if (mmr != MMSYSERR_NOERROR) {
468 lResult = MMSYSERR_INVALPARAM;
469 } else {
470 lResult = acmDriverMessage(had, uMsg, lParam1, lParam2);
471 acmDriverClose(had, 0);
472 }
473 }
474 } else {
475 lResult = MSACM_Message(had, uMsg, lParam1, lParam2);
476 }
477 if (pConfigInfo) {
478 HeapFree(MSACM_hHeap, 0, alias_name);
479 HeapFree(MSACM_hHeap, 0, section_name);
480 HeapFree(MSACM_hHeap, 0, pConfigInfo);
481 }
482 return lResult;
483 }
484 WARN("invalid parameter\n");
485 return MMSYSERR_INVALPARAM;
486 }
487
488 /***********************************************************************
489 * acmDriverOpen (MSACM32.@)
490 */
acmDriverOpen(PHACMDRIVER phad,HACMDRIVERID hadid,DWORD fdwOpen)491 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
492 {
493 PWINE_ACMDRIVERID padid;
494 PWINE_ACMDRIVER pad = NULL;
495 MMRESULT ret;
496
497 TRACE("(%p, %p, %08u)\n", phad, hadid, fdwOpen);
498
499 if (!phad) {
500 WARN("invalid parameter\n");
501 return MMSYSERR_INVALPARAM;
502 }
503
504 if (fdwOpen) {
505 WARN("invalid flag\n");
506 return MMSYSERR_INVALFLAG;
507 }
508
509 padid = MSACM_GetDriverID(hadid);
510 if (!padid) {
511 WARN("invalid handle\n");
512 return MMSYSERR_INVALHANDLE;
513 }
514
515 pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
516 if (!pad) {
517 WARN("no memory\n");
518 return MMSYSERR_NOMEM;
519 }
520
521 pad->obj.dwType = WINE_ACMOBJ_DRIVER;
522 pad->obj.pACMDriverID = padid;
523 pad->hDrvr = 0;
524 pad->pLocalDrvrInst = NULL;
525
526 if (padid->pLocalDriver == NULL)
527 {
528 ACMDRVOPENDESCW adod;
529 int len;
530 LPWSTR section_name;
531
532 /* this is not an externally added driver... need to actually load it */
533 if (!padid->pszDriverAlias)
534 {
535 ret = MMSYSERR_ERROR;
536 goto gotError;
537 }
538
539 adod.cbStruct = sizeof(adod);
540 adod.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
541 adod.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
542 adod.dwVersion = acmGetVersion();
543 adod.dwFlags = fdwOpen;
544 adod.dwError = 0;
545 len = strlen("Drivers32") + 1;
546 section_name = HeapAlloc(MSACM_hHeap, 0, len * sizeof(WCHAR));
547 MultiByteToWideChar(CP_ACP, 0, "Drivers32", -1, section_name, len);
548 adod.pszSectionName = section_name;
549 adod.pszAliasName = padid->pszDriverAlias;
550 adod.dnDevNode = 0;
551
552 pad->hDrvr = OpenDriver(padid->pszDriverAlias, NULL, (DWORD_PTR)&adod);
553
554 HeapFree(MSACM_hHeap, 0, section_name);
555 if (!pad->hDrvr)
556 {
557 ret = adod.dwError;
558 if (ret == MMSYSERR_NOERROR)
559 ret = MMSYSERR_NODRIVER;
560 goto gotError;
561 }
562 }
563 else
564 {
565 ACMDRVOPENDESCW adod;
566
567 pad->hDrvr = NULL;
568
569 adod.cbStruct = sizeof(adod);
570 adod.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
571 adod.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
572 adod.dwVersion = acmGetVersion();
573 adod.dwFlags = fdwOpen;
574 adod.dwError = 0;
575 adod.pszSectionName = NULL;
576 adod.pszAliasName = NULL;
577 adod.dnDevNode = 0;
578
579 pad->pLocalDrvrInst = MSACM_OpenLocalDriver(padid->pLocalDriver, (DWORD_PTR)&adod);
580 if (!pad->pLocalDrvrInst)
581 {
582 ret = adod.dwError;
583 if (ret == MMSYSERR_NOERROR)
584 ret = MMSYSERR_NODRIVER;
585 goto gotError;
586 }
587 }
588
589 /* insert new pad at beg of list */
590 pad->pNextACMDriver = padid->pACMDriverList;
591 padid->pACMDriverList = pad;
592
593 /* FIXME: Create a WINE_ACMDRIVER32 */
594 *phad = (HACMDRIVER)pad;
595 TRACE("%s => %p\n", debugstr_w(padid->pszDriverAlias), pad);
596
597 return MMSYSERR_NOERROR;
598 gotError:
599 WARN("failed: ret = %08x\n", ret);
600 HeapFree(MSACM_hHeap, 0, pad);
601 return ret;
602 }
603
604 /***********************************************************************
605 * acmDriverPriority (MSACM32.@)
606 */
acmDriverPriority(HACMDRIVERID hadid,DWORD dwPriority,DWORD fdwPriority)607 MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fdwPriority)
608 {
609
610 TRACE("(%p, %08x, %08x)\n", hadid, dwPriority, fdwPriority);
611
612 /* Check for unknown flags */
613 if (fdwPriority &
614 ~(ACM_DRIVERPRIORITYF_ENABLE|ACM_DRIVERPRIORITYF_DISABLE|
615 ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) {
616 WARN("invalid flag\n");
617 return MMSYSERR_INVALFLAG;
618 }
619
620 /* Check for incompatible flags */
621 if ((fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) &&
622 (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE)) {
623 WARN("invalid flag\n");
624 return MMSYSERR_INVALFLAG;
625 }
626
627 /* Check for incompatible flags */
628 if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) &&
629 (fdwPriority & ACM_DRIVERPRIORITYF_END)) {
630 WARN("invalid flag\n");
631 return MMSYSERR_INVALFLAG;
632 }
633
634 /* According to MSDN, ACM_DRIVERPRIORITYF_BEGIN and ACM_DRIVERPRIORITYF_END
635 may only appear by themselves, and in addition, hadid and dwPriority must
636 both be zero */
637 if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) ||
638 (fdwPriority & ACM_DRIVERPRIORITYF_END)) {
639 if (fdwPriority & ~(ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) {
640 WARN("ACM_DRIVERPRIORITYF_[BEGIN|END] cannot be used with any other flags\n");
641 return MMSYSERR_INVALPARAM;
642 }
643 if (dwPriority) {
644 WARN("priority invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n");
645 return MMSYSERR_INVALPARAM;
646 }
647 if (hadid) {
648 WARN("non-null hadid invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n");
649 return MMSYSERR_INVALPARAM;
650 }
651 /* FIXME: MSDN wording suggests that deferred notification should be
652 implemented as a system-wide lock held by a calling task, and that
653 re-enabling notifications should broadcast them across all processes.
654 This implementation uses a simple DWORD counter. One consequence of the
655 current implementation is that applications will never see
656 MMSYSERR_ALLOCATED as a return error.
657 */
658 if (fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) {
659 MSACM_DisableNotifications();
660 } else if (fdwPriority & ACM_DRIVERPRIORITYF_END) {
661 MSACM_EnableNotifications();
662 }
663 return MMSYSERR_NOERROR;
664 } else {
665 PWINE_ACMDRIVERID padid;
666 PWINE_ACMNOTIFYWND panwnd;
667 BOOL bPerformBroadcast = FALSE;
668
669 /* Fetch driver ID */
670 padid = MSACM_GetDriverID(hadid);
671 panwnd = MSACM_GetNotifyWnd(hadid);
672 if (!padid && !panwnd) {
673 WARN("invalid handle\n");
674 return MMSYSERR_INVALHANDLE;
675 }
676
677 if (padid) {
678 /* Check whether driver ID is appropriate for requested op */
679 if (dwPriority) {
680 if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL) {
681 return MMSYSERR_NOTSUPPORTED;
682 }
683 if (dwPriority != 1 && dwPriority != (DWORD)-1) {
684 FIXME("unexpected priority %d, using sign only\n", dwPriority);
685 if ((signed)dwPriority < 0) dwPriority = (DWORD)-1;
686 if (dwPriority > 0) dwPriority = 1;
687 }
688
689 if (dwPriority == 1 && (padid->pPrevACMDriverID == NULL ||
690 (padid->pPrevACMDriverID->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL))) {
691 /* do nothing - driver is first of list, or first after last
692 local driver */
693 } else if (dwPriority == (DWORD)-1 && padid->pNextACMDriverID == NULL) {
694 /* do nothing - driver is last of list */
695 } else {
696 MSACM_RePositionDriver(padid, dwPriority);
697 bPerformBroadcast = TRUE;
698 }
699 }
700
701 /* Check whether driver ID should be enabled or disabled */
702 if (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE) {
703 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED)) {
704 padid->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
705 bPerformBroadcast = TRUE;
706 }
707 } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) {
708 if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
709 padid->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED;
710 bPerformBroadcast = TRUE;
711 }
712 }
713 }
714
715 if (panwnd) {
716 if (dwPriority) {
717 return MMSYSERR_NOTSUPPORTED;
718 }
719
720 /* Check whether notify window should be enabled or disabled */
721 if (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE) {
722 if (!(panwnd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED)) {
723 panwnd->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
724 bPerformBroadcast = TRUE;
725 }
726 } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) {
727 if (panwnd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
728 panwnd->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED;
729 bPerformBroadcast = TRUE;
730 }
731 }
732 }
733
734 /* Perform broadcast of changes */
735 if (bPerformBroadcast) {
736 MSACM_WriteCurrentPriorities();
737 MSACM_BroadcastNotification();
738 }
739 return MMSYSERR_NOERROR;
740 }
741 }
742
743 /***********************************************************************
744 * acmDriverRemove (MSACM32.@)
745 */
acmDriverRemove(HACMDRIVERID hadid,DWORD fdwRemove)746 MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
747 {
748 PWINE_ACMDRIVERID padid;
749 PWINE_ACMNOTIFYWND panwnd;
750
751 TRACE("(%p, %08x)\n", hadid, fdwRemove);
752
753 padid = MSACM_GetDriverID(hadid);
754 panwnd = MSACM_GetNotifyWnd(hadid);
755 if (!padid && !panwnd) {
756 WARN("invalid handle\n");
757 return MMSYSERR_INVALHANDLE;
758 }
759
760 if (fdwRemove) {
761 WARN("invalid flag\n");
762 return MMSYSERR_INVALFLAG;
763 }
764
765 if (padid) MSACM_UnregisterDriver(padid);
766 if (panwnd) MSACM_UnRegisterNotificationWindow(panwnd);
767 MSACM_BroadcastNotification();
768
769 return MMSYSERR_NOERROR;
770 }
771