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