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