advapi32: Fix the failing QueryServiceConfig2 test on platforms win2k3 and vista.
[wine/multimedia.git] / dlls / msacm32 / format.c
bloba6fd57aa372ff5080a03721a50f71b2bdc5df0cb
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MSACM32 library
6 * Copyright 1998 Patrik Stridvall
7 * 2000 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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"
40 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
42 static PACMFORMATCHOOSEA afc;
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;
55 static BOOL CALLBACK MSACM_FillFormatTagsCB(HACMDRIVERID hadid,
56 PACMFORMATTAGDETAILSA paftd,
57 DWORD dwInstance, DWORD fdwSupport)
59 struct MSACM_FillFormatData* affd = (struct MSACM_FillFormatData*)dwInstance;
61 switch (affd->mode) {
62 case WINE_ACMFF_TAG:
63 if (SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
64 CB_FINDSTRINGEXACT,
65 (WPARAM)-1, (LPARAM)paftd->szFormatTag) == CB_ERR)
66 SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
67 CB_ADDSTRING, 0, (DWORD)paftd->szFormatTag);
68 break;
69 case WINE_ACMFF_FORMAT:
70 if (strcmp(affd->szFormatTag, paftd->szFormatTag) == 0) {
71 HACMDRIVER had;
73 if (acmDriverOpen(&had, hadid, 0) == MMSYSERR_NOERROR) {
74 ACMFORMATDETAILSA afd;
75 unsigned int i, len;
76 MMRESULT mmr;
77 char buffer[ACMFORMATDETAILS_FORMAT_CHARS+16];
79 afd.cbStruct = sizeof(afd);
80 afd.dwFormatTag = paftd->dwFormatTag;
81 afd.pwfx = HeapAlloc(MSACM_hHeap, 0, paftd->cbFormatSize);
82 if (!afd.pwfx) return FALSE;
83 afd.pwfx->wFormatTag = paftd->dwFormatTag;
84 afd.pwfx->cbSize = paftd->cbFormatSize;
85 afd.cbwfx = paftd->cbFormatSize;
87 for (i = 0; i < paftd->cStandardFormats; i++) {
88 afd.dwFormatIndex = i;
89 mmr = acmFormatDetailsA(had, &afd, ACM_FORMATDETAILSF_INDEX);
90 if (mmr == MMSYSERR_NOERROR) {
91 lstrcpynA(buffer, afd.szFormat, ACMFORMATTAGDETAILS_FORMATTAG_CHARS + 1);
92 len = strlen(buffer);
93 memset(buffer+len, ' ', ACMFORMATTAGDETAILS_FORMATTAG_CHARS - len);
94 wsprintfA(buffer + ACMFORMATTAGDETAILS_FORMATTAG_CHARS,
95 "%d Ko/s",
96 (afd.pwfx->nAvgBytesPerSec + 512) / 1024);
97 SendDlgItemMessageA(affd->hWnd,
98 IDD_ACMFORMATCHOOSE_CMB_FORMAT,
99 CB_ADDSTRING, 0, (DWORD)buffer);
102 acmDriverClose(had, 0);
103 SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT,
104 CB_SETCURSEL, 0, 0);
105 HeapFree(MSACM_hHeap, 0, afd.pwfx);
108 break;
109 case WINE_ACMFF_WFX:
110 if (strcmp(affd->szFormatTag, paftd->szFormatTag) == 0) {
111 HACMDRIVER had;
113 if (acmDriverOpen(&had, hadid, 0) == MMSYSERR_NOERROR) {
114 ACMFORMATDETAILSA afd;
116 afd.cbStruct = sizeof(afd);
117 afd.dwFormatTag = paftd->dwFormatTag;
118 afd.pwfx = affd->afc->pwfx;
119 afd.cbwfx = affd->afc->cbwfx;
121 afd.dwFormatIndex = SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT,
122 CB_GETCURSEL, 0, 0);
123 affd->ret = acmFormatDetailsA(had, &afd, ACM_FORMATDETAILSF_INDEX);
124 acmDriverClose(had, 0);
125 return TRUE;
128 break;
129 default:
130 FIXME("Unknown mode (%d)\n", affd->mode);
131 break;
133 return TRUE;
136 static BOOL MSACM_FillFormatTags(HWND hWnd)
138 ACMFORMATTAGDETAILSA aftd;
139 struct MSACM_FillFormatData affd;
141 memset(&aftd, 0, sizeof(aftd));
142 aftd.cbStruct = sizeof(aftd);
144 affd.hWnd = hWnd;
145 affd.mode = WINE_ACMFF_TAG;
147 acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD)&affd, 0);
148 SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, CB_SETCURSEL, 0, 0);
149 return TRUE;
152 static BOOL MSACM_FillFormat(HWND hWnd)
154 ACMFORMATTAGDETAILSA aftd;
155 struct MSACM_FillFormatData affd;
157 SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_RESETCONTENT, 0, 0);
159 memset(&aftd, 0, sizeof(aftd));
160 aftd.cbStruct = sizeof(aftd);
162 affd.hWnd = hWnd;
163 affd.mode = WINE_ACMFF_FORMAT;
164 SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
165 CB_GETLBTEXT,
166 SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
167 CB_GETCURSEL, 0, 0),
168 (DWORD)affd.szFormatTag);
170 acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD)&affd, 0);
171 SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_SETCURSEL, 0, 0);
172 return TRUE;
175 static MMRESULT MSACM_GetWFX(HWND hWnd, PACMFORMATCHOOSEA afc)
177 ACMFORMATTAGDETAILSA aftd;
178 struct MSACM_FillFormatData affd;
180 memset(&aftd, 0, sizeof(aftd));
181 aftd.cbStruct = sizeof(aftd);
183 affd.hWnd = hWnd;
184 affd.mode = WINE_ACMFF_WFX;
185 affd.afc = afc;
186 affd.ret = MMSYSERR_NOERROR;
187 SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
188 CB_GETLBTEXT,
189 SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
190 CB_GETCURSEL, 0, 0),
191 (DWORD)affd.szFormatTag);
193 acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD)&affd, 0);
194 return affd.ret;
197 static INT_PTR CALLBACK FormatChooseDlgProc(HWND hWnd, UINT msg,
198 WPARAM wParam, LPARAM lParam)
201 TRACE("hwnd=%p msg=%i 0x%08lx 0x%08lx\n", hWnd, msg, wParam, lParam );
203 switch (msg) {
204 case WM_INITDIALOG:
205 afc = (PACMFORMATCHOOSEA)lParam;
206 MSACM_FillFormatTags(hWnd);
207 MSACM_FillFormat(hWnd);
208 if ((afc->fdwStyle & ~(ACMFORMATCHOOSE_STYLEF_CONTEXTHELP|
209 ACMFORMATCHOOSE_STYLEF_SHOWHELP)) != 0)
210 FIXME("Unsupported style %08x\n", ((PACMFORMATCHOOSEA)lParam)->fdwStyle);
211 if (!(afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_SHOWHELP))
212 ShowWindow(GetDlgItem(hWnd, IDD_ACMFORMATCHOOSE_BTN_HELP), SW_HIDE);
213 return TRUE;
215 case WM_COMMAND:
216 switch (LOWORD(wParam)) {
217 case IDOK:
218 EndDialog(hWnd, MSACM_GetWFX(hWnd, afc));
219 return TRUE;
220 case IDCANCEL:
221 EndDialog(hWnd, ACMERR_CANCELED);
222 return TRUE;
223 case IDD_ACMFORMATCHOOSE_CMB_FORMATTAG:
224 switch (HIWORD(wParam)) {
225 case CBN_SELCHANGE:
226 MSACM_FillFormat(hWnd);
227 break;
228 default:
229 TRACE("Dropped dlgNotif (fmtTag): 0x%08x 0x%08lx\n",
230 HIWORD(wParam), lParam);
231 break;
233 break;
234 case IDD_ACMFORMATCHOOSE_BTN_HELP:
235 if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_SHOWHELP)
236 SendMessageA(afc->hwndOwner,
237 RegisterWindowMessageA(ACMHELPMSGSTRINGA), 0L, 0L);
238 break;
240 default:
241 TRACE("Dropped dlgCmd: ctl=%d ntf=0x%04x 0x%08lx\n",
242 LOWORD(wParam), HIWORD(wParam), lParam);
243 break;
245 break;
246 case WM_CONTEXTMENU:
247 if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_CONTEXTHELP)
248 SendMessageA(afc->hwndOwner,
249 RegisterWindowMessageA(ACMHELPMSGCONTEXTMENUA),
250 wParam, lParam);
251 break;
252 #if defined(WM_CONTEXTHELP)
253 case WM_CONTEXTHELP:
254 if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_CONTEXTHELP)
255 SendMessageA(afc->hwndOwner,
256 RegisterWindowMessageA(ACMHELPMSGCONTEXTHELPA),
257 wParam, lParam);
258 break;
259 #endif
260 default:
261 TRACE("Dropped dlgMsg: hwnd=%p msg=%i 0x%08lx 0x%08lx\n",
262 hWnd, msg, wParam, lParam );
263 break;
265 return FALSE;
268 /***********************************************************************
269 * acmFormatChooseA (MSACM32.@)
271 MMRESULT WINAPI acmFormatChooseA(PACMFORMATCHOOSEA pafmtc)
273 return DialogBoxParamA(MSACM_hInstance32, MAKEINTRESOURCEA(DLG_ACMFORMATCHOOSE_ID),
274 pafmtc->hwndOwner, FormatChooseDlgProc, (LPARAM)pafmtc);
277 /***********************************************************************
278 * acmFormatChooseW (MSACM32.@)
280 MMRESULT WINAPI acmFormatChooseW(PACMFORMATCHOOSEW pafmtc)
282 FIXME("(%p): stub\n", pafmtc);
283 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
284 return MMSYSERR_ERROR;
287 /***********************************************************************
288 * acmFormatDetailsA (MSACM32.@)
290 MMRESULT WINAPI acmFormatDetailsA(HACMDRIVER had, PACMFORMATDETAILSA pafd,
291 DWORD fdwDetails)
293 ACMFORMATDETAILSW afdw;
294 MMRESULT mmr;
296 memset(&afdw, 0, sizeof(afdw));
297 afdw.cbStruct = sizeof(afdw);
298 afdw.dwFormatIndex = pafd->dwFormatIndex;
299 afdw.dwFormatTag = pafd->dwFormatTag;
300 afdw.pwfx = pafd->pwfx;
301 afdw.cbwfx = pafd->cbwfx;
303 mmr = acmFormatDetailsW(had, &afdw, fdwDetails);
304 if (mmr == MMSYSERR_NOERROR) {
305 pafd->dwFormatTag = afdw.dwFormatTag;
306 pafd->fdwSupport = afdw.fdwSupport;
307 WideCharToMultiByte( CP_ACP, 0, afdw.szFormat, -1,
308 pafd->szFormat, sizeof(pafd->szFormat), NULL, NULL );
310 return mmr;
313 /***********************************************************************
314 * acmFormatDetailsW (MSACM32.@)
316 MMRESULT WINAPI acmFormatDetailsW(HACMDRIVER had, PACMFORMATDETAILSW pafd, DWORD fdwDetails)
318 MMRESULT mmr;
319 static const WCHAR fmt1[] = {'%','d',' ','H','z',0};
320 static const WCHAR fmt2[] = {';',' ','%','d',' ','b','i','t','s',0};
321 ACMFORMATTAGDETAILSA aftd;
323 TRACE("(%p, %p, %d)\n", had, pafd, fdwDetails);
325 memset(&aftd, 0, sizeof(aftd));
326 aftd.cbStruct = sizeof(aftd);
328 if (pafd->cbStruct < sizeof(*pafd)) return MMSYSERR_INVALPARAM;
330 switch (fdwDetails) {
331 case ACM_FORMATDETAILSF_FORMAT:
332 if (pafd->dwFormatTag != pafd->pwfx->wFormatTag) {
333 mmr = MMSYSERR_INVALPARAM;
334 break;
336 if (had == NULL) {
337 PWINE_ACMDRIVERID padid;
339 mmr = ACMERR_NOTPOSSIBLE;
340 for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
341 /* should check for codec only */
342 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
343 acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == 0) {
344 mmr = MSACM_Message(had, ACMDM_FORMAT_DETAILS, (LPARAM)pafd, fdwDetails);
345 acmDriverClose(had, 0);
346 if (mmr == MMSYSERR_NOERROR) break;
349 } else {
350 mmr = MSACM_Message(had, ACMDM_FORMAT_DETAILS, (LPARAM)pafd, fdwDetails);
352 break;
353 case ACM_FORMATDETAILSF_INDEX:
354 /* should check pafd->dwFormatIndex < aftd->cStandardFormats */
355 mmr = MSACM_Message(had, ACMDM_FORMAT_DETAILS, (LPARAM)pafd, fdwDetails);
356 break;
357 default:
358 WARN("Unknown fdwDetails %08x\n", fdwDetails);
359 mmr = MMSYSERR_INVALFLAG;
360 break;
363 if (mmr == MMSYSERR_NOERROR && pafd->szFormat[0] == (WCHAR)0) {
364 wsprintfW(pafd->szFormat, fmt1, pafd->pwfx->nSamplesPerSec);
365 if (pafd->pwfx->wBitsPerSample) {
366 wsprintfW(pafd->szFormat + lstrlenW(pafd->szFormat), fmt2,
367 pafd->pwfx->wBitsPerSample);
369 MultiByteToWideChar( CP_ACP, 0, (pafd->pwfx->nChannels == 1) ? "; Mono" : "; Stereo", -1,
370 pafd->szFormat + strlenW(pafd->szFormat),
371 sizeof(pafd->szFormat)/sizeof(WCHAR) - strlenW(pafd->szFormat) );
374 TRACE("=> %d\n", mmr);
375 return mmr;
378 struct MSACM_FormatEnumWtoA_Instance {
379 PACMFORMATDETAILSA pafda;
380 DWORD dwInstance;
381 ACMFORMATENUMCBA fnCallback;
384 static BOOL CALLBACK MSACM_FormatEnumCallbackWtoA(HACMDRIVERID hadid,
385 PACMFORMATDETAILSW pafdw,
386 DWORD dwInstance,
387 DWORD fdwSupport)
389 struct MSACM_FormatEnumWtoA_Instance* pafei;
391 pafei = (struct MSACM_FormatEnumWtoA_Instance*)dwInstance;
393 pafei->pafda->dwFormatIndex = pafdw->dwFormatIndex;
394 pafei->pafda->dwFormatTag = pafdw->dwFormatTag;
395 pafei->pafda->fdwSupport = pafdw->fdwSupport;
396 WideCharToMultiByte( CP_ACP, 0, pafdw->szFormat, -1,
397 pafei->pafda->szFormat, sizeof(pafei->pafda->szFormat), NULL, NULL );
399 return (pafei->fnCallback)(hadid, pafei->pafda,
400 pafei->dwInstance, fdwSupport);
403 /***********************************************************************
404 * acmFormatEnumA (MSACM32.@)
406 MMRESULT WINAPI acmFormatEnumA(HACMDRIVER had, PACMFORMATDETAILSA pafda,
407 ACMFORMATENUMCBA fnCallback, DWORD dwInstance,
408 DWORD fdwEnum)
410 ACMFORMATDETAILSW afdw;
411 struct MSACM_FormatEnumWtoA_Instance afei;
413 if (!pafda)
414 return MMSYSERR_INVALPARAM;
416 if (pafda->cbStruct < sizeof(*pafda))
417 return MMSYSERR_INVALPARAM;
419 memset(&afdw, 0, sizeof(afdw));
420 afdw.cbStruct = sizeof(afdw);
421 afdw.dwFormatIndex = pafda->dwFormatIndex;
422 afdw.dwFormatTag = pafda->dwFormatTag;
423 afdw.pwfx = pafda->pwfx;
424 afdw.cbwfx = pafda->cbwfx;
426 afei.pafda = pafda;
427 afei.dwInstance = dwInstance;
428 afei.fnCallback = fnCallback;
430 return acmFormatEnumW(had, &afdw, MSACM_FormatEnumCallbackWtoA,
431 (DWORD)&afei, fdwEnum);
434 /***********************************************************************
435 * acmFormatEnumW (MSACM32.@)
437 static BOOL MSACM_FormatEnumHelper(PWINE_ACMDRIVERID padid, HACMDRIVER had,
438 PACMFORMATDETAILSW pafd, PWAVEFORMATEX pwfxRef,
439 ACMFORMATENUMCBW fnCallback, DWORD dwInstance,
440 DWORD fdwEnum)
442 ACMFORMATTAGDETAILSW aftd;
443 unsigned int i, j;
445 for (i = 0; i < padid->cFormatTags; i++) {
446 memset(&aftd, 0, sizeof(aftd));
447 aftd.cbStruct = sizeof(aftd);
448 aftd.dwFormatTagIndex = i;
449 if (acmFormatTagDetailsW(had, &aftd, ACM_FORMATTAGDETAILSF_INDEX) != MMSYSERR_NOERROR)
450 continue;
452 if ((fdwEnum & ACM_FORMATENUMF_WFORMATTAG) && aftd.dwFormatTag != pwfxRef->wFormatTag)
453 continue;
455 for (j = 0; j < aftd.cStandardFormats; j++) {
456 pafd->dwFormatIndex = j;
457 pafd->dwFormatTag = aftd.dwFormatTag;
458 if (acmFormatDetailsW(had, pafd, ACM_FORMATDETAILSF_INDEX) != MMSYSERR_NOERROR)
459 continue;
461 if ((fdwEnum & ACM_FORMATENUMF_NCHANNELS) &&
462 pafd->pwfx->nChannels != pwfxRef->nChannels)
463 continue;
464 if ((fdwEnum & ACM_FORMATENUMF_NSAMPLESPERSEC) &&
465 pafd->pwfx->nSamplesPerSec != pwfxRef->nSamplesPerSec)
466 continue;
467 if ((fdwEnum & ACM_FORMATENUMF_WBITSPERSAMPLE) &&
468 pafd->pwfx->wBitsPerSample != pwfxRef->wBitsPerSample)
469 continue;
470 if ((fdwEnum & ACM_FORMATENUMF_HARDWARE) &&
471 !(pafd->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_HARDWARE))
472 continue;
474 /* more checks to be done on fdwEnum */
476 if (!(fnCallback)((HACMDRIVERID)padid, pafd, dwInstance, padid->fdwSupport))
477 return FALSE;
479 /* the "formats" used by the filters are also reported */
481 return TRUE;
484 /**********************************************************************/
486 MMRESULT WINAPI acmFormatEnumW(HACMDRIVER had, PACMFORMATDETAILSW pafd,
487 ACMFORMATENUMCBW fnCallback, DWORD dwInstance,
488 DWORD fdwEnum)
490 PWINE_ACMDRIVERID padid;
491 WAVEFORMATEX wfxRef;
492 BOOL ret;
494 TRACE("(%p, %p, %p, %d, %d)\n",
495 had, pafd, fnCallback, dwInstance, fdwEnum);
497 if (!pafd)
498 return MMSYSERR_INVALPARAM;
500 if (pafd->cbStruct < sizeof(*pafd))
501 return MMSYSERR_INVALPARAM;
503 if (fdwEnum & (ACM_FORMATENUMF_WFORMATTAG|ACM_FORMATENUMF_NCHANNELS|
504 ACM_FORMATENUMF_NSAMPLESPERSEC|ACM_FORMATENUMF_WBITSPERSAMPLE|
505 ACM_FORMATENUMF_CONVERT|ACM_FORMATENUMF_SUGGEST))
506 wfxRef = *pafd->pwfx;
508 if ((fdwEnum & ACM_FORMATENUMF_HARDWARE) &&
509 !(fdwEnum & (ACM_FORMATENUMF_INPUT|ACM_FORMATENUMF_OUTPUT)))
510 return MMSYSERR_INVALPARAM;
512 if ((fdwEnum & ACM_FORMATENUMF_WFORMATTAG) &&
513 (pafd->dwFormatTag != pafd->pwfx->wFormatTag))
514 return MMSYSERR_INVALPARAM;
516 if (fdwEnum & (ACM_FORMATENUMF_CONVERT|ACM_FORMATENUMF_SUGGEST|
517 ACM_FORMATENUMF_INPUT|ACM_FORMATENUMF_OUTPUT))
518 FIXME("Unsupported fdwEnum values %08x\n", fdwEnum);
520 if (had) {
521 HACMDRIVERID hadid;
523 if (acmDriverID((HACMOBJ)had, &hadid, 0) != MMSYSERR_NOERROR)
524 return MMSYSERR_INVALHANDLE;
525 MSACM_FormatEnumHelper(MSACM_GetDriverID(hadid), had, pafd, &wfxRef,
526 fnCallback, dwInstance, fdwEnum);
527 return MMSYSERR_NOERROR;
529 for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
530 /* should check for codec only */
531 if ((padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
532 acmDriverOpen(&had, (HACMDRIVERID)padid, 0) != MMSYSERR_NOERROR)
533 continue;
534 ret = MSACM_FormatEnumHelper(padid, had, pafd, &wfxRef,
535 fnCallback, dwInstance, fdwEnum);
536 acmDriverClose(had, 0);
537 if (!ret) break;
539 return MMSYSERR_NOERROR;
542 /***********************************************************************
543 * acmFormatSuggest (MSACM32.@)
545 MMRESULT WINAPI acmFormatSuggest(HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
546 PWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest)
548 ACMDRVFORMATSUGGEST adfg;
549 MMRESULT mmr;
551 TRACE("(%p, %p, %p, %d, %d)\n",
552 had, pwfxSrc, pwfxDst, cbwfxDst, fdwSuggest);
554 if (fdwSuggest & ~(ACM_FORMATSUGGESTF_NCHANNELS|ACM_FORMATSUGGESTF_NSAMPLESPERSEC|
555 ACM_FORMATSUGGESTF_WBITSPERSAMPLE|ACM_FORMATSUGGESTF_WFORMATTAG))
556 return MMSYSERR_INVALFLAG;
558 adfg.cbStruct = sizeof(adfg);
559 adfg.fdwSuggest = fdwSuggest;
560 adfg.pwfxSrc = pwfxSrc;
561 adfg.cbwfxSrc = (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) ?
562 sizeof(WAVEFORMATEX) : (sizeof(WAVEFORMATEX) + pwfxSrc->cbSize);
563 adfg.pwfxDst = pwfxDst;
564 adfg.cbwfxDst = cbwfxDst;
566 if (had == NULL) {
567 PWINE_ACMDRIVERID padid;
569 /* MS doc says: ACM finds the best suggestion.
570 * Well, first found will be the "best"
572 mmr = ACMERR_NOTPOSSIBLE;
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;
579 if (MSACM_Message(had, ACMDM_FORMAT_SUGGEST, (LPARAM)&adfg, 0L) == MMSYSERR_NOERROR) {
580 mmr = MMSYSERR_NOERROR;
581 break;
583 acmDriverClose(had, 0);
585 } else {
586 mmr = MSACM_Message(had, ACMDM_FORMAT_SUGGEST, (LPARAM)&adfg, 0L);
588 return mmr;
591 /***********************************************************************
592 * acmFormatTagDetailsA (MSACM32.@)
594 MMRESULT WINAPI acmFormatTagDetailsA(HACMDRIVER had, PACMFORMATTAGDETAILSA paftda,
595 DWORD fdwDetails)
597 ACMFORMATTAGDETAILSW aftdw;
598 MMRESULT mmr;
600 memset(&aftdw, 0, sizeof(aftdw));
601 aftdw.cbStruct = sizeof(aftdw);
602 aftdw.dwFormatTagIndex = paftda->dwFormatTagIndex;
603 aftdw.dwFormatTag = paftda->dwFormatTag;
605 mmr = acmFormatTagDetailsW(had, &aftdw, fdwDetails);
606 if (mmr == MMSYSERR_NOERROR) {
607 paftda->dwFormatTag = aftdw.dwFormatTag;
608 paftda->dwFormatTagIndex = aftdw.dwFormatTagIndex;
609 paftda->cbFormatSize = aftdw.cbFormatSize;
610 paftda->fdwSupport = aftdw.fdwSupport;
611 paftda->cStandardFormats = aftdw.cStandardFormats;
612 WideCharToMultiByte( CP_ACP, 0, aftdw.szFormatTag, -1, paftda->szFormatTag,
613 sizeof(paftda->szFormatTag), NULL, NULL );
615 return mmr;
618 /***********************************************************************
619 * acmFormatTagDetailsW (MSACM32.@)
621 MMRESULT WINAPI acmFormatTagDetailsW(HACMDRIVER had, PACMFORMATTAGDETAILSW paftd,
622 DWORD fdwDetails)
624 PWINE_ACMDRIVERID padid;
625 MMRESULT mmr = ACMERR_NOTPOSSIBLE;
627 TRACE("(%p, %p, %d)\n", had, paftd, fdwDetails);
629 if (fdwDetails & ~(ACM_FORMATTAGDETAILSF_FORMATTAG|ACM_FORMATTAGDETAILSF_INDEX|
630 ACM_FORMATTAGDETAILSF_LARGESTSIZE))
631 return MMSYSERR_INVALFLAG;
633 switch (fdwDetails) {
634 case ACM_FORMATTAGDETAILSF_FORMATTAG:
635 if (had == NULL) {
636 for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
637 /* should check for codec only */
638 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
639 MSACM_FindFormatTagInCache(padid, paftd->dwFormatTag, NULL) &&
640 acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == 0) {
641 mmr = MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)paftd, fdwDetails);
642 acmDriverClose(had, 0);
643 if (mmr == MMSYSERR_NOERROR) break;
646 } else {
647 PWINE_ACMDRIVER pad = MSACM_GetDriver(had);
649 if (pad && MSACM_FindFormatTagInCache(pad->obj.pACMDriverID, paftd->dwFormatTag, NULL))
650 mmr = MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)paftd, fdwDetails);
652 break;
654 case ACM_FORMATTAGDETAILSF_INDEX:
655 if (had != NULL) {
656 PWINE_ACMDRIVER pad = MSACM_GetDriver(had);
658 if (pad && paftd->dwFormatTagIndex < pad->obj.pACMDriverID->cFormatTags)
659 mmr = MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)paftd, fdwDetails);
661 break;
663 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
664 if (had == NULL) {
665 ACMFORMATTAGDETAILSW tmp;
666 DWORD ft = paftd->dwFormatTag;
668 for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
669 /* should check for codec only */
670 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
671 acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == 0) {
673 memset(&tmp, 0, sizeof(tmp));
674 tmp.cbStruct = sizeof(tmp);
675 tmp.dwFormatTag = ft;
677 if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
678 (LPARAM)&tmp, fdwDetails) == MMSYSERR_NOERROR) {
679 if (mmr == ACMERR_NOTPOSSIBLE ||
680 paftd->cbFormatSize < tmp.cbFormatSize) {
681 *paftd = tmp;
682 mmr = MMSYSERR_NOERROR;
685 acmDriverClose(had, 0);
688 } else {
689 mmr = MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)paftd, fdwDetails);
691 break;
693 default:
694 WARN("Unsupported fdwDetails=%08x\n", fdwDetails);
695 mmr = MMSYSERR_ERROR;
698 if (mmr == MMSYSERR_NOERROR &&
699 paftd->dwFormatTag == WAVE_FORMAT_PCM && paftd->szFormatTag[0] == 0)
700 MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
701 sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
703 return mmr;
706 struct MSACM_FormatTagEnumWtoA_Instance {
707 PACMFORMATTAGDETAILSA paftda;
708 DWORD dwInstance;
709 ACMFORMATTAGENUMCBA fnCallback;
712 static BOOL CALLBACK MSACM_FormatTagEnumCallbackWtoA(HACMDRIVERID hadid,
713 PACMFORMATTAGDETAILSW paftdw,
714 DWORD dwInstance,
715 DWORD fdwSupport)
717 struct MSACM_FormatTagEnumWtoA_Instance* paftei;
719 paftei = (struct MSACM_FormatTagEnumWtoA_Instance*)dwInstance;
721 paftei->paftda->dwFormatTagIndex = paftdw->dwFormatTagIndex;
722 paftei->paftda->dwFormatTag = paftdw->dwFormatTag;
723 paftei->paftda->cbFormatSize = paftdw->cbFormatSize;
724 paftei->paftda->fdwSupport = paftdw->fdwSupport;
725 paftei->paftda->cStandardFormats = paftdw->cStandardFormats;
726 WideCharToMultiByte( CP_ACP, 0, paftdw->szFormatTag, -1, paftei->paftda->szFormatTag,
727 sizeof(paftei->paftda->szFormatTag), NULL, NULL );
729 return (paftei->fnCallback)(hadid, paftei->paftda,
730 paftei->dwInstance, fdwSupport);
733 /***********************************************************************
734 * acmFormatTagEnumA (MSACM32.@)
736 MMRESULT WINAPI acmFormatTagEnumA(HACMDRIVER had, PACMFORMATTAGDETAILSA paftda,
737 ACMFORMATTAGENUMCBA fnCallback, DWORD dwInstance,
738 DWORD fdwEnum)
740 ACMFORMATTAGDETAILSW aftdw;
741 struct MSACM_FormatTagEnumWtoA_Instance aftei;
743 if (!paftda)
744 return MMSYSERR_INVALPARAM;
746 if (paftda->cbStruct < sizeof(*paftda))
747 return MMSYSERR_INVALPARAM;
749 if (fdwEnum != 0)
750 return MMSYSERR_INVALFLAG;
752 memset(&aftdw, 0, sizeof(aftdw));
753 aftdw.cbStruct = sizeof(aftdw);
754 aftdw.dwFormatTagIndex = paftda->dwFormatTagIndex;
755 aftdw.dwFormatTag = paftda->dwFormatTag;
757 aftei.paftda = paftda;
758 aftei.dwInstance = dwInstance;
759 aftei.fnCallback = fnCallback;
761 return acmFormatTagEnumW(had, &aftdw, MSACM_FormatTagEnumCallbackWtoA,
762 (DWORD)&aftei, fdwEnum);
765 /***********************************************************************
766 * acmFormatTagEnumW (MSACM32.@)
768 MMRESULT WINAPI acmFormatTagEnumW(HACMDRIVER had, PACMFORMATTAGDETAILSW paftd,
769 ACMFORMATTAGENUMCBW fnCallback, DWORD dwInstance,
770 DWORD fdwEnum)
772 PWINE_ACMDRIVERID padid;
773 unsigned int i;
774 BOOL bPcmDone = FALSE;
776 TRACE("(%p, %p, %p, %d, %d)\n",
777 had, paftd, fnCallback, dwInstance, fdwEnum);
779 if (!paftd)
780 return MMSYSERR_INVALPARAM;
782 if (paftd->cbStruct < sizeof(*paftd))
783 return MMSYSERR_INVALPARAM;
785 if (fdwEnum != 0)
786 return MMSYSERR_INVALFLAG;
788 /* (WS) MSDN info page says that if had != 0, then we should find
789 * the specific driver to get its tags from. Therefore I'm removing
790 * the FIXME call and adding a search block below. It also seems
791 * that the lack of this functionality was the responsible for
792 * codecs to be multiply and incorrectly listed.
795 /* if (had) FIXME("had != NULL, not supported\n"); */
797 if (had) {
799 if (acmDriverID((HACMOBJ)had, (HACMDRIVERID *)&padid, 0) != MMSYSERR_NOERROR)
800 return MMSYSERR_INVALHANDLE;
802 for (i = 0; i < padid->cFormatTags; i++) {
803 paftd->dwFormatTagIndex = i;
804 if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
805 (LPARAM)paftd, ACM_FORMATTAGDETAILSF_INDEX) == MMSYSERR_NOERROR) {
806 if (paftd->dwFormatTag == WAVE_FORMAT_PCM) {
807 if (paftd->szFormatTag[0] == 0)
808 MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
809 sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
810 /* (WS) I'm preserving this PCM hack since it seems to be
811 * correct. Please notice this block was borrowed from
812 * below.
814 if (bPcmDone) continue;
815 bPcmDone = TRUE;
817 if (!(fnCallback)((HACMDRIVERID)padid, paftd, dwInstance, padid->fdwSupport))
818 return MMSYSERR_NOERROR;
824 /* if had==0 then search for the first suitable driver */
825 else {
826 for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
827 /* should check for codec only */
828 if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
829 acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == MMSYSERR_NOERROR) {
830 for (i = 0; i < padid->cFormatTags; i++) {
831 paftd->dwFormatTagIndex = i;
832 if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
833 (LPARAM)paftd, ACM_FORMATTAGDETAILSF_INDEX) == MMSYSERR_NOERROR) {
834 if (paftd->dwFormatTag == WAVE_FORMAT_PCM) {
835 if (paftd->szFormatTag[0] == 0)
836 MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
837 sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
838 /* FIXME (EPP): I'm not sure this is the correct
839 * algorithm (should make more sense to apply the same
840 * for all already loaded formats, but this will do
841 * for now
843 if (bPcmDone) continue;
844 bPcmDone = TRUE;
846 if (!(fnCallback)((HACMDRIVERID)padid, paftd, dwInstance, padid->fdwSupport)) {
847 acmDriverClose(had, 0);
848 return MMSYSERR_NOERROR;
853 acmDriverClose(had, 0);
856 return MMSYSERR_NOERROR;