Create the system heap event before the shared mapping to avoid a race
[wine] / dlls / winmm / mcianim / mcianim.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Sample MCI ANIMATION Wine Driver for Linux
4  *
5  * Copyright 1994 Martin Ayotte
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23 #include <string.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "wownt32.h"
29 #include "mmddk.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(mcianim);
33
34 #define ANIMFRAMES_PERSEC       30
35 #define ANIMFRAMES_PERMIN       1800
36 #define SECONDS_PERMIN          60
37
38 typedef struct {
39         UINT            wDevID;
40         int             nUseCount;          /* Incremented for each shared open */
41         BOOL            fShareable;         /* TRUE if first open was shareable */
42         WORD            wNotifyDeviceID;    /* MCI device ID with a pending notification */
43         MCI_OPEN_PARMSA openParms;
44         DWORD           dwTimeFormat;
45         int             mode;
46         UINT            nCurTrack;
47         DWORD           dwCurFrame;
48         UINT            nTracks;
49         DWORD           dwTotalLen;
50         LPDWORD         lpdwTrackLen;
51         LPDWORD         lpdwTrackPos;
52 } WINE_MCIANIM;
53
54 /*-----------------------------------------------------------------------*/
55
56 /**************************************************************************
57  *                              MCIANIM_drvOpen                 [internal]
58  */
59 static  DWORD   MCIANIM_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
60 {
61     WINE_MCIANIM*       wma;
62
63     if (!modp) return 0xFFFFFFFF;
64
65     wma = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIANIM));
66
67     if (!wma)
68         return 0;
69
70     wma->wDevID = modp->wDeviceID;
71     mciSetDriverData(wma->wDevID, (DWORD)wma);
72     modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
73     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
74     return modp->wDeviceID;
75 }
76
77 /**************************************************************************
78  *                              MCIANIM_drvClose                [internal]
79  */
80 static  DWORD   MCIANIM_drvClose(DWORD dwDevID)
81 {
82     WINE_MCIANIM*  wma = (WINE_MCIANIM*)mciGetDriverData(dwDevID);
83
84     if (wma) {
85         HeapFree(GetProcessHeap(), 0, wma);
86         return 1;
87     }
88     return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
89 }
90
91 /**************************************************************************
92  *                              MCIANIM_mciGetOpenDrv           [internal]
93  */
94 static WINE_MCIANIM*  MCIANIM_mciGetOpenDrv(UINT16 wDevID)
95 {
96     WINE_MCIANIM*       wma = (WINE_MCIANIM*)mciGetDriverData(wDevID);
97
98     if (wma == NULL || wma->nUseCount == 0) {
99         WARN("Invalid wDevID=%u\n", wDevID);
100         return 0;
101     }
102     return wma;
103 }
104
105 /**************************************************************************
106  *                              MCIANIM_mciOpen                 [internal]
107  */
108 static DWORD MCIANIM_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
109 {
110     DWORD               dwDeviceID;
111     WINE_MCIANIM*       wma = (WINE_MCIANIM*)mciGetDriverData(wDevID);
112
113     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
114
115     if (lpOpenParms == NULL)    return MCIERR_INTERNAL;
116     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
117
118     if (wma->nUseCount > 0) {
119         /* The driver already open on this channel */
120         /* If the driver was opened shareable before and this open specifies */
121         /* shareable then increment the use count */
122         if (wma->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
123             ++wma->nUseCount;
124         else
125             return MCIERR_MUST_USE_SHAREABLE;
126     } else {
127         wma->nUseCount = 1;
128         wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
129     }
130
131     dwDeviceID = lpOpenParms->wDeviceID;
132
133     TRACE("wDevID=%04X\n", wDevID);
134     /* FIXME this is not consistent with other implementations */
135     lpOpenParms->wDeviceID = wDevID;
136
137     /*TRACE("lpParms->wDevID=%04X\n", lpParms->wDeviceID);*/
138     if (dwFlags & MCI_OPEN_ELEMENT) {
139         TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpOpenParms->lpstrElementName);
140         if (lpOpenParms->lpstrElementName && strlen(lpOpenParms->lpstrElementName) > 0) {
141         }
142         FIXME("element is not opened\n");
143     }
144     memcpy(&wma->openParms, lpOpenParms, sizeof(MCI_OPEN_PARMSA));
145     wma->wNotifyDeviceID = dwDeviceID;
146     wma->mode = 0;
147     wma->dwTimeFormat = MCI_FORMAT_TMSF;
148     wma->nCurTrack = 0;
149     wma->nTracks = 0;
150     wma->dwTotalLen = 0;
151     wma->lpdwTrackLen = NULL;
152     wma->lpdwTrackPos = NULL;
153     /*
154       Moved to mmsystem.c mciOpen routine
155
156       if (dwFlags & MCI_NOTIFY) {
157       TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n",
158       lpParms->dwCallback);
159       mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
160       wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
161       }
162     */
163     return 0;
164 }
165
166 /**************************************************************************
167  *                              MCIANIM_mciClose                [internal]
168  */
169 static DWORD MCIANIM_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
170 {
171     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
172
173     TRACE("(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
174
175     if (wma == NULL)     return MCIERR_INVALID_DEVICE_ID;
176
177     if (--wma->nUseCount == 0) {
178         /* do the actual clean-up */
179     }
180     return 0;
181 }
182
183 /**************************************************************************
184  *                              MCIANIM_mciGetDevCaps   [internal]
185  */
186 static DWORD MCIANIM_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags,
187                                 LPMCI_GETDEVCAPS_PARMS lpParms)
188 {
189     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
190     DWORD               ret;
191
192     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
193
194     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
195     if (wma == NULL)     return MCIERR_INVALID_DEVICE_ID;
196
197     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
198         TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
199
200         switch(lpParms->dwItem) {
201         case MCI_GETDEVCAPS_CAN_RECORD:
202             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
203             ret = MCI_RESOURCE_RETURNED;
204             break;
205         case MCI_GETDEVCAPS_HAS_AUDIO:
206             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
207             ret = MCI_RESOURCE_RETURNED;
208             break;
209         case MCI_GETDEVCAPS_HAS_VIDEO:
210             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
211             ret = MCI_RESOURCE_RETURNED;
212             break;
213         case MCI_GETDEVCAPS_DEVICE_TYPE:
214             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_ANIMATION, MCI_DEVTYPE_ANIMATION);
215             ret = MCI_RESOURCE_RETURNED;
216             break;
217         case MCI_GETDEVCAPS_USES_FILES:
218             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
219             ret = MCI_RESOURCE_RETURNED;
220             break;
221         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
222             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
223             ret = MCI_RESOURCE_RETURNED;
224             break;
225         case MCI_GETDEVCAPS_CAN_EJECT:
226             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
227             ret = MCI_RESOURCE_RETURNED;
228             break;
229         case MCI_GETDEVCAPS_CAN_PLAY:
230             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
231             ret = MCI_RESOURCE_RETURNED;
232             break;
233         case MCI_GETDEVCAPS_CAN_SAVE:
234             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
235             ret = MCI_RESOURCE_RETURNED;
236             break;
237         default:
238             FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
239             return MCIERR_UNRECOGNIZED_COMMAND;
240         }
241     } else {
242         WARN("No GETDEVCAPS_ITEM !\n");
243         return MCIERR_UNRECOGNIZED_COMMAND;
244     }
245     TRACE("lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
246     return ret;
247 }
248
249
250 /**************************************************************************
251  *                              MCIANIM_CalcTime                        [internal]
252  */
253 static DWORD MCIANIM_CalcTime(WINE_MCIANIM* wma, DWORD dwFormatType, DWORD dwFrame, LPDWORD lpRet)
254 {
255     DWORD       dwTime = 0;
256     UINT16      wTrack;
257     UINT16      wMinutes;
258     UINT16      wSeconds;
259     UINT16      wFrames;
260
261     TRACE("(%p, %08lX, %lu);\n", wma, dwFormatType, dwFrame);
262
263     switch (dwFormatType) {
264     case MCI_FORMAT_MILLISECONDS:
265         dwTime = dwFrame / ANIMFRAMES_PERSEC * 1000;
266         *lpRet = 0;
267         TRACE("MILLISECONDS %lu\n", dwTime);
268         break;
269     case MCI_FORMAT_MSF:
270         wMinutes = dwFrame / ANIMFRAMES_PERMIN;
271         wSeconds = (dwFrame - ANIMFRAMES_PERMIN * wMinutes) / ANIMFRAMES_PERSEC;
272         wFrames = dwFrame - ANIMFRAMES_PERMIN * wMinutes -
273             ANIMFRAMES_PERSEC * wSeconds;
274         dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
275         TRACE("MSF %02u:%02u:%02u -> dwTime=%lu\n",wMinutes, wSeconds, wFrames, dwTime);
276         *lpRet = MCI_COLONIZED3_RETURN;
277         break;
278     default:
279         /* unknown format ! force TMSF ! ... */
280         dwFormatType = MCI_FORMAT_TMSF;
281     case MCI_FORMAT_TMSF:
282         for (wTrack = 0; wTrack < wma->nTracks; wTrack++) {
283             /*                          dwTime += wma->lpdwTrackLen[wTrack - 1];
284                                         TRACE("Adding trk#%u curpos=%u \n", dwTime);
285                                         if (dwTime >= dwFrame) break; */
286             if (wma->lpdwTrackPos[wTrack - 1] >= dwFrame) break;
287         }
288         wMinutes = dwFrame / ANIMFRAMES_PERMIN;
289         wSeconds = (dwFrame - ANIMFRAMES_PERMIN * wMinutes) / ANIMFRAMES_PERSEC;
290         wFrames = dwFrame - ANIMFRAMES_PERMIN * wMinutes -
291             ANIMFRAMES_PERSEC * wSeconds;
292         dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
293         *lpRet = MCI_COLONIZED4_RETURN;
294         TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
295         break;
296     }
297     return dwTime;
298 }
299
300
301 /**************************************************************************
302  *                              MCIANIM_CalcFrame                       [internal]
303  */
304 static DWORD MCIANIM_CalcFrame(WINE_MCIANIM* wma, DWORD dwFormatType, DWORD dwTime)
305 {
306     DWORD       dwFrame = 0;
307     UINT16      wTrack;
308
309     TRACE("(%p, %08lX, %lu);\n", wma, dwFormatType, dwTime);
310
311     switch (dwFormatType) {
312     case MCI_FORMAT_MILLISECONDS:
313         dwFrame = dwTime * ANIMFRAMES_PERSEC / 1000;
314         TRACE("MILLISECONDS %lu\n", dwFrame);
315         break;
316     case MCI_FORMAT_MSF:
317         TRACE("MSF %02u:%02u:%02u\n",
318               MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime),
319               MCI_MSF_FRAME(dwTime));
320         dwFrame += ANIMFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
321         dwFrame += ANIMFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
322         dwFrame += MCI_MSF_FRAME(dwTime);
323         break;
324     default:
325         /* unknown format ! force TMSF ! ... */
326         dwFormatType = MCI_FORMAT_TMSF;
327     case MCI_FORMAT_TMSF:
328         wTrack = MCI_TMSF_TRACK(dwTime);
329         TRACE("TMSF %02u-%02u:%02u:%02u\n",
330               MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime),
331               MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
332         TRACE("TMSF trackpos[%u]=%lu\n",
333               wTrack, wma->lpdwTrackPos[wTrack - 1]);
334         dwFrame = wma->lpdwTrackPos[wTrack - 1];
335         dwFrame += ANIMFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
336         dwFrame += ANIMFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
337         dwFrame += MCI_TMSF_FRAME(dwTime);
338         break;
339     }
340     return dwFrame;
341 }
342
343 /**************************************************************************
344  *                              MCIANIM_mciInfo                 [internal]
345  */
346 static DWORD MCIANIM_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
347 {
348     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
349     LPCSTR              str = 0;
350     DWORD               ret = 0;
351
352     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
353
354     if (lpParms == NULL || lpParms->lpstrReturn == NULL)
355         return MCIERR_NULL_PARAMETER_BLOCK;
356
357     if (wma == NULL)
358         return MCIERR_INVALID_DEVICE_ID;
359
360     TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
361
362     switch(dwFlags) {
363     case MCI_INFO_PRODUCT:
364         str = "Wine's animation";
365         break;
366     case MCI_INFO_FILE:
367         str = wma->openParms.lpstrElementName;
368         break;
369     case MCI_ANIM_INFO_TEXT:
370         str = "Animation Window";
371         break;
372     default:
373         WARN("Don't know this info command (%lu)\n", dwFlags);
374         return MCIERR_UNRECOGNIZED_COMMAND;
375     }
376
377     if (str) {
378         if (lpParms->dwRetSize <= strlen(str)) {
379             lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize - 1);
380             ret = MCIERR_PARAM_OVERFLOW;
381         } else {
382             strcpy(lpParms->lpstrReturn, str);
383         }
384     } else {
385         *lpParms->lpstrReturn = 0;
386     }
387     return ret;
388 }
389
390 /**************************************************************************
391  *                              MCIANIM_mciStatus               [internal]
392  */
393 static DWORD MCIANIM_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
394 {
395     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
396     DWORD               ret;
397
398     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
399
400     if (lpParms == NULL) return MCIERR_INTERNAL;
401     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
402
403     if (dwFlags & MCI_NOTIFY) {
404         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
405
406         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
407                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
408     }
409     if (dwFlags & MCI_STATUS_ITEM) {
410         switch(lpParms->dwItem) {
411         case MCI_STATUS_CURRENT_TRACK:
412             lpParms->dwReturn = wma->nCurTrack;
413             TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
414             break;
415         case MCI_STATUS_LENGTH:
416             if (dwFlags & MCI_TRACK) {
417                 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
418                 if (lpParms->dwTrack > wma->nTracks)
419                     return MCIERR_OUTOFRANGE;
420                 lpParms->dwReturn = wma->lpdwTrackLen[lpParms->dwTrack];
421             }
422             else
423                 lpParms->dwReturn = wma->dwTotalLen;
424             lpParms->dwReturn = MCIANIM_CalcTime(wma, wma->dwTimeFormat, lpParms->dwReturn, &ret);
425             TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
426             break;
427         case MCI_STATUS_MODE:
428             TRACE("MCI_STATUS_MODE=%04X !\n", wma->mode);
429             lpParms->dwReturn = MAKEMCIRESOURCE(wma->mode, wma->mode);
430             ret = MCI_RESOURCE_RETURNED;
431             break;
432         case MCI_STATUS_MEDIA_PRESENT:
433             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
434             ret = MCI_RESOURCE_RETURNED;
435             TRACE("MCI_STATUS_MEDIA_PRESENT !\n");
436             break;
437         case MCI_STATUS_NUMBER_OF_TRACKS:
438             lpParms->dwReturn = 1;
439             TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
440             break;
441         case MCI_STATUS_POSITION:
442             lpParms->dwReturn = wma->dwCurFrame;
443             if (dwFlags & MCI_STATUS_START) {
444                 lpParms->dwReturn = 0;
445                 TRACE("get MCI_STATUS_START !\n");
446             }
447             if (dwFlags & MCI_TRACK) {
448                 if (lpParms->dwTrack > wma->nTracks)
449                     return MCIERR_OUTOFRANGE;
450                 lpParms->dwReturn = wma->lpdwTrackPos[lpParms->dwTrack - 1];
451                 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
452             }
453             lpParms->dwReturn = MCIANIM_CalcTime(wma, wma->dwTimeFormat, lpParms->dwReturn, &ret);
454             TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
455             break;
456         case MCI_STATUS_READY:
457             TRACE("MCI_STATUS_READY !\n");
458             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
459             ret = MCI_RESOURCE_RETURNED;
460             return 0;
461         case MCI_STATUS_TIME_FORMAT:
462             TRACE("MCI_STATUS_TIME_FORMAT !\n");
463             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_FORMAT_MILLISECONDS, MCI_FORMAT_MILLISECONDS_S);
464             TRACE("MCI_STATUS_TIME_FORMAT => %u\n", LOWORD(lpParms->dwReturn));
465             ret = MCI_RESOURCE_RETURNED;
466             return 0;
467         default:
468             FIXME("Unknown command %08lX !\n", lpParms->dwItem);
469             return MCIERR_UNRECOGNIZED_COMMAND;
470         }
471     } else {
472         WARN("No MCI_STATUS_ITEM !\n");
473         return MCIERR_UNRECOGNIZED_COMMAND;
474     }
475     return ret;
476 }
477
478
479 /**************************************************************************
480  *                              MCIANIM_mciPlay                 [internal]
481  */
482 static DWORD MCIANIM_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
483 {
484     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
485     int         start, end;
486
487     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
488
489     if (lpParms == NULL) return MCIERR_INTERNAL;
490     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
491
492     start = 0;          end = wma->dwTotalLen;
493     wma->nCurTrack = 1;
494     if (dwFlags & MCI_FROM) {
495         start = MCIANIM_CalcFrame(wma, wma->dwTimeFormat, lpParms->dwFrom);
496         TRACE("MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
497     }
498     if (dwFlags & MCI_TO) {
499         end = MCIANIM_CalcFrame(wma, wma->dwTimeFormat, lpParms->dwTo);
500         TRACE("MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
501     }
502     wma->mode = MCI_MODE_PLAY;
503     if (dwFlags & MCI_NOTIFY) {
504         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n",
505               lpParms->dwCallback);
506         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
507                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
508     }
509     return 0;
510 }
511
512 /**************************************************************************
513  *                              MCIANIM_mciStop                 [internal]
514  */
515 static DWORD MCIANIM_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
516 {
517     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
518
519     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
520
521     if (lpParms == NULL) return MCIERR_INTERNAL;
522     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
523
524     wma->mode = MCI_MODE_STOP;
525     if (dwFlags & MCI_NOTIFY) {
526         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
527
528         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
529                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
530     }
531     return 0;
532 }
533
534 /**************************************************************************
535  *                              MCIANIM_mciPause                [internal]
536  */
537 static DWORD MCIANIM_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
538 {
539     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
540
541     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
542     if (lpParms == NULL) return MCIERR_INTERNAL;
543     wma->mode = MCI_MODE_PAUSE;
544     if (dwFlags & MCI_NOTIFY) {
545         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
546
547         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
548                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
549     }
550     return 0;
551 }
552
553 /**************************************************************************
554  *                              MCIANIM_mciResume               [internal]
555  */
556 static DWORD MCIANIM_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
557 {
558     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
559
560     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
561     if (lpParms == NULL) return MCIERR_INTERNAL;
562     wma->mode = MCI_MODE_STOP;
563     if (dwFlags & MCI_NOTIFY) {
564         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
565
566         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
567                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
568     }
569     return 0;
570 }
571
572 /**************************************************************************
573  *                              MCIANIM_mciSeek                 [internal]
574  */
575 static DWORD MCIANIM_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
576 {
577     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
578     DWORD       dwRet;
579     MCI_PLAY_PARMS PlayParms;
580
581     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
582
583     if (lpParms == NULL) return MCIERR_INTERNAL;
584     wma->mode = MCI_MODE_SEEK;
585     switch (dwFlags) {
586     case MCI_SEEK_TO_START:
587         PlayParms.dwFrom = 0;
588         break;
589     case MCI_SEEK_TO_END:
590         PlayParms.dwFrom = wma->dwTotalLen;
591         break;
592     case MCI_TO:
593         PlayParms.dwFrom = lpParms->dwTo;
594         break;
595     }
596     dwRet = MCIANIM_mciPlay(wDevID, MCI_WAIT | MCI_FROM, &PlayParms);
597     if (dwRet != 0) return dwRet;
598     dwRet = MCIANIM_mciStop(wDevID, MCI_WAIT, (LPMCI_GENERIC_PARMS)&PlayParms);
599     if (dwFlags & MCI_NOTIFY) {
600         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
601
602         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
603                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
604     }
605     return dwRet;
606 }
607
608
609 /**************************************************************************
610  *                              MCIANIM_mciSet                  [internal]
611  */
612 static DWORD MCIANIM_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
613 {
614     WINE_MCIANIM*       wma = MCIANIM_mciGetOpenDrv(wDevID);
615
616     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
617
618     if (lpParms == NULL) return MCIERR_INTERNAL;
619     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
620     /*
621       TRACE("(dwTimeFormat=%08lX)\n", lpParms->dwTimeFormat);
622       TRACE("(dwAudio=%08lX)\n", lpParms->dwAudio);
623     */
624     if (dwFlags & MCI_SET_TIME_FORMAT) {
625         switch (lpParms->dwTimeFormat) {
626         case MCI_FORMAT_MILLISECONDS:
627             TRACE("MCI_FORMAT_MILLISECONDS !\n");
628             break;
629         case MCI_FORMAT_MSF:
630             TRACE("MCI_FORMAT_MSF !\n");
631             break;
632         case MCI_FORMAT_TMSF:
633             TRACE("MCI_FORMAT_TMSF !\n");
634             break;
635         default:
636             WARN("Bad time format !\n");
637             return MCIERR_BAD_TIME_FORMAT;
638         }
639         wma->dwTimeFormat = lpParms->dwTimeFormat;
640     }
641     if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
642     if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
643     if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
644     if (dwFlags & MCI_NOTIFY) {
645         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
646         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
647                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
648     }
649     return 0;
650 }
651
652 /**************************************************************************
653  *                              DriverProc (MCIANIM.@)
654  */
655 LONG WINAPI MCIANIM_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
656                                DWORD dwParam1, DWORD dwParam2)
657 {
658     switch (wMsg) {
659     case DRV_LOAD:              return 1;
660     case DRV_FREE:              return 1;
661     case DRV_OPEN:              return MCIANIM_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
662     case DRV_CLOSE:             return MCIANIM_drvClose(dwDevID);
663     case DRV_ENABLE:            return 1;
664     case DRV_DISABLE:           return 1;
665     case DRV_QUERYCONFIGURE:    return 1;
666     case DRV_CONFIGURE:         MessageBoxA(0, "Sample MultiMedia Driver !", "Wine Driver", MB_OK); return 1;
667     case DRV_INSTALL:           return DRVCNF_RESTART;
668     case DRV_REMOVE:            return DRVCNF_RESTART;
669     }
670
671     if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
672
673     switch (wMsg) {
674     case MCI_OPEN_DRIVER:       return MCIANIM_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
675     case MCI_CLOSE_DRIVER:      return MCIANIM_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
676     case MCI_GETDEVCAPS:        return MCIANIM_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
677     case MCI_INFO:              return MCIANIM_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMSA)dwParam2);
678     case MCI_STATUS:            return MCIANIM_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
679     case MCI_SET:               return MCIANIM_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
680     case MCI_PLAY:              return MCIANIM_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
681     case MCI_STOP:              return MCIANIM_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
682     case MCI_PAUSE:             return MCIANIM_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
683     case MCI_RESUME:            return MCIANIM_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
684     case MCI_SEEK:              return MCIANIM_mciSeek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
685     case MCI_LOAD:
686     case MCI_SAVE:
687     case MCI_FREEZE:
688     case MCI_PUT:
689     case MCI_REALIZE:
690     case MCI_UNFREEZE:
691     case MCI_UPDATE:
692     case MCI_WHERE:
693     case MCI_WINDOW:
694     case MCI_STEP:
695     case MCI_SPIN:
696     case MCI_ESCAPE:
697     case MCI_COPY:
698     case MCI_CUT:
699     case MCI_DELETE:
700     case MCI_PASTE:
701         FIXME("Unsupported message [%lu]\n", wMsg);
702         break;
703     case MCI_OPEN:
704     case MCI_CLOSE:
705         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
706         break;
707     default:
708         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
709         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
710     }
711     return MCIERR_UNRECOGNIZED_COMMAND;
712 }
713
714 /*-----------------------------------------------------------------------*/