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