winmm: Check callback flags prior to opening a driver.
authorJörg Höhle <hoehle@users.sourceforge.net>
Tue, 15 Mar 2011 22:00:04 +0000 (23:00 +0100)
committerAlexandre Julliard <julliard@winehq.org>
Mon, 4 Apr 2011 12:42:12 +0000 (14:42 +0200)
dlls/winmm/tests/mixer.c
dlls/winmm/winmm.c

index 59627a7b38f9eb5ad6e2ea165f9ee91e35937360..da27b160ada0a5852284e2ea6c537be874585be6 100644 (file)
@@ -1004,6 +1004,7 @@ static void mixer_testsW(void)
 static void test_mixerOpen(void)
 {
     HMIXER mix;
+    HANDLE event;
     MMRESULT rc;
     UINT ndev, d;
 
@@ -1031,7 +1032,7 @@ static void test_mixerOpen(void)
 
         rc = mixerOpen(&mix, d, 0xdeadbeef, 0, CALLBACK_WINDOW);
         ok(rc == MMSYSERR_INVALPARAM ||
-           rc == MMSYSERR_NOERROR, /* 98 */
+           broken(rc == MMSYSERR_NOERROR /* 98 */),
            "mixerOpen: MMSYSERR_INVALPARAM expected, got %s\n",
            mmsys_error(rc));
         if (rc == MMSYSERR_NOERROR)
@@ -1042,7 +1043,35 @@ static void test_mixerOpen(void)
         ok(rc == MMSYSERR_NOERROR,
            "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
            mmsys_error(rc));
+        if (rc == MMSYSERR_NOERROR)
+            test_mixerClose(mix);
+
+        rc = mixerOpen(&mix, d, 0, 0, CALLBACK_THREAD);
+        ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
+           rc == MMSYSERR_NOTSUPPORTED, /* 98 */
+           "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
+           mmsys_error(rc));
+        if (rc == MMSYSERR_NOERROR)
+            test_mixerClose(mix);
+
+        rc = mixerOpen(&mix, d, 0, 0, CALLBACK_EVENT);
+        ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
+           rc == MMSYSERR_NOTSUPPORTED, /* 98 */
+           "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
+           mmsys_error(rc));
+        if (rc == MMSYSERR_NOERROR)
+            test_mixerClose(mix);
 
+        event = CreateEvent(NULL, FALSE, FALSE, NULL);
+        ok(event != NULL, "CreateEvent(): error=%d\n", GetLastError());
+
+        /* NOTSUPPORTED is not broken, but it enables the todo_wine marker. */
+        rc = mixerOpen(&mix, d, (DWORD_PTR)event, 0, CALLBACK_EVENT);
+        todo_wine
+        ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
+           broken(rc == MMSYSERR_NOTSUPPORTED), /* 98 */
+           "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
+           mmsys_error(rc));
         if (rc == MMSYSERR_NOERROR)
             test_mixerClose(mix);
 
@@ -1054,6 +1083,10 @@ static void test_mixerOpen(void)
 
         if (rc == MMSYSERR_NOERROR)
             test_mixerClose(mix);
+
+        rc = WaitForSingleObject(event, 0);
+        ok(rc == WAIT_TIMEOUT, "WaitEvent %d\n", rc);
+        CloseHandle(event);
     }
 }
 
index 6d5950ba2d1d1413bb34a7e5d55cfc7edad7671d..29f068b80fa68e761ae668f03d9cce723460c13b 100644 (file)
@@ -172,6 +172,35 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
     return TRUE;
 }
 
+/**************************************************************************
+ *                     WINMM_CheckCallback                     [internal]
+ */
+static MMRESULT WINMM_CheckCallback(DWORD_PTR dwCallback, DWORD fdwOpen, BOOL mixer)
+{
+    switch (fdwOpen & CALLBACK_TYPEMASK) {
+    case CALLBACK_NULL:     /* dwCallback need not be NULL */
+        break;
+    case CALLBACK_WINDOW:
+        if (dwCallback && !IsWindow((HWND)dwCallback))
+            return MMSYSERR_INVALPARAM;
+        break;
+
+    case CALLBACK_FUNCTION:
+        /* a NULL cb is acceptable since w2k, MMSYSERR_INVALPARAM earlier */
+        if (mixer)
+            return MMSYSERR_INVALFLAG; /* since w2k, MMSYSERR_NOTSUPPORTED earlier */
+        break;
+    case CALLBACK_THREAD:
+    case CALLBACK_EVENT:
+        if (mixer) /* FIXME: mixer supports THREAD+EVENT since w2k */
+            return MMSYSERR_NOTSUPPORTED; /* w9X */
+        break;
+    default:
+        WARN("Unknown callback type %d\n", HIWORD(fdwOpen));
+    }
+    return MMSYSERR_NOERROR;
+}
+
 /**************************************************************************
  *     Mixer devices. New to Win95
  */
