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