Akihiro Sagawa : mciqtz32: Fix notify flag behavior.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Mar 18 10:26:28 CDT 2015


Module: wine
Branch: master
Commit: 0221688cdde04f347580bd3376b5b1a2fae6573a
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=0221688cdde04f347580bd3376b5b1a2fae6573a

Author: Akihiro Sagawa <sagawa.aki at gmail.com>
Date:   Wed Mar 18 00:04:59 2015 +0900

mciqtz32: Fix notify flag behavior.

---

 dlls/mciqtz32/mciqtz.c         | 116 +++++++++++++++++++++++++++++++++--------
 dlls/mciqtz32/mciqtz_private.h |   6 ++-
 dlls/winmm/tests/mci.c         |   6 +--
 3 files changed, 103 insertions(+), 25 deletions(-)

diff --git a/dlls/mciqtz32/mciqtz.c b/dlls/mciqtz32/mciqtz.c
index a72f1af..a1c3450 100644
--- a/dlls/mciqtz32/mciqtz.c
+++ b/dlls/mciqtz32/mciqtz.c
@@ -85,6 +85,7 @@ static DWORD MCIQTZ_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
     if (!wma)
         return 0;
 
+    wma->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
     wma->wDevID = modp->wDeviceID;
     modp->wCustomCommandTable = wma->command_table = mciLoadCommandResource(MCIQTZ_hInstance, mciAviWStr, 0);
@@ -110,6 +111,7 @@ static DWORD MCIQTZ_drvClose(DWORD dwDevID)
 
         mciFreeCommandResource(wma->command_table);
         mciSetDriverData(dwDevID, 0);
+        CloseHandle(wma->stop_event);
         HeapFree(GetProcessHeap(), 0, wma);
         return 1;
     }
@@ -137,6 +139,20 @@ static DWORD MCIQTZ_drvConfigure(DWORD dwDevID)
     return 1;
 }
 
+/**************************************************************************
+ *                              MCIQTZ_mciNotify                [internal]
+ *
+ * Notifications in MCI work like a 1-element queue.
+ * Each new notification request supersedes the previous one.
+ */
+static void MCIQTZ_mciNotify(DWORD_PTR hWndCallBack, WINE_MCIQTZ* wma, UINT wStatus)
+{
+    MCIDEVICEID wDevID = wma->notify_devid;
+    HANDLE old = InterlockedExchangePointer(&wma->callback, NULL);
+    if (old) mciDriverNotify(old, wDevID, MCI_NOTIFY_SUPERSEDED);
+    mciDriverNotify(HWND_32(LOWORD(hWndCallBack)), wDevID, wStatus);
+}
+
 /***************************************************************************
  *                              MCIQTZ_mciOpen                  [internal]
  */
@@ -307,6 +323,63 @@ static DWORD MCIQTZ_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpP
 }
 
 /***************************************************************************
+ *                              MCIQTZ_notifyThread             [internal]
+ */
+static DWORD CALLBACK MCIQTZ_notifyThread(LPVOID parm)
+{
+    WINE_MCIQTZ* wma = (WINE_MCIQTZ *)parm;
+    HRESULT hr;
+    HANDLE handle[2];
+    DWORD n = 0, ret = 0;
+
+    handle[n++] = wma->stop_event;
+    IMediaEvent_GetEventHandle(wma->mevent, (OAEVENT *)&handle[n++]);
+
+    for (;;) {
+        DWORD r;
+        HANDLE old;
+
+        r = WaitForMultipleObjects(n, handle, FALSE, INFINITE);
+        if (r == WAIT_OBJECT_0) {
+            TRACE("got stop event\n");
+            old = InterlockedExchangePointer(&wma->callback, NULL);
+            if (old)
+                mciDriverNotify(old, wma->notify_devid, MCI_NOTIFY_ABORTED);
+            break;
+        }
+        else if (r == WAIT_OBJECT_0+1) {
+            LONG event_code;
+            LONG_PTR p1, p2;
+            do {
+                hr = IMediaEvent_GetEvent(wma->mevent, &event_code, &p1, &p2, 0);
+                if (SUCCEEDED(hr)) {
+                    TRACE("got event_code = 0x%02x\n", event_code);
+                    IMediaEvent_FreeEventParams(wma->mevent, event_code, p1, p2);
+                }
+            } while (hr == S_OK && event_code != EC_COMPLETE);
+            if (hr == S_OK && event_code == EC_COMPLETE) {
+                old = InterlockedExchangePointer(&wma->callback, NULL);
+                if (old)
+                    mciDriverNotify(old, wma->notify_devid, MCI_NOTIFY_SUCCESSFUL);
+                break;
+            }
+        }
+        else {
+            TRACE("Unknown error (%d)\n", (int)r);
+            break;
+        }
+    }
+
+    hr = IMediaControl_Stop(wma->pmctrl);
+    if (FAILED(hr)) {
+        TRACE("Cannot stop filtergraph (hr = %x)\n", hr);
+        ret = MCIERR_INTERNAL;
+    }
+
+    return ret;
+}
+
+/***************************************************************************
  *                              MCIQTZ_mciPlay                  [internal]
  */
 static DWORD MCIQTZ_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
@@ -326,6 +399,14 @@ static DWORD MCIQTZ_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
 
+    ResetEvent(wma->stop_event);
+    if (dwFlags & MCI_NOTIFY) {
+        HANDLE old;
+        old = InterlockedExchangePointer(&wma->callback, HWND_32(LOWORD(lpParms->dwCallback)));
+        if (old)
+            mciDriverNotify(old, wma->notify_devid, MCI_NOTIFY_ABORTED);
+    }
+
     IMediaSeeking_GetTimeFormat(wma->seek, &format);
     if (dwFlags & MCI_FROM) {
         if (IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME))
