[MCIQTZ32] Sync with Wine Staging 1.7.47. CORE-9924
[reactos.git] / reactos / dll / win32 / mciqtz32 / mciqtz.c
index 4471251..3269c0c 100644 (file)
@@ -33,7 +33,7 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(mciqtz);
 
-static DWORD MCIQTZ_mciClose(UINT, DWORD, LPMCI_GENERIC_PARMS);
+static DWORD CALLBACK MCIQTZ_taskThread(LPVOID arg);
 static DWORD MCIQTZ_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
 
 /*======================================================================*
@@ -70,6 +70,40 @@ static WINE_MCIQTZ* MCIQTZ_mciGetOpenDev(UINT wDevID)
     return wma;
 }
 
+/***************************************************************************
+ *                              MCIQTZ_relayTaskMessage         [internal]
+ */
+static LRESULT MCIQTZ_relayTaskMessage(DWORD_PTR dwDevID, UINT wMsg,
+                                      DWORD dwFlags, LPARAM lpParms)
+{
+    WINE_MCIQTZ *wma;
+    LRESULT res;
+    HANDLE handles[2];
+    DWORD ret;
+    TRACE("(%08lX, %08x, %08x, %08lx)\n", dwDevID, wMsg, dwFlags, lpParms);
+
+    wma = MCIQTZ_mciGetOpenDev(dwDevID);
+    if (!wma)
+        return MCIERR_INVALID_DEVICE_ID;
+    EnterCriticalSection(&wma->cs);
+    wma->task.devid = dwDevID;
+    wma->task.msg   = wMsg;
+    wma->task.flags = dwFlags;
+    wma->task.parms = lpParms;
+    SetEvent(wma->task.notify);
+    handles[0] = wma->task.done;
+    handles[1] = wma->task.thread;
+    ret = WaitForMultipleObjects(sizeof(handles)/sizeof(handles[0]), handles,
+                                 FALSE, INFINITE);
+    if (ret == WAIT_OBJECT_0)
+        res = wma->task.res;
+    else
+        res = MCIERR_INTERNAL;
+    LeaveCriticalSection(&wma->cs);
+
+    return res;
+}
+
 /**************************************************************************
  *                              MCIQTZ_drvOpen                  [internal]
  */
@@ -88,12 +122,26 @@ static DWORD MCIQTZ_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
     if (!wma)
         return 0;
 
+    wma->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+    wma->task.notify = CreateEventW(NULL, FALSE, FALSE, NULL);
+    if (!wma->task.notify) goto err;
+    wma->task.done = CreateEventW(NULL, FALSE, FALSE, NULL);
+    if (!wma->task.done)   goto err;
+    wma->task.thread = CreateThread(NULL, 0, MCIQTZ_taskThread, &wma->task, 0, NULL);
+    if (!wma->task.thread) goto err;
+    InitializeCriticalSection(&wma->cs);
+    wma->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": WINE_MCIQTZ");
     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
     wma->wDevID = modp->wDeviceID;
     modp->wCustomCommandTable = wma->command_table = mciLoadCommandResource(MCIQTZ_hInstance, mciAviWStr, 0);
     mciSetDriverData(wma->wDevID, (DWORD_PTR)wma);
 
     return modp->wDeviceID;
+err:
+    if (wma->task.notify) CloseHandle(wma->task.notify);
+    if (wma->task.done)   CloseHandle(wma->task.done);
+    HeapFree(GetProcessHeap(), 0, wma);
+    return 0;
 }
 
 /**************************************************************************
@@ -109,10 +157,17 @@ static DWORD MCIQTZ_drvClose(DWORD dwDevID)
 
     if (wma) {
         /* finish all outstanding things */
-        MCIQTZ_mciClose(dwDevID, MCI_WAIT, NULL);
+        MCIQTZ_relayTaskMessage(dwDevID, MCI_CLOSE_DRIVER, MCI_WAIT, 0);
 
         mciFreeCommandResource(wma->command_table);
+        MCIQTZ_relayTaskMessage(dwDevID, MCI_CLOSE, MCI_WAIT, 0);
+        WaitForSingleObject(wma->task.thread, INFINITE);
+        CloseHandle(wma->task.notify);
+        CloseHandle(wma->task.done);
+        CloseHandle(wma->task.thread);
+        DeleteCriticalSection(&wma->cs);
         mciSetDriverData(dwDevID, 0);
+        CloseHandle(wma->stop_event);
         HeapFree(GetProcessHeap(), 0, wma);
         return 1;
     }
@@ -140,6 +195,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]
  */
@@ -153,9 +222,6 @@ static DWORD MCIQTZ_mciOpen(UINT wDevID, DWORD dwFlags,
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpOpenParms);
 
