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