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