- implementation of RtlReg* (read access), RtlEvent*, RtlSemaphore*,
[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 "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_DIGITAL_VIDEO;
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     DWORD               ret = 0;
329     
330     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
331     
332     if (lpParms == NULL || lpParms->lpstrReturn == NULL)
333         return MCIERR_NULL_PARAMETER_BLOCK;
334
335     if (wma == NULL)
336         return MCIERR_INVALID_DEVICE_ID;
337     
338     TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
339     
340     switch(dwFlags) {
341     case MCI_INFO_PRODUCT:
342         str = "Wine's animation";
343         break;
344     case MCI_INFO_FILE:
345         str = wma->openParms.lpstrElementName;
346         break;
347     case MCI_ANIM_INFO_TEXT:
348         str = "Animation Window";
349         break;
350     default:
351         WARN("Don't know this info command (%lu)\n", dwFlags);
352         return MCIERR_UNRECOGNIZED_COMMAND;
353     }
354
355     if (str) {
356         if (lpParms->dwRetSize <= strlen(str)) {
357             lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize - 1);
358             ret = MCIERR_PARAM_OVERFLOW;
359         } else {
360             strcpy(lpParms->lpstrReturn, str);
361         }       
362     } else {
363         *lpParms->lpstrReturn = 0;
364     }
365     return ret;
366 }
367
368 /**************************************************************************
369  *                              ANIM_mciStatus          [internal]
370  */
371 static DWORD ANIM_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
372 {
373     WINE_MCIANIM*       wma = ANIM_mciGetOpenDrv(wDevID);
374     DWORD               ret;
375
376     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
377     
378     if (lpParms == NULL) return MCIERR_INTERNAL;
379     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
380     
381     if (dwFlags & MCI_NOTIFY) {
382         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
383
384         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
385                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
386     }
387     if (dwFlags & MCI_STATUS_ITEM) {
388         switch(lpParms->dwItem) {
389         case MCI_STATUS_CURRENT_TRACK:
390             lpParms->dwReturn = wma->nCurTrack;
391             TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
392             break;
393         case MCI_STATUS_LENGTH:
394             if (dwFlags & MCI_TRACK) {
395                 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
396                 if (lpParms->dwTrack > wma->nTracks)
397                     return MCIERR_OUTOFRANGE;
398                 lpParms->dwReturn = wma->lpdwTrackLen[lpParms->dwTrack];
399             }
400             else
401                 lpParms->dwReturn = wma->dwTotalLen;
402             lpParms->dwReturn = ANIM_CalcTime(wma, wma->dwTimeFormat, lpParms->dwReturn, &ret);
403             TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
404             break;
405         case MCI_STATUS_MODE:
406             TRACE("MCI_STATUS_MODE=%04X !\n", wma->mode);
407             lpParms->dwReturn = MAKEMCIRESOURCE(wma->mode, wma->mode);
408             ret = MCI_RESOURCE_RETURNED;
409             break;
410         case MCI_STATUS_MEDIA_PRESENT:
411             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
412             ret = MCI_RESOURCE_RETURNED;
413             TRACE("MCI_STATUS_MEDIA_PRESENT !\n");
414             break;
415         case MCI_STATUS_NUMBER_OF_TRACKS:
416             lpParms->dwReturn = 1;
417             TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
418             break;
419         case MCI_STATUS_POSITION:
420             lpParms->dwReturn = wma->dwCurFrame;
421             if (dwFlags & MCI_STATUS_START) {
422                 lpParms->dwReturn = 0;
423                 TRACE("get MCI_STATUS_START !\n");
424             }
425             if (dwFlags & MCI_TRACK) {
426                 if (lpParms->dwTrack > wma->nTracks)
427                     return MCIERR_OUTOFRANGE;
428                 lpParms->dwReturn = wma->lpdwTrackPos[lpParms->dwTrack - 1];
429                 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
430             }
431             lpParms->dwReturn = ANIM_CalcTime(wma, wma->dwTimeFormat, lpParms->dwReturn, &ret);
432             TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
433             break;
434         case MCI_STATUS_READY:
435             TRACE("MCI_STATUS_READY !\n");
436             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
437             ret = MCI_RESOURCE_RETURNED;
438             return 0;
439         case MCI_STATUS_TIME_FORMAT:
440             TRACE("MCI_STATUS_TIME_FORMAT !\n");
441             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_FORMAT_MILLISECONDS, MCI_FORMAT_MILLISECONDS);
442             TRACE("MCI_STATUS_TIME_FORMAT => %u\n", LOWORD(lpParms->dwReturn));
443             ret = MCI_RESOURCE_RETURNED;
444             return 0;
445         default:
446             FIXME("Unknown command %08lX !\n", lpParms->dwItem);
447             return MCIERR_UNRECOGNIZED_COMMAND;
448         }
449     } else {
450         WARN("No MCI_STATUS_ITEM !\n");
451         return MCIERR_UNRECOGNIZED_COMMAND;
452     }
453     return ret;
454 }
455
456
457 /**************************************************************************
458  *                              ANIM_mciPlay                    [internal]
459  */
460 static DWORD ANIM_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
461 {
462     WINE_MCIANIM*       wma = ANIM_mciGetOpenDrv(wDevID);
463     int         start, end;
464     
465     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
466     
467     if (lpParms == NULL) return MCIERR_INTERNAL;
468     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
469     
470     start = 0;          end = wma->dwTotalLen;
471     wma->nCurTrack = 1;
472     if (dwFlags & MCI_FROM) {
473         start = ANIM_CalcFrame(wma, wma->dwTimeFormat, lpParms->dwFrom); 
474         TRACE("MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
475     }
476     if (dwFlags & MCI_TO) {
477         end = ANIM_CalcFrame(wma, wma->dwTimeFormat, lpParms->dwTo);
478         TRACE("MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
479     }
480     wma->mode = MCI_MODE_PLAY;
481     if (dwFlags & MCI_NOTIFY) {
482         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
483               lpParms->dwCallback);
484         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
485                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
486     }
487     return 0;
488 }
489
490 /**************************************************************************
491  *                              ANIM_mciStop                    [internal]
492  */
493 static DWORD ANIM_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
494 {
495     WINE_MCIANIM*       wma = ANIM_mciGetOpenDrv(wDevID);
496     
497     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
498     
499     if (lpParms == NULL) return MCIERR_INTERNAL;
500     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
501     
502     wma->mode = MCI_MODE_STOP;
503     if (dwFlags & MCI_NOTIFY) {
504         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
505
506         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
507                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
508     }
509     return 0;
510 }
511
512 /**************************************************************************
513  *                              ANIM_mciPause           [internal]
514  */
515 static DWORD ANIM_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
516 {
517     WINE_MCIANIM*       wma = ANIM_mciGetOpenDrv(wDevID);
518     
519     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
520     if (lpParms == NULL) return MCIERR_INTERNAL;
521     wma->mode = MCI_MODE_PAUSE;
522     if (dwFlags & MCI_NOTIFY) {
523         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
524
525         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
526                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
527     }
528     return 0;
529 }
530
531 /**************************************************************************
532  *                              ANIM_mciResume          [internal]
533  */
534 static DWORD ANIM_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
535 {
536     WINE_MCIANIM*       wma = ANIM_mciGetOpenDrv(wDevID);
537     
538     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
539     if (lpParms == NULL) return MCIERR_INTERNAL;
540     wma->mode = MCI_MODE_STOP;
541     if (dwFlags & MCI_NOTIFY) {
542         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
543
544         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
545                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
546     }
547     return 0;
548 }
549
550 /**************************************************************************
551  *                              ANIM_mciSeek                    [internal]
552  */
553 static DWORD ANIM_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
554 {
555     WINE_MCIANIM*       wma = ANIM_mciGetOpenDrv(wDevID);
556     DWORD       dwRet;
557     MCI_PLAY_PARMS PlayParms;
558     
559     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
560     
561     if (lpParms == NULL) return MCIERR_INTERNAL;
562     wma->mode = MCI_MODE_SEEK;
563     switch (dwFlags) {
564     case MCI_SEEK_TO_START:
565         PlayParms.dwFrom = 0;
566         break;
567     case MCI_SEEK_TO_END:
568         PlayParms.dwFrom = wma->dwTotalLen;
569         break;
570     case MCI_TO:
571         PlayParms.dwFrom = lpParms->dwTo;
572         break;
573     }
574     dwRet = ANIM_mciPlay(wDevID, MCI_WAIT | MCI_FROM, &PlayParms);
575     if (dwRet != 0) return dwRet;
576     dwRet = ANIM_mciStop(wDevID, MCI_WAIT, (LPMCI_GENERIC_PARMS)&PlayParms);
577     if (dwFlags & MCI_NOTIFY) {
578         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
579
580         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
581                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
582     }
583     return dwRet;
584 }
585
586
587 /**************************************************************************
588  *                              ANIM_mciSet                     [internal]
589  */
590 static DWORD ANIM_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
591 {
592     WINE_MCIANIM*       wma = ANIM_mciGetOpenDrv(wDevID);
593     
594     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
595
596     if (lpParms == NULL) return MCIERR_INTERNAL;
597     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
598     /*
599       TRACE("(dwTimeFormat=%08lX)\n", lpParms->dwTimeFormat);
600       TRACE("(dwAudio=%08lX)\n", lpParms->dwAudio);
601     */
602     if (dwFlags & MCI_SET_TIME_FORMAT) {
603         switch (lpParms->dwTimeFormat) {
604         case MCI_FORMAT_MILLISECONDS:
605             TRACE("MCI_FORMAT_MILLISECONDS !\n");
606             break;
607         case MCI_FORMAT_MSF:
608             TRACE("MCI_FORMAT_MSF !\n");
609             break;
610         case MCI_FORMAT_TMSF:
611             TRACE("MCI_FORMAT_TMSF !\n");
612             break;
613         default:
614             WARN("Bad time format !\n");
615             return MCIERR_BAD_TIME_FORMAT;
616         }
617         wma->dwTimeFormat = lpParms->dwTimeFormat;
618     }
619     if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
620     if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
621     if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
622     if (dwFlags & MCI_NOTIFY) {
623         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
624         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
625                           wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
626     }
627     return 0;
628 }
629
630 /**************************************************************************
631  *                              ANIM_DriverProc                 [sample driver]
632  */
633 LONG    CALLBACK        MCIANIM_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
634                                            DWORD dwParam1, DWORD dwParam2)
635 {
636     switch (wMsg) {
637     case DRV_LOAD:              return 1;
638     case DRV_FREE:              return 1; 
639     case DRV_OPEN:              return ANIM_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
640     case DRV_CLOSE:             return ANIM_drvClose(dwDevID);
641     case DRV_ENABLE:            return 1;
642     case DRV_DISABLE:           return 1;
643     case DRV_QUERYCONFIGURE:    return 1;
644     case DRV_CONFIGURE:         MessageBoxA(0, "Sample MultiMedia Driver !", "Wine Driver", MB_OK); return 1;
645     case DRV_INSTALL:           return DRVCNF_RESTART;
646     case DRV_REMOVE:            return DRVCNF_RESTART;
647         
648     case MCI_OPEN_DRIVER:       return ANIM_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2); 
649     case MCI_CLOSE_DRIVER:      return ANIM_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
650     case MCI_GETDEVCAPS:        return ANIM_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
651     case MCI_INFO:              return ANIM_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)dwParam2);
652     case MCI_STATUS:            return ANIM_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
653     case MCI_SET:               return ANIM_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
654     case MCI_PLAY:              return ANIM_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
655     case MCI_STOP:              return ANIM_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
656     case MCI_PAUSE:             return ANIM_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
657     case MCI_RESUME:            return ANIM_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
658     case MCI_SEEK:              return ANIM_mciSeek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
659     case MCI_LOAD:              
660     case MCI_SAVE:              
661     case MCI_FREEZE:            
662     case MCI_PUT:               
663     case MCI_REALIZE:           
664     case MCI_UNFREEZE:          
665     case MCI_UPDATE:            
666     case MCI_WHERE:             
667     case MCI_WINDOW:            
668     case MCI_STEP:              
669     case MCI_SPIN:              
670     case MCI_ESCAPE:            
671     case MCI_COPY:              
672     case MCI_CUT:               
673     case MCI_DELETE:            
674     case MCI_PASTE:             
675         FIXME("Unsupported message [%lu]\n", wMsg);
676         break;
677     case MCI_OPEN:
678     case MCI_CLOSE:
679         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
680         break;
681     default:                    
682         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
683         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
684     }
685     return MCIERR_UNRECOGNIZED_COMMAND;
686 }
687
688 /*-----------------------------------------------------------------------*/