mf: Avoid unnecessary prerolling calls in SAR.
[wine.git] / dlls / msacm32 / driver.c
blobf0d003f648b44de24fe3fc183b241dcc7ac0ca10
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MSACM32 library
6 * Copyright 1998 Patrik Stridvall
7 * 1999 Eric Pouech
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
25 #include <stdarg.h>
26 #include <stdio.h>
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"
40 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
42 /***********************************************************************
43 * acmDriverAddA (MSACM32.@)
45 MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule,
46 LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
48 MMRESULT resultW;
49 WCHAR * driverW = NULL;
50 LPARAM lParamW = lParam;
52 TRACE("(%p, %p, %08lx, %08x, %08x)\n",
53 phadid, hinstModule, lParam, dwPriority, fdwAdd);
55 if (!phadid) {
56 WARN("invalid parameter\n");
57 return MMSYSERR_INVALPARAM;
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;
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;
75 /* A->W translation of name */
76 if ((fdwAdd & ACM_DRIVERADDF_TYPEMASK) == ACM_DRIVERADDF_NAME) {
77 INT len;
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;
87 resultW = acmDriverAddW(phadid, hinstModule, lParamW, dwPriority, fdwAdd);
88 HeapFree(MSACM_hHeap, 0, driverW);
89 return resultW;
92 /***********************************************************************
93 * acmDriverAddW (MSACM32.@)
96 MMRESULT WINAPI acmDriverAddW(PHACMDRIVERID phadid, HINSTANCE hinstModule,
97 LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
99 PWINE_ACMLOCALDRIVER pLocalDrv = NULL;
101 TRACE("(%p, %p, %08lx, %08x, %08x)\n",
102 phadid, hinstModule, lParam, dwPriority, fdwAdd);
104 if (!phadid) {
105 WARN("invalid parameter\n");
106 return MMSYSERR_INVALPARAM;
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;
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;
124 switch (fdwAdd & ACM_DRIVERADDF_TYPEMASK) {
125 case ACM_DRIVERADDF_NAME:
127 hInstModule (unused)
128 lParam name of value in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32
129 dwPriority (unused, set to 0)
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;
136 break;
137 case ACM_DRIVERADDF_FUNCTION:
139 hInstModule Handle of module which contains driver entry proc
140 lParam Driver function address
141 dwPriority (unused, set to 0)
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
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;
154 break;
155 case ACM_DRIVERADDF_NOTIFYHWND:
157 hInstModule (unused)
158 lParam Handle of notification window
159 dwPriority Window message to send for notification broadcasts
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;
166 break;
167 default:
168 ERR("invalid flag value 0x%08x for fdwAdd\n", fdwAdd);
169 return MMSYSERR_INVALFLAG;
172 MSACM_BroadcastNotification();
173 return MMSYSERR_NOERROR;
176 /***********************************************************************
177 * acmDriverClose (MSACM32.@)
179 MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
181 PWINE_ACMDRIVER pad;
182 PWINE_ACMDRIVERID padid;
183 PWINE_ACMDRIVER* tpad;
185 TRACE("(%p, %08x)\n", had, fdwClose);
187 if (fdwClose) {
188 WARN("invalid flag\n");
189 return MMSYSERR_INVALFLAG;
192 pad = MSACM_GetDriver(had);
193 if (!pad) {
194 WARN("invalid handle\n");
195 return MMSYSERR_INVALHANDLE;
198 padid = pad->obj.pACMDriverID;
200 /* remove driver from list */
201 for (tpad = &(padid->pACMDriverList); *tpad; tpad = &((*tpad)->pNextACMDriver)) {
202 if (*tpad == pad) {
203 *tpad = (*tpad)->pNextACMDriver;
204 break;
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);
214 pad->obj.dwType = 0;
215 HeapFree(MSACM_hHeap, 0, pad);
217 return MMSYSERR_NOERROR;
220 /***********************************************************************
221 * acmDriverDetailsA (MSACM32.@)
223 MMRESULT WINAPI acmDriverDetailsA(HACMDRIVERID hadid, PACMDRIVERDETAILSA padd, DWORD fdwDetails)
225 MMRESULT mmr;
226 ACMDRIVERDETAILSW addw;
228 TRACE("(%p, %p, %08x)\n", hadid, padd, fdwDetails);
230 if (!padd) {
231 WARN("invalid parameter\n");
232 return MMSYSERR_INVALPARAM;
235 if (padd->cbStruct < 4) {
236 WARN("invalid parameter\n");
237 return MMSYSERR_INVALPARAM;
240 addw.cbStruct = sizeof(addw);
241 mmr = acmDriverDetailsW(hadid, &addw, fdwDetails);
242 if (mmr == 0) {
243 ACMDRIVERDETAILSA padda;
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);
268 return mmr;
271 /***********************************************************************
272 * acmDriverDetailsW (MSACM32.@)
274 MMRESULT WINAPI acmDriverDetailsW(HACMDRIVERID hadid, PACMDRIVERDETAILSW padd, DWORD fdwDetails)
276 HACMDRIVER acmDrvr;
277 MMRESULT mmr;
279 TRACE("(%p, %p, %08x)\n", hadid, padd, fdwDetails);
281 if (!padd) {
282 WARN("invalid parameter\n");
283 return MMSYSERR_INVALPARAM;
286 if (padd->cbStruct < 4) {
287 WARN("invalid parameter\n");
288 return MMSYSERR_INVALPARAM;
291 if (fdwDetails) {
292 WARN("invalid flag\n");
293 return MMSYSERR_INVALFLAG;
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);
302 acmDriverClose(acmDrvr, 0);
303 paddw.cbStruct = min(padd->cbStruct, sizeof(*padd));
304 memcpy(padd, &paddw, paddw.cbStruct);
306 else if (mmr == MMSYSERR_NODRIVER)
307 return MMSYSERR_NOTSUPPORTED;
309 return mmr;
312 /***********************************************************************
313 * acmDriverEnum (MSACM32.@)
315 MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD_PTR dwInstance,
316 DWORD fdwEnum)
318 PWINE_ACMDRIVERID padid;
319 DWORD fdwSupport;
321 TRACE("(%p, %08lx, %08x)\n", fnCallback, dwInstance, fdwEnum);
323 if (!fnCallback) {
324 WARN("invalid parameter\n");
325 return MMSYSERR_INVALPARAM;
328 if (fdwEnum & ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) {
329 WARN("invalid flag\n");
330 return MMSYSERR_INVALFLAG;
333 for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
334 fdwSupport = padid->fdwSupport;
336 if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
337 if (fdwEnum & ACM_DRIVERENUMF_DISABLED)
338 fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
339 else
340 continue;
342 if (!(*fnCallback)((HACMDRIVERID)padid, dwInstance, fdwSupport))
343 break;
346 return MMSYSERR_NOERROR;
349 /***********************************************************************
350 * acmDriverID (MSACM32.@)
352 MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID)
354 PWINE_ACMOBJ pao;
356 TRACE("(%p, %p, %08x)\n", hao, phadid, fdwDriverID);
358 if (fdwDriverID) {
359 WARN("invalid flag\n");
360 return MMSYSERR_INVALFLAG;
363 pao = MSACM_GetObj(hao, WINE_ACMOBJ_DONTCARE);
364 if (!pao) {
365 WARN("invalid handle\n");
366 return MMSYSERR_INVALHANDLE;
369 if (!phadid) {
370 WARN("invalid parameter\n");
371 return MMSYSERR_INVALPARAM;
374 *phadid = (HACMDRIVERID) pao->pACMDriverID;
376 return MMSYSERR_NOERROR;
379 /***********************************************************************
380 * acmDriverMessage (MSACM32.@)
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.
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.
392 LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
394 TRACE("(%p, %04x, %08lx, %08lx\n", had, uMsg, lParam1, lParam2);
396 if ((uMsg >= ACMDM_USER && uMsg < ACMDM_RESERVED_LOW) ||
397 uMsg == ACMDM_DRIVER_ABOUT ||
398 uMsg == DRV_QUERYCONFIGURE ||
399 uMsg == DRV_CONFIGURE)
401 PWINE_ACMDRIVERID padid;
402 LRESULT lResult;
403 LPDRVCONFIGINFO pConfigInfo = NULL;
404 LPWSTR section_name = NULL;
405 LPWSTR alias_name = NULL;
407 /* Check whether handle is an HACMDRIVERID */
408 padid = MSACM_GetDriverID((HACMDRIVERID)had);
410 /* If the message is DRV_CONFIGURE, and the application provides no
411 DRVCONFIGINFO structure, msacm must supply its own.
413 if (uMsg == DRV_CONFIGURE && lParam2 == 0) {
414 LPWSTR pAlias;
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");
422 } else {
423 FIXME("DRV_CONFIGURE: reverse lookup HACMDRIVER -> HACMDRIVERID not implemented\n");
424 pAlias = NULL;
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.
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'};
439 pConfigInfo->dwDCISize = iStructSize;
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;
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");
458 lParam2 = (LPARAM)pConfigInfo;
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);
474 } else {
475 lResult = MSACM_Message(had, uMsg, lParam1, lParam2);
477 if (pConfigInfo) {
478 HeapFree(MSACM_hHeap, 0, alias_name);
479 HeapFree(MSACM_hHeap, 0, section_name);
480 HeapFree(MSACM_hHeap, 0, pConfigInfo);
482 return lResult;
484 WARN("invalid parameter\n");
485 return MMSYSERR_INVALPARAM;
488 /***********************************************************************
489 * acmDriverOpen (MSACM32.@)
491 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
493 PWINE_ACMDRIVERID padid;
494 PWINE_ACMDRIVER pad = NULL;
495 MMRESULT ret;
497 TRACE("(%p, %p, %08u)\n", phad, hadid, fdwOpen);
499 if (!phad) {
500 WARN("invalid parameter\n");
501 return MMSYSERR_INVALPARAM;
504 if (fdwOpen) {
505 WARN("invalid flag\n");
506 return MMSYSERR_INVALFLAG;
509 padid = MSACM_GetDriverID(hadid);
510 if (!padid) {
511 WARN("invalid handle\n");
512 return MMSYSERR_INVALHANDLE;
515 pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
516 if (!pad) {
517 WARN("no memory\n");
518 return MMSYSERR_NOMEM;
521 pad->obj.dwType = WINE_ACMOBJ_DRIVER;
522 pad->obj.pACMDriverID = padid;
523 pad->hDrvr = 0;
524 pad->pLocalDrvrInst = NULL;
526 if (padid->pLocalDriver == NULL)
528 ACMDRVOPENDESCW adod;
529 int len;
530 LPWSTR section_name;
532 /* this is not an externally added driver... need to actually load it */
533 if (!padid->pszDriverAlias)
535 ret = MMSYSERR_ERROR;
536 goto gotError;
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;
552 pad->hDrvr = OpenDriver(padid->pszDriverAlias, NULL, (DWORD_PTR)&adod);
554 HeapFree(MSACM_hHeap, 0, section_name);
555 if (!pad->hDrvr)
557 ret = adod.dwError;
558 if (ret == MMSYSERR_NOERROR)
559 ret = MMSYSERR_NODRIVER;
560 goto gotError;
563 else
565 ACMDRVOPENDESCW adod;
567 pad->hDrvr = NULL;
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;
579 pad->pLocalDrvrInst = MSACM_OpenLocalDriver(padid->pLocalDriver, (DWORD_PTR)&adod);
580 if (!pad->pLocalDrvrInst)
582 ret = adod.dwError;
583 if (ret == MMSYSERR_NOERROR)
584 ret = MMSYSERR_NODRIVER;
585 goto gotError;
589 /* insert new pad at beg of list */
590 pad->pNextACMDriver = padid->pACMDriverList;
591 padid->pACMDriverList = pad;
593 /* FIXME: Create a WINE_ACMDRIVER32 */
594 *phad = (HACMDRIVER)pad;
595 TRACE("%s => %p\n", debugstr_w(padid->pszDriverAlias), pad);
597 return MMSYSERR_NOERROR;
598 gotError:
599 WARN("failed: ret = %08x\n", ret);
600 HeapFree(MSACM_hHeap, 0, pad);
601 return ret;
604 /***********************************************************************
605 * acmDriverPriority (MSACM32.@)
607 MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fdwPriority)
610 TRACE("(%p, %08x, %08x)\n", hadid, dwPriority, fdwPriority);
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;
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;
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;
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;
643 if (dwPriority) {
644 WARN("priority invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n");
645 return MMSYSERR_INVALPARAM;
647 if (hadid) {
648 WARN("non-null hadid invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n");
649 return MMSYSERR_INVALPARAM;
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.
658 if (fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) {
659 MSACM_DisableNotifications();
660 } else if (fdwPriority & ACM_DRIVERPRIORITYF_END) {
661 MSACM_EnableNotifications();
663 return MMSYSERR_NOERROR;
664 } else {
665 PWINE_ACMDRIVERID padid;
666 PWINE_ACMNOTIFYWND panwnd;
667 BOOL bPerformBroadcast = FALSE;
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;
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;
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;
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;
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;
707 } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) {
708 if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
709 padid->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED;
710 bPerformBroadcast = TRUE;
715 if (panwnd) {
716 if (dwPriority) {
717 return MMSYSERR_NOTSUPPORTED;
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;
726 } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) {
727 if (panwnd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
728 panwnd->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED;
729 bPerformBroadcast = TRUE;
734 /* Perform broadcast of changes */
735 if (bPerformBroadcast) {
736 MSACM_WriteCurrentPriorities();
737 MSACM_BroadcastNotification();
739 return MMSYSERR_NOERROR;
743 /***********************************************************************
744 * acmDriverRemove (MSACM32.@)
746 MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
748 PWINE_ACMDRIVERID padid;
749 PWINE_ACMNOTIFYWND panwnd;
751 TRACE("(%p, %08x)\n", hadid, fdwRemove);
753 padid = MSACM_GetDriverID(hadid);
754 panwnd = MSACM_GetNotifyWnd(hadid);
755 if (!padid && !panwnd) {
756 WARN("invalid handle\n");
757 return MMSYSERR_INVALHANDLE;
760 if (fdwRemove) {
761 WARN("invalid flag\n");
762 return MMSYSERR_INVALFLAG;
765 if (padid) MSACM_UnregisterDriver(padid);
766 if (panwnd) MSACM_UnRegisterNotificationWindow(panwnd);
767 MSACM_BroadcastNotification();
769 return MMSYSERR_NOERROR;