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