Fixed a race condition on RPC worker thread creation, and a typo.
[wine] / dlls / winmm / mciavi / mciavi.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * Digital video MCI Wine Driver
5  *
6  * Copyright 1999, 2000 Eric POUECH
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 /* TODO list :
24  *      - handling of palettes
25  *      - recording (which input devices ?), a cam recorder ?
26  *      - lots of messages still need to be handled (cf FIXME)
27  *      - synchronization between audio and video (especially for interleaved
28  *        files)
29  *      - synchronization (as in all the Wine MCI drivers (MCI_WAIT) messages)
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  *      - mciWindow (for setting the hWnd) is broken with media player
37  *      - stopping while playing a file with sound blocks until all buffered
38  *        audio is played... still should be stopped ASAP
39  */
40
41 #include <string.h>
42 #include "private_mciavi.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
46
47 /* ===================================================================
48  * ===================================================================
49  * FIXME: should be using the new mmThreadXXXX functions from WINMM
50  * instead of those
51  * it would require to add a wine internal flag to mmThreadCreate
52  * in order to pass a 32 bit function instead of a 16 bit one
53  * ===================================================================
54  * =================================================================== */
55
56 struct SCA {
57     UINT        wDevID;
58     UINT        wMsg;
59     DWORD       dwParam1;
60     DWORD       dwParam2;
61 };
62
63 /**************************************************************************
64  *                              MCI_SCAStarter                  [internal]
65  */
66 static DWORD CALLBACK   MCI_SCAStarter(LPVOID arg)
67 {
68     struct SCA* sca = (struct SCA*)arg;
69     DWORD       ret;
70
71     TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
72           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
73     ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
74     TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
75           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
76     HeapFree(GetProcessHeap(), 0, sca);
77     ExitThread(ret);
78     WARN("Should not happen ? what's wrong \n");
79     /* should not go after this point */
80     return ret;
81 }
82
83 /**************************************************************************
84  *                              MCI_SendCommandAsync            [internal]
85  */
86 static  DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
87                                    DWORD dwParam2, UINT size)
88 {
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)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 (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     return 0;
113 }
114
115 /*======================================================================*
116  *                          MCI AVI implemantation                      *
117  *======================================================================*/
118
119 HINSTANCE MCIAVI_hInstance = 0;
120
121 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
122 {
123     switch (fdwReason) {
124     case DLL_PROCESS_ATTACH:
125         MCIAVI_hInstance = hInstDLL;
126         break;
127     }
128     return TRUE;
129 }
130
131 /**************************************************************************
132  *                              MCIAVI_drvOpen                  [internal]
133  */
134 static  DWORD   MCIAVI_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
135 {
136     WINE_MCIAVI*        wma;
137     static WCHAR        mciAviWStr[] = {'M','C','I','A','V','I',0};
138
139     if (!modp) return 0xFFFFFFFF;
140
141     wma = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIAVI));
142     if (!wma)
143         return 0;
144
145     wma->wDevID = modp->wDeviceID;
146     mciSetDriverData(wma->wDevID, (DWORD)wma);
147     wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, mciAviWStr, 0);
148     modp->wCustomCommandTable = wma->wCommandTable;
149     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
150     return modp->wDeviceID;
151 }
152
153 /**************************************************************************
154  *                              MCIAVI_drvClose         [internal]
155  */
156 static  DWORD   MCIAVI_drvClose(DWORD dwDevID)
157 {
158     WINE_MCIAVI*  wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
159
160     if (wma) {
161         mciSetDriverData(dwDevID, 0);
162         mciFreeCommandResource(wma->wCommandTable);
163         HeapFree(GetProcessHeap(), 0, wma);
164         return 1;
165     }
166     return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
167 }
168
169 /**************************************************************************
170  *                              MCIAVI_drvConfigure             [internal]
171  */
172 static  DWORD   MCIAVI_drvConfigure(DWORD dwDevID)
173 {
174     WINE_MCIAVI*  wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
175
176     if (wma) {
177         MessageBoxA(0, "Sample AVI Wine Driver !", "MM-Wine Driver", MB_OK);
178         return 1;
179     }
180     return 0;
181 }
182
183 /**************************************************************************
184  *                              MCIAVI_mciGetOpenDev            [internal]
185  */
186 WINE_MCIAVI*  MCIAVI_mciGetOpenDev(UINT wDevID)
187 {
188     WINE_MCIAVI*        wma = (WINE_MCIAVI*)mciGetDriverData(wDevID);
189
190     if (wma == NULL || wma->nUseCount == 0) {
191         WARN("Invalid wDevID=%u\n", wDevID);
192         return 0;
193     }
194     return wma;
195 }
196
197 static void MCIAVI_CleanUp(WINE_MCIAVI* wma)
198 {
199     /* to prevent handling in WindowProc */
200     wma->dwStatus = MCI_MODE_NOT_READY;
201     if (wma->hFile) {
202         mmioClose(wma->hFile, 0);
203         wma->hFile = 0;
204         if (wma->lpVideoIndex)  HeapFree(GetProcessHeap(), 0, wma->lpVideoIndex);
205         wma->lpVideoIndex = NULL;
206         if (wma->lpAudioIndex)  HeapFree(GetProcessHeap(), 0, wma->lpAudioIndex);
207         wma->lpAudioIndex = NULL;
208         if (wma->hic)           ICClose(wma->hic);
209         wma->hic = 0;
210         if (wma->inbih)         HeapFree(GetProcessHeap(), 0, wma->inbih);
211         wma->inbih = NULL;
212         if (wma->outbih)        HeapFree(GetProcessHeap(), 0, wma->outbih);
213         wma->outbih = NULL;
214         if (wma->indata)        HeapFree(GetProcessHeap(), 0, wma->indata);
215         wma->indata = NULL;
216         if (wma->outdata)       HeapFree(GetProcessHeap(), 0, wma->outdata);
217         wma->outdata = NULL;
218         if (wma->hbmFrame)      DeleteObject(wma->hbmFrame);
219         wma->hbmFrame = 0;
220         if (wma->hWnd)          DestroyWindow(wma->hWnd);
221         wma->hWnd = 0;
222
223         if (wma->lpWaveFormat)  HeapFree(GetProcessHeap(), 0, wma->lpWaveFormat);
224         wma->lpWaveFormat = 0;
225
226         memset(&wma->mah, 0, sizeof(wma->mah));
227         memset(&wma->ash_video, 0, sizeof(wma->ash_video));
228         memset(&wma->ash_audio, 0, sizeof(wma->ash_audio));
229         wma->dwCurrVideoFrame = wma->dwCurrAudioBlock = 0;
230     }
231 }
232
233 static  DWORD   MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
234
235 /***************************************************************************
236  *                              MCIAVI_mciOpen                  [internal]
237  */
238 static  DWORD   MCIAVI_mciOpen(UINT wDevID, DWORD dwFlags,
239                             LPMCI_DGV_OPEN_PARMSA lpOpenParms)
240 {
241     WINE_MCIAVI*        wma = (WINE_MCIAVI*)mciGetDriverData(wDevID);
242     LRESULT             dwRet = 0;
243
244     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
245
246     if (lpOpenParms == NULL)            return MCIERR_NULL_PARAMETER_BLOCK;
247     if (wma == NULL)                    return MCIERR_INVALID_DEVICE_ID;
248
249     if (wma->nUseCount > 0) {
250         /* The driver is already open on this channel */
251         /* If the driver was opened shareable before and this open specifies */
252         /* shareable then increment the use count */
253         if (wma->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
254             ++wma->nUseCount;
255         else
256             return MCIERR_MUST_USE_SHAREABLE;
257     } else {
258         wma->nUseCount = 1;
259         wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
260     }
261
262     wma->dwStatus = MCI_MODE_NOT_READY;
263     InitializeCriticalSection(&wma->cs);
264
265     if (dwFlags & MCI_OPEN_ELEMENT) {
266         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
267             /* could it be that (DWORD)lpOpenParms->lpstrElementName
268              * contains the hFile value ?
269              */
270             dwRet = MCIERR_UNRECOGNIZED_COMMAND;
271         } else if (strlen(lpOpenParms->lpstrElementName) > 0) {
272             /* FIXME : what should be done id wma->hFile is already != 0, or the driver is playin' */
273             TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpOpenParms->lpstrElementName);
274
275             if (lpOpenParms->lpstrElementName && (strlen(lpOpenParms->lpstrElementName) > 0)) {
276                 wma->hFile = mmioOpenA(lpOpenParms->lpstrElementName, NULL,
277                                        MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READWRITE);
278
279                 if (wma->hFile == 0) {
280                     WARN("can't find file='%s' !\n", lpOpenParms->lpstrElementName);
281                     dwRet = MCIERR_FILE_NOT_FOUND;
282                 } else {
283                     if (!MCIAVI_GetInfo(wma))
284                         dwRet = MCIERR_INVALID_FILE;
285                     else if (!MCIAVI_OpenVideo(wma))
286                         dwRet = MCIERR_CANNOT_LOAD_DRIVER;
287                     else if (!MCIAVI_CreateWindow(wma, dwFlags, lpOpenParms))
288                         dwRet = MCIERR_CREATEWINDOW;
289                 }
290             }
291         } else {
292             FIXME("Don't record yet\n");
293             dwRet = MCIERR_UNSUPPORTED_FUNCTION;
294         }
295     }
296
297     memcpy(&wma->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
298
299     if (dwRet == 0) {
300         wma->dwStatus = MCI_MODE_STOP;
301         wma->dwMciTimeFormat = MCI_FORMAT_FRAMES;
302     } else {
303         MCIAVI_CleanUp(wma);
304     }
305     return dwRet;
306
307 }
308
309 /***************************************************************************
310  *                              MCIAVI_mciClose                 [internal]
311  */
312 static  DWORD   MCIAVI_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
313 {
314     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
315     DWORD               dwRet = 0;
316
317     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
318
319     if (wma == NULL)    return MCIERR_INVALID_DEVICE_ID;
320
321     if (wma->nUseCount == 1) {
322         if (wma->dwStatus != MCI_MODE_STOP)
323             dwRet = MCIAVI_mciStop(wDevID, MCI_WAIT, lpParms);
324         MCIAVI_CleanUp(wma);
325
326         if ((dwFlags & MCI_NOTIFY) && lpParms) {
327             mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
328                             wma->openParms.wDeviceID,
329                             MCI_NOTIFY_SUCCESSFUL);
330         }
331         HeapFree(GetProcessHeap(), 0, wma);
332         return dwRet;
333     }
334     wma->nUseCount--;
335     return dwRet;
336 }
337
338 /***************************************************************************
339  *                              MCIAVI_mciPlay                  [internal]
340  */
341 static  DWORD   MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
342 {
343     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
344     DWORD               tc;
345     DWORD               frameTime;
346     DWORD               delta;
347     DWORD               dwRet;
348     LPWAVEHDR           waveHdr = NULL;
349     unsigned            i, nHdr = 0;
350     DWORD               dwFromFrame, dwToFrame;
351
352     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
353
354     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
355     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
356
357     if (!wma->hFile)            return MCIERR_FILE_NOT_FOUND;
358     if (!wma->hWnd)             return MCIERR_NO_WINDOW;
359
360     wma->dwStatus = MCI_MODE_PLAY;
361
362     if (!(dwFlags & MCI_WAIT)) {
363         return MCI_SendCommandAsync(wma->openParms.wDeviceID, MCI_PLAY, dwFlags,
364                                     (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
365     }
366
367     ShowWindow(wma->hWnd, SW_SHOW);
368
369     dwFromFrame = wma->dwCurrVideoFrame;
370     dwToFrame = wma->dwPlayableVideoFrames - 1;
371
372     if (lpParms && (dwFlags & MCI_FROM)) {
373         dwFromFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwFrom);
374     }
375     if (lpParms && (dwFlags & MCI_TO)) {
376         dwToFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
377     }
378     if (dwToFrame >= wma->dwPlayableVideoFrames)
379         dwToFrame = wma->dwPlayableVideoFrames - 1;
380
381     TRACE("Playing from frame=%lu to frame=%lu\n", dwFromFrame, dwToFrame);
382
383     if (dwToFrame <= wma->dwCurrVideoFrame)
384         return TRUE;
385     wma->dwCurrVideoFrame = dwFromFrame;
386
387     if (dwFlags & (MCI_DGV_PLAY_REPEAT|MCI_DGV_PLAY_REVERSE|MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLSCREEN))
388         FIXME("Unsupported flag %08lx\n", dwFlags);
389
390     /* time is in microseconds, we should convert it to milliseconds */
391     frameTime = (wma->mah.dwMicroSecPerFrame + 500) / 1000;
392
393     if (wma->lpWaveFormat) {
394         if ((dwRet = MCIAVI_OpenAudio(wma, &nHdr, &waveHdr)) != 0)
395             goto cleanUp;
396         /* fill the queue with as many wave headers as possible */
397         MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
398     }
399
400     while (wma->dwStatus != MCI_MODE_STOP && wma->dwStatus != MCI_MODE_NOT_READY) {
401         tc = GetTickCount();
402
403         MCIAVI_DrawFrame(wma);
404
405         if (wma->lpWaveFormat) {
406             MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
407             delta = GetTickCount() - tc;
408             WaitForSingleObject(wma->hEvent, (delta >= frameTime) ? 0 : frameTime - delta);
409         }
410
411         delta = GetTickCount() - tc;
412         if (delta < frameTime)
413             Sleep(frameTime - delta);
414
415         if (wma->dwCurrVideoFrame++ >= dwToFrame) {
416             wma->dwCurrVideoFrame--;
417             wma->dwStatus = MCI_MODE_STOP;
418         }
419     }
420
421     if (wma->lpWaveFormat) {
422         while (*(volatile DWORD*)&wma->dwEventCount != nHdr - 1) {
423             Sleep(100);
424         }
425
426         /* just to get rid of some race conditions between play, stop and pause */
427         waveOutReset(wma->hWave);
428
429         for (i = 0; i < nHdr; i++)
430             waveOutUnprepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR));
431     }
432
433     dwRet = 0;
434 cleanUp:
435     if (wma->lpWaveFormat) {
436         HeapFree(GetProcessHeap(), 0, waveHdr);
437
438         if (wma->hWave) {
439             waveOutClose(wma->hWave);
440             wma->hWave = 0;
441         }
442         CloseHandle(wma->hEvent);
443     }
444
445     if (lpParms && (dwFlags & MCI_NOTIFY)) {
446         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
447         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
448                         wma->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
449     }
450
451     wma->dwStatus = MCI_MODE_STOP;
452
453     return dwRet;
454 }
455
456 /***************************************************************************
457  *                              MCIAVI_mciRecord                        [internal]
458  */
459 static  DWORD   MCIAVI_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECORD_PARMS lpParms)
460 {
461     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
462
463     FIXME("(%04x, %08lX, %p) : stub\n", wDevID, dwFlags, lpParms);
464
465     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
466     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
467
468     wma->dwStatus = MCI_MODE_RECORD;
469     return 0;
470 }
471
472 /***************************************************************************
473  *                              MCIAVI_mciStop                  [internal]
474  */
475 static  DWORD   MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
476 {
477     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
478     DWORD               dwRet = 0;
479
480     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
481
482     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
483     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
484
485     switch (wma->dwStatus) {
486     case MCI_MODE_PAUSE:
487     case MCI_MODE_PLAY:
488     case MCI_MODE_RECORD:
489         {
490             int oldStat = wma->dwStatus;
491             wma->dwStatus = MCI_MODE_NOT_READY;
492             if (oldStat == MCI_MODE_PAUSE)
493                 dwRet = waveOutReset(wma->hWave);
494         }
495         while (wma->dwStatus != MCI_MODE_STOP)
496             Sleep(10);
497         break;
498     default:
499         wma->dwStatus = MCI_MODE_STOP;
500         break;
501     }
502
503     if ((dwFlags & MCI_NOTIFY) && lpParms) {
504         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
505                         wma->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
506     }
507
508     return dwRet;
509 }
510
511 /***************************************************************************
512  *                              MCIAVI_mciPause                 [internal]
513  */
514 static  DWORD   MCIAVI_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
515 {
516     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
517
518     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
519     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
520
521     if (wma->dwStatus == MCI_MODE_PLAY)
522         wma->dwStatus = MCI_MODE_PAUSE;
523
524     return (wma->lpWaveFormat) ? waveOutPause(wma->hWave) : 0;
525 }
526
527 /***************************************************************************
528  *                              MCIAVI_mciResume                        [internal]
529  */
530 static  DWORD   MCIAVI_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
531 {
532     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
533
534     FIXME("(%04x, %08lX, %p) : stub\n", wDevID, dwFlags, lpParms);
535
536     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
537     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
538
539     if (wma->dwStatus == MCI_MODE_PAUSE)
540         wma->dwStatus = MCI_MODE_PLAY;
541
542     return (wma->lpWaveFormat) ? waveOutRestart(wma->hWave) : 0;
543 }
544
545 /***************************************************************************
546  *                              MCIAVI_mciSeek                  [internal]
547  */
548 static  DWORD   MCIAVI_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
549 {
550     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
551
552     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
553
554     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
555     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
556
557     EnterCriticalSection(&wma->cs);
558
559     MCIAVI_mciStop(wDevID, MCI_WAIT, 0);
560
561     if (dwFlags & MCI_SEEK_TO_START) {
562         wma->dwCurrVideoFrame = 0;
563     } else if (dwFlags & MCI_SEEK_TO_END) {
564         wma->dwCurrVideoFrame = wma->dwPlayableVideoFrames - 1;
565     } else if (dwFlags & MCI_TO) {
566         wma->dwCurrVideoFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
567     } else {
568         WARN("dwFlag doesn't tell where to seek to...\n");
569         LeaveCriticalSection(&wma->cs);
570         return MCIERR_MISSING_PARAMETER;
571     }
572
573     TRACE("Seeking to frame=%lu bytes\n", wma->dwCurrVideoFrame);
574
575     if (dwFlags & MCI_NOTIFY) {
576         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
577                         wma->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
578     }
579
580     LeaveCriticalSection(&wma->cs);
581
582     return 0;
583 }
584
585 /*****************************************************************************
586  *                              MCIAVI_mciLoad                  [internal]
587  */
588 static DWORD    MCIAVI_mciLoad(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LOAD_PARMSA lpParms)
589 {
590     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
591
592     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
593
594     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
595     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
596
597     return 0;
598 }
599
600 /******************************************************************************
601  *                              MCIAVI_mciSave                  [internal]
602  */
603 static  DWORD   MCIAVI_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SAVE_PARMSA lpParms)
604 {
605     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
606
607     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
608
609     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
610     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
611
612     return 0;
613 }
614
615 /******************************************************************************
616  *                              MCIAVI_mciFreeze                        [internal]
617  */
618 static  DWORD   MCIAVI_mciFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
619 {
620     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
621
622     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
623
624     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
625     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
626
627     return 0;
628 }
629
630 /******************************************************************************
631  *                              MCIAVI_mciRealize                       [internal]
632  */
633 static  DWORD   MCIAVI_mciRealize(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
634 {
635     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
636
637     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
638
639     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
640     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
641
642     return 0;
643 }
644
645 /******************************************************************************
646  *                              MCIAVI_mciUnFreeze                      [internal]
647  */
648 static  DWORD   MCIAVI_mciUnFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
649 {
650     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
651
652     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
653
654     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
655     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
656
657     return 0;
658 }
659
660 /******************************************************************************
661  *                              MCIAVI_mciUpdate                        [internal]
662  */
663 static  DWORD   MCIAVI_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
664 {
665     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
666
667     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
668
669     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
670     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
671
672     return 0;
673 }
674
675 /******************************************************************************
676  *                              MCIAVI_mciStep                  [internal]
677  */
678 static  DWORD   MCIAVI_mciStep(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpParms)
679 {
680     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
681
682     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
683
684     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
685     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
686
687     return 0;
688 }
689
690 /******************************************************************************
691  *                              MCIAVI_mciCopy                  [internal]
692  */
693 static  DWORD   MCIAVI_mciCopy(UINT wDevID, DWORD dwFlags, LPMCI_DGV_COPY_PARMS lpParms)
694 {
695     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
696
697     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
698
699     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
700     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
701
702     return 0;
703 }
704
705 /******************************************************************************
706  *                              MCIAVI_mciCut                   [internal]
707  */
708 static  DWORD   MCIAVI_mciCut(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUT_PARMS lpParms)
709 {
710     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
711
712     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
713
714     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
715     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
716
717     return 0;
718 }
719
720 /******************************************************************************
721  *                              MCIAVI_mciDelete                        [internal]
722  */
723 static  DWORD   MCIAVI_mciDelete(UINT wDevID, DWORD dwFlags, LPMCI_DGV_DELETE_PARMS lpParms)
724 {
725     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
726
727     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
728
729     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
730     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
731
732     return 0;
733 }
734
735 /******************************************************************************
736  *                              MCIAVI_mciPaste                 [internal]
737  */
738 static  DWORD   MCIAVI_mciPaste(UINT wDevID, DWORD dwFlags, LPMCI_DGV_PASTE_PARMS lpParms)
739 {
740     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
741
742     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
743
744     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
745     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
746
747     return 0;
748 }
749
750 /******************************************************************************
751  *                              MCIAVI_mciCue                   [internal]
752  */
753 static  DWORD   MCIAVI_mciCue(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpParms)
754 {
755     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
756
757     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
758
759     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
760     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
761
762     return 0;
763 }
764
765 /******************************************************************************
766  *                              MCIAVI_mciCapture                       [internal]
767  */
768 static  DWORD   MCIAVI_mciCapture(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CAPTURE_PARMSA lpParms)
769 {
770     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
771
772     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
773
774     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
775     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
776
777     return 0;
778 }
779
780 /******************************************************************************
781  *                              MCIAVI_mciMonitor                       [internal]
782  */
783 static  DWORD   MCIAVI_mciMonitor(UINT wDevID, DWORD dwFlags, LPMCI_DGV_MONITOR_PARMS lpParms)
784 {
785     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
786
787     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
788
789     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
790     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
791
792     return 0;
793 }
794
795 /******************************************************************************
796  *                              MCIAVI_mciReserve                       [internal]
797  */
798 static  DWORD   MCIAVI_mciReserve(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESERVE_PARMSA lpParms)
799 {
800     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
801
802     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
803
804     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
805     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
806
807     return 0;
808 }
809
810 /******************************************************************************
811  *                              MCIAVI_mciSetAudio                      [internal]
812  */
813 static  DWORD   MCIAVI_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSA lpParms)
814 {
815     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
816
817     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
818
819     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
820     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
821
822     return 0;
823 }
824
825 /******************************************************************************
826  *                              MCIAVI_mciSignal                        [internal]
827  */
828 static  DWORD   MCIAVI_mciSignal(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpParms)
829 {
830     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
831
832     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
833
834     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
835     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
836
837     return 0;
838 }
839
840 /******************************************************************************
841  *                              MCIAVI_mciSetVideo                      [internal]
842  */
843 static  DWORD   MCIAVI_mciSetVideo(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMSA lpParms)
844 {
845     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
846
847     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
848
849     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
850     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
851
852     return 0;
853 }
854
855 /******************************************************************************
856  *                              MCIAVI_mciQuality                       [internal]
857  */
858 static  DWORD   MCIAVI_mciQuality(UINT wDevID, DWORD dwFlags, LPMCI_DGV_QUALITY_PARMSA lpParms)
859 {
860     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
861
862     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
863
864     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
865     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
866
867     return 0;
868 }
869
870 /******************************************************************************
871  *                              MCIAVI_mciList                  [internal]
872  */
873 static  DWORD   MCIAVI_mciList(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LIST_PARMSA lpParms)
874 {
875     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
876
877     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
878
879     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
880     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
881
882     return 0;
883 }
884
885 /******************************************************************************
886  *                              MCIAVI_mciUndo                  [internal]
887  */
888 static  DWORD   MCIAVI_mciUndo(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
889 {
890     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
891
892     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
893
894     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
895     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
896
897     return 0;
898 }
899
900 /******************************************************************************
901  *                              MCIAVI_mciConfigure                     [internal]
902  */
903 static  DWORD   MCIAVI_mciConfigure(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
904 {
905     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
906
907     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
908
909     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
910     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
911
912     return 0;
913 }
914
915 /******************************************************************************
916  *                              MCIAVI_mciRestore                       [internal]
917  */
918 static  DWORD   MCIAVI_mciRestore(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESTORE_PARMSA lpParms)
919 {
920     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
921
922     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
923
924     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
925     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
926
927     return 0;
928 }
929
930 /*======================================================================*
931  *                          MCI AVI entry points                        *
932  *======================================================================*/
933
934 /**************************************************************************
935  *                              DriverProc (MCIAVI.@)
936  */
937 LONG CALLBACK   MCIAVI_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
938                                   DWORD dwParam1, DWORD dwParam2)
939 {
940     TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
941           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
942
943     switch (wMsg) {
944     case DRV_LOAD:              return 1;
945     case DRV_FREE:              return 1;
946     case DRV_OPEN:              return MCIAVI_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
947     case DRV_CLOSE:             return MCIAVI_drvClose(dwDevID);
948     case DRV_ENABLE:            return 1;
949     case DRV_DISABLE:           return 1;
950     case DRV_QUERYCONFIGURE:    return 1;
951     case DRV_CONFIGURE:         return MCIAVI_drvConfigure(dwDevID);
952     case DRV_INSTALL:           return DRVCNF_RESTART;
953     case DRV_REMOVE:            return DRVCNF_RESTART;
954     }
955
956     if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
957
958     switch (wMsg) {
959     case MCI_OPEN_DRIVER:       return MCIAVI_mciOpen      (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSA)     dwParam2);
960     case MCI_CLOSE_DRIVER:      return MCIAVI_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
961     case MCI_PLAY:              return MCIAVI_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
962     case MCI_RECORD:            return MCIAVI_mciRecord    (dwDevID, dwParam1, (LPMCI_DGV_RECORD_PARMS)    dwParam2);
963     case MCI_STOP:              return MCIAVI_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
964     case MCI_SET:               return MCIAVI_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
965     case MCI_PAUSE:             return MCIAVI_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
966     case MCI_RESUME:            return MCIAVI_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
967     case MCI_STATUS:            return MCIAVI_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSA)   dwParam2);
968     case MCI_GETDEVCAPS:        return MCIAVI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
969     case MCI_INFO:              return MCIAVI_mciInfo      (dwDevID, dwParam1, (LPMCI_DGV_INFO_PARMSA)     dwParam2);
970     case MCI_SEEK:              return MCIAVI_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
971     case MCI_PUT:               return MCIAVI_mciPut       (dwDevID, dwParam1, (LPMCI_DGV_PUT_PARMS)       dwParam2);
972     case MCI_WINDOW:            return MCIAVI_mciWindow    (dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSA)   dwParam2);
973     case MCI_LOAD:              return MCIAVI_mciLoad      (dwDevID, dwParam1, (LPMCI_DGV_LOAD_PARMSA)     dwParam2);
974     case MCI_SAVE:              return MCIAVI_mciSave      (dwDevID, dwParam1, (LPMCI_DGV_SAVE_PARMSA)     dwParam2);
975     case MCI_FREEZE:            return MCIAVI_mciFreeze    (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
976     case MCI_REALIZE:           return MCIAVI_mciRealize   (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
977     case MCI_UNFREEZE:          return MCIAVI_mciUnFreeze  (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
978     case MCI_UPDATE:            return MCIAVI_mciUpdate    (dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)    dwParam2);
979     case MCI_WHERE:             return MCIAVI_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
980     case MCI_STEP:              return MCIAVI_mciStep      (dwDevID, dwParam1, (LPMCI_DGV_STEP_PARMS)      dwParam2);
981     case MCI_COPY:              return MCIAVI_mciCopy      (dwDevID, dwParam1, (LPMCI_DGV_COPY_PARMS)      dwParam2);
982     case MCI_CUT:               return MCIAVI_mciCut       (dwDevID, dwParam1, (LPMCI_DGV_CUT_PARMS)       dwParam2);
983     case MCI_DELETE:            return MCIAVI_mciDelete    (dwDevID, dwParam1, (LPMCI_DGV_DELETE_PARMS)    dwParam2);
984     case MCI_PASTE:             return MCIAVI_mciPaste     (dwDevID, dwParam1, (LPMCI_DGV_PASTE_PARMS)     dwParam2);
985     case MCI_CUE:               return MCIAVI_mciCue       (dwDevID, dwParam1, (LPMCI_DGV_CUE_PARMS)       dwParam2);
986         /* Digital Video specific */
987     case MCI_CAPTURE:           return MCIAVI_mciCapture   (dwDevID, dwParam1, (LPMCI_DGV_CAPTURE_PARMSA)  dwParam2);
988     case MCI_MONITOR:           return MCIAVI_mciMonitor   (dwDevID, dwParam1, (LPMCI_DGV_MONITOR_PARMS)   dwParam2);
989     case MCI_RESERVE:           return MCIAVI_mciReserve   (dwDevID, dwParam1, (LPMCI_DGV_RESERVE_PARMSA)  dwParam2);
990     case MCI_SETAUDIO:          return MCIAVI_mciSetAudio  (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSA) dwParam2);
991     case MCI_SIGNAL:            return MCIAVI_mciSignal    (dwDevID, dwParam1, (LPMCI_DGV_SIGNAL_PARMS)    dwParam2);
992     case MCI_SETVIDEO:          return MCIAVI_mciSetVideo  (dwDevID, dwParam1, (LPMCI_DGV_SETVIDEO_PARMSA) dwParam2);
993     case MCI_QUALITY:           return MCIAVI_mciQuality   (dwDevID, dwParam1, (LPMCI_DGV_QUALITY_PARMSA)  dwParam2);
994     case MCI_LIST:              return MCIAVI_mciList      (dwDevID, dwParam1, (LPMCI_DGV_LIST_PARMSA)     dwParam2);
995     case MCI_UNDO:              return MCIAVI_mciUndo      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
996     case MCI_CONFIGURE:         return MCIAVI_mciConfigure (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
997     case MCI_RESTORE:           return MCIAVI_mciRestore   (dwDevID, dwParam1, (LPMCI_DGV_RESTORE_PARMSA)  dwParam2);
998
999     case MCI_SPIN:
1000     case MCI_ESCAPE:
1001         WARN("Unsupported command [%lu]\n", wMsg);
1002         break;
1003     case MCI_OPEN:
1004     case MCI_CLOSE:
1005         FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1006         break;
1007     default:
1008         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
1009         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1010     }
1011     return MCIERR_UNRECOGNIZED_COMMAND;
1012 }