-    if (!lpOpenParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
-
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
@@ -201,6 +267,12 @@ static DWORD MCIQTZ_mciOpen(UINT wDevID, DWORD dwFlags,
         goto err;
     }
 
+    hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IBasicAudio, (void**)&wma->audio);
+    if (FAILED(hr)) {
+        TRACE("Cannot get IBasicAudio interface (hr = %x)\n", hr);
+        goto err;
+    }
+
     if (!(dwFlags & MCI_OPEN_ELEMENT) || (dwFlags & MCI_OPEN_ELEMENT_ID)) {
         TRACE("Wrong dwFlags %x\n", dwFlags);
         goto err;
@@ -243,6 +315,9 @@ static DWORD MCIQTZ_mciOpen(UINT wDevID, DWORD dwFlags,
     return 0;
 
 err:
+    if (wma->audio)
+        IBasicAudio_Release(wma->audio);
+    wma->audio = NULL;
     if (wma->vidbasic)
         IBasicVideo_Release(wma->vidbasic);
     wma->vidbasic = NULL;
@@ -287,6 +362,7 @@ static DWORD MCIQTZ_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpP
     if (wma->opened) {
         IVideoWindow_Release(wma->vidwin);
         IBasicVideo_Release(wma->vidbasic);
+        IBasicAudio_Release(wma->audio);
         IMediaSeeking_Release(wma->seek);
         IMediaEvent_Release(wma->mevent);
         IGraphBuilder_Release(wma->pgraph);
@@ -299,6 +375,63 @@ static DWORD MCIQTZ_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpP
     return 0;
 }
 
+/***************************************************************************
+ *                              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]
  */
@@ -312,13 +445,18 @@ static DWORD MCIQTZ_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
 
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
-
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     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))
@@ -345,8 +483,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;
 }
 
@@ -361,9 +502,6 @@ static DWORD MCIQTZ_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
 
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
-
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
@@ -390,7 +528,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;
 }
@@ -401,7 +539,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);
 
@@ -412,10 +549,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)
@@ -456,9 +594,6 @@ static DWORD MCIQTZ_mciGetDevCaps(UINT wDevID, DWORD dwFlags, LPMCI_GETDEVCAPS_P
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
 
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
-
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
@@ -555,9 +690,6 @@ static DWORD MCIQTZ_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SET_PARMS lpPar
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
 
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
-
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
@@ -612,9 +744,6 @@ static DWORD MCIQTZ_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STATUS_PARMS
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
 
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
-
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
@@ -669,19 +798,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;
@@ -707,7 +826,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;
 }
