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