Changed "strings.h" to "string.h".
[wine] / multimedia / mci.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * MCI internal functions
5  *
6  * Copyright 1998/1999 Eric Pouech
7  */
8
9 #include <string.h>
10
11 #include "winbase.h"
12 #include "winuser.h"
13 #include "heap.h"
14 #include "driver.h"
15 #include "mmsystem.h"
16 #include "multimedia.h"
17 #include "selectors.h"
18 #include "debug.h"
19 #include "digitalv.h"
20
21 struct WINE_MCIDRIVER mciDrv[MAXMCIDRIVERS];
22
23 int     mciInstalledCount;
24 int     mciInstalledListLen;
25 LPSTR   lpmciInstallNames = NULL;
26
27 /* The wDevID's returned by wine were originally in the range 
28  * 0 - (MAXMCIDRIVERS - 1) and used directly as array indices.
29  * Unfortunately, ms-windows uses wDevID of zero to indicate
30  * errors.  Now, multimedia drivers must pass the wDevID through
31  * MCI_DevIDToIndex to get an index in that range.  An
32  * arbitrary value, MCI_MAGIC is added to the wDevID seen
33  * by the windows programs.
34  */
35
36 #define MCI_MAGIC 0x0F00
37
38 MCI_WineDesc    MCI_InternalDescriptors[] = {
39     {MCI_DEVTYPE_CD_AUDIO,              "CDAUDIO",      MCICDAUDIO_DriverProc},
40     {MCI_DEVTYPE_WAVEFORM_AUDIO,        "WAVEAUDIO",    MCIWAVE_DriverProc},
41     {MCI_DEVTYPE_SEQUENCER,             "SEQUENCER",    MCIMIDI_DriverProc},
42     {MCI_DEVTYPE_ANIMATION,             "ANIMATION1",   MCIANIM_DriverProc},
43     {MCI_DEVTYPE_DIGITAL_VIDEO,         "AVIVIDEO",     MCIAVI_DriverProc},
44
45     {0xFFFF,                            NULL,           NULL}   /* sentinel */
46 };
47
48 /**************************************************************************
49  *                              MCI_GetDevTypeString            [internal]
50  */
51 static  LPCSTR          MCI_GetDevTypeString(WORD uDevType)
52 {
53     LPCSTR      str = "??? MCI ???";
54     int         i;
55
56     for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
57         if (MCI_InternalDescriptors[i].uDevType != 0 && MCI_InternalDescriptors[i].uDevType == uDevType) {
58             str = MCI_InternalDescriptors[i].lpstrName;
59             break;
60         }
61     }
62     /*    TRACE(mci, "devType=%u => %s\n", uDevType, str);*/
63     return str;
64 }
65
66 /**************************************************************************
67  *                              MCI_GetProc                     [internal]
68  */
69 static  MCIPROC         MCI_GetProc(UINT16 uDevType)
70 {
71     MCIPROC     proc = 0;
72     int         i;
73
74     for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
75         if (MCI_InternalDescriptors[i].uDevType != 0 && 
76             MCI_InternalDescriptors[i].uDevType == uDevType) {
77             proc = MCI_InternalDescriptors[i].lpfnProc;
78             break;
79         }
80     }
81     return proc;
82 }
83
84 /**************************************************************************
85  *                              MCI_GetDevType                  [internal]
86  */
87 WORD            MCI_GetDevType(LPCSTR str)
88 {
89     WORD        uDevType = 0;
90     int         i;
91
92     for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
93         if (MCI_InternalDescriptors[i].uDevType != 0 && 
94             strcmp(str, MCI_InternalDescriptors[i].lpstrName) == 0) {
95             uDevType = MCI_InternalDescriptors[i].uDevType;
96             break;
97         }
98     }
99     return uDevType;
100 }
101
102 /**************************************************************************
103  *                              MCI_DevIDToIndex                [internal]
104  */
105 int MCI_DevIDToIndex(UINT16 wDevID) 
106 {
107     return wDevID - MCI_MAGIC;
108 }
109
110 /**************************************************************************
111  *                              MCI_FirstDevId                  [internal]
112  */
113 UINT16 MCI_FirstDevID(void)
114 {
115     return MCI_MAGIC;
116 }
117
118 /**************************************************************************
119  *                              MCI_NextDevId                   [internal]
120  */
121 UINT16 MCI_NextDevID(UINT16 wDevID) 
122 {
123     return wDevID + 1;
124 }
125
126 /**************************************************************************
127  *                              MCI_DevIDValid                  [internal]
128  */
129 BOOL MCI_DevIDValid(UINT16 wDevID) 
130 {
131     return wDevID >= MCI_MAGIC && wDevID < (MCI_MAGIC + MAXMCIDRIVERS);
132 }
133
134 /**************************************************************************
135  *                      MCI_CommandToString                     [internal]
136  */
137 const char* MCI_CommandToString(UINT16 wMsg)
138 {
139     static char buffer[100];
140     
141 #define CASE(s) case (s): return #s
142     
143     switch (wMsg) {
144         CASE(MCI_BREAK);
145         CASE(MCI_CLOSE);
146         CASE(MCI_CLOSE_DRIVER);
147         CASE(MCI_COPY);
148         CASE(MCI_CUE);
149         CASE(MCI_CUT);
150         CASE(MCI_DELETE);
151         CASE(MCI_ESCAPE);
152         CASE(MCI_FREEZE);
153         CASE(MCI_PAUSE);
154         CASE(MCI_PLAY);
155         CASE(MCI_GETDEVCAPS);
156         CASE(MCI_INFO);
157         CASE(MCI_LOAD);
158         CASE(MCI_OPEN);
159         CASE(MCI_OPEN_DRIVER);
160         CASE(MCI_PASTE);
161         CASE(MCI_PUT);
162         CASE(MCI_REALIZE);
163         CASE(MCI_RECORD);
164         CASE(MCI_RESUME);
165         CASE(MCI_SAVE);
166         CASE(MCI_SEEK);
167         CASE(MCI_SET);
168         CASE(MCI_SPIN);
169         CASE(MCI_STATUS);
170         CASE(MCI_STEP);
171         CASE(MCI_STOP);
172         CASE(MCI_SYSINFO);
173         CASE(MCI_UNFREEZE);
174         CASE(MCI_UPDATE);
175         CASE(MCI_WHERE);
176         CASE(MCI_WINDOW);
177     default:
178         sprintf(buffer, "MCI_<<%04X>>", wMsg);
179         return buffer;
180     }
181 #undef CASE
182 }
183
184 /**************************************************************************
185  *                      MCI_MapMsg16To32A                       [internal]
186  */
187 int     MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam)
188 {
189     if (*lParam == 0)
190         return 0;
191     /* FIXME: to add also (with seg/linear modifications to do):
192      * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE
193      * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO
194      */
195     switch (wMsg) {
196         /* case MCI_CAPTURE */
197     case MCI_CLOSE:             
198     case MCI_CLOSE_DRIVER:      
199         /* case MCI_CONFIGURE:*/
200     case MCI_COPY:
201     case MCI_CUE:
202     case MCI_CUT:
203     case MCI_DELETE:
204     case MCI_FREEZE:
205     case MCI_GETDEVCAPS:
206         /* case MCI_INDEX: */
207         /* case MCI_MARK: */
208         /* case MCI_MONITOR: */
209     case MCI_PASTE:
210     case MCI_PAUSE:             
211     case MCI_PLAY:              
212     case MCI_PUT:
213     case MCI_REALIZE:
214     case MCI_RECORD:            
215     case MCI_RESUME:            
216     case MCI_SEEK:              
217     case MCI_SET:
218         /* case MCI_SETTIMECODE:*/
219         /* case MCI_SIGNAL:*/
220     case MCI_SPIN:
221     case MCI_STATUS:            /* FIXME: is wrong for digital video */
222     case MCI_STEP:
223     case MCI_STOP:              
224         /* case MCI_UNDO: */
225     case MCI_UNFREEZE:
226     case MCI_UPDATE:
227     case MCI_WHERE:
228         *lParam = (DWORD)PTR_SEG_TO_LIN(*lParam);
229         return 0;
230     case MCI_WINDOW:
231         /* in fact, I would also need the dwFlags... to see 
232          * which members of lParam are effectively used 
233          */
234         *lParam = (DWORD)PTR_SEG_TO_LIN(*lParam);
235         FIXME(mci, "Current mapping may be wrong\n");
236         break;
237     case MCI_BREAK:
238         {
239             LPMCI_BREAK_PARMS           mbp32 = HeapAlloc(SystemHeap, 0, sizeof(MCI_BREAK_PARMS));
240             LPMCI_BREAK_PARMS16         mbp16 = PTR_SEG_TO_LIN(*lParam);
241
242             if (mbp32) {
243                 mbp32->dwCallback = mbp16->dwCallback;
244                 mbp32->nVirtKey = mbp16->nVirtKey;
245                 mbp32->hwndBreak = mbp16->hwndBreak;
246             } else {
247                 return -2;
248             }
249             *lParam = (DWORD)mbp32;
250         }
251         return 1;
252     case MCI_ESCAPE:
253         {
254             LPMCI_VD_ESCAPE_PARMSA      mvep32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_VD_ESCAPE_PARMSA));
255             LPMCI_VD_ESCAPE_PARMS16     mvep16  = PTR_SEG_TO_LIN(*lParam);
256
257             if (mvep32a) {
258                 mvep32a->dwCallback       = mvep16->dwCallback;
259                 mvep32a->lpstrCommand     = PTR_SEG_TO_LIN(mvep16->lpstrCommand);
260             } else {
261                 return -2;
262             }
263             *lParam = (DWORD)mvep32a;
264         }
265         return 1;
266     case MCI_INFO:
267         {
268             LPMCI_INFO_PARMSA   mip32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_INFO_PARMSA));
269             LPMCI_INFO_PARMS16  mip16  = PTR_SEG_TO_LIN(*lParam);
270
271             /* FIXME this is wrong if device is of type 
272              * MCI_DEVTYPE_DIGITAL_VIDEO, some members are not mapped
273              */
274             if (mip32a) {
275                 mip32a->dwCallback  = mip16->dwCallback;
276                 mip32a->lpstrReturn = PTR_SEG_TO_LIN(mip16->lpstrReturn);
277                 mip32a->dwRetSize   = mip16->dwRetSize;
278             } else {
279                 return -2;
280             }
281             *lParam = (DWORD)mip32a;
282         }
283         return 1;
284     case MCI_OPEN:
285     case MCI_OPEN_DRIVER:       
286         {
287             LPMCI_OPEN_PARMSA   mop32a = HeapAlloc(SystemHeap, 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_OPEN_PARMSA) + 2 * sizeof(DWORD));
288             LPMCI_OPEN_PARMS16  mop16  = PTR_SEG_TO_LIN(*lParam);
289
290             if (mop32a) {
291                 *(LPMCI_OPEN_PARMS16*)(mop32a) = mop16;
292                 mop32a = (LPMCI_OPEN_PARMSA)((char*)mop32a + sizeof(LPMCI_OPEN_PARMS16));
293                 mop32a->dwCallback       = mop16->dwCallback;
294                 mop32a->wDeviceID        = mop16->wDeviceID;
295                 mop32a->lpstrDeviceType  = PTR_SEG_TO_LIN(mop16->lpstrDeviceType);
296                 mop32a->lpstrElementName = PTR_SEG_TO_LIN(mop16->lpstrElementName);
297                 mop32a->lpstrAlias       = PTR_SEG_TO_LIN(mop16->lpstrAlias);
298                 /* copy extended information if any...
299                  * FIXME: this may seg fault if initial structure does not contain them and
300                  * the reads after msip16 fail under LDT limits...
301                  * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and 
302                  * should not take care of extended parameters, and should be used by MCI_Open
303                  * to fetch uDevType. When, this is known, the mapping for sending the 
304                  * MCI_OPEN_DRIVER shall be done depending on uDevType.
305                  */
306                 memcpy(mop32a + 1, mop16 + 1, 2 * sizeof(DWORD));
307             } else {
308                 return -2;
309             }
310             *lParam = (DWORD)mop32a;
311         }
312         return 1;
313     case MCI_SYSINFO:
314         {
315             LPMCI_SYSINFO_PARMSA        msip32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_SYSINFO_PARMSA));
316             LPMCI_SYSINFO_PARMS16       msip16  = PTR_SEG_TO_LIN(*lParam);
317
318             if (msip32a) {
319                 msip32a->dwCallback       = msip16->dwCallback;
320                 msip32a->lpstrReturn      = PTR_SEG_TO_LIN(msip16->lpstrReturn);
321                 msip32a->dwRetSize        = msip16->dwRetSize;
322                 msip32a->dwNumber         = msip16->dwNumber;
323                 msip32a->wDeviceType      = msip16->wDeviceType;
324             } else {
325                 return -2;
326             }
327             *lParam = (DWORD)msip32a;
328         }
329         return 1;
330     case DRV_LOAD:
331     case DRV_ENABLE:
332     case DRV_OPEN:
333     case DRV_CLOSE:
334     case DRV_DISABLE:
335     case DRV_FREE:
336     case DRV_CONFIGURE:
337     case DRV_QUERYCONFIGURE:
338     case DRV_INSTALL:
339     case DRV_REMOVE:
340     case DRV_EXITSESSION:
341     case DRV_EXITAPPLICATION:
342     case DRV_POWER:
343         FIXME(mci, "This is a hack\n");
344         return 0;
345
346     default:
347         WARN(mci, "Don't know how to map msg=%s\n", MCI_CommandToString(wMsg));
348     }
349     return -1;
350 }
351
352 /**************************************************************************
353  *                      MCI_UnMapMsg16To32A                     [internal]
354  */
355 int     MCI_UnMapMsg16To32A(WORD uDevType, WORD wMsg, DWORD lParam)
356 {
357     switch (wMsg) {
358         /* case MCI_CAPTURE */
359     case MCI_CLOSE:
360     case MCI_CLOSE_DRIVER:      
361         /* case MCI_CONFIGURE:*/
362     case MCI_COPY:
363     case MCI_CUE:
364     case MCI_CUT:
365     case MCI_DELETE:
366     case MCI_FREEZE:
367     case MCI_GETDEVCAPS:
368         /* case MCI_INDEX: */
369         /* case MCI_MARK: */
370         /* case MCI_MONITOR: */
371     case MCI_PASTE:
372     case MCI_PAUSE:             
373     case MCI_PLAY:              
374     case MCI_PUT:
375     case MCI_REALIZE:
376     case MCI_RECORD:            
377     case MCI_RESUME:            
378     case MCI_SEEK:              
379     case MCI_SET:
380         /* case MCI_SETTIMECODE:*/
381         /* case MCI_SIGNAL:*/
382     case MCI_SPIN:
383     case MCI_STATUS:            
384     case MCI_STEP:
385     case MCI_STOP:              
386         /* case MCI_UNDO: */
387     case MCI_UNFREEZE:
388     case MCI_UPDATE:
389     case MCI_WHERE:
390         return 0;
391
392     case MCI_WINDOW:
393         /* FIXME ?? see Map function */
394         return 0;
395
396     case MCI_BREAK:
397     case MCI_ESCAPE:
398     case MCI_INFO:
399     case MCI_SYSINFO:
400         HeapFree(SystemHeap, 0, (LPVOID)lParam);
401         return 0;
402     case MCI_OPEN:
403     case MCI_OPEN_DRIVER:       
404         if (lParam) {
405             LPMCI_OPEN_PARMSA   mop32a = (LPMCI_OPEN_PARMSA)lParam;
406             LPMCI_OPEN_PARMS16  mop16  = *(LPMCI_OPEN_PARMS16*)((char*)mop32a - sizeof(LPMCI_OPEN_PARMS16*));
407             
408             mop16->wDeviceID = mop32a->wDeviceID;
409             if (!HeapFree(SystemHeap, 0, (LPVOID)(lParam - sizeof(LPMCI_OPEN_PARMS16))))
410                 FIXME(mci, "bad free line=%d\n", __LINE__);
411         }
412         return 0;
413     case DRV_LOAD:
414     case DRV_ENABLE:
415     case DRV_OPEN:
416     case DRV_CLOSE:
417     case DRV_DISABLE:
418     case DRV_FREE:
419     case DRV_CONFIGURE:
420     case DRV_QUERYCONFIGURE:
421     case DRV_INSTALL:
422     case DRV_REMOVE:
423     case DRV_EXITSESSION:
424     case DRV_EXITAPPLICATION:
425     case DRV_POWER:
426         FIXME(mci, "This is a hack\n");
427         return 0;
428     default:
429         FIXME(mci, "Map/Unmap internal error on msg=%s\n", MCI_CommandToString(wMsg));
430     }
431     return -1;
432 }
433
434 /**************************************************************************
435  *                      MCI_MsgMapper32To16_Create              [internal]
436  *
437  * Helper for MCI_MapMsg32ATo16. 
438  * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit segmented pointer.
439  * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area.
440  *  1 : ok, some memory allocated
441  * -2 : ko, memory problem
442  */
443 static  int     MCI_MsgMapper32To16_Create(void** ptr, int size, BOOLEAN keep)
444 {
445     void*       lp = SEGPTR_ALLOC(sizeof(void**) + size);
446
447     if (!lp) {
448         return -2;
449     }
450     if (keep) {
451         *(void**)lp = *ptr;
452         memcpy((char*)lp + sizeof(void**), *ptr, size);
453         *ptr = (char*)SEGPTR_GET(lp) + sizeof(void**);
454     } else {
455         memcpy((char*)lp, *ptr, size);
456         *ptr = (void*)SEGPTR_GET(lp);
457     }
458     return 1;
459    
460 }
461
462 /**************************************************************************
463  *                      MCI_MsgMapper32To16_Destroy             [internal]
464  *
465  * Helper for MCI_UnMapMsg32ATo16. 
466  */
467 static  int     MCI_MsgMapper32To16_Destroy(void* ptr, int size, BOOLEAN kept)
468 {
469     if (ptr) {
470         void*   msg16 = PTR_SEG_TO_LIN(ptr);
471         void*   alloc;
472
473         if (kept) {
474             alloc = (char*)msg16 - sizeof(void**);
475             memcpy(*(void**)alloc, msg16, size);
476         } else {
477             alloc = msg16;
478         }
479
480         if (!SEGPTR_FREE(alloc)) {
481             FIXME(mci, "bad free\n");
482         } 
483     }   
484     return 0;
485 }
486
487 /**************************************************************************
488  *                      MCI_MapMsg32ATo16                       [internal]
489  *
490  * Map a 32-A bit MCI message to a 16 bit MCI message.
491  *  1 : ok, some memory allocated, need to call MCI_UnMapMsg32ATo16
492  *  0 : ok, no memory allocated
493  * -1 : ko, unknown message
494  * -2 : ko, memory problem
495  */
496 int     MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam)
497 {
498     int         size;
499     BOOLEAN     keep = FALSE;
500
501     if (*lParam == 0)
502         return 0;
503     /* FIXME: to add also (with seg/linear modifications to do):
504      * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE
505      * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO
506      */
507     switch (wMsg) {
508         /* case MCI_BREAK: */
509         /* case MCI_CAPTURE */
510     case MCI_CLOSE:
511     case MCI_CLOSE_DRIVER:      
512         size = sizeof(MCI_GENERIC_PARMS);       
513         break;
514         /* case MCI_CONFIGURE:*/
515         /* case MCI_COPY: */
516     case MCI_CUE:
517         switch (uDevType) {
518         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_CUE_PARMS);       break;
519         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_CUE_PARMS);     break;*/        FIXME(mci, "NIY vcr\n");        return -2;
520         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
521         }
522         break;
523         /* case MCI_CUT:*/
524     case MCI_DELETE:
525         switch (uDevType) {
526         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_DELETE_PARMS);    FIXME(mci, "NIY rect\n");       return -2;
527         case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_DELETE_PARMS);   break;
528         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
529         }
530         break;
531         /* case MCI_ESCAPE: */
532     case MCI_FREEZE:
533         switch (uDevType) {
534         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_FREEZE_PARMS);    FIXME(mci, "NIY rect\n");       return -2;
535         case MCI_DEVTYPE_OVERLAY:       /*size = sizeof(MCI_OVLY_FREEZE_PARMS); FIXME(mci, "NIY rect\n");       return -2;*/
536                                         FIXME(mci, "NIY ovly\n");       return -2;
537         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
538         }
539         break;
540     case MCI_GETDEVCAPS:
541         keep = TRUE;
542         size = sizeof(MCI_GETDEVCAPS_PARMS);
543         break;
544         /* case MCI_INDEX: */
545     case MCI_INFO:
546         {
547             LPMCI_INFO_PARMSA   mip32a = (LPMCI_INFO_PARMSA)(*lParam);
548             char*               ptr;
549             LPMCI_INFO_PARMS16  mip16;
550             
551             switch (uDevType) {
552             case MCI_DEVTYPE_DIGITAL_VIDEO:     size = sizeof(MCI_DGV_INFO_PARMS16);    break;
553             default:                            size = sizeof(MCI_INFO_PARMS16);        break;
554             }
555             ptr = SEGPTR_ALLOC(sizeof(LPMCI_INFO_PARMSA) + size);
556
557             if (ptr) {
558                 *(LPMCI_INFO_PARMSA*)ptr = mip32a;
559                 mip16 = (LPMCI_INFO_PARMS16)(ptr + sizeof(LPMCI_INFO_PARMSA));
560                 mip16->dwCallback  = mip32a->dwCallback;
561                 mip16->lpstrReturn = (LPSTR)SEGPTR_GET(SEGPTR_ALLOC(mip32a->dwRetSize));
562                 mip16->dwRetSize   = mip32a->dwRetSize;
563                 if (uDevType == MCI_DEVTYPE_DIGITAL_VIDEO) {
564                     ((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSA)mip32a)->dwItem;
565                 }
566             } else {
567                 return -2;
568             }
569             *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_INFO_PARMSA);
570         }
571         return 1;
572         /* case MCI_MARK: */
573         /* case MCI_MONITOR: */
574     case MCI_OPEN:
575     case MCI_OPEN_DRIVER:       
576         {
577             LPMCI_OPEN_PARMSA   mop32a = (LPMCI_OPEN_PARMSA)(*lParam);
578             char*               ptr    = SEGPTR_ALLOC(sizeof(LPMCI_OPEN_PARMSA) + sizeof(MCI_OPEN_PARMS16) + 2 * sizeof(DWORD));
579             LPMCI_OPEN_PARMS16  mop16;
580
581
582             if (ptr) {
583                 *(LPMCI_OPEN_PARMSA*)(ptr) = mop32a;
584                 mop16 = (LPMCI_OPEN_PARMS16)(ptr + sizeof(LPMCI_OPEN_PARMSA));
585                 mop16->dwCallback       = mop32a->dwCallback;
586                 mop16->wDeviceID        = mop32a->wDeviceID;
587                 if (dwFlags & MCI_OPEN_TYPE) {
588                     if (dwFlags & MCI_OPEN_TYPE_ID) {
589                         /* dword "transparent" value */
590                         mop16->lpstrDeviceType = mop32a->lpstrDeviceType;
591                     } else {
592                         /* string */
593                         mop16->lpstrDeviceType = mop32a->lpstrDeviceType ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrDeviceType)) : 0;
594                     }
595                 } else {
596                     /* nuthin' */
597                     mop16->lpstrDeviceType = 0;
598                 }
599                 if (dwFlags & MCI_OPEN_ELEMENT) {
600                     if (dwFlags & MCI_OPEN_ELEMENT_ID) {
601                         mop16->lpstrElementName = mop32a->lpstrElementName;
602                     } else {
603                         mop16->lpstrElementName = mop32a->lpstrElementName ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrElementName)) : 0;
604                     }
605                 } else {
606                     mop16->lpstrElementName = 0;
607                 }
608                 if (dwFlags & MCI_OPEN_ALIAS) {
609                     mop16->lpstrAlias = mop32a->lpstrAlias ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrAlias)) : 0;
610                 } else {
611                     mop16->lpstrAlias = 0;
612                 }
613                 /* copy extended information if any...
614                  * FIXME: this may seg fault if initial structure does not contain them and
615                  * the reads after msip16 fail under LDT limits...
616                  * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and 
617                  * should not take care of extended parameters, and should be used by MCI_Open
618                  * to fetch uDevType. When, this is known, the mapping for sending the 
619                  * MCI_OPEN_DRIVER shall be done depending on uDevType.
620                  */
621                 memcpy(mop16 + 1, mop32a + 1, 2 * sizeof(DWORD));
622             } else {
623                 return -2;
624             }
625             *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_OPEN_PARMSA);
626         }
627         return 1;
628         /* case MCI_PASTE:*/
629     case MCI_PAUSE:
630         size = sizeof(MCI_GENERIC_PARMS);
631         break;
632     case MCI_PLAY:
633         switch (uDevType) {
634         case MCI_DEVTYPE_OVERLAY:       /*size = sizeof(MCI_OVLY_PLAY_PARMS);   break;*/FIXME(mci, "NIY ovly\n");       return -2;
635         default:                        size = sizeof(MCI_PLAY_PARMS);          break;
636         }
637         break;
638     case MCI_PUT:
639         switch (uDevType) {
640         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_PUT_PARMS);       FIXME(mci, "NIY rect\n");       return -2;
641         case MCI_DEVTYPE_OVERLAY:       /*size = sizeof(MCI_OVLY_PUT_PARMS);    FIXME(mci, "NIY rect\n");       return -2;*/
642                                         FIXME(mci, "NIY ovly\n");       return -2;
643         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
644         }
645         break;
646     case MCI_REALIZE:
647         size = sizeof(MCI_GENERIC_PARMS);
648         break;
649     case MCI_RECORD:
650         switch (uDevType) {
651         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECORD_PARMS);    FIXME(mci, "NIY rect\n");       return -2;
652         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_RECORD_PARMS);  break;*/FIXME(mci, "NIY vcr\n");        return -2;
653         default:                        size = sizeof(MCI_RECORD_PARMS);        break;
654         }
655         break;
656     case MCI_RESUME:            
657         size = sizeof(MCI_GENERIC_PARMS);
658         break;
659     case MCI_SEEK:
660         switch (uDevType) {
661         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_SEEK_PARMS);    break;*/FIXME(mci, "NIY vcr\n");        return -2;
662         default:                        size = sizeof(MCI_SEEK_PARMS);          break;
663         }
664         break;
665     case MCI_SET:
666         switch (uDevType) {
667         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SET_PARMS);       break;
668         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_SET_PARMS);     break;*/FIXME(mci, "NIY vcr\n");        return -2;
669         case MCI_DEVTYPE_SEQUENCER:     size = sizeof(MCI_SEQ_SET_PARMS);       break;
670         /* FIXME: normally the 16 and 32 bit structures are byte by byte aligned, 
671          * so not doing anything should work...
672          */
673         case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_SET_PARMS);      break;
674         default:                        size = sizeof(MCI_SET_PARMS);           break;
675         }
676         break;  
677         /* case MCI_SETTIMECODE:*/
678         /* case MCI_SIGNAL:*/
679     case MCI_SPIN:
680         size = sizeof(MCI_SET_PARMS);           
681         break;
682     case MCI_STATUS:
683         keep = TRUE;
684         switch (uDevType) {
685         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16);  FIXME(mci, "NIY lpstrDevice\n");return -2;
686         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_STATUS_PARMS);  break;*/FIXME(mci, "NIY vcr\n");        return -2;
687         default:                        size = sizeof(MCI_STATUS_PARMS);        break;
688         }
689         break;
690     case MCI_STEP:
691         switch (uDevType) {
692         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STEP_PARMS);      break;
693         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_STEP_PARMS);    break;*/FIXME(mci, "NIY vcr\n");        return -2;
694         case MCI_DEVTYPE_VIDEODISC:     size = sizeof(MCI_VD_STEP_PARMS);       break;
695         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
696         }
697         break;  
698     case MCI_STOP:              
699         size = sizeof(MCI_SET_PARMS);           
700         break;
701     case MCI_SYSINFO:
702         {
703             LPMCI_SYSINFO_PARMSA        msip32a = (LPMCI_SYSINFO_PARMSA)(*lParam);
704             char*                       ptr     = SEGPTR_ALLOC(sizeof(LPMCI_SYSINFO_PARMSA) + sizeof(MCI_SYSINFO_PARMS16));
705             LPMCI_SYSINFO_PARMS16       msip16;
706
707             if (ptr) {
708                 *(LPMCI_SYSINFO_PARMSA*)(ptr) = msip32a;
709                 msip16 = (LPMCI_SYSINFO_PARMS16)(ptr + sizeof(LPMCI_SYSINFO_PARMSA));
710
711                 msip16->dwCallback       = msip32a->dwCallback;
712                 msip16->lpstrReturn      = (LPSTR)SEGPTR_GET(SEGPTR_ALLOC(msip32a->dwRetSize));
713                 msip16->dwRetSize        = msip32a->dwRetSize;
714                 msip16->dwNumber         = msip32a->dwNumber;
715                 msip16->wDeviceType      = msip32a->wDeviceType;
716             } else {
717                 return -2;
718             }
719             *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_SYSINFO_PARMSA);
720         }
721         return 1;
722         /* case MCI_UNDO: */
723     case MCI_UNFREEZE:
724         switch (uDevType) {
725         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS);      FIXME(mci, "NIY rect\n");       return -2;
726         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_RECT_PARMS);     FIXME(mci, "NIY rect\n");       return -2;
727         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
728         }
729         break;
730     case MCI_UPDATE:
731         switch (uDevType) {
732         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_UPDATE_PARMS);    FIXME(mci, "NIY rect\n");       return -2;
733         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
734         }
735         break;
736     case MCI_WHERE:
737         switch (uDevType) {
738         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS);      FIXME(mci, "NIY rect\n");       return -2;
739         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_RECT_PARMS);     FIXME(mci, "NIY rect\n");       return -2;
740         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
741         }
742         break;
743     case MCI_WINDOW:
744         switch (uDevType) {
745         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16);  FIXME(mci, "NIY lpstrText\n");  return -2;
746         case MCI_DEVTYPE_OVERLAY:       /*size = sizeof(MCI_OVLY_WINDOW_PARMS); FIXME(mci, "NIY lpstrText\n");  return -2;*/
747                                         FIXME(mci, "NIY ovly\n");       return -2;
748         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
749         }
750         break;
751     case DRV_LOAD:
752     case DRV_ENABLE:
753     case DRV_OPEN:
754     case DRV_CLOSE:
755     case DRV_DISABLE:
756     case DRV_FREE:
757     case DRV_CONFIGURE:
758     case DRV_QUERYCONFIGURE:
759     case DRV_INSTALL:
760     case DRV_REMOVE:
761     case DRV_EXITSESSION:
762     case DRV_EXITAPPLICATION:
763     case DRV_POWER:
764         FIXME(mci, "This is a hack\n");
765         return 0;
766
767     default:
768         WARN(mci, "Don't know how to map msg=%s\n", MCI_CommandToString(wMsg));
769         return -1;
770     }
771     return MCI_MsgMapper32To16_Create((void**)lParam, size, keep);
772 }
773
774 /**************************************************************************
775  *                      MCI_UnMapMsg32ATo16                     [internal]
776  */
777 int     MCI_UnMapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam)
778 {
779     int         size = 0;
780     BOOLEAN     kept = FALSE;   /* there is no need to compute size when kept is FALSE */
781
782     switch (wMsg) {
783         /* case MCI_CAPTURE */
784     case MCI_CLOSE:     
785     case MCI_CLOSE_DRIVER:      
786         break;
787         /* case MCI_CONFIGURE:*/
788         /* case MCI_COPY: */
789     case MCI_CUE:       
790         break;
791         /* case MCI_CUT: */
792     case MCI_DELETE:
793         break;
794         /* case MCI_ESCAPE: */
795     case MCI_FREEZE:
796         break;
797     case MCI_GETDEVCAPS:
798         kept = TRUE;
799         size = sizeof(MCI_GETDEVCAPS_PARMS);
800         break;
801         /* case MCI_INDEX: */
802     case MCI_INFO:
803         {
804             LPMCI_INFO_PARMS16  mip16  = (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(lParam);
805             LPMCI_INFO_PARMSA   mip32a = *(LPMCI_INFO_PARMSA*)((char*)mip16 - sizeof(LPMCI_INFO_PARMSA));
806
807             memcpy(mip32a->lpstrReturn, PTR_SEG_TO_LIN(mip16->lpstrReturn), mip32a->dwRetSize);
808
809             if (!SEGPTR_FREE(PTR_SEG_TO_LIN(mip16->lpstrReturn)))
810                 FIXME(mci, "bad free line=%d\n", __LINE__);
811             if (!SEGPTR_FREE((char*)mip16 - sizeof(LPMCI_INFO_PARMSA)))
812                 FIXME(mci, "bad free line=%d\n", __LINE__);
813         }
814         return 0;
815         /* case MCI_MARK: */
816         /* case MCI_MONITOR: */
817     case MCI_OPEN:
818     case MCI_OPEN_DRIVER:       
819         if (lParam) {
820             LPMCI_OPEN_PARMS16  mop16  = (LPMCI_OPEN_PARMS16)PTR_SEG_TO_LIN(lParam);
821             LPMCI_OPEN_PARMSA   mop32a = *(LPMCI_OPEN_PARMSA*)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA));
822             
823             mop32a->wDeviceID = mop16->wDeviceID;
824             if ((dwFlags & MCI_OPEN_TYPE) && ! 
825                 (dwFlags & MCI_OPEN_TYPE_ID) && 
826                 !SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrDeviceType)))
827                 FIXME(mci, "bad free line=%d\n", __LINE__);
828             if ((dwFlags & MCI_OPEN_ELEMENT) && 
829                 !(dwFlags & MCI_OPEN_ELEMENT_ID) && 
830                 !SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrElementName)))
831                 FIXME(mci, "bad free line=%d\n", __LINE__);
832             if ((dwFlags & MCI_OPEN_ALIAS) && 
833                 !SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrAlias)))
834                 FIXME(mci, "bad free line=%d\n", __LINE__);
835
836             if (!SEGPTR_FREE((LPVOID)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA))))
837                 FIXME(mci, "bad free line=%d\n", __LINE__);
838         }
839         return 0;
840         /* case MCI_PASTE:*/
841     case MCI_PAUSE:
842         break;
843     case MCI_PLAY:              
844         break;
845     case MCI_PUT:
846         break;
847     case MCI_REALIZE:
848         break;
849     case MCI_RECORD:
850         break;
851     case MCI_RESUME:
852         break;
853     case MCI_SEEK:
854         break;
855     case MCI_SET:
856         break;
857         /* case MCI_SETTIMECODE:*/
858         /* case MCI_SIGNAL:*/
859     case MCI_SPIN:
860         break;
861     case MCI_STATUS:
862         kept = TRUE;
863         switch (uDevType) {
864         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16);  FIXME(mci, "NIY lpstrDevice\n");return -2;
865         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_STATUS_PARMS);  break;*/FIXME(mci, "NIY vcr\n");        return -2;
866         default:                        size = sizeof(MCI_STATUS_PARMS);        break;
867         }
868         break;
869     case MCI_STEP:
870         break;
871     case MCI_STOP:
872         break;
873     case MCI_SYSINFO:
874         if (lParam) {
875             LPMCI_SYSINFO_PARMS16       msip16  = (LPMCI_SYSINFO_PARMS16)PTR_SEG_TO_LIN(lParam);
876             LPMCI_SYSINFO_PARMSA        msip32a = *(LPMCI_SYSINFO_PARMSA*)((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA));
877
878             if (msip16) {
879                 msip16->dwCallback       = msip32a->dwCallback;
880                 memcpy(msip32a->lpstrReturn, PTR_SEG_TO_LIN(msip16->lpstrReturn), msip32a->dwRetSize);
881                 if (!SEGPTR_FREE(msip16->lpstrReturn))
882                     FIXME(mci, "bad free line=%d\n", __LINE__);
883
884                 if (!SEGPTR_FREE((LPVOID)(lParam - sizeof(LPMCI_SYSINFO_PARMSA))))
885                     FIXME(mci, "bad free line=%d\n", __LINE__);
886             } else {
887                 return -2;
888             }
889         }
890         return 1;
891         /* case MCI_UNDO: */
892     case MCI_UNFREEZE:
893         break;
894     case MCI_UPDATE:
895         break;
896     case MCI_WHERE:
897         break;
898     case MCI_WINDOW:
899         /* FIXME: see map function */
900         break;
901
902     case DRV_LOAD:
903     case DRV_ENABLE:
904     case DRV_OPEN:
905     case DRV_CLOSE:
906     case DRV_DISABLE:
907     case DRV_FREE:
908     case DRV_CONFIGURE:
909     case DRV_QUERYCONFIGURE:
910     case DRV_INSTALL:
911     case DRV_REMOVE:
912     case DRV_EXITSESSION:
913     case DRV_EXITAPPLICATION:
914     case DRV_POWER:
915         FIXME(mci, "This is a hack\n");
916         return 0;
917     default:
918         FIXME(mci, "Map/Unmap internal error on msg=%s\n", MCI_CommandToString(wMsg));
919         return -1;
920     }
921     return MCI_MsgMapper32To16_Destroy((void*)lParam, size, kept);
922 }
923
924 /**************************************************************************
925  *                      MCI_SendCommand                         [internal]
926  */
927 DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
928 {
929     DWORD               dwRet = MCIERR_DEVICE_NOT_INSTALLED;
930     
931     if (!MCI_DevIDValid(wDevID)) {
932         dwRet = MCIERR_INVALID_DEVICE_ID;
933     } else {
934         MCIPROC         proc = MCI_GetProc(MCI_GetDrv(wDevID)->modp.wType);
935         
936         if (proc) {
937             dwRet = (*proc)(MCI_GetDrv(wDevID)->modp.wDeviceID, 
938                             MCI_GetDrv(wDevID)->hDrv, 
939                             wMsg, dwParam1, dwParam2);
940         } else if (MCI_GetDrv(wDevID)->hDrv) {
941             switch (DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv)) {
942             case WINE_DI_TYPE_16:
943                 {
944                     int                 res;
945                     
946                     switch (res = MCI_MapMsg32ATo16(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam1, &dwParam2)) {
947                     case -1:
948                         TRACE(mci, "Not handled yet (%s)\n", MCI_CommandToString(wMsg));
949                         dwRet = MCIERR_DRIVER_INTERNAL;
950                         break;
951                     case -2:
952                         TRACE(mci, "Problem mapping msg=%s from 16 to 32a\n", MCI_CommandToString(wMsg));
953                         dwRet = MCIERR_OUT_OF_MEMORY;
954                         break;
955                     case 0:
956                     case 1:
957                         dwRet = SendDriverMessage16(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
958                         if (res)
959                             MCI_UnMapMsg32ATo16(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam1, dwParam2);
960                         break;
961                     }
962                 }
963                 break;
964             case WINE_DI_TYPE_32:
965                 dwRet = SendDriverMessage(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
966                 break;
967             default:
968                 WARN(mci, "Unknown driver type=%u\n", DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv));
969                 dwRet = MCIERR_DRIVER_INTERNAL;
970             }
971         } else {
972             WARN(mci, "unknown device type=%04X !\n", MCI_GetDrv(wDevID)->modp.wType);
973         }
974     }
975     return dwRet;
976 }
977
978 /**************************************************************************
979  *                      MCI_Open                                [internal]
980  */
981 DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSA lpParms)
982 {
983     char                strDevTyp[128];
984     UINT16              uDevType = 0;
985     UINT16              wDevID = MCI_FirstDevID();
986     DWORD               dwRet;
987     
988     TRACE(mci, "(%08lX, %p)\n", dwParam, lpParms);
989     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
990     
991     if ((dwParam & ~(MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT|MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_NOTIFY|MCI_WAIT)) != 0) {
992         FIXME(mci, "unsupported yet dwFlags=%08lX\n", 
993               (dwParam & ~(MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT|MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_NOTIFY|MCI_WAIT)));
994     }
995
996     while (MCI_GetDrv(wDevID)->modp.wType != 0) {
997         wDevID = MCI_NextDevID(wDevID);
998         if (!MCI_DevIDValid(wDevID)) {
999             TRACE(mci, "MAXMCIDRIVERS reached !\n");
1000             return MCIERR_OUT_OF_MEMORY;
1001         }
1002     }
1003
1004     TRACE(mci, "wDevID=%04X \n", wDevID);
1005     memcpy(MCI_GetOpenDrv(wDevID), lpParms, sizeof(*lpParms));
1006     
1007     strDevTyp[0] = 0;
1008
1009     if (dwParam & MCI_OPEN_ELEMENT) {
1010         char*   t;
1011         
1012         TRACE(mci, "lpstrElementName='%s'\n", lpParms->lpstrElementName);
1013         t = strrchr(lpParms->lpstrElementName, '.');
1014         if (t) {
1015             GetProfileStringA("mci extensions", t+1, "*", strDevTyp, sizeof(strDevTyp));
1016             if (strcmp(strDevTyp, "*") == 0) {
1017                 TRACE(mci,"No [mci extensions] entry for %s found.\n", t);
1018                 return MCIERR_EXTENSION_NOT_FOUND;
1019             }
1020             TRACE(mci, "Extension %s is mapped to type %s\n", t, strDevTyp);
1021         } else if (GetDriveTypeA(lpParms->lpstrElementName) == DRIVE_CDROM) {
1022             /* FIXME: this will not work if several CDROM drives are installed on the machine */
1023             strcpy(strDevTyp, "CDAUDIO");
1024         } else {
1025             return MCIERR_EXTENSION_NOT_FOUND;
1026         }
1027     }
1028     
1029     if (dwParam & MCI_OPEN_ALIAS) {
1030         TRACE(mci, "Alias='%s' !\n", lpParms->lpstrAlias);
1031         /* FIXME is there any memory leak here ? */
1032         MCI_GetOpenDrv(wDevID)->lpstrAlias = strdup(lpParms->lpstrAlias);
1033         /* mplayer does allocate alias to CDAUDIO */
1034     }
1035     if (dwParam & MCI_OPEN_TYPE) {
1036         if (dwParam & MCI_OPEN_TYPE_ID) {
1037 #if 0
1038             TRACE(mci, "Dev=%08lx!\n", (DWORD)lpParms->lpstrDeviceType);
1039             uDevType = LOWORD((DWORD)lpParms->lpstrDeviceType);
1040             MCI_GetOpenDrv(wDevID)->lpstrDeviceType = lpParms->lpstrDeviceType;
1041 #endif
1042             if (LOWORD((DWORD)lpParms->lpstrDeviceType) != MCI_DEVTYPE_CD_AUDIO) {
1043                 FIXME(mci, "MCI_OPEN_TYPE_ID is no longer properly supported\n");
1044             }
1045         } else {
1046             if (lpParms->lpstrDeviceType == NULL) 
1047                 return MCIERR_NULL_PARAMETER_BLOCK;
1048             TRACE(mci, "Dev='%s' !\n", lpParms->lpstrDeviceType);
1049             /* FIXME is there any memory leak here ? */
1050             MCI_GetOpenDrv(wDevID)->lpstrDeviceType = strdup(lpParms->lpstrDeviceType);
1051             strcpy(strDevTyp, lpParms->lpstrDeviceType);
1052         }
1053     }
1054
1055     if (uDevType == 0 && strDevTyp[0] != 0) {
1056         CharUpperA(strDevTyp);
1057         /* try Wine internal MCI drivers */
1058         uDevType = MCI_GetDevType(strDevTyp);
1059         if (uDevType == 0) { /* Nope, load external */
1060             HDRVR                       hDrv;
1061             MCI_OPEN_DRIVER_PARMSA      modp;
1062             
1063             modp.wDeviceID = wDevID;
1064             modp.lpstrParams = NULL;
1065
1066             /* FIXME: this is a hack... some MCI drivers, while being open, call
1067              * mciSetData, which lookup for non empty slots in MCI table list
1068              * Unfortunatly, open slots are known when wType == 0...
1069              * so use a dummy type, just to keep on going. May be wType == 0 is 
1070              * not the best solution to indicate empty slot in MCI drivers table
1071              */
1072             MCI_GetDrv(wDevID)->modp.wType = MCI_DEVTYPE_CD_AUDIO;
1073             hDrv = OpenDriverA(strDevTyp, "mci", (LPARAM)&modp);
1074
1075             if (!hDrv) {
1076                 FIXME(mci, "Couldn't load driver for type %s.\n", strDevTyp);
1077                 return MCIERR_DEVICE_NOT_INSTALLED;
1078             }                   
1079             uDevType = modp.wType;
1080             MCI_GetDrv(wDevID)->hDrv = hDrv;
1081
1082             TRACE(mci, "Loaded driver %u (%s), type is %d\n", hDrv, strDevTyp, uDevType);
1083         }
1084     } else {
1085         MCI_GetDrv(wDevID)->hDrv = 0;
1086     }
1087
1088     MCI_GetDrv(wDevID)->modp.wType = uDevType;
1089     MCI_GetDrv(wDevID)->modp.wDeviceID = 0;  /* FIXME? for multiple devices */
1090
1091     lpParms->wDeviceID = wDevID;
1092
1093     TRACE(mci, "mcidev=%d, uDevType=%04X wDeviceID=%04X !\n", 
1094           wDevID, uDevType, lpParms->wDeviceID);
1095
1096     dwRet = MCI_SendCommand(wDevID, MCI_OPEN_DRIVER, dwParam, (DWORD)lpParms);
1097     MCI_GetDrv(wDevID)->lpfnYieldProc = 0;
1098     MCI_GetDrv(wDevID)->dwYieldData = 0;
1099     
1100     if (dwRet == 0) {
1101         /* only handled devices fall through */
1102         TRACE(mci, "wDevID = %04X wDeviceID = %d dwRet = %ld\n", wDevID, lpParms->wDeviceID, dwRet);
1103     } else {
1104         TRACE(mci, "failed to open driver (MCI_OPEN_DRIVER msg) [%08lx], closing\n", dwRet);
1105         MCI_GetDrv(wDevID)->modp.wType = 0;
1106     }
1107     if (dwParam & MCI_NOTIFY)
1108         mciDriverNotify16(lpParms->dwCallback, wDevID, dwRet == 0 ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
1109     
1110     return dwRet;
1111 }
1112
1113 /**************************************************************************
1114  *                      MCI_Close                               [internal]
1115  */
1116 DWORD MCI_Close(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
1117 {
1118     DWORD       dwRet;
1119     
1120     TRACE(mci, "(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms);
1121
1122     if (wDevID == MCI_ALL_DEVICE_ID) {
1123         FIXME(mci, "unhandled MCI_ALL_DEVICE_ID\n");
1124         return MCIERR_CANNOT_USE_ALL;
1125     }
1126
1127     dwRet = MCI_SendCommand(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD)lpParms);
1128     if (MCI_GetDrv(wDevID)->hDrv) {
1129 #if 0
1130         CloseDriver(MCI_GetDrv(wDevID)->hDrv, 0, 0);
1131 #endif
1132     }
1133     MCI_GetDrv(wDevID)->modp.wType = 0;
1134     
1135     if (dwParam & MCI_NOTIFY)
1136         mciDriverNotify16(lpParms->dwCallback, wDevID,
1137                           (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
1138     
1139     return dwRet;
1140 }
1141
1142 /**************************************************************************
1143  *                      MCI_WriteString                         [internal]
1144  */
1145 DWORD   MCI_WriteString(LPSTR lpDstStr, DWORD dstSize, LPCSTR lpSrcStr)
1146 {
1147     DWORD       ret;
1148
1149     if (dstSize <= strlen(lpSrcStr)) {
1150         lstrcpynA(lpDstStr, lpSrcStr, dstSize - 1);
1151         ret = MCIERR_PARAM_OVERFLOW;
1152     } else {
1153         strcpy(lpDstStr, lpSrcStr);
1154         ret = 0;
1155     }
1156     return ret;
1157 }
1158
1159 /**************************************************************************
1160  *                      MCI_Sysinfo                             [internal]
1161  */
1162 DWORD MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSA lpParms)
1163 {
1164     DWORD       ret = MCIERR_INVALID_DEVICE_ID;
1165     
1166     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1167     
1168     TRACE(mci, "(%08x, %08lX, %08lX[num=%ld, wDevTyp=%u])\n", 
1169           uDevID, dwFlags, (DWORD)lpParms, lpParms->dwNumber, lpParms->wDeviceType);
1170     
1171     switch (dwFlags & ~MCI_SYSINFO_OPEN) {
1172     case MCI_SYSINFO_QUANTITY:
1173         {
1174             DWORD       cnt = 0;
1175             WORD        i;
1176             
1177             if (lpParms->wDeviceType < MCI_DEVTYPE_FIRST || lpParms->wDeviceType > MCI_DEVTYPE_LAST) {
1178                 if (dwFlags & MCI_SYSINFO_OPEN) {
1179                     TRACE(mci, "MCI_SYSINFO_QUANTITY: # of open MCI drivers\n");
1180                     for (i = 0; i < MAXMCIDRIVERS; i++) {
1181                         if (mciDrv[i].modp.wType != 0) cnt++;
1182                     }
1183                 } else {
1184                     TRACE(mci, "MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n");
1185                     cnt = mciInstalledCount;
1186                 }
1187             } else {
1188                 if (dwFlags & MCI_SYSINFO_OPEN) {
1189                     TRACE(mci, "MCI_SYSINFO_QUANTITY: # of open MCI drivers of type %u\n", lpParms->wDeviceType);
1190                     for (i = 0; i < MAXMCIDRIVERS; i++) {
1191                         if (mciDrv[i].modp.wType == lpParms->wDeviceType) cnt++;
1192                     }
1193                 } else {
1194                     TRACE(mci, "MCI_SYSINFO_QUANTITY: # of installed MCI drivers of type %u\n", lpParms->wDeviceType);
1195                     FIXME(mci, "Don't know how to get # of MCI devices of a given type\n");
1196                     cnt = 1;
1197                 }
1198             }
1199             *(DWORD*)lpParms->lpstrReturn = cnt;
1200         }
1201         TRACE(mci, "(%ld) => '%ld'\n", lpParms->dwNumber, *(DWORD*)lpParms->lpstrReturn);
1202         ret = 0;
1203         break;
1204     case MCI_SYSINFO_INSTALLNAME:
1205         TRACE(mci, "MCI_SYSINFO_INSTALLNAME \n");
1206         if (MCI_DevIDValid(uDevID)) {
1207             LPCSTR      str = MCI_GetDevTypeString(MCI_GetDrv(uDevID)->modp.wType);
1208             ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, str);
1209         } else {
1210             *lpParms->lpstrReturn = 0;
1211             ret = MCIERR_INVALID_DEVICE_ID;
1212         }
1213         TRACE(mci, "(%ld) => '%s'\n", lpParms->dwNumber, lpParms->lpstrReturn);
1214         break;
1215     case MCI_SYSINFO_NAME:
1216         TRACE(mci, "MCI_SYSINFO_NAME\n");
1217         if (dwFlags & MCI_SYSINFO_OPEN) {
1218             FIXME(mci, "Don't handle MCI_SYSINFO_NAME|MCI_SYSINFO_OPEN (yet)\n");
1219             ret = MCIERR_UNRECOGNIZED_COMMAND;
1220         } else if (lpParms->dwNumber > mciInstalledCount) {
1221             ret = MCIERR_OUTOFRANGE;
1222         } else {
1223             DWORD       count = lpParms->dwNumber;
1224             LPSTR       ptr = lpmciInstallNames;
1225
1226             while (--count > 0) ptr += strlen(ptr) + 1;
1227             ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, ptr);
1228         }
1229         TRACE(mci, "(%ld) => '%s'\n", lpParms->dwNumber, lpParms->lpstrReturn);
1230         break;
1231     default:
1232         TRACE(mci, "Unsupported flag value=%08lx\n", dwFlags);
1233         ret = MCIERR_UNRECOGNIZED_COMMAND;
1234     }
1235     return ret;
1236 }
1237
1238 struct SCA {
1239     UINT        wDevID;
1240     UINT        wMsg;
1241     DWORD       dwParam1;
1242     DWORD       dwParam2;
1243     BOOL        allocatedCopy;
1244 };
1245
1246 DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2);
1247
1248 /**************************************************************************
1249  *                              MCI_SCAStarter                  [internal]
1250  */
1251 static DWORD WINAPI MCI_SCAStarter(LPVOID arg)
1252 {
1253     struct SCA* sca = (struct SCA*)arg;
1254     DWORD               ret;
1255
1256     TRACE(mci, "In thread before async command (%08x,%s,%08lx,%08lx)\n",
1257           sca->wDevID, MCI_CommandToString(sca->wMsg), sca->dwParam1, sca->dwParam2);
1258     ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
1259     TRACE(mci, "In thread after async command (%08x,%s,%08lx,%08lx)\n",
1260           sca->wDevID, MCI_CommandToString(sca->wMsg), sca->dwParam1, sca->dwParam2);
1261     if (sca->allocatedCopy)
1262         HeapFree(GetProcessHeap(), 0, (LPVOID)sca->dwParam2);
1263     HeapFree(GetProcessHeap(), 0, sca);
1264     ExitThread(ret);
1265     WARN(mci, "Should not happen ? what's wrong \n");
1266     /* should not go after this point */
1267     return ret;
1268 }
1269
1270 /**************************************************************************
1271  *                              MCI_SendCommandAsync            [internal]
1272  */
1273 DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2, UINT size)
1274 {
1275     struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA));
1276
1277     if (sca == 0)
1278         return MCIERR_OUT_OF_MEMORY;
1279
1280     sca->wDevID   = wDevID;
1281     sca->wMsg     = wMsg;
1282     sca->dwParam1 = dwParam1;
1283     
1284     if (size) {
1285         sca->dwParam2 = (DWORD)HeapAlloc(GetProcessHeap(), 0, size);
1286         if (sca->dwParam2 == 0) {
1287             HeapFree(GetProcessHeap(), 0, sca);
1288             return MCIERR_OUT_OF_MEMORY;
1289         }
1290         sca->allocatedCopy = TRUE;
1291         /* copy structure passed by program in dwParam2 to be sure 
1292          * we can still use it whatever the program does 
1293          */
1294         memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
1295     } else {
1296         sca->dwParam2 = dwParam2;
1297         sca->allocatedCopy = FALSE;
1298     }
1299
1300     if (CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL) == 0) {
1301         WARN(mci, "Couldn't allocate thread for async command handling, sending synchonously\n");
1302         return MCI_SCAStarter(&sca);
1303     }
1304     return 0;
1305 }
1306
1307 /**************************************************************************
1308  *                              MCI_CleanUp                     [internal]
1309  *
1310  * Some MCI commands need to be cleaned-up (when not called from 
1311  * mciSendString), because MCI drivers return extra information for string
1312  * transformation. This function gets read of them.
1313  */
1314 LRESULT         MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2, BOOL bIs32)
1315 {
1316     switch (wMsg) {
1317     case MCI_GETDEVCAPS:
1318         switch (dwRet & 0xFFFF0000ul) {
1319         case 0:
1320             break;
1321         case MCI_RESOURCE_RETURNED:
1322         case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER:
1323         case MCI_COLONIZED3_RETURN:
1324         case MCI_COLONIZED4_RETURN:
1325         case MCI_INTEGER_RETURNED:
1326             {
1327                 LPMCI_GETDEVCAPS_PARMS  lmgp = (LPMCI_GETDEVCAPS_PARMS)(bIs32 ? (void*)dwParam2 : PTR_SEG_TO_LIN(dwParam2));
1328
1329                 dwRet = LOWORD(dwRet);
1330                 TRACE(mci, "Changing %08lx to %08lx\n", lmgp->dwReturn, (DWORD)LOWORD(lmgp->dwReturn));
1331
1332                 lmgp->dwReturn = LOWORD(lmgp->dwReturn);
1333             } 
1334             break;
1335         default:
1336             FIXME(mci, "Unsupported value for hiword (%04x) returned by DriverProc\n", HIWORD(dwRet));
1337         }
1338         break;
1339     case MCI_STATUS:
1340         switch (dwRet & 0xFFFF0000ul) {
1341         case 0:
1342             break;
1343         case MCI_RESOURCE_RETURNED:
1344         case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER:
1345         case MCI_COLONIZED3_RETURN:
1346         case MCI_COLONIZED4_RETURN:
1347         case MCI_INTEGER_RETURNED:
1348             {
1349                 LPMCI_STATUS_PARMS      lsp = (LPMCI_STATUS_PARMS)(bIs32 ? (void*)dwParam2 : PTR_SEG_TO_LIN(dwParam2));
1350
1351                 dwRet = LOWORD(dwRet);
1352                 TRACE(mci, "Changing %08lx to %08lx\n", lsp->dwReturn,(DWORD) LOWORD(lsp->dwReturn));
1353                 lsp->dwReturn = LOWORD(lsp->dwReturn);
1354             }
1355             break;
1356         default:
1357             FIXME(mci, "Unsupported value for hiword (%04x) returned by DriverProc\n", HIWORD(dwRet));
1358         }
1359         break;
1360     default:
1361         break;
1362     }
1363     return dwRet;
1364 }
1365