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