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