dmusic: Avoid swallowing collection Load failures.
[wine.git] / dlls / msacm32 / driver.c
blobc01872d636afa8ca3cb329fb177697b7f014f40c
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, %08Ix, %08lx, %08lx)\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, %08Ix, %08lx, %08lx)\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%08lx 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, %08lx)\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, %08lx)\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, %08lx)\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, %08Ix, %08lx)\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, %08lx)\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, %08Ix, %08Ix\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 LPDRVCONFIGINFOEX 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 pConfigInfo = HeapAlloc(MSACM_hHeap, 0, sizeof(*pConfigInfo));
429 if (!pConfigInfo) {
430 ERR("OOM while supplying DRVCONFIGINFOEX for DRV_CONFIGURE, using NULL\n");
431 } else {
432 /* In some cases (seen in the 32bit world), a DRVCONFIGINFOEX struct is passed
433 * (with extended size) instead of the documented DRVCONFIGINFO.
434 * So, always pass a DRVCONFIGINFOEX to be one the safe side
436 pConfigInfo->dwDCISize = sizeof(*pConfigInfo);
438 section_name = HeapAlloc(MSACM_hHeap, 0, sizeof(L"Drivers32"));
439 if (section_name) lstrcpyW(section_name, L"Drivers32");
440 pConfigInfo->lpszDCISectionName = section_name;
441 alias_name = HeapAlloc(MSACM_hHeap, 0, (lstrlenW(pAlias) + 1) * sizeof(WCHAR));
442 if (alias_name) lstrcpyW(alias_name, pAlias);
443 pConfigInfo->lpszDCIAliasName = alias_name;
444 pConfigInfo->dnDevNode = 0; /* FIXME */
446 if (pConfigInfo->lpszDCISectionName == NULL || pConfigInfo->lpszDCIAliasName == NULL) {
447 HeapFree(MSACM_hHeap, 0, alias_name);
448 HeapFree(MSACM_hHeap, 0, section_name);
449 HeapFree(MSACM_hHeap, 0, pConfigInfo);
450 pConfigInfo = NULL;
451 ERR("OOM while supplying DRVCONFIGINFO for DRV_CONFIGURE, using NULL\n");
456 lParam2 = (LPARAM)pConfigInfo;
459 if (padid) {
460 /* Handle is really an HACMDRIVERID, must have an open session to get an HACMDRIVER */
461 if (padid->pACMDriverList != NULL) {
462 lResult = MSACM_Message((HACMDRIVER)padid->pACMDriverList, uMsg, lParam1, lParam2);
463 } else {
464 MMRESULT mmr = acmDriverOpen(&had, (HACMDRIVERID)padid, 0);
465 if (mmr != MMSYSERR_NOERROR) {
466 lResult = MMSYSERR_INVALPARAM;
467 } else {
468 lResult = acmDriverMessage(had, uMsg, lParam1, lParam2);
469 acmDriverClose(had, 0);
472 } else {
473 lResult = MSACM_Message(had, uMsg, lParam1, lParam2);
475 if (pConfigInfo) {
476 HeapFree(MSACM_hHeap, 0, alias_name);
477 HeapFree(MSACM_hHeap, 0, section_name);
478 HeapFree(MSACM_hHeap, 0, pConfigInfo);
480 return lResult;
482 WARN("invalid parameter\n");
483 return MMSYSERR_INVALPARAM;
486 /***********************************************************************
487 * acmDriverOpen (MSACM32.@)
489 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
491 PWINE_ACMDRIVERID padid;
492 PWINE_ACMDRIVER pad = NULL;
493 MMRESULT ret;
495 TRACE("(%p, %p, %08lu)\n", phad, hadid, fdwOpen);
497 if (!phad) {
498 WARN("invalid parameter\n");
499 return MMSYSERR_INVALPARAM;
502 if (fdwOpen) {
503 WARN("invalid flag\n");
504 return MMSYSERR_INVALFLAG;
507 padid = MSACM_GetDriverID(hadid);
508 if (!padid) {
509 WARN("invalid handle\n");
510 return MMSYSERR_INVALHANDLE;
513 pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
514 if (!pad) {
515 WARN("no memory\n");
516 return MMSYSERR_NOMEM;
519 pad->obj.dwType = WINE_ACMOBJ_DRIVER;
520 pad->obj.pACMDriverID = padid;
521 pad->hDrvr = 0;
522 pad->pLocalDrvrInst = NULL;
524 if (padid->pLocalDriver == NULL)
526 ACMDRVOPENDESCW adod;
527 int len;
528 LPWSTR section_name;
530 /* this is not an externally added driver... need to actually load it */
531 if (!padid->pszDriverAlias)
533 ret = MMSYSERR_ERROR;
534 goto gotError;
537 adod.cbStruct = sizeof(adod);
538 adod.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
539 adod.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
540 adod.dwVersion = acmGetVersion();
541 adod.dwFlags = fdwOpen;
542 adod.dwError = 0;
543 len = strlen("Drivers32") + 1;
544 section_name = HeapAlloc(MSACM_hHeap, 0, len * sizeof(WCHAR));
545 MultiByteToWideChar(CP_ACP, 0, "Drivers32", -1, section_name, len);
546 adod.pszSectionName = section_name;
547 adod.pszAliasName = padid->pszDriverAlias;
548 adod.dnDevNode = 0;
550 pad->hDrvr = OpenDriver(padid->pszDriverAlias, NULL, (DWORD_PTR)&adod);
552 HeapFree(MSACM_hHeap, 0, section_name);
553 if (!pad->hDrvr)
555 ret = adod.dwError;
556 if (ret == MMSYSERR_NOERROR)
557 ret = MMSYSERR_NODRIVER;
558 goto gotError;
561 else
563 ACMDRVOPENDESCW adod;
565 pad->hDrvr = NULL;
567 adod.cbStruct = sizeof(adod);
568 adod.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
569 adod.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
570 adod.dwVersion = acmGetVersion();
571 adod.dwFlags = fdwOpen;
572 adod.dwError = 0;
573 adod.pszSectionName = NULL;
574 adod.pszAliasName = NULL;
575 adod.dnDevNode = 0;
577 pad->pLocalDrvrInst = MSACM_OpenLocalDriver(padid->pLocalDriver, (DWORD_PTR)&adod);
578 if (!pad->pLocalDrvrInst)
580 ret = adod.dwError;
581 if (ret == MMSYSERR_NOERROR)
582 ret = MMSYSERR_NODRIVER;
583 goto gotError;
587 /* insert new pad at beg of list */
588 pad->pNextACMDriver = padid->pACMDriverList;
589 padid->pACMDriverList = pad;
591 /* FIXME: Create a WINE_ACMDRIVER32 */
592 *phad = (HACMDRIVER)pad;
593 TRACE("%s => %p\n", debugstr_w(padid->pszDriverAlias), pad);
595 return MMSYSERR_NOERROR;
596 gotError:
597 WARN("failed: ret = %08x\n", ret);
598 HeapFree(MSACM_hHeap, 0, pad);
599 return ret;
602 /***********************************************************************
603 * acmDriverPriority (MSACM32.@)
605 MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fdwPriority)
608 TRACE("(%p, %08lx, %08lx)\n", hadid, dwPriority, fdwPriority);
610 /* Check for unknown flags */
611 if (fdwPriority &
612 ~(ACM_DRIVERPRIORITYF_ENABLE|ACM_DRIVERPRIORITYF_DISABLE|
613 ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) {
614 WARN("invalid flag\n");
615 return MMSYSERR_INVALFLAG;
618 /* Check for incompatible flags */
619 if ((fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) &&
620 (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE)) {
621 WARN("invalid flag\n");
622 return MMSYSERR_INVALFLAG;
625 /* Check for incompatible flags */
626 if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) &&
627 (fdwPriority & ACM_DRIVERPRIORITYF_END)) {
628 WARN("invalid flag\n");
629 return MMSYSERR_INVALFLAG;
632 /* According to MSDN, ACM_DRIVERPRIORITYF_BEGIN and ACM_DRIVERPRIORITYF_END
633 may only appear by themselves, and in addition, hadid and dwPriority must
634 both be zero */
635 if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) ||
636 (fdwPriority & ACM_DRIVERPRIORITYF_END)) {
637 if (fdwPriority & ~(ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) {
638 WARN("ACM_DRIVERPRIORITYF_[BEGIN|END] cannot be used with any other flags\n");
639 return MMSYSERR_INVALPARAM;
641 if (dwPriority) {
642 WARN("priority invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n");
643 return MMSYSERR_INVALPARAM;
645 if (hadid) {
646 WARN("non-null hadid invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n");
647 return MMSYSERR_INVALPARAM;
649 /* FIXME: MSDN wording suggests that deferred notification should be
650 implemented as a system-wide lock held by a calling task, and that
651 re-enabling notifications should broadcast them across all processes.
652 This implementation uses a simple DWORD counter. One consequence of the
653 current implementation is that applications will never see
654 MMSYSERR_ALLOCATED as a return error.
656 if (fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) {
657 MSACM_DisableNotifications();
658 } else if (fdwPriority & ACM_DRIVERPRIORITYF_END) {
659 MSACM_EnableNotifications();
661 return MMSYSERR_NOERROR;
662 } else {
663 PWINE_ACMDRIVERID padid;
664 PWINE_ACMNOTIFYWND panwnd;
665 BOOL bPerformBroadcast = FALSE;
667 /* Fetch driver ID */
668 padid = MSACM_GetDriverID(hadid);
669 panwnd = MSACM_GetNotifyWnd(hadid);
670 if (!padid && !panwnd) {
671 WARN("invalid handle\n");
672 return MMSYSERR_INVALHANDLE;
675 if (padid) {
676 /* Check whether driver ID is appropriate for requested op */
677 if (dwPriority) {
678 if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL) {
679 return MMSYSERR_NOTSUPPORTED;
681 if (dwPriority != 1 && dwPriority != (DWORD)-1) {
682 FIXME("unexpected priority %ld, using sign only\n", dwPriority);
683 if ((signed)dwPriority < 0) dwPriority = (DWORD)-1;
684 if (dwPriority > 0) dwPriority = 1;
687 if (dwPriority == 1 && (padid->pPrevACMDriverID == NULL ||
688 (padid->pPrevACMDriverID->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL))) {
689 /* do nothing - driver is first of list, or first after last
690 local driver */
691 } else if (dwPriority == (DWORD)-1 && padid->pNextACMDriverID == NULL) {
692 /* do nothing - driver is last of list */
693 } else {
694 MSACM_RePositionDriver(padid, dwPriority);
695 bPerformBroadcast = TRUE;
699 /* Check whether driver ID should be enabled or disabled */
700 if (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE) {
701 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED)) {
702 padid->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
703 bPerformBroadcast = TRUE;
705 } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) {
706 if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
707 padid->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED;
708 bPerformBroadcast = TRUE;
713 if (panwnd) {
714 if (dwPriority) {
715 return MMSYSERR_NOTSUPPORTED;
718 /* Check whether notify window should be enabled or disabled */
719 if (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE) {
720 if (!(panwnd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED)) {
721 panwnd->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
722 bPerformBroadcast = TRUE;
724 } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) {
725 if (panwnd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
726 panwnd->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED;
727 bPerformBroadcast = TRUE;
732 /* Perform broadcast of changes */
733 if (bPerformBroadcast) {
734 MSACM_WriteCurrentPriorities();
735 MSACM_BroadcastNotification();
737 return MMSYSERR_NOERROR;
741 /***********************************************************************
742 * acmDriverRemove (MSACM32.@)
744 MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
746 PWINE_ACMDRIVERID padid;
747 PWINE_ACMNOTIFYWND panwnd;
749 TRACE("(%p, %08lx)\n", hadid, fdwRemove);
751 padid = MSACM_GetDriverID(hadid);
752 panwnd = MSACM_GetNotifyWnd(hadid);
753 if (!padid && !panwnd) {
754 WARN("invalid handle\n");
755 return MMSYSERR_INVALHANDLE;
758 if (fdwRemove) {
759 WARN("invalid flag\n");
760 return MMSYSERR_INVALFLAG;
763 if (padid) MSACM_UnregisterDriver(padid);
764 if (panwnd) MSACM_UnRegisterNotificationWindow(panwnd);
765 MSACM_BroadcastNotification();
767 return MMSYSERR_NOERROR;