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