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