@@ -297,35 +326,27 @@ UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
 {
     HANDLE             hMix;
     LPWINE_MLD         wmld;
-    DWORD              dwRet = 0;
+    DWORD              dwRet;
     MIXEROPENDESC      mod;
 
     TRACE("(%p, %d, %08lx, %08lx, %08x)\n",
          lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
 
-    mod.dwCallback = (DWORD_PTR)MIXER_WCallback;
-    mod.dwInstance = 0;
+    dwRet = WINMM_CheckCallback(dwCallback, fdwOpen, TRUE);
+    if (dwRet != MMSYSERR_NOERROR)
+        return dwRet;
 
-/* If callback is a function,
- * dwCallback contains function pointer
- * dwInstance private data
- *
- * if callback is a window
- * dwCallback contains a window handle
- */
-    switch (fdwOpen & CALLBACK_TYPEMASK) {
-    default:
-        return MMSYSERR_INVALFLAG;
-
-    case CALLBACK_NULL:
-        break;
-
-    case CALLBACK_WINDOW:
+    mod.dwCallback = (DWORD_PTR)MIXER_WCallback;
+    if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_WINDOW)
         mod.dwInstance = dwCallback;
-        if (dwCallback && !IsWindow((HWND)dwCallback))
-            return MMSYSERR_INVALPARAM;
-        break;
-    }
+    else
+        mod.dwInstance = 0;
+
+    /* We're remapping to CALLBACK_FUNCTION because that's what old winmm is
+     * documented to do when opening the mixer driver.
+     * FIXME: Native supports CALLBACK_EVENT + CALLBACK_THREAD flags since w2k.
+     * FIXME: The non ALSA drivers ignore callback requests - bug.
+     */
 
     wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
                       &dwCallback, &dwInstance);
@@ -901,19 +922,16 @@ UINT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
 {
     HMIDIOUT           hMidiOut;
     LPWINE_MIDI                lpwm;
-    UINT               dwRet = 0;
+    UINT               dwRet;
 
     TRACE("(%p, %d, %08lX, %08lX, %08X);\n",
          lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
 
     if (lphMidiOut != NULL) *lphMidiOut = 0;
 
-    switch (dwFlags & CALLBACK_TYPEMASK) {
-    case CALLBACK_WINDOW:
-        if (dwCallback && !IsWindow((HWND)dwCallback))
-            return MMSYSERR_INVALPARAM;
-        break;
-    }
+    dwRet = WINMM_CheckCallback(dwCallback, dwFlags, FALSE);
+    if (dwRet != MMSYSERR_NOERROR)
+       return dwRet;
 
     lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags, 0, NULL);
 
@@ -1200,13 +1218,17 @@ UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
 {
     HANDLE             hMidiIn;
     LPWINE_MIDI                lpwm;
-    DWORD              dwRet = 0;
+    DWORD              dwRet;
 
     TRACE("(%p, %d, %08lX, %08lX, %08X);\n",
          lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
 
     if (lphMidiIn != NULL) *lphMidiIn = 0;
 
+    dwRet = WINMM_CheckCallback(dwCallback, dwFlags, FALSE);
+    if (dwRet != MMSYSERR_NOERROR)
+       return dwRet;
+
     lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
                                    &dwFlags, &dwCallback, &dwInstance);
 
@@ -1758,12 +1780,9 @@ MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
     if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
        return MMSYSERR_INVALPARAM;
 
-    switch (fdwOpen & CALLBACK_TYPEMASK) {
-    case CALLBACK_WINDOW:
-        if (dwCallback && !IsWindow((HWND)dwCallback))
-            return MMSYSERR_INVALPARAM;
-        break;
-    }
+    ret = WINMM_CheckCallback(dwCallback, fdwOpen, FALSE);
+    if (ret != MMSYSERR_NOERROR)
+       return ret;
 
     lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
     if (!lpMidiStrm)
@@ -2012,7 +2031,7 @@ static UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
 {
     HANDLE             handle;
     LPWINE_MLD         wmld;
-    DWORD              dwRet = MMSYSERR_NOERROR;
+    DWORD              dwRet;
     WAVEOPENDESC       wod;
 
     TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08X);\n",
@@ -2022,6 +2041,10 @@ static UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
     if (dwFlags & WAVE_FORMAT_QUERY)
         TRACE("WAVE_FORMAT_QUERY requested !\n");
 
+    dwRet = WINMM_CheckCallback(dwCallback, dwFlags, FALSE);
+    if (dwRet != MMSYSERR_NOERROR)
+        return dwRet;
+
     if (lpFormat == NULL) {
         WARN("bad format\n");
         return WAVERR_BADFORMAT;
@@ -2039,7 +2062,6 @@ static UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
 
     if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
                            &dwFlags, &dwCallback, &dwInstance)) == NULL) {
-        WARN("no memory\n");
        return MMSYSERR_NOMEM;
     }