@@ -725,9 +844,6 @@ static DWORD MCIQTZ_mciWhere(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lp
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
 
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
-
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
@@ -790,8 +906,6 @@ static DWORD MCIQTZ_mciWindow(UINT wDevID, DWORD dwFlags, LPMCI_DGV_WINDOW_PARMS
 
     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
 
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
     if (dwFlags & MCI_TEST)
@@ -835,9 +949,6 @@ static DWORD MCIQTZ_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS
 
     TRACE("%04x, %08x, %p\n", wDevID, dwFlags, lpParms);
 
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
-
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
@@ -895,18 +1006,115 @@ out:
 static DWORD MCIQTZ_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
 {
     WINE_MCIQTZ *wma;
+    DWORD ret = 0;
 
-    FIXME("(%04x, %08x, %p) : stub\n", wDevID, dwFlags, lpParms);
-
-    if (!lpParms)
-        return MCIERR_NULL_PARAMETER_BLOCK;
+    TRACE("(%04x, %08x, %p)\n", wDevID, dwFlags, lpParms);
 
     wma = MCIQTZ_mciGetOpenDev(wDevID);
     if (!wma)
         return MCIERR_INVALID_DEVICE_ID;
 
-    MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
+    if (!(dwFlags & MCI_DGV_SETAUDIO_ITEM)) {
+        FIXME("Unknown flags (%08x)\n", dwFlags);
+        return 0;
+    }
+
+    if (dwFlags & MCI_DGV_SETAUDIO_ITEM) {
+        switch (lpParms->dwItem) {
+        case MCI_DGV_SETAUDIO_VOLUME:
+            if (dwFlags & MCI_DGV_SETAUDIO_VALUE) {
+                long vol = -10000;
+                HRESULT hr;
+                if (lpParms->dwValue > 1000) {
+                    ret = MCIERR_OUTOFRANGE;
+                    break;
+                }
+                if (dwFlags & MCI_TEST)
+                    break;
+                vol += (long)lpParms->dwValue * 10;
+                hr = IBasicAudio_put_Volume(wma->audio, vol);
+                if (FAILED(hr)) {
+                    WARN("Cannot set volume (hr = %x)\n", hr);
+                    ret = MCIERR_INTERNAL;
+                }
+            }
+            break;
+        default:
+            FIXME("Unknown item %08x\n", lpParms->dwItem);
+            break;
+        }
+    }
+
+    return ret;
+}
+
+/***************************************************************************
+ *                              MCIQTZ_taskThread               [internal]
+ */
+static DWORD CALLBACK MCIQTZ_taskThread(LPVOID arg)
+{
+    WINE_MCIQTZ_TASK *task = (WINE_MCIQTZ_TASK *)arg;
+
+    for (;;) {
+        DWORD ret = WaitForSingleObject(task->notify, INFINITE);
+        if (ret != WAIT_OBJECT_0) {
+            TRACE("Got error (%u)\n", ret);
+            continue;
+        }
+
+        switch (task->msg) {
+        case MCI_OPEN_DRIVER:
+            task->res = MCIQTZ_mciOpen(task->devid, task->flags, (LPMCI_DGV_OPEN_PARMSW)task->parms);
+            break;
+        case MCI_CLOSE_DRIVER:
+            task->res = MCIQTZ_mciClose(task->devid, task->flags, (LPMCI_GENERIC_PARMS)task->parms);
+            break;
+        case MCI_PLAY:
+            task->res = MCIQTZ_mciPlay(task->devid, task->flags, (LPMCI_PLAY_PARMS)task->parms);
+            break;
+        case MCI_SEEK:
+            task->res = MCIQTZ_mciSeek(task->devid, task->flags, (LPMCI_SEEK_PARMS)task->parms);
+            break;
+        case MCI_STOP:
+            task->res = MCIQTZ_mciStop(task->devid, task->flags, (LPMCI_GENERIC_PARMS)task->parms);
+            break;
+        case MCI_PAUSE:
+            task->res = MCIQTZ_mciPause(task->devid, task->flags, (LPMCI_GENERIC_PARMS)task->parms);
+            break;
+        case MCI_GETDEVCAPS:
+            task->res = MCIQTZ_mciGetDevCaps(task->devid, task->flags, (LPMCI_GETDEVCAPS_PARMS)task->parms);
+            break;
+        case MCI_SET:
+            task->res = MCIQTZ_mciSet(task->devid, task->flags, (LPMCI_DGV_SET_PARMS)task->parms);
+            break;
+        case MCI_STATUS:
+            task->res = MCIQTZ_mciStatus(task->devid, task->flags, (LPMCI_DGV_STATUS_PARMSW)task->parms);
+            break;
+        case MCI_WHERE:
+            task->res = MCIQTZ_mciWhere(task->devid, task->flags, (LPMCI_DGV_RECT_PARMS)task->parms);
+            break;
+        case MCI_SETAUDIO:
+            task->res = MCIQTZ_mciSetAudio(task->devid, task->flags, (LPMCI_DGV_SETAUDIO_PARMSW)task->parms);
+            break;
+        case MCI_UPDATE:
+            task->res = MCIQTZ_mciUpdate(task->devid, task->flags, (LPMCI_DGV_UPDATE_PARMS)task->parms);
+            break;
+        case MCI_WINDOW:
+            task->res = MCIQTZ_mciWindow(task->devid, task->flags, (LPMCI_DGV_WINDOW_PARMSW)task->parms);
+            break;
+        case MCI_CLOSE:
+            /* Special internal message */
+            SetEvent(task->done);
+            goto end;
+        default:
+            FIXME("Shouldn't receive another message (%04x)\n", task->msg);
+            task->res = MCIERR_UNRECOGNIZED_COMMAND;
+            break;
+        }
+        SetEvent(task->done);
+    }
 
+end:
     return 0;
 }
 
@@ -941,22 +1149,25 @@ LRESULT CALLBACK MCIQTZ_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
         return 1;
 
     switch (wMsg) {
-        case MCI_OPEN_DRIVER:   return MCIQTZ_mciOpen      (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSW)     dwParam2);
-        case MCI_CLOSE_DRIVER:  return MCIQTZ_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
-        case MCI_PLAY:          return MCIQTZ_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
-        case MCI_SEEK:          return MCIQTZ_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
-        case MCI_STOP:          return MCIQTZ_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
-        case MCI_PAUSE:         return MCIQTZ_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
-        case MCI_GETDEVCAPS:    return MCIQTZ_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
-        case MCI_SET:           return MCIQTZ_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
-        case MCI_STATUS:        return MCIQTZ_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW)   dwParam2);
-        case MCI_WHERE:         return MCIQTZ_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
+        case MCI_OPEN_DRIVER:
+        case MCI_PLAY:
+        case MCI_SEEK:
+        case MCI_GETDEVCAPS:
+        case MCI_SET:
+        case MCI_STATUS:
+        case MCI_WHERE:
+            if (!dwParam2) return MCIERR_NULL_PARAMETER_BLOCK;
+            return MCIQTZ_relayTaskMessage(dwDevID, wMsg, dwParam1, dwParam2);
+        case MCI_CLOSE_DRIVER:
+        case MCI_STOP:
+        case MCI_PAUSE:
+            return MCIQTZ_relayTaskMessage(dwDevID, wMsg, dwParam1, dwParam2);
         /* Digital Video specific */
-        case MCI_SETAUDIO:      return MCIQTZ_mciSetAudio  (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
+        case MCI_SETAUDIO:
         case MCI_UPDATE:
-            return MCIQTZ_mciUpdate(dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)dwParam2);
         case MCI_WINDOW:
-            return MCIQTZ_mciWindow(dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSW)dwParam2);
+            if (!dwParam2) return MCIERR_NULL_PARAMETER_BLOCK;
+            return MCIQTZ_relayTaskMessage(dwDevID, wMsg, dwParam1, dwParam2);
         case MCI_PUT:
         case MCI_RECORD:
         case MCI_RESUME: