- implementation of RtlReg* (read access), RtlEvent*, RtlSemaphore*,
[wine] / dlls / winmm / 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 <stdlib.h>
10 #include <string.h>
11
12 #include "winbase.h"
13 #include "winuser.h"
14 #include "heap.h"
15 #include "driver.h"
16 #include "winemm.h"
17 #include "selectors.h"
18 #include "digitalv.h"
19 #include "options.h"
20 #include "wine/winbase16.h"
21 #include "debugtools.h"
22
23 DEFAULT_DEBUG_CHANNEL(mci)
24
25 static  int                     MCI_InstalledCount;
26 static  LPSTR                   MCI_lpInstallNames = NULL;
27
28 /* First MCI valid device ID (0 means error) */
29 #define MCI_MAGIC 0x0001
30
31 /**************************************************************************
32  *                              MCI_GetDriver                   [internal]
33  */
34 LPWINE_MCIDRIVER        MCI_GetDriver(UINT16 wDevID) 
35 {
36     LPWINE_MCIDRIVER    wmd = 0;
37     LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
38
39     EnterCriticalSection(&iData->cs);
40     for (wmd = iData->lpMciDrvs; wmd; wmd = wmd->lpNext) {
41         if (wmd->wDeviceID == wDevID)
42             break;
43     }
44     LeaveCriticalSection(&iData->cs);
45     return wmd;
46 }
47
48 /**************************************************************************
49  *                              MCI_GetDriverFromString         [internal]
50  */
51 UINT    MCI_GetDriverFromString(LPCSTR lpstrName)
52 {
53     LPWINE_MCIDRIVER    wmd;
54     LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
55     UINT                ret = 0;
56
57     if (!lpstrName)
58         return 0;
59     
60     if (!lstrcmpiA(lpstrName, "ALL"))
61         return MCI_ALL_DEVICE_ID;
62     
63     EnterCriticalSection(&iData->cs);
64     for (wmd = iData->lpMciDrvs; wmd; wmd = wmd->lpNext) {
65         if (wmd->lpstrElementName && strcmp(wmd->lpstrElementName, lpstrName) == 0) {
66             ret = wmd->wDeviceID;
67             break;
68         }
69         
70         if (wmd->lpstrDeviceType && strcmp(wmd->lpstrDeviceType, lpstrName) == 0) {
71             ret = wmd->wDeviceID;
72             break;
73         }
74         
75         if (wmd->lpstrAlias && strcmp(wmd->lpstrAlias, lpstrName) == 0) {
76             ret = wmd->wDeviceID;
77             break;
78         }
79     }
80     LeaveCriticalSection(&iData->cs);
81     
82     return ret;
83 }
84
85 /**************************************************************************
86  *                      MCI_MessageToString                     [internal]
87  */
88 const char* MCI_MessageToString(UINT16 wMsg)
89 {
90     static char buffer[100];
91     
92 #define CASE(s) case (s): return #s
93     
94     switch (wMsg) {
95         CASE(MCI_BREAK);
96         CASE(MCI_CLOSE);
97         CASE(MCI_CLOSE_DRIVER);
98         CASE(MCI_COPY);
99         CASE(MCI_CUE);
100         CASE(MCI_CUT);
101         CASE(MCI_DELETE);
102         CASE(MCI_ESCAPE);
103         CASE(MCI_FREEZE);
104         CASE(MCI_PAUSE);
105         CASE(MCI_PLAY);
106         CASE(MCI_GETDEVCAPS);
107         CASE(MCI_INFO);
108         CASE(MCI_LOAD);
109         CASE(MCI_OPEN);
110         CASE(MCI_OPEN_DRIVER);
111         CASE(MCI_PASTE);
112         CASE(MCI_PUT);
113         CASE(MCI_REALIZE);
114         CASE(MCI_RECORD);
115         CASE(MCI_RESUME);
116         CASE(MCI_SAVE);
117         CASE(MCI_SEEK);
118         CASE(MCI_SET);
119         CASE(MCI_SPIN);
120         CASE(MCI_STATUS);
121         CASE(MCI_STEP);
122         CASE(MCI_STOP);
123         CASE(MCI_SYSINFO);
124         CASE(MCI_UNFREEZE);
125         CASE(MCI_UPDATE);
126         CASE(MCI_WHERE);
127         CASE(MCI_WINDOW);
128         /* constants for digital video */
129         CASE(MCI_CAPTURE);
130         CASE(MCI_MONITOR);
131         CASE(MCI_RESERVE);
132         CASE(MCI_SETAUDIO);
133         CASE(MCI_SIGNAL);
134         CASE(MCI_SETVIDEO);
135         CASE(MCI_QUALITY);
136         CASE(MCI_LIST);
137         CASE(MCI_UNDO);
138         CASE(MCI_CONFIGURE);
139         CASE(MCI_RESTORE);
140 #undef CASE
141     default:
142         sprintf(buffer, "MCI_<<%04X>>", wMsg);
143         return buffer;
144     }
145 }
146
147 /**************************************************************************
148  *                              MCI_GetDevTypeFromFileName      [internal]
149  */
150 static  DWORD   MCI_GetDevTypeFromFileName(LPCSTR fileName, LPSTR buf, UINT len)
151 {
152     LPSTR       tmp;
153
154     if ((tmp = strrchr(fileName, '.'))) {
155         GetProfileStringA("mci extensions", tmp + 1, "*", buf, len);
156         if (strcmp(buf, "*") != 0) {
157             return 0;
158         }
159         TRACE("No [mci extensions] entry for '%s' found.\n", tmp);
160     }
161     return MCIERR_EXTENSION_NOT_FOUND;
162 }
163
164 #define MAX_MCICMDTABLE                 20
165 #define MCI_COMMAND_TABLE_NOT_LOADED    0xFFFE
166
167 typedef struct tagWINE_MCICMDTABLE {
168     HANDLE              hMem;
169     UINT                uDevType;
170     LPCSTR              lpTable;
171     UINT                nVerbs;         /* number of verbs in command table */
172     LPCSTR*             aVerbs;         /* array of verbs to speed up the verb look up process */
173 } WINE_MCICMDTABLE, *LPWINE_MCICMDTABLE;
174 WINE_MCICMDTABLE        S_MciCmdTable[MAX_MCICMDTABLE];
175
176 /**************************************************************************
177  *                              MCI_IsCommandTableValid         [internal]
178  */
179 static  BOOL            MCI_IsCommandTableValid(UINT uTbl)
180 {
181     LPCSTR      lmem, str;
182     DWORD       flg;
183     WORD        eid;
184     int         idx = 0;
185     BOOL        inCst = FALSE;
186
187     TRACE("Dumping cmdTbl=%d [hMem=%08x devType=%d]\n", 
188           uTbl, S_MciCmdTable[uTbl].hMem, S_MciCmdTable[uTbl].uDevType);
189
190     if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].hMem || !S_MciCmdTable[uTbl].lpTable) 
191         return FALSE;
192
193     lmem = S_MciCmdTable[uTbl].lpTable;
194     do {
195         do {
196             str = lmem;
197             lmem += strlen(lmem) + 1;
198             flg = *(LPDWORD)lmem;
199             eid = *(LPWORD)(lmem + sizeof(DWORD));
200             lmem += sizeof(DWORD) + sizeof(WORD);
201             idx ++;
202             /* EPP          TRACE("cmd='%s' %08lx %04x\n", str, flg, eid); */
203             switch (eid) {
204             case MCI_COMMAND_HEAD:      if (!*str || !flg) return FALSE; idx = 0;                       break;  /* check unicity of str in table */
205             case MCI_STRING:            if (inCst) return FALSE;                                        break;
206             case MCI_INTEGER:           if (!*str) return FALSE;                                        break;
207             case MCI_END_COMMAND:       if (*str || flg || idx == 0) return FALSE; idx = 0;             break;
208             case MCI_RETURN:            if (*str || idx != 1) return FALSE;                             break;
209             case MCI_FLAG:              if (!*str) return FALSE;                                        break;
210             case MCI_END_COMMAND_LIST:  if (*str || flg) return FALSE;  idx = 0;                        break;
211             case MCI_RECT:              if (!*str || inCst) return FALSE;                               break;
212             case MCI_CONSTANT:          if (inCst) return FALSE; inCst = TRUE;                          break;
213             case MCI_END_CONSTANT:      if (*str || flg || !inCst) return FALSE; inCst = FALSE;         break;
214             default:                    return FALSE;
215             }
216         } while (eid != MCI_END_COMMAND_LIST);
217     } while (eid != MCI_END_COMMAND_LIST);
218     return TRUE;
219 }
220
221 /**************************************************************************
222  *                              MCI_DumpCommandTable            [internal]
223  */
224 static  BOOL            MCI_DumpCommandTable(UINT uTbl)
225 {
226     LPCSTR      lmem;
227     LPCSTR      str;
228     DWORD       flg;
229     WORD        eid;
230     
231     if (!MCI_IsCommandTableValid(uTbl)) {
232         ERR("Ooops: %d is not valid\n", uTbl);
233         return FALSE;
234     }
235
236     lmem = S_MciCmdTable[uTbl].lpTable;
237     do {
238         do {
239             str = lmem;
240             lmem += strlen(lmem) + 1;
241             flg = *(LPDWORD)lmem;
242             eid = *(LPWORD)(lmem + sizeof(DWORD));
243             TRACE("cmd='%s' %08lx %04x\n", str, flg, eid);
244             lmem += sizeof(DWORD) + sizeof(WORD);
245         } while (eid != MCI_END_COMMAND && eid != MCI_END_COMMAND_LIST);
246         TRACE(" => end of command%s\n", (eid == MCI_END_COMMAND_LIST) ? " list" : "");
247     } while (eid != MCI_END_COMMAND_LIST);
248     return TRUE;
249 }
250
251 static  UINT            MCI_SetCommandTable(LPWINE_MM_IDATA iData, HANDLE hMem, UINT uDevType);
252
253 /**************************************************************************
254  *                              MCI_GetCommandTable             [internal]
255  */
256 static  UINT            MCI_GetCommandTable(LPWINE_MM_IDATA iData, UINT uDevType)
257 {
258     UINT        uTbl;
259     char        buf[32];
260     LPSTR       str = NULL;
261     
262     /* first look up existing for existing devType */
263     for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) {
264         if (S_MciCmdTable[uTbl].hMem && S_MciCmdTable[uTbl].uDevType == uDevType)
265             return uTbl;        
266     }
267
268     /* well try to load id */
269     if (uDevType >= MCI_DEVTYPE_FIRST && uDevType <= MCI_DEVTYPE_LAST) {
270         if (LoadStringA(iData->hWinMM32Instance, uDevType, buf, sizeof(buf))) {
271             str = buf;
272         }
273     } else if (uDevType == 0) {
274         str = "CORE";
275     }
276     uTbl = MCI_NO_COMMAND_TABLE;
277     if (str) {
278         HRSRC   hRsrc = FindResourceA(iData->hWinMM32Instance, str, (LPCSTR)RT_RCDATAA);
279         HANDLE  hMem = 0;
280
281         if (hRsrc) hMem = LoadResource(iData->hWinMM32Instance, hRsrc);
282         if (hMem) {
283             uTbl = MCI_SetCommandTable(iData, hMem, uDevType);
284         } else {
285             WARN("No command table found in resource %04x[%s]\n", 
286                  iData->hWinMM32Instance, str);
287         }
288     }
289     TRACE("=> %d\n", uTbl);
290     return uTbl;
291 }
292
293 /**************************************************************************
294  *                              MCI_SetCommandTable             [internal]
295  */
296 static  UINT            MCI_SetCommandTable(LPWINE_MM_IDATA iData, HANDLE hMem, 
297                                             UINT uDevType)
298 {    
299     int                 uTbl;
300     static      BOOL    bInitDone = FALSE;
301
302     /* <HACK>
303      * The CORE command table must be loaded first, so that MCI_GetCommandTable()
304      * can be called with 0 as a uDevType to retrieve it.
305      * </HACK>
306      */
307     if (!bInitDone) {
308         bInitDone = TRUE;
309         for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) {
310             S_MciCmdTable[uTbl].hMem = 0;
311         }
312         MCI_GetCommandTable(iData, 0);
313     }
314
315     for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) {
316         if (S_MciCmdTable[uTbl].hMem == 0) {
317             LPCSTR      lmem, str;
318             WORD        eid;
319             WORD        count;
320
321             S_MciCmdTable[uTbl].hMem = hMem;
322             S_MciCmdTable[uTbl].uDevType = uDevType;
323             S_MciCmdTable[uTbl].lpTable = LockResource(hMem);
324
325             if (TRACE_ON(mci)) {
326                 MCI_DumpCommandTable(uTbl);
327             }
328
329             /* create the verbs table */
330             /* get # of entries */
331             lmem = S_MciCmdTable[uTbl].lpTable;
332             count = 0;
333             do {
334                 lmem += strlen(lmem) + 1;
335                 eid = *(LPWORD)(lmem + sizeof(DWORD));
336                 lmem += sizeof(DWORD) + sizeof(WORD);
337                 if (eid == MCI_COMMAND_HEAD)
338                     count++;
339             } while (eid != MCI_END_COMMAND_LIST);
340
341             S_MciCmdTable[uTbl].aVerbs = HeapAlloc(SystemHeap, 0, count * sizeof(LPCSTR));
342             S_MciCmdTable[uTbl].nVerbs = count;
343
344             lmem = S_MciCmdTable[uTbl].lpTable;
345             count = 0;
346             do {
347                 str = lmem;
348                 lmem += strlen(lmem) + 1;
349                 eid = *(LPWORD)(lmem + sizeof(DWORD));
350                 lmem += sizeof(DWORD) + sizeof(WORD);
351                 if (eid == MCI_COMMAND_HEAD)
352                     S_MciCmdTable[uTbl].aVerbs[count++] = str;
353             } while (eid != MCI_END_COMMAND_LIST);
354             /* assert(count == S_MciCmdTable[uTbl].nVerbs); */
355             return uTbl;
356         }
357     }
358
359     return MCI_NO_COMMAND_TABLE;
360 }
361
362 /**************************************************************************
363  *                              MCI_DeleteCommandTable          [internal]
364  */
365 static  BOOL    MCI_DeleteCommandTable(UINT uTbl)
366 {
367     if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].hMem)
368         return FALSE;
369
370     FreeResource16(S_MciCmdTable[uTbl].hMem);
371     S_MciCmdTable[uTbl].hMem = 0;
372     if (S_MciCmdTable[uTbl].aVerbs) {
373         HeapFree(SystemHeap, 0, S_MciCmdTable[uTbl].aVerbs);
374         S_MciCmdTable[uTbl].aVerbs = 0;
375     }
376     return TRUE;
377 }
378
379 /**************************************************************************
380  *                              MCI_UnLoadMciDriver             [internal]
381  */
382 static  BOOL    MCI_UnLoadMciDriver(LPWINE_MM_IDATA iData, LPWINE_MCIDRIVER wmd)
383 {
384     LPWINE_MCIDRIVER*           tmp;
385
386     if (!wmd)
387         return TRUE;
388
389     if (wmd->hDrv) 
390         CloseDriver(wmd->hDrv, 0, 0);
391
392     if (wmd->dwPrivate != 0)
393         WARN("Unloading mci driver with non nul dwPrivate field\n");
394
395     EnterCriticalSection(&iData->cs);
396     for (tmp = &iData->lpMciDrvs; *tmp; tmp = &(*tmp)->lpNext) {
397         if (*tmp == wmd) {
398             *tmp = wmd->lpNext;
399             break;
400         }
401     }
402     LeaveCriticalSection(&iData->cs);
403
404     HeapFree(GetProcessHeap(), 0, wmd->lpstrDeviceType);
405     HeapFree(GetProcessHeap(), 0, wmd->lpstrAlias);
406     HeapFree(GetProcessHeap(), 0, wmd->lpstrElementName);
407
408     HeapFree(GetProcessHeap(), 0, wmd);
409     return TRUE;
410 }
411
412 /**************************************************************************
413  *                              MCI_LoadMciDriver               [internal]
414  */
415 static  DWORD   MCI_LoadMciDriver(LPWINE_MM_IDATA iData, LPCSTR _strDevTyp, 
416                                   LPWINE_MCIDRIVER* lpwmd)
417 {
418     LPSTR                       strDevTyp = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, _strDevTyp));
419     LPWINE_MCIDRIVER            wmd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmd));
420     MCI_OPEN_DRIVER_PARMSA      modp;
421     DWORD                       dwRet = 0;
422     HDRVR                       hDrv = 0;
423
424     if (!wmd || !strDevTyp) {
425         dwRet = MCIERR_OUT_OF_MEMORY;
426         goto errCleanUp;
427     }
428
429     EnterCriticalSection(&iData->cs);
430     /* wmd must be inserted in list before sending opening the driver, coz' it
431      * may want to lookup at wDevID
432      */
433     wmd->lpNext = iData->lpMciDrvs;
434     iData->lpMciDrvs = wmd;
435
436     for (modp.wDeviceID = MCI_MAGIC; 
437          MCI_GetDriver(modp.wDeviceID) != 0; 
438          modp.wDeviceID++);
439
440     wmd->wDeviceID = modp.wDeviceID;
441     wmd->lpfnYieldProc = MCI_DefYieldProc;
442     wmd->dwYieldData = VK_CANCEL;
443     wmd->hCreatorTask = GetCurrentTask();
444
445     LeaveCriticalSection(&iData->cs);
446
447     TRACE("wDevID=%04X \n", modp.wDeviceID);
448
449     modp.lpstrParams = NULL;
450     
451     hDrv = OpenDriverA(strDevTyp, "mci", (LPARAM)&modp);
452     
453     if (!hDrv) {
454         FIXME("Couldn't load driver for type %s.\n"
455               "If you don't have a windows installation accessible from Wine,\n"
456               "you perhaps forgot to create a [mci] section in system.ini\n",
457               strDevTyp);
458         dwRet = MCIERR_DEVICE_NOT_INSTALLED;
459         goto errCleanUp;
460     }                           
461
462     /* FIXME: should also check that module's description is of the form
463      * MODULENAME:[MCI] comment
464      */
465
466     wmd->hDrv = hDrv;
467     /* some drivers will return 0x0000FFFF, some others 0xFFFFFFFF */
468     wmd->uSpecificCmdTable = LOWORD(modp.wCustomCommandTable);
469     wmd->uTypeCmdTable = MCI_COMMAND_TABLE_NOT_LOADED;
470
471     TRACE("Loaded driver %x (%s), type is %d, cmdTable=%08x\n", 
472           hDrv, strDevTyp, modp.wType, modp.wCustomCommandTable);
473     
474     wmd->lpstrDeviceType = strDevTyp;
475     wmd->wType = modp.wType;
476
477     TRACE("mcidev=%d, uDevTyp=%04X wDeviceID=%04X !\n", 
478           modp.wDeviceID, modp.wType, modp.wDeviceID);
479     *lpwmd = wmd;
480     return 0;
481 errCleanUp:
482     MCI_UnLoadMciDriver(iData, wmd);
483     HeapFree(GetProcessHeap(), 0, strDevTyp);
484     *lpwmd = 0;
485     return dwRet;
486 }
487     
488 /**************************************************************************
489  *                      MCI_FinishOpen                          [internal]
490  */
491 static  DWORD   MCI_FinishOpen(LPWINE_MCIDRIVER wmd, LPMCI_OPEN_PARMSA lpParms, 
492                                DWORD dwParam)
493 {
494     if (dwParam & MCI_OPEN_ELEMENT)
495         wmd->lpstrElementName = HEAP_strdupA(GetProcessHeap(), 0, 
496                                              lpParms->lpstrElementName);
497
498     if (dwParam & MCI_OPEN_ALIAS)
499         wmd->lpstrAlias = HEAP_strdupA(GetProcessHeap(), 0, lpParms->lpstrAlias);
500
501     lpParms->wDeviceID = wmd->wDeviceID;
502
503     return MCI_SendCommandFrom32(wmd->wDeviceID, MCI_OPEN_DRIVER, dwParam, 
504                                  (DWORD)lpParms);
505 }
506
507 /**************************************************************************
508  *                              MCI_FindCommand         [internal]
509  */
510 static  LPCSTR          MCI_FindCommand(UINT uTbl, LPCSTR verb)
511 {
512     UINT        idx;
513
514     if (uTbl >= MAX_MCICMDTABLE || S_MciCmdTable[uTbl].hMem == 0)
515         return NULL;
516
517     /* another improvement would be to have the aVerbs array sorted,
518      * so that we could use a dichotomic search on it, rather than this dumb
519      * array look up
520      */
521     for (idx = 0; idx < S_MciCmdTable[uTbl].nVerbs; idx++) {
522         if (strcmp(S_MciCmdTable[uTbl].aVerbs[idx], verb) == 0)
523             return S_MciCmdTable[uTbl].aVerbs[idx];
524     }
525
526     return NULL;
527 }
528
529 /**************************************************************************
530  *                              MCI_GetReturnType               [internal]
531  */
532 static  DWORD           MCI_GetReturnType(LPCSTR lpCmd)
533 {
534     lpCmd += strlen(lpCmd) + 1 + sizeof(DWORD) + sizeof(WORD);
535     if (*lpCmd == '\0' && *(LPWORD)(lpCmd + 1 + sizeof(DWORD)) == MCI_RETURN) {
536         return *(LPDWORD)(lpCmd + 1);
537     }
538     return 0L;
539 }
540
541 /**************************************************************************
542  *                              MCI_GetMessage                  [internal]
543  */
544 static  WORD            MCI_GetMessage(LPCSTR lpCmd)
545 {
546     return (WORD)*(LPDWORD)(lpCmd + strlen(lpCmd) + 1);
547 }
548
549 /**************************************************************************
550  *                              MCI_GetDWord                    [internal]
551  */
552 static  BOOL            MCI_GetDWord(LPDWORD data, LPSTR* ptr)
553 {
554     DWORD       val;
555     LPSTR       ret;
556
557     val = strtoul(*ptr, &ret, 0);
558
559     switch (*ret) {
560     case '\0':  break;
561     case ' ':   ret++; break;
562     default:    return FALSE;
563     }
564
565     *data |= val;
566     *ptr = ret;
567     return TRUE;
568 }
569
570 /**************************************************************************
571  *                              MCI_GetString           [internal]
572  */
573 static  DWORD   MCI_GetString(LPSTR* str, LPSTR* args)
574 {
575     LPSTR       ptr = *args;
576
577     /* see if we have a quoted string */
578     if (*ptr == '"') {
579         ptr = strchr(*str = ptr + 1, '"');
580         if (!ptr) return MCIERR_NO_CLOSING_QUOTE;
581         /* FIXME: shall we escape \" from string ?? */
582         if (ptr[-1] == '\\') TRACE("Ooops: un-escaped \"\n");
583         *ptr++ = '\0'; /* remove trailing " */
584         if (*ptr != ' ' && *ptr != '\0') return MCIERR_EXTRA_CHARACTERS;
585         *ptr++ = '\0';
586     } else {
587         ptr = strchr(ptr, ' ');
588
589         if (ptr) {
590             *ptr++ = '\0';
591         } else {
592             ptr = *args + strlen(*args);
593         }
594         *str = *args;
595     }
596
597     *args = ptr;
598     return 0;
599 }
600
601 #define MCI_DATA_SIZE   16
602
603 /**************************************************************************
604  *                              MCI_ParseOptArgs                [internal]
605  */
606 static  DWORD   MCI_ParseOptArgs(LPDWORD data, int _offset, LPCSTR lpCmd, 
607                                     LPSTR args, LPDWORD dwFlags)
608 {
609     int         len, offset;
610     LPCSTR      lmem, str;
611     DWORD       dwRet, flg, cflg = 0;
612     WORD        eid;
613     BOOL        inCst, found;
614
615     /* loop on arguments */
616     while (*args) {
617         lmem = lpCmd;
618         found = inCst = FALSE;
619         offset = _offset;
620         TRACE("args='%s' offset=%d\n", args, offset);
621             
622         do { /* loop on options for command table for the requested verb */
623             str = lmem;
624             lmem += (len = strlen(lmem)) + 1;
625             flg = *(LPDWORD)lmem;
626             eid = *(LPWORD)(lmem + sizeof(DWORD));
627             lmem += sizeof(DWORD) + sizeof(WORD);
628 /* EPP      TRACE("\tcmd='%s' inCst=%s\n", str, inCst ? "Y" : "N"); */
629             
630             switch (eid) {
631             case MCI_CONSTANT:          
632                 inCst = TRUE;   cflg = flg;     break;
633             case MCI_END_CONSTANT:      
634                 /* there may be additional integral values after flag in constant */
635                 if (inCst && MCI_GetDWord(&(data[offset]), &args)) {
636                     *dwFlags |= cflg;
637                 }
638                 inCst = FALSE;  cflg = 0;       
639                 break;
640             }
641
642             if (strncasecmp(args, str, len) == 0 && 
643                 (args[len] == 0 || args[len] == ' ')) {
644                 /* store good values into data[] */
645                 args += len;
646                 if (*args == ' ') args++;
647                 found = TRUE;
648
649                 switch (eid) {
650                 case MCI_COMMAND_HEAD:
651                 case MCI_RETURN:
652                 case MCI_END_COMMAND:
653                 case MCI_END_COMMAND_LIST:
654                 case MCI_CONSTANT:      /* done above */
655                 case MCI_END_CONSTANT:  /* done above */
656                     break;
657                 case MCI_FLAG:                  
658                     *dwFlags |= flg;
659                     break;
660                 case MCI_INTEGER:
661                     if (inCst) {
662                         data[offset] |= flg;
663                         *dwFlags |= cflg;
664                         inCst = FALSE;
665                     } else {
666                         *dwFlags |= flg;
667                         if (!MCI_GetDWord(&(data[offset]), &args)) {
668                             return MCIERR_BAD_INTEGER;
669                         }
670                     }
671                     break;
672                 case MCI_RECT:                  
673                     /* store rect in data (offset...offset+3) */
674                     *dwFlags |= flg;
675                     if (!MCI_GetDWord(&(data[offset+0]), &args) ||
676                         !MCI_GetDWord(&(data[offset+1]), &args) ||
677                         !MCI_GetDWord(&(data[offset+2]), &args) ||
678                         !MCI_GetDWord(&(data[offset+3]), &args)) {
679                         ERR("Bad rect '%s'\n", args);
680                         return MCIERR_BAD_INTEGER;
681                     }
682                     break;
683                 case MCI_STRING:
684                     *dwFlags |= flg;
685                     if ((dwRet = MCI_GetString((LPSTR*)&data[offset], &args)))
686                         return dwRet;
687                     break;
688                 default:        ERR("oops");
689                 }
690                 /* exit inside while loop */
691                 eid = MCI_END_COMMAND;
692             } else {
693                 /* have offset incremented if needed */
694                 switch (eid) {
695                 case MCI_COMMAND_HEAD:
696                 case MCI_RETURN:
697                 case MCI_END_COMMAND:
698                 case MCI_END_COMMAND_LIST:
699                 case MCI_CONSTANT:
700                 case MCI_FLAG:                  break;
701                 case MCI_INTEGER:               if (!inCst) offset++;   break;
702                 case MCI_END_CONSTANT:          
703                 case MCI_STRING:                offset++; break;
704                 case MCI_RECT:                  offset += 4; break;
705                 default:                        ERR("oops");
706                 }
707             }
708         } while (eid != MCI_END_COMMAND);
709         if (!found) {
710             TRACE("Optarg '%s' not found\n", args);
711             return MCIERR_UNRECOGNIZED_COMMAND;
712         }
713         if (offset == MCI_DATA_SIZE) {
714             ERR("Internal data[] buffer overflow\n");
715             return MCIERR_PARSER_INTERNAL;
716         }
717     }
718     return 0;
719 }
720
721 /**************************************************************************
722  *                              MCI_HandleReturnValues  [internal]
723  */
724 static  DWORD   MCI_HandleReturnValues(LPWINE_MM_IDATA iData, DWORD dwRet, 
725                                        LPWINE_MCIDRIVER wmd, LPCSTR lpCmd, LPDWORD data, 
726                                        LPSTR lpstrRet, UINT uRetLen)
727 {
728     if (lpstrRet) {
729         switch (MCI_GetReturnType(lpCmd)) {
730         case 0: /* nothing to return */
731             break;
732         case MCI_INTEGER:       
733             switch (dwRet & 0xFFFF0000ul) {
734             case 0:
735             case MCI_INTEGER_RETURNED:
736                 wsnprintfA(lpstrRet, uRetLen, "%ld", data[1]);
737                 break;
738             case MCI_RESOURCE_RETURNED:
739                 /* return string which ID is HIWORD(data[1]), 
740                  * string is loaded from mmsystem.dll */
741                 LoadStringA(iData->hWinMM32Instance, HIWORD(data[1]), 
742                             lpstrRet, uRetLen);
743                 break;
744             case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER:
745                 /* return string which ID is HIWORD(data[1]), 
746                  * string is loaded from driver */
747                 LoadStringA(wmd->hDrv, HIWORD(data[1]), lpstrRet, uRetLen);
748                 break;
749             case MCI_COLONIZED3_RETURN:
750                 wsnprintfA(lpstrRet, uRetLen, "%d:%d:%d", 
751                          LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])), 
752                          LOBYTE(HIWORD(data[1])));
753                 break;
754             case MCI_COLONIZED4_RETURN:
755                 wsnprintfA(lpstrRet, uRetLen, "%d:%d:%d:%d", 
756                          LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])), 
757                          LOBYTE(HIWORD(data[1])), HIBYTE(HIWORD(data[1])));
758                 break;
759             default:    ERR("Ooops (%04X)\n", HIWORD(dwRet));
760             }
761             break;
762         case MCI_STRING:        
763             switch (dwRet & 0xFFFF0000ul) {
764             case 0:
765                 /* nothing to do data[1] == lpstrRet */
766                 break;
767             case MCI_INTEGER_RETURNED:
768                 data[1] = *(LPDWORD)lpstrRet;
769                 wsnprintfA(lpstrRet, uRetLen, "%ld", data[1]);
770                 break;
771             default:
772                 WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet));
773                 break;
774             }
775             break;
776         case MCI_RECT:  
777             if (dwRet & 0xFFFF0000ul)   
778                 WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet));
779             wsnprintfA(lpstrRet, uRetLen, "%ld %ld %ld %ld", 
780                        data[1], data[2], data[3], data[4]);     
781             break;
782         default:                ERR("oops\n");
783         }
784     }
785     return LOWORD(dwRet);
786 }
787
788 /**************************************************************************
789  *                              mciSendStringA          [MMSYSTEM.702][WINMM.51]
790  */
791 DWORD WINAPI mciSendStringA(LPCSTR lpstrCommand, LPSTR lpstrRet, 
792                             UINT uRetLen, HWND hwndCallback)
793 {
794     LPSTR               verb, dev, args;
795     LPWINE_MCIDRIVER    wmd = 0;
796     DWORD               dwFlags = 0, dwRet = 0;
797     int                 offset = 0;
798     DWORD               data[MCI_DATA_SIZE];
799     LPCSTR              lpCmd = 0;
800     LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
801
802     TRACE("('%s', %p, %d, %X)\n", lpstrCommand, lpstrRet, uRetLen, hwndCallback);
803
804     /* format is <command> <device> <optargs> */
805     if (!(verb = HEAP_strdupA(GetProcessHeap(), 0, lpstrCommand)))
806         return MCIERR_OUT_OF_MEMORY;
807
808     memset(data, 0, sizeof(data));
809
810     if (!(args = strchr(verb, ' '))) {
811         dwRet = MCIERR_MISSING_DEVICE_NAME;
812         goto errCleanUp;
813     }
814     *args++ = '\0';
815     if ((dwRet = MCI_GetString(&dev, &args))) {
816         goto errCleanUp;
817     }
818
819     /* case dev == 'new' has to be handled */
820     if (!strcasecmp(dev, "new")) {
821         FIXME("'new': NIY as device name\n");
822         dwRet = MCIERR_MISSING_DEVICE_NAME;
823         goto errCleanUp;
824     }
825
826     /* otherwise, try to grab devType from open */
827     if (!strcmp(verb, "open")) {
828         LPSTR   devType, tmp;
829
830         if ((devType = strchr(dev, '!')) != NULL) {
831             *devType++ = '\0';      
832             tmp = devType; devType = dev; dev = tmp;
833
834             dwFlags |= MCI_OPEN_TYPE;
835             data[2] = (DWORD)devType;
836             devType = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, devType));
837         } else {
838             if ((devType = strstr(args, "type ")) != NULL) {
839                 devType += 5;
840                 tmp = strchr(devType, ' ');
841                 if (tmp) *tmp = '\0';
842                 devType = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, devType));
843                 if (tmp) *tmp = ' ';
844                 /* dwFlags and data[2] will be correctly set in ParseOpt loop */
845             } else {
846                 char    buf[32];
847                 if ((dwRet = MCI_GetDevTypeFromFileName(dev, buf, sizeof(buf))))
848                     goto errCleanUp;
849
850                 devType = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, buf));
851             }
852             dwFlags |= MCI_OPEN_ELEMENT;
853             data[3] = (DWORD)dev;
854         }
855         dwRet = MCI_LoadMciDriver(iData, devType, &wmd);
856         HeapFree(GetProcessHeap(), 0, devType);
857         if (dwRet) {
858             MCI_UnLoadMciDriver(iData, wmd);
859             goto errCleanUp;
860         }
861     } else {
862         wmd = MCI_GetDriver(mciGetDeviceIDA(dev));
863         if (!wmd) {
864             FIXME("Oooch: couldn't find driver for '%s' in '%s'; automatic open is NIY\n", 
865                   dev, lpstrCommand);
866             dwRet = MCIERR_INVALID_DEVICE_ID;
867             goto errCleanUp;
868         }
869     }
870
871     /* get the verb in the different command tables */
872     /* try the device specific command table */
873     if (wmd) lpCmd = MCI_FindCommand(wmd->uSpecificCmdTable, verb);
874     /* try the type specific command table */
875     if (!lpCmd) {
876         if (wmd && wmd->uTypeCmdTable == MCI_COMMAND_TABLE_NOT_LOADED)
877             wmd->uTypeCmdTable = MCI_GetCommandTable(iData, wmd->wType);
878         if (wmd && wmd->uTypeCmdTable != MCI_NO_COMMAND_TABLE)
879             lpCmd = MCI_FindCommand(wmd->uTypeCmdTable, verb);
880     }
881     /* try core command table */
882     if (!lpCmd) lpCmd = MCI_FindCommand(MCI_GetCommandTable(iData, 0), verb);
883
884     if (!lpCmd) {
885         TRACE("Command '%s' not found!\n", verb);
886         dwRet = MCIERR_UNRECOGNIZED_COMMAND;
887         goto errCleanUp;
888     }
889
890     /* set up call back */
891     if (hwndCallback != 0) {
892         dwFlags |= MCI_NOTIFY;
893         data[0] = (DWORD)hwndCallback;
894     }
895
896     /* set return information */
897     switch (MCI_GetReturnType(lpCmd)) {
898     case 0:             offset = 1;     break;
899     case MCI_INTEGER:   offset = 2;     break;
900     case MCI_STRING:    data[1] = (DWORD)lpstrRet; data[2] = uRetLen; offset = 3; break;
901     case MCI_RECT:      offset = 5;     break;
902     default:    ERR("oops\n");
903     }
904
905     TRACE("verb='%s' on dev='%s'; offset=%d\n", verb, dev, offset);
906
907     if ((dwRet = MCI_ParseOptArgs(data, offset, lpCmd, args, &dwFlags)))
908         goto errCleanUp;
909
910     if (lpstrRet && uRetLen) *lpstrRet = '\0';
911
912 #define STR_OF(_x) (((_x)&0xFF000000)?(char*)(_x):"?")
913     TRACE("[%d, %s, %08lx, %08lx/%s %08lx/%s %08lx/%s %08lx/%s %08lx/%s %08lx/%s]\n",
914           wmd->wDeviceID, MCI_MessageToString(MCI_GetMessage(lpCmd)), dwFlags, 
915           data[0], STR_OF(data[0]), data[1], STR_OF(data[1]),
916           data[2], STR_OF(data[2]), data[3], STR_OF(data[3]),
917           data[4], STR_OF(data[4]), data[5], STR_OF(data[5]));
918 #undef STR_OF
919
920     if (strcmp(verb, "open") == 0) {
921         if ((dwRet = MCI_FinishOpen(wmd, (LPMCI_OPEN_PARMSA)data, dwFlags)))
922             MCI_UnLoadMciDriver(iData, wmd);
923         /* FIXME: notification is not properly shared across two opens */
924     } else {
925         dwRet = MCI_SendCommand(wmd->wDeviceID, MCI_GetMessage(lpCmd), dwFlags, (DWORD)data, TRUE);
926     }
927     TRACE("=> 1/ %lx (%s)\n", dwRet, lpstrRet);
928     if (dwRet)  goto errCleanUp;
929     
930     dwRet = MCI_HandleReturnValues(iData, dwRet, wmd, lpCmd, data, lpstrRet, uRetLen);
931     TRACE("=> 2/ %lx (%s)\n", dwRet, lpstrRet);
932
933 errCleanUp:
934     HeapFree(GetProcessHeap(), 0, verb);
935     return dwRet;
936 }
937
938 /**************************************************************************
939  *                              mciSendStringW                  [WINMM.52]
940  */
941 DWORD WINAPI mciSendStringW(LPCWSTR lpwstrCommand, LPSTR lpstrRet, 
942                             UINT uRetLen, HWND hwndCallback)
943 {
944     LPSTR       lpstrCommand;
945     UINT        ret;
946
947     /* FIXME: is there something to do with lpstrReturnString ? */
948     lpstrCommand = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrCommand);
949     ret = mciSendStringA(lpstrCommand, lpstrRet, uRetLen, hwndCallback);
950     HeapFree(GetProcessHeap(), 0, lpstrCommand);
951     return ret;
952 }
953
954 /**************************************************************************
955  *                              mciSendString16                 [MMSYSTEM.702]
956  */
957 DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrRet, 
958                              UINT16 uRetLen, HWND16 hwndCallback)
959 {
960     return mciSendStringA(lpstrCommand, lpstrRet, uRetLen, hwndCallback);
961 }
962
963 /**************************************************************************
964  *                              mciExecute                      [WINMM.38]
965  */
966 DWORD WINAPI mciExecute(LPCSTR lpstrCommand)
967 {
968     char        strRet[256];
969     DWORD       ret;
970
971     TRACE("(%s)!\n", lpstrCommand);
972
973     ret = mciSendString16(lpstrCommand, strRet, sizeof(strRet), 0);
974     if (ret != 0) {
975         if (!mciGetErrorStringA(ret, strRet, sizeof(strRet))) {
976             sprintf(strRet, "Unknown MCI error (%ld)", ret);
977         }
978         MessageBoxA(0, strRet, "Error in mciExecute()", MB_OK); 
979     }
980     /* FIXME: what shall I return ? */
981     return 0;
982 }
983
984 /**************************************************************************
985  *                      mciLoadCommandResource                  [MMSYSTEM.705]
986  */
987 UINT16 WINAPI mciLoadCommandResource16(HANDLE16 hInst, LPCSTR resname, UINT16 type)
988 {
989     HRSRC               hRsrc = 0;
990     HGLOBAL             hMem;
991     UINT16              ret = MCI_NO_COMMAND_TABLE;
992     LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
993
994     TRACE("(%04x, %s, %d)!\n", hInst, resname, type);
995
996     /* if file exists "resname.mci", then load resource "resname" from it
997      * otherwise directly from driver
998      * We don't support it (who uses this feature ?), but we check anyway
999      */
1000     if (!type) {
1001         char            buf[128];
1002         OFSTRUCT        ofs;
1003
1004         strcat(strcpy(buf, resname), ".mci");
1005         if (OpenFile(buf, &ofs, OF_EXIST) != HFILE_ERROR) {
1006             FIXME("NIY: command table to be loaded from '%s'\n", ofs.szPathName);
1007         }
1008     }
1009     if (!(hRsrc = FindResourceA(hInst, resname, (LPCSTR)RT_RCDATAA))) {
1010         WARN("No command table found in resource\n");
1011     } else if ((hMem = LoadResource(hInst, hRsrc))) {
1012         ret = MCI_SetCommandTable(iData, hMem, type);
1013     } else {
1014         WARN("Couldn't load resource.\n");
1015     }
1016     TRACE("=> %04x\n", ret);
1017     return ret;
1018 }
1019
1020 /**************************************************************************
1021  *                      mciFreeCommandResource                  [MMSYSTEM.713]
1022  */
1023 BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable)
1024 {
1025     TRACE("(%04x)!\n", uTable);
1026
1027     return MCI_DeleteCommandTable(uTable);
1028 }
1029  
1030 /**************************************************************************
1031  *                      mciLoadCommandResource                  [WINMM.48]
1032  *
1033  * Strangely, this function only exists as an UNICODE one.
1034  */
1035 UINT WINAPI mciLoadCommandResource(HINSTANCE hinst, LPCWSTR resNameW, UINT type)
1036 {
1037     LPSTR       resNameA;
1038     UINT        ret;
1039
1040     TRACE("(%04x, %s, %d)!\n", hinst, debugstr_w(resNameW), type);
1041
1042     resNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, resNameW);
1043     ret = mciLoadCommandResource16(hinst, resNameA, type);
1044     HeapFree(GetProcessHeap(), 0, resNameA);
1045     return ret;
1046 }
1047
1048 /**************************************************************************
1049  *                      mciFreeCommandResource                  [WINMM.39]
1050  */
1051 BOOL WINAPI mciFreeCommandResource(UINT uTable)
1052 {
1053     TRACE("(%08x)!\n", uTable);
1054
1055     return mciFreeCommandResource16(uTable);
1056 }
1057
1058 typedef enum {
1059     MCI_MAP_NOMEM,      /* ko, memory problem */
1060     MCI_MAP_MSGERROR,   /* ko, unknown message */
1061     MCI_MAP_OK,         /* ok, no memory allocated. to be sent to the proc. */
1062     MCI_MAP_OKMEM,      /* ok, some memory allocated, need to call UnMapMsg. to be sent to the proc. */
1063     MCI_MAP_PASS        /* not handled (no memory allocated) to be sent to the driver */
1064 } MCI_MapType;
1065
1066 /**************************************************************************
1067  *                      MCI_MapMsg16To32A                       [internal]
1068  */
1069 static  MCI_MapType     MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam)
1070 {
1071     if (*lParam == 0)
1072         return MCI_MAP_OK;
1073     /* FIXME: to add also (with seg/linear modifications to do):
1074      * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE
1075      * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO
1076      */
1077     switch (wMsg) {
1078         /* case MCI_CAPTURE */
1079     case MCI_CLOSE:             
1080     case MCI_CLOSE_DRIVER:      
1081         /* case MCI_CONFIGURE:*/
1082     case MCI_COPY:
1083     case MCI_CUE:
1084     case MCI_CUT:
1085     case MCI_DELETE:
1086     case MCI_FREEZE:
1087     case MCI_GETDEVCAPS:
1088         /* case MCI_INDEX: */
1089         /* case MCI_MARK: */
1090         /* case MCI_MONITOR: */
1091     case MCI_PASTE:
1092     case MCI_PAUSE:             
1093     case MCI_PLAY:              
1094     case MCI_PUT:
1095     case MCI_REALIZE:
1096     case MCI_RECORD:            
1097     case MCI_RESUME:            
1098     case MCI_SEEK:              
1099     case MCI_SET:
1100         /* case MCI_SETTIMECODE:*/
1101         /* case MCI_SIGNAL:*/
1102     case MCI_SPIN:
1103     case MCI_STATUS:            /* FIXME: is wrong for digital video */
1104     case MCI_STEP:
1105     case MCI_STOP:              
1106         /* case MCI_UNDO: */
1107     case MCI_UNFREEZE:
1108     case MCI_UPDATE:
1109     case MCI_WHERE:
1110         *lParam = (DWORD)PTR_SEG_TO_LIN(*lParam);
1111         return MCI_MAP_OK;
1112     case MCI_WINDOW:
1113         /* in fact, I would also need the dwFlags... to see 
1114          * which members of lParam are effectively used 
1115          */
1116         *lParam = (DWORD)PTR_SEG_TO_LIN(*lParam);
1117         FIXME("Current mapping may be wrong\n");
1118         break;
1119     case MCI_BREAK:
1120         {
1121             LPMCI_BREAK_PARMS           mbp32 = HeapAlloc(SystemHeap, 0, sizeof(MCI_BREAK_PARMS));
1122             LPMCI_BREAK_PARMS16         mbp16 = PTR_SEG_TO_LIN(*lParam);
1123
1124             if (mbp32) {
1125                 mbp32->dwCallback = mbp16->dwCallback;
1126                 mbp32->nVirtKey = mbp16->nVirtKey;
1127                 mbp32->hwndBreak = mbp16->hwndBreak;
1128             } else {
1129                 return MCI_MAP_NOMEM;
1130             }
1131             *lParam = (DWORD)mbp32;
1132         }
1133         return MCI_MAP_OKMEM;
1134     case MCI_ESCAPE:
1135         {
1136             LPMCI_VD_ESCAPE_PARMSA      mvep32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_VD_ESCAPE_PARMSA));
1137             LPMCI_VD_ESCAPE_PARMS16     mvep16  = PTR_SEG_TO_LIN(*lParam);
1138
1139             if (mvep32a) {
1140                 mvep32a->dwCallback       = mvep16->dwCallback;
1141                 mvep32a->lpstrCommand     = PTR_SEG_TO_LIN(mvep16->lpstrCommand);
1142             } else {
1143                 return MCI_MAP_NOMEM;
1144             }
1145             *lParam = (DWORD)mvep32a;
1146         }
1147         return MCI_MAP_OKMEM;
1148     case MCI_INFO:
1149         {
1150             LPMCI_INFO_PARMSA   mip32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_INFO_PARMSA));
1151             LPMCI_INFO_PARMS16  mip16  = PTR_SEG_TO_LIN(*lParam);
1152
1153             /* FIXME this is wrong if device is of type 
1154              * MCI_DEVTYPE_DIGITAL_VIDEO, some members are not mapped
1155              */
1156             if (mip32a) {
1157                 mip32a->dwCallback  = mip16->dwCallback;
1158                 mip32a->lpstrReturn = PTR_SEG_TO_LIN(mip16->lpstrReturn);
1159                 mip32a->dwRetSize   = mip16->dwRetSize;
1160             } else {
1161                 return MCI_MAP_NOMEM;
1162             }
1163             *lParam = (DWORD)mip32a;
1164         }
1165         return MCI_MAP_OKMEM;
1166     case MCI_OPEN:
1167     case MCI_OPEN_DRIVER:       
1168         {
1169             LPMCI_OPEN_PARMSA   mop32a = HeapAlloc(SystemHeap, 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_OPEN_PARMSA) + 2 * sizeof(DWORD));
1170             LPMCI_OPEN_PARMS16  mop16  = PTR_SEG_TO_LIN(*lParam);
1171
1172             if (mop32a) {
1173                 *(LPMCI_OPEN_PARMS16*)(mop32a) = mop16;
1174                 mop32a = (LPMCI_OPEN_PARMSA)((char*)mop32a + sizeof(LPMCI_OPEN_PARMS16));
1175                 mop32a->dwCallback       = mop16->dwCallback;
1176                 mop32a->wDeviceID        = mop16->wDeviceID;
1177                 mop32a->lpstrDeviceType  = PTR_SEG_TO_LIN(mop16->lpstrDeviceType);
1178                 mop32a->lpstrElementName = PTR_SEG_TO_LIN(mop16->lpstrElementName);
1179                 mop32a->lpstrAlias       = PTR_SEG_TO_LIN(mop16->lpstrAlias);
1180                 /* copy extended information if any...
1181                  * FIXME: this may seg fault if initial structure does not contain them and
1182                  * the reads after msip16 fail under LDT limits...
1183                  * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and 
1184                  * should not take care of extended parameters, and should be used by MCI_Open
1185                  * to fetch uDevType. When, this is known, the mapping for sending the 
1186                  * MCI_OPEN_DRIVER shall be done depending on uDevType.
1187                  */
1188                 memcpy(mop32a + 1, mop16 + 1, 2 * sizeof(DWORD));
1189             } else {
1190                 return MCI_MAP_NOMEM;
1191             }
1192             *lParam = (DWORD)mop32a;
1193         }
1194         return MCI_MAP_OKMEM;
1195     case MCI_SYSINFO:
1196         {
1197             LPMCI_SYSINFO_PARMSA        msip32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_SYSINFO_PARMSA));
1198             LPMCI_SYSINFO_PARMS16       msip16  = PTR_SEG_TO_LIN(*lParam);
1199
1200             if (msip32a) {
1201                 msip32a->dwCallback       = msip16->dwCallback;
1202                 msip32a->lpstrReturn      = PTR_SEG_TO_LIN(msip16->lpstrReturn);
1203                 msip32a->dwRetSize        = msip16->dwRetSize;
1204                 msip32a->dwNumber         = msip16->dwNumber;
1205                 msip32a->wDeviceType      = msip16->wDeviceType;
1206             } else {
1207                 return MCI_MAP_NOMEM;
1208             }
1209             *lParam = (DWORD)msip32a;
1210         }
1211         return MCI_MAP_OKMEM;
1212     case DRV_LOAD:
1213     case DRV_ENABLE:
1214     case DRV_OPEN:
1215     case DRV_CLOSE:
1216     case DRV_DISABLE:
1217     case DRV_FREE:
1218     case DRV_CONFIGURE:
1219     case DRV_QUERYCONFIGURE:
1220     case DRV_INSTALL:
1221     case DRV_REMOVE:
1222     case DRV_EXITSESSION:
1223     case DRV_EXITAPPLICATION:
1224     case DRV_POWER:
1225         FIXME("This is a hack\n");
1226         return MCI_MAP_OK;
1227
1228     default:
1229         WARN("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg));
1230     }
1231     return MCI_MAP_MSGERROR;
1232 }
1233
1234 /**************************************************************************
1235  *                      MCI_UnMapMsg16To32A                     [internal]
1236  */
1237 static  MCI_MapType     MCI_UnMapMsg16To32A(WORD uDevType, WORD wMsg, DWORD lParam)
1238 {
1239     switch (wMsg) {
1240         /* case MCI_CAPTURE */
1241     case MCI_CLOSE:
1242     case MCI_CLOSE_DRIVER:      
1243         /* case MCI_CONFIGURE:*/
1244     case MCI_COPY:
1245     case MCI_CUE:
1246     case MCI_CUT:
1247     case MCI_DELETE:
1248     case MCI_FREEZE:
1249     case MCI_GETDEVCAPS:
1250         /* case MCI_INDEX: */
1251         /* case MCI_MARK: */
1252         /* case MCI_MONITOR: */
1253     case MCI_PASTE:
1254     case MCI_PAUSE:             
1255     case MCI_PLAY:              
1256     case MCI_PUT:
1257     case MCI_REALIZE:
1258     case MCI_RECORD:            
1259     case MCI_RESUME:            
1260     case MCI_SEEK:              
1261     case MCI_SET:
1262         /* case MCI_SETTIMECODE:*/
1263         /* case MCI_SIGNAL:*/
1264     case MCI_SPIN:
1265     case MCI_STATUS:            
1266     case MCI_STEP:
1267     case MCI_STOP:              
1268         /* case MCI_UNDO: */
1269     case MCI_UNFREEZE:
1270     case MCI_UPDATE:
1271     case MCI_WHERE:
1272         return MCI_MAP_OK;
1273
1274     case MCI_WINDOW:
1275         /* FIXME ?? see Map function */
1276         return MCI_MAP_OK;
1277
1278     case MCI_BREAK:
1279     case MCI_ESCAPE:
1280     case MCI_INFO:
1281     case MCI_SYSINFO:
1282         HeapFree(SystemHeap, 0, (LPVOID)lParam);
1283         return MCI_MAP_OK;
1284     case MCI_OPEN:
1285     case MCI_OPEN_DRIVER:       
1286         if (lParam) {
1287             LPMCI_OPEN_PARMSA   mop32a = (LPMCI_OPEN_PARMSA)lParam;
1288             LPMCI_OPEN_PARMS16  mop16  = *(LPMCI_OPEN_PARMS16*)((char*)mop32a - sizeof(LPMCI_OPEN_PARMS16));
1289             
1290             mop16->wDeviceID = mop32a->wDeviceID;
1291             if (!HeapFree(SystemHeap, 0, (LPVOID)(lParam - sizeof(LPMCI_OPEN_PARMS16))))
1292                 FIXME("bad free line=%d\n", __LINE__);
1293         }
1294         return MCI_MAP_OK;
1295     case DRV_LOAD:
1296     case DRV_ENABLE:
1297     case DRV_OPEN:
1298     case DRV_CLOSE:
1299     case DRV_DISABLE:
1300     case DRV_FREE:
1301     case DRV_CONFIGURE:
1302     case DRV_QUERYCONFIGURE:
1303     case DRV_INSTALL:
1304     case DRV_REMOVE:
1305     case DRV_EXITSESSION:
1306     case DRV_EXITAPPLICATION:
1307     case DRV_POWER:
1308         FIXME("This is a hack\n");
1309         return MCI_MAP_OK;
1310     default:
1311         FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg));
1312     }
1313     return MCI_MAP_MSGERROR;
1314 }
1315
1316 /*
1317  * 0000 stop
1318  * 0001 squeeze   signed 4 bytes to 2 bytes     *( LPINT16)D = ( INT16)*( LPINT16)S; D += 2;     S += 4
1319  * 0010 squeeze unsigned 4 bytes to 2 bytes     *(LPUINT16)D = (UINT16)*(LPUINT16)S; D += 2;     S += 4
1320  * 0100
1321  * 0101 
1322  * 0110 zero 4 bytes                            *(DWORD)D = 0                        D += 4;     S += 4
1323  * 0111 copy string                             *(LPSTR*)D = seg dup(*(LPSTR*)S)     D += 4;     S += 4
1324  * 1xxx copy xxx + 1 bytes                      memcpy(D, S, xxx + 1);               D += xxx+1; S += xxx+1
1325  */
1326
1327 /**************************************************************************
1328  *                      MCI_MsgMapper32To16_Create              [internal]
1329  *
1330  * Helper for MCI_MapMsg32ATo16. 
1331  * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit 
1332  * segmented pointer.
1333  * map contains a list of action to be performed for the mapping (see list
1334  * above)
1335  * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area.
1336  */
1337 static  MCI_MapType     MCI_MsgMapper32To16_Create(void** ptr, int size16, DWORD map, BOOLEAN keep)
1338 {
1339     void*       lp = SEGPTR_ALLOC((keep ? sizeof(void**) : 0) + size16);
1340     LPBYTE      p16, p32;
1341
1342     if (!lp) {
1343         return MCI_MAP_NOMEM;
1344     }
1345     p32 = (LPBYTE)(*ptr);
1346     if (keep) {
1347         *(void**)lp = *ptr;
1348         p16 = (LPBYTE)lp + sizeof(void**);
1349         *ptr = (char*)SEGPTR_GET(lp) + sizeof(void**);
1350     } else {
1351         p16 = lp;
1352         *ptr = (void*)SEGPTR_GET(lp);
1353     }
1354     
1355     if (map == 0) {
1356         memcpy(p16, p32, size16);
1357     } else {
1358         unsigned        nibble;
1359         unsigned        sz;
1360
1361         while (map & 0xF) {
1362             nibble = map & 0xF;
1363             if (nibble & 0x8) {
1364                 sz = (nibble & 7) + 1;
1365                 memcpy(p16, p32, sz);
1366                 p16 += sz;
1367                 p32 += sz;
1368                 size16 -= sz;   /* DEBUG only */
1369             } else {
1370                 switch (nibble) {
1371                 case 0x1:       *( LPINT16)p16 = ( INT16)*( LPINT16)p32;                p16 += 2;       p32 += 4;       size16 -= 2;    break;
1372                 case 0x2:       *(LPUINT16)p16 = (UINT16)*(LPUINT16)p32;                p16 += 2;       p32 += 4;       size16 -= 2;    break;
1373                 case 0x6:       *(LPDWORD)p16 = 0;                                      p16 += 4;       p32 += 4;       size16 -= 4;    break;
1374                 case 0x7:       *(LPDWORD)p16 = SEGPTR_GET(SEGPTR_STRDUP(*(LPSTR*)p32));p16 += 4;       p32 += 4;       size16 -= 4;    break;
1375                 default:        FIXME("Unknown nibble for mapping (%x)\n", nibble);
1376                 }
1377             }
1378             map >>= 4;
1379         }
1380         if (size16 != 0) /* DEBUG only */
1381             FIXME("Mismatch between 16 bit struct size and map nibbles serie\n");
1382     }
1383     return MCI_MAP_OKMEM;
1384 }
1385
1386 /**************************************************************************
1387  *                      MCI_MsgMapper32To16_Destroy             [internal]
1388  *
1389  * Helper for MCI_UnMapMsg32ATo16. 
1390  */
1391 static  MCI_MapType     MCI_MsgMapper32To16_Destroy(void* ptr, int size16, DWORD map, BOOLEAN kept)
1392 {
1393     if (ptr) {
1394         void*           msg16 = PTR_SEG_TO_LIN(ptr);
1395         void*           alloc;
1396         LPBYTE          p32, p16;
1397         unsigned        nibble;
1398
1399         if (kept) {
1400             alloc = (char*)msg16 - sizeof(void**);
1401             p32 = *(void**)alloc;
1402             p16 = msg16;
1403
1404             if (map == 0) {
1405                 memcpy(p32, p16, size16);
1406             } else {
1407                 while (map & 0xF) {
1408                     nibble = map & 0xF;
1409                     if (nibble & 0x8) {
1410                         memcpy(p32, p16, (nibble & 7) + 1);
1411                         p16 += (nibble & 7) + 1;
1412                         p32 += (nibble & 7) + 1;
1413                         size16 -= (nibble & 7) + 1;
1414                     } else {
1415                         switch (nibble) {
1416                         case 0x1:       *( LPINT)p32 = *( LPINT16)p16;                          p16 += 2;       p32 += 4;       size16 -= 2;    break;
1417                         case 0x2:       *(LPUINT)p32 = *(LPUINT16)p16;                          p16 += 2;       p32 += 4;       size16 -= 2;    break;
1418                         case 0x6:                                                               p16 += 4;       p32 += 4;       size16 -= 4;    break;
1419                         case 0x7:       strcpy(*(LPSTR*)p32, PTR_SEG_TO_LIN(*(DWORD*)p16));
1420                             if (!SEGPTR_FREE(PTR_SEG_TO_LIN(*(DWORD*)p16))) {
1421                                 FIXME("bad free line=%d\n", __LINE__);
1422                             }
1423                             p16 += 4;   p32 += 4;       size16 -= 4;    break;
1424                         default:        FIXME("Unknown nibble for mapping (%x)\n", nibble);
1425                         }
1426                     }
1427                     map >>= 4;
1428                 }
1429                 if (size16 != 0) /* DEBUG only */
1430                     FIXME("Mismatch between 16 bit struct size and map nibbles serie\n");
1431             }
1432         } else {
1433             alloc = msg16;
1434         }
1435
1436         if (!SEGPTR_FREE(alloc)) {
1437             FIXME("bad free line=%d\n", __LINE__);
1438         } 
1439     }   
1440     return MCI_MAP_OK;
1441 }
1442
1443 /**************************************************************************
1444  *                      MCI_MapMsg32ATo16                       [internal]
1445  *
1446  * Map a 32-A bit MCI message to a 16 bit MCI message.
1447  */
1448 static  MCI_MapType     MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam)
1449 {
1450     int         size;
1451     BOOLEAN     keep = FALSE;
1452     DWORD       map = 0;
1453
1454     if (*lParam == 0)
1455         return MCI_MAP_OK;
1456
1457     /* FIXME: to add also (with seg/linear modifications to do):
1458      * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE
1459      * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO
1460      */
1461     switch (wMsg) {
1462     case MCI_BREAK:
1463         size = sizeof(MCI_BREAK_PARMS);
1464         break;
1465         /* case MCI_CAPTURE */
1466     case MCI_CLOSE:
1467     case MCI_CLOSE_DRIVER:      
1468         size = sizeof(MCI_GENERIC_PARMS);       
1469         break;
1470         /* case MCI_CONFIGURE:*/
1471         /* case MCI_COPY: */
1472     case MCI_CUE:
1473         switch (uDevType) {
1474         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_CUE_PARMS);       break;
1475         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_CUE_PARMS);     break;*/        FIXME("NIY vcr\n");     return MCI_MAP_NOMEM;
1476         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1477         }
1478         break;
1479         /* case MCI_CUT:*/
1480     case MCI_DELETE:
1481         switch (uDevType) {
1482         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_DELETE_PARMS16);  map = 0x0F1111FB;       break;
1483         case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_DELETE_PARMS);   break;
1484         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1485         }
1486         break;
1487         /* case MCI_ESCAPE: */
1488     case MCI_FREEZE:
1489         switch (uDevType) {
1490         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_FREEZE_PARMS);    map = 0x0001111B;       break;
1491         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_RECT_PARMS);     map = 0x0001111B;       break;
1492         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1493         }
1494         break;
1495     case MCI_GETDEVCAPS:
1496         keep = TRUE;
1497         size = sizeof(MCI_GETDEVCAPS_PARMS);
1498         break;
1499         /* case MCI_INDEX: */
1500     case MCI_INFO:
1501         {
1502             LPMCI_INFO_PARMSA   mip32a = (LPMCI_INFO_PARMSA)(*lParam);
1503             char*               ptr;
1504             LPMCI_INFO_PARMS16  mip16;
1505             
1506             switch (uDevType) {
1507             case MCI_DEVTYPE_DIGITAL_VIDEO:     size = sizeof(MCI_DGV_INFO_PARMS16);    break;
1508             default:                            size = sizeof(MCI_INFO_PARMS16);        break;
1509             }
1510             ptr = SEGPTR_ALLOC(sizeof(LPMCI_INFO_PARMSA) + size);
1511
1512             if (ptr) {
1513                 *(LPMCI_INFO_PARMSA*)ptr = mip32a;
1514                 mip16 = (LPMCI_INFO_PARMS16)(ptr + sizeof(LPMCI_INFO_PARMSA));
1515                 mip16->dwCallback  = mip32a->dwCallback;
1516                 mip16->lpstrReturn = (LPSTR)SEGPTR_GET(SEGPTR_ALLOC(mip32a->dwRetSize));
1517                 mip16->dwRetSize   = mip32a->dwRetSize;
1518                 if (uDevType == MCI_DEVTYPE_DIGITAL_VIDEO) {
1519                     ((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSA)mip32a)->dwItem;
1520                 }
1521             } else {
1522                 return MCI_MAP_NOMEM;
1523             }
1524             *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_INFO_PARMSA);
1525         }
1526         return MCI_MAP_OKMEM;
1527         /* case MCI_MARK: */
1528         /* case MCI_MONITOR: */
1529     case MCI_OPEN:
1530     case MCI_OPEN_DRIVER:       
1531         {
1532             LPMCI_OPEN_PARMSA   mop32a = (LPMCI_OPEN_PARMSA)(*lParam);
1533             char*               ptr    = SEGPTR_ALLOC(sizeof(LPMCI_OPEN_PARMSA) + sizeof(MCI_OPEN_PARMS16) + 2 * sizeof(DWORD));
1534             LPMCI_OPEN_PARMS16  mop16;
1535
1536
1537             if (ptr) {
1538                 *(LPMCI_OPEN_PARMSA*)(ptr) = mop32a;
1539                 mop16 = (LPMCI_OPEN_PARMS16)(ptr + sizeof(LPMCI_OPEN_PARMSA));
1540                 mop16->dwCallback       = mop32a->dwCallback;
1541                 mop16->wDeviceID        = mop32a->wDeviceID;
1542                 if (dwFlags & MCI_OPEN_TYPE) {
1543                     if (dwFlags & MCI_OPEN_TYPE_ID) {
1544                         /* dword "transparent" value */
1545                         mop16->lpstrDeviceType = mop32a->lpstrDeviceType;
1546                     } else {
1547                         /* string */
1548                         mop16->lpstrDeviceType = mop32a->lpstrDeviceType ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrDeviceType)) : 0;
1549                     }
1550                 } else {
1551                     /* nuthin' */
1552                     mop16->lpstrDeviceType = 0;
1553                 }
1554                 if (dwFlags & MCI_OPEN_ELEMENT) {
1555                     if (dwFlags & MCI_OPEN_ELEMENT_ID) {
1556                         mop16->lpstrElementName = mop32a->lpstrElementName;
1557                     } else {
1558                         mop16->lpstrElementName = mop32a->lpstrElementName ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrElementName)) : 0;
1559                     }
1560                 } else {
1561                     mop16->lpstrElementName = 0;
1562                 }
1563                 if (dwFlags & MCI_OPEN_ALIAS) {
1564                     mop16->lpstrAlias = mop32a->lpstrAlias ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrAlias)) : 0;
1565                 } else {
1566                     mop16->lpstrAlias = 0;
1567                 }
1568                 /* copy extended information if any...
1569                  * FIXME: this may seg fault if initial structure does not contain them and
1570                  * the reads after msip16 fail under LDT limits...
1571                  * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and 
1572                  * should not take care of extended parameters, and should be used by MCI_Open
1573                  * to fetch uDevType. When, this is known, the mapping for sending the 
1574                  * MCI_OPEN_DRIVER shall be done depending on uDevType.
1575                  */
1576                 memcpy(mop16 + 1, mop32a + 1, 2 * sizeof(DWORD));
1577             } else {
1578                 return MCI_MAP_NOMEM;
1579             }
1580             *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_OPEN_PARMSA);
1581         }
1582         return MCI_MAP_OKMEM;
1583         /* case MCI_PASTE:*/
1584     case MCI_PAUSE:
1585         size = sizeof(MCI_GENERIC_PARMS);
1586         break;
1587     case MCI_PLAY:
1588         size = sizeof(MCI_PLAY_PARMS);
1589         break;
1590     case MCI_PUT:
1591         switch (uDevType) {
1592         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16);    map = 0x0001111B;       break;
1593         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_RECT_PARMS);     map = 0x0001111B;       break;
1594         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1595         }
1596         break;
1597     case MCI_REALIZE:
1598         size = sizeof(MCI_GENERIC_PARMS);
1599         break;
1600     case MCI_RECORD:
1601         switch (uDevType) {
1602         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECORD_PARMS16);  map = 0x0F1111FB;       break;
1603         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_RECORD_PARMS);  break;*/FIXME("NIY vcr\n");     return MCI_MAP_NOMEM;
1604         default:                        size = sizeof(MCI_RECORD_PARMS);        break;
1605         }
1606         break;
1607     case MCI_RESUME:            
1608         size = sizeof(MCI_GENERIC_PARMS);
1609         break;
1610     case MCI_SEEK:
1611         switch (uDevType) {
1612         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_SEEK_PARMS);    break;*/FIXME("NIY vcr\n");     return MCI_MAP_NOMEM;
1613         default:                        size = sizeof(MCI_SEEK_PARMS);          break;
1614         }
1615         break;
1616     case MCI_SET:
1617         switch (uDevType) {
1618         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SET_PARMS);       break;
1619         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_SET_PARMS);     break;*/FIXME("NIY vcr\n");     return MCI_MAP_NOMEM;
1620         case MCI_DEVTYPE_SEQUENCER:     size = sizeof(MCI_SEQ_SET_PARMS);       break;
1621         /* FIXME: normally the 16 and 32 bit structures are byte by byte aligned, 
1622          * so not doing anything should work...
1623          */
1624         case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_SET_PARMS);      break;
1625         default:                        size = sizeof(MCI_SET_PARMS);           break;
1626         }
1627         break;  
1628         /* case MCI_SETTIMECODE:*/
1629         /* case MCI_SIGNAL:*/
1630     case MCI_SPIN:
1631         size = sizeof(MCI_SET_PARMS);           
1632         break;
1633     case MCI_STATUS:
1634         keep = TRUE;
1635         switch (uDevType) {
1636         /* FIXME:
1637          * don't know if buffer for value is the one passed thru lpstrDevice 
1638          * or is provided by MCI driver.
1639          * Assuming solution 2: provided by MCI driver, so zeroing on entry
1640          */
1641         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16);  map = 0x0B6FF;          break;
1642         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_STATUS_PARMS);  break;*/FIXME("NIY vcr\n");     return MCI_MAP_NOMEM;
1643         default:                        size = sizeof(MCI_STATUS_PARMS);        break;
1644         }
1645         break;
1646     case MCI_STEP:
1647         switch (uDevType) {
1648         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STEP_PARMS);      break;
1649         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_STEP_PARMS);    break;*/FIXME("NIY vcr\n");     return MCI_MAP_NOMEM;
1650         case MCI_DEVTYPE_VIDEODISC:     size = sizeof(MCI_VD_STEP_PARMS);       break;
1651         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1652         }
1653         break;  
1654     case MCI_STOP:              
1655         size = sizeof(MCI_SET_PARMS);           
1656         break;
1657     case MCI_SYSINFO:
1658         {
1659             LPMCI_SYSINFO_PARMSA        msip32a = (LPMCI_SYSINFO_PARMSA)(*lParam);
1660             char*                       ptr     = SEGPTR_ALLOC(sizeof(LPMCI_SYSINFO_PARMSA) + sizeof(MCI_SYSINFO_PARMS16));
1661             LPMCI_SYSINFO_PARMS16       msip16;
1662
1663             if (ptr) {
1664                 *(LPMCI_SYSINFO_PARMSA*)(ptr) = msip32a;
1665                 msip16 = (LPMCI_SYSINFO_PARMS16)(ptr + sizeof(LPMCI_SYSINFO_PARMSA));
1666
1667                 msip16->dwCallback       = msip32a->dwCallback;
1668                 msip16->lpstrReturn      = (LPSTR)SEGPTR_GET(SEGPTR_ALLOC(msip32a->dwRetSize));
1669                 msip16->dwRetSize        = msip32a->dwRetSize;
1670                 msip16->dwNumber         = msip32a->dwNumber;
1671                 msip16->wDeviceType      = msip32a->wDeviceType;
1672             } else {
1673                 return MCI_MAP_NOMEM;
1674             }
1675             *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_SYSINFO_PARMSA);
1676         }
1677         return MCI_MAP_OKMEM;
1678         /* case MCI_UNDO: */
1679     case MCI_UNFREEZE:
1680         switch (uDevType) {
1681         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16);    map = 0x0001111B;       break;
1682         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_RECT_PARMS16);   map = 0x0001111B;       break;
1683         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1684         }
1685         break;
1686     case MCI_UPDATE:
1687         switch (uDevType) {
1688         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_UPDATE_PARMS16);  map = 0x000B1111B;      break;
1689         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1690         }
1691         break;
1692     case MCI_WHERE:
1693         switch (uDevType) {
1694         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16);    map = 0x0001111B;       keep = TRUE;    break;
1695         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_RECT_PARMS16);   map = 0x0001111B;       keep = TRUE;    break;
1696         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1697         }
1698         break;
1699     case MCI_WINDOW:
1700         switch (uDevType) {
1701         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16);  if (dwFlags & MCI_DGV_WINDOW_TEXT)  map = 0x7FB;        break;
1702         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7FB;        break;
1703         default:                        size = sizeof(MCI_GENERIC_PARMS);       break;
1704         }
1705         break;
1706     case DRV_LOAD:
1707     case DRV_ENABLE:
1708     case DRV_OPEN:
1709     case DRV_CLOSE:
1710     case DRV_DISABLE:
1711     case DRV_FREE:
1712     case DRV_CONFIGURE:
1713     case DRV_QUERYCONFIGURE:
1714     case DRV_INSTALL:
1715     case DRV_REMOVE:
1716     case DRV_EXITSESSION:
1717     case DRV_EXITAPPLICATION:
1718     case DRV_POWER:
1719         return MCI_MAP_PASS;
1720
1721     default:
1722         WARN("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg));
1723         return MCI_MAP_MSGERROR;
1724     }
1725     return MCI_MsgMapper32To16_Create((void**)lParam, size, map, keep);
1726 }
1727
1728 /**************************************************************************
1729  *                      MCI_UnMapMsg32ATo16                     [internal]
1730  */
1731 static  MCI_MapType     MCI_UnMapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam)
1732 {
1733     int         size = 0;
1734     BOOLEAN     kept = FALSE;   /* there is no need to compute size when kept is FALSE */
1735     DWORD       map = 0;
1736
1737     switch (wMsg) {
1738     case MCI_BREAK:
1739         break;
1740         /* case MCI_CAPTURE */
1741     case MCI_CLOSE:     
1742     case MCI_CLOSE_DRIVER:      
1743         break;
1744         /* case MCI_CONFIGURE:*/
1745         /* case MCI_COPY: */
1746     case MCI_CUE:       
1747         break;
1748         /* case MCI_CUT: */
1749     case MCI_DELETE:
1750         break;
1751         /* case MCI_ESCAPE: */
1752     case MCI_FREEZE:
1753         break;
1754     case MCI_GETDEVCAPS:
1755         kept = TRUE;
1756         size = sizeof(MCI_GETDEVCAPS_PARMS);
1757         break;
1758         /* case MCI_INDEX: */
1759     case MCI_INFO:
1760         {
1761             LPMCI_INFO_PARMS16  mip16  = (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(lParam);
1762             LPMCI_INFO_PARMSA   mip32a = *(LPMCI_INFO_PARMSA*)((char*)mip16 - sizeof(LPMCI_INFO_PARMSA));
1763
1764             memcpy(mip32a->lpstrReturn, PTR_SEG_TO_LIN(mip16->lpstrReturn), mip32a->dwRetSize);
1765
1766             if (!SEGPTR_FREE(PTR_SEG_TO_LIN(mip16->lpstrReturn)))
1767                 FIXME("bad free line=%d\n", __LINE__);
1768             if (!SEGPTR_FREE((char*)mip16 - sizeof(LPMCI_INFO_PARMSA)))
1769                 FIXME("bad free line=%d\n", __LINE__);
1770         }
1771         return MCI_MAP_OK;
1772         /* case MCI_MARK: */
1773         /* case MCI_MONITOR: */
1774     case MCI_OPEN:
1775     case MCI_OPEN_DRIVER:       
1776         if (lParam) {
1777             LPMCI_OPEN_PARMS16  mop16  = (LPMCI_OPEN_PARMS16)PTR_SEG_TO_LIN(lParam);
1778             LPMCI_OPEN_PARMSA   mop32a = *(LPMCI_OPEN_PARMSA*)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA));
1779             
1780             mop32a->wDeviceID = mop16->wDeviceID;
1781             if ((dwFlags & MCI_OPEN_TYPE) && ! 
1782                 (dwFlags & MCI_OPEN_TYPE_ID) && 
1783                 !SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrDeviceType)))
1784                 FIXME("bad free line=%d\n", __LINE__);
1785             if ((dwFlags & MCI_OPEN_ELEMENT) && 
1786                 !(dwFlags & MCI_OPEN_ELEMENT_ID) && 
1787                 !SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrElementName)))
1788                 FIXME("bad free line=%d\n", __LINE__);
1789             if ((dwFlags & MCI_OPEN_ALIAS) && 
1790                 !SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrAlias)))
1791                 FIXME("bad free line=%d\n", __LINE__);
1792
1793             if (!SEGPTR_FREE((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA)))
1794                 FIXME("bad free line=%d\n", __LINE__);
1795         }
1796         return MCI_MAP_OK;
1797         /* case MCI_PASTE:*/
1798     case MCI_PAUSE:
1799         break;
1800     case MCI_PLAY:              
1801         break;
1802     case MCI_PUT:
1803         break;
1804     case MCI_REALIZE:
1805         break;
1806     case MCI_RECORD:
1807         break;
1808     case MCI_RESUME:
1809         break;
1810     case MCI_SEEK:
1811         break;
1812     case MCI_SET:
1813         break;
1814         /* case MCI_SETTIMECODE:*/
1815         /* case MCI_SIGNAL:*/
1816     case MCI_SPIN:
1817         break;
1818     case MCI_STATUS:
1819         kept = TRUE;
1820         switch (uDevType) {
1821         case MCI_DEVTYPE_DIGITAL_VIDEO: 
1822         if (lParam) {
1823             LPMCI_DGV_STATUS_PARMS16    mdsp16  = (LPMCI_DGV_STATUS_PARMS16)PTR_SEG_TO_LIN(lParam);
1824             LPMCI_DGV_STATUS_PARMSA     mdsp32a = *(LPMCI_DGV_STATUS_PARMSA*)((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA));
1825
1826             if (mdsp16) {
1827                 mdsp32a->dwReturn = mdsp16->dwReturn;
1828                 if (dwFlags & MCI_DGV_STATUS_DISKSPACE) {
1829                     TRACE("MCI_STATUS (DGV) lpstrDrive=%p\n", mdsp16->lpstrDrive);
1830                     TRACE("MCI_STATUS (DGV) lpstrDrive=%s\n", (LPSTR)PTR_SEG_TO_LIN(mdsp16->lpstrDrive));
1831
1832                     /* FIXME: see map function */
1833                     strcpy(mdsp32a->lpstrDrive, (LPSTR)PTR_SEG_TO_LIN(mdsp16->lpstrDrive));
1834                 }
1835
1836                 if (!SEGPTR_FREE((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA)))
1837                     FIXME("bad free line=%d\n", __LINE__);
1838             } else {
1839                 return MCI_MAP_NOMEM;
1840             }
1841         }
1842         return MCI_MAP_OKMEM;
1843         case MCI_DEVTYPE_VCR:           /*size = sizeof(MCI_VCR_STATUS_PARMS);  break;*/FIXME("NIY vcr\n");     return MCI_MAP_NOMEM;
1844         default:                        size = sizeof(MCI_STATUS_PARMS);        break;
1845         }
1846         break;
1847     case MCI_STEP:
1848         break;
1849     case MCI_STOP:
1850         break;
1851     case MCI_SYSINFO:
1852         if (lParam) {
1853             LPMCI_SYSINFO_PARMS16       msip16  = (LPMCI_SYSINFO_PARMS16)PTR_SEG_TO_LIN(lParam);
1854             LPMCI_SYSINFO_PARMSA        msip32a = *(LPMCI_SYSINFO_PARMSA*)((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA));
1855
1856             if (msip16) {
1857                 msip16->dwCallback       = msip32a->dwCallback;
1858                 memcpy(msip32a->lpstrReturn, PTR_SEG_TO_LIN(msip16->lpstrReturn), msip32a->dwRetSize);
1859                 if (!SEGPTR_FREE(PTR_SEG_TO_LIN(msip16->lpstrReturn)))
1860                     FIXME("bad free line=%d\n", __LINE__);
1861
1862                 if (!SEGPTR_FREE((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA)))
1863                     FIXME("bad free line=%d\n", __LINE__);
1864             } else {
1865                 return MCI_MAP_NOMEM;
1866             }
1867         }
1868         return MCI_MAP_OKMEM;
1869         /* case MCI_UNDO: */
1870     case MCI_UNFREEZE:
1871         break;
1872     case MCI_UPDATE:
1873         break;
1874     case MCI_WHERE:
1875         switch (uDevType) {
1876         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16);    map = 0x0001111B;       kept = TRUE;    break;
1877         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_RECT_PARMS16);   map = 0x0001111B;       kept = TRUE;    break;
1878         default:                        break;
1879         }
1880         break;
1881     case MCI_WINDOW:
1882         switch (uDevType) {
1883         case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16);  if (dwFlags & MCI_DGV_WINDOW_TEXT)  map = 0x7666;       break;
1884         case MCI_DEVTYPE_OVERLAY:       size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7666;       break;
1885         default:                        break;
1886         }
1887         /* FIXME: see map function */
1888         break;
1889
1890     case DRV_LOAD:
1891     case DRV_ENABLE:
1892     case DRV_OPEN:
1893     case DRV_CLOSE:
1894     case DRV_DISABLE:
1895     case DRV_FREE:
1896     case DRV_CONFIGURE:
1897     case DRV_QUERYCONFIGURE:
1898     case DRV_INSTALL:
1899     case DRV_REMOVE:
1900     case DRV_EXITSESSION:
1901     case DRV_EXITAPPLICATION:
1902     case DRV_POWER:
1903         FIXME("This is a hack\n");
1904         return MCI_MAP_PASS;
1905     default:
1906         FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg));
1907         return MCI_MAP_MSGERROR;
1908     }
1909     return MCI_MsgMapper32To16_Destroy((void*)lParam, size, map, kept);
1910 }
1911
1912 /**************************************************************************
1913  *                      MCI_SendCommandFrom32                   [internal]
1914  */
1915 DWORD MCI_SendCommandFrom32(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1916 {
1917     DWORD               dwRet = MCIERR_DEVICE_NOT_INSTALLED;
1918     LPWINE_MCIDRIVER    wmd = MCI_GetDriver(wDevID);
1919
1920     if (!wmd) {
1921         dwRet = MCIERR_INVALID_DEVICE_ID;
1922     } else {
1923         switch (GetDriverFlags(wmd->hDrv) & (WINE_GDF_EXIST|WINE_GDF_16BIT)) {
1924         case WINE_GDF_EXIST|WINE_GDF_16BIT:
1925             {
1926                 MCI_MapType     res;
1927                 
1928                 switch (res = MCI_MapMsg32ATo16(wmd->wType, wMsg, dwParam1, &dwParam2)) {
1929                 case MCI_MAP_MSGERROR:
1930                     TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg));
1931                     dwRet = MCIERR_DRIVER_INTERNAL;
1932                     break;
1933                 case MCI_MAP_NOMEM:
1934                     TRACE("Problem mapping msg=%s from 32a to 16\n", MCI_MessageToString(wMsg));
1935                     dwRet = MCIERR_OUT_OF_MEMORY;
1936                     break;
1937                 case MCI_MAP_OK:
1938                 case MCI_MAP_OKMEM:
1939                     dwRet = SendDriverMessage16(wmd->hDrv, wMsg, dwParam1, dwParam2);
1940                     if (res == MCI_MAP_OKMEM)
1941                         MCI_UnMapMsg32ATo16(wmd->wType, wMsg, dwParam1, dwParam2);
1942                     break;
1943                 case MCI_MAP_PASS:
1944                     dwRet = SendDriverMessage(wmd->hDrv, wMsg, dwParam1, dwParam2);
1945                     break;
1946                 }
1947             }
1948             break;
1949         case WINE_GDF_EXIST:
1950             dwRet = SendDriverMessage(wmd->hDrv, wMsg, dwParam1, dwParam2);
1951             break;
1952         default:
1953             WARN("Unknown driver %u\n", wmd->hDrv);
1954             dwRet = MCIERR_DRIVER_INTERNAL;
1955         }
1956     }
1957     return dwRet;
1958 }
1959
1960 /**************************************************************************
1961  *                      MCI_SendCommandFrom16                   [internal]
1962  */
1963 DWORD MCI_SendCommandFrom16(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
1964 {
1965     DWORD               dwRet = MCIERR_DEVICE_NOT_INSTALLED;
1966     LPWINE_MCIDRIVER    wmd = MCI_GetDriver(wDevID);
1967
1968     if (!wmd) {
1969         dwRet = MCIERR_INVALID_DEVICE_ID;
1970     } else {
1971         MCI_MapType             res;
1972         
1973         switch (GetDriverFlags(wmd->hDrv) & (WINE_GDF_EXIST|WINE_GDF_16BIT)) {
1974         case WINE_GDF_EXIST|WINE_GDF_16BIT:             
1975             dwRet = SendDriverMessage16(wmd->hDrv, wMsg, dwParam1, dwParam2);
1976             break;
1977         case WINE_GDF_EXIST:
1978             switch (res = MCI_MapMsg16To32A(wmd->wType, wMsg, &dwParam2)) {
1979             case MCI_MAP_MSGERROR:
1980                 TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg));
1981                 dwRet = MCIERR_DRIVER_INTERNAL;
1982                 break;
1983             case MCI_MAP_NOMEM:
1984                 TRACE("Problem mapping msg=%s from 16 to 32a\n", MCI_MessageToString(wMsg));
1985                 dwRet = MCIERR_OUT_OF_MEMORY;
1986                 break;
1987             case MCI_MAP_OK:
1988             case MCI_MAP_OKMEM:
1989                 dwRet = SendDriverMessage(wmd->hDrv, wMsg, dwParam1, dwParam2);
1990                 if (res == MCI_MAP_OKMEM)
1991                     MCI_UnMapMsg16To32A(wmd->wType, wMsg, dwParam2);
1992                 break;
1993             case MCI_MAP_PASS:
1994                 dwRet = SendDriverMessage16(wmd->hDrv, wMsg, dwParam1, dwParam2);
1995                 break;
1996             }
1997             break;
1998         default:
1999             WARN("Unknown driver %u\n", wmd->hDrv);
2000             dwRet = MCIERR_DRIVER_INTERNAL;
2001         }
2002     }
2003     return dwRet;
2004 }
2005
2006 /**************************************************************************
2007  *                      MCI_Open                                [internal]
2008  */
2009 static  DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSA lpParms)
2010 {
2011     char                        strDevTyp[128];
2012     DWORD                       dwRet; 
2013     LPWINE_MCIDRIVER            wmd;
2014     LPWINE_MM_IDATA             iData = MULTIMEDIA_GetIData();
2015
2016     TRACE("(%08lX, %p)\n", dwParam, lpParms);
2017     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
2018
2019     /* only two low bytes are generic, the other ones are dev type specific */
2020 #define WINE_MCIDRIVER_SUPP     (0xFFFF0000|MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT| \
2021                          MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID| \
2022                          MCI_NOTIFY|MCI_WAIT)
2023     if ((dwParam & ~WINE_MCIDRIVER_SUPP) != 0) {
2024         FIXME("Unsupported yet dwFlags=%08lX\n", dwParam & ~WINE_MCIDRIVER_SUPP);
2025     }
2026 #undef WINE_MCIDRIVER_SUPP
2027
2028     strDevTyp[0] = 0;
2029
2030     if (dwParam & MCI_OPEN_TYPE) {
2031         if (dwParam & MCI_OPEN_TYPE_ID) {
2032             WORD uDevType = LOWORD((DWORD)lpParms->lpstrDeviceType);
2033
2034             if (uDevType < MCI_DEVTYPE_FIRST ||
2035                 uDevType > MCI_DEVTYPE_LAST ||
2036                 !LoadStringA(iData->hWinMM32Instance, uDevType, strDevTyp, sizeof(strDevTyp))) {
2037                 dwRet = MCIERR_BAD_INTEGER;
2038                 goto errCleanUp;
2039             }
2040         } else {
2041             LPSTR       ptr;
2042             if (lpParms->lpstrDeviceType == NULL) {
2043                 dwRet = MCIERR_NULL_PARAMETER_BLOCK;
2044                 goto errCleanUp;
2045             }
2046             strcpy(strDevTyp, lpParms->lpstrDeviceType);
2047             ptr = strchr(strDevTyp, '!');
2048             if (ptr) {
2049                 /* this behavior is not documented in windows. However, since, in
2050                  * some occasions, MCI_OPEN handling is translated by WinMM into
2051                  * a call to mciSendString("open <type>"); this code shall be correct
2052                  */
2053                 if (dwParam & MCI_OPEN_ELEMENT) {
2054                     ERR("Both MCI_OPEN_ELEMENT(%s) and %s are used\n",
2055                         lpParms->lpstrElementName, strDevTyp);
2056                     dwRet = MCIERR_UNRECOGNIZED_KEYWORD;
2057                     goto errCleanUp;
2058                 }
2059                 dwParam |= MCI_OPEN_ELEMENT;
2060                 *ptr++ = 0;
2061                 /* FIXME: not a good idea to write in user supplied buffer */
2062                 lpParms->lpstrElementName = ptr;
2063             }
2064                 
2065         }
2066         TRACE("devType='%s' !\n", strDevTyp);
2067     }
2068
2069     if (dwParam & MCI_OPEN_ELEMENT) {
2070         TRACE("lpstrElementName='%s'\n", lpParms->lpstrElementName);
2071
2072         if (dwParam & MCI_OPEN_ELEMENT_ID) {
2073             FIXME("Unsupported yet flag MCI_OPEN_ELEMENT_ID\n");
2074             dwRet = MCIERR_UNRECOGNIZED_KEYWORD;
2075             goto errCleanUp;
2076         }
2077
2078         if (!lpParms->lpstrElementName) {
2079             dwRet = MCIERR_NULL_PARAMETER_BLOCK;
2080             goto errCleanUp;
2081         }
2082
2083         /* type, if given as a parameter, supersedes file extension */
2084         if (!strDevTyp[0] && 
2085             MCI_GetDevTypeFromFileName(lpParms->lpstrElementName, 
2086                                        strDevTyp, sizeof(strDevTyp))) {
2087             if (GetDriveTypeA(lpParms->lpstrElementName) != DRIVE_CDROM) {
2088                 dwRet = MCIERR_EXTENSION_NOT_FOUND;
2089                 goto errCleanUp;
2090             }
2091             /* FIXME: this will not work if several CDROM drives are installed on the machine */
2092             strcpy(strDevTyp, "CDAUDIO");
2093         }
2094     }
2095     
2096     if (strDevTyp[0] == 0) {
2097         FIXME("Couldn't load driver\n");
2098         dwRet = MCIERR_INVALID_DEVICE_NAME;
2099         goto errCleanUp;
2100     }
2101
2102     if (dwParam & MCI_OPEN_ALIAS) {
2103         TRACE("Alias='%s' !\n", lpParms->lpstrAlias);
2104         if (!lpParms->lpstrAlias) {
2105             dwRet = MCIERR_NULL_PARAMETER_BLOCK;
2106             goto errCleanUp;
2107         }
2108     }
2109
2110     if ((dwRet = MCI_LoadMciDriver(iData, strDevTyp, &wmd))) {
2111         goto errCleanUp;
2112     }
2113
2114     if ((dwRet = MCI_FinishOpen(wmd, lpParms, dwParam))) {
2115         TRACE("Failed to open driver (MCI_OPEN_DRIVER) [%08lx], closing\n", dwRet);
2116         /* FIXME: is dwRet the correct ret code ? */
2117         goto errCleanUp;
2118     }
2119
2120     /* only handled devices fall through */
2121     TRACE("wDevID=%04X wDeviceID=%d dwRet=%ld\n", wmd->wDeviceID, lpParms->wDeviceID, dwRet);
2122
2123     if (dwParam & MCI_NOTIFY)
2124         mciDriverNotify16(lpParms->dwCallback, wmd->wDeviceID, MCI_NOTIFY_SUCCESSFUL);
2125     
2126     return 0;
2127 errCleanUp:
2128     MCI_UnLoadMciDriver(iData, wmd);
2129
2130     if (dwParam & MCI_NOTIFY)
2131         mciDriverNotify16(lpParms->dwCallback, 0, MCI_NOTIFY_FAILURE);
2132     return dwRet;
2133 }
2134
2135 /**************************************************************************
2136  *                      MCI_Close                               [internal]
2137  */
2138 static  DWORD MCI_Close(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
2139 {
2140     DWORD               dwRet;
2141     LPWINE_MCIDRIVER    wmd;
2142     LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
2143
2144     TRACE("(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms);
2145
2146     if (wDevID == MCI_ALL_DEVICE_ID) {
2147         LPWINE_MCIDRIVER        next;
2148
2149         EnterCriticalSection(&iData->cs);
2150         /* FIXME: shall I notify once after all is done, or for 
2151          * each of the open drivers ? if the latest, which notif
2152          * to return when only one fails ?
2153          */
2154         for (wmd = iData->lpMciDrvs; wmd; ) {
2155             next = wmd->lpNext;
2156             MCI_Close(wmd->wDeviceID, dwParam, lpParms);
2157             wmd = next;
2158         }       
2159         LeaveCriticalSection(&iData->cs);
2160         return 0;
2161     }
2162
2163     if (!(wmd = MCI_GetDriver(wDevID))) {
2164         return MCIERR_INVALID_DEVICE_ID;
2165     }
2166
2167     dwRet = MCI_SendCommandFrom32(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD)lpParms);
2168
2169     MCI_UnLoadMciDriver(iData, wmd);
2170
2171     if (dwParam & MCI_NOTIFY)
2172         mciDriverNotify16(lpParms->dwCallback, wDevID,
2173                           (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
2174     
2175     return dwRet;
2176 }
2177
2178 /**************************************************************************
2179  *                      MCI_WriteString                         [internal]
2180  */
2181 DWORD   MCI_WriteString(LPSTR lpDstStr, DWORD dstSize, LPCSTR lpSrcStr)
2182 {
2183     DWORD       ret = 0;
2184
2185     if (lpSrcStr) {
2186         if (dstSize <= strlen(lpSrcStr)) {
2187             lstrcpynA(lpDstStr, lpSrcStr, dstSize - 1);
2188             ret = MCIERR_PARAM_OVERFLOW;
2189         } else {
2190             strcpy(lpDstStr, lpSrcStr);
2191         }       
2192     } else {
2193         *lpDstStr = 0;
2194     }
2195     return ret;
2196 }
2197
2198 /**************************************************************************
2199  *                      MCI_Sysinfo                             [internal]
2200  */
2201 static  DWORD MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSA lpParms)
2202 {
2203     DWORD               ret = MCIERR_INVALID_DEVICE_ID;
2204     LPWINE_MCIDRIVER    wmd;
2205     LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
2206
2207     if (lpParms == NULL)                        return MCIERR_NULL_PARAMETER_BLOCK;
2208
2209     TRACE("(%08x, %08lX, %08lX[num=%ld, wDevTyp=%u])\n", 
2210           uDevID, dwFlags, (DWORD)lpParms, lpParms->dwNumber, lpParms->wDeviceType);
2211     
2212     switch (dwFlags & ~MCI_SYSINFO_OPEN) {
2213     case MCI_SYSINFO_QUANTITY:
2214         {
2215             DWORD       cnt = 0;
2216             
2217             if (lpParms->wDeviceType < MCI_DEVTYPE_FIRST || 
2218                 lpParms->wDeviceType > MCI_DEVTYPE_LAST) {
2219                 if (dwFlags & MCI_SYSINFO_OPEN) {
2220                     TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers\n");
2221                     EnterCriticalSection(&iData->cs);
2222                     for (wmd = iData->lpMciDrvs; wmd; wmd = wmd->lpNext) {
2223                         cnt++;
2224                     }
2225                     LeaveCriticalSection(&iData->cs);
2226                 } else {
2227                     TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n");
2228                     cnt = MCI_InstalledCount;
2229                 }
2230             } else {
2231                 if (dwFlags & MCI_SYSINFO_OPEN) {
2232                     TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers of type %u\n", 
2233                           lpParms->wDeviceType);
2234                     EnterCriticalSection(&iData->cs);
2235                     for (wmd = iData->lpMciDrvs; wmd; wmd = wmd->lpNext) {
2236                         if (wmd->wType == lpParms->wDeviceType)
2237                             cnt++;
2238                     }
2239                     LeaveCriticalSection(&iData->cs);
2240                 } else {
2241                     TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers of type %u\n", 
2242                           lpParms->wDeviceType);
2243                     FIXME("Don't know how to get # of MCI devices of a given type\n");
2244                     cnt = 1;
2245                 }
2246             }
2247             *(DWORD*)lpParms->lpstrReturn = cnt;
2248         }
2249         TRACE("(%ld) => '%ld'\n", lpParms->dwNumber, *(DWORD*)lpParms->lpstrReturn);
2250         ret = MCI_INTEGER_RETURNED;
2251         break;
2252     case MCI_SYSINFO_INSTALLNAME:
2253         TRACE("MCI_SYSINFO_INSTALLNAME \n");
2254         if ((wmd = MCI_GetDriver(uDevID))) {
2255             ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, 
2256                                   wmd->lpstrDeviceType);
2257         } else {
2258             *lpParms->lpstrReturn = 0;
2259             ret = MCIERR_INVALID_DEVICE_ID;
2260         }
2261         TRACE("(%ld) => '%s'\n", lpParms->dwNumber, lpParms->lpstrReturn);
2262         break;
2263     case MCI_SYSINFO_NAME:
2264         TRACE("MCI_SYSINFO_NAME\n");
2265         if (dwFlags & MCI_SYSINFO_OPEN) {
2266             FIXME("Don't handle MCI_SYSINFO_NAME|MCI_SYSINFO_OPEN (yet)\n");
2267             ret = MCIERR_UNRECOGNIZED_COMMAND;
2268         } else if (lpParms->dwNumber > MCI_InstalledCount) {
2269             ret = MCIERR_OUTOFRANGE;
2270         } else {
2271             DWORD       count = lpParms->dwNumber;
2272             LPSTR       ptr = MCI_lpInstallNames;
2273
2274             while (--count > 0) ptr += strlen(ptr) + 1;
2275             ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, ptr);
2276         }
2277         TRACE("(%ld) => '%s'\n", lpParms->dwNumber, lpParms->lpstrReturn);
2278         break;
2279     default:
2280         TRACE("Unsupported flag value=%08lx\n", dwFlags);
2281         ret = MCIERR_UNRECOGNIZED_COMMAND;
2282     }
2283     return ret;
2284 }
2285
2286 /**************************************************************************
2287  *                      MCI_Break                               [internal]
2288  */
2289 static  DWORD MCI_Break(UINT wDevID, DWORD dwFlags, LPMCI_BREAK_PARMS lpParms)
2290 {
2291     DWORD       dwRet = 0;
2292     
2293     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
2294
2295     if (dwFlags & MCI_NOTIFY)
2296         mciDriverNotify16(lpParms->dwCallback, wDevID,
2297                           (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
2298
2299     return dwRet;
2300 }
2301     
2302 /**************************************************************************
2303  *                      MCI_SendCommand                         [internal]
2304  */
2305 DWORD   MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, 
2306                         DWORD dwParam2, BOOL bFrom32)
2307 {
2308     DWORD               dwRet = MCIERR_UNRECOGNIZED_COMMAND;
2309
2310     switch (wMsg) {
2311     case MCI_OPEN:
2312         if (bFrom32) {
2313             dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
2314         } else {
2315             switch (MCI_MapMsg16To32A(0, wMsg, &dwParam2)) {
2316             case MCI_MAP_OK:
2317             case MCI_MAP_OKMEM:
2318                 dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
2319                 MCI_UnMapMsg16To32A(0, wMsg, dwParam2);
2320                 break;
2321             default: break; /* so that gcc does not bark */
2322             }
2323         }
2324         break;
2325     case MCI_CLOSE:
2326         if (bFrom32) {
2327             dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
2328         } else {
2329             switch (MCI_MapMsg16To32A(0, wMsg, &dwParam2)) {
2330             case MCI_MAP_OK:
2331             case MCI_MAP_OKMEM:
2332                 dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
2333                 MCI_UnMapMsg16To32A(0, wMsg, dwParam2);
2334                 break;
2335             default: break; /* so that gcc does not bark */
2336             }
2337         }
2338         break;
2339     case MCI_SYSINFO:
2340         if (bFrom32) {
2341             dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
2342         } else {
2343             switch (MCI_MapMsg16To32A(0, wDevID, &dwParam2)) {
2344             case MCI_MAP_OK:
2345             case MCI_MAP_OKMEM:
2346                 dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
2347                 MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
2348                 break;
2349             default: break; /* so that gcc doesnot  bark */
2350             }
2351         }
2352         break;
2353     case MCI_BREAK:
2354         if (bFrom32) {
2355             dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2);
2356         } else {
2357             switch (MCI_MapMsg16To32A(0, wDevID, &dwParam2)) {
2358             case MCI_MAP_OK:
2359             case MCI_MAP_OKMEM:
2360                 dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2);
2361                 MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
2362                 break;
2363             default: break; /* so that gcc does not bark */
2364             }
2365         }
2366         break;
2367     case MCI_SOUND:
2368         /* FIXME: it seems that MCI_SOUND needs the same handling as MCI_BREAK
2369          * but I couldn't get any doc on this MCI message
2370          */
2371         break;
2372     default:
2373         if (wDevID == MCI_ALL_DEVICE_ID) {
2374             FIXME("unhandled MCI_ALL_DEVICE_ID\n");
2375             dwRet = MCIERR_CANNOT_USE_ALL;
2376         } else {
2377             dwRet = (bFrom32) ?
2378                 MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2) :
2379                 MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2);
2380         }           
2381         break;
2382     }
2383     return dwRet;
2384 }
2385
2386 /**************************************************************************
2387  *                              MCI_CleanUp                     [internal]
2388  *
2389  * Some MCI commands need to be cleaned-up (when not called from 
2390  * mciSendString), because MCI drivers return extra information for string
2391  * transformation. This function gets rid of them.
2392  */
2393 LRESULT         MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2, BOOL bIs32)
2394 {
2395     if (LOWORD(dwRet)) 
2396         return LOWORD(dwRet);
2397
2398     switch (wMsg) {
2399     case MCI_GETDEVCAPS:
2400         switch (dwRet & 0xFFFF0000ul) {
2401         case 0:
2402         case MCI_COLONIZED3_RETURN:
2403         case MCI_COLONIZED4_RETURN:
2404         case MCI_INTEGER_RETURNED:
2405             /* nothing to do */
2406             break;
2407         case MCI_RESOURCE_RETURNED:
2408         case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER:
2409             {
2410                 LPMCI_GETDEVCAPS_PARMS  lmgp;
2411
2412                 lmgp = (LPMCI_GETDEVCAPS_PARMS)(bIs32 ? (void*)dwParam2 : PTR_SEG_TO_LIN(dwParam2));
2413                 TRACE("Changing %08lx to %08lx\n", lmgp->dwReturn, (DWORD)LOWORD(lmgp->dwReturn));
2414                 lmgp->dwReturn = LOWORD(lmgp->dwReturn);
2415             } 
2416             break;
2417         default:
2418             FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n", 
2419                   HIWORD(dwRet), MCI_MessageToString(wMsg));
2420         }
2421         break;
2422     case MCI_STATUS:
2423         switch (dwRet & 0xFFFF0000ul) {
2424         case 0:
2425         case MCI_COLONIZED3_RETURN:
2426         case MCI_COLONIZED4_RETURN:
2427         case MCI_INTEGER_RETURNED:
2428             /* nothing to do */
2429             break;
2430         case MCI_RESOURCE_RETURNED:
2431         case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER:
2432             {
2433                 LPMCI_STATUS_PARMS      lsp;
2434
2435                 lsp = (LPMCI_STATUS_PARMS)(bIs32 ? (void*)dwParam2 : PTR_SEG_TO_LIN(dwParam2));
2436                 TRACE("Changing %08lx to %08lx\n", lsp->dwReturn, (DWORD)LOWORD(lsp->dwReturn));
2437                 lsp->dwReturn = LOWORD(lsp->dwReturn);
2438             }
2439             break;
2440         default:
2441             FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n", 
2442                   HIWORD(dwRet), MCI_MessageToString(wMsg));
2443         }
2444         break;
2445     case MCI_SYSINFO:
2446         switch (dwRet & 0xFFFF0000ul) {
2447         case 0:
2448         case MCI_INTEGER_RETURNED:
2449             /* nothing to do */
2450             break;
2451         default:
2452             FIXME("Unsupported value for hiword (%04x)\n", HIWORD(dwRet));      
2453         }
2454         break;
2455     default:
2456         if (HIWORD(dwRet)) {
2457             FIXME("Got non null hiword for dwRet=0x%08lx for command %s\n", 
2458                   dwRet, MCI_MessageToString(wMsg));
2459         }
2460         break;
2461     }
2462     return LOWORD(dwRet);
2463 }
2464
2465 /**************************************************************************
2466  *                      MULTIMEDIA_MciInit                      [internal]
2467  *
2468  * Initializes the MCI internal variables.
2469  *
2470  */
2471 BOOL MULTIMEDIA_MciInit(void)
2472 {
2473     LPSTR       ptr1, ptr2;
2474
2475     MCI_InstalledCount = 0;
2476     ptr1 = MCI_lpInstallNames = HeapAlloc(SystemHeap, 0, 2048);
2477
2478     if (!MCI_lpInstallNames)
2479         return FALSE;
2480
2481     /* FIXME: should do also some registry diving here ? */
2482     if (PROFILE_GetWineIniString("options", "mci", "", MCI_lpInstallNames, 2048) > 0) {
2483         TRACE("Wine => '%s' \n", ptr1);
2484         while ((ptr2 = strchr(ptr1, ':')) != 0) {
2485             *ptr2++ = 0;
2486             TRACE("---> '%s' \n", ptr1);
2487             MCI_InstalledCount++;
2488             ptr1 = ptr2;
2489         }
2490         MCI_InstalledCount++;
2491         TRACE("---> '%s' \n", ptr1);
2492         ptr1 += strlen(ptr1) + 1;
2493     } else {
2494         GetPrivateProfileStringA("mci", NULL, "", MCI_lpInstallNames, 2048, "SYSTEM.INI");
2495         while (strlen(ptr1) > 0) {
2496             TRACE("---> '%s' \n", ptr1);
2497             ptr1 += strlen(ptr1) + 1;
2498             MCI_InstalledCount++;
2499         }
2500     }
2501     return TRUE;
2502 }
2503