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