msacm: Add support for ACM_METRIC_DRIVER_SUPPORT.
[wine] / dlls / msacm / driver.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winnls.h"
36 #include "winreg.h"
37 #include "mmsystem.h"
38 #include "mmreg.h"
39 #include "msacm.h"
40 #include "msacmdrv.h"
41 #include "wineacm.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
45
46 /***********************************************************************
47  *           acmDriverAddA (MSACM32.@)
48  */
49 MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule,
50                               LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
51 {
52     TRACE("(%p, %p, %08lx, %08lx, %08lx)\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     /* FIXME: in fact, should GetModuleFileName(hinstModule) and do a
76      * LoadDriver on it, to be sure we can call SendDriverMessage on the
77      * hDrvr handle.
78      */
79     *phadid = (HACMDRIVERID) MSACM_RegisterDriver(NULL, NULL, hinstModule);
80
81     /* FIXME: lParam, dwPriority and fdwAdd ignored */
82
83     return MMSYSERR_NOERROR;
84 }
85
86 /***********************************************************************
87  *           acmDriverAddW (MSACM32.@)
88  * FIXME
89  *   Not implemented
90  */
91 MMRESULT WINAPI acmDriverAddW(PHACMDRIVERID phadid, HINSTANCE hinstModule,
92                               LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
93 {
94     FIXME("(%p, %p, %ld, %ld, %ld): stub\n",
95           phadid, hinstModule, lParam, dwPriority, fdwAdd);
96
97     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
98     return MMSYSERR_ERROR;
99 }
100
101 /***********************************************************************
102  *           acmDriverClose (MSACM32.@)
103  */
104 MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
105 {
106     PWINE_ACMDRIVER     pad;
107     PWINE_ACMDRIVERID   padid;
108     PWINE_ACMDRIVER*    tpad;
109
110     TRACE("(%p, %08lx)\n", had, fdwClose);
111
112     if (fdwClose) {
113         WARN("invalid flag\n");
114         return MMSYSERR_INVALFLAG;
115     }
116
117     pad = MSACM_GetDriver(had);
118     if (!pad) {
119         WARN("invalid handle\n");
120         return MMSYSERR_INVALHANDLE;
121     }
122
123     padid = pad->obj.pACMDriverID;
124
125     /* remove driver from list */
126     for (tpad = &(padid->pACMDriverList); *tpad; tpad = &((*tpad)->pNextACMDriver)) {
127         if (*tpad == pad) {
128             *tpad = (*tpad)->pNextACMDriver;
129             break;
130         }
131     }
132
133     /* close driver if it has been opened */
134     if (pad->hDrvr && !padid->hInstModule)
135         CloseDriver(pad->hDrvr, 0, 0);
136
137     HeapFree(MSACM_hHeap, 0, pad);
138
139     return MMSYSERR_NOERROR;
140 }
141
142 /***********************************************************************
143  *           acmDriverDetailsA (MSACM32.@)
144  */
145 MMRESULT WINAPI acmDriverDetailsA(HACMDRIVERID hadid, PACMDRIVERDETAILSA padd, DWORD fdwDetails)
146 {
147     MMRESULT mmr;
148     ACMDRIVERDETAILSW   addw;
149
150     TRACE("(%p, %p, %08lx)\n", hadid, padd, fdwDetails);
151
152     if (!padd) {
153         WARN("invalid parameter\n");
154         return MMSYSERR_INVALPARAM;
155     }
156
157     if (padd->cbStruct < 4) {
158         WARN("invalid parameter\n");
159         return MMSYSERR_INVALPARAM;
160     }
161
162     addw.cbStruct = sizeof(addw);
163     mmr = acmDriverDetailsW(hadid, &addw, fdwDetails);
164     if (mmr == 0) {
165         ACMDRIVERDETAILSA padda;
166
167         padda.fccType = addw.fccType;
168         padda.fccComp = addw.fccComp;
169         padda.wMid = addw.wMid;
170         padda.wPid = addw.wPid;
171         padda.vdwACM = addw.vdwACM;
172         padda.vdwDriver = addw.vdwDriver;
173         padda.fdwSupport = addw.fdwSupport;
174         padda.cFormatTags = addw.cFormatTags;
175         padda.cFilterTags = addw.cFilterTags;
176         padda.hicon = addw.hicon;
177         WideCharToMultiByte( CP_ACP, 0, addw.szShortName, -1, padda.szShortName,
178                              sizeof(padda.szShortName), NULL, NULL );
179         WideCharToMultiByte( CP_ACP, 0, addw.szLongName, -1, padda.szLongName,
180                              sizeof(padda.szLongName), NULL, NULL );
181         WideCharToMultiByte( CP_ACP, 0, addw.szCopyright, -1, padda.szCopyright,
182                              sizeof(padda.szCopyright), NULL, NULL );
183         WideCharToMultiByte( CP_ACP, 0, addw.szLicensing, -1, padda.szLicensing,
184                              sizeof(padda.szLicensing), NULL, NULL );
185         WideCharToMultiByte( CP_ACP, 0, addw.szFeatures, -1, padda.szFeatures,
186                              sizeof(padda.szFeatures), NULL, NULL );
187         padda.cbStruct = min(padd->cbStruct, sizeof(*padd));
188         memcpy(padd, &padda, padda.cbStruct);
189     }
190     return mmr;
191 }
192
193 /***********************************************************************
194  *           acmDriverDetailsW (MSACM32.@)
195  */
196 MMRESULT WINAPI acmDriverDetailsW(HACMDRIVERID hadid, PACMDRIVERDETAILSW padd, DWORD fdwDetails)
197 {
198     HACMDRIVER acmDrvr;
199     MMRESULT mmr;
200
201     TRACE("(%p, %p, %08lx)\n", hadid, padd, fdwDetails);
202
203     if (!padd) {
204         WARN("invalid parameter\n");
205         return MMSYSERR_INVALPARAM;
206     }
207
208     if (padd->cbStruct < 4) {
209         WARN("invalid parameter\n");
210         return MMSYSERR_INVALPARAM;
211     }
212
213     if (fdwDetails) {
214         WARN("invalid flag\n");
215         return MMSYSERR_INVALFLAG;
216     }
217
218     mmr = acmDriverOpen(&acmDrvr, hadid, 0);
219     if (mmr == MMSYSERR_NOERROR) {
220         ACMDRIVERDETAILSW paddw;
221         paddw.cbStruct = sizeof(paddw);
222         mmr = (MMRESULT)MSACM_Message(acmDrvr, ACMDM_DRIVER_DETAILS, (LPARAM)&paddw,  0);
223
224         acmDriverClose(acmDrvr, 0);
225         paddw.cbStruct = min(padd->cbStruct, sizeof(*padd));
226         memcpy(padd, &paddw, paddw.cbStruct);
227     }
228
229     return mmr;
230 }
231
232 /***********************************************************************
233  *           acmDriverEnum (MSACM32.@)
234  */
235 MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum)
236 {
237     PWINE_ACMDRIVERID   padid;
238     DWORD               fdwSupport;
239
240     TRACE("(%p, %08lx, %08lx)\n", fnCallback, dwInstance, fdwEnum);
241
242     if (!fnCallback) {
243         WARN("invalid parameter\n");
244         return MMSYSERR_INVALPARAM;
245     }
246
247     if (fdwEnum & ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) {
248         WARN("invalid flag\n");
249         return MMSYSERR_INVALFLAG;
250     }
251
252     for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
253         fdwSupport = padid->fdwSupport;
254
255         if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) {
256             if (fdwEnum & ACM_DRIVERENUMF_DISABLED)
257                 fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
258             else
259                 continue;
260         }
261         if (!(*fnCallback)((HACMDRIVERID)padid, dwInstance, fdwSupport))
262             break;
263     }
264
265     return MMSYSERR_NOERROR;
266 }
267
268 /***********************************************************************
269  *           acmDriverID (MSACM32.@)
270  */
271 MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID)
272 {
273     PWINE_ACMOBJ pao;
274
275     TRACE("(%p, %p, %08lx)\n", hao, phadid, fdwDriverID);
276
277     if (fdwDriverID) {
278         WARN("invalid flag\n");
279         return MMSYSERR_INVALFLAG;
280     }
281
282     pao = MSACM_GetObj(hao, WINE_ACMOBJ_DONTCARE);
283     if (!pao) {
284         WARN("invalid handle\n");
285         return MMSYSERR_INVALHANDLE;
286     }
287
288     if (!phadid) {
289         WARN("invalid parameter\n");
290         return MMSYSERR_INVALPARAM;
291     }
292
293     *phadid = (HACMDRIVERID) pao->pACMDriverID;
294
295     return MMSYSERR_NOERROR;
296 }
297
298 /***********************************************************************
299  *           acmDriverMessage (MSACM32.@)
300  *
301  */
302 LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
303 {
304     TRACE("(%p, %04x, %08lx, %08lx\n", had, uMsg, lParam1, lParam2);
305
306     if ((uMsg >= ACMDM_USER && uMsg < ACMDM_RESERVED_LOW) ||
307         uMsg == ACMDM_DRIVER_ABOUT ||
308         uMsg == DRV_QUERYCONFIGURE ||
309         uMsg == DRV_CONFIGURE)
310         return MSACM_Message(had, uMsg, lParam1, lParam2);
311
312     WARN("invalid parameter\n");
313     return MMSYSERR_INVALPARAM;
314 }
315
316 /***********************************************************************
317  *           acmDriverOpen (MSACM32.@)
318  */
319 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
320 {
321     PWINE_ACMDRIVERID   padid;
322     PWINE_ACMDRIVER     pad = NULL;
323     MMRESULT            ret;
324
325     TRACE("(%p, %p, %08lu)\n", phad, hadid, fdwOpen);
326
327     if (!phad) {
328         WARN("invalid parameter\n");
329         return MMSYSERR_INVALPARAM;
330     }
331
332     if (fdwOpen) {
333         WARN("invalid flag\n");
334         return MMSYSERR_INVALFLAG;
335     }
336
337     padid = MSACM_GetDriverID(hadid);
338     if (!padid) {
339         WARN("invalid handle\n");
340         return MMSYSERR_INVALHANDLE;
341     }
342
343     pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
344     if (!pad) {
345         WARN("no memory\n");
346         return MMSYSERR_NOMEM;
347     }
348
349     pad->obj.dwType = WINE_ACMOBJ_DRIVER;
350     pad->obj.pACMDriverID = padid;
351
352     if (!(pad->hDrvr = (HDRVR)padid->hInstModule))
353     {
354         ACMDRVOPENDESCW adod;
355         int             len;
356
357         /* this is not an externally added driver... need to actually load it */
358         if (!padid->pszDriverAlias)
359         {
360             ret = MMSYSERR_ERROR;
361             goto gotError;
362         }
363
364         adod.cbStruct = sizeof(adod);
365         adod.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
366         adod.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
367         adod.dwVersion = acmGetVersion();
368         adod.dwFlags = fdwOpen;
369         adod.dwError = 0;
370         len = strlen("Drivers32") + 1;
371         adod.pszSectionName = HeapAlloc(MSACM_hHeap, 0, len * sizeof(WCHAR));
372         MultiByteToWideChar(CP_ACP, 0, "Drivers32", -1, (LPWSTR)adod.pszSectionName, len);
373         adod.pszAliasName = padid->pszDriverAlias;
374         adod.dnDevNode = 0;
375
376         pad->hDrvr = OpenDriver(padid->pszDriverAlias, NULL, (DWORD)&adod);
377
378         HeapFree(MSACM_hHeap, 0, (LPWSTR)adod.pszSectionName);
379         if (!pad->hDrvr)
380         {
381             ret = adod.dwError;
382             goto gotError;
383         }
384     }
385
386     /* insert new pad at beg of list */
387     pad->pNextACMDriver = padid->pACMDriverList;
388     padid->pACMDriverList = pad;
389
390     /* FIXME: Create a WINE_ACMDRIVER32 */
391     *phad = (HACMDRIVER)pad;
392     TRACE("'%s' => %p\n", debugstr_w(padid->pszDriverAlias), pad);
393
394     return MMSYSERR_NOERROR;
395  gotError:
396     WARN("failed: ret = %08x\n", ret);
397     if (pad && !pad->hDrvr)
398         HeapFree(MSACM_hHeap, 0, pad);
399     return ret;
400 }
401
402 /***********************************************************************
403  *           acmDriverPriority (MSACM32.@)
404  */
405 MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fdwPriority)
406 {
407     PWINE_ACMDRIVERID padid;
408     CHAR szSubKey[17];
409     CHAR szBuffer[256];
410     LONG lBufferLength = sizeof(szBuffer);
411     LONG lError;
412     HKEY hPriorityKey;
413     DWORD dwPriorityCounter;
414
415     TRACE("(%p, %08lx, %08lx)\n", hadid, dwPriority, fdwPriority);
416
417     padid = MSACM_GetDriverID(hadid);
418     if (!padid) {
419         WARN("invalid handle\n");
420         return MMSYSERR_INVALHANDLE;
421     }
422
423     /* Check for unknown flags */
424     if (fdwPriority &
425         ~(ACM_DRIVERPRIORITYF_ENABLE|ACM_DRIVERPRIORITYF_DISABLE|
426           ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) {
427         WARN("invalid flag\n");
428         return MMSYSERR_INVALFLAG;
429     }
430
431     /* Check for incompatible flags */
432     if ((fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) &&
433         (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE)) {
434         WARN("invalid flag\n");
435         return MMSYSERR_INVALFLAG;
436     }
437
438     /* Check for incompatible flags */
439     if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) &&
440         (fdwPriority & ACM_DRIVERPRIORITYF_END)) {
441         WARN("invalid flag\n");
442         return MMSYSERR_INVALFLAG;
443     }
444
445     lError = RegOpenKeyA(HKEY_CURRENT_USER,
446                          "Software\\Microsoft\\Multimedia\\"
447                          "Audio Compression Manager\\Priority v4.00",
448                          &hPriorityKey
449                          );
450     /* FIXME: Create key */
451     if (lError != ERROR_SUCCESS) {
452         WARN("RegOpenKeyA failed\n");
453         return MMSYSERR_ERROR;
454     }
455
456     for (dwPriorityCounter = 1; ; dwPriorityCounter++)  {
457         snprintf(szSubKey, 17, "Priority%ld", dwPriorityCounter);
458         lError = RegQueryValueA(hPriorityKey, szSubKey, szBuffer, &lBufferLength);
459         if (lError != ERROR_SUCCESS)
460             break;
461
462         FIXME("(%p, %ld, %ld): stub (partial)\n",
463               hadid, dwPriority, fdwPriority);
464         break;
465     }
466
467     RegCloseKey(hPriorityKey);
468
469     WARN("RegQueryValueA failed\n");
470     return MMSYSERR_ERROR;
471 }
472
473 /***********************************************************************
474  *           acmDriverRemove (MSACM32.@)
475  */
476 MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
477 {
478     PWINE_ACMDRIVERID padid;
479
480     TRACE("(%p, %08lx)\n", hadid, fdwRemove);
481
482     padid = MSACM_GetDriverID(hadid);
483     if (!padid) {
484         WARN("invalid handle\n");
485         return MMSYSERR_INVALHANDLE;
486     }
487
488     if (fdwRemove) {
489         WARN("invalid flag\n");
490         return MMSYSERR_INVALFLAG;
491     }
492
493     MSACM_UnregisterDriver(padid);
494
495     return MMSYSERR_NOERROR;
496 }