rpcrt4: CContext can be NULL in NDRCContextMarshall, in which case we should marshall...
[wine] / dlls / mciavi32 / mciavi.c
1 /*
2  * Digital video MCI Wine Driver
3  *
4  * Copyright 1999, 2000 Eric POUECH
5  * Copyright 2003 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 /* TODO list :
23  *      - handling of palettes
24  *      - recording (which input devices ?), a cam recorder ?
25  *      - lots of messages still need to be handled (cf FIXME)
26  *      - synchronization between audio and video (especially for interleaved
27  *        files)
28  *      - robustness when reading file can be enhanced
29  *      - better move the AVI handling part to avifile DLL and make use of it
30  *      - some files appear to have more than one audio stream (we only play the
31  *        first one)
32  *      - some files contain an index of audio/video frame. Better use it,
33  *        instead of rebuilding it
34  *      - stopping while playing a file with sound blocks until all buffered
35  *        audio is played... still should be stopped ASAP
36  */
37
38 #include <string.h>
39 #include "private_mciavi.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
44
45 static DWORD MCIAVI_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
46
47 /*======================================================================*
48  *                          MCI AVI implemantation                      *
49  *======================================================================*/
50
51 HINSTANCE MCIAVI_hInstance = 0;
52
53 /***********************************************************************
54  *              DllMain (MCIAVI.0)
55  */
56 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
57 {
58     switch (fdwReason) {
59     case DLL_PROCESS_ATTACH:
60         DisableThreadLibraryCalls(hInstDLL);
61         MCIAVI_hInstance = hInstDLL;
62         break;
63     }
64     return TRUE;
65 }
66
67 /**************************************************************************
68  *                              MCIAVI_drvOpen                  [internal]
69  */
70 static  DWORD   MCIAVI_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
71 {
72     WINE_MCIAVI*        wma;
73     static const WCHAR mciAviWStr[] = {'M','C','I','A','V','I',0};
74
75     TRACE("%s, %p\n", debugstr_w(str), modp);
76
77     /* session instance */
78     if (!modp) return 0xFFFFFFFF;
79
80     if (!MCIAVI_RegisterClass()) return 0;
81
82     wma = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIAVI));
83     if (!wma)
84         return 0;
85
86     InitializeCriticalSection(&wma->cs);
87     wma->ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
88     wma->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
89     wma->wDevID = modp->wDeviceID;
90     wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, mciAviWStr, 0);
91     modp->wCustomCommandTable = wma->wCommandTable;
92     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
93     mciSetDriverData(wma->wDevID, (DWORD)wma);
94
95     return modp->wDeviceID;
96 }
97
98 /**************************************************************************
99  *                              MCIAVI_drvClose         [internal]
100  */
101 static  DWORD   MCIAVI_drvClose(DWORD dwDevID)
102 {
103     WINE_MCIAVI *wma;
104
105     TRACE("%04lx\n", dwDevID);
106
107     /* finish all outstanding things */
108     MCIAVI_mciClose(dwDevID, MCI_WAIT, NULL);
109
110     wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
111
112     if (wma) {
113         MCIAVI_UnregisterClass();
114
115         EnterCriticalSection(&wma->cs);
116
117         mciSetDriverData(dwDevID, 0);
118         mciFreeCommandResource(wma->wCommandTable);
119
120         CloseHandle(wma->ack_event);
121         CloseHandle(wma->hStopEvent);
122
123         LeaveCriticalSection(&wma->cs);
124         DeleteCriticalSection(&wma->cs);
125
126         HeapFree(GetProcessHeap(), 0, wma);
127         return 1;
128     }
129     return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
130 }
131
132 /**************************************************************************
133  *                              MCIAVI_drvConfigure             [internal]
134  */
135 static  DWORD   MCIAVI_drvConfigure(DWORD dwDevID)
136 {
137     WINE_MCIAVI *wma;
138
139     TRACE("%04lx\n", dwDevID);
140
141     MCIAVI_mciStop(dwDevID, MCI_WAIT, NULL);
142
143     wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
144
145     if (wma) {
146         MessageBoxA(0, "Sample AVI Wine Driver !", "MM-Wine Driver", MB_OK);
147         return 1;
148     }
149     return 0;
150 }
151
152 /**************************************************************************
153  *                              MCIAVI_mciGetOpenDev            [internal]
154  */
155 WINE_MCIAVI*  MCIAVI_mciGetOpenDev(UINT wDevID)
156 {
157     WINE_MCIAVI*        wma = (WINE_MCIAVI*)mciGetDriverData(wDevID);
158
159     if (wma == NULL || wma->nUseCount == 0) {
160         WARN("Invalid wDevID=%u\n", wDevID);
161         return 0;
162     }
163     return wma;
164 }
165
166 static void MCIAVI_CleanUp(WINE_MCIAVI* wma)
167 {
168     /* to prevent handling in WindowProc */
169     wma->dwStatus = MCI_MODE_NOT_READY;
170     if (wma->hFile) {
171         mmioClose(wma->hFile, 0);
172         wma->hFile = 0;
173
174         HeapFree(GetProcessHeap(), 0, wma->lpFileName);
175         wma->lpFileName = NULL;
176
177         HeapFree(GetProcessHeap(), 0, wma->lpVideoIndex);
178         wma->lpVideoIndex = NULL;
179         HeapFree(GetProcessHeap(), 0, wma->lpAudioIndex);
180         wma->lpAudioIndex = NULL;
181         if (wma->hic)           ICClose(wma->hic);
182         wma->hic = 0;
183         HeapFree(GetProcessHeap(), 0, wma->inbih);
184         wma->inbih = NULL;
185         HeapFree(GetProcessHeap(), 0, wma->outbih);
186         wma->outbih = NULL;
187         HeapFree(GetProcessHeap(), 0, wma->indata);
188         wma->indata = NULL;
189         HeapFree(GetProcessHeap(), 0, wma->outdata);
190         wma->outdata = NULL;
191         if (wma->hbmFrame)      DeleteObject(wma->hbmFrame);
192         wma->hbmFrame = 0;
193         if (wma->hWnd)          DestroyWindow(wma->hWnd);
194         wma->hWnd = 0;
195
196         HeapFree(GetProcessHeap(), 0, wma->lpWaveFormat);
197         wma->lpWaveFormat = 0;
198
199         memset(&wma->mah, 0, sizeof(wma->mah));
200         memset(&wma->ash_video, 0, sizeof(wma->ash_video));
201         memset(&wma->ash_audio, 0, sizeof(wma->ash_audio));
202         wma->dwCurrVideoFrame = wma->dwCurrAudioBlock = 0;
203         wma->dwCachedFrame = -1;
204     }
205 }
206
207 /***************************************************************************
208  *                              MCIAVI_mciOpen                  [internal]
209  */
210 static  DWORD   MCIAVI_mciOpen(UINT wDevID, DWORD dwFlags,
211                                LPMCI_DGV_OPEN_PARMSW lpOpenParms)
212 {
213     WINE_MCIAVI *wma;
214     LRESULT             dwRet = 0;
215
216     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
217
218     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
219
220     if (lpOpenParms == NULL)            return MCIERR_NULL_PARAMETER_BLOCK;
221
222     wma = (WINE_MCIAVI *)mciGetDriverData(wDevID);
223     if (wma == NULL)                    return MCIERR_INVALID_DEVICE_ID;
224
225     EnterCriticalSection(&wma->cs);
226
227     if (wma->nUseCount > 0) {
228         /* The driver is already open on this channel */
229         /* If the driver was opened shareable before and this open specifies */
230         /* shareable then increment the use count */
231         if (wma->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
232             ++wma->nUseCount;
233         else
234         {
235             LeaveCriticalSection(&wma->cs);
236             return MCIERR_MUST_USE_SHAREABLE;
237         }
238     } else {
239         wma->nUseCount = 1;
240         wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
241     }
242
243     wma->dwStatus = MCI_MODE_NOT_READY;
244
245     if (dwFlags & MCI_OPEN_ELEMENT) {
246         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
247             /* could it be that (DWORD)lpOpenParms->lpstrElementName
248              * contains the hFile value ?
249              */
250             dwRet = MCIERR_UNRECOGNIZED_COMMAND;
251         } else if (strlenW(lpOpenParms->lpstrElementName) > 0) {
252             /* FIXME : what should be done id wma->hFile is already != 0, or the driver is playin' */
253             TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(lpOpenParms->lpstrElementName));
254
255             if (lpOpenParms->lpstrElementName && (strlenW(lpOpenParms->lpstrElementName) > 0))
256             {
257                 wma->lpFileName = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpOpenParms->lpstrElementName) + 1) * sizeof(WCHAR));
258                 strcpyW(wma->lpFileName, lpOpenParms->lpstrElementName);
259
260                 wma->hFile = mmioOpenW(lpOpenParms->lpstrElementName, NULL,
261                                        MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READ);
262
263                 if (wma->hFile == 0) {
264                     WARN("can't find file=%s!\n", debugstr_w(lpOpenParms->lpstrElementName));
265                     dwRet = MCIERR_FILE_NOT_FOUND;
266                 } else {
267                     if (!MCIAVI_GetInfo(wma))
268                         dwRet = MCIERR_INVALID_FILE;
269                     else if (!MCIAVI_OpenVideo(wma))
270                         dwRet = MCIERR_CANNOT_LOAD_DRIVER;
271                     else if (!MCIAVI_CreateWindow(wma, dwFlags, lpOpenParms))
272                         dwRet = MCIERR_CREATEWINDOW;
273                 }
274             }
275         } else {
276             FIXME("Don't record yet\n");
277             dwRet = MCIERR_UNSUPPORTED_FUNCTION;
278         }
279     }
280
281     if (dwRet == 0) {
282         TRACE("lpOpenParms->wDeviceID = %04x\n", lpOpenParms->wDeviceID);
283
284         wma->dwStatus = MCI_MODE_STOP;
285         wma->dwMciTimeFormat = MCI_FORMAT_FRAMES;
286     } else {
287         MCIAVI_CleanUp(wma);
288     }
289
290     LeaveCriticalSection(&wma->cs);
291     return dwRet;
292 }
293
294 /***************************************************************************
295  *                              MCIAVI_mciClose                 [internal]
296  */
297 DWORD MCIAVI_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
298 {
299     WINE_MCIAVI *wma;
300     DWORD               dwRet = 0;
301
302     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
303
304     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
305
306     wma = (WINE_MCIAVI *)MCIAVI_mciGetOpenDev(wDevID);
307     if (wma == NULL)    return MCIERR_INVALID_DEVICE_ID;
308
309     EnterCriticalSection(&wma->cs);
310
311     if (wma->nUseCount == 1) {
312         if (wma->dwStatus != MCI_MODE_STOP)
313            dwRet = MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
314         MCIAVI_CleanUp(wma);
315
316         if ((dwFlags & MCI_NOTIFY) && lpParms) {
317             mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
318                            wDevID,
319                             MCI_NOTIFY_SUCCESSFUL);
320         }
321         LeaveCriticalSection(&wma->cs);
322         return dwRet;
323     }
324     wma->nUseCount--;
325
326     LeaveCriticalSection(&wma->cs);
327     return dwRet;
328 }
329
330 static DWORD MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms);
331
332 struct MCIAVI_play_data
333 {
334     MCIDEVICEID wDevID;
335     DWORD flags;
336     MCI_PLAY_PARMS params;
337 };
338
339 /*
340  * MCIAVI_mciPlay_thread
341  *
342  * FIXME: probably should use a common worker thread created at the driver
343  * load time and queue all async commands to it.
344  */
345 static DWORD WINAPI MCIAVI_mciPlay_thread(LPVOID arg)
346 {
347     struct MCIAVI_play_data *data = (struct MCIAVI_play_data *)arg;
348     DWORD ret;
349
350     TRACE("In thread before async play command (id %08x, flags %08lx)\n", data->wDevID, data->flags);
351     ret = MCIAVI_mciPlay(data->wDevID, data->flags | MCI_WAIT, &data->params);
352     TRACE("In thread after async play command (id %08x, flags %08lx)\n", data->wDevID, data->flags);
353
354     HeapFree(GetProcessHeap(), 0, data);
355     return ret;
356 }
357
358 /*
359  * MCIAVI_mciPlay_async
360  */
361 static DWORD MCIAVI_mciPlay_async(WINE_MCIAVI *wma, DWORD dwFlags, LPMCI_PLAY_PARMS lpParams)
362 {
363     HANDLE handle, ack_event = wma->ack_event;
364     struct MCIAVI_play_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct MCIAVI_play_data));
365
366     if (!data) return MCIERR_OUT_OF_MEMORY;
367
368     data->wDevID = wma->wDevID;
369     data->flags = dwFlags;
370     memcpy(&data->params, lpParams, sizeof(MCI_PLAY_PARMS));
371
372     if (!(handle = CreateThread(NULL, 0, MCIAVI_mciPlay_thread, data, 0, NULL)))
373     {
374         WARN("Couldn't create thread for async play, playing synchronously\n");
375         return MCIAVI_mciPlay_thread(data);
376     }
377     SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
378     CloseHandle(handle);
379     /* wait until the thread starts up, so the app could see a changed status */
380     WaitForSingleObject(ack_event, INFINITE);
381     TRACE("Async play has started\n");
382     return 0;
383 }
384
385 /***************************************************************************
386  *                              MCIAVI_mciPlay                  [internal]
387  */
388 static  DWORD   MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
389 {
390     WINE_MCIAVI *wma;
391     DWORD               tc;
392     DWORD               frameTime;
393     DWORD               delta;
394     DWORD               dwRet;
395     LPWAVEHDR           waveHdr = NULL;
396     unsigned            i, nHdr = 0;
397     DWORD               dwFromFrame, dwToFrame;
398
399     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
400
401     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
402
403     wma = (WINE_MCIAVI *)MCIAVI_mciGetOpenDev(wDevID);
404     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
405
406     EnterCriticalSection(&wma->cs);
407
408     if (!wma->hFile)
409     {
410         LeaveCriticalSection(&wma->cs);
411         return MCIERR_FILE_NOT_FOUND;
412     }
413     if (!wma->hWndPaint)
414     {
415         LeaveCriticalSection(&wma->cs);
416         return MCIERR_NO_WINDOW;
417     }
418
419     LeaveCriticalSection(&wma->cs);
420
421     if (!(dwFlags & MCI_WAIT))
422         return MCIAVI_mciPlay_async(wma, dwFlags, lpParms);
423
424     if (!(GetWindowLongW(wma->hWndPaint, GWL_STYLE) & WS_VISIBLE))
425         ShowWindow(wma->hWndPaint, SW_SHOWNA);
426
427     EnterCriticalSection(&wma->cs);
428
429     dwFromFrame = wma->dwCurrVideoFrame;
430     dwToFrame = wma->dwPlayableVideoFrames - 1;
431
432     if (lpParms && (dwFlags & MCI_FROM)) {
433         dwFromFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwFrom);
434     }
435     if (lpParms && (dwFlags & MCI_TO)) {
436         dwToFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
437     }
438     if (dwToFrame >= wma->dwPlayableVideoFrames)
439         dwToFrame = wma->dwPlayableVideoFrames - 1;
440
441     TRACE("Playing from frame=%lu to frame=%lu\n", dwFromFrame, dwToFrame);
442
443     wma->dwCurrVideoFrame = dwFromFrame;
444     wma->dwToVideoFrame = dwToFrame;
445
446     /* if already playing exit */
447     if (wma->dwStatus == MCI_MODE_PLAY)
448     {
449         LeaveCriticalSection(&wma->cs);
450         SetEvent(wma->ack_event);
451         return 0;
452     }
453
454     if (wma->dwToVideoFrame <= wma->dwCurrVideoFrame)
455     {
456         dwRet = 0;
457         SetEvent(wma->ack_event);
458         goto mci_play_done;
459     }
460
461     wma->dwStatus = MCI_MODE_PLAY;
462     /* signal the state change */
463     SetEvent(wma->ack_event);
464
465     if (dwFlags & (MCI_DGV_PLAY_REPEAT|MCI_DGV_PLAY_REVERSE|MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLSCREEN))
466         FIXME("Unsupported flag %08lx\n", dwFlags);
467
468     /* time is in microseconds, we should convert it to milliseconds */
469     frameTime = (wma->mah.dwMicroSecPerFrame + 500) / 1000;
470
471     if (wma->lpWaveFormat) {
472        if (MCIAVI_OpenAudio(wma, &nHdr, &waveHdr) != 0)
473         {
474             /* can't play audio */
475             HeapFree(GetProcessHeap(), 0, wma->lpWaveFormat);
476             wma->lpWaveFormat = NULL;
477         }
478         else
479         /* fill the queue with as many wave headers as possible */
480         MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
481     }
482
483     while (wma->dwStatus == MCI_MODE_PLAY)
484     {
485         HDC hDC;
486         DWORD ret;
487
488         tc = GetTickCount();
489
490         hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
491         if (hDC)
492         {
493             MCIAVI_PaintFrame(wma, hDC);
494             ReleaseDC(wma->hWndPaint, hDC);
495         }
496
497         if (wma->lpWaveFormat) {
498             HANDLE events[2];
499
500             events[0] = wma->hStopEvent;
501             events[1] = wma->hEvent;
502
503             MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
504             delta = GetTickCount() - tc;
505
506             LeaveCriticalSection(&wma->cs);
507             ret = MsgWaitForMultipleObjectsEx(2, events,
508                 (delta >= frameTime) ? 0 : frameTime - delta, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
509             EnterCriticalSection(&wma->cs);
510
511             if (ret == WAIT_OBJECT_0 || wma->dwStatus != MCI_MODE_PLAY) break;
512         }
513
514         delta = GetTickCount() - tc;
515         if (delta < frameTime)
516             delta = frameTime - delta;
517         else
518             delta = 0;
519
520         LeaveCriticalSection(&wma->cs);
521         ret = MsgWaitForMultipleObjectsEx(1, &wma->hStopEvent, delta,
522                                           QS_ALLINPUT, MWMO_INPUTAVAILABLE);
523         EnterCriticalSection(&wma->cs);
524         if (ret == WAIT_OBJECT_0) break;
525
526        if (wma->dwCurrVideoFrame < dwToFrame)
527            wma->dwCurrVideoFrame++;
528         else
529             break;
530     }
531
532     if (wma->lpWaveFormat) {
533        while (wma->dwEventCount != nHdr - 1)
534         {
535             LeaveCriticalSection(&wma->cs);
536             Sleep(100);
537             EnterCriticalSection(&wma->cs);
538         }
539
540         /* just to get rid of some race conditions between play, stop and pause */
541         LeaveCriticalSection(&wma->cs);
542         waveOutReset(wma->hWave);
543         EnterCriticalSection(&wma->cs);
544
545         for (i = 0; i < nHdr; i++)
546             waveOutUnprepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR));
547     }
548
549     dwRet = 0;
550
551     if (wma->lpWaveFormat) {
552         HeapFree(GetProcessHeap(), 0, waveHdr);
553
554         if (wma->hWave) {
555             LeaveCriticalSection(&wma->cs);
556             waveOutClose(wma->hWave);
557             EnterCriticalSection(&wma->cs);
558             wma->hWave = 0;
559         }
560         CloseHandle(wma->hEvent);
561     }
562
563 mci_play_done:
564     wma->dwStatus = MCI_MODE_STOP;
565
566     if (lpParms && (dwFlags & MCI_NOTIFY)) {
567         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
568         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
569                        wDevID, MCI_NOTIFY_SUCCESSFUL);
570     }
571     LeaveCriticalSection(&wma->cs);
572     return dwRet;
573 }
574
575 /***************************************************************************
576  *                              MCIAVI_mciRecord                        [internal]
577  */
578 static  DWORD   MCIAVI_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECORD_PARMS lpParms)
579 {
580     WINE_MCIAVI *wma;
581
582     FIXME("(%04x, %08lX, %p) : stub\n", wDevID, dwFlags, lpParms);
583
584     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
585
586     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
587
588     wma = MCIAVI_mciGetOpenDev(wDevID);
589     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
590
591     EnterCriticalSection(&wma->cs);
592     wma->dwStatus = MCI_MODE_RECORD;
593     LeaveCriticalSection(&wma->cs);
594     return 0;
595 }
596
597 /***************************************************************************
598  *                              MCIAVI_mciStop                  [internal]
599  */
600 static  DWORD   MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
601 {
602     WINE_MCIAVI *wma;
603     DWORD               dwRet = 0;
604
605     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
606
607     wma = MCIAVI_mciGetOpenDev(wDevID);
608     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
609
610     EnterCriticalSection(&wma->cs);
611
612     TRACE("current status %04lx\n", wma->dwStatus);
613
614     switch (wma->dwStatus) {
615     case MCI_MODE_PLAY:
616     case MCI_MODE_RECORD:
617         LeaveCriticalSection(&wma->cs);
618         SetEvent(wma->hStopEvent);
619         EnterCriticalSection(&wma->cs);
620         /* fall through */
621     case MCI_MODE_PAUSE:
622         /* Since our wave notification callback takes the lock,
623          * we must release it before resetting the device */
624         LeaveCriticalSection(&wma->cs);
625         dwRet = waveOutReset(wma->hWave);
626         EnterCriticalSection(&wma->cs);
627         /* fall through */
628     default:
629         do /* one more chance for an async thread to finish */
630         {
631             LeaveCriticalSection(&wma->cs);
632             Sleep(10);
633             EnterCriticalSection(&wma->cs);
634         } while (wma->dwStatus != MCI_MODE_STOP);
635
636         break;
637
638     case MCI_MODE_NOT_READY:
639         break;        
640     }
641
642     if ((dwFlags & MCI_NOTIFY) && lpParms) {
643         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
644                        wDevID, MCI_NOTIFY_SUCCESSFUL);
645     }
646     LeaveCriticalSection(&wma->cs);
647     return dwRet;
648 }
649
650 /***************************************************************************
651  *                              MCIAVI_mciPause                 [internal]
652  */
653 static  DWORD   MCIAVI_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
654 {
655     WINE_MCIAVI *wma;
656
657     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
658
659     wma = MCIAVI_mciGetOpenDev(wDevID);
660     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
661
662     EnterCriticalSection(&wma->cs);
663
664     if (wma->dwStatus == MCI_MODE_PLAY)
665         wma->dwStatus = MCI_MODE_PAUSE;
666
667     if (wma->lpWaveFormat) {
668         LeaveCriticalSection(&wma->cs);
669         return waveOutPause(wma->hWave);
670     }
671
672     LeaveCriticalSection(&wma->cs);
673     return 0;
674 }
675
676 /***************************************************************************
677  *                              MCIAVI_mciResume                        [internal]
678  */
679 static  DWORD   MCIAVI_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
680 {
681     WINE_MCIAVI *wma;
682
683     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
684
685     wma = MCIAVI_mciGetOpenDev(wDevID);
686     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
687
688     EnterCriticalSection(&wma->cs);
689
690     if (wma->dwStatus == MCI_MODE_PAUSE)
691         wma->dwStatus = MCI_MODE_PLAY;
692
693     if (wma->lpWaveFormat) {
694         LeaveCriticalSection(&wma->cs);
695         return waveOutRestart(wma->hWave);
696     }
697
698     LeaveCriticalSection(&wma->cs);
699     return 0;
700 }
701
702 /***************************************************************************
703  *                              MCIAVI_mciSeek                  [internal]
704  */
705 static  DWORD   MCIAVI_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
706 {
707     WINE_MCIAVI *wma;
708
709     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
710
711     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
712
713     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
714
715     wma = MCIAVI_mciGetOpenDev(wDevID);
716     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
717
718     EnterCriticalSection(&wma->cs);
719
720     if (dwFlags & MCI_SEEK_TO_START) {
721         wma->dwCurrVideoFrame = 0;
722     } else if (dwFlags & MCI_SEEK_TO_END) {
723         wma->dwCurrVideoFrame = wma->dwPlayableVideoFrames - 1;
724     } else if (dwFlags & MCI_TO) {
725         if (lpParms->dwTo > wma->dwPlayableVideoFrames - 1)
726             lpParms->dwTo = wma->dwPlayableVideoFrames - 1;
727         wma->dwCurrVideoFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
728     } else {
729         WARN("dwFlag doesn't tell where to seek to...\n");
730         LeaveCriticalSection(&wma->cs);
731         return MCIERR_MISSING_PARAMETER;
732     }
733
734     TRACE("Seeking to frame=%lu bytes\n", wma->dwCurrVideoFrame);
735
736     if (dwFlags & MCI_NOTIFY) {
737         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
738                        wDevID, MCI_NOTIFY_SUCCESSFUL);
739     }
740     LeaveCriticalSection(&wma->cs);
741     return 0;
742 }
743
744 /*****************************************************************************
745  *                              MCIAVI_mciLoad                  [internal]
746  */
747 static DWORD    MCIAVI_mciLoad(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LOAD_PARMSW lpParms)
748 {
749     WINE_MCIAVI *wma;
750
751     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
752
753     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
754
755     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
756
757     wma = MCIAVI_mciGetOpenDev(wDevID);
758     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
759
760     return 0;
761 }
762
763 /******************************************************************************
764  *                              MCIAVI_mciSave                  [internal]
765  */
766 static  DWORD   MCIAVI_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SAVE_PARMSW lpParms)
767 {
768     WINE_MCIAVI *wma;
769
770     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
771
772     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
773
774     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
775
776     wma = MCIAVI_mciGetOpenDev(wDevID);
777     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
778
779     return 0;
780 }
781
782 /******************************************************************************
783  *                              MCIAVI_mciFreeze                        [internal]
784  */
785 static  DWORD   MCIAVI_mciFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
786 {
787     WINE_MCIAVI *wma;
788
789     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
790
791     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
792
793     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
794
795     wma = MCIAVI_mciGetOpenDev(wDevID);
796     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
797
798     return 0;
799 }
800
801 /******************************************************************************
802  *                              MCIAVI_mciRealize                       [internal]
803  */
804 static  DWORD   MCIAVI_mciRealize(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
805 {
806     WINE_MCIAVI *wma;
807
808     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
809
810     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
811
812     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
813
814     wma = MCIAVI_mciGetOpenDev(wDevID);
815     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
816
817     return 0;
818 }
819
820 /******************************************************************************
821  *                              MCIAVI_mciUnFreeze                      [internal]
822  */
823 static  DWORD   MCIAVI_mciUnFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
824 {
825     WINE_MCIAVI *wma;
826
827     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
828
829     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
830
831     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
832
833     wma = MCIAVI_mciGetOpenDev(wDevID);
834     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
835
836     return 0;
837 }
838
839 /******************************************************************************
840  *                              MCIAVI_mciUpdate                        [internal]
841  */
842 static  DWORD   MCIAVI_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
843 {
844     WINE_MCIAVI *wma;
845
846     TRACE("%04x, %08lx, %p\n", wDevID, dwFlags, lpParms);
847
848     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
849
850     wma = MCIAVI_mciGetOpenDev(wDevID);
851     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
852
853     EnterCriticalSection(&wma->cs);
854
855     if (dwFlags & MCI_DGV_UPDATE_HDC)
856         MCIAVI_PaintFrame(wma, lpParms->hDC);
857
858     LeaveCriticalSection(&wma->cs);
859
860     return 0;
861 }
862
863 /******************************************************************************
864  *                              MCIAVI_mciStep                  [internal]
865  */
866 static  DWORD   MCIAVI_mciStep(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpParms)
867 {
868     WINE_MCIAVI *wma;
869
870     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
871
872     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
873
874     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
875
876     wma = MCIAVI_mciGetOpenDev(wDevID);
877     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
878
879     return 0;
880 }
881
882 /******************************************************************************
883  *                              MCIAVI_mciCopy                  [internal]
884  */
885 static  DWORD   MCIAVI_mciCopy(UINT wDevID, DWORD dwFlags, LPMCI_DGV_COPY_PARMS lpParms)
886 {
887     WINE_MCIAVI *wma;
888
889     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
890
891     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
892
893     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
894
895     wma = MCIAVI_mciGetOpenDev(wDevID);
896     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
897
898     return 0;
899 }
900
901 /******************************************************************************
902  *                              MCIAVI_mciCut                   [internal]
903  */
904 static  DWORD   MCIAVI_mciCut(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUT_PARMS lpParms)
905 {
906     WINE_MCIAVI *wma;
907
908     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
909
910     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
911
912     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
913
914     wma = MCIAVI_mciGetOpenDev(wDevID);
915     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
916
917     return 0;
918 }
919
920 /******************************************************************************
921  *                              MCIAVI_mciDelete                        [internal]
922  */
923 static  DWORD   MCIAVI_mciDelete(UINT wDevID, DWORD dwFlags, LPMCI_DGV_DELETE_PARMS lpParms)
924 {
925     WINE_MCIAVI *wma;
926
927     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
928
929     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
930
931     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
932
933     wma = MCIAVI_mciGetOpenDev(wDevID);
934     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
935
936     return 0;
937 }
938
939 /******************************************************************************
940  *                              MCIAVI_mciPaste                 [internal]
941  */
942 static  DWORD   MCIAVI_mciPaste(UINT wDevID, DWORD dwFlags, LPMCI_DGV_PASTE_PARMS lpParms)
943 {
944     WINE_MCIAVI *wma;
945
946     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
947
948     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
949
950     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
951
952     wma = MCIAVI_mciGetOpenDev(wDevID);
953     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
954
955     return 0;
956 }
957
958 /******************************************************************************
959  *                              MCIAVI_mciCue                   [internal]
960  */
961 static  DWORD   MCIAVI_mciCue(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpParms)
962 {
963     WINE_MCIAVI *wma;
964
965     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
966
967     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
968
969     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
970
971     wma = MCIAVI_mciGetOpenDev(wDevID);
972     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
973
974     return 0;
975 }
976
977 /******************************************************************************
978  *                              MCIAVI_mciCapture                       [internal]
979  */
980 static  DWORD   MCIAVI_mciCapture(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CAPTURE_PARMSW lpParms)
981 {
982     WINE_MCIAVI *wma;
983
984     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
985
986     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
987
988     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
989
990     wma = MCIAVI_mciGetOpenDev(wDevID);
991     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
992
993     return 0;
994 }
995
996 /******************************************************************************
997  *                              MCIAVI_mciMonitor                       [internal]
998  */
999 static  DWORD   MCIAVI_mciMonitor(UINT wDevID, DWORD dwFlags, LPMCI_DGV_MONITOR_PARMS lpParms)
1000 {
1001     WINE_MCIAVI *wma;
1002
1003     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1004
1005     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1006
1007     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1008
1009     wma = MCIAVI_mciGetOpenDev(wDevID);
1010     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1011
1012     return 0;
1013 }
1014
1015 /******************************************************************************
1016  *                              MCIAVI_mciReserve                       [internal]
1017  */
1018 static  DWORD   MCIAVI_mciReserve(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESERVE_PARMSW lpParms)
1019 {
1020     WINE_MCIAVI *wma;
1021
1022     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1023
1024     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1025
1026     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1027
1028     wma = MCIAVI_mciGetOpenDev(wDevID);
1029     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1030
1031     return 0;
1032 }
1033
1034 /******************************************************************************
1035  *                              MCIAVI_mciSetAudio                      [internal]
1036  */
1037 static  DWORD   MCIAVI_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
1038 {
1039     WINE_MCIAVI *wma;
1040
1041     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1042
1043     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1044
1045     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1046
1047     wma = MCIAVI_mciGetOpenDev(wDevID);
1048     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1049
1050     return 0;
1051 }
1052
1053 /******************************************************************************
1054  *                              MCIAVI_mciSignal                        [internal]
1055  */
1056 static  DWORD   MCIAVI_mciSignal(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpParms)
1057 {
1058     WINE_MCIAVI *wma;
1059
1060     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1061
1062     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1063
1064     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1065
1066     wma = MCIAVI_mciGetOpenDev(wDevID);
1067     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1068
1069     return 0;
1070 }
1071
1072 /******************************************************************************
1073  *                              MCIAVI_mciSetVideo                      [internal]
1074  */
1075 static  DWORD   MCIAVI_mciSetVideo(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMSW lpParms)
1076 {
1077     WINE_MCIAVI *wma;
1078
1079     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1080
1081     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1082
1083     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1084
1085     wma = MCIAVI_mciGetOpenDev(wDevID);
1086     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1087
1088     return 0;
1089 }
1090
1091 /******************************************************************************
1092  *                              MCIAVI_mciQuality                       [internal]
1093  */
1094 static  DWORD   MCIAVI_mciQuality(UINT wDevID, DWORD dwFlags, LPMCI_DGV_QUALITY_PARMSW lpParms)
1095 {
1096     WINE_MCIAVI *wma;
1097
1098     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1099
1100     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1101
1102     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1103
1104     wma = MCIAVI_mciGetOpenDev(wDevID);
1105     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1106
1107     return 0;
1108 }
1109
1110 /******************************************************************************
1111  *                              MCIAVI_mciList                  [internal]
1112  */
1113 static  DWORD   MCIAVI_mciList(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LIST_PARMSW lpParms)
1114 {
1115     WINE_MCIAVI *wma;
1116
1117     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1118
1119     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1120
1121     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1122
1123     wma = MCIAVI_mciGetOpenDev(wDevID);
1124     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1125
1126     return 0;
1127 }
1128
1129 /******************************************************************************
1130  *                              MCIAVI_mciUndo                  [internal]
1131  */
1132 static  DWORD   MCIAVI_mciUndo(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1133 {
1134     WINE_MCIAVI *wma;
1135
1136     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1137
1138     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1139
1140     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1141
1142     wma = MCIAVI_mciGetOpenDev(wDevID);
1143     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1144
1145     return 0;
1146 }
1147
1148 /******************************************************************************
1149  *                              MCIAVI_mciConfigure                     [internal]
1150  */
1151 static  DWORD   MCIAVI_mciConfigure(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1152 {
1153     WINE_MCIAVI *wma;
1154
1155     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1156
1157     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1158
1159     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1160
1161     wma = MCIAVI_mciGetOpenDev(wDevID);
1162     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1163
1164     return 0;
1165 }
1166
1167 /******************************************************************************
1168  *                              MCIAVI_mciRestore                       [internal]
1169  */
1170 static  DWORD   MCIAVI_mciRestore(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESTORE_PARMSW lpParms)
1171 {
1172     WINE_MCIAVI *wma;
1173
1174     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1175
1176     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1177
1178     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1179
1180     wma = MCIAVI_mciGetOpenDev(wDevID);
1181     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1182
1183     return 0;
1184 }
1185
1186 /*======================================================================*
1187  *                          MCI AVI entry points                        *
1188  *======================================================================*/
1189
1190 /**************************************************************************
1191  *                              DriverProc (MCIAVI.@)
1192  */
1193 LRESULT CALLBACK MCIAVI_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1194                                    LPARAM dwParam1, LPARAM dwParam2)
1195 {
1196     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1197           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1198
1199     switch (wMsg) {
1200     case DRV_LOAD:              return 1;
1201     case DRV_FREE:              return 1;
1202     case DRV_OPEN:              return MCIAVI_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1203     case DRV_CLOSE:             return MCIAVI_drvClose(dwDevID);
1204     case DRV_ENABLE:            return 1;
1205     case DRV_DISABLE:           return 1;
1206     case DRV_QUERYCONFIGURE:    return 1;
1207     case DRV_CONFIGURE:         return MCIAVI_drvConfigure(dwDevID);
1208     case DRV_INSTALL:           return DRVCNF_RESTART;
1209     case DRV_REMOVE:            return DRVCNF_RESTART;
1210     }
1211
1212     /* session instance */
1213     if (dwDevID == 0xFFFFFFFF) return 1;
1214
1215     switch (wMsg) {
1216     case MCI_OPEN_DRIVER:       return MCIAVI_mciOpen      (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSW)     dwParam2);
1217     case MCI_CLOSE_DRIVER:      return MCIAVI_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1218     case MCI_PLAY:              return MCIAVI_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
1219     case MCI_RECORD:            return MCIAVI_mciRecord    (dwDevID, dwParam1, (LPMCI_DGV_RECORD_PARMS)    dwParam2);
1220     case MCI_STOP:              return MCIAVI_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1221     case MCI_SET:               return MCIAVI_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
1222     case MCI_PAUSE:             return MCIAVI_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1223     case MCI_RESUME:            return MCIAVI_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1224     case MCI_STATUS:            return MCIAVI_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW)   dwParam2);
1225     case MCI_GETDEVCAPS:        return MCIAVI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
1226     case MCI_INFO:              return MCIAVI_mciInfo      (dwDevID, dwParam1, (LPMCI_DGV_INFO_PARMSW)     dwParam2);
1227     case MCI_SEEK:              return MCIAVI_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
1228     case MCI_PUT:               return MCIAVI_mciPut       (dwDevID, dwParam1, (LPMCI_DGV_PUT_PARMS)       dwParam2);
1229     case MCI_WINDOW:            return MCIAVI_mciWindow    (dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSW)   dwParam2);
1230     case MCI_LOAD:              return MCIAVI_mciLoad      (dwDevID, dwParam1, (LPMCI_DGV_LOAD_PARMSW)     dwParam2);
1231     case MCI_SAVE:              return MCIAVI_mciSave      (dwDevID, dwParam1, (LPMCI_DGV_SAVE_PARMSW)     dwParam2);
1232     case MCI_FREEZE:            return MCIAVI_mciFreeze    (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1233     case MCI_REALIZE:           return MCIAVI_mciRealize   (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1234     case MCI_UNFREEZE:          return MCIAVI_mciUnFreeze  (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1235     case MCI_UPDATE:            return MCIAVI_mciUpdate    (dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)    dwParam2);
1236     case MCI_WHERE:             return MCIAVI_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1237     case MCI_STEP:              return MCIAVI_mciStep      (dwDevID, dwParam1, (LPMCI_DGV_STEP_PARMS)      dwParam2);
1238     case MCI_COPY:              return MCIAVI_mciCopy      (dwDevID, dwParam1, (LPMCI_DGV_COPY_PARMS)      dwParam2);
1239     case MCI_CUT:               return MCIAVI_mciCut       (dwDevID, dwParam1, (LPMCI_DGV_CUT_PARMS)       dwParam2);
1240     case MCI_DELETE:            return MCIAVI_mciDelete    (dwDevID, dwParam1, (LPMCI_DGV_DELETE_PARMS)    dwParam2);
1241     case MCI_PASTE:             return MCIAVI_mciPaste     (dwDevID, dwParam1, (LPMCI_DGV_PASTE_PARMS)     dwParam2);
1242     case MCI_CUE:               return MCIAVI_mciCue       (dwDevID, dwParam1, (LPMCI_DGV_CUE_PARMS)       dwParam2);
1243         /* Digital Video specific */
1244     case MCI_CAPTURE:           return MCIAVI_mciCapture   (dwDevID, dwParam1, (LPMCI_DGV_CAPTURE_PARMSW)  dwParam2);
1245     case MCI_MONITOR:           return MCIAVI_mciMonitor   (dwDevID, dwParam1, (LPMCI_DGV_MONITOR_PARMS)   dwParam2);
1246     case MCI_RESERVE:           return MCIAVI_mciReserve   (dwDevID, dwParam1, (LPMCI_DGV_RESERVE_PARMSW)  dwParam2);
1247     case MCI_SETAUDIO:          return MCIAVI_mciSetAudio  (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
1248     case MCI_SIGNAL:            return MCIAVI_mciSignal    (dwDevID, dwParam1, (LPMCI_DGV_SIGNAL_PARMS)    dwParam2);
1249     case MCI_SETVIDEO:          return MCIAVI_mciSetVideo  (dwDevID, dwParam1, (LPMCI_DGV_SETVIDEO_PARMSW) dwParam2);
1250     case MCI_QUALITY:           return MCIAVI_mciQuality   (dwDevID, dwParam1, (LPMCI_DGV_QUALITY_PARMSW)  dwParam2);
1251     case MCI_LIST:              return MCIAVI_mciList      (dwDevID, dwParam1, (LPMCI_DGV_LIST_PARMSW)     dwParam2);
1252     case MCI_UNDO:              return MCIAVI_mciUndo      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1253     case MCI_CONFIGURE:         return MCIAVI_mciConfigure (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1254     case MCI_RESTORE:           return MCIAVI_mciRestore   (dwDevID, dwParam1, (LPMCI_DGV_RESTORE_PARMSW)  dwParam2);
1255
1256     case MCI_SPIN:
1257     case MCI_ESCAPE:
1258         WARN("Unsupported command [%u]\n", wMsg);
1259         break;
1260     case MCI_OPEN:
1261     case MCI_CLOSE:
1262         FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1263         break;
1264     default:
1265         TRACE("Sending msg [%u] to default driver proc\n", wMsg);
1266         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1267     }
1268     return MCIERR_UNRECOGNIZED_COMMAND;
1269 }