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