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