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