user32: Move EnumProps16 to wnd16.c.
[wine] / dlls / msacm32 / format.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  *      MSACM32 library
5  *
6  *      Copyright 1998  Patrik Stridvall
7  *                2000  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 <stdarg.h>
25 #include <string.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winerror.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "mmsystem.h"
35 #include "mmreg.h"
36 #include "msacm.h"
37 #include "msacmdrv.h"
38 #include "wineacm.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
41
42 static  PACMFORMATCHOOSEA       afc;
43
44 struct MSACM_FillFormatData {
45     HWND                hWnd;
46 #define WINE_ACMFF_TAG          0
47 #define WINE_ACMFF_FORMAT       1
48 #define WINE_ACMFF_WFX          2
49     int                 mode;
50     char                szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
51     PACMFORMATCHOOSEA   afc;
52     DWORD               ret;
53 };
54
55 static BOOL CALLBACK MSACM_FillFormatTagsCB(HACMDRIVERID hadid,
56                                             PACMFORMATTAGDETAILSA paftd,
57                                             DWORD_PTR dwInstance,
58                                             DWORD fdwSupport)
59 {
60     struct MSACM_FillFormatData*        affd = (struct MSACM_FillFormatData*)dwInstance;
61
62     switch (affd->mode) {
63     case WINE_ACMFF_TAG:
64         if (SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
65                                 CB_FINDSTRINGEXACT, -1,
66                                 (LPARAM)paftd->szFormatTag) == CB_ERR)
67             SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
68                                 CB_ADDSTRING, 0, (LPARAM)paftd->szFormatTag);
69         break;
70     case WINE_ACMFF_FORMAT:
71         if (strcmp(affd->szFormatTag, paftd->szFormatTag) == 0) {
72             HACMDRIVER          had;
73
74             if (acmDriverOpen(&had, hadid, 0) == MMSYSERR_NOERROR) {
75                 ACMFORMATDETAILSA       afd;
76                unsigned int            i, len;
77                 MMRESULT                mmr;
78                 char                    buffer[ACMFORMATDETAILS_FORMAT_CHARS+16];
79
80                 afd.cbStruct = sizeof(afd);
81                 afd.dwFormatTag = paftd->dwFormatTag;
82                 afd.pwfx = HeapAlloc(MSACM_hHeap, 0, paftd->cbFormatSize);
83                 if (!afd.pwfx) return FALSE;
84                 afd.pwfx->wFormatTag = paftd->dwFormatTag;
85                 afd.pwfx->cbSize = paftd->cbFormatSize;
86                 afd.cbwfx = paftd->cbFormatSize;
87
88                 for (i = 0; i < paftd->cStandardFormats; i++) {
89                     afd.dwFormatIndex = i;
90                     mmr = acmFormatDetailsA(had, &afd, ACM_FORMATDETAILSF_INDEX);
91                     if (mmr == MMSYSERR_NOERROR) {
92                        lstrcpynA(buffer, afd.szFormat, ACMFORMATTAGDETAILS_FORMATTAG_CHARS + 1);
93                        len = strlen(buffer);
94                        memset(buffer+len, ' ', ACMFORMATTAGDETAILS_FORMATTAG_CHARS - len);
95                         wsprintfA(buffer + ACMFORMATTAGDETAILS_FORMATTAG_CHARS,
96                                   "%d Ko/s",
97                                   (afd.pwfx->nAvgBytesPerSec + 512) / 1024);
98                         SendDlgItemMessageA(affd->hWnd,
99                                             IDD_ACMFORMATCHOOSE_CMB_FORMAT,
100                                             CB_ADDSTRING, 0, (LPARAM)buffer);
101                     }
102                 }
103                 acmDriverClose(had, 0);
104                 SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT,
105                                     CB_SETCURSEL, 0, 0);
106                 HeapFree(MSACM_hHeap, 0, afd.pwfx);
107             }
108         }
109         break;
110     case WINE_ACMFF_WFX:
111         if (strcmp(affd->szFormatTag, paftd->szFormatTag) == 0) {
112             HACMDRIVER          had;
113
114             if (acmDriverOpen(&had, hadid, 0) == MMSYSERR_NOERROR) {
115                 ACMFORMATDETAILSA       afd;
116
117                 afd.cbStruct = sizeof(afd);
118                 afd.dwFormatTag = paftd->dwFormatTag;
119                 afd.pwfx = affd->afc->pwfx;
120                 afd.cbwfx = affd->afc->cbwfx;
121
122                 afd.dwFormatIndex = SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT,
123                                                         CB_GETCURSEL, 0, 0);
124                 affd->ret = acmFormatDetailsA(had, &afd, ACM_FORMATDETAILSF_INDEX);
125                 acmDriverClose(had, 0);
126                 return TRUE;
127             }
128         }
129         break;
130     default:
131         FIXME("Unknown mode (%d)\n", affd->mode);
132         break;
133     }
134     return TRUE;
135 }
136
137 static BOOL MSACM_FillFormatTags(HWND hWnd)
138 {
139     ACMFORMATTAGDETAILSA        aftd;
140     struct MSACM_FillFormatData affd;
141
142     memset(&aftd, 0, sizeof(aftd));
143     aftd.cbStruct = sizeof(aftd);
144
145     affd.hWnd = hWnd;
146     affd.mode = WINE_ACMFF_TAG;
147
148     acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
149     SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, CB_SETCURSEL, 0, 0);
150     return TRUE;
151 }
152
153 static BOOL MSACM_FillFormat(HWND hWnd)
154 {
155     ACMFORMATTAGDETAILSA        aftd;
156     struct MSACM_FillFormatData affd;
157
158     SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_RESETCONTENT, 0, 0);
159
160     memset(&aftd, 0, sizeof(aftd));
161     aftd.cbStruct = sizeof(aftd);
162
163     affd.hWnd = hWnd;
164     affd.mode = WINE_ACMFF_FORMAT;
165     SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
166                         CB_GETLBTEXT,
167                         SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
168                                             CB_GETCURSEL, 0, 0),
169                         (LPARAM)affd.szFormatTag);
170
171     acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
172     SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_SETCURSEL, 0, 0);
173     return TRUE;
174 }
175
176 static MMRESULT MSACM_GetWFX(HWND hWnd, PACMFORMATCHOOSEA afc)
177 {
178     ACMFORMATTAGDETAILSA        aftd;
179     struct MSACM_FillFormatData affd;
180
181     memset(&aftd, 0, sizeof(aftd));
182     aftd.cbStruct = sizeof(aftd);
183
184     affd.hWnd = hWnd;
185     affd.mode = WINE_ACMFF_WFX;
186     affd.afc = afc;
187     affd.ret = MMSYSERR_NOERROR;
188     SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
189                         CB_GETLBTEXT,
190                         SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
191                                             CB_GETCURSEL, 0, 0),
192                         (LPARAM)affd.szFormatTag);
193
194     acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
195     return affd.ret;
196 }
197
198 static INT_PTR CALLBACK FormatChooseDlgProc(HWND hWnd, UINT msg,
199                                        WPARAM wParam, LPARAM lParam)
200 {
201
202     TRACE("hwnd=%p msg=%i 0x%08lx 0x%08lx\n", hWnd,  msg, wParam, lParam );
203
204     switch (msg) {
205     case WM_INITDIALOG:
206         afc = (PACMFORMATCHOOSEA)lParam;
207         MSACM_FillFormatTags(hWnd);
208         MSACM_FillFormat(hWnd);
209         if ((afc->fdwStyle & ~(ACMFORMATCHOOSE_STYLEF_CONTEXTHELP|
210                                ACMFORMATCHOOSE_STYLEF_SHOWHELP)) != 0)
211             FIXME("Unsupported style %08x\n", ((PACMFORMATCHOOSEA)lParam)->fdwStyle);
212         if (!(afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_SHOWHELP))
213             ShowWindow(GetDlgItem(hWnd, IDD_ACMFORMATCHOOSE_BTN_HELP), SW_HIDE);
214         return TRUE;
215
216     case WM_COMMAND:
217         switch (LOWORD(wParam)) {
218         case IDOK:
219             EndDialog(hWnd, MSACM_GetWFX(hWnd, afc));
220             return TRUE;
221         case IDCANCEL:
222             EndDialog(hWnd, ACMERR_CANCELED);
223             return TRUE;
224         case IDD_ACMFORMATCHOOSE_CMB_FORMATTAG:
225             switch (HIWORD(wParam)) {
226             case CBN_SELCHANGE:
227                 MSACM_FillFormat(hWnd);
228                 break;
229             default:
230                 TRACE("Dropped dlgNotif (fmtTag): 0x%08x 0x%08lx\n",
231                       HIWORD(wParam), lParam);
232                 break;
233             }
234             break;
235         case IDD_ACMFORMATCHOOSE_BTN_HELP:
236             if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_SHOWHELP)
237                 SendMessageA(afc->hwndOwner,
238                              RegisterWindowMessageA(ACMHELPMSGSTRINGA), 0L, 0L);
239             break;
240
241         default:
242             TRACE("Dropped dlgCmd: ctl=%d ntf=0x%04x 0x%08lx\n",
243                   LOWORD(wParam), HIWORD(wParam), lParam);
244             break;
245         }
246         break;
247     case WM_CONTEXTMENU:
248         if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_CONTEXTHELP)
249             SendMessageA(afc->hwndOwner,
250                          RegisterWindowMessageA(ACMHELPMSGCONTEXTMENUA),
251                          wParam, lParam);
252         break;
253 #if defined(WM_CONTEXTHELP)
254     case WM_CONTEXTHELP:
255         if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_CONTEXTHELP)
256             SendMessageA(afc->hwndOwner,
257                          RegisterWindowMessageA(ACMHELPMSGCONTEXTHELPA),
258                          wParam, lParam);
259         break;
260 #endif
261     default:
262         TRACE("Dropped dlgMsg: hwnd=%p msg=%i 0x%08lx 0x%08lx\n",
263               hWnd,  msg, wParam, lParam );
264         break;
265     }
266     return FALSE;
267 }
268
269 /***********************************************************************
270  *           acmFormatChooseA (MSACM32.@)
271  */
272 MMRESULT WINAPI acmFormatChooseA(PACMFORMATCHOOSEA pafmtc)
273 {
274     return DialogBoxParamA(MSACM_hInstance32, MAKEINTRESOURCEA(DLG_ACMFORMATCHOOSE_ID),
275                            pafmtc->hwndOwner, FormatChooseDlgProc, (LPARAM)pafmtc);
276 }
277
278 /***********************************************************************
279  *           acmFormatChooseW (MSACM32.@)
280  */
281 MMRESULT WINAPI acmFormatChooseW(PACMFORMATCHOOSEW pafmtc)
282 {
283     FIXME("(%p): stub\n", pafmtc);
284     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
285     return MMSYSERR_ERROR;
286 }
287
288 /***********************************************************************
289  *           acmFormatDetailsA (MSACM32.@)
290  */
291 MMRESULT WINAPI acmFormatDetailsA(HACMDRIVER had, PACMFORMATDETAILSA pafd,
292                                   DWORD fdwDetails)
293 {
294     ACMFORMATDETAILSW   afdw;
295     MMRESULT            mmr;
296
297     memset(&afdw, 0, sizeof(afdw));
298     afdw.cbStruct = sizeof(afdw);
299     afdw.dwFormatIndex = pafd->dwFormatIndex;
300     afdw.dwFormatTag = pafd->dwFormatTag;
301     afdw.pwfx = pafd->pwfx;
302     afdw.cbwfx = pafd->cbwfx;
303
304     mmr = acmFormatDetailsW(had, &afdw, fdwDetails);
305     if (mmr == MMSYSERR_NOERROR) {
306         pafd->dwFormatTag = afdw.dwFormatTag;
307         pafd->fdwSupport = afdw.fdwSupport;
308         WideCharToMultiByte( CP_ACP, 0, afdw.szFormat, -1,
309                              pafd->szFormat, sizeof(pafd->szFormat), NULL, NULL );
310     }
311     return mmr;
312 }
313
314 /***********************************************************************
315  *           acmFormatDetailsW (MSACM32.@)
316  */
317 MMRESULT WINAPI acmFormatDetailsW(HACMDRIVER had, PACMFORMATDETAILSW pafd, DWORD fdwDetails)
318 {
319     MMRESULT                    mmr;
320     static const WCHAR          fmt1[] = {'%','d',' ','H','z',0};
321     static const WCHAR          fmt2[] = {';',' ','%','d',' ','b','i','t','s',0};
322     ACMFORMATTAGDETAILSA        aftd;
323
324     TRACE("(%p, %p, %d)\n", had, pafd, fdwDetails);
325
326     memset(&aftd, 0, sizeof(aftd));
327     aftd.cbStruct = sizeof(aftd);
328
329     if (pafd->cbStruct < sizeof(*pafd)) return MMSYSERR_INVALPARAM;
330
331     switch (fdwDetails) {
332     case ACM_FORMATDETAILSF_FORMAT:
333         if (pafd->dwFormatTag != pafd->pwfx->wFormatTag) {
334             mmr = MMSYSERR_INVALPARAM;
335             break;
336         }
337         if (had == NULL) {
338             PWINE_ACMDRIVERID           padid;
339
340             mmr = ACMERR_NOTPOSSIBLE;
341             for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
342                 /* should check for codec only */
343                 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
344                     acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == 0) {
345                     mmr = MSACM_Message(had, ACMDM_FORMAT_DETAILS, (LPARAM)pafd, fdwDetails);
346                     acmDriverClose(had, 0);
347                     if (mmr == MMSYSERR_NOERROR) break;
348                 }
349             }
350         } else {
351             mmr = MSACM_Message(had, ACMDM_FORMAT_DETAILS, (LPARAM)pafd, fdwDetails);
352         }
353         break;
354     case ACM_FORMATDETAILSF_INDEX:
355         /* should check pafd->dwFormatIndex < aftd->cStandardFormats */
356         mmr = MSACM_Message(had, ACMDM_FORMAT_DETAILS, (LPARAM)pafd, fdwDetails);
357         break;
358     default:
359         WARN("Unknown fdwDetails %08x\n", fdwDetails);
360         mmr = MMSYSERR_INVALFLAG;
361         break;
362     }
363
364     if (mmr == MMSYSERR_NOERROR && pafd->szFormat[0] == 0) {
365         wsprintfW(pafd->szFormat, fmt1, pafd->pwfx->nSamplesPerSec);
366         if (pafd->pwfx->wBitsPerSample) {
367             wsprintfW(pafd->szFormat + lstrlenW(pafd->szFormat), fmt2,
368                       pafd->pwfx->wBitsPerSample);
369         }
370         MultiByteToWideChar( CP_ACP, 0, (pafd->pwfx->nChannels == 1) ? "; Mono" : "; Stereo", -1,
371                              pafd->szFormat + strlenW(pafd->szFormat),
372                              sizeof(pafd->szFormat)/sizeof(WCHAR) - strlenW(pafd->szFormat) );
373     }
374
375     TRACE("=> %d\n", mmr);
376     return mmr;
377 }
378
379 struct MSACM_FormatEnumWtoA_Instance {
380     PACMFORMATDETAILSA pafda;
381     DWORD_PTR          dwInstance;
382     ACMFORMATENUMCBA   fnCallback;
383 };
384
385 static BOOL CALLBACK MSACM_FormatEnumCallbackWtoA(HACMDRIVERID hadid,
386                                                   PACMFORMATDETAILSW pafdw,
387                                                   DWORD_PTR dwInstance,
388                                                   DWORD fdwSupport)
389 {
390     struct MSACM_FormatEnumWtoA_Instance* pafei;
391
392     pafei = (struct MSACM_FormatEnumWtoA_Instance*)dwInstance;
393
394     pafei->pafda->dwFormatIndex = pafdw->dwFormatIndex;
395     pafei->pafda->dwFormatTag = pafdw->dwFormatTag;
396     pafei->pafda->fdwSupport = pafdw->fdwSupport;
397     WideCharToMultiByte( CP_ACP, 0, pafdw->szFormat, -1,
398                          pafei->pafda->szFormat, sizeof(pafei->pafda->szFormat), NULL, NULL );
399
400     return (pafei->fnCallback)(hadid, pafei->pafda,
401                                pafei->dwInstance, fdwSupport);
402 }
403
404 /***********************************************************************
405  *           acmFormatEnumA (MSACM32.@)
406  */
407 MMRESULT WINAPI acmFormatEnumA(HACMDRIVER had, PACMFORMATDETAILSA pafda,
408                                ACMFORMATENUMCBA fnCallback,
409                                DWORD_PTR dwInstance, DWORD fdwEnum)
410 {
411     ACMFORMATDETAILSW           afdw;
412     struct MSACM_FormatEnumWtoA_Instance afei;
413
414     if (!pafda)
415         return MMSYSERR_INVALPARAM;
416
417     if (pafda->cbStruct < sizeof(*pafda))
418         return MMSYSERR_INVALPARAM;
419
420     memset(&afdw, 0, sizeof(afdw));
421     afdw.cbStruct = sizeof(afdw);
422     afdw.dwFormatIndex = pafda->dwFormatIndex;
423     afdw.dwFormatTag = pafda->dwFormatTag;
424     afdw.pwfx = pafda->pwfx;
425     afdw.cbwfx = pafda->cbwfx;
426
427     afei.pafda = pafda;
428     afei.dwInstance = dwInstance;
429     afei.fnCallback = fnCallback;
430
431     return acmFormatEnumW(had, &afdw, MSACM_FormatEnumCallbackWtoA,
432                           (DWORD_PTR)&afei, fdwEnum);
433 }
434
435 /***********************************************************************
436  *           acmFormatEnumW (MSACM32.@)
437  */
438 static BOOL MSACM_FormatEnumHelper(PWINE_ACMDRIVERID padid, HACMDRIVER had,
439                                    PACMFORMATDETAILSW pafd, PWAVEFORMATEX pwfxRef,
440                                    ACMFORMATENUMCBW fnCallback,
441                                    DWORD_PTR dwInstance, DWORD fdwEnum)
442 {
443     ACMFORMATTAGDETAILSW        aftd;
444     unsigned int                        i, j;
445
446     if (fdwEnum & ACM_FORMATENUMF_SUGGEST) {
447         HDRVR hdrvr;
448         ACMDRVFORMATSUGGEST adfs;
449         pafd->dwFormatIndex = 0;
450         memset(&aftd, 0, sizeof(aftd));
451         aftd.cbStruct = sizeof(aftd);
452         memset(&adfs, 0, sizeof(adfs));
453         adfs.cbStruct = sizeof(adfs);
454
455         for (i = 0; i < padid->cFormatTags; i++) {
456             aftd.dwFormatTag = i;
457             pafd->dwFormatTag = aftd.dwFormatTag;
458             pafd->pwfx->wFormatTag = pafd->dwFormatTag;
459
460             if (acmFormatTagDetailsW(had, &aftd, ACM_FORMATTAGDETAILSF_INDEX) != MMSYSERR_NOERROR)
461                 continue;
462
463             adfs.cbwfxSrc = aftd.cbFormatSize;
464             adfs.cbwfxDst = aftd.cbFormatSize;
465             adfs.pwfxSrc = pwfxRef;
466             adfs.pwfxDst = pafd->pwfx;
467             pafd->fdwSupport = padid->fdwSupport;
468
469             if ((fdwEnum & ACM_FORMATENUMF_WFORMATTAG) &&
470                 aftd.dwFormatTag != pwfxRef->wFormatTag)
471                 continue;
472
473             if ((fdwEnum & ACM_FORMATENUMF_HARDWARE) &&
474                 !(pafd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_HARDWARE))
475                 continue;
476
477             hdrvr = OpenDriver(padid->pszFileName,0,0);
478             SendDriverMessage(hdrvr,ACMDM_FORMAT_SUGGEST,(LPARAM)&adfs,(fdwEnum & 0x000000FFL));
479
480             if (acmFormatDetailsW(had, pafd, ACM_FORMATDETAILSF_FORMAT) != MMSYSERR_NOERROR)
481                 continue;
482
483             pafd->cbwfx = sizeof(*(pafd->pwfx));
484
485             if (!(fnCallback)((HACMDRIVERID)padid, pafd, dwInstance, padid->fdwSupport))
486                 return FALSE;
487         }
488     } else {
489         for (i = 0; i < padid->cFormatTags; i++) {
490             memset(&aftd, 0, sizeof(aftd));
491             aftd.cbStruct = sizeof(aftd);
492             aftd.dwFormatTagIndex = i;
493             if (acmFormatTagDetailsW(had, &aftd, ACM_FORMATTAGDETAILSF_INDEX) != MMSYSERR_NOERROR)
494                 continue;
495
496             if ((fdwEnum & ACM_FORMATENUMF_WFORMATTAG) && aftd.dwFormatTag != pwfxRef->wFormatTag)
497                 continue;
498
499             for (j = 0; j < aftd.cStandardFormats; j++) {
500                 pafd->dwFormatIndex = j;
501                 pafd->dwFormatTag = aftd.dwFormatTag;
502                 if (acmFormatDetailsW(had, pafd, ACM_FORMATDETAILSF_INDEX) != MMSYSERR_NOERROR)
503                     continue;
504
505                 if ((fdwEnum & ACM_FORMATENUMF_NCHANNELS) &&
506                     pafd->pwfx->nChannels != pwfxRef->nChannels)
507                     continue;
508                 if ((fdwEnum & ACM_FORMATENUMF_NSAMPLESPERSEC) &&
509                     pafd->pwfx->nSamplesPerSec != pwfxRef->nSamplesPerSec)
510                     continue;
511                 if ((fdwEnum & ACM_FORMATENUMF_WBITSPERSAMPLE) &&
512                     pafd->pwfx->wBitsPerSample != pwfxRef->wBitsPerSample)
513                     continue;
514                 if ((fdwEnum & ACM_FORMATENUMF_HARDWARE) &&
515                     !(pafd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_HARDWARE))
516                     continue;
517
518             /* more checks to be done on fdwEnum */
519
520                 if (!(fnCallback)((HACMDRIVERID)padid, pafd, dwInstance, padid->fdwSupport))
521                     return FALSE;
522             }
523         /* the "formats" used by the filters are also reported */
524         }
525     }
526     return TRUE;
527 }
528
529 /**********************************************************************/
530
531 MMRESULT WINAPI acmFormatEnumW(HACMDRIVER had, PACMFORMATDETAILSW pafd,
532                                ACMFORMATENUMCBW fnCallback,
533                                DWORD_PTR dwInstance, DWORD fdwEnum)
534 {
535     PWINE_ACMDRIVERID           padid;
536     WAVEFORMATEX                wfxRef;
537     BOOL                        ret;
538
539     TRACE("(%p, %p, %p, %ld, %d)\n",
540           had, pafd, fnCallback, dwInstance, fdwEnum);
541
542     if (!pafd)
543         return MMSYSERR_INVALPARAM;
544
545     if (pafd->cbStruct < sizeof(*pafd))
546         return MMSYSERR_INVALPARAM;
547
548     if (fdwEnum & (ACM_FORMATENUMF_WFORMATTAG|ACM_FORMATENUMF_NCHANNELS|
549                    ACM_FORMATENUMF_NSAMPLESPERSEC|ACM_FORMATENUMF_WBITSPERSAMPLE|
550                    ACM_FORMATENUMF_CONVERT|ACM_FORMATENUMF_SUGGEST))
551         wfxRef = *pafd->pwfx;
552
553     if ((fdwEnum & ACM_FORMATENUMF_HARDWARE) &&
554         !(fdwEnum & (ACM_FORMATENUMF_INPUT|ACM_FORMATENUMF_OUTPUT)))
555         return MMSYSERR_INVALPARAM;
556
557     if ((fdwEnum & ACM_FORMATENUMF_WFORMATTAG) &&
558         (pafd->dwFormatTag != pafd->pwfx->wFormatTag))
559         return MMSYSERR_INVALPARAM;
560
561     if (fdwEnum & (ACM_FORMATENUMF_CONVERT|ACM_FORMATENUMF_INPUT|ACM_FORMATENUMF_OUTPUT))
562         FIXME("Unsupported fdwEnum values %08x\n", fdwEnum);
563
564     if (had) {
565         HACMDRIVERID    hadid;
566
567         if (acmDriverID((HACMOBJ)had, &hadid, 0) != MMSYSERR_NOERROR)
568             return MMSYSERR_INVALHANDLE;
569         MSACM_FormatEnumHelper(MSACM_GetDriverID(hadid), had, pafd, &wfxRef,
570                                fnCallback, dwInstance, fdwEnum);
571         return MMSYSERR_NOERROR;
572     }
573     for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
574             /* should check for codec only */
575             if ((padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
576                 acmDriverOpen(&had, (HACMDRIVERID)padid, 0) != MMSYSERR_NOERROR)
577                 continue;
578             ret = MSACM_FormatEnumHelper(padid, had, pafd, &wfxRef,
579                                          fnCallback, dwInstance, fdwEnum);
580             acmDriverClose(had, 0);
581             if (!ret) break;
582     }
583     return MMSYSERR_NOERROR;
584 }
585
586 /***********************************************************************
587  *           acmFormatSuggest (MSACM32.@)
588  */
589 MMRESULT WINAPI acmFormatSuggest(HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
590                                  PWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest)
591 {
592     ACMDRVFORMATSUGGEST adfg;
593     MMRESULT            mmr;
594
595     TRACE("(%p, %p, %p, %d, %d)\n",
596           had, pwfxSrc, pwfxDst, cbwfxDst, fdwSuggest);
597
598     if (fdwSuggest & ~(ACM_FORMATSUGGESTF_NCHANNELS|ACM_FORMATSUGGESTF_NSAMPLESPERSEC|
599                        ACM_FORMATSUGGESTF_WBITSPERSAMPLE|ACM_FORMATSUGGESTF_WFORMATTAG))
600         return MMSYSERR_INVALFLAG;
601
602     adfg.cbStruct = sizeof(adfg);
603     adfg.fdwSuggest = fdwSuggest;
604     adfg.pwfxSrc = pwfxSrc;
605     adfg.cbwfxSrc = (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) ?
606         sizeof(WAVEFORMATEX) : (sizeof(WAVEFORMATEX) + pwfxSrc->cbSize);
607     adfg.pwfxDst = pwfxDst;
608     adfg.cbwfxDst = cbwfxDst;
609
610     if (had == NULL) {
611         PWINE_ACMDRIVERID       padid;
612
613         /* MS doc says: ACM finds the best suggestion.
614          * Well, first found will be the "best"
615          */
616         mmr = ACMERR_NOTPOSSIBLE;
617         for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
618             /* should check for codec only */
619             if ((padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
620                 acmDriverOpen(&had, (HACMDRIVERID)padid, 0) != MMSYSERR_NOERROR)
621                 continue;
622
623             if (MSACM_Message(had, ACMDM_FORMAT_SUGGEST, (LPARAM)&adfg, 0L) == MMSYSERR_NOERROR) {
624                 mmr = MMSYSERR_NOERROR;
625                 break;
626             }
627             acmDriverClose(had, 0);
628         }
629     } else {
630         mmr = MSACM_Message(had, ACMDM_FORMAT_SUGGEST, (LPARAM)&adfg, 0L);
631     }
632     return mmr;
633 }
634
635 /***********************************************************************
636  *           acmFormatTagDetailsA (MSACM32.@)
637  */
638 MMRESULT WINAPI acmFormatTagDetailsA(HACMDRIVER had, PACMFORMATTAGDETAILSA paftda,
639                                      DWORD fdwDetails)
640 {
641     ACMFORMATTAGDETAILSW        aftdw;
642     MMRESULT                    mmr;
643
644     memset(&aftdw, 0, sizeof(aftdw));
645     aftdw.cbStruct = sizeof(aftdw);
646     aftdw.dwFormatTagIndex = paftda->dwFormatTagIndex;
647     aftdw.dwFormatTag = paftda->dwFormatTag;
648
649     mmr = acmFormatTagDetailsW(had, &aftdw, fdwDetails);
650     if (mmr == MMSYSERR_NOERROR) {
651         paftda->dwFormatTag = aftdw.dwFormatTag;
652         paftda->dwFormatTagIndex = aftdw.dwFormatTagIndex;
653         paftda->cbFormatSize = aftdw.cbFormatSize;
654         paftda->fdwSupport = aftdw.fdwSupport;
655         paftda->cStandardFormats = aftdw.cStandardFormats;
656         WideCharToMultiByte( CP_ACP, 0, aftdw.szFormatTag, -1, paftda->szFormatTag,
657                              sizeof(paftda->szFormatTag), NULL, NULL );
658     }
659     return mmr;
660 }
661
662 /***********************************************************************
663  *           acmFormatTagDetailsW (MSACM32.@)
664  */
665 MMRESULT WINAPI acmFormatTagDetailsW(HACMDRIVER had, PACMFORMATTAGDETAILSW paftd,
666                                      DWORD fdwDetails)
667 {
668     PWINE_ACMDRIVERID   padid;
669     MMRESULT            mmr = ACMERR_NOTPOSSIBLE;
670
671     TRACE("(%p, %p, %d)\n", had, paftd, fdwDetails);
672
673     if (fdwDetails & ~(ACM_FORMATTAGDETAILSF_FORMATTAG|ACM_FORMATTAGDETAILSF_INDEX|
674                        ACM_FORMATTAGDETAILSF_LARGESTSIZE))
675         return MMSYSERR_INVALFLAG;
676
677     switch (fdwDetails) {
678     case ACM_FORMATTAGDETAILSF_FORMATTAG:
679         if (had == NULL) {
680             for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
681                 /* should check for codec only */
682                 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
683                     MSACM_FindFormatTagInCache(padid, paftd->dwFormatTag, NULL) &&
684                     acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == 0) {
685                     mmr = MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)paftd, fdwDetails);
686                     acmDriverClose(had, 0);
687                     if (mmr == MMSYSERR_NOERROR) break;
688                 }
689             }
690         } else {
691             PWINE_ACMDRIVER     pad = MSACM_GetDriver(had);
692
693             if (pad && MSACM_FindFormatTagInCache(pad->obj.pACMDriverID, paftd->dwFormatTag, NULL))
694                 mmr = MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)paftd, fdwDetails);
695         }
696         break;
697
698     case ACM_FORMATTAGDETAILSF_INDEX:
699         if (had != NULL) {
700             PWINE_ACMDRIVER     pad = MSACM_GetDriver(had);
701
702             if (pad && paftd->dwFormatTagIndex < pad->obj.pACMDriverID->cFormatTags)
703                 mmr = MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)paftd, fdwDetails);
704         }
705         break;
706
707     case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
708         if (had == NULL) {
709             ACMFORMATTAGDETAILSW        tmp;
710             DWORD                       ft = paftd->dwFormatTag;
711
712             for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
713                 /* should check for codec only */
714                 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
715                     acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == 0) {
716
717                     memset(&tmp, 0, sizeof(tmp));
718                     tmp.cbStruct = sizeof(tmp);
719                     tmp.dwFormatTag = ft;
720
721                     if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
722                                       (LPARAM)&tmp, fdwDetails) == MMSYSERR_NOERROR) {
723                         if (mmr == ACMERR_NOTPOSSIBLE ||
724                             paftd->cbFormatSize < tmp.cbFormatSize) {
725                             *paftd = tmp;
726                             mmr = MMSYSERR_NOERROR;
727                         }
728                     }
729                     acmDriverClose(had, 0);
730                 }
731             }
732         } else {
733             mmr = MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)paftd, fdwDetails);
734         }
735         break;
736
737     default:
738         WARN("Unsupported fdwDetails=%08x\n", fdwDetails);
739         mmr = MMSYSERR_ERROR;
740     }
741
742     if (mmr == MMSYSERR_NOERROR &&
743         paftd->dwFormatTag == WAVE_FORMAT_PCM && paftd->szFormatTag[0] == 0)
744         MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
745                              sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
746
747     return mmr;
748 }
749
750 struct MSACM_FormatTagEnumWtoA_Instance {
751     PACMFORMATTAGDETAILSA paftda;
752     DWORD_PTR             dwInstance;
753     ACMFORMATTAGENUMCBA   fnCallback;
754 };
755
756 static BOOL CALLBACK MSACM_FormatTagEnumCallbackWtoA(HACMDRIVERID hadid,
757                                                      PACMFORMATTAGDETAILSW paftdw,
758                                                      DWORD_PTR dwInstance,
759                                                      DWORD fdwSupport)
760 {
761     struct MSACM_FormatTagEnumWtoA_Instance* paftei;
762
763     paftei = (struct MSACM_FormatTagEnumWtoA_Instance*)dwInstance;
764
765     paftei->paftda->dwFormatTagIndex = paftdw->dwFormatTagIndex;
766     paftei->paftda->dwFormatTag = paftdw->dwFormatTag;
767     paftei->paftda->cbFormatSize = paftdw->cbFormatSize;
768     paftei->paftda->fdwSupport = paftdw->fdwSupport;
769     paftei->paftda->cStandardFormats = paftdw->cStandardFormats;
770     WideCharToMultiByte( CP_ACP, 0, paftdw->szFormatTag, -1, paftei->paftda->szFormatTag,
771                          sizeof(paftei->paftda->szFormatTag), NULL, NULL );
772
773     return (paftei->fnCallback)(hadid, paftei->paftda,
774                                 paftei->dwInstance, fdwSupport);
775 }
776
777 /***********************************************************************
778  *           acmFormatTagEnumA (MSACM32.@)
779  */
780 MMRESULT WINAPI acmFormatTagEnumA(HACMDRIVER had, PACMFORMATTAGDETAILSA paftda,
781                                   ACMFORMATTAGENUMCBA fnCallback,
782                                   DWORD_PTR dwInstance, DWORD fdwEnum)
783 {
784     ACMFORMATTAGDETAILSW        aftdw;
785     struct MSACM_FormatTagEnumWtoA_Instance aftei;
786
787     if (!paftda)
788         return MMSYSERR_INVALPARAM;
789
790     if (paftda->cbStruct < sizeof(*paftda))
791         return MMSYSERR_INVALPARAM;
792
793     if (fdwEnum != 0)
794         return MMSYSERR_INVALFLAG;
795
796     memset(&aftdw, 0, sizeof(aftdw));
797     aftdw.cbStruct = sizeof(aftdw);
798     aftdw.dwFormatTagIndex = paftda->dwFormatTagIndex;
799     aftdw.dwFormatTag = paftda->dwFormatTag;
800
801     aftei.paftda = paftda;
802     aftei.dwInstance = dwInstance;
803     aftei.fnCallback = fnCallback;
804
805     return acmFormatTagEnumW(had, &aftdw, MSACM_FormatTagEnumCallbackWtoA,
806                              (DWORD_PTR)&aftei, fdwEnum);
807 }
808
809 /***********************************************************************
810  *           acmFormatTagEnumW (MSACM32.@)
811  */
812 MMRESULT WINAPI acmFormatTagEnumW(HACMDRIVER had, PACMFORMATTAGDETAILSW paftd,
813                                   ACMFORMATTAGENUMCBW fnCallback,
814                                   DWORD_PTR dwInstance, DWORD fdwEnum)
815 {
816     PWINE_ACMDRIVERID           padid;
817     unsigned int                        i;
818     BOOL                        bPcmDone = FALSE;
819
820     TRACE("(%p, %p, %p, %ld, %d)\n",
821           had, paftd, fnCallback, dwInstance, fdwEnum);
822
823     if (!paftd)
824         return MMSYSERR_INVALPARAM;
825
826     if (paftd->cbStruct < sizeof(*paftd))
827         return MMSYSERR_INVALPARAM;
828
829     if (fdwEnum != 0)
830         return MMSYSERR_INVALFLAG;
831
832     /* (WS) MSDN info page says that if had != 0, then we should find
833      * the specific driver to get its tags from. Therefore I'm removing
834      * the FIXME call and adding a search block below. It also seems
835      * that the lack of this functionality was the responsible for 
836      * codecs to be multiply and incorrectly listed. 
837      */
838
839     /* if (had) FIXME("had != NULL, not supported\n"); */
840
841     if (had) {
842
843        if (acmDriverID((HACMOBJ)had, (HACMDRIVERID *)&padid, 0) != MMSYSERR_NOERROR)
844           return MMSYSERR_INVALHANDLE;
845
846        for (i = 0; i < padid->cFormatTags; i++) {
847           paftd->dwFormatTagIndex = i;
848           if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
849           (LPARAM)paftd, ACM_FORMATTAGDETAILSF_INDEX) == MMSYSERR_NOERROR) {
850              if (paftd->dwFormatTag == WAVE_FORMAT_PCM) {
851                 if (paftd->szFormatTag[0] == 0)
852                    MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
853                          sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
854                 /* (WS) I'm preserving this PCM hack since it seems to be
855                  * correct. Please notice this block was borrowed from
856                  * below.
857                  */
858                 if (bPcmDone) continue;
859                    bPcmDone = TRUE;
860              }
861              if (!(fnCallback)((HACMDRIVERID)padid, paftd, dwInstance, padid->fdwSupport)) 
862                 return MMSYSERR_NOERROR;
863           }
864        }
865
866     }
867
868     /* if had==0 then search for the first suitable driver */
869     else {
870        for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
871           /* should check for codec only */
872           if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
873              acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == MMSYSERR_NOERROR) {
874              for (i = 0; i < padid->cFormatTags; i++) {
875                 paftd->dwFormatTagIndex = i;
876                 if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
877                    (LPARAM)paftd, ACM_FORMATTAGDETAILSF_INDEX) == MMSYSERR_NOERROR) {
878                    if (paftd->dwFormatTag == WAVE_FORMAT_PCM) {
879                       if (paftd->szFormatTag[0] == 0)
880                          MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
881                                  sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
882                       /* FIXME (EPP): I'm not sure this is the correct
883                        * algorithm (should make more sense to apply the same
884                        * for all already loaded formats, but this will do
885                        * for now
886                        */
887                       if (bPcmDone) continue;
888                          bPcmDone = TRUE;
889                    }
890                    if (!(fnCallback)((HACMDRIVERID)padid, paftd, dwInstance, padid->fdwSupport)) {
891                       acmDriverClose(had, 0);
892                       return MMSYSERR_NOERROR;
893                    }
894                 }
895              }
896           }
897           acmDriverClose(had, 0);
898        }
899     }
900     return MMSYSERR_NOERROR;
901 }