Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[wine.git] / multimedia / mcistring.c
blobb5af30e54047554ec55e36a968d5787cdad669c5
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MCI stringinterface
6 * Copyright 1995 Marcus Meissner
7 */
8 /* FIXME:
9 * + special commands of device drivers should be handled by those drivers
10 * + this current implementation does not allow commands like
11 * "capability <filename> can play" which is allowed by the MCI standard.
12 * + return value and their conversion to strings (including error codes)
13 * is not coherent with MCI standard.
14 * + digital video interface has not been throughoutfully tested
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22 #include <assert.h>
23 #include "multimedia.h"
24 #include "digitalv.h"
25 #include "heap.h"
26 #include "ldt.h"
27 #include "user.h"
28 #include "driver.h"
29 #include "callback.h"
30 #include "debug.h"
31 #include "xmalloc.h"
33 DEFAULT_DEBUG_CHANNEL(mci)
35 /* The reason why I just don't lowercase the keywords array in
36 * mciSendString is left as an exercise to the reader.
37 * (EP: For the blinds, like me, it's linked to file name handling
38 * which is case sensitive).
40 #define STRCMP(x, y) lstrcmpiA(x, y)
42 /* standard function parameters for all functions */
43 #define _MCISTR_PROTO_ \
44 WORD wDevID, WORD uDevTyp, LPSTR lpstrReturnString, \
45 UINT16 uReturnLength, LPCSTR dev, LPSTR* keywords, \
46 UINT16 nrofkeywords, DWORD dwFlags, HWND16 hwndCallback
48 /* copy string to return pointer including necessary checks
49 * for use in mciSendString()
51 #define _MCI_STR(s) \
52 do { \
53 TRACE(mci, "-> returns '%s'\n", s); \
54 if (lpstrReturnString) { \
55 lstrcpynA(lpstrReturnString, s, uReturnLength); \
56 TRACE(mci, "--> '%s'\n", lpstrReturnString); \
57 } \
58 } while(0)
60 static LPSTR _MCISTR_Unquote(LPSTR str)
62 if (str) {
63 int i, len = strlen(str);
65 if (len > 1 && str[0] == '"' && str[len-1] == '"') {
66 for (i = 1; i < len-1; i++) {
67 str[i - 1] = str[i];
69 str[len-2] = 0;
72 return str;
75 /* print a DWORD in the specified timeformat */
76 static void
77 _MCISTR_printtf(char *buf, UINT16 uDevType, DWORD timef, DWORD val)
79 *buf = '\0';
80 switch (timef) {
81 case MCI_FORMAT_MILLISECONDS:
82 case MCI_FORMAT_FRAMES:
83 case MCI_FORMAT_BYTES:
84 case MCI_FORMAT_SAMPLES:
85 case MCI_VD_FORMAT_TRACK:
86 /*case MCI_SEQ_FORMAT_SONGPTR: sameas MCI_VD_FORMAT_TRACK */
87 sprintf(buf, "%ld",val);
88 break;
89 case MCI_FORMAT_HMS:
90 /* well, the macros have the same content*/
91 /*FALLTRHOUGH*/
92 case MCI_FORMAT_MSF:
93 sprintf(buf, "%d:%d:%d",
94 MCI_HMS_HOUR(val),
95 MCI_HMS_MINUTE(val),
96 MCI_HMS_SECOND(val));
97 break;
98 case MCI_FORMAT_TMSF:
99 sprintf(buf, "%d:%d:%d:%d",
100 MCI_TMSF_TRACK(val),
101 MCI_TMSF_MINUTE(val),
102 MCI_TMSF_SECOND(val),
103 MCI_TMSF_FRAME(val));
104 break;
105 default:
106 FIXME(mci, "missing timeformat for %ld, report.\n", timef);
107 strcpy(buf, "0"); /* hmm */
108 break;
110 return;
112 /* possible different return types */
113 #define _MCISTR_int 1
114 #define _MCISTR_time 2
115 #define _MCISTR_bool 3
116 #define _MCISTR_tfname 4
117 #define _MCISTR_mode 5
118 #define _MCISTR_divtype 6
119 #define _MCISTR_seqtype 7
120 #define _MCISTR_vdmtype 8
121 #define _MCISTR_devtype 9
123 static void
124 _MCISTR_convreturn(int type, DWORD dwReturn, LPSTR lpstrReturnString,
125 WORD uReturnLength, WORD uDevTyp, int timef)
127 switch (type) {
128 case _MCISTR_vdmtype:
129 switch (dwReturn) {
130 case MCI_VD_MEDIA_CLV: _MCI_STR("CLV"); break;
131 case MCI_VD_MEDIA_CAV: _MCI_STR("CAV"); break;
132 default:
133 case MCI_VD_MEDIA_OTHER:_MCI_STR("other"); break;
135 break;
136 case _MCISTR_seqtype:
137 switch (dwReturn) {
138 case MCI_SEQ_NONE: _MCI_STR("none"); break;
139 case MCI_SEQ_SMPTE: _MCI_STR("smpte"); break;
140 case MCI_SEQ_FILE: _MCI_STR("file"); break;
141 case MCI_SEQ_MIDI: _MCI_STR("midi"); break;
142 default:FIXME(mci, "missing sequencer mode %ld\n", dwReturn);
144 break;
145 case _MCISTR_mode:
146 switch (dwReturn) {
147 case MCI_MODE_NOT_READY:_MCI_STR("not ready"); break;
148 case MCI_MODE_STOP: _MCI_STR("stopped"); break;
149 case MCI_MODE_PLAY: _MCI_STR("playing"); break;
150 case MCI_MODE_RECORD: _MCI_STR("recording"); break;
151 case MCI_MODE_SEEK: _MCI_STR("seeking"); break;
152 case MCI_MODE_PAUSE: _MCI_STR("paused"); break;
153 case MCI_MODE_OPEN: _MCI_STR("open"); break;
154 default:break;
156 break;
157 case _MCISTR_bool:
158 if (dwReturn)
159 _MCI_STR("true");
160 else
161 _MCI_STR("false");
162 break;
163 case _MCISTR_int:{
164 char buf[16];
165 sprintf(buf, "%ld", dwReturn);
166 _MCI_STR(buf);
167 break;
169 case _MCISTR_time: {
170 char buf[100];
171 _MCISTR_printtf(buf, uDevTyp, timef, dwReturn);
172 _MCI_STR(buf);
173 break;
175 case _MCISTR_tfname:
176 switch (timef) {
177 case MCI_FORMAT_MILLISECONDS: _MCI_STR("milliseconds"); break;
178 case MCI_FORMAT_FRAMES: _MCI_STR("frames"); break;
179 case MCI_FORMAT_BYTES: _MCI_STR("bytes"); break;
180 case MCI_FORMAT_SAMPLES: _MCI_STR("samples"); break;
181 case MCI_FORMAT_HMS: _MCI_STR("hms"); break;
182 case MCI_FORMAT_MSF: _MCI_STR("msf"); break;
183 case MCI_FORMAT_TMSF: _MCI_STR("tmsf"); break;
184 default:
185 FIXME(mci, "missing timefmt for %d, report.\n", timef);
186 break;
188 break;
189 case _MCISTR_divtype:
190 switch (dwReturn) {
191 case MCI_SEQ_DIV_PPQN: _MCI_STR("PPQN"); break;
192 case MCI_SEQ_DIV_SMPTE_24: _MCI_STR("SMPTE 24 frame"); break;
193 case MCI_SEQ_DIV_SMPTE_25: _MCI_STR("SMPTE 25 frame"); break;
194 case MCI_SEQ_DIV_SMPTE_30: _MCI_STR("SMPTE 30 frame"); break;
195 case MCI_SEQ_DIV_SMPTE_30DROP: _MCI_STR("SMPTE 30 frame drop");break;
197 case _MCISTR_devtype:
198 switch (dwReturn) {
199 case MCI_DEVTYPE_VCR: _MCI_STR("vcr"); break;
200 case MCI_DEVTYPE_VIDEODISC: _MCI_STR("videodisc"); break;
201 case MCI_DEVTYPE_CD_AUDIO: _MCI_STR("cd audio"); break;
202 case MCI_DEVTYPE_OVERLAY: _MCI_STR("overlay"); break;
203 case MCI_DEVTYPE_DAT: _MCI_STR("dat"); break;
204 case MCI_DEVTYPE_SCANNER: _MCI_STR("scanner"); break;
205 case MCI_DEVTYPE_ANIMATION: _MCI_STR("animation"); break;
206 case MCI_DEVTYPE_DIGITAL_VIDEO: _MCI_STR("digital video"); break;
207 case MCI_DEVTYPE_OTHER: _MCI_STR("other"); break;
208 case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio"); break;
209 case MCI_DEVTYPE_SEQUENCER: _MCI_STR("sequencer"); break;
210 default:FIXME(mci, "unknown device type %ld, report.\n",
211 dwReturn);break;
213 break;
214 default:
215 FIXME(mci, "unknown resulttype %d, report.\n", type);
216 break;
220 #define FLAG1(str, flag) \
221 if (!STRCMP(keywords[i], str)) { \
222 dwFlags |= flag; \
223 i++; \
224 continue; \
227 #define FLAG2(str1, str2, flag) \
228 if (!STRCMP(keywords[i], str1) && \
229 (i+1 < nrofkeywords) && \
230 !STRCMP(keywords[i+1], str2)) { \
231 dwFlags |= flag; \
232 i += 2; \
233 continue; \
236 /* All known subcommands are implemented in single functions to avoid
237 * bloat and a xxxx lines long mciSendString(). All commands are of the
238 * format MCISTR_Cmd(_MCISTR_PROTO_) where _MCISTR_PROTO_ is the above
239 * defined line of arguments. (This is just for easy enhanceability.)
240 * All functions return the MCIERR_ errorvalue as DWORD. Returnvalues
241 * for the calls are in lpstrReturnString (If I mention return values
242 * in function headers, I mean returnvalues in lpstrReturnString.)
243 * Integers are sprintf("%d")ed integers. Boolean values are
244 * "true" and "false".
245 * timeformat depending values are "%d" "%d:%d" "%d:%d:%d" "%d:%d:%d:%d"
246 * FIXME: is above line correct?
248 * Preceding every function is a list of implemented/known arguments.
249 * Feel free to add missing arguments.
254 * Opens the specified MCI driver.
255 * Arguments: <name>
256 * Optional:
257 * "shareable"
258 * "alias <aliasname>"
259 * "element <elementname>"
260 * Additional:
261 * waveform audio:
262 * "buffer <nrBytesPerSec>"
263 * Animation:
264 * "nostatic" increaste nr of nonstatic colours
265 * "parent <windowhandle>"
266 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
267 * "style child" WS_CHILD
268 * "style overlap" WS_OVERLAPPED
269 * "style popup" WS_POPUP
270 * Overlay:
271 * "parent <windowhandle>"
272 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
273 * "style child" WS_CHILD
274 * "style overlap" WS_OVERLAPPED
275 * "style popup" WS_POPUP
276 * Returns nothing.
278 static DWORD
279 MCISTR_Open(_MCISTR_PROTO_)
281 int res, i;
282 char* s;
283 union U {
284 MCI_OPEN_PARMSA openParams;
285 MCI_WAVE_OPEN_PARMSA waveopenParams;
286 MCI_ANIM_OPEN_PARMSA animopenParams;
287 MCI_OVLY_OPEN_PARMSA ovlyopenParams;
288 MCI_DGV_OPEN_PARMSA dgvopenParams;
290 union U* pU = xmalloc(sizeof(union U));
292 pU->openParams.lpstrElementName = NULL;
293 s = strchr(dev, '!');
294 if (s != NULL) {
295 *s++ = '\0';
296 pU->openParams.lpstrElementName = strdup(s);
297 dwFlags |= MCI_OPEN_ELEMENT;
299 for (i = 0; i < nrofkeywords; ) {
300 if ((!STRCMP(keywords[i], "type")) && (i < nrofkeywords-1)) {
301 pU->openParams.lpstrElementName = strdup(dev);
302 dwFlags |= MCI_OPEN_ELEMENT;
303 dev = keywords[i+1];
304 /* FIXME: isn't there a memory leak here ? keyword+i ? */
305 memcpy(keywords+i, keywords+(i+2), (nrofkeywords-i-2) * sizeof(char*));
306 nrofkeywords -= 2;
307 i += 2;
308 continue;
310 i++;
312 CharUpperA((char*)dev);
313 uDevTyp = MCI_GetDevTypeFromString(dev);
314 if (uDevTyp == 0) {
315 free(pU->openParams.lpstrElementName);
316 free(pU);
317 return MCIERR_INVALID_DEVICE_NAME;
320 pU->openParams.dwCallback = hwndCallback;
321 pU->openParams.wDeviceID = wDevID;
322 pU->ovlyopenParams.dwStyle = 0;
323 pU->animopenParams.dwStyle = 0;
324 pU->openParams.lpstrDeviceType = strdup(dev);
325 pU->openParams.lpstrAlias = NULL;
326 dwFlags |= MCI_OPEN_TYPE;
327 for (i = 0; i < nrofkeywords; ) {
328 FLAG1("shareable", MCI_OPEN_SHAREABLE);
329 if (!STRCMP(keywords[i], "alias") && (i+1 < nrofkeywords)) {
330 dwFlags |= MCI_OPEN_ALIAS;
331 pU->openParams.lpstrAlias = strdup(keywords[i+1]);
332 i += 2;
333 continue;
335 if (!STRCMP(keywords[i], "element") && (i+1 < nrofkeywords)) {
336 dwFlags |= MCI_OPEN_ELEMENT;
337 assert(pU->openParams.lpstrElementName == NULL);
338 pU->openParams.lpstrElementName = strdup(keywords[i+1]);
339 i += 2;
340 continue;
342 switch (uDevTyp) {
343 case MCI_DEVTYPE_ANIMATION:
344 FLAG1("nostatic", MCI_ANIM_OPEN_NOSTATIC);
345 if (!STRCMP(keywords[i], "parent") && (i+1 < nrofkeywords)) {
346 dwFlags |= MCI_ANIM_OPEN_PARENT;
347 sscanf(keywords[i+1], "%u", &(pU->animopenParams.hWndParent));
348 i += 2;
349 continue;
351 if (!STRCMP(keywords[i], "style") && (i+1 < nrofkeywords)) {
352 DWORD st;
354 dwFlags |= MCI_ANIM_OPEN_WS;
355 if (!STRCMP(keywords[i+1], "popup")) {
356 pU->animopenParams.dwStyle |= WS_POPUP;
357 } else if (!STRCMP(keywords[i+1], "overlap")) {
358 pU->animopenParams.dwStyle |= WS_OVERLAPPED;
359 } else if (!STRCMP(keywords[i+1], "child")) {
360 pU->animopenParams.dwStyle |= WS_CHILD;
361 } else if (sscanf(keywords[i+1], "%ld", &st)) {
362 pU->animopenParams.dwStyle |= st;
363 } else
364 FIXME(mci, "unknown 'style' keyword %s, please report.\n", keywords[i+1]);
365 i += 2;
366 continue;
368 break;
369 case MCI_DEVTYPE_DIGITAL_VIDEO:
370 FLAG1("nostatic", MCI_ANIM_OPEN_NOSTATIC);
371 if (!STRCMP(keywords[i], "parent") && (i+1 < nrofkeywords)) {
372 dwFlags |= MCI_DGV_OPEN_PARENT;
373 sscanf(keywords[i+1], "%u", &(pU->dgvopenParams.hWndParent));
374 i += 2;
375 continue;
377 if (!STRCMP(keywords[i], "style") && (i+1 < nrofkeywords)) {
378 DWORD st;
380 dwFlags |= MCI_DGV_OPEN_WS;
381 if (!STRCMP(keywords[i+1], "popup")) {
382 pU->dgvopenParams.dwStyle |= WS_POPUP;
383 } else if (!STRCMP(keywords[i+1], "overlap")) {
384 pU->dgvopenParams.dwStyle |= WS_OVERLAPPED;
385 } else if (!STRCMP(keywords[i+1], "child")) {
386 pU->dgvopenParams.dwStyle |= WS_CHILD;
387 } else if (sscanf(keywords[i+1], "%ld", &st)) {
388 pU->dgvopenParams.dwStyle |= st;
389 } else
390 FIXME(mci, "unknown 'style' keyword %s, please report.\n", keywords[i+1]);
391 i += 2;
392 continue;
394 break;
395 case MCI_DEVTYPE_WAVEFORM_AUDIO:
396 if (!STRCMP(keywords[i], "buffer") && (i+1 < nrofkeywords)) {
397 dwFlags |= MCI_WAVE_OPEN_BUFFER;
398 sscanf(keywords[i+1], "%ld", &(pU->waveopenParams.dwBufferSeconds));
400 break;
401 case MCI_DEVTYPE_OVERLAY:
402 /* looks just like anim, but without NOSTATIC */
403 if (!STRCMP(keywords[i], "parent") && (i+1 < nrofkeywords)) {
404 dwFlags |= MCI_OVLY_OPEN_PARENT;
405 sscanf(keywords[i+1], "%u", &(pU->ovlyopenParams.hWndParent));
406 i += 2;
407 continue;
409 if (!STRCMP(keywords[i], "style") && (i+1 < nrofkeywords)) {
410 DWORD st;
412 dwFlags |= MCI_OVLY_OPEN_WS;
413 if (!STRCMP(keywords[i+1], "popup")) {
414 pU->ovlyopenParams.dwStyle |= WS_POPUP;
415 } else if (!STRCMP(keywords[i+1], "overlap")) {
416 pU->ovlyopenParams.dwStyle |= WS_OVERLAPPED;
417 } else if (!STRCMP(keywords[i+1], "child")) {
418 pU->ovlyopenParams.dwStyle |= WS_CHILD;
419 } else if (sscanf(keywords[i+1], "%ld", &st)) {
420 pU->ovlyopenParams.dwStyle |= st;
421 } else
422 FIXME(mci, "unknown 'style' keyword %s, please report.\n", keywords[i+1]);
423 i += 2;
424 continue;
426 break;
428 FIXME(mci, "unknown parameter passed %s, please report.\n",
429 keywords[i]);
430 i++;
433 _MCISTR_Unquote(pU->openParams.lpstrElementName);
435 res = mciSendCommandA(0, MCI_OPEN, dwFlags, (DWORD)pU);
437 free(pU->openParams.lpstrElementName);
438 free(pU->openParams.lpstrDeviceType);
439 free(pU->openParams.lpstrAlias);
440 free(pU);
441 return res;
444 /* A helper function for a lot of others ...
445 * for instance status/play/record/seek etc.
447 DWORD
448 _MCISTR_determine_timeformat(LPCSTR dev, WORD wDevID, WORD uDevTyp, int *timef)
450 int res;
451 DWORD dwFlags = MCI_STATUS_ITEM;
452 LPMCI_STATUS_PARMS statusParams = xmalloc(sizeof(MCI_STATUS_PARMS));
454 if (!statusParams) return 0;
455 statusParams->dwItem = MCI_STATUS_TIME_FORMAT;
456 statusParams->dwReturn = 0;
457 res = mciSendCommandA(wDevID, MCI_STATUS, dwFlags, (DWORD)statusParams);
459 if (res == 0) *timef = statusParams->dwReturn;
460 free(statusParams);
461 return res;
464 /* query status of MCI drivers
465 * Arguments:
466 * Required:
467 * "mode" - returns "not ready" "paused" "playing" "stopped" "open"
468 * "parked" "recording" "seeking" ....
469 * Basics:
470 * "current track" - returns current track as integer
471 * "length [track <nr>]" - returns length [of track <nr>] in current
472 * timeformat
473 * "number of tracks" - returns number of tracks as integer
474 * "position [track <nr>]" - returns position [in track <nr>] in current
475 * timeformat
476 * "ready" - checks if device is ready to play, -> bool
477 * "start position" - returns start position in timeformat
478 * "time format" - returns timeformat (list of possible values:
479 * "ms" "msf" "milliseconds" "hmsf" "tmsf" "frames"
480 * "bytes" "samples" "hms")
481 * "media present" - returns if media is present as bool
482 * Animation:
483 * "forward" - returns "true" if device is playing forwards
484 * "speed" - returns speed for device
485 * "palette handle" - returns palette handle
486 * "window handle" - returns window handle
487 * "stretch" - returns stretch bool
488 * MIDI sequencer:
489 * "division type" - ? returns "PPQN" "SMPTE 24 frame"
490 * "SMPTE 25 frame" "SMPTE 30 frame" "SMPTE 30 drop frame"
491 * "tempo" - current tempo in (PPQN? speed in frames, SMPTE*? speed in hsmf)
492 * "offset" - offset in dito.
493 * "port" - midi port as integer
494 * "slave" - slave device ("midi", "file", "none", "smpte")
495 * "master" - masterdevice (dito.)
496 * Overlay:
497 * "window handle" - see animation
498 * "stretch" - dito
499 * Video Disc:
500 * "speed" - speed as integer
501 * "forward" - returns bool (when playing forward)
502 * "side" - returns 1 or 2
503 * "media type" - returns "CAV" "CLV" "other"
504 * "disc size" - returns "8" or "12"
505 * WAVEFORM audio:
506 * "input" - base queries on input set
507 * "output" - base queries on output set
508 * "format tag" - return integer format tag
509 * "channels" - return integer nr of channels
510 * "bytespersec" - return average nr of bytes/sec
511 * "samplespersec" - return nr of samples per sec
512 * "bitspersample" - return bitspersample
513 * "alignment" - return block alignment
514 * "level" - return level?
515 * Digitalvideo:
516 * "audio"
517 * "audio alignment"
518 * "audio bitspersample"
519 * "audio breaks"
520 * "audio bytespersec"
521 * "audio input"
522 * "audio record"
523 * "audio source"
524 * "audio samplespersec"
525 * "audio stream"
526 * "bass"
527 * "bitsperpel"
528 * "brightness"
529 * "color"
530 * "contrast"
531 * "disk space drive"
532 * "file completion"
533 * "file format "
534 * "file mode"
535 * "forward"
536 * "frames skipped"
537 * "gamma"
538 * "input"
539 * "left volume"
540 * "media present"
541 * "mode"
542 * "monitor"
543 * "monitor method"
544 * "nominal"
545 * "nominal frame rate"
546 * "nominal record frame rate"
547 * "output"
548 * "palette handle"
549 * "pause mode"
550 * "play speed"
551 * "record frame rate"
552 * "reference frame"
553 * "reserved size"
554 * "right volume"
555 * "seek exactly"
556 * "sharpness"
557 * "smpte"
558 * "speed"
559 * "still file format"
560 * "tint"
561 * "treble"
562 * "unsaved"
563 * "video"
564 * "video key index"
565 * "video key color"
566 * "video record"
567 * "video source"
568 * "video source number"
569 * "video stream"
570 * "volume"
571 * "window handle"
572 * "window visible"
573 * "window minimized"
574 * "window maximized"
577 #define ITEM1(str, item, xtype) \
578 if (!STRCMP(keywords[i], str)) { \
579 pU->statusParams.dwItem = item; \
580 type = xtype; \
581 i++; \
582 continue; \
584 #define ITEM2(str1, str2, item, xtype) \
585 if ( !STRCMP(keywords[i], str1) && \
586 (i+1 < nrofkeywords) && \
587 !STRCMP(keywords[i+1], str2)) { \
588 pU->statusParams.dwItem = item; \
589 type = xtype; \
590 i += 2; \
591 continue; \
593 #define ITEM3(str1, str2, str3, item, xtype) \
594 if ( !STRCMP(keywords[i], str1) && \
595 (i+2 < nrofkeywords) && \
596 !STRCMP(keywords[i+1], str2) && \
597 !STRCMP(keywords[i+2], str3)) { \
598 pU->statusParams.dwItem = item; \
599 type = xtype; \
600 i += 3; \
601 continue; \
603 #define ITEM4(str1, str2, str3, str4, item, xtype) \
604 if ( !STRCMP(keywords[i], str1) && \
605 (i+3 < nrofkeywords) && \
606 !STRCMP(keywords[i+1], str2) && \
607 !STRCMP(keywords[i+2], str3) && \
608 !STRCMP(keywords[i+3], str4)) { \
609 pU->statusParams.dwItem = item; \
610 type = xtype; \
611 i += 4; \
612 continue; \
615 static DWORD
616 MCISTR_Status(_MCISTR_PROTO_) {
617 union U {
618 MCI_STATUS_PARMS statusParams;
619 MCI_DGV_STATUS_PARMSA dgvstatusParams;
621 union U* pU = xmalloc(sizeof(union U));
622 int type = 0, i, res, timef;
624 pU->statusParams.dwCallback = hwndCallback;
625 dwFlags |= MCI_STATUS_ITEM;
626 res = _MCISTR_determine_timeformat(dev, wDevID, uDevTyp, &timef);
627 if (res) return res;
629 pU->statusParams.dwReturn = 0;
630 pU->statusParams.dwItem = 0;
632 for (i = 0; i < nrofkeywords; ) {
633 if (!STRCMP(keywords[i], "track") && (i+1 < nrofkeywords)) {
634 sscanf(keywords[i+1], "%ld", &(pU->statusParams.dwTrack));
635 dwFlags |= MCI_TRACK;
636 i += 2;
637 continue;
639 FLAG1("start", MCI_STATUS_START);
640 /* generic things */
641 ITEM2("current", "track", MCI_STATUS_CURRENT_TRACK, _MCISTR_time);
642 ITEM2("time", "format", MCI_STATUS_TIME_FORMAT, _MCISTR_tfname);
643 ITEM1("ready", MCI_STATUS_READY, _MCISTR_bool);
644 ITEM1("mode", MCI_STATUS_MODE, _MCISTR_mode);
645 ITEM3("number", "of", "tracks", MCI_STATUS_NUMBER_OF_TRACKS, _MCISTR_int);
646 ITEM1("length", MCI_STATUS_LENGTH, _MCISTR_time);
647 ITEM1("position", MCI_STATUS_POSITION, _MCISTR_time);
648 ITEM2("media", "present", MCI_STATUS_MEDIA_PRESENT, _MCISTR_bool);
650 switch (uDevTyp) {
651 case MCI_DEVTYPE_ANIMATION:
652 ITEM2("palette", "handle", MCI_ANIM_STATUS_HPAL, _MCISTR_int);
653 ITEM2("window", "handle", MCI_ANIM_STATUS_HWND, _MCISTR_int);
654 ITEM1("stretch", MCI_ANIM_STATUS_STRETCH, _MCISTR_bool);
655 ITEM1("speed", MCI_ANIM_STATUS_SPEED, _MCISTR_int);
656 ITEM1("forward", MCI_ANIM_STATUS_FORWARD, _MCISTR_bool);
657 break;
658 case MCI_DEVTYPE_SEQUENCER:
659 /* just completing the list, not working correctly */
660 ITEM2("division", "type", MCI_SEQ_STATUS_DIVTYPE, _MCISTR_divtype);
661 /* tempo ... PPQN in frames/second, SMPTE in hmsf */
662 ITEM1("tempo", MCI_SEQ_STATUS_TEMPO, _MCISTR_int);
663 ITEM1("port", MCI_SEQ_STATUS_PORT, _MCISTR_int);
664 ITEM1("slave", MCI_SEQ_STATUS_SLAVE, _MCISTR_seqtype);
665 ITEM1("master", MCI_SEQ_STATUS_SLAVE, _MCISTR_seqtype);
666 /* offset ... PPQN in frames/second, SMPTE in hmsf */
667 ITEM1("offset", MCI_SEQ_STATUS_SLAVE, _MCISTR_time);
668 break;
669 case MCI_DEVTYPE_OVERLAY:
670 ITEM2("window", "handle", MCI_OVLY_STATUS_HWND, _MCISTR_int);
671 ITEM1("stretch", MCI_OVLY_STATUS_STRETCH, _MCISTR_bool);
672 break;
673 case MCI_DEVTYPE_VIDEODISC:
674 ITEM1("speed", MCI_VD_STATUS_SPEED, _MCISTR_int);
675 ITEM1("forward", MCI_VD_STATUS_FORWARD, _MCISTR_bool);
676 ITEM1("side", MCI_VD_STATUS_SIDE, _MCISTR_int);
677 ITEM2("media", "type", MCI_VD_STATUS_SIDE, _MCISTR_vdmtype);
678 /* returns 8 or 12 */
679 ITEM2("disc", "size", MCI_VD_STATUS_DISC_SIZE, _MCISTR_int);
680 break;
681 case MCI_DEVTYPE_WAVEFORM_AUDIO:
682 /* I am not quite sure if foll. 2 lines are right. */
683 FLAG1("input", MCI_WAVE_INPUT);
684 FLAG1("output", MCI_WAVE_OUTPUT);
686 ITEM2("format", "tag", MCI_WAVE_STATUS_FORMATTAG, _MCISTR_int);
687 ITEM1("channels", MCI_WAVE_STATUS_CHANNELS, _MCISTR_int);
688 ITEM1("bytespersec", MCI_WAVE_STATUS_AVGBYTESPERSEC, _MCISTR_int);
689 ITEM1("samplespersec", MCI_WAVE_STATUS_SAMPLESPERSEC, _MCISTR_int);
690 ITEM1("bitspersample", MCI_WAVE_STATUS_BITSPERSAMPLE, _MCISTR_int);
691 ITEM1("alignment", MCI_WAVE_STATUS_BLOCKALIGN, _MCISTR_int);
692 ITEM1("level", MCI_WAVE_STATUS_LEVEL, _MCISTR_int);
693 break;
694 case MCI_DEVTYPE_DIGITAL_VIDEO:
695 ITEM1("audio", MCI_DGV_STATUS_AUDIO, _MCISTR_bool); /* FIXME? doc says MCI_ON/MCI_OFF */
696 ITEM2("audio", "alignment", MCI_DGV_STATUS_BLOCKALIGN, _MCISTR_int);
697 ITEM2("audio", "bitspersample", MCI_DGV_STATUS_BITSPERSAMPLE, _MCISTR_int);
698 /* EPP ITEM2("audio", "breaks", MCI_AVI_STATUS_AUDIO_BREAKS, _MCISTR_int); */
699 ITEM2("audio", "bytespersec", MCI_DGV_STATUS_AVGBYTESPERSEC, _MCISTR_int);
700 ITEM2("audio", "input", MCI_DGV_STATUS_AUDIO_INPUT, _MCISTR_int);
701 ITEM2("audio", "record", MCI_DGV_STATUS_AUDIO_RECORD, _MCISTR_bool); /* FIXME? doc says MCI_ON/MCI_OFF */
702 ITEM3("audio", "source", "number", MCI_DGV_STATUS_AUDIO_SOURCE, _MCISTR_int);
703 /* FIXME: ITEM2("audio", "source", MCI_DGV_STATUS_AUDIO_SOURCE, _MCISTR_dgvaudiosource); */
704 /* EPP ITEM2("audio", "samplespersec", MCI_DGV_STATUS_SAMPLESPERSECOND, _MCISTR_int); */
705 ITEM2("audio", "stream", MCI_DGV_STATUS_AUDIO_STREAM, _MCISTR_int);
706 ITEM1("bass", MCI_DGV_STATUS_BASS, _MCISTR_int);
707 ITEM1("bitsperpel", MCI_DGV_STATUS_BITSPERPEL, _MCISTR_int);
708 ITEM1("brightness", MCI_DGV_STATUS_BRIGHTNESS, _MCISTR_int);
709 ITEM1("color", MCI_DGV_STATUS_COLOR, _MCISTR_int);
710 ITEM1("contrast", MCI_DGV_STATUS_CONTRAST, _MCISTR_int);
711 /* EPP * "disk space drive" FIXME */
712 ITEM2("file", "completion", MCI_DGV_STATUS_FILE_COMPLETION, _MCISTR_int);
713 /* EPP ITEM2("file", "format", MCI_DGV_STATUS_FILEFORMAT, _MCISTR_???); */
714 /* EPP ITEM2("file", "mode", MCI_DGV_STATUS_FILE_MODE, _MCISTR_gdvfileformat); */
715 ITEM1("forward", MCI_DGV_STATUS_FORWARD, _MCISTR_bool);
716 /* EPP ITEM2("frames", "skipped", MCI_AVI_STATUS_FRAMES_SKIPPED, _MCISTR_int); */
717 ITEM1("gamma", MCI_DGV_STATUS_GAMMA, _MCISTR_int);
718 ITEM2("input", "bass", MCI_DGV_STATUS_BASS|MCI_DGV_STATUS_INPUT, _MCISTR_int);
719 ITEM2("input", "brightness", MCI_DGV_STATUS_BRIGHTNESS|MCI_DGV_STATUS_INPUT, _MCISTR_int);
720 ITEM2("input", "color", MCI_DGV_STATUS_COLOR|MCI_DGV_STATUS_INPUT, _MCISTR_int);
721 ITEM2("input", "contrast", MCI_DGV_STATUS_CONTRAST|MCI_DGV_STATUS_INPUT, _MCISTR_int);
722 ITEM2("input", "gamma", MCI_DGV_STATUS_GAMMA|MCI_DGV_STATUS_INPUT, _MCISTR_int);
723 ITEM2("input", "sharpness", MCI_DGV_STATUS_SHARPNESS|MCI_DGV_STATUS_INPUT, _MCISTR_int);
724 ITEM2("input", "tint", MCI_DGV_STATUS_TINT|MCI_DGV_STATUS_INPUT, _MCISTR_int);
725 ITEM2("input", "treble", MCI_DGV_STATUS_TREBLE|MCI_DGV_STATUS_INPUT, _MCISTR_int);
727 ITEM2("left", "volume", MCI_DGV_STATUS_VOLUME|MCI_DGV_STATUS_LEFT, _MCISTR_int);
728 ITEM2("media", "present", MCI_STATUS_MEDIA_PRESENT, _MCISTR_bool);
729 /* EPP ITEM2("monitor", "method", MCI_DGV_STATUS_MONITOR_METHOD, _MCISTR_monitor); */
730 /* EPP ITEM1("monitor", MCI_DGV_STATUS_MONITOR, _MCISTR_monitor2); */
731 ITEM2("nominal", "bass", MCI_DGV_STATUS_BASS|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
732 ITEM2("nominal", "brightness", MCI_DGV_STATUS_BRIGHTNESS|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
733 ITEM2("nominal", "color", MCI_DGV_STATUS_COLOR|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
734 ITEM2("nominal", "contrast", MCI_DGV_STATUS_CONTRAST|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
735 ITEM2("nominal", "gamma", MCI_DGV_STATUS_GAMMA|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
736 ITEM2("nominal", "sharpness", MCI_DGV_STATUS_SHARPNESS|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
737 ITEM2("nominal", "tint", MCI_DGV_STATUS_TINT|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
738 ITEM2("nominal", "treble", MCI_DGV_STATUS_TREBLE|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
739 ITEM3("nominal", "frame", "rate", MCI_DGV_STATUS_FRAME_RATE|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
740 ITEM4("nominal", "record", "frame", "rate", MCI_DGV_STATUS_FRAME_RATE|MCI_DGV_STATUS_RECORD|MCI_DGV_STATUS_NOMINAL, _MCISTR_int);
741 ITEM2("output", "bass", MCI_DGV_STATUS_BASS|MCI_DGV_STATUS_OUTPUT, _MCISTR_int);
742 ITEM2("output", "brightness", MCI_DGV_STATUS_BRIGHTNESS|MCI_DGV_STATUS_OUTPUT, _MCISTR_int);
743 ITEM2("output", "color", MCI_DGV_STATUS_COLOR|MCI_DGV_STATUS_OUTPUT, _MCISTR_int);
744 ITEM2("output", "contrast", MCI_DGV_STATUS_CONTRAST|MCI_DGV_STATUS_OUTPUT, _MCISTR_int);
745 ITEM2("output", "gamma", MCI_DGV_STATUS_GAMMA|MCI_DGV_STATUS_OUTPUT, _MCISTR_int);
746 ITEM2("output", "sharpness", MCI_DGV_STATUS_SHARPNESS|MCI_DGV_STATUS_OUTPUT, _MCISTR_int);
747 ITEM2("output", "tint", MCI_DGV_STATUS_TINT|MCI_DGV_STATUS_OUTPUT, _MCISTR_int);
748 ITEM2("output", "treble", MCI_DGV_STATUS_TREBLE|MCI_DGV_STATUS_OUTPUT, _MCISTR_int);
749 ITEM2("palette", "handle", MCI_DGV_STATUS_HPAL, _MCISTR_int); /* FIXME? */
750 ITEM2("pause", "mode", MCI_DGV_STATUS_PAUSE_MODE, _MCISTR_bool); /* FIXME */
751 /* EPP ITEM2("play", "speed", MCI_AVI_STATUS_LAST_PLAY_SPEED, _MCISTR_int); */
752 ITEM3("record", "frame", "rate", MCI_DGV_STATUS_FRAME_RATE|MCI_DGV_STATUS_RECORD, _MCISTR_int);
753 ITEM2("reference", "frame", MCI_DGV_STATUS_FRAME_RATE, _MCISTR_int); /* FIXME */
754 ITEM2("reserved", "size", MCI_DGV_STATUS_SIZE, _MCISTR_int);
755 ITEM2("right", "volume", MCI_DGV_STATUS_VOLUME|MCI_DGV_STATUS_RIGHT, _MCISTR_int);
756 ITEM2("seek", "exactly", MCI_DGV_STATUS_SEEK_EXACTLY, _MCISTR_bool);
757 ITEM1("sharpness", MCI_DGV_STATUS_SHARPNESS, _MCISTR_int);
758 /* EPP ITEM1("smpte", MCI_DGV_STATUS_SMPTE, _MCISTR_smpte); */
759 /* EPP ITEM1("speed", MCI_DGV_STATUS_SPEED, _MCISTR_speed); */
760 /* EPP ITEM3("still", "file", "format", MCI_DGV_STATUS_STILL_FILEFORMAT, _MCISTR_???); */
761 ITEM1("tint", MCI_DGV_STATUS_TINT, _MCISTR_int);
762 ITEM1("treble", MCI_DGV_STATUS_TREBLE, _MCISTR_int);
763 ITEM1("unsaved", MCI_DGV_STATUS_UNSAVED, _MCISTR_bool);
764 ITEM3("video", "key", "index", MCI_DGV_STATUS_KEY_INDEX, _MCISTR_int);
765 ITEM3("video", "key", "color", MCI_DGV_STATUS_KEY_COLOR, _MCISTR_bool);
766 ITEM2("video", "record", MCI_DGV_STATUS_VIDEO_RECORD, _MCISTR_bool); /* FIXME MCI_ON/OFF */
767 ITEM3("video", "source", "number", MCI_DGV_STATUS_VIDEO_SOURCE, _MCISTR_int);
768 /* EPP ITEM2("video", "source", MCI_DGV_STATUS_VIDEO_SOURCE, _MCISTR_videosrctype); */
769 ITEM2("video", "stream", MCI_DGV_STATUS_VIDEO_STREAM, _MCISTR_int);
770 ITEM1("video", MCI_DGV_STATUS_VIDEO, _MCISTR_bool); /* FIXME MCI_ON/OFF */
771 ITEM1("volume", MCI_DGV_STATUS_VOLUME, _MCISTR_int);
772 ITEM2("window", "handle", MCI_DGV_STATUS_HWND, _MCISTR_int);
773 ITEM2("window", "visible", MCI_DGV_STATUS_WINDOW_VISIBLE, _MCISTR_bool);
774 ITEM2("window", "minimized", MCI_DGV_STATUS_WINDOW_MINIMIZED, _MCISTR_bool);
775 ITEM2("window", "maximized",MCI_DGV_STATUS_WINDOW_MAXIMIZED , _MCISTR_bool);
776 break;
778 FIXME(mci, "unknown keyword '%s'\n", keywords[i]);
779 i++;
781 if (!pU->statusParams.dwItem)
782 return MCIERR_MISSING_STRING_ARGUMENT;
784 res = mciSendCommandA(wDevID, MCI_STATUS, dwFlags, (DWORD)pU);
786 if (res == 0)
787 _MCISTR_convreturn(type, pU->statusParams.dwReturn, lpstrReturnString, uReturnLength, uDevTyp, timef);
788 free(pU);
789 return res;
791 #undef ITEM1
792 #undef ITEM2
793 #undef ITEM3
794 #undef ITEM4
796 /* set specified parameters in respective MCI drivers
797 * Arguments:
798 * "door open" eject media or somesuch
799 * "door close" load media
800 * "time format <timeformatname>" "ms" "milliseconds" "msf" "hmsf"
801 * "tmsf" "SMPTE 24" "SMPTE 25" "SMPTE 30"
802 * "SMPTE drop 30"
803 * "audio [all|left|right] [on|off]" sets specified audiochannel on or off
804 * "video [on|off]" sets video on/off
805 * Waveform audio:
806 * "formattag pcm" sets format to pcm
807 * "formattag <nr>" sets integer formattag value
808 * "any input" accept input from any known source
809 * "any output" output to any known destination
810 * "input <nr>" input from source <nr>
811 * "output <nr>" output to destination <nr>
812 * "channels <nr>" sets nr of channels
813 * "bytespersec <nr>" sets average bytes per second
814 * "samplespersec <nr>" sets average samples per second (1 sample can
815 * be 2 bytes!)
816 * "alignment <nr>" sets the blockalignment to <nr>
817 * "bitspersample <nr>" sets the nr of bits per sample
818 * Sequencer:
819 * "master [midi|file|smpte|none]" sets the midi master device
820 * "slave [midi|file|smpte|none]" sets the midi master device
821 * "port mapper" midioutput to portmapper
822 * "port <nr>" midioutput to specified port
823 * "tempo <nr>" tempo of track (depends on timeformat/divtype)
824 * "offset <nr>" start offset?
826 static DWORD
827 MCISTR_Set(_MCISTR_PROTO_) {
828 union U {
829 MCI_SET_PARMS setParams;
830 MCI_WAVE_SET_PARMS wavesetParams;
831 MCI_SEQ_SET_PARMS seqsetParams;
833 union U* pU = xmalloc(sizeof(union U));
834 int i, res;
836 pU->setParams.dwCallback = hwndCallback;
838 for (i = 0; i < nrofkeywords; ) {
839 FLAG2("door", "open", MCI_SET_DOOR_OPEN);
840 FLAG2("door", "closed", MCI_SET_DOOR_CLOSED);
842 if (!STRCMP(keywords[i], "time") && (i+2 < nrofkeywords) && !STRCMP(keywords[i+1], "format")) {
843 dwFlags |= MCI_SET_TIME_FORMAT;
845 /* FIXME:is this a shortcut for milliseconds or
846 * minutes:seconds? */
847 if (!STRCMP(keywords[i+2], "ms"))
848 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
850 if (!STRCMP(keywords[i+2], "milliseconds"))
851 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
852 if (!STRCMP(keywords[i+2], "msf"))
853 pU->setParams.dwTimeFormat = MCI_FORMAT_MSF;
854 if (!STRCMP(keywords[i+2], "hms"))
855 pU->setParams.dwTimeFormat = MCI_FORMAT_HMS;
856 if (!STRCMP(keywords[i+2], "frames"))
857 pU->setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
858 if (!STRCMP(keywords[i+2], "track"))
859 pU->setParams.dwTimeFormat = MCI_VD_FORMAT_TRACK;
860 if (!STRCMP(keywords[i+2], "bytes"))
861 pU->setParams.dwTimeFormat = MCI_FORMAT_BYTES;
862 if (!STRCMP(keywords[i+2], "samples"))
863 pU->setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
864 if (!STRCMP(keywords[i+2], "tmsf"))
865 pU->setParams.dwTimeFormat = MCI_FORMAT_TMSF;
866 if ( !STRCMP(keywords[i+2], "song") &&
867 (i+3 < nrofkeywords) &&
868 !STRCMP(keywords[i+3], "pointer")
870 pU->setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR;
871 if (!STRCMP(keywords[i+2], "smpte") && (i+3 < nrofkeywords)) {
872 if (!STRCMP(keywords[i+3], "24"))
873 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
874 if (!STRCMP(keywords[i+3], "25"))
875 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
876 if (!STRCMP(keywords[i+3], "30"))
877 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
878 if (!STRCMP(keywords[i+3], "drop") && (i+4 < nrofkeywords) && !STRCMP(keywords[i+4], "30")) {
879 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
880 i++;
882 i++;
883 /*FALLTHROUGH*/
885 i += 3;
886 continue;
888 if (!STRCMP(keywords[i], "audio") && (i+1 < nrofkeywords)) {
889 dwFlags |= MCI_SET_AUDIO;
890 if (!STRCMP(keywords[i+1], "all"))
891 pU->setParams.dwAudio = MCI_SET_AUDIO_ALL;
892 if (!STRCMP(keywords[i+1], "left"))
893 pU->setParams.dwAudio = MCI_SET_AUDIO_LEFT;
894 if (!STRCMP(keywords[i+1], "right"))
895 pU->setParams.dwAudio = MCI_SET_AUDIO_RIGHT;
896 i += 2;
897 continue;
899 FLAG1("video", MCI_SET_VIDEO);
900 FLAG1("on", MCI_SET_ON);
901 FLAG1("off", MCI_SET_OFF);
902 switch (uDevTyp) {
903 case MCI_DEVTYPE_WAVEFORM_AUDIO:
904 FLAG2("any", "input", MCI_WAVE_SET_ANYINPUT);
905 FLAG2("any", "output", MCI_WAVE_SET_ANYOUTPUT);
907 if ( !STRCMP(keywords[i], "formattag") &&
908 (i+1 < nrofkeywords) &&
909 !STRCMP(keywords[i+1], "pcm")
911 dwFlags |= MCI_WAVE_SET_FORMATTAG;
912 pU->wavesetParams.wFormatTag = WAVE_FORMAT_PCM;
913 i += 2;
914 continue;
917 /* <keyword> <integer> */
918 #define WII(str,flag,fmt,element) \
919 if (!STRCMP(keywords[i], str) && \
920 (i+1 < nrofkeywords)) { \
921 sscanf(keywords[i+1], fmt, \
922 &(pU->wavesetParams. element)); \
923 dwFlags |= flag; \
924 i += 2; \
925 continue; \
927 WII("formattag", MCI_WAVE_SET_FORMATTAG, "%u", wFormatTag);
928 WII("channels", MCI_WAVE_SET_CHANNELS, "%u", nChannels);
929 WII("bytespersec", MCI_WAVE_SET_AVGBYTESPERSEC, "%lu", nAvgBytesPerSec);
930 WII("samplespersec", MCI_WAVE_SET_SAMPLESPERSEC, "%lu", nSamplesPerSec);
931 WII("alignment", MCI_WAVE_SET_BLOCKALIGN, "%u", nBlockAlign);
932 WII("bitspersample", MCI_WAVE_SET_BITSPERSAMPLE, "%u", wBitsPerSample);
933 WII("input", MCI_WAVE_INPUT, "%u", wInput);
934 WII("output", MCI_WAVE_OUTPUT, "%u", wOutput);
935 #undef WII
936 break;
937 case MCI_DEVTYPE_SEQUENCER:
938 if (!STRCMP(keywords[i], "master") && (i+1 < nrofkeywords)) {
939 dwFlags |= MCI_SEQ_SET_MASTER;
940 if (!STRCMP(keywords[i+1], "midi"))
941 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
942 if (!STRCMP(keywords[i+1], "file"))
943 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
944 if (!STRCMP(keywords[i+1], "smpte"))
945 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
946 if (!STRCMP(keywords[i+1], "none"))
947 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
948 i += 2;
949 continue;
951 if (!STRCMP(keywords[i], "slave") && (i+1 < nrofkeywords)) {
952 dwFlags |= MCI_SEQ_SET_SLAVE;
953 if (!STRCMP(keywords[i+1], "midi"))
954 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
955 if (!STRCMP(keywords[i+1], "file"))
956 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
957 if (!STRCMP(keywords[i+1], "smpte"))
958 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
959 if (!STRCMP(keywords[i+1], "none"))
960 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
961 i += 2;
962 continue;
964 if ( !STRCMP(keywords[i], "port") &&
965 (i+1 < nrofkeywords) &&
966 !STRCMP(keywords[i+1], "mapper")
968 pU->seqsetParams.dwPort=-1;/* FIXME:not sure*/
969 dwFlags |= MCI_SEQ_SET_PORT;
970 i += 2;
971 continue;
973 #define SII(str,flag,element) \
974 if (!STRCMP(keywords[i], str) && \
975 (i+1 < nrofkeywords)) { \
976 sscanf(keywords[i+1], "%ld", \
977 &(pU->seqsetParams.element));\
978 dwFlags |= flag; \
979 i += 2; \
980 continue; \
982 SII("tempo", MCI_SEQ_SET_TEMPO, dwTempo);
983 SII("port", MCI_SEQ_SET_PORT, dwPort);
984 SII("offset", MCI_SEQ_SET_PORT, dwOffset);
985 #undef SII
987 i++;
989 if (!dwFlags)
990 return MCIERR_MISSING_STRING_ARGUMENT;
991 res = mciSendCommandA(wDevID, MCI_SET, dwFlags, (DWORD)pU);
992 free(pU);
993 return res;
996 /* specify break key
997 * Arguments:
998 * "off" disable break
999 * "on <keyid>" enable break on key with keyid
1000 * (I strongly suspect, that there is another parameter:
1001 * "window <handle>"
1002 * but I don't see it mentioned in my documentation.
1003 * Returns nothing.
1005 static DWORD
1006 MCISTR_Break(_MCISTR_PROTO_)
1008 LPMCI_BREAK_PARMS breakParams = xmalloc(sizeof(MCI_BREAK_PARMS));
1009 int res, i;
1011 if (!breakParams) return 0;
1013 breakParams->dwCallback = hwndCallback;
1014 /*breakParams.hwndBreak ? */
1015 for (i = 0; i < nrofkeywords; i++) {
1016 FLAG1("off", MCI_BREAK_OFF);
1017 if (!STRCMP(keywords[i], "on") && (nrofkeywords > i+1)) {
1018 dwFlags &= ~MCI_BREAK_OFF;
1019 dwFlags |= MCI_BREAK_KEY;
1020 sscanf(keywords[i+1], "%d", &(breakParams->nVirtKey));
1021 i += 2;
1022 continue;
1025 res = mciSendCommandA(wDevID, MCI_BREAK, dwFlags, (DWORD)breakParams);
1026 free(breakParams);
1027 return res;
1030 #define ITEM1(str, item, xtype) \
1031 if (!STRCMP(keywords[i], str)) { \
1032 gdcParams->dwItem = item; \
1033 type = xtype; \
1034 i++; \
1035 continue; \
1037 #define ITEM2(str1, str2, item, xtype) \
1038 if ( !STRCMP(keywords[i], str1) && \
1039 (i+1 < nrofkeywords) && \
1040 !STRCMP(keywords[i+1], str2)) { \
1041 gdcParams->dwItem = item; \
1042 type = xtype; \
1043 i += 2; \
1044 continue; \
1046 #define ITEM3(str1, str2, str3, item, xtype) \
1047 if ( !STRCMP(keywords[i], str1) && \
1048 (i+2 < nrofkeywords) && \
1049 !STRCMP(keywords[i+1], str2) && \
1050 !STRCMP(keywords[i+2], str3)) { \
1051 gdcParams->dwItem = item; \
1052 type = xtype; \
1053 i += 3; \
1054 continue; \
1057 /* get device capabilities of MCI drivers
1058 * Arguments:
1059 * Generic:
1060 * "device type" returns device name as string
1061 * "has audio" returns bool
1062 * "has video" returns bool
1063 * "uses files" returns bool
1064 * "compound device" returns bool
1065 * "can record" returns bool
1066 * "can play" returns bool
1067 * "can eject" returns bool
1068 * "can save" returns bool
1069 * Animation:
1070 * "palettes" returns nr of available palette entries
1071 * "windows" returns nr of available windows
1072 * "can reverse" returns bool
1073 * "can stretch" returns bool
1074 * "slow play rate" returns the slow playrate
1075 * "fast play rate" returns the fast playrate
1076 * "normal play rate" returns the normal playrate
1077 * Digital video
1078 * "can freeze" returns bool
1079 * "can lock" returns bool
1080 * "can reverse" returns bool
1081 * "can stretch" returns bool
1082 * "can stretch input" returns bool
1083 * "can test" returns bool
1084 * "has still" returns bool
1085 * "maximum play rate" returns the maximum play rate, in fps
1086 * "minimum play rate" returns the minimum play rate, in fps
1087 * "uses files" returns bool
1088 * "uses palettes" returns bool
1089 * "windows" returns nr of available windows
1090 * Overlay:
1091 * "windows" returns nr of available windows
1092 * "can stretch" returns bool
1093 * "can freeze" returns bool
1094 * Videodisc:
1095 * "cav" assume CAV discs (default if no disk inserted)
1096 * "clv" assume CLV discs
1097 * "can reverse" returns bool
1098 * "slow play rate" returns the slow playrate
1099 * "fast play rate" returns the fast playrate
1100 * "normal play rate" returns the normal playrate
1101 * Waveform audio:
1102 * "inputs" returns nr of inputdevices
1103 * "outputs" returns nr of outputdevices
1105 static DWORD
1106 MCISTR_Capability(_MCISTR_PROTO_) {
1107 MCI_GETDEVCAPS_PARMS *gdcParams = xmalloc(sizeof(MCI_GETDEVCAPS_PARMS));
1108 int type=0, i, res;
1110 gdcParams->dwCallback = hwndCallback;
1111 if (!nrofkeywords)
1112 return MCIERR_MISSING_STRING_ARGUMENT;
1113 /* well , thats default */
1114 dwFlags |= MCI_GETDEVCAPS_ITEM;
1115 gdcParams->dwItem = 0;
1117 for (i = 0; i < nrofkeywords; i++) {
1118 ITEM2("device", "type", MCI_GETDEVCAPS_DEVICE_TYPE, _MCISTR_devtype);
1119 ITEM2("has", "audio", MCI_GETDEVCAPS_HAS_AUDIO, _MCISTR_bool);
1120 ITEM2("has", "video", MCI_GETDEVCAPS_HAS_VIDEO, _MCISTR_bool);
1121 ITEM2("uses", "files", MCI_GETDEVCAPS_USES_FILES, _MCISTR_bool);
1122 ITEM2("compound", "device", MCI_GETDEVCAPS_COMPOUND_DEVICE, _MCISTR_bool);
1123 ITEM2("can", "record", MCI_GETDEVCAPS_CAN_RECORD, _MCISTR_bool);
1124 ITEM2("can", "play", MCI_GETDEVCAPS_CAN_PLAY, _MCISTR_bool);
1125 ITEM2("can", "eject", MCI_GETDEVCAPS_CAN_EJECT, _MCISTR_bool);
1126 ITEM2("can", "save", MCI_GETDEVCAPS_CAN_SAVE, _MCISTR_bool);
1127 switch (uDevTyp) {
1128 case MCI_DEVTYPE_ANIMATION:
1129 ITEM1("palettes", MCI_ANIM_GETDEVCAPS_PALETTES, _MCISTR_int);
1130 ITEM1("windows", MCI_ANIM_GETDEVCAPS_MAX_WINDOWS, _MCISTR_int);
1131 ITEM2("can", "reverse", MCI_ANIM_GETDEVCAPS_CAN_REVERSE, _MCISTR_bool);
1132 ITEM2("can", "stretch", MCI_ANIM_GETDEVCAPS_CAN_STRETCH, _MCISTR_bool);
1133 ITEM3("slow", "play", "rate", MCI_ANIM_GETDEVCAPS_SLOW_RATE, _MCISTR_int);
1134 ITEM3("fast", "play", "rate", MCI_ANIM_GETDEVCAPS_FAST_RATE, _MCISTR_int);
1135 ITEM3("normal", "play", "rate", MCI_ANIM_GETDEVCAPS_NORMAL_RATE, _MCISTR_int);
1136 break;
1137 case MCI_DEVTYPE_DIGITAL_VIDEO:
1138 ITEM2("can", "freeze", MCI_DGV_GETDEVCAPS_CAN_FREEZE, _MCISTR_bool);
1139 ITEM2("can", "lock", MCI_DGV_GETDEVCAPS_CAN_LOCK, _MCISTR_bool);
1140 ITEM2("can", "reverse", MCI_DGV_GETDEVCAPS_CAN_REVERSE, _MCISTR_bool);
1141 ITEM3("can", "stretch", "input", MCI_DGV_GETDEVCAPS_CAN_STR_IN, _MCISTR_bool);
1142 ITEM2("can", "stretch", MCI_DGV_GETDEVCAPS_CAN_STRETCH, _MCISTR_bool);
1143 ITEM2("can", "test", MCI_DGV_GETDEVCAPS_CAN_TEST, _MCISTR_bool);
1144 ITEM2("has", "still", MCI_DGV_GETDEVCAPS_HAS_STILL, _MCISTR_bool);
1145 ITEM3("maximum", "play", "rate", MCI_DGV_GETDEVCAPS_MAXIMUM_RATE, _MCISTR_int);
1146 ITEM3("minimum", "play", "rate", MCI_DGV_GETDEVCAPS_MINIMUM_RATE, _MCISTR_int);
1147 ITEM2("uses", "files", MCI_GETDEVCAPS_USES_FILES, _MCISTR_bool);
1148 ITEM2("uses", "palettes", MCI_DGV_GETDEVCAPS_PALETTES, _MCISTR_bool);
1149 ITEM1("windows", MCI_DGV_GETDEVCAPS_MAX_WINDOWS, _MCISTR_int);
1150 break;
1151 case MCI_DEVTYPE_OVERLAY:
1152 ITEM1("windows", MCI_OVLY_GETDEVCAPS_MAX_WINDOWS, _MCISTR_int);
1153 ITEM2("can", "freeze", MCI_OVLY_GETDEVCAPS_CAN_FREEZE, _MCISTR_bool);
1154 ITEM2("can", "stretch", MCI_OVLY_GETDEVCAPS_CAN_STRETCH, _MCISTR_bool);
1155 break;
1156 case MCI_DEVTYPE_VIDEODISC:
1157 FLAG1("cav", MCI_VD_GETDEVCAPS_CAV);
1158 FLAG1("clv", MCI_VD_GETDEVCAPS_CLV);
1159 ITEM2("can", "reverse", MCI_VD_GETDEVCAPS_CAN_REVERSE, _MCISTR_bool);
1160 ITEM3("slow", "play", "rate", MCI_VD_GETDEVCAPS_SLOW_RATE, _MCISTR_int);
1161 ITEM3("fast", "play", "rate", MCI_VD_GETDEVCAPS_FAST_RATE, _MCISTR_int);
1162 ITEM3("normal", "play", "rate", MCI_VD_GETDEVCAPS_NORMAL_RATE, _MCISTR_int);
1163 break;
1164 case MCI_DEVTYPE_WAVEFORM_AUDIO:
1165 ITEM1("inputs", MCI_WAVE_GETDEVCAPS_INPUTS, _MCISTR_int);
1166 ITEM1("outputs", MCI_WAVE_GETDEVCAPS_OUTPUTS, _MCISTR_int);
1167 break;
1170 res = mciSendCommandA(wDevID, MCI_GETDEVCAPS, dwFlags, (DWORD)gdcParams);
1172 /* no timeformat needed */
1173 if (res == 0)
1174 _MCISTR_convreturn(type, gdcParams->dwReturn, lpstrReturnString,
1175 uReturnLength, uDevTyp, 0);
1176 free(gdcParams);
1177 return res;
1179 #undef ITEM1
1180 #undef ITEM2
1181 #undef ITEM3
1182 /* resumes operation of device. no arguments, no return values */
1183 static DWORD
1184 MCISTR_Resume(_MCISTR_PROTO_)
1186 MCI_GENERIC_PARMS* genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1187 int res;
1189 genParams->dwCallback = hwndCallback;
1190 res = mciSendCommandA(wDevID, MCI_RESUME, dwFlags, (DWORD)genParams);
1191 free(genParams);
1192 return res;
1195 /* pauses operation of device. no arguments, no return values */
1196 static DWORD
1197 MCISTR_Pause(_MCISTR_PROTO_)
1199 MCI_GENERIC_PARMS* genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1200 int res;
1202 genParams->dwCallback = hwndCallback;
1203 res = mciSendCommandA(wDevID, MCI_PAUSE, dwFlags, (DWORD)genParams);
1204 free(genParams);
1205 return res;
1208 /* stops operation of device. no arguments, no return values */
1209 static DWORD
1210 MCISTR_Stop(_MCISTR_PROTO_)
1212 MCI_GENERIC_PARMS* genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1213 int res;
1215 genParams->dwCallback = hwndCallback;
1216 res = mciSendCommandA(wDevID, MCI_STOP, dwFlags, (DWORD)genParams);
1217 free(genParams);
1218 return res;
1221 /* starts recording.
1222 * Arguments:
1223 * "overwrite" overwrite existing things
1224 * "insert" insert at current position
1225 * "to <time>" record up to <time> (specified in timeformat)
1226 * "from <time>" record from <time> (specified in timeformat)
1228 static DWORD
1229 MCISTR_Record(_MCISTR_PROTO_) {
1230 int i, res, timef, nrargs, j, k, a[4];
1231 char *parsestr;
1232 MCI_RECORD_PARMS *recordParams = xmalloc(sizeof(MCI_RECORD_PARMS));
1234 res = _MCISTR_determine_timeformat(dev, wDevID, uDevTyp, &timef);
1235 if (res) return res;
1237 switch (timef) {
1238 case MCI_FORMAT_MILLISECONDS:
1239 case MCI_FORMAT_FRAMES:
1240 case MCI_FORMAT_BYTES:
1241 case MCI_FORMAT_SAMPLES:
1242 nrargs = 1;
1243 parsestr = "%d";
1244 break;
1245 case MCI_FORMAT_HMS:
1246 case MCI_FORMAT_MSF:
1247 parsestr="%d:%d:%d";
1248 nrargs=3;
1249 break;
1250 case MCI_FORMAT_TMSF:
1251 parsestr="%d:%d:%d:%d";
1252 nrargs=4;
1253 break;
1254 default:FIXME(mci, "unknown timeformat %d, please report.\n", timef);
1255 parsestr="%d";
1256 nrargs=1;
1257 break;
1259 recordParams->dwCallback = hwndCallback;
1260 for (i = 0; i < nrofkeywords; ) {
1261 if (!strcmp(keywords[i], "to") && (i+1 < nrofkeywords)) {
1262 dwFlags |= MCI_TO;
1263 a[0] = a[1] = a[2] = a[3] = 0;
1264 j=sscanf(keywords[i+1], parsestr, &a[0], &a[1], &a[2], &a[3]);
1265 /* add up all integers we got, if we have more
1266 * shift them. (Well I should use the macros in
1267 * mmsystem.h, right).
1269 recordParams->dwTo = 0;
1270 for (k = 0; k < j; k++)
1271 recordParams->dwTo += a[k] << (8*(nrargs-k));
1272 i += 2;
1273 continue;
1275 if (!strcmp(keywords[i], "from") && (i+1 < nrofkeywords)) {
1276 dwFlags |= MCI_FROM;
1277 a[0] = a[1] = a[2] = a[3] = 0;
1278 j = sscanf(keywords[i+1], parsestr, &a[0], &a[1], &a[2], &a[3]);
1279 /* dito. */
1280 recordParams->dwFrom = 0;
1281 for (k = 0; k < j; k++)
1282 recordParams->dwFrom += a[k]<<(8*(nrargs-k));
1283 i += 2;
1284 continue;
1286 FLAG1("insert", MCI_RECORD_INSERT);
1287 FLAG1("overwrite", MCI_RECORD_OVERWRITE);
1288 i++;
1290 res = mciSendCommandA(wDevID, MCI_RECORD, dwFlags, (DWORD)recordParams);
1291 free(recordParams);
1292 return res;
1295 /* play media
1296 * Arguments:
1297 * "to <time>" play up to <time> (specified in set timeformat)
1298 * "from <time>" play from <time> (specified in set timeformat)
1299 * Animation:
1300 * "slow" play slow
1301 * "fast" play fast
1302 * "scan" play as fast as possible (with audio disabled perhaps)
1303 * "reverse" play reverse
1304 * "speed <fps>" play with specified frames per second
1305 * Videodisc:
1306 * "slow" play slow
1307 * "fast" play fast
1308 * "scan" play as fast as possible (with audio disabled perhaps)
1309 * "reverse" play reverse
1310 * "speed <fps>" play with specified frames per second
1311 * Digitalvideo:
1312 * "fullscreen"
1313 * "repeat"
1314 * "reverse"
1315 * "window"
1317 static DWORD
1318 MCISTR_Play(_MCISTR_PROTO_) {
1319 int i, res, timef, nrargs, j, k, a[4];
1320 char *parsestr;
1321 union U {
1322 MCI_PLAY_PARMS playParams;
1323 MCI_VD_PLAY_PARMS vdplayParams;
1324 MCI_ANIM_PLAY_PARMS animplayParams;
1325 MCI_DGV_PLAY_PARMS dgvplayParams;
1327 union U *pU = xmalloc(sizeof(union U));
1329 res = _MCISTR_determine_timeformat(dev, wDevID, uDevTyp, &timef);
1330 if (res) return res;
1331 switch (timef) {
1332 case MCI_FORMAT_MILLISECONDS:
1333 case MCI_FORMAT_FRAMES:
1334 case MCI_FORMAT_BYTES:
1335 case MCI_FORMAT_SAMPLES:
1336 nrargs=1;
1337 parsestr="%d";
1338 break;
1339 case MCI_FORMAT_HMS:
1340 case MCI_FORMAT_MSF:
1341 parsestr="%d:%d:%d";
1342 nrargs=3;
1343 break;
1344 case MCI_FORMAT_TMSF:
1345 parsestr="%d:%d:%d:%d";
1346 nrargs=4;
1347 break;
1348 default:FIXME(mci, "unknown timeformat %d, please report.\n", timef);
1349 parsestr="%d";
1350 nrargs=1;
1351 break;
1353 pU->playParams.dwCallback = hwndCallback;
1354 for (i = 0; i < nrofkeywords; ) {
1355 if (!strcmp(keywords[i], "to") && (i+1 < nrofkeywords)) {
1356 dwFlags |= MCI_TO;
1357 a[0]=a[1]=a[2]=a[3]=0;
1358 j=sscanf(keywords[i+1], parsestr, &a[0], &a[1], &a[2], &a[3]);
1359 /* add up all integers we got, if we have more
1360 * shift them. (Well I should use the macros in
1361 * mmsystem.h, right).
1363 pU->playParams.dwTo=0;
1364 for (k = 0; k < j; k++)
1365 pU->playParams.dwTo += a[k] << (8*(nrargs-k));
1366 i += 2;
1367 continue;
1369 if (!strcmp(keywords[i], "from") && (i+1 < nrofkeywords)) {
1370 dwFlags |= MCI_FROM;
1371 a[0]=a[1]=a[2]=a[3]=0;
1372 j=sscanf(keywords[i+1], parsestr, &a[0], &a[1], &a[2], &a[3]);
1373 /* dito. */
1374 pU->playParams.dwFrom=0;
1375 for (k = 0; k < j; k++)
1376 pU->playParams.dwFrom += a[k]<<(8*(nrargs-k));
1377 i += 2;
1378 continue;
1380 switch (uDevTyp) {
1381 case MCI_DEVTYPE_VIDEODISC:
1382 FLAG1("slow", MCI_VD_PLAY_SLOW);
1383 FLAG1("fast", MCI_VD_PLAY_FAST);
1384 FLAG1("scan", MCI_VD_PLAY_SCAN);
1385 FLAG1("reverse", MCI_VD_PLAY_REVERSE);
1386 if (!STRCMP(keywords[i], "speed") && (i+1 < nrofkeywords)) {
1387 dwFlags |= MCI_VD_PLAY_SPEED;
1388 sscanf(keywords[i+1], "%ld", &(pU->vdplayParams.dwSpeed));
1389 i += 2;
1390 continue;
1392 break;
1393 case MCI_DEVTYPE_ANIMATION:
1394 FLAG1("slow", MCI_ANIM_PLAY_SLOW);
1395 FLAG1("fast", MCI_ANIM_PLAY_FAST);
1396 FLAG1("scan", MCI_ANIM_PLAY_SCAN);
1397 FLAG1("reverse", MCI_ANIM_PLAY_REVERSE);
1398 if (!STRCMP(keywords[i], "speed") && (i+1 < nrofkeywords)) {
1399 dwFlags |= MCI_ANIM_PLAY_SPEED;
1400 sscanf(keywords[i+1], "%ld", &(pU->animplayParams.dwSpeed));
1401 i += 2;
1402 continue;
1404 break;
1405 case MCI_DEVTYPE_DIGITAL_VIDEO:
1406 /* EPP FLAG1("fullscreen", MCI_MCIAVI_PLAY_FULLSCREEN); */
1407 FLAG1("repeat", MCI_DGV_PLAY_REPEAT);
1408 FLAG1("reverse", MCI_DGV_PLAY_REVERSE);
1409 /* EPP FLAG1("window", MCI_MCIAVI_PLAY_WINDOW); */
1410 break;
1412 i++;
1414 res = mciSendCommandA(wDevID, MCI_PLAY, dwFlags, (DWORD)pU);
1415 free(pU);
1416 return res;
1419 /* seek to a specified position
1420 * Arguments:
1421 * "to start" seek to start of medium
1422 * "to end" seek to end of medium
1423 * "to <time>" seek to <time> specified in current timeformat
1425 static DWORD
1426 MCISTR_Seek(_MCISTR_PROTO_) {
1427 int i, res, timef, nrargs, j, k, a[4];
1428 char *parsestr;
1429 MCI_SEEK_PARMS *seekParams = xmalloc(sizeof(MCI_SEEK_PARMS));
1431 res = _MCISTR_determine_timeformat(dev, wDevID, uDevTyp, &timef);
1432 if (res) return res;
1433 switch (timef) {
1434 case MCI_FORMAT_MILLISECONDS:
1435 case MCI_FORMAT_FRAMES:
1436 case MCI_FORMAT_BYTES:
1437 case MCI_FORMAT_SAMPLES:
1438 nrargs=1;
1439 parsestr="%d";
1440 break;
1441 case MCI_FORMAT_HMS:
1442 case MCI_FORMAT_MSF:
1443 parsestr="%d:%d:%d";
1444 nrargs=3;
1445 break;
1446 case MCI_FORMAT_TMSF:
1447 parsestr="%d:%d:%d:%d";
1448 nrargs=4;
1449 break;
1450 default:
1451 FIXME(mci, "unknown timeformat %d, please report.\n", timef);
1452 parsestr="%d";
1453 nrargs=1;
1454 break;
1456 seekParams->dwCallback = hwndCallback;
1457 for (i = 0; i < nrofkeywords; ) {
1458 if (!STRCMP(keywords[i], "to") && (i+1 < nrofkeywords)) {
1459 if (!STRCMP(keywords[i+1], "start")) {
1460 dwFlags |= MCI_SEEK_TO_START;
1461 seekParams->dwTo = 0;
1462 i += 2;
1463 continue;
1465 if (!STRCMP(keywords[i+1], "end")) {
1466 dwFlags |= MCI_SEEK_TO_END;
1467 seekParams->dwTo = 0;
1468 i += 2;
1469 continue;
1471 dwFlags |= MCI_TO;
1472 i += 2;
1473 a[0] = a[1] = a[2] = a[3] = 0;
1474 j = sscanf(keywords[i+1], parsestr, &a[0], &a[1], &a[2], &a[3]);
1475 seekParams->dwTo = 0;
1476 for (k = 0; k < j; k++)
1477 seekParams->dwTo += a[k] << (8*(nrargs-k));
1478 continue;
1480 switch (uDevTyp) {
1481 case MCI_DEVTYPE_VIDEODISC:
1482 FLAG1("reverse", MCI_VD_SEEK_REVERSE);
1483 break;
1485 i++;
1487 res = mciSendCommandA(wDevID, MCI_SEEK, dwFlags, (DWORD)seekParams);
1488 free(seekParams);
1489 return res;
1492 /* close media/driver */
1493 static DWORD
1494 MCISTR_Close(_MCISTR_PROTO_)
1496 MCI_GENERIC_PARMS* closeParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1497 int res;
1499 closeParams->dwCallback = hwndCallback;
1500 res = mciSendCommandA(wDevID, MCI_CLOSE, dwFlags, (DWORD)closeParams);
1501 free(closeParams);
1502 return res;
1505 /* return information.
1506 * Arguments:
1507 * "product" return product name (human readable)
1508 * "file" return filename
1509 * Animation:
1510 * "text" returns text?
1511 * Overlay:
1512 * "text" returns text?
1513 * Digitalvideo
1514 * "audio algorithm"
1515 * "audio quality"
1516 * "still algorithm"
1517 * "still quality"
1518 * "usage"
1519 * "version"
1520 * "video algorithm"
1521 * "video quality"
1522 * "window text"
1524 static DWORD
1525 MCISTR_Info(_MCISTR_PROTO_)
1527 union U {
1528 MCI_INFO_PARMSA infoParams;
1529 MCI_DGV_INFO_PARMSA dgvinfoParams;
1531 union U* pU = xmalloc(sizeof(union U));
1532 DWORD sflags;
1533 int i, res;
1535 sflags = dwFlags;
1536 for (i = 0; i < nrofkeywords; i++) {
1537 FLAG1("product", MCI_INFO_PRODUCT);
1538 FLAG1("file", MCI_INFO_FILE);
1539 switch (uDevTyp) {
1540 case MCI_DEVTYPE_ANIMATION:
1541 FLAG2("window", "text", MCI_ANIM_INFO_TEXT);
1542 break;
1543 case MCI_DEVTYPE_OVERLAY:
1544 FLAG2("window", "text", MCI_OVLY_INFO_TEXT);
1545 break;
1546 case MCI_DEVTYPE_DIGITAL_VIDEO:
1547 #define MI1(str, flag) \
1548 if (!STRCMP(keywords[i], str)) { \
1549 dwFlags |= MCI_DGV_INFO_ITEM; \
1550 pU->dgvinfoParams.dwItem |= flag; \
1551 i++; \
1552 continue; \
1554 #define MI2(str1, str2, flag) \
1555 if (!STRCMP(keywords[i], str1) && \
1556 (i+1 < nrofkeywords) && \
1557 !STRCMP(keywords[i+1], str2)) { \
1558 dwFlags |= MCI_DGV_INFO_ITEM; \
1559 pU->dgvinfoParams.dwItem |= flag; \
1560 i += 2; \
1561 continue; \
1563 MI2("audio", "algorithm", MCI_DGV_INFO_AUDIO_ALG);
1564 MI2("audio", "quality", MCI_DGV_INFO_AUDIO_QUALITY);
1565 MI2("still", "algorithm", MCI_DGV_INFO_STILL_ALG);
1566 MI2("still", "quality", MCI_DGV_INFO_STILL_QUALITY);
1567 MI1("usage", MCI_DGV_INFO_USAGE);
1568 MI1("version", MCI_INFO_VERSION );
1569 MI2("video", "algorithm", MCI_DGV_INFO_VIDEO_ALG);
1570 MI2("video", "quality", MCI_DGV_INFO_VIDEO_QUALITY);
1571 MI2("window", "text", MCI_DGV_INFO_TEXT);
1572 #undef MI1
1573 #undef MI2
1576 if (dwFlags == sflags)
1577 return MCIERR_MISSING_STRING_ARGUMENT;
1578 pU->infoParams.dwCallback = hwndCallback;
1580 /* MCI driver will fill in lpstrReturn, dwRetSize.
1581 * FIXME: I don't know if this is correct behaviour
1583 res = mciSendCommandA(wDevID, MCI_INFO, dwFlags, (DWORD)pU);
1584 if (res == 0)
1585 _MCI_STR(pU->infoParams.lpstrReturn);
1586 free(pU);
1587 return res;
1590 /* query MCI driver itself for information
1591 * Arguments:
1592 * "installname" return install name of <device> (system.ini)
1593 * "quantity" return nr of installed drivers
1594 * "open" open drivers only (additional flag)
1595 * "name <nr>" return nr of devices with <devicetyp>
1596 * "name all" return nr of all devices
1599 static DWORD
1600 MCISTR_Sysinfo(_MCISTR_PROTO_) {
1601 MCI_SYSINFO_PARMSA sysinfoParams;
1602 int i, res;
1604 sysinfoParams.lpstrReturn = lpstrReturnString;
1605 sysinfoParams.dwRetSize = uReturnLength;
1606 sysinfoParams.wDeviceType = uDevTyp;
1607 sysinfoParams.dwCallback = hwndCallback;
1609 for (i = 0; i < nrofkeywords; i++) {
1610 FLAG1("installname", MCI_SYSINFO_INSTALLNAME);
1611 FLAG1("quantity", MCI_SYSINFO_INSTALLNAME);
1612 FLAG1("open", MCI_SYSINFO_OPEN);
1613 if (!strcmp(keywords[i], "name") && (i+1 < nrofkeywords)) {
1614 sscanf(keywords[i+1], "%ld", &(sysinfoParams.dwNumber));
1615 dwFlags |= MCI_SYSINFO_NAME;
1616 i++;
1619 res = mciSendCommandA(0, MCI_SYSINFO, dwFlags, (DWORD)&sysinfoParams);
1621 if (dwFlags & MCI_SYSINFO_QUANTITY) {
1622 char buf[100];
1624 sprintf(buf, "%ld", *(long*)lpstrReturnString);
1625 _MCI_STR(buf);
1627 /* no need to copy anything back, mciSysInfo did it for us */
1628 return res;
1631 /* load file
1632 * Argument: "<filename>"
1633 * Overlay: "at <left> <top> <right> <bottom>" additional
1635 static DWORD
1636 MCISTR_Load(_MCISTR_PROTO_) {
1637 union U {
1638 MCI_LOAD_PARMSA loadParams;
1639 MCI_OVLY_LOAD_PARMSA ovlyloadParams;
1641 union U *pU = xmalloc(sizeof(union U));
1642 int i, len = 0, res;
1643 char *s;
1645 for (i = 0; i < nrofkeywords; ) {
1646 switch (uDevTyp) {
1647 case MCI_DEVTYPE_OVERLAY:
1648 if (!STRCMP(keywords[i], "at") && (i+4 < nrofkeywords)) {
1649 dwFlags |= MCI_OVLY_RECT;
1650 sscanf(keywords[i+1], "%d", &(pU->ovlyloadParams.rc.left));
1651 sscanf(keywords[i+2], "%d", &(pU->ovlyloadParams.rc.top));
1652 sscanf(keywords[i+3], "%d", &(pU->ovlyloadParams.rc.right));
1653 sscanf(keywords[i+4], "%d", &(pU->ovlyloadParams.rc.bottom));
1654 memcpy(keywords+i, keywords+(i+5), nrofkeywords-(i+5));
1655 continue;
1657 break;
1659 len += strlen(keywords[i])+1;
1660 i++;
1662 s=(char*)xmalloc(len);
1663 *s='\0';
1664 while (i < nrofkeywords) {
1665 strcat(s, keywords[i]);
1666 i++;
1667 if (i < nrofkeywords) strcat(s, " ");
1669 pU->loadParams.lpfilename = s;
1670 pU->loadParams.dwCallback = hwndCallback;
1671 dwFlags |= MCI_LOAD_FILE;
1672 res = mciSendCommandA(wDevID, MCI_LOAD, dwFlags, (DWORD)pU);
1673 free(s);
1674 free(pU);
1675 return res;
1678 /* save to file
1679 * Argument: "<filename>"
1680 * Overlay: "at <left> <top> <right> <bottom>" additional
1682 static DWORD
1683 MCISTR_Save(_MCISTR_PROTO_) {
1684 union U {
1685 MCI_SAVE_PARMS saveParams;
1686 MCI_OVLY_SAVE_PARMSA ovlysaveParams;
1688 union U* pU = xmalloc(sizeof(union U));
1689 int i, len = 0, res;
1690 char* s;
1692 for (i = 0; i < nrofkeywords; ) {
1693 switch (uDevTyp) {
1694 case MCI_DEVTYPE_OVERLAY:
1695 if (!STRCMP(keywords[i], "at") && (i+4 < nrofkeywords)) {
1696 dwFlags |= MCI_OVLY_RECT;
1697 sscanf(keywords[i+1], "%d", &(pU->ovlysaveParams.rc.left));
1698 sscanf(keywords[i+2], "%d", &(pU->ovlysaveParams.rc.top));
1699 sscanf(keywords[i+3], "%d", &(pU->ovlysaveParams.rc.right));
1700 sscanf(keywords[i+4], "%d", &(pU->ovlysaveParams.rc.bottom));
1701 memcpy(keywords+i, keywords+(i+5), nrofkeywords-(i+5));
1702 continue;
1704 break;
1706 len += strlen(keywords[i])+1;
1707 i++;
1709 s = (char*)xmalloc(len);
1710 *s = '\0';
1711 while (i < nrofkeywords) {
1712 strcat(s, keywords[i]);
1713 i++;
1714 if (i < nrofkeywords) strcat(s, " ");
1716 pU->saveParams.lpfilename = s;
1717 pU->saveParams.dwCallback = hwndCallback;
1718 dwFlags |= MCI_LOAD_FILE;
1719 res = mciSendCommandA(wDevID, MCI_SAVE, dwFlags, (DWORD)pU);
1720 free(s);
1721 free(pU);
1722 return res;
1725 /* prepare device for input/output
1726 * (only applyable to waveform audio)
1728 static DWORD
1729 MCISTR_Cue(_MCISTR_PROTO_) {
1730 MCI_GENERIC_PARMS *cueParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1731 int i, res;
1733 for (i = 0; i < nrofkeywords; i++) {
1734 switch (uDevTyp) {
1735 case MCI_DEVTYPE_WAVEFORM_AUDIO:
1736 FLAG1("input", MCI_WAVE_INPUT);
1737 FLAG1("output", MCI_WAVE_OUTPUT);
1738 break;
1742 cueParams->dwCallback = hwndCallback;
1744 res = mciSendCommandA(wDevID, MCI_CUE, dwFlags, (DWORD)cueParams);
1745 free(cueParams);
1746 return res;
1749 /* delete information */
1750 static DWORD
1751 MCISTR_Delete(_MCISTR_PROTO_) {
1752 int timef, nrargs, i, j, k, a[4], res;
1753 char *parsestr;
1754 MCI_WAVE_DELETE_PARMS *deleteParams = xmalloc(sizeof(MCI_WAVE_DELETE_PARMS));
1756 /* only implemented for waveform audio */
1757 if (uDevTyp != MCI_DEVTYPE_WAVEFORM_AUDIO)
1758 return MCIERR_UNSUPPORTED_FUNCTION; /* well it fits */
1759 res = _MCISTR_determine_timeformat(dev, wDevID, uDevTyp, &timef);
1760 if (res) return res;
1761 switch (timef) {
1762 case MCI_FORMAT_MILLISECONDS:
1763 case MCI_FORMAT_FRAMES:
1764 case MCI_FORMAT_BYTES:
1765 case MCI_FORMAT_SAMPLES:
1766 nrargs=1;
1767 parsestr="%d";
1768 break;
1769 case MCI_FORMAT_HMS:
1770 case MCI_FORMAT_MSF:
1771 parsestr="%d:%d:%d";
1772 nrargs=3;
1773 break;
1774 case MCI_FORMAT_TMSF:
1775 parsestr="%d:%d:%d:%d";
1776 nrargs=4;
1777 break;
1778 default:FIXME(mci, "unknown timeformat %d, please report.\n", timef);
1779 parsestr="%d";
1780 nrargs=1;
1781 break;
1783 for (i = 0; i < nrofkeywords; ) {
1784 if (!strcmp(keywords[i], "to") && (i+1 < nrofkeywords)) {
1785 dwFlags |= MCI_TO;
1786 a[0] = a[1] = a[2] = a[3] = 0;
1787 j = sscanf(keywords[i+1], parsestr, &a[0], &a[1], &a[2], &a[3]);
1788 /* add up all integers we got, if we have more
1789 * shift them. (Well I should use the macros in
1790 * mmsystem.h, right).
1792 deleteParams->dwTo = 0;
1793 for (k = 0;k < j;k++)
1794 deleteParams->dwTo += a[k]<<(8*(nrargs-k));
1795 i += 2;
1796 continue;
1798 if (!strcmp(keywords[i], "from") && (i+1 < nrofkeywords)) {
1799 dwFlags |= MCI_FROM;
1800 a[0] = a[1] = a[2] = a[3] = 0;
1801 j = sscanf(keywords[i+1], parsestr, &a[0], &a[1], &a[2], &a[3]);
1802 /* dito. */
1803 deleteParams->dwFrom = 0;
1804 for (k = 0; k < j; k++)
1805 deleteParams->dwFrom += a[k]<<(8*(nrargs-k));
1806 i += 2;
1807 continue;
1809 i++;
1811 deleteParams->dwCallback = hwndCallback;
1812 res = mciSendCommandA(wDevID, MCI_DELETE, dwFlags, (DWORD)deleteParams);
1813 free(deleteParams);
1814 return res;
1817 /* send command to device. only applies to videodisc */
1818 static DWORD
1819 MCISTR_Escape(_MCISTR_PROTO_)
1821 LPMCI_VD_ESCAPE_PARMSA escapeParams = xmalloc(sizeof(MCI_VD_ESCAPE_PARMSA));
1822 int i, len = 0, res;
1823 char *s;
1825 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1826 return MCIERR_UNSUPPORTED_FUNCTION;
1828 for (i = 0; i < nrofkeywords; i++) {
1829 len += strlen(keywords[i]) + 1;
1831 s = (char*)malloc(len);
1832 *s = '\0';
1833 for (i = 0; i < nrofkeywords; ) {
1834 strcat(s, keywords[i]);
1835 i++;
1836 if (i < nrofkeywords) strcat(s, " ");
1838 escapeParams->lpstrCommand = s;
1839 escapeParams->dwCallback = hwndCallback;
1840 dwFlags |= MCI_VD_ESCAPE_STRING;
1841 res = mciSendCommandA(wDevID, MCI_ESCAPE, dwFlags, (DWORD)escapeParams);
1842 free(s);
1843 free(escapeParams);
1844 return res;
1847 /* unfreeze [part of] the overlayed video
1848 * only applyable to Overlay devices
1850 static DWORD
1851 MCISTR_Unfreeze(_MCISTR_PROTO_)
1853 LPMCI_OVLY_RECT_PARMS unfreezeParams = xmalloc(sizeof(MCI_OVLY_RECT_PARMS));
1854 int i, res;
1856 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1857 return MCIERR_UNSUPPORTED_FUNCTION;
1858 for (i = 0; i < nrofkeywords; ) {
1859 if (!STRCMP(keywords[i], "at") && (i+4 < nrofkeywords)) {
1860 sscanf(keywords[i+1], "%d", &(unfreezeParams->rc.left));
1861 sscanf(keywords[i+2], "%d", &(unfreezeParams->rc.top));
1862 sscanf(keywords[i+3], "%d", &(unfreezeParams->rc.right));
1863 sscanf(keywords[i+4], "%d", &(unfreezeParams->rc.bottom));
1864 dwFlags |= MCI_OVLY_RECT;
1865 i += 5;
1866 continue;
1868 i++;
1870 unfreezeParams->dwCallback = hwndCallback;
1871 res = mciSendCommandA(wDevID, MCI_UNFREEZE, dwFlags, (DWORD)unfreezeParams);
1872 free(unfreezeParams);
1873 return res;
1875 /* freeze [part of] the overlayed video
1876 * only applyable to Overlay devices
1878 static DWORD
1879 MCISTR_Freeze(_MCISTR_PROTO_)
1881 LPMCI_OVLY_RECT_PARMS freezeParams = xmalloc(sizeof(MCI_OVLY_RECT_PARMS));
1882 int i, res;
1884 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1885 return MCIERR_UNSUPPORTED_FUNCTION;
1886 for (i = 0; i < nrofkeywords; ) {
1887 if (!STRCMP(keywords[i], "at") && (i+4 < nrofkeywords)) {
1888 sscanf(keywords[i+1], "%d", &(freezeParams->rc.left));
1889 sscanf(keywords[i+2], "%d", &(freezeParams->rc.top));
1890 sscanf(keywords[i+3], "%d", &(freezeParams->rc.right));
1891 sscanf(keywords[i+4], "%d", &(freezeParams->rc.bottom));
1892 dwFlags |= MCI_OVLY_RECT;
1893 i += 5;
1894 continue;
1896 i++;
1898 freezeParams->dwCallback = hwndCallback;
1899 res = mciSendCommandA(wDevID, MCI_FREEZE, dwFlags, (DWORD)freezeParams);
1900 free(freezeParams);
1901 return res;
1904 /* copy parts of image to somewhere else
1905 * "source [at <left> <top> <right> <bottom>]" source is framebuffer [or rect]
1906 * "destination [at <left> <top> <right> <bottom>]" destination is framebuffer [or rect]
1907 * Overlay:
1908 * "frame [at <left> <top> <right> <bottom>]" frame is framebuffer [or rect]
1909 * where the video input is placed
1910 * "video [at <left> <top> <right> <bottom>]" video is whole video [or rect]
1911 * (defining part of input to
1912 * be displayed)
1913 * FIXME: This whole junk is passing multiple rectangles.
1914 * I don't know how to do that with the present interface.
1915 * (Means code below is broken)
1917 static DWORD
1918 MCISTR_Put(_MCISTR_PROTO_) {
1919 union U {
1920 MCI_OVLY_RECT_PARMS ovlyputParams;
1921 MCI_ANIM_RECT_PARMS animputParams;
1922 MCI_DGV_RECT_PARMS dgvputParams;
1924 union U* pU = xmalloc(sizeof(union U));
1925 int i, res;
1927 for (i = 0; i < nrofkeywords; ) {
1928 switch (uDevTyp) {
1929 case MCI_DEVTYPE_ANIMATION:
1930 FLAG1("source", MCI_ANIM_PUT_SOURCE);
1931 FLAG1("destination", MCI_ANIM_PUT_DESTINATION);
1932 if (!STRCMP(keywords[i], "at") && (i+4 < nrofkeywords)) {
1933 sscanf(keywords[i+1], "%d", &(pU->animputParams.rc.left));
1934 sscanf(keywords[i+2], "%d", &(pU->animputParams.rc.top));
1935 sscanf(keywords[i+3], "%d", &(pU->animputParams.rc.right));
1936 sscanf(keywords[i+4], "%d", &(pU->animputParams.rc.bottom));
1937 dwFlags |= MCI_ANIM_RECT;
1938 i += 5;
1939 continue;
1941 break;
1942 case MCI_DEVTYPE_OVERLAY:
1943 FLAG1("source", MCI_OVLY_PUT_SOURCE);
1944 FLAG1("destination", MCI_OVLY_PUT_DESTINATION);
1945 FLAG1("video", MCI_OVLY_PUT_VIDEO);
1946 FLAG1("frame", MCI_OVLY_PUT_FRAME);
1947 if (!STRCMP(keywords[i], "at") && (i+4 < nrofkeywords)) {
1948 sscanf(keywords[i+1], "%d", &(pU->ovlyputParams.rc.left));
1949 sscanf(keywords[i+2], "%d", &(pU->ovlyputParams.rc.top));
1950 sscanf(keywords[i+3], "%d", &(pU->ovlyputParams.rc.right));
1951 sscanf(keywords[i+4], "%d", &(pU->ovlyputParams.rc.bottom));
1952 dwFlags |= MCI_OVLY_RECT;
1953 i += 5;
1954 continue;
1956 break;
1957 case MCI_DEVTYPE_DIGITAL_VIDEO:
1958 FLAG1("source", MCI_DGV_PUT_SOURCE);
1959 FLAG1("destination", MCI_DGV_PUT_DESTINATION);
1960 FLAG1("video", MCI_DGV_PUT_VIDEO);
1961 FLAG1("frame", MCI_DGV_PUT_FRAME);
1962 if (!STRCMP(keywords[i], "at") && (i+4 < nrofkeywords)) {
1963 sscanf(keywords[i+1], "%d", &(pU->dgvputParams.rc.left));
1964 sscanf(keywords[i+2], "%d", &(pU->dgvputParams.rc.top));
1965 sscanf(keywords[i+3], "%d", &(pU->dgvputParams.rc.right));
1966 sscanf(keywords[i+4], "%d", &(pU->dgvputParams.rc.bottom));
1967 dwFlags |= MCI_DGV_RECT;
1968 i += 5;
1969 continue;
1971 break;
1972 break;
1974 i++;
1976 pU->dgvputParams.dwCallback = hwndCallback;
1977 res = mciSendCommandA(wDevID, MCI_PUT, dwFlags, (DWORD)pU);
1978 free(pU);
1979 return res;
1982 /* palette behaviour changing
1983 * (Animation only)
1984 * "normal" realize the palette normally
1985 * "background" realize the palette as background palette
1987 static DWORD
1988 MCISTR_Realize(_MCISTR_PROTO_)
1990 MCI_GENERIC_PARMS *realizeParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1991 int i, res;
1993 if (uDevTyp != MCI_DEVTYPE_ANIMATION)
1994 return MCIERR_UNSUPPORTED_FUNCTION;
1995 for (i = 0; i < nrofkeywords; i++) {
1996 FLAG1("background", MCI_ANIM_REALIZE_BKGD);
1997 FLAG1("normal", MCI_ANIM_REALIZE_NORM);
1999 realizeParams->dwCallback = hwndCallback;
2000 res = mciSendCommandA(wDevID, MCI_REALIZE, dwFlags, (DWORD)realizeParams);
2001 free(realizeParams);
2002 return res;
2005 /* Digitalvideo:
2006 * "algorithm <algorithm>"
2007 * "alignment to <integer>"
2008 * "bass to <factor>"
2009 * "bitspersample to <bit_count>"
2010 * "bytespersec to <integer>"
2011 * "clocktime"
2012 * "input"
2013 * "left off"
2014 * "left on"
2015 * "left volume to <factor>"
2016 * "off"
2017 * "on"
2018 * "output"
2019 * "over <duration>"
2020 * "quality <descripto>r"
2021 * "record off"
2022 * "record on"
2023 * "right off"
2024 * "right on"
2025 * "right volume to <factor>"
2026 * "samplespersec to <integer>"
2027 * "source to <sourcename>"
2028 * "stream to <number>"
2029 * "treble to <factor>"
2030 * "volume to <factor>"
2031 * Vcr:
2032 * "off"
2033 * "on"
2034 * "monitor to type number number"
2035 * "record off"
2036 * "record track track_number off"
2037 * "record on "
2038 * "record track track_number on "
2039 * "source to type number number"
2040 * "track track_number off"
2041 * "track track_number on"
2043 static DWORD
2044 MCISTR_SetAudio(_MCISTR_PROTO_)
2046 MCI_DGV_SETAUDIO_PARMSA setaudioParams;
2047 int i, res;
2049 if (uDevTyp != MCI_DEVTYPE_DIGITAL_VIDEO)
2050 return MCIERR_UNSUPPORTED_FUNCTION;
2052 setaudioParams.dwCallback = hwndCallback;
2054 for (i = 0; i < nrofkeywords; ) {
2055 if (!STRCMP(keywords[i], "algorithm") && (i+1 < nrofkeywords)) {
2056 setaudioParams.lpstrAlgorithm = strdup(keywords[i+1]);
2057 dwFlags |= MCI_DGV_SETAUDIO_ALG;
2058 i += 2;
2059 continue;
2061 #define MSAI2(str1, str2, flag) \
2062 if ( !STRCMP(keywords[i], str1) && (i+2 < nrofkeywords) && \
2063 !STRCMP(keywords[i+1], str2)) { \
2064 dwFlags |= MCI_DGV_SETAUDIO_ITEM; \
2065 setaudioParams.dwItem = flag; \
2066 sscanf(keywords[i+2], "%lu", &setaudioParams.dwValue); \
2067 i += 3; \
2068 continue; \
2070 #define MSAI3(str1, str2, str3, flag) \
2071 if ( !STRCMP(keywords[i], str1) && (i+3 < nrofkeywords) && \
2072 !STRCMP(keywords[i+1], str2) && !STRCMP(keywords[i+2], str3)) { \
2073 dwFlags |= MCI_DGV_SETAUDIO_ITEM; \
2074 setaudioParams.dwItem = flag; \
2075 sscanf(keywords[i+3], "%lu", &setaudioParams.dwValue); \
2076 i += 4; \
2077 continue; \
2079 MSAI2("alignment", "to", MCI_DGV_SETAUDIO_BLOCKALIGN);
2080 MSAI2("bass", "to", MCI_DGV_SETAUDIO_BASS);
2081 MSAI2("bitspersample", "to", MCI_DGV_SETAUDIO_BITSPERSAMPLE);
2082 MSAI2("bytespersec", "to", MCI_DGV_SETAUDIO_AVGBYTESPERSEC);
2083 MSAI2("samplespersec", "to", MCI_DGV_SETAUDIO_SAMPLESPERSEC);
2084 MSAI2("stream", "to", MCI_DGV_SETAUDIO_STREAM);
2085 MSAI2("treble", "to", MCI_DGV_SETAUDIO_TREBLE);
2086 MSAI2("volume", "to", MCI_DGV_SETAUDIO_VOLUME);
2087 MSAI3("input", "bass", "to", MCI_DGV_SETAUDIO_BASS|MCI_DGV_SETAUDIO_INPUT);
2088 MSAI3("input", "treble", "to", MCI_DGV_SETAUDIO_TREBLE|MCI_DGV_SETAUDIO_INPUT);
2089 MSAI3("input", "volume", "to", MCI_DGV_SETAUDIO_VOLUME|MCI_DGV_SETAUDIO_INPUT);
2090 MSAI3("output", "bass", "to", MCI_DGV_SETAUDIO_BASS|MCI_DGV_SETAUDIO_OUTPUT);
2091 MSAI3("output", "treble", "to", MCI_DGV_SETAUDIO_TREBLE|MCI_DGV_SETAUDIO_OUTPUT);
2092 MSAI3("output", "volume", "to", MCI_DGV_SETAUDIO_VOLUME|MCI_DGV_SETAUDIO_OUTPUT);
2094 FLAG1("clocktime", MCI_DGV_SETAUDIO_CLOCKTIME);
2095 FLAG2("left", "off", MCI_DGV_SETAUDIO_LEFT|MCI_SET_OFF);
2096 FLAG2("left", "on", MCI_DGV_SETAUDIO_LEFT|MCI_SET_ON);
2097 if (!STRCMP(keywords[i], "left") && (i+3 < nrofkeywords) &&
2098 !STRCMP(keywords[i+1], "volume") && !STRCMP(keywords[i+2], "to")) {
2099 dwFlags |= MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE | MCI_DGV_SETAUDIO_LEFT;
2100 setaudioParams.dwItem = MCI_DGV_SETAUDIO_VOLUME;
2101 sscanf(keywords[i+3], "%lu", &setaudioParams.dwValue);
2102 i += 4;
2103 continue;
2105 FLAG1("off", MCI_SET_OFF);
2106 FLAG1("on", MCI_SET_ON);
2107 if (!STRCMP(keywords[i], "over") && (i+1 < nrofkeywords)) {
2108 dwFlags |= MCI_DGV_SETAUDIO_OVER;
2109 sscanf(keywords[i+3], "%lu", &setaudioParams.dwOver);
2110 i += 2;
2111 continue;
2113 if (!STRCMP(keywords[i], "quality") && (i+1 < nrofkeywords)) {
2114 setaudioParams.lpstrQuality = strdup(keywords[i+1]);
2115 dwFlags |= MCI_DGV_SETAUDIO_QUALITY;
2116 i += 2;
2117 continue;
2119 FLAG2("record", "off", MCI_DGV_SETAUDIO_RECORD|MCI_SET_OFF);
2120 FLAG2("record", "on", MCI_DGV_SETAUDIO_RECORD|MCI_SET_ON);
2121 FLAG2("right", "off", MCI_DGV_SETAUDIO_RIGHT|MCI_SET_OFF);
2122 FLAG2("right", "on", MCI_DGV_SETAUDIO_RIGHT|MCI_SET_ON);
2123 if (!STRCMP(keywords[i], "right") && (i+3 < nrofkeywords) &&
2124 !STRCMP(keywords[i+1], "volume") && !STRCMP(keywords[i+2], "to")) {
2125 dwFlags |= MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE | MCI_DGV_SETAUDIO_RIGHT;
2126 setaudioParams.dwItem = MCI_DGV_SETAUDIO_VOLUME;
2127 sscanf(keywords[i+3], "%lu", &setaudioParams.dwValue);
2128 i += 4;
2129 continue;
2131 if (!STRCMP(keywords[i], "source") && (i+2 < nrofkeywords) && !STRCMP(keywords[i+1], "to")) {
2132 dwFlags |= MCI_DGV_SETAUDIO_ITEM;
2133 setaudioParams.dwItem |= MCI_DGV_SETAUDIO_SOURCE;
2134 if (!STRCMP(keywords[i+2], "left")) {
2135 setaudioParams.dwValue |= MCI_DGV_SETAUDIO_SOURCE_LEFT;
2136 } else if (!STRCMP(keywords[i+2], "right")) {
2137 setaudioParams.dwValue |= MCI_DGV_SETAUDIO_SOURCE_RIGHT;
2138 } else if (!STRCMP(keywords[i+2], "average")) {
2139 setaudioParams.dwValue |= MCI_DGV_SETAUDIO_SOURCE_AVERAGE;
2140 } else if (!STRCMP(keywords[i+2], "stereo")) {
2141 setaudioParams.dwValue |= MCI_DGV_SETAUDIO_SOURCE_STEREO;
2142 } else {
2143 res = MCIERR_UNSUPPORTED_FUNCTION;
2144 return res;
2146 i += 3;
2147 continue;
2150 res = mciSendCommandA(wDevID, MCI_SETAUDIO, dwFlags, (DWORD)&setaudioParams);
2151 free(setaudioParams.lpstrAlgorithm);
2152 free(setaudioParams.lpstrQuality);
2153 return res;
2156 /* videodisc spinning
2157 * "up"
2158 * "down"
2160 static DWORD
2161 MCISTR_Spin(_MCISTR_PROTO_)
2163 MCI_GENERIC_PARMS *spinParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
2164 int i, res;
2166 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
2167 return MCIERR_UNSUPPORTED_FUNCTION;
2168 for (i = 0; i < nrofkeywords; i++) {
2169 FLAG1("up", MCI_VD_SPIN_UP);
2170 FLAG1("down", MCI_VD_SPIN_UP);
2172 spinParams->dwCallback = hwndCallback;
2173 res = mciSendCommandA(wDevID, MCI_SPIN, dwFlags, (DWORD)spinParams);
2174 free(spinParams);
2175 return res;
2178 /* step single frames
2179 * "reverse" optional flag
2180 * "by <nr>" for <nr> frames
2182 static DWORD
2183 MCISTR_Step(_MCISTR_PROTO_) {
2184 union U {
2185 MCI_ANIM_STEP_PARMS animstepParams;
2186 MCI_VD_STEP_PARMS vdstepParams;
2188 union U *pU = xmalloc(sizeof(union U));
2189 int i, res;
2191 for (i = 0; i < nrofkeywords; ) {
2192 switch (uDevTyp) {
2193 case MCI_DEVTYPE_ANIMATION:
2194 FLAG1("reverse", MCI_ANIM_STEP_REVERSE);
2195 if (!STRCMP(keywords[i], "by") && (i+1 < nrofkeywords)) {
2196 sscanf(keywords[i+1], "%ld", &(pU->animstepParams.dwFrames));
2197 dwFlags |= MCI_ANIM_STEP_FRAMES;
2198 i += 2;
2199 continue;
2201 break;
2202 case MCI_DEVTYPE_VIDEODISC:
2203 FLAG1("reverse", MCI_VD_STEP_REVERSE);
2204 if (!STRCMP(keywords[i], "by") && (i+1 < nrofkeywords)) {
2205 sscanf(keywords[i+1], "%ld", &(pU->vdstepParams.dwFrames));
2206 dwFlags |= MCI_VD_STEP_FRAMES;
2207 i += 2;
2208 continue;
2210 break;
2212 i++;
2214 pU->animstepParams.dwCallback = hwndCallback;
2215 res = mciSendCommandA(wDevID, MCI_STEP, dwFlags, (DWORD)pU);
2216 free(pU);
2217 return res;
2220 /* update animation window
2221 * Arguments:
2222 * "at <left> <top> <right> <bottom>" only in this rectangle
2223 * "hdc" device context
2225 static DWORD
2226 MCISTR_Update(_MCISTR_PROTO_) {
2227 int i, res;
2228 LPMCI_ANIM_UPDATE_PARMS updateParams = xmalloc(sizeof(MCI_ANIM_UPDATE_PARMS));
2230 for (i = 0; i < nrofkeywords; ) {
2231 if (!STRCMP(keywords[i], "at") && (i+4 < nrofkeywords)) {
2232 sscanf(keywords[i+1], "%d", &(updateParams->rc.left));
2233 sscanf(keywords[i+2], "%d", &(updateParams->rc.top));
2234 sscanf(keywords[i+3], "%d", &(updateParams->rc.right));
2235 sscanf(keywords[i+4], "%d", &(updateParams->rc.bottom));
2236 dwFlags |= MCI_ANIM_RECT;
2237 i += 5;
2238 continue;
2240 if (!STRCMP(keywords[i], "hdc") && (i+1 < nrofkeywords)) {
2241 dwFlags |= MCI_ANIM_UPDATE_HDC;
2242 sscanf(keywords[i+1], "%d", &(updateParams->hDC));
2243 i += 2;
2244 continue;
2246 i++;
2248 updateParams->dwCallback = hwndCallback;
2249 res = mciSendCommandA(wDevID, MCI_UPDATE, dwFlags, (DWORD)updateParams);
2250 free(updateParams);
2251 return res;
2254 /* where command for animation and overlay drivers.
2255 * just returns the specified rectangle as a string
2256 * Arguments:
2257 * "source"
2258 * "destination"
2259 * Overlay special:
2260 * "video"
2261 * "frame"
2263 static DWORD
2264 MCISTR_Where(_MCISTR_PROTO_) {
2265 union U {
2266 MCI_ANIM_RECT_PARMS animwhereParams;
2267 MCI_OVLY_RECT_PARMS ovlywhereParams;
2269 union U* pU = xmalloc(sizeof(union U));
2270 int i, res;
2272 for (i = 0; i < nrofkeywords; i++) {
2273 switch (uDevTyp) {
2274 case MCI_DEVTYPE_ANIMATION:
2275 FLAG1("source", MCI_ANIM_WHERE_SOURCE);
2276 FLAG1("destination", MCI_ANIM_WHERE_DESTINATION);
2277 break;
2278 case MCI_DEVTYPE_OVERLAY:
2279 FLAG1("source", MCI_OVLY_WHERE_SOURCE);
2280 FLAG1("destination", MCI_OVLY_WHERE_DESTINATION);
2281 FLAG1("video", MCI_OVLY_WHERE_VIDEO);
2282 FLAG1("frame", MCI_OVLY_WHERE_FRAME);
2283 break;
2286 pU->animwhereParams.dwCallback = hwndCallback;
2287 res = mciSendCommandA(wDevID, MCI_WHERE, dwFlags, (DWORD)pU);
2288 if (res == 0) {
2289 char buf[100];
2290 switch (uDevTyp) {
2291 case MCI_DEVTYPE_ANIMATION:
2292 sprintf(buf, "%d %d %d %d",
2293 pU->animwhereParams.rc.left,
2294 pU->animwhereParams.rc.top,
2295 pU->animwhereParams.rc.right,
2296 pU->animwhereParams.rc.bottom
2298 break;
2299 case MCI_DEVTYPE_OVERLAY:
2300 sprintf(buf, "%d %d %d %d",
2301 pU->ovlywhereParams.rc.left,
2302 pU->ovlywhereParams.rc.top,
2303 pU->ovlywhereParams.rc.right,
2304 pU->ovlywhereParams.rc.bottom
2306 break;
2307 default:strcpy(buf, "0 0 0 0");break;
2309 _MCI_STR(buf);
2311 free(pU);
2312 return res;
2315 static DWORD
2316 MCISTR_Window(_MCISTR_PROTO_) {
2317 union U {
2318 MCI_ANIM_WINDOW_PARMSA animwindowParams;
2319 MCI_OVLY_WINDOW_PARMSA ovlywindowParams;
2320 MCI_DGV_WINDOW_PARMSA dgvwindowParams;
2322 union U* pU = xmalloc(sizeof(union U));
2323 int i, res;
2324 char* s;
2326 s = NULL;
2327 for (i = 0; i < nrofkeywords; ) {
2328 switch (uDevTyp) {
2329 case MCI_DEVTYPE_ANIMATION:
2330 if (!STRCMP(keywords[i], "handle") && (i+1 < nrofkeywords)) {
2331 dwFlags |= MCI_ANIM_WINDOW_HWND;
2332 if (!STRCMP(keywords[i+1], "default"))
2333 pU->animwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
2334 else
2335 sscanf(keywords[i+1], "%d", &(pU->animwindowParams.hWnd));
2336 i += 2;
2337 continue;
2339 if (!STRCMP(keywords[i], "state") && (i+1 < nrofkeywords)) {
2340 dwFlags |= MCI_ANIM_WINDOW_STATE;
2341 if (!STRCMP(keywords[i+1], "hide"))
2342 pU->animwindowParams.nCmdShow = SW_HIDE;
2343 if (!STRCMP(keywords[i+1], "iconic"))
2344 pU->animwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
2345 if (!STRCMP(keywords[i+1], "minimized"))
2346 pU->animwindowParams.nCmdShow = SW_SHOWMINIMIZED;
2347 if (!STRCMP(keywords[i+1], "maximized"))
2348 pU->animwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
2349 if (!STRCMP(keywords[i+1], "minimize"))
2350 pU->animwindowParams.nCmdShow = SW_MINIMIZE;
2351 if (!STRCMP(keywords[i+1], "normal"))
2352 pU->animwindowParams.nCmdShow = SW_NORMAL;
2353 if (!STRCMP(keywords[i+1], "restore"))
2354 pU->animwindowParams.nCmdShow = SW_NORMAL;
2355 if (!STRCMP(keywords[i+1], "show"))
2356 pU->animwindowParams.nCmdShow = SW_SHOW;
2357 if (!STRCMP(keywords[i+1], "no") && (i+2 < nrofkeywords)) {
2358 if (!STRCMP(keywords[i+2], "active"))
2359 pU->animwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
2360 if (!STRCMP(keywords[i+2], "action"))
2361 pU->animwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
2362 i++;
2364 i += 2;
2365 continue;
2367 /* text is enclosed in " ... " as it seems */
2368 if (!STRCMP(keywords[i], "text")) {
2369 if (keywords[i+1][0] != '"') {
2370 i++;
2371 continue;
2373 dwFlags |= MCI_ANIM_WINDOW_TEXT;
2374 pU->animwindowParams.lpstrText = _MCISTR_Unquote(keywords[i+1]);
2375 i += 2;
2376 continue;
2378 FLAG1("stretch", MCI_ANIM_WINDOW_ENABLE_STRETCH);
2379 break;
2380 case MCI_DEVTYPE_DIGITAL_VIDEO:
2381 if (!STRCMP(keywords[i], "handle") && (i+1 < nrofkeywords)) {
2382 dwFlags |= MCI_DGV_WINDOW_HWND;
2383 if (!STRCMP(keywords[i+1], "default"))
2384 pU->dgvwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
2385 else
2386 sscanf(keywords[i+1], "%d", &(pU->dgvwindowParams.hWnd));
2387 i += 2;
2388 continue;
2390 if (!STRCMP(keywords[i], "state") && (i+1 < nrofkeywords)) {
2391 dwFlags |= MCI_DGV_WINDOW_STATE;
2392 if (!STRCMP(keywords[i+1], "hide"))
2393 pU->dgvwindowParams.nCmdShow = SW_HIDE;
2394 if (!STRCMP(keywords[i+1], "iconic"))
2395 pU->dgvwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
2396 if (!STRCMP(keywords[i+1], "minimized"))
2397 pU->dgvwindowParams.nCmdShow = SW_SHOWMINIMIZED;
2398 if (!STRCMP(keywords[i+1], "maximized"))
2399 pU->dgvwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
2400 if (!STRCMP(keywords[i+1], "minimize"))
2401 pU->dgvwindowParams.nCmdShow = SW_MINIMIZE;
2402 if (!STRCMP(keywords[i+1], "normal"))
2403 pU->dgvwindowParams.nCmdShow = SW_NORMAL;
2404 if (!STRCMP(keywords[i+1], "restore"))
2405 pU->dgvwindowParams.nCmdShow = SW_NORMAL;
2406 if (!STRCMP(keywords[i+1], "show"))
2407 pU->dgvwindowParams.nCmdShow = SW_SHOW;
2408 if (!STRCMP(keywords[i+1], "no") && (i+2 < nrofkeywords)) {
2409 if (!STRCMP(keywords[i+2], "active"))
2410 pU->dgvwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
2411 if (!STRCMP(keywords[i+2], "action"))
2412 pU->dgvwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
2413 i++;
2415 i += 2;
2416 continue;
2418 /* text is enclosed in " ... " as it seems */
2419 if (!STRCMP(keywords[i], "text")) {
2420 if (keywords[i+1][0] != '"') {
2421 i++;
2422 continue;
2424 dwFlags |= MCI_DGV_WINDOW_TEXT;
2425 pU->dgvwindowParams.lpstrText = _MCISTR_Unquote(keywords[i+1]);
2426 i += 2;
2427 continue;
2429 break;
2431 case MCI_DEVTYPE_OVERLAY:
2432 if (!STRCMP(keywords[i], "handle") && (i+1 < nrofkeywords)) {
2433 dwFlags |= MCI_OVLY_WINDOW_HWND;
2434 if (!STRCMP(keywords[i+1], "default"))
2435 pU->ovlywindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
2436 else
2437 sscanf(keywords[i+1], "%d", &(pU->ovlywindowParams.hWnd));
2438 i += 2;
2439 continue;
2441 if (!STRCMP(keywords[i], "state") && (i+1 < nrofkeywords)) {
2442 dwFlags |= MCI_OVLY_WINDOW_STATE;
2443 if (!STRCMP(keywords[i+1], "hide"))
2444 pU->ovlywindowParams.nCmdShow = SW_HIDE;
2445 if (!STRCMP(keywords[i+1], "iconic"))
2446 pU->ovlywindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
2447 if (!STRCMP(keywords[i+1], "minimized"))
2448 pU->ovlywindowParams.nCmdShow = SW_SHOWMINIMIZED;
2449 if (!STRCMP(keywords[i+1], "maximized"))
2450 pU->ovlywindowParams.nCmdShow = SW_SHOWMAXIMIZED;
2451 if (!STRCMP(keywords[i+1], "minimize"))
2452 pU->ovlywindowParams.nCmdShow = SW_MINIMIZE;
2453 if (!STRCMP(keywords[i+1], "normal"))
2454 pU->ovlywindowParams.nCmdShow = SW_NORMAL;
2455 if (!STRCMP(keywords[i+1], "show"))
2456 pU->ovlywindowParams.nCmdShow = SW_SHOW;
2457 if (!STRCMP(keywords[i+1], "no") && (i+2 < nrofkeywords)) {
2458 if (!STRCMP(keywords[i+2], "active"))
2459 pU->ovlywindowParams.nCmdShow = SW_SHOWNOACTIVATE;
2460 if (!STRCMP(keywords[i+2], "action"))
2461 pU->ovlywindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
2462 i++;
2464 i += 2;
2465 continue;
2467 /* text is enclosed in " ... " as it seems */
2468 if (!STRCMP(keywords[i], "text")) {
2469 if (keywords[i+1][0] != '"') {
2470 i++;
2471 continue;
2473 dwFlags |= MCI_OVLY_WINDOW_TEXT;
2474 pU->ovlywindowParams.lpstrText = _MCISTR_Unquote(keywords[i+1]);
2475 i += 2;
2476 continue;
2478 FLAG1("stretch", MCI_OVLY_WINDOW_ENABLE_STRETCH);
2479 break;
2481 i++;
2483 pU->animwindowParams.dwCallback = hwndCallback;
2484 res = mciSendCommandA(wDevID, MCI_WINDOW, dwFlags, (DWORD)pU);
2485 if (s) free(s);
2486 free(pU);
2487 return res;
2490 struct _MCISTR_cmdtable {
2491 char *cmd;
2492 DWORD (*fun)(_MCISTR_PROTO_);
2493 } MCISTR_cmdtable[]={
2494 {"break", MCISTR_Break},
2495 {"capability", MCISTR_Capability},
2496 {"close", MCISTR_Close},
2497 {"cue", MCISTR_Cue},
2498 {"delete", MCISTR_Delete},
2499 {"escape", MCISTR_Escape},
2500 {"freeze", MCISTR_Freeze},
2501 {"info", MCISTR_Info},
2502 {"load", MCISTR_Load},
2503 {"open", MCISTR_Open},
2504 {"pause", MCISTR_Pause},
2505 {"play", MCISTR_Play},
2506 {"put", MCISTR_Put},
2507 {"realize", MCISTR_Realize},
2508 {"record", MCISTR_Record},
2509 {"resume", MCISTR_Resume},
2510 {"save", MCISTR_Save},
2511 {"seek", MCISTR_Seek},
2512 {"set", MCISTR_Set},
2513 {"setaudio", MCISTR_SetAudio},
2514 {"spin", MCISTR_Spin},
2515 {"status", MCISTR_Status},
2516 {"step", MCISTR_Step},
2517 {"stop", MCISTR_Stop},
2518 {"sysinfo", MCISTR_Sysinfo},
2519 {"unfreeze", MCISTR_Unfreeze},
2520 {"update", MCISTR_Update},
2521 {"where", MCISTR_Where},
2522 {"window", MCISTR_Window},
2523 {NULL, NULL}
2526 /**************************************************************************
2527 * mciSendString16 [MMSYSTEM.702]
2529 /* The usercode sends a string with a command (and flags) expressed in
2530 * words in it... We do our best to call appropriate drivers,
2531 * and return a errorcode AND a readable string (if lpstrRS != NULL)
2532 * Info gathered by watching cool134.exe and from Borland's mcistrwh.hlp
2534 /* FIXME: "all" is a valid devicetype and we should access all devices if
2535 * it is used. (imagine "close all"). Not implemented yet.
2537 DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2538 UINT16 uReturnLength, HWND16 hwndCallback)
2540 char *cmd, *dev, *args, **keywords;
2541 WORD uDevTyp = 0, wDevID = 0;
2542 DWORD dwFlags;
2543 int res = 0, i, nrofkeywords;
2545 TRACE(mci, "('%s', %p, %d, %X)\n",
2546 lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2548 /* format is <command> <device> <optargs> */
2549 cmd = strdup(lpstrCommand);
2550 dev = strchr(cmd, ' ');
2551 if (dev == NULL) {
2552 free(cmd);
2553 return MCIERR_MISSING_DEVICE_NAME;
2555 *dev++ = '\0';
2556 args = strchr(dev, ' ');
2558 if (args != NULL) {
2559 char *s;
2561 *args = '\0';
2562 while (*++args == ' ');
2564 i = 1;/* nrofkeywords = nrofspaces+1 */
2565 s = args;
2566 while ((s = strchr(s, ' ')) != NULL) {
2567 i++;
2568 while (*++s == ' ');
2569 /* see if we have a quoted string */
2570 if (*s == '"') {
2571 s = strchr(s+1, '"');
2572 if (!s || s[1] != ' ') {
2573 /* missed closing '"'*/
2574 free(cmd);
2575 return MCIERR_NO_CLOSING_QUOTE;
2579 keywords = (char**)xmalloc(sizeof(char*) * (i + 2));
2580 nrofkeywords = i;
2581 s = args;
2582 i = 0;
2583 while (s && i < nrofkeywords) {
2584 keywords[i++] = s;
2585 if (*s == '"') {
2586 if ((s = strchr(s+1, '"')) != NULL) s++;
2587 } else {
2588 s = strchr(s, ' ');
2590 if (s) {
2591 *s = '\0';
2592 while (*++s == ' ');
2594 TRACE(mci, "[%d] => '%s'\n", i-1, keywords[i-1]);
2596 keywords[i] = NULL;
2597 } else {
2598 nrofkeywords = 0;
2599 keywords = (char**)xmalloc(sizeof(char*));
2600 keywords[0] = NULL;
2602 dwFlags = 0; /* default flags */
2603 for (i = 0; i < nrofkeywords;) {
2604 if (!STRCMP(keywords[i], "wait")) {
2605 dwFlags |= MCI_WAIT;
2606 memcpy(keywords+i, keywords+(i+1), (nrofkeywords-i-1) * sizeof(char*));
2607 nrofkeywords--;
2608 continue;
2610 if (!STRCMP(keywords[i], "notify")) {
2611 dwFlags |= MCI_NOTIFY;
2612 memcpy(keywords+i, keywords+(i+1), (nrofkeywords-i-1) * sizeof(char*));
2613 nrofkeywords--;
2614 continue;
2616 i++;
2619 /* determine wDevID and uDevTyp for all commands except "open" */
2620 if (STRCMP(cmd, "open") != 0) {
2621 wDevID = mciGetDeviceIDA(dev);
2622 if (wDevID == 0) {
2623 TRACE(mci, "Device '%s' not found!\n", dev);
2624 res = MCIERR_INVALID_DEVICE_NAME;
2625 goto the_end;
2627 uDevTyp = MCI_GetDrv(wDevID)->modp.wType;
2630 if (lpstrReturnString && uReturnLength > 0)
2631 *lpstrReturnString = 0;
2633 for (i = 0; MCISTR_cmdtable[i].cmd != NULL; i++) {
2634 if (!STRCMP(MCISTR_cmdtable[i].cmd, cmd)) {
2635 res = MCISTR_cmdtable[i].fun(wDevID, uDevTyp, lpstrReturnString,
2636 uReturnLength, dev, (LPSTR*)keywords,
2637 nrofkeywords, dwFlags, hwndCallback);
2638 break;
2641 if (MCISTR_cmdtable[i].cmd == NULL) {
2642 FIXME(mci, "('%s', %p, %u, %X): unimplemented, please report.\n",
2643 lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2644 res = MCIERR_MISSING_COMMAND_STRING;
2646 the_end:
2647 free(keywords); free(cmd);
2648 return res;
2651 /**************************************************************************
2652 * mciSendStringA [MMSYSTEM.702][WINMM.51]
2654 DWORD WINAPI mciSendStringA(LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2655 UINT uReturnLength, HWND hwndCallback)
2657 return mciSendString16(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2660 /**************************************************************************
2661 * mciSendStringW [WINMM.52]
2663 DWORD WINAPI mciSendStringW(LPCWSTR lpwstrCommand, LPSTR lpstrReturnString,
2664 UINT uReturnLength, HWND hwndCallback)
2666 LPSTR lpstrCommand;
2667 UINT ret;
2669 /* FIXME: is there something to do with lpstrReturnString ? */
2670 lpstrCommand = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrCommand);
2671 ret = mciSendString16(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2672 HeapFree(GetProcessHeap(), 0, lpstrCommand);
2673 return ret;
2676 /**************************************************************************
2677 * mciExecute [WINMM.38]
2679 DWORD WINAPI mciExecute(LPCSTR lpstrCommand)
2681 char strRet[256];
2682 DWORD ret;
2684 TRACE(mci, "(%s)!\n", lpstrCommand);
2686 ret = mciSendString16(lpstrCommand, strRet, sizeof(strRet), 0);
2687 if (ret != 0) {
2688 if (!mciGetErrorString16(ret, strRet, sizeof(strRet))) {
2689 sprintf(strRet, "Unknown MCI error (%ld)", ret);
2691 MessageBoxA(0, strRet, "Error in mciExecute()", MB_OK);
2693 /* FIXME: what shall I return ? */
2694 return 0;