[MSACM32] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / msacm32 / format.c
index 748fd3c..b3d2900 100644 (file)
@@ -1,5 +1,3 @@
-/* -*- tab-width: 8; c-basic-offset: 4 -*- */
-
 /*
  *      MSACM32 library
  *
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define WIN32_NO_STATUS
-
 #include <stdarg.h>
-//#include <string.h>
-#include <windef.h>
-//#include "winbase.h"
-//#include "winnls.h"
-//#include "winerror.h"
-#include <wingdi.h>
-#include <winuser.h>
-#include <wine/unicode.h>
-#include <wine/debug.h>
-//#include "mmsystem.h"
-//#include "mmreg.h"
-//#include "msacm.h"
-#include <msacmdrv.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+#include "mmsystem.h"
+#include "mmreg.h"
+#include "msacm.h"
+#include "msacmdrv.h"
 #include "wineacm.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
 
-static PACMFORMATCHOOSEA       afc;
-
 struct MSACM_FillFormatData {
     HWND               hWnd;
 #define WINE_ACMFF_TAG         0
 #define WINE_ACMFF_FORMAT      1
 #define WINE_ACMFF_WFX         2
     int                        mode;
-    char               szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
-    PACMFORMATCHOOSEA  afc;
+    WCHAR              szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
+    PACMFORMATCHOOSEW  afc;
     DWORD              ret;
 };
 
 static BOOL CALLBACK MSACM_FillFormatTagsCB(HACMDRIVERID hadid,
-                                           PACMFORMATTAGDETAILSA paftd,
+                                            PACMFORMATTAGDETAILSW paftd,
                                             DWORD_PTR dwInstance,
                                             DWORD fdwSupport)
 {
@@ -63,67 +57,86 @@ static BOOL CALLBACK MSACM_FillFormatTagsCB(HACMDRIVERID hadid,
 
     switch (affd->mode) {
     case WINE_ACMFF_TAG:
-       if (SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
-                                CB_FINDSTRINGEXACT, -1,
-                                (LPARAM)paftd->szFormatTag) == CB_ERR)
-           SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
-                                CB_ADDSTRING, 0, (LPARAM)paftd->szFormatTag);
+        if (paftd->cStandardFormats > 0)
+        {
+            if (SendDlgItemMessageW(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
+                                    CB_FINDSTRINGEXACT, -1,
+                                    (LPARAM)paftd->szFormatTag) == CB_ERR)
+            {
+                int index = SendDlgItemMessageW(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
+                                    CB_ADDSTRING, 0, (LPARAM)paftd->szFormatTag);
+                if (((affd->afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT) &&
+                    (paftd->dwFormatTag == affd->afc->pwfx->wFormatTag)) ||
+                   (!(affd->afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT) &&
+                    (paftd->dwFormatTag == WAVE_FORMAT_PCM)))
+                    SendDlgItemMessageW(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
+                                        CB_SETCURSEL, index, 0);
+            }
+        }
        break;
     case WINE_ACMFF_FORMAT:
-       if (strcmp(affd->szFormatTag, paftd->szFormatTag) == 0) {
+       if (strcmpW(affd->szFormatTag, paftd->szFormatTag) == 0) {
            HACMDRIVER          had;
 
            if (acmDriverOpen(&had, hadid, 0) == MMSYSERR_NOERROR) {
-               ACMFORMATDETAILSA       afd;
-               unsigned int            i, len;
+               ACMFORMATDETAILSW       afd = {0};
+                unsigned int            i, len;
                MMRESULT                mmr;
-               char                    buffer[ACMFORMATDETAILS_FORMAT_CHARS+16];
+               WCHAR                   buffer[ACMFORMATDETAILS_FORMAT_CHARS+16];
 
                afd.cbStruct = sizeof(afd);
                afd.dwFormatTag = paftd->dwFormatTag;
                afd.pwfx = HeapAlloc(MSACM_hHeap, 0, paftd->cbFormatSize);
                if (!afd.pwfx) return FALSE;
                afd.pwfx->wFormatTag = paftd->dwFormatTag;
-               afd.pwfx->cbSize = paftd->cbFormatSize;
+               if (paftd->dwFormatTag != WAVE_FORMAT_PCM)
+                   afd.pwfx->cbSize = paftd->cbFormatSize - sizeof(WAVEFORMATEX);
                afd.cbwfx = paftd->cbFormatSize;
 
                for (i = 0; i < paftd->cStandardFormats; i++) {
+                    static const WCHAR fmtW[] = {'%','d',' ','K','o','/','s','\0'};
+                    int j, index;
+
                    afd.dwFormatIndex = i;
-                   mmr = acmFormatDetailsA(had, &afd, ACM_FORMATDETAILSF_INDEX);
+                   afd.fdwSupport = 0;
+                   mmr = acmFormatDetailsW(had, &afd, ACM_FORMATDETAILSF_INDEX);
                    if (mmr == MMSYSERR_NOERROR) {
-                       lstrcpynA(buffer, afd.szFormat, ACMFORMATTAGDETAILS_FORMATTAG_CHARS + 1);
-                       len = strlen(buffer);
-                       memset(buffer+len, ' ', ACMFORMATTAGDETAILS_FORMATTAG_CHARS - len);
-                       wsprintfA(buffer + ACMFORMATTAGDETAILS_FORMATTAG_CHARS,
-                                 "%d Ko/s",
-                                 (afd.pwfx->nAvgBytesPerSec + 512) / 1024);
-                       SendDlgItemMessageA(affd->hWnd,
-                                           IDD_ACMFORMATCHOOSE_CMB_FORMAT,
-                                            CB_ADDSTRING, 0, (LPARAM)buffer);
+                       lstrcpynW(buffer, afd.szFormat, ACMFORMATTAGDETAILS_FORMATTAG_CHARS + 1);
+                       len = strlenW(buffer);
+                       for (j = len; j < ACMFORMATTAGDETAILS_FORMATTAG_CHARS; j++)
+                           buffer[j] = ' ';
+                       wsprintfW(buffer + ACMFORMATTAGDETAILS_FORMATTAG_CHARS,
+                                 fmtW, (afd.pwfx->nAvgBytesPerSec + 512) / 1024);
+                       index = SendDlgItemMessageW(affd->hWnd,
+                                           IDD_ACMFORMATCHOOSE_CMB_FORMAT,
+                                           CB_ADDSTRING, 0, (LPARAM)buffer);
+                       if ((affd->afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT) &&
+                           affd->afc->cbwfx >= paftd->cbFormatSize &&
+                           !memcmp(afd.pwfx, affd->afc->pwfx, paftd->cbFormatSize))
+                           SendDlgItemMessageW(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT,
+                                               CB_SETCURSEL, index, 0);
                    }
                }
                acmDriverClose(had, 0);
-               SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT,
-                                   CB_SETCURSEL, 0, 0);
                HeapFree(MSACM_hHeap, 0, afd.pwfx);
            }
        }
        break;
     case WINE_ACMFF_WFX:
-       if (strcmp(affd->szFormatTag, paftd->szFormatTag) == 0) {
+       if (strcmpW(affd->szFormatTag, paftd->szFormatTag) == 0) {
            HACMDRIVER          had;
 
            if (acmDriverOpen(&had, hadid, 0) == MMSYSERR_NOERROR) {
-               ACMFORMATDETAILSA       afd;
+               ACMFORMATDETAILSW       afd = {0};
 
                afd.cbStruct = sizeof(afd);
                afd.dwFormatTag = paftd->dwFormatTag;
                afd.pwfx = affd->afc->pwfx;
                afd.cbwfx = affd->afc->cbwfx;
 
-               afd.dwFormatIndex = SendDlgItemMessageA(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT,
+               afd.dwFormatIndex = SendDlgItemMessageW(affd->hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT,
                                                        CB_GETCURSEL, 0, 0);
-               affd->ret = acmFormatDetailsA(had, &afd, ACM_FORMATDETAILSF_INDEX);
+               affd->ret = acmFormatDetailsW(had, &afd, ACM_FORMATDETAILSF_INDEX);
                acmDriverClose(had, 0);
                return TRUE;
            }
@@ -136,9 +149,9 @@ static BOOL CALLBACK MSACM_FillFormatTagsCB(HACMDRIVERID hadid,
     return TRUE;
 }
 
-static BOOL MSACM_FillFormatTags(HWND hWnd)
+static BOOL MSACM_FillFormatTags(HWND hWnd, PACMFORMATCHOOSEW afc)
 {
-    ACMFORMATTAGDETAILSA       aftd;
+    ACMFORMATTAGDETAILSW       aftd;
     struct MSACM_FillFormatData        affd;
 
     memset(&aftd, 0, sizeof(aftd));
@@ -146,38 +159,42 @@ static BOOL MSACM_FillFormatTags(HWND hWnd)
 
     affd.hWnd = hWnd;
     affd.mode = WINE_ACMFF_TAG;
+    affd.afc = afc;
 
-    acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
-    SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, CB_SETCURSEL, 0, 0);
+    acmFormatTagEnumW(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
+    if (SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, CB_GETCURSEL, 0, 0) == CB_ERR)
+        SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, CB_SETCURSEL, 0, 0);
     return TRUE;
 }
 
-static BOOL MSACM_FillFormat(HWND hWnd)
+static BOOL MSACM_FillFormat(HWND hWnd, PACMFORMATCHOOSEW afc)
 {
-    ACMFORMATTAGDETAILSA       aftd;
+    ACMFORMATTAGDETAILSW       aftd;
     struct MSACM_FillFormatData        affd;
 
-    SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_RESETCONTENT, 0, 0);
 
     memset(&aftd, 0, sizeof(aftd));
     aftd.cbStruct = sizeof(aftd);
 
     affd.hWnd = hWnd;
     affd.mode = WINE_ACMFF_FORMAT;
-    SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
+    affd.afc = afc;
+    SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
                        CB_GETLBTEXT,
-                       SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
+                       SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
                                            CB_GETCURSEL, 0, 0),
                         (LPARAM)affd.szFormatTag);
 
-    acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
-    SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_SETCURSEL, 0, 0);
+    acmFormatTagEnumW(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
+    if (SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_GETCURSEL, 0, 0) == CB_ERR)
+        SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMAT, CB_SETCURSEL, 0, 0);
     return TRUE;
 }
 
-static MMRESULT MSACM_GetWFX(HWND hWnd, PACMFORMATCHOOSEA afc)
+static MMRESULT MSACM_GetWFX(HWND hWnd, PACMFORMATCHOOSEW afc)
 {
-    ACMFORMATTAGDETAILSA       aftd;
+    ACMFORMATTAGDETAILSW       aftd;
     struct MSACM_FillFormatData        affd;
 
     memset(&aftd, 0, sizeof(aftd));
@@ -187,30 +204,37 @@ static MMRESULT MSACM_GetWFX(HWND hWnd, PACMFORMATCHOOSEA afc)
     affd.mode = WINE_ACMFF_WFX;
     affd.afc = afc;
     affd.ret = MMSYSERR_NOERROR;
-    SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
+    SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
                        CB_GETLBTEXT,
-                       SendDlgItemMessageA(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
+                       SendDlgItemMessageW(hWnd, IDD_ACMFORMATCHOOSE_CMB_FORMATTAG,
                                            CB_GETCURSEL, 0, 0),
                         (LPARAM)affd.szFormatTag);
 
-    acmFormatTagEnumA(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
+    acmFormatTagEnumW(NULL, &aftd, MSACM_FillFormatTagsCB, (DWORD_PTR)&affd, 0);
     return affd.ret;
 }
 
+static const WCHAR fmt_prop[] = {'a','c','m','p','r','o','p','\0'};
+
 static INT_PTR CALLBACK FormatChooseDlgProc(HWND hWnd, UINT msg,
-                                      WPARAM wParam, LPARAM lParam)
+                                            WPARAM wParam, LPARAM lParam)
 {
+    PACMFORMATCHOOSEW   afc = (PACMFORMATCHOOSEW)GetPropW(hWnd, fmt_prop);
 
-    TRACE("hwnd=%p msg=%i 0x%08lx 0x%08lx\n", hWnd,  msg, wParam, lParam );
+    TRACE("hwnd=%p msg=%i 0x%08lx 0x%08lx\n", hWnd, msg, wParam, lParam);
 
     switch (msg) {
     case WM_INITDIALOG:
-       afc = (PACMFORMATCHOOSEA)lParam;
-       MSACM_FillFormatTags(hWnd);
-       MSACM_FillFormat(hWnd);
+       afc = (PACMFORMATCHOOSEW)lParam;
+       SetPropW(hWnd, fmt_prop, (HANDLE)afc);
+       MSACM_FillFormatTags(hWnd, afc);
+       MSACM_FillFormat(hWnd, afc);
        if ((afc->fdwStyle & ~(ACMFORMATCHOOSE_STYLEF_CONTEXTHELP|
-                              ACMFORMATCHOOSE_STYLEF_SHOWHELP)) != 0)
-            FIXME("Unsupported style %08x\n", ((PACMFORMATCHOOSEA)lParam)->fdwStyle);
+                              ACMFORMATCHOOSE_STYLEF_SHOWHELP|
+                               ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT|
+                               ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATEHANDLE|
+                               ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATE)) != 0)
+            FIXME("Unsupported style %08x\n", afc->fdwStyle);
        if (!(afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_SHOWHELP))
            ShowWindow(GetDlgItem(hWnd, IDD_ACMFORMATCHOOSE_BTN_HELP), SW_HIDE);
        return TRUE;
@@ -226,7 +250,7 @@ static INT_PTR CALLBACK FormatChooseDlgProc(HWND hWnd, UINT msg,
        case IDD_ACMFORMATCHOOSE_CMB_FORMATTAG:
            switch (HIWORD(wParam)) {
            case CBN_SELCHANGE:
-               MSACM_FillFormat(hWnd);
+               MSACM_FillFormat(hWnd, afc);
                break;
            default:
                TRACE("Dropped dlgNotif (fmtTag): 0x%08x 0x%08lx\n",
@@ -236,8 +260,8 @@ static INT_PTR CALLBACK FormatChooseDlgProc(HWND hWnd, UINT msg,
            break;
        case IDD_ACMFORMATCHOOSE_BTN_HELP:
            if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_SHOWHELP)
-               SendMessageA(afc->hwndOwner,
-                            RegisterWindowMessageA(ACMHELPMSGSTRINGA), 0L, 0L);
+               SendMessageW(afc->hwndOwner,
+                            RegisterWindowMessageW(ACMHELPMSGSTRINGW), 0L, 0L);
            break;
 
        default:
@@ -248,15 +272,15 @@ static INT_PTR CALLBACK FormatChooseDlgProc(HWND hWnd, UINT msg,
        break;
     case WM_CONTEXTMENU:
        if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_CONTEXTHELP)
-           SendMessageA(afc->hwndOwner,
-                        RegisterWindowMessageA(ACMHELPMSGCONTEXTMENUA),
+           SendMessageW(afc->hwndOwner,
+                        RegisterWindowMessageW(ACMHELPMSGCONTEXTMENUW),
                         wParam, lParam);
        break;
 #if defined(WM_CONTEXTHELP)
     case WM_CONTEXTHELP:
        if (afc->fdwStyle & ACMFORMATCHOOSE_STYLEF_CONTEXTHELP)
-           SendMessageA(afc->hwndOwner,
-                        RegisterWindowMessageA(ACMHELPMSGCONTEXTHELPA),
+           SendMessageW(afc->hwndOwner,
+                        RegisterWindowMessageW(ACMHELPMSGCONTEXTHELPW),
                         wParam, lParam);
        break;
 #endif
@@ -273,8 +297,80 @@ static INT_PTR CALLBACK FormatChooseDlgProc(HWND hWnd, UINT msg,
  */
 MMRESULT WINAPI acmFormatChooseA(PACMFORMATCHOOSEA pafmtc)
 {
-    return DialogBoxParamA(MSACM_hInstance32, MAKEINTRESOURCEA(DLG_ACMFORMATCHOOSE_ID),
-                           pafmtc->hwndOwner, FormatChooseDlgProc, (LPARAM)pafmtc);
+    ACMFORMATCHOOSEW    afcw;
+    MMRESULT            ret;
+    LPWSTR              title = NULL;
+    LPWSTR              name = NULL;
+    LPWSTR              templ = NULL;
+    DWORD               sz;
+
+    if (pafmtc->cbStruct < sizeof(ACMFORMATCHOOSEA))
+        return MMSYSERR_INVALPARAM;
+
+    afcw.cbStruct  = sizeof(afcw);
+    afcw.fdwStyle  = pafmtc->fdwStyle;
+    afcw.hwndOwner = pafmtc->hwndOwner;
+    afcw.pwfx      = pafmtc->pwfx;
+    afcw.cbwfx     = pafmtc->cbwfx;
+    if (pafmtc->pszTitle)
+    {
+        sz = MultiByteToWideChar(CP_ACP, 0, pafmtc->pszTitle, -1, NULL, 0);
+        if (!(title = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+        {
+            ret = MMSYSERR_NOMEM;
+            goto done;
+        }
+        MultiByteToWideChar(CP_ACP, 0, pafmtc->pszTitle, -1, title, sz);
+    }
+    afcw.pszTitle  = title;
+    if (pafmtc->pszName)
+    {
+        sz = MultiByteToWideChar(CP_ACP, 0, pafmtc->pszName, -1, NULL, 0);
+        if (!(name = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+        {
+            ret = MMSYSERR_NOMEM;
+            goto done;
+        }
+        MultiByteToWideChar(CP_ACP, 0, pafmtc->pszName, -1, name, sz);
+    }
+    afcw.pszName   = name;
+    afcw.cchName   = pafmtc->cchName;
+    afcw.fdwEnum   = pafmtc->fdwEnum;
+    afcw.pwfxEnum  = pafmtc->pwfxEnum;
+    afcw.hInstance = pafmtc->hInstance;
+    if (pafmtc->pszTemplateName)
+    {
+        sz = MultiByteToWideChar(CP_ACP, 0, pafmtc->pszTemplateName, -1, NULL, 0);
+        if (!(templ = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+        {
+            ret = MMSYSERR_NOMEM;
+            goto done;
+        }
+        MultiByteToWideChar(CP_ACP, 0, pafmtc->pszTemplateName, -1, templ, sz);
+    }
+    afcw.pszTemplateName = templ;
+    /* FIXME: hook procs not supported yet */
+    if (pafmtc->pfnHook)
+    {
+        FIXME("Unsupported hook procs\n");
+        ret = MMSYSERR_NOTSUPPORTED;
+        goto done;
+    }
+    ret = acmFormatChooseW(&afcw);
+    if (ret == MMSYSERR_NOERROR)
+    {
+        WideCharToMultiByte(CP_ACP, 0, afcw.szFormatTag, -1, pafmtc->szFormatTag, sizeof(pafmtc->szFormatTag),
+                            NULL, NULL);
+        WideCharToMultiByte(CP_ACP, 0, afcw.szFormat, -1, pafmtc->szFormat, sizeof(pafmtc->szFormat),
+                            NULL, NULL);
+        if (pafmtc->pszName)
+            WideCharToMultiByte(CP_ACP, 0, afcw.pszName, -1, pafmtc->pszName, pafmtc->cchName, NULL, NULL);
+    }
+done:
+    HeapFree(GetProcessHeap(), 0, title);
+    HeapFree(GetProcessHeap(), 0, name);
+    HeapFree(GetProcessHeap(), 0, templ);
+    return ret;
 }
 
 /***********************************************************************
@@ -282,9 +378,22 @@ MMRESULT WINAPI acmFormatChooseA(PACMFORMATCHOOSEA pafmtc)
  */
 MMRESULT WINAPI acmFormatChooseW(PACMFORMATCHOOSEW pafmtc)
 {
-    FIXME("(%p): stub\n", pafmtc);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return MMSYSERR_ERROR;
+    if (pafmtc->cbStruct < sizeof(ACMFORMATCHOOSEW))
+        return MMSYSERR_INVALPARAM;
+
+    if (!pafmtc->pwfx)
+        return MMSYSERR_INVALPARAM;
+
+    if (pafmtc->fdwStyle & ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATEHANDLE)
+        return DialogBoxIndirectParamW(MSACM_hInstance32, (LPCDLGTEMPLATEW)pafmtc->hInstance,
+                                       pafmtc->hwndOwner, FormatChooseDlgProc, (LPARAM)pafmtc);
+
+    if (pafmtc->fdwStyle & ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATE)
+        return DialogBoxParamW(pafmtc->hInstance, pafmtc->pszTemplateName,
+                               pafmtc->hwndOwner, FormatChooseDlgProc, (LPARAM)pafmtc);
+
+    return DialogBoxParamW(MSACM_hInstance32, MAKEINTRESOURCEW(DLG_ACMFORMATCHOOSE_ID),
+                           pafmtc->hwndOwner, FormatChooseDlgProc, (LPARAM)pafmtc);
 }
 
 /***********************************************************************
@@ -296,10 +405,14 @@ MMRESULT WINAPI acmFormatDetailsA(HACMDRIVER had, PACMFORMATDETAILSA pafd,
     ACMFORMATDETAILSW  afdw;
     MMRESULT           mmr;
 
+    if (!pafd)
+        return MMSYSERR_INVALPARAM;
+
     memset(&afdw, 0, sizeof(afdw));
     afdw.cbStruct = sizeof(afdw);
     afdw.dwFormatIndex = pafd->dwFormatIndex;
     afdw.dwFormatTag = pafd->dwFormatTag;
+    afdw.fdwSupport = pafd->fdwSupport;
     afdw.pwfx = pafd->pwfx;
     afdw.cbwfx = pafd->cbwfx;
 
@@ -321,15 +434,27 @@ MMRESULT WINAPI acmFormatDetailsW(HACMDRIVER had, PACMFORMATDETAILSW pafd, DWORD
     MMRESULT                   mmr;
     static const WCHAR         fmt1[] = {'%','d',' ','H','z',0};
     static const WCHAR         fmt2[] = {';',' ','%','d',' ','b','i','t','s',0};
-    ACMFORMATTAGDETAILSA       aftd;
+    ACMFORMATTAGDETAILSW       aftd = {0};
 
     TRACE("(%p, %p, %d)\n", had, pafd, fdwDetails);
 
-    memset(&aftd, 0, sizeof(aftd));
-    aftd.cbStruct = sizeof(aftd);
+    if (!pafd)
+        return MMSYSERR_INVALPARAM;
 
     if (pafd->cbStruct < sizeof(*pafd)) return MMSYSERR_INVALPARAM;
 
+    if (!pafd->pwfx)
+        return MMSYSERR_INVALPARAM;
+
+    if (pafd->cbwfx < sizeof(PCMWAVEFORMAT))
+        return MMSYSERR_INVALPARAM;
+
+    if (pafd->fdwSupport)
+        return MMSYSERR_INVALPARAM;
+
+    if (pafd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
+        return MMSYSERR_INVALPARAM;
+
     switch (fdwDetails) {
     case ACM_FORMATDETAILSF_FORMAT:
        if (pafd->dwFormatTag != pafd->pwfx->wFormatTag) {
@@ -354,7 +479,16 @@ MMRESULT WINAPI acmFormatDetailsW(HACMDRIVER had, PACMFORMATDETAILSW pafd, DWORD
        }
        break;
     case ACM_FORMATDETAILSF_INDEX:
-       /* should check pafd->dwFormatIndex < aftd->cStandardFormats */
+        aftd.cbStruct = sizeof(aftd);
+        aftd.dwFormatTag = pafd->dwFormatTag;
+        mmr = acmFormatTagDetailsW(had, &aftd, ACM_FORMATTAGDETAILSF_FORMATTAG);
+        if (mmr != MMSYSERR_NOERROR)
+            break;
+        if (pafd->dwFormatIndex >= aftd.cStandardFormats)
+        {
+            mmr = MMSYSERR_INVALPARAM;
+            break;
+        }
        mmr = MSACM_Message(had, ACMDM_FORMAT_DETAILS, (LPARAM)pafd, fdwDetails);
        break;
     default:
@@ -416,6 +550,9 @@ MMRESULT WINAPI acmFormatEnumA(HACMDRIVER had, PACMFORMATDETAILSA pafda,
     if (!pafda)
         return MMSYSERR_INVALPARAM;
 
+    if (!fnCallback)
+        return MMSYSERR_INVALPARAM;
+
     if (pafda->cbStruct < sizeof(*pafda))
         return MMSYSERR_INVALPARAM;
 
@@ -423,6 +560,7 @@ MMRESULT WINAPI acmFormatEnumA(HACMDRIVER had, PACMFORMATDETAILSA pafda,
     afdw.cbStruct = sizeof(afdw);
     afdw.dwFormatIndex = pafda->dwFormatIndex;
     afdw.dwFormatTag = pafda->dwFormatTag;
+    afdw.fdwSupport = pafda->fdwSupport;
     afdw.pwfx = pafda->pwfx;
     afdw.cbwfx = pafda->cbwfx;
 
@@ -501,6 +639,7 @@ static BOOL MSACM_FormatEnumHelper(PWINE_ACMDRIVERID padid, HACMDRIVER had,
             for (j = 0; j < aftd.cStandardFormats; j++) {
                 pafd->dwFormatIndex = j;
                 pafd->dwFormatTag = aftd.dwFormatTag;
+                pafd->fdwSupport = 0;
                 if (acmFormatDetailsW(had, pafd, ACM_FORMATDETAILSF_INDEX) != MMSYSERR_NOERROR)
                     continue;
 
@@ -537,6 +676,8 @@ MMRESULT WINAPI acmFormatEnumW(HACMDRIVER had, PACMFORMATDETAILSW pafd,
     PWINE_ACMDRIVERID          padid;
     WAVEFORMATEX               wfxRef;
     BOOL                       ret;
+    DWORD                      cbwfxMax;
+    MMRESULT                   mmr;
 
     TRACE("(%p, %p, %p, %ld, %d)\n",
          had, pafd, fnCallback, dwInstance, fdwEnum);
@@ -544,9 +685,18 @@ MMRESULT WINAPI acmFormatEnumW(HACMDRIVER had, PACMFORMATDETAILSW pafd,
     if (!pafd)
         return MMSYSERR_INVALPARAM;
 
+    if (!fnCallback)
+        return MMSYSERR_INVALPARAM;
+
     if (pafd->cbStruct < sizeof(*pafd))
         return MMSYSERR_INVALPARAM;
 
+    if (pafd->fdwSupport)
+        return MMSYSERR_INVALPARAM;
+
+    if (!pafd->pwfx)
+        return MMSYSERR_INVALPARAM;
+
     if (fdwEnum & (ACM_FORMATENUMF_WFORMATTAG|ACM_FORMATENUMF_NCHANNELS|
                   ACM_FORMATENUMF_NSAMPLESPERSEC|ACM_FORMATENUMF_WBITSPERSAMPLE|
                   ACM_FORMATENUMF_CONVERT|ACM_FORMATENUMF_SUGGEST))
@@ -563,6 +713,12 @@ MMRESULT WINAPI acmFormatEnumW(HACMDRIVER had, PACMFORMATDETAILSW pafd,
     if (fdwEnum & (ACM_FORMATENUMF_CONVERT|ACM_FORMATENUMF_INPUT|ACM_FORMATENUMF_OUTPUT))
        FIXME("Unsupported fdwEnum values %08x\n", fdwEnum);
 
+    mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &cbwfxMax);
+    if (mmr != MMSYSERR_NOERROR)
+        return mmr;
+    if (pafd->cbwfx < cbwfxMax)
+        return MMSYSERR_INVALPARAM;
+
     if (had) {
        HACMDRIVERID    hadid;
 
@@ -591,16 +747,46 @@ MMRESULT WINAPI acmFormatEnumW(HACMDRIVER had, PACMFORMATDETAILSW pafd,
 MMRESULT WINAPI acmFormatSuggest(HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
                                 PWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest)
 {
+    ACMFORMATTAGDETAILSW aftd = {0};
     ACMDRVFORMATSUGGEST        adfg;
     MMRESULT           mmr;
 
     TRACE("(%p, %p, %p, %d, %d)\n",
          had, pwfxSrc, pwfxDst, cbwfxDst, fdwSuggest);
 
+    if (!pwfxSrc || !pwfxDst)
+        return MMSYSERR_INVALPARAM;
+
     if (fdwSuggest & ~(ACM_FORMATSUGGESTF_NCHANNELS|ACM_FORMATSUGGESTF_NSAMPLESPERSEC|
                       ACM_FORMATSUGGESTF_WBITSPERSAMPLE|ACM_FORMATSUGGESTF_WFORMATTAG))
        return MMSYSERR_INVALFLAG;
 
+    /* if we were given PCM, try to convert to PCM */
+    if (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && !had &&
+        !(fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
+    {
+        ACMFORMATDETAILSW afd = {0};
+        afd.cbStruct = sizeof(afd);
+        afd.dwFormatTag = WAVE_FORMAT_PCM;
+        afd.pwfx = pwfxSrc;
+        afd.cbwfx = sizeof(PCMWAVEFORMAT);
+        if (!acmFormatDetailsW(had, &afd, ACM_FORMATDETAILSF_FORMAT))
+        {
+            memcpy(pwfxDst, pwfxSrc, sizeof(PCMWAVEFORMAT));
+            return MMSYSERR_NOERROR;
+        }
+    }
+
+    aftd.cbStruct = sizeof(aftd);
+    if (fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)
+        aftd.dwFormatTag = pwfxDst->wFormatTag;
+    mmr = acmFormatTagDetailsW(had, &aftd, ACM_FORMATTAGDETAILSF_LARGESTSIZE);
+    if ((fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG) && mmr == ACMERR_NOTPOSSIBLE)
+        return ACMERR_NOTPOSSIBLE;
+
+    if (cbwfxDst < aftd.cbFormatSize)
+        return MMSYSERR_INVALPARAM;
+
     adfg.cbStruct = sizeof(adfg);
     adfg.fdwSuggest = fdwSuggest;
     adfg.pwfxSrc = pwfxSrc;
@@ -815,12 +1001,12 @@ MMRESULT WINAPI acmFormatTagEnumW(HACMDRIVER had, PACMFORMATTAGDETAILSW paftd,
                                   ACMFORMATTAGENUMCBW fnCallback,
                                   DWORD_PTR dwInstance, DWORD fdwEnum)
 {
-    PWINE_ACMDRIVERID          padid;
-    unsigned int                       i;
-    BOOL                       bPcmDone = FALSE;
+    PWINE_ACMDRIVERID   padid;
+    unsigned int        i;
+    BOOL                bPcmDone = FALSE;
 
     TRACE("(%p, %p, %p, %ld, %d)\n",
-         had, paftd, fnCallback, dwInstance, fdwEnum);
+          had, paftd, fnCallback, dwInstance, fdwEnum);
 
     if (!paftd)
         return MMSYSERR_INVALPARAM;
@@ -841,63 +1027,60 @@ MMRESULT WINAPI acmFormatTagEnumW(HACMDRIVER had, PACMFORMATTAGDETAILSW paftd,
     /* if (had) FIXME("had != NULL, not supported\n"); */
 
     if (had) {
+        if (acmDriverID((HACMOBJ)had, (HACMDRIVERID *)&padid, 0) != MMSYSERR_NOERROR)
+        return MMSYSERR_INVALHANDLE;
 
-       if (acmDriverID((HACMOBJ)had, (HACMDRIVERID *)&padid, 0) != MMSYSERR_NOERROR)
-          return MMSYSERR_INVALHANDLE;
-
-       for (i = 0; i < padid->cFormatTags; i++) {
-         paftd->dwFormatTagIndex = i;
-         if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
-         (LPARAM)paftd, ACM_FORMATTAGDETAILSF_INDEX) == MMSYSERR_NOERROR) {
-            if (paftd->dwFormatTag == WAVE_FORMAT_PCM) {
-               if (paftd->szFormatTag[0] == 0)
-                  MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
-                        sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
-               /* (WS) I'm preserving this PCM hack since it seems to be
-                * correct. Please notice this block was borrowed from
-                * below.
-                */
-               if (bPcmDone) continue;
-                  bPcmDone = TRUE;
-            }
-            if (!(fnCallback)((HACMDRIVERID)padid, paftd, dwInstance, padid->fdwSupport)) 
-                return MMSYSERR_NOERROR;
-         }
-       }
-
+        for (i = 0; i < padid->cFormatTags; i++) {
+            paftd->dwFormatTagIndex = i;
+            if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
+                (LPARAM)paftd, ACM_FORMATTAGDETAILSF_INDEX) == MMSYSERR_NOERROR) {
+                if (paftd->dwFormatTag == WAVE_FORMAT_PCM) {
+                    if (paftd->szFormatTag[0] == 0)
+                        MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
+                                            sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
+                    /* (WS) I'm preserving this PCM hack since it seems to be
+                     * correct. Please notice this block was borrowed from
+                     * below.
+                     */
+                    if (bPcmDone) continue;
+                    bPcmDone = TRUE;
+                }
+                if (!(fnCallback)((HACMDRIVERID)padid, paftd, dwInstance, padid->fdwSupport))
+                    return MMSYSERR_NOERROR;
+            }
+        }
     }
-
     /* if had==0 then search for the first suitable driver */
     else {
-       for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
-          /* should check for codec only */
-          if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
-            acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == MMSYSERR_NOERROR) {
-            for (i = 0; i < padid->cFormatTags; i++) {
-               paftd->dwFormatTagIndex = i;
-               if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
-                  (LPARAM)paftd, ACM_FORMATTAGDETAILSF_INDEX) == MMSYSERR_NOERROR) {
-                  if (paftd->dwFormatTag == WAVE_FORMAT_PCM) {
-                     if (paftd->szFormatTag[0] == 0)
-                        MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
-                                sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
-                     /* FIXME (EPP): I'm not sure this is the correct
-                      * algorithm (should make more sense to apply the same
-                      * for all already loaded formats, but this will do
-                      * for now
-                      */
-                     if (bPcmDone) continue;
-                        bPcmDone = TRUE;
-                  }
-                  if (!(fnCallback)((HACMDRIVERID)padid, paftd, dwInstance, padid->fdwSupport)) {
-                      acmDriverClose(had, 0);
-                      return MMSYSERR_NOERROR;
-                  }
-               }
-            }
-            acmDriverClose(had, 0);
-          }
-       }
+        for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) {
+            /* should check for codec only */
+            if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) &&
+                acmDriverOpen(&had, (HACMDRIVERID)padid, 0) == MMSYSERR_NOERROR) {
+                for (i = 0; i < padid->cFormatTags; i++) {
+                    paftd->dwFormatTagIndex = i;
+                    if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS,
+                        (LPARAM)paftd, ACM_FORMATTAGDETAILSF_INDEX) == MMSYSERR_NOERROR) {
+                        if (paftd->dwFormatTag == WAVE_FORMAT_PCM) {
+                            if (paftd->szFormatTag[0] == 0)
+                                MultiByteToWideChar( CP_ACP, 0, "PCM", -1, paftd->szFormatTag,
+                                                     sizeof(paftd->szFormatTag)/sizeof(WCHAR) );
+                            /* FIXME (EPP): I'm not sure this is the correct
+                             * algorithm (should make more sense to apply the same
+                             * for all already loaded formats, but this will do
+                             * for now
+                             */
+                            if (bPcmDone) continue;
+                            bPcmDone = TRUE;
+                        }
+                        if (!(fnCallback)((HACMDRIVERID)padid, paftd, dwInstance, padid->fdwSupport)) {
+                            acmDriverClose(had, 0);
+                            return MMSYSERR_NOERROR;
+                        }
+                    }
+                }
+                acmDriverClose(had, 0);
+            }
+        }
     }
     return MMSYSERR_NOERROR;
 }