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