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