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