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