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