@@ -352,8 +433,11 @@ static DWORD MCIQTZ_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms
 
     IVideoWindow_put_Visible(wma->vidwin, OATRUE);
 
-    if (dwFlags & MCI_NOTIFY)
-        mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
+    wma->thread = CreateThread(NULL, 0, MCIQTZ_notifyThread, wma, 0, NULL);
+    if (!wma->thread) {
+        TRACE("Can't create thread\n");
+        return MCIERR_INTERNAL;
+    }
     return 0;
 }
 
@@ -397,7 +481,7 @@ static DWORD MCIQTZ_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms
     }
 
     if (dwFlags & MCI_NOTIFY)
-        mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
+        MCIQTZ_mciNotify(lpParms->dwCallback, wma, MCI_NOTIFY_SUCCESSFUL);
 
     return 0;
 }
@@ -408,7 +492,6 @@ static DWORD MCIQTZ_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms
 static DWORD MCIQTZ_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
     WINE_MCIQTZ* wma;
-    HRESULT hr;
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
 
@@ -419,10 +502,11 @@ static DWORD MCIQTZ_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpPa
     if (!wma->opened)
         return 0;
 
-    hr = IMediaControl_Stop(wma->pmctrl);
-    if (FAILED(hr)) {
-        TRACE("Cannot stop filtergraph (hr = %x)\n", hr);
-        return MCIERR_INTERNAL;
+    if (wma->thread) {
+        SetEvent(wma->stop_event);
+        WaitForSingleObject(wma->thread, INFINITE);
+        CloseHandle(wma->thread);
+        wma->thread = NULL;
     }
 
     if (!wma->parent)
@@ -676,19 +760,9 @@ static DWORD MCIQTZ_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STATUS_PARMS
             if (state == State_Stopped)
                 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_STOP, MCI_MODE_STOP);
             else if (state == State_Running) {
-                LONG code;
-                LONG_PTR p1, p2;
-
                 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_PLAY, MCI_MODE_PLAY);
-
-                do {
-                    hr = IMediaEvent_GetEvent(wma->mevent, &code, &p1, &p2, 0);
-                    if (hr == S_OK && code == EC_COMPLETE){
-                        lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_STOP, MCI_MODE_STOP);
-                        IMediaControl_Stop(wma->pmctrl);
-                    }
-                } while (hr == S_OK);
-
+                if (!wma->thread || WaitForSingleObject(wma->thread, 0) == WAIT_OBJECT_0)
+                    lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_STOP, MCI_MODE_STOP);
             } else if (state == State_Paused)
                 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_PAUSE, MCI_MODE_PAUSE);
             ret = MCI_RESOURCE_RETURNED;
@@ -714,7 +788,7 @@ static DWORD MCIQTZ_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STATUS_PARMS
     }
 
     if (dwFlags & MCI_NOTIFY)
-        mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
+        MCIQTZ_mciNotify(lpParms->dwCallback, wma, MCI_NOTIFY_SUCCESSFUL);
 
     return ret;
 }
diff --git a/dlls/mciqtz32/mciqtz_private.h b/dlls/mciqtz32/mciqtz_private.h
index 7263a26..27939aa 100644
--- a/dlls/mciqtz32/mciqtz_private.h
+++ b/dlls/mciqtz32/mciqtz_private.h
@@ -38,7 +38,11 @@ typedef struct {
     IBasicAudio*   audio;
     DWORD          time_format;
     UINT           command_table;
-    HWND parent;
+    HWND           parent;
+    MCIDEVICEID    notify_devid;
+    HANDLE         callback;
+    HANDLE         thread;
+    HANDLE         stop_event;
 } WINE_MCIQTZ;
 
 #endif  /* __WINE_PRIVATE_MCIQTZ_H */
diff --git a/dlls/winmm/tests/mci.c b/dlls/winmm/tests/mci.c
index 423fceb..7470ed1 100644
--- a/dlls/winmm/tests/mci.c
+++ b/dlls/winmm/tests/mci.c
@@ -1376,7 +1376,7 @@ static void test_asyncWaveTypeMpegvideo(HWND hwnd)
     err = mciSendStringA("status mysound mode notify", buf, sizeof(buf), hwnd);
     ok(!err,"mci status mode returned %s\n", dbg_mcierr(err));
     if(!err) ok(!strcmp(buf,"paused"), "mci status mode: %s\n", buf);
-    todo_wine test_notification(hwnd,"play (superseded)",MCI_NOTIFY_SUPERSEDED);
+    test_notification(hwnd,"play (superseded)",MCI_NOTIFY_SUPERSEDED);
     test_notification(hwnd,"status",MCI_NOTIFY_SUCCESSFUL);
 
     err = mciSendStringA("seek mysound to start wait", NULL, 0, NULL);
@@ -1388,11 +1388,11 @@ static void test_asyncWaveTypeMpegvideo(HWND hwnd)
     err = mciSendStringA("play mysound to 1500 notify", NULL, 0, hwnd);
     ok(!err,"mci play returned %s\n", dbg_mcierr(err));
     Sleep(200);
-    todo_wine test_notification(hwnd,"play",0);
+    test_notification(hwnd,"play",0);
 
     err = mciSendStringA("close mysound wait", NULL, 0, NULL);
     ok(!err,"mci close wait returned %s\n", dbg_mcierr(err));
-    todo_wine test_notification(hwnd,"play (aborted by close)",MCI_NOTIFY_ABORTED);
+    test_notification(hwnd,"play (aborted by close)",MCI_NOTIFY_ABORTED);
 }
 
 START_TEST(mci)




More information about the wine-cvs mailing list