Release 990226.
[wine/gsoc-2012-control.git] / multimedia / mcistring.c
blob4d6c1b7d147eba7cfe6775b557c30b417c911286
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MCI stringinterface
6 * Copyright 1995 Marcus Meissner
7 */
8 /* FIXME: special commands of device drivers should be handled by those drivers
9 */
11 /* FIXME: this current implementation does not allow commands like
12 * capability <filename> can play
13 * which is allowed by the MCI standard.
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <fcntl.h>
20 #include <sys/ioctl.h>
21 #include "multimedia.h"
22 #include "heap.h"
23 #include "ldt.h"
24 #include "user.h"
25 #include "driver.h"
26 #include "callback.h"
27 #include "debug.h"
28 #include "xmalloc.h"
30 /* FIXME the following definitions must be moved to mmsystem.c */
31 extern struct WINE_MCIDRIVER mciDrv[MAXMCIDRIVERS];
33 #define MCI_GetDrv(wDevID) (&mciDrv[MCI_DevIDToIndex(wDevID)])
34 #define MCI_GetOpenDrv(wDevID) (&(MCI_GetDrv(wDevID)->mop))
35 /* end of FIXME */
37 /* The reason why I just don't lowercase the keywords array in
38 * mciSendString is left as an exercise to the reader.
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 /* print a DWORD in the specified timeformat */
61 static void
62 _MCISTR_printtf(char *buf,UINT16 uDevType,DWORD timef,DWORD val)
64 *buf = '\0';
65 switch (timef) {
66 case MCI_FORMAT_MILLISECONDS:
67 case MCI_FORMAT_FRAMES:
68 case MCI_FORMAT_BYTES:
69 case MCI_FORMAT_SAMPLES:
70 case MCI_VD_FORMAT_TRACK:
71 /*case MCI_SEQ_FORMAT_SONGPTR: sameas MCI_VD_FORMAT_TRACK */
72 sprintf(buf, "%ld",val);
73 break;
74 case MCI_FORMAT_HMS:
75 /* well, the macros have the same content*/
76 /*FALLTRHOUGH*/
77 case MCI_FORMAT_MSF:
78 sprintf(buf, "%d:%d:%d",
79 MCI_HMS_HOUR(val),
80 MCI_HMS_MINUTE(val),
81 MCI_HMS_SECOND(val));
82 break;
83 case MCI_FORMAT_TMSF:
84 sprintf(buf, "%d:%d:%d:%d",
85 MCI_TMSF_TRACK(val),
86 MCI_TMSF_MINUTE(val),
87 MCI_TMSF_SECOND(val),
88 MCI_TMSF_FRAME(val) );
89 break;
90 default:
91 FIXME(mci, "missing timeformat for %ld, report.\n",timef);
92 strcpy(buf,"0"); /* hmm */
93 break;
95 return;
97 /* possible different return types */
98 #define _MCISTR_int 1
99 #define _MCISTR_time 2
100 #define _MCISTR_bool 3
101 #define _MCISTR_tfname 4
102 #define _MCISTR_mode 5
103 #define _MCISTR_divtype 6
104 #define _MCISTR_seqtype 7
105 #define _MCISTR_vdmtype 8
106 #define _MCISTR_devtype 9
108 static void
109 _MCISTR_convreturn(int type,DWORD dwReturn,LPSTR lpstrReturnString,
110 WORD uReturnLength,WORD uDevTyp,int timef)
112 switch (type) {
113 case _MCISTR_vdmtype:
114 switch (dwReturn) {
115 case MCI_VD_MEDIA_CLV: _MCI_STR("CLV"); break;
116 case MCI_VD_MEDIA_CAV: _MCI_STR("CAV"); break;
117 default:
118 case MCI_VD_MEDIA_OTHER:_MCI_STR("other"); break;
120 break;
121 case _MCISTR_seqtype:
122 switch (dwReturn) {
123 case MCI_SEQ_NONE: _MCI_STR("none"); break;
124 case MCI_SEQ_SMPTE: _MCI_STR("smpte"); break;
125 case MCI_SEQ_FILE: _MCI_STR("file"); break;
126 case MCI_SEQ_MIDI: _MCI_STR("midi"); break;
127 default:FIXME(mci,"missing sequencer mode %ld\n",dwReturn);
129 break;
130 case _MCISTR_mode:
131 switch (dwReturn) {
132 case MCI_MODE_NOT_READY:_MCI_STR("not ready"); break;
133 case MCI_MODE_STOP: _MCI_STR("stopped"); break;
134 case MCI_MODE_PLAY: _MCI_STR("playing"); break;
135 case MCI_MODE_RECORD: _MCI_STR("recording"); break;
136 case MCI_MODE_SEEK: _MCI_STR("seeking"); break;
137 case MCI_MODE_PAUSE: _MCI_STR("paused"); break;
138 case MCI_MODE_OPEN: _MCI_STR("open"); break;
139 default:break;
141 break;
142 case _MCISTR_bool:
143 if (dwReturn)
144 _MCI_STR("true");
145 else
146 _MCI_STR("false");
147 break;
148 case _MCISTR_int:{
149 char buf[16];
150 sprintf(buf,"%ld",dwReturn);
151 _MCI_STR(buf);
152 break;
154 case _MCISTR_time: {
155 char buf[100];
156 _MCISTR_printtf(buf,uDevTyp,timef,dwReturn);
157 _MCI_STR(buf);
158 break;
160 case _MCISTR_tfname:
161 switch (timef) {
162 case MCI_FORMAT_MILLISECONDS: _MCI_STR("milliseconds"); break;
163 case MCI_FORMAT_FRAMES: _MCI_STR("frames"); break;
164 case MCI_FORMAT_BYTES: _MCI_STR("bytes"); break;
165 case MCI_FORMAT_SAMPLES: _MCI_STR("samples"); break;
166 case MCI_FORMAT_HMS: _MCI_STR("hms"); break;
167 case MCI_FORMAT_MSF: _MCI_STR("msf"); break;
168 case MCI_FORMAT_TMSF: _MCI_STR("tmsf"); break;
169 default:
170 FIXME(mci,"missing timefmt for %d, report.\n",timef);
171 break;
173 break;
174 case _MCISTR_divtype:
175 switch (dwReturn) {
176 case MCI_SEQ_DIV_PPQN: _MCI_STR("PPQN"); break;
177 case MCI_SEQ_DIV_SMPTE_24: _MCI_STR("SMPTE 24 frame"); break;
178 case MCI_SEQ_DIV_SMPTE_25: _MCI_STR("SMPTE 25 frame"); break;
179 case MCI_SEQ_DIV_SMPTE_30: _MCI_STR("SMPTE 30 frame"); break;
180 case MCI_SEQ_DIV_SMPTE_30DROP: _MCI_STR("SMPTE 30 frame drop");break;
182 case _MCISTR_devtype:
183 switch (dwReturn) {
184 case MCI_DEVTYPE_VCR: _MCI_STR("vcr"); break;
185 case MCI_DEVTYPE_VIDEODISC: _MCI_STR("videodisc"); break;
186 case MCI_DEVTYPE_CD_AUDIO: _MCI_STR("cd audio"); break;
187 case MCI_DEVTYPE_OVERLAY: _MCI_STR("overlay"); break;
188 case MCI_DEVTYPE_DAT: _MCI_STR("dat"); break;
189 case MCI_DEVTYPE_SCANNER: _MCI_STR("scanner"); break;
190 case MCI_DEVTYPE_ANIMATION: _MCI_STR("animation"); break;
191 case MCI_DEVTYPE_DIGITAL_VIDEO: _MCI_STR("digital video"); break;
192 case MCI_DEVTYPE_OTHER: _MCI_STR("other"); break;
193 case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio"); break;
194 case MCI_DEVTYPE_SEQUENCER: _MCI_STR("sequencer"); break;
195 default:FIXME(mci,"unknown device type %ld, report.\n",
196 dwReturn);break;
198 break;
199 default:
200 FIXME(mci,"unknown resulttype %d, report.\n",type);
201 break;
205 #define FLAG1(str,flag) \
206 if (!STRCMP(keywords[i],str)) { \
207 dwFlags |= flag; \
208 i++; \
209 continue; \
212 #define FLAG2(str1,str2,flag) \
213 if (!STRCMP(keywords[i],str1) && \
214 (i+1<nrofkeywords) && \
215 !STRCMP(keywords[i+1],str2)) { \
216 dwFlags |= flag; \
217 i+=2; \
218 continue; \
221 /* All known subcommands are implemented in single functions to avoid
222 * bloat and a xxxx lines long mciSendString(). All commands are of the
223 * format MCISTR_Cmd(_MCISTR_PROTO_) where _MCISTR_PROTO_ is the above
224 * defined line of arguments. (This is just for easy enhanceability.)
225 * All functions return the MCIERR_ errorvalue as DWORD. Returnvalues
226 * for the calls are in lpstrReturnString (If I mention return values
227 * in function headers, I mean returnvalues in lpstrReturnString.)
228 * Integers are sprintf("%d")ed integers. Boolean values are
229 * "true" and "false".
230 * timeformat depending values are "%d" "%d:%d" "%d:%d:%d" "%d:%d:%d:%d"
231 * FIXME: is above line correct?
233 * Preceding every function is a list of implemented/known arguments.
234 * Feel free to add missing arguments.
239 * Opens the specified MCI driver.
240 * Arguments: <name>
241 * Optional:
242 * "shareable"
243 * "alias <aliasname>"
244 * "element <elementname>"
245 * Additional:
246 * waveform audio:
247 * "buffer <nrBytesPerSec>"
248 * Animation:
249 * "nostatic" increaste nr of nonstatic colours
250 * "parent <windowhandle>"
251 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
252 * "style child" WS_CHILD
253 * "style overlap" WS_OVERLAPPED
254 * "style popup" WS_POPUP
255 * Overlay:
256 * "parent <windowhandle>"
257 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
258 * "style child" WS_CHILD
259 * "style overlap" WS_OVERLAPPED
260 * "style popup" WS_POPUP
261 * Returns nothing.
263 static DWORD
264 MCISTR_Open(_MCISTR_PROTO_)
266 int res,i;
267 char *s;
268 union U {
269 MCI_OPEN_PARMS16 openParams;
270 MCI_WAVE_OPEN_PARMS16 waveopenParams;
271 MCI_ANIM_OPEN_PARMS16 animopenParams;
272 MCI_OVLY_OPEN_PARMS16 ovlyopenParams;
274 union U *pU = xmalloc(sizeof(union U));
276 pU->openParams.lpstrElementName = NULL;
277 s = strchr(dev,'!');
278 if (s != NULL) {
279 *s++ = '\0';
280 pU->openParams.lpstrElementName = strdup(s);
281 dwFlags |= MCI_OPEN_ELEMENT;
283 uDevTyp = MCI_GetDevType(dev);
284 if (uDevTyp == 0) {
285 free(pU->openParams.lpstrElementName);
286 free(pU);
287 return MCIERR_INVALID_DEVICE_NAME;
290 pU->openParams.dwCallback = hwndCallback;
291 pU->openParams.wDeviceID = wDevID;
292 pU->openParams.wReserved0 = 0;
293 pU->ovlyopenParams.dwStyle = 0;
294 pU->animopenParams.dwStyle = 0;
295 pU->openParams.lpstrDeviceType = strdup(dev);
296 pU->openParams.lpstrAlias = NULL;
297 dwFlags |= MCI_OPEN_TYPE;
298 i = 0;
299 while (i < nrofkeywords) {
300 FLAG1("shareable",MCI_OPEN_SHAREABLE);
301 if (!STRCMP(keywords[i],"alias") && (i+1 < nrofkeywords)) {
302 dwFlags |= MCI_OPEN_ALIAS;
303 pU->openParams.lpstrAlias = strdup(keywords[i+1]);
304 i+=2;
305 continue;
307 if (!STRCMP(keywords[i],"element") && (i+1<nrofkeywords)) {
308 dwFlags |= MCI_OPEN_ELEMENT;
309 pU->openParams.lpstrElementName = strdup(keywords[i+1]);
310 i+=2;
311 continue;
313 switch (uDevTyp) {
314 case MCI_DEVTYPE_ANIMATION:
315 case MCI_DEVTYPE_DIGITAL_VIDEO:
316 FLAG1("nostatic",MCI_ANIM_OPEN_NOSTATIC);
317 if (!STRCMP(keywords[i],"parent") && (i+1 < nrofkeywords)) {
318 dwFlags |= MCI_ANIM_OPEN_PARENT;
319 sscanf(keywords[i+1], "%hu", &(pU->animopenParams.hWndParent));
320 i+=2;
321 continue;
323 if (!STRCMP(keywords[i], "style") && (i+1 < nrofkeywords)) {
324 DWORD st;
326 dwFlags |= MCI_ANIM_OPEN_WS;
327 if (!STRCMP(keywords[i+1],"popup")) {
328 pU->animopenParams.dwStyle |= WS_POPUP;
329 } else if (!STRCMP(keywords[i+1],"overlap")) {
330 pU->animopenParams.dwStyle |= WS_OVERLAPPED;
331 } else if (!STRCMP(keywords[i+1],"child")) {
332 pU->animopenParams.dwStyle |= WS_CHILD;
333 } else if (sscanf(keywords[i+1],"%ld",&st)) {
334 pU->animopenParams.dwStyle |= st;
335 } else
336 FIXME(mci, "unknown 'style' keyword %s, please report.\n", keywords[i+1]);
337 i+=2;
338 continue;
340 break;
341 case MCI_DEVTYPE_WAVEFORM_AUDIO:
342 if (!STRCMP(keywords[i],"buffer") && (i+1 < nrofkeywords)) {
343 dwFlags |= MCI_WAVE_OPEN_BUFFER;
344 sscanf(keywords[i+1], "%ld", &(pU->waveopenParams.dwBufferSeconds));
346 break;
347 case MCI_DEVTYPE_OVERLAY:
348 /* looks just like anim, but without NOSTATIC */
349 if (!STRCMP(keywords[i], "parent") && (i+1 < nrofkeywords)) {
350 dwFlags |= MCI_OVLY_OPEN_PARENT;
351 sscanf(keywords[i+1], "%hd", &(pU->ovlyopenParams.hWndParent));
352 i+=2;
353 continue;
355 if (!STRCMP(keywords[i],"style") && (i+1 < nrofkeywords)) {
356 DWORD st;
358 dwFlags |= MCI_OVLY_OPEN_WS;
359 if (!STRCMP(keywords[i+1],"popup")) {
360 pU->ovlyopenParams.dwStyle |= WS_POPUP;
361 } else if (!STRCMP(keywords[i+1],"overlap")) {
362 pU->ovlyopenParams.dwStyle |= WS_OVERLAPPED;
363 } else if (!STRCMP(keywords[i+1],"child")) {
364 pU->ovlyopenParams.dwStyle |= WS_CHILD;
365 } else if (sscanf(keywords[i+1],"%ld",&st)) {
366 pU->ovlyopenParams.dwStyle |= st;
367 } else
368 FIXME(mci,"unknown 'style' keyword %s, please report.\n",keywords[i+1]);
369 i+=2;
370 continue;
372 break;
374 FIXME(mci,"unknown parameter passed %s, please report.\n",
375 keywords[i]);
376 i++;
378 res = mciSendCommandA(0, MCI_OPEN, dwFlags, (DWORD)pU);
380 free(pU->openParams.lpstrElementName);
381 free(pU->openParams.lpstrDeviceType);
382 free(pU->openParams.lpstrAlias);
383 free(pU);
384 return res;
387 /* A help function for a lot of others ...
388 * for instance status/play/record/seek etc.
390 DWORD
391 _MCISTR_determine_timeformat(LPCSTR dev,WORD wDevID,WORD uDevTyp,int *timef)
393 int res;
394 DWORD dwFlags = MCI_STATUS_ITEM;
395 MCI_STATUS_PARMS *statusParams = xmalloc(sizeof(MCI_STATUS_PARMS));
397 if (!statusParams) return 0;
398 statusParams->dwItem = MCI_STATUS_TIME_FORMAT;
399 statusParams->dwReturn = 0;
400 res = mciSendCommandA(wDevID, MCI_STATUS, dwFlags, (DWORD)statusParams);
402 if (res==0) *timef = statusParams->dwReturn;
403 free(statusParams);
404 return res;
407 /* query status of MCI drivers
408 * Arguments:
409 * Required:
410 * "mode" - returns "not ready" "paused" "playing" "stopped" "open"
411 * "parked" "recording" "seeking" ....
412 * Basics:
413 * "current track" - returns current track as integer
414 * "length [track <nr>]" - returns length [of track <nr>] in current
415 * timeformat
416 * "number of tracks" - returns number of tracks as integer
417 * "position [track <nr>]" - returns position [in track <nr>] in current
418 * timeformat
419 * "ready" - checks if device is ready to play, -> bool
420 * "start position" - returns start position in timeformat
421 * "time format" - returns timeformat (list of possible values:
422 * "ms" "msf" "milliseconds" "hmsf" "tmsf" "frames"
423 * "bytes" "samples" "hms")
424 * "media present" - returns if media is present as bool
425 * Animation:
426 * "forward" - returns "true" if device is playing forwards
427 * "speed" - returns speed for device
428 * "palette handle" - returns palette handle
429 * "window handle" - returns window handle
430 * "stretch" - returns stretch bool
431 * MIDI sequencer:
432 * "division type" - ? returns "PPQN" "SMPTE 24 frame"
433 * "SMPTE 25 frame" "SMPTE 30 frame" "SMPTE 30 drop frame"
434 * "tempo" - current tempo in (PPQN? speed in frames, SMPTE*? speed in hsmf)
435 * "offset" - offset in dito.
436 * "port" - midi port as integer
437 * "slave" - slave device ("midi","file","none","smpte")
438 * "master" - masterdevice (dito.)
439 * Overlay:
440 * "window handle" - see animation
441 * "stretch" - dito
442 * Video Disc:
443 * "speed" - speed as integer
444 * "forward" - returns bool (when playing forward)
445 * "side" - returns 1 or 2
446 * "media type" - returns "CAV" "CLV" "other"
447 * "disc size" - returns "8" or "12"
448 * WAVEFORM audio:
449 * "input" - base queries on input set
450 * "output" - base queries on output set
451 * "format tag" - return integer format tag
452 * "channels" - return integer nr of channels
453 * "bytespersec" - return average nr of bytes/sec
454 * "samplespersec" - return nr of samples per sec
455 * "bitspersample" - return bitspersample
456 * "alignment" - return block alignment
457 * "level" - return level?
460 #define ITEM1(str,item,xtype) \
461 if (!STRCMP(keywords[i],str)) { \
462 statusParams->dwItem = item; \
463 type = xtype; \
464 i++; \
465 continue; \
467 #define ITEM2(str1,str2,item,xtype) \
468 if ( !STRCMP(keywords[i],str1) && \
469 (i+1 < nrofkeywords) && \
470 !STRCMP(keywords[i+1],str2)) { \
471 statusParams->dwItem = item; \
472 type = xtype; \
473 i+=2; \
474 continue; \
476 #define ITEM3(str1,str2,str3,item,xtype) \
477 if ( !STRCMP(keywords[i],str1) && \
478 (i+2 < nrofkeywords) && \
479 !STRCMP(keywords[i+1],str2) && \
480 !STRCMP(keywords[i+2],str3)) { \
481 statusParams->dwItem = item; \
482 type = xtype; \
483 i+=3; \
484 continue; \
487 static DWORD
488 MCISTR_Status(_MCISTR_PROTO_) {
489 MCI_STATUS_PARMS *statusParams = xmalloc(sizeof(MCI_STATUS_PARMS));
490 int type = 0,i,res,timef;
492 statusParams->dwCallback = hwndCallback;
493 dwFlags |= MCI_STATUS_ITEM;
494 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
495 if (res) return res;
497 statusParams->dwReturn = 0;
498 statusParams->dwItem = 0;
499 i = 0;
501 while (i < nrofkeywords) {
502 if (!STRCMP(keywords[i],"track") && (i+1 < nrofkeywords)) {
503 sscanf(keywords[i+1],"%ld",&(statusParams->dwTrack));
504 dwFlags |= MCI_TRACK;
505 i+=2;
506 continue;
508 FLAG1("start",MCI_STATUS_START);
509 /* generic things */
510 ITEM2("current","track",MCI_STATUS_CURRENT_TRACK,_MCISTR_time);
511 ITEM2("time","format",MCI_STATUS_TIME_FORMAT,_MCISTR_tfname);
512 ITEM1("ready",MCI_STATUS_READY,_MCISTR_bool);
513 ITEM1("mode",MCI_STATUS_MODE,_MCISTR_mode);
514 ITEM3("number","of","tracks",MCI_STATUS_NUMBER_OF_TRACKS,_MCISTR_int);
515 ITEM1("length",MCI_STATUS_LENGTH,_MCISTR_time);
516 ITEM1("position",MCI_STATUS_POSITION,_MCISTR_time);
517 ITEM2("media","present",MCI_STATUS_MEDIA_PRESENT,_MCISTR_bool);
519 switch (uDevTyp) {
520 case MCI_DEVTYPE_ANIMATION:
521 case MCI_DEVTYPE_DIGITAL_VIDEO:
522 ITEM2("palette","handle",MCI_ANIM_STATUS_HPAL,_MCISTR_int);
523 ITEM2("window","handle",MCI_ANIM_STATUS_HWND,_MCISTR_int);
524 ITEM1("stretch",MCI_ANIM_STATUS_STRETCH,_MCISTR_bool);
525 ITEM1("speed",MCI_ANIM_STATUS_SPEED,_MCISTR_int);
526 ITEM1("forward",MCI_ANIM_STATUS_FORWARD,_MCISTR_bool);
527 break;
528 case MCI_DEVTYPE_SEQUENCER:
529 /* just completing the list, not working correctly */
530 ITEM2("division","type",MCI_SEQ_STATUS_DIVTYPE,_MCISTR_divtype);
531 /* tempo ... PPQN in frames/second, SMPTE in hmsf */
532 ITEM1("tempo",MCI_SEQ_STATUS_TEMPO,_MCISTR_int);
533 ITEM1("port",MCI_SEQ_STATUS_PORT,_MCISTR_int);
534 ITEM1("slave",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
535 ITEM1("master",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
536 /* offset ... PPQN in frames/second, SMPTE in hmsf */
537 ITEM1("offset",MCI_SEQ_STATUS_SLAVE,_MCISTR_time);
538 break;
539 case MCI_DEVTYPE_OVERLAY:
540 ITEM2("window","handle",MCI_OVLY_STATUS_HWND,_MCISTR_int);
541 ITEM1("stretch",MCI_OVLY_STATUS_STRETCH,_MCISTR_bool);
542 break;
543 case MCI_DEVTYPE_VIDEODISC:
544 ITEM1("speed",MCI_VD_STATUS_SPEED,_MCISTR_int);
545 ITEM1("forward",MCI_VD_STATUS_FORWARD,_MCISTR_bool);
546 ITEM1("side",MCI_VD_STATUS_SIDE,_MCISTR_int);
547 ITEM2("media","type",MCI_VD_STATUS_SIDE,_MCISTR_vdmtype);
548 /* returns 8 or 12 */
549 ITEM2("disc","size",MCI_VD_STATUS_DISC_SIZE,_MCISTR_int);
550 break;
551 case MCI_DEVTYPE_WAVEFORM_AUDIO:
552 /* I am not quite sure if foll. 2 lines are right. */
553 FLAG1("input",MCI_WAVE_INPUT);
554 FLAG1("output",MCI_WAVE_OUTPUT);
556 ITEM2("format","tag",MCI_WAVE_STATUS_FORMATTAG,_MCISTR_int);
557 ITEM1("channels",MCI_WAVE_STATUS_CHANNELS,_MCISTR_int);
558 ITEM1("bytespersec",MCI_WAVE_STATUS_AVGBYTESPERSEC,_MCISTR_int);
559 ITEM1("samplespersec",MCI_WAVE_STATUS_SAMPLESPERSEC,_MCISTR_int);
560 ITEM1("bitspersample",MCI_WAVE_STATUS_BITSPERSAMPLE,_MCISTR_int);
561 ITEM1("alignment",MCI_WAVE_STATUS_BLOCKALIGN,_MCISTR_int);
562 ITEM1("level",MCI_WAVE_STATUS_LEVEL,_MCISTR_int);
563 break;
565 FIXME(mci,"unknown keyword '%s'\n",keywords[i]);
566 i++;
568 if (!statusParams->dwItem)
569 return MCIERR_MISSING_STRING_ARGUMENT;
571 res = mciSendCommandA(wDevID, MCI_STATUS, dwFlags, (DWORD)statusParams);
573 if (res==0)
574 _MCISTR_convreturn(type,statusParams->dwReturn,lpstrReturnString,uReturnLength,uDevTyp,timef);
575 free(statusParams);
576 return res;
578 #undef ITEM1
579 #undef ITEM2
580 #undef ITEM3
582 /* set specified parameters in respective MCI drivers
583 * Arguments:
584 * "door open" eject media or somesuch
585 * "door close" load media
586 * "time format <timeformatname>" "ms" "milliseconds" "msf" "hmsf"
587 * "tmsf" "SMPTE 24" "SMPTE 25" "SMPTE 30"
588 * "SMPTE drop 30"
589 * "audio [all|left|right] [on|off]" sets specified audiochannel on or off
590 * "video [on|off]" sets video on/off
591 * Waveform audio:
592 * "formattag pcm" sets format to pcm
593 * "formattag <nr>" sets integer formattag value
594 * "any input" accept input from any known source
595 * "any output" output to any known destination
596 * "input <nr>" input from source <nr>
597 * "output <nr>" output to destination <nr>
598 * "channels <nr>" sets nr of channels
599 * "bytespersec <nr>" sets average bytes per second
600 * "samplespersec <nr>" sets average samples per second (1 sample can
601 * be 2 bytes!)
602 * "alignment <nr>" sets the blockalignment to <nr>
603 * "bitspersample <nr>" sets the nr of bits per sample
604 * Sequencer:
605 * "master [midi|file|smpte|none]" sets the midi master device
606 * "slave [midi|file|smpte|none]" sets the midi master device
607 * "port mapper" midioutput to portmapper
608 * "port <nr>" midioutput to specified port
609 * "tempo <nr>" tempo of track (depends on timeformat/divtype)
610 * "offset <nr>" start offset?
612 static DWORD
613 MCISTR_Set(_MCISTR_PROTO_) {
614 union U {
615 MCI_SET_PARMS setParams;
616 MCI_WAVE_SET_PARMS16 wavesetParams;
617 MCI_SEQ_SET_PARMS seqsetParams;
619 union U *pU = xmalloc(sizeof(union U));
620 int i,res;
622 pU->setParams.dwCallback = hwndCallback;
623 i = 0;
624 while (i < nrofkeywords) {
625 FLAG2("door","open",MCI_SET_DOOR_OPEN);
626 FLAG2("door","closed",MCI_SET_DOOR_CLOSED);
628 if ( !STRCMP(keywords[i],"time") &&
629 (i+2 < nrofkeywords) &&
630 !STRCMP(keywords[i+1],"format")
632 dwFlags |= MCI_SET_TIME_FORMAT;
634 /* FIXME:is this a shortcut for milliseconds or
635 * minutes:seconds? */
636 if (!STRCMP(keywords[i+2],"ms"))
637 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
639 if (!STRCMP(keywords[i+2],"milliseconds"))
640 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
641 if (!STRCMP(keywords[i+2],"msf"))
642 pU->setParams.dwTimeFormat = MCI_FORMAT_MSF;
643 if (!STRCMP(keywords[i+2],"hms"))
644 pU->setParams.dwTimeFormat = MCI_FORMAT_HMS;
645 if (!STRCMP(keywords[i+2],"frames"))
646 pU->setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
647 if (!STRCMP(keywords[i+2],"track"))
648 pU->setParams.dwTimeFormat = MCI_VD_FORMAT_TRACK;
649 if (!STRCMP(keywords[i+2],"bytes"))
650 pU->setParams.dwTimeFormat = MCI_FORMAT_BYTES;
651 if (!STRCMP(keywords[i+2],"samples"))
652 pU->setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
653 if (!STRCMP(keywords[i+2],"tmsf"))
654 pU->setParams.dwTimeFormat = MCI_FORMAT_TMSF;
655 if ( !STRCMP(keywords[i+2],"song") &&
656 (i+3 < nrofkeywords) &&
657 !STRCMP(keywords[i+3],"pointer")
659 pU->setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR;
660 if (!STRCMP(keywords[i+2],"smpte") && (i+3 < nrofkeywords)) {
661 if (!STRCMP(keywords[i+3],"24"))
662 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
663 if (!STRCMP(keywords[i+3],"25"))
664 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
665 if (!STRCMP(keywords[i+3],"30"))
666 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
667 if (!STRCMP(keywords[i+3],"drop") && (i+4 < nrofkeywords) && !STRCMP(keywords[i+4],"30")) {
668 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
669 i++;
671 i++;
672 /*FALLTHROUGH*/
674 i+=3;
675 continue;
677 if (!STRCMP(keywords[i],"audio") && (i+1 < nrofkeywords)) {
678 dwFlags |= MCI_SET_AUDIO;
679 if (!STRCMP(keywords[i+1],"all"))
680 pU->setParams.dwAudio = MCI_SET_AUDIO_ALL;
681 if (!STRCMP(keywords[i+1],"left"))
682 pU->setParams.dwAudio = MCI_SET_AUDIO_LEFT;
683 if (!STRCMP(keywords[i+1],"right"))
684 pU->setParams.dwAudio = MCI_SET_AUDIO_RIGHT;
685 i+=2;
686 continue;
688 FLAG1("video",MCI_SET_VIDEO);
689 FLAG1("on",MCI_SET_ON);
690 FLAG1("off",MCI_SET_OFF);
691 switch (uDevTyp) {
692 case MCI_DEVTYPE_WAVEFORM_AUDIO:
693 FLAG2("any","input",MCI_WAVE_SET_ANYINPUT);
694 FLAG2("any","output",MCI_WAVE_SET_ANYOUTPUT);
696 if ( !STRCMP(keywords[i],"formattag") &&
697 (i+1 < nrofkeywords) &&
698 !STRCMP(keywords[i+1],"pcm")
700 dwFlags |= MCI_WAVE_SET_FORMATTAG;
701 pU->wavesetParams.wFormatTag = WAVE_FORMAT_PCM;
702 i+=2;
703 continue;
706 /* <keyword> <integer> */
707 #define WII(str,flag,fmt,element) \
708 if (!STRCMP(keywords[i],str) && \
709 (i+1 < nrofkeywords)) { \
710 sscanf(keywords[i+1], fmt, \
711 &(pU->wavesetParams. element)); \
712 dwFlags |= flag; \
713 i+=2; \
714 continue; \
716 WII("formattag",MCI_WAVE_SET_FORMATTAG,"%hu",wFormatTag);
717 WII("channels",MCI_WAVE_SET_CHANNELS,"%hu",nChannels);
718 WII("bytespersec",MCI_WAVE_SET_AVGBYTESPERSEC,"%lu",nAvgBytesPerSec);
719 WII("samplespersec",MCI_WAVE_SET_SAMPLESPERSEC,"%lu",nSamplesPerSec);
720 WII("alignment",MCI_WAVE_SET_BLOCKALIGN,"%hu",nBlockAlign);
721 WII("bitspersample",MCI_WAVE_SET_BITSPERSAMPLE,"%hu",wBitsPerSample);
722 WII("input",MCI_WAVE_INPUT,"%hu",wInput);
723 WII("output",MCI_WAVE_OUTPUT,"%hu",wOutput);
724 #undef WII
725 break;
726 case MCI_DEVTYPE_SEQUENCER:
727 if (!STRCMP(keywords[i],"master") && (i+1 < nrofkeywords)) {
728 dwFlags |= MCI_SEQ_SET_MASTER;
729 if (!STRCMP(keywords[i+1],"midi"))
730 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
731 if (!STRCMP(keywords[i+1],"file"))
732 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
733 if (!STRCMP(keywords[i+1],"smpte"))
734 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
735 if (!STRCMP(keywords[i+1],"none"))
736 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
737 i+=2;
738 continue;
740 if (!STRCMP(keywords[i],"slave") && (i+1 < nrofkeywords)) {
741 dwFlags |= MCI_SEQ_SET_SLAVE;
742 if (!STRCMP(keywords[i+1],"midi"))
743 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
744 if (!STRCMP(keywords[i+1],"file"))
745 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
746 if (!STRCMP(keywords[i+1],"smpte"))
747 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
748 if (!STRCMP(keywords[i+1],"none"))
749 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
750 i+=2;
751 continue;
753 if ( !STRCMP(keywords[i],"port") &&
754 (i+1 < nrofkeywords) &&
755 !STRCMP(keywords[i+1],"mapper")
757 pU->seqsetParams.dwPort=-1;/* FIXME:not sure*/
758 dwFlags |= MCI_SEQ_SET_PORT;
759 i+=2;
760 continue;
762 #define SII(str,flag,element) \
763 if (!STRCMP(keywords[i],str) && (i+1 < nrofkeywords)) {\
764 sscanf(keywords[i+1],"%ld",&(pU->seqsetParams. element));\
765 dwFlags |= flag;\
766 i+=2;\
767 continue;\
769 SII("tempo",MCI_SEQ_SET_TEMPO,dwTempo);
770 SII("port",MCI_SEQ_SET_PORT,dwPort);
771 SII("offset",MCI_SEQ_SET_PORT,dwOffset);
773 i++;
775 if (!dwFlags)
776 return MCIERR_MISSING_STRING_ARGUMENT;
777 res = mciSendCommandA(wDevID, MCI_SET, dwFlags, (DWORD)pU);
778 free(pU);
779 return res;
782 /* specify break key
783 * Arguments:
784 * "off" disable break
785 * "on <keyid>" enable break on key with keyid
786 * (I strongly suspect, that there is another parameter:
787 * "window <handle>"
788 * but I don't see it mentioned in my documentation.
789 * Returns nothing.
791 static DWORD
792 MCISTR_Break(_MCISTR_PROTO_)
794 MCI_BREAK_PARMS16 *breakParams = xmalloc(sizeof(MCI_BREAK_PARMS16));
795 int res,i;
797 if (!breakParams) return 0;
798 /*breakParams.hwndBreak ? */
799 for (i = 0; i < nrofkeywords; i++) {
800 FLAG1("off",MCI_BREAK_OFF);
801 if (!strcmp(keywords[i],"on") && (nrofkeywords>i+1)) {
802 dwFlags&=~MCI_BREAK_OFF;
803 dwFlags|=MCI_BREAK_KEY;
804 sscanf(keywords[i+1],"%hd",&(breakParams->nVirtKey));
805 i+=2;
806 continue;
809 res = mciSendCommandA(wDevID, MCI_BREAK, dwFlags, (DWORD)breakParams);
810 free(breakParams);
811 return res;
814 #define ITEM1(str,item,xtype) \
815 if (!STRCMP(keywords[i],str)) { \
816 gdcParams->dwItem = item; \
817 type = xtype; \
818 i++; \
819 continue; \
821 #define ITEM2(str1,str2,item,xtype) \
822 if ( !STRCMP(keywords[i],str1) && \
823 (i+1 < nrofkeywords) && \
824 !STRCMP(keywords[i+1],str2)) { \
825 gdcParams->dwItem = item; \
826 type = xtype; \
827 i+=2; \
828 continue; \
830 #define ITEM3(str1,str2,str3,item,xtype) \
831 if ( !STRCMP(keywords[i],str1) && \
832 (i+2 < nrofkeywords) && \
833 !STRCMP(keywords[i+1],str2) && \
834 !STRCMP(keywords[i+2],str3)) { \
835 gdcParams->dwItem = item; \
836 type = xtype; \
837 i+=3; \
838 continue; \
841 /* get device capabilities of MCI drivers
842 * Arguments:
843 * Generic:
844 * "device type" returns device name as string
845 * "has audio" returns bool
846 * "has video" returns bool
847 * "uses files" returns bool
848 * "compound device" returns bool
849 * "can record" returns bool
850 * "can play" returns bool
851 * "can eject" returns bool
852 * "can save" returns bool
853 * Animation:
854 * "palettes" returns nr of available palette entries
855 * "windows" returns nr of available windows
856 * "can reverse" returns bool
857 * "can stretch" returns bool
858 * "slow play rate" returns the slow playrate
859 * "fast play rate" returns the fast playrate
860 * "normal play rate" returns the normal playrate
861 * Overlay:
862 * "windows" returns nr of available windows
863 * "can stretch" returns bool
864 * "can freeze" returns bool
865 * Videodisc:
866 * "cav" assume CAV discs (default if no disk inserted)
867 * "clv" assume CLV discs
868 * "can reverse" returns bool
869 * "slow play rate" returns the slow playrate
870 * "fast play rate" returns the fast playrate
871 * "normal play rate" returns the normal playrate
872 * Waveform audio:
873 * "inputs" returns nr of inputdevices
874 * "outputs" returns nr of outputdevices
876 static DWORD
877 MCISTR_Capability(_MCISTR_PROTO_) {
878 MCI_GETDEVCAPS_PARMS *gdcParams = xmalloc(sizeof(MCI_GETDEVCAPS_PARMS));
879 int type=0,i,res;
881 gdcParams->dwCallback = hwndCallback;
882 if (!nrofkeywords)
883 return MCIERR_MISSING_STRING_ARGUMENT;
884 /* well , thats default */
885 dwFlags |= MCI_GETDEVCAPS_ITEM;
886 gdcParams->dwItem = 0;
887 i=0;
888 while (i < nrofkeywords) {
889 ITEM2("device","type",MCI_GETDEVCAPS_DEVICE_TYPE,_MCISTR_devtype);
890 ITEM2("has","audio",MCI_GETDEVCAPS_HAS_AUDIO,_MCISTR_bool);
891 ITEM2("has","video",MCI_GETDEVCAPS_HAS_VIDEO,_MCISTR_bool);
892 ITEM2("uses","files",MCI_GETDEVCAPS_USES_FILES,_MCISTR_bool);
893 ITEM2("compound","device",MCI_GETDEVCAPS_COMPOUND_DEVICE,_MCISTR_bool);
894 ITEM2("can","record",MCI_GETDEVCAPS_CAN_RECORD,_MCISTR_bool);
895 ITEM2("can","play",MCI_GETDEVCAPS_CAN_PLAY,_MCISTR_bool);
896 ITEM2("can","eject",MCI_GETDEVCAPS_CAN_EJECT,_MCISTR_bool);
897 ITEM2("can","save",MCI_GETDEVCAPS_CAN_SAVE,_MCISTR_bool);
898 switch (uDevTyp) {
899 case MCI_DEVTYPE_ANIMATION:
900 ITEM1("palettes",MCI_ANIM_GETDEVCAPS_PALETTES,_MCISTR_int);
901 ITEM1("windows",MCI_ANIM_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
902 ITEM2("can","reverse",MCI_ANIM_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
903 ITEM2("can","stretch",MCI_ANIM_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
904 ITEM3("slow","play","rate",MCI_ANIM_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
905 ITEM3("fast","play","rate",MCI_ANIM_GETDEVCAPS_FAST_RATE,_MCISTR_int);
906 ITEM3("normal","play","rate",MCI_ANIM_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
907 break;
908 case MCI_DEVTYPE_OVERLAY:
909 ITEM1("windows",MCI_OVLY_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
910 ITEM2("can","freeze",MCI_OVLY_GETDEVCAPS_CAN_FREEZE,_MCISTR_bool);
911 ITEM2("can","stretch",MCI_OVLY_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
912 break;
913 case MCI_DEVTYPE_VIDEODISC:
914 FLAG1("cav",MCI_VD_GETDEVCAPS_CAV);
915 FLAG1("clv",MCI_VD_GETDEVCAPS_CLV);
916 ITEM2("can","reverse",MCI_VD_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
917 ITEM3("slow","play","rate",MCI_VD_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
918 ITEM3("fast","play","rate",MCI_VD_GETDEVCAPS_FAST_RATE,_MCISTR_int);
919 ITEM3("normal","play","rate",MCI_VD_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
920 break;
921 case MCI_DEVTYPE_WAVEFORM_AUDIO:
922 ITEM1("inputs",MCI_WAVE_GETDEVCAPS_INPUTS,_MCISTR_int);
923 ITEM1("outputs",MCI_WAVE_GETDEVCAPS_OUTPUTS,_MCISTR_int);
924 break;
926 i++;
928 res = mciSendCommandA(wDevID, MCI_GETDEVCAPS, dwFlags, (DWORD)gdcParams);
930 /* no timeformat needed */
931 if (res==0)
932 _MCISTR_convreturn(type, gdcParams->dwReturn, lpstrReturnString,
933 uReturnLength, uDevTyp, 0);
934 free(gdcParams);
935 return res;
937 #undef ITEM1
938 #undef ITEM2
939 #undef ITEM3
940 /* resumes operation of device. no arguments, no return values */
941 static DWORD
942 MCISTR_Resume(_MCISTR_PROTO_)
944 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
945 int res;
946 genParams->dwCallback = hwndCallback;
947 res = mciSendCommandA(wDevID, MCI_RESUME, dwFlags, (DWORD)genParams);
948 free(genParams);
949 return res;
952 /* pauses operation of device. no arguments, no return values */
953 static DWORD
954 MCISTR_Pause(_MCISTR_PROTO_)
956 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
957 int res;
958 genParams->dwCallback = hwndCallback;
959 res = mciSendCommandA(wDevID, MCI_PAUSE, dwFlags, (DWORD)genParams);
960 free(genParams);
961 return res;
964 /* stops operation of device. no arguments, no return values */
965 static DWORD
966 MCISTR_Stop(_MCISTR_PROTO_)
968 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
969 int res;
970 genParams->dwCallback = hwndCallback;
971 res = mciSendCommandA(wDevID, MCI_STOP, dwFlags, (DWORD)genParams);
972 free(genParams);
973 return res;
976 /* starts recording.
977 * Arguments:
978 * "overwrite" overwrite existing things
979 * "insert" insert at current position
980 * "to <time>" record up to <time> (specified in timeformat)
981 * "from <time>" record from <time> (specified in timeformat)
983 static DWORD
984 MCISTR_Record(_MCISTR_PROTO_) {
985 int i,res,timef,nrargs,j,k,a[4];
986 char *parsestr;
987 MCI_RECORD_PARMS *recordParams = xmalloc(sizeof(MCI_RECORD_PARMS));
989 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
990 if (res) return res;
992 switch (timef) {
993 case MCI_FORMAT_MILLISECONDS:
994 case MCI_FORMAT_FRAMES:
995 case MCI_FORMAT_BYTES:
996 case MCI_FORMAT_SAMPLES:
997 nrargs=1;
998 parsestr="%d";
999 break;
1000 case MCI_FORMAT_HMS:
1001 case MCI_FORMAT_MSF:
1002 parsestr="%d:%d:%d";
1003 nrargs=3;
1004 break;
1005 case MCI_FORMAT_TMSF:
1006 parsestr="%d:%d:%d:%d";
1007 nrargs=4;
1008 break;
1009 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1010 parsestr="%d";
1011 nrargs=1;
1012 break;
1014 recordParams->dwCallback = hwndCallback;
1015 i = 0;
1016 while (i < nrofkeywords) {
1017 if (!strcmp(keywords[i],"to") && (i+1 < nrofkeywords)) {
1018 dwFlags |= MCI_TO;
1019 a[0]=a[1]=a[2]=a[3]=0;
1020 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1021 /* add up all integers we got, if we have more
1022 * shift them. (Well I should use the macros in
1023 * mmsystem.h, right).
1025 recordParams->dwTo=0;
1026 for (k=0;k < j;k++)
1027 recordParams->dwTo+=a[k] << (8*(nrargs-k));
1028 i+=2;
1029 continue;
1031 if (!strcmp(keywords[i],"from") && (i+1 < nrofkeywords)) {
1032 dwFlags |= MCI_FROM;
1033 a[0]=a[1]=a[2]=a[3]=0;
1034 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1035 /* dito. */
1036 recordParams->dwFrom=0;
1037 for (k=0;k < j;k++)
1038 recordParams->dwFrom+=a[k]<<(8*(nrargs-k));
1039 i+=2;
1040 continue;
1042 FLAG1("insert",MCI_RECORD_INSERT);
1043 FLAG1("overwrite",MCI_RECORD_OVERWRITE);
1044 i++;
1046 res = mciSendCommandA(wDevID, MCI_RECORD, dwFlags, (DWORD)recordParams);
1047 free(recordParams);
1048 return res;
1051 /* play media
1052 * Arguments:
1053 * "to <time>" play up to <time> (specified in set timeformat)
1054 * "from <time>" play from <time> (specified in set timeformat)
1055 * Animation:
1056 * "slow" play slow
1057 * "fast" play fast
1058 * "scan" play as fast as possible (with audio disabled perhaps)
1059 * "reverse" play reverse
1060 * "speed <fps>" play with specified frames per second
1061 * Videodisc:
1062 * "slow" play slow
1063 * "fast" play fast
1064 * "scan" play as fast as possible (with audio disabled perhaps)
1065 * "reverse" play reverse
1066 * "speed <fps>" play with specified frames per second
1068 static DWORD
1069 MCISTR_Play(_MCISTR_PROTO_) {
1070 int i,res,timef,nrargs,j,k,a[4];
1071 char *parsestr;
1072 union U {
1073 MCI_PLAY_PARMS playParams;
1074 MCI_VD_PLAY_PARMS vdplayParams;
1075 MCI_ANIM_PLAY_PARMS animplayParams;
1077 union U *pU = xmalloc(sizeof(union U));
1079 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1080 if (res) return res;
1081 switch (timef) {
1082 case MCI_FORMAT_MILLISECONDS:
1083 case MCI_FORMAT_FRAMES:
1084 case MCI_FORMAT_BYTES:
1085 case MCI_FORMAT_SAMPLES:
1086 nrargs=1;
1087 parsestr="%d";
1088 break;
1089 case MCI_FORMAT_HMS:
1090 case MCI_FORMAT_MSF:
1091 parsestr="%d:%d:%d";
1092 nrargs=3;
1093 break;
1094 case MCI_FORMAT_TMSF:
1095 parsestr="%d:%d:%d:%d";
1096 nrargs=4;
1097 break;
1098 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1099 parsestr="%d";
1100 nrargs=1;
1101 break;
1103 pU->playParams.dwCallback=hwndCallback;
1104 i=0;
1105 while (i < nrofkeywords) {
1106 if (!strcmp(keywords[i],"to") && (i+1 < nrofkeywords)) {
1107 dwFlags |= MCI_TO;
1108 a[0]=a[1]=a[2]=a[3]=0;
1109 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1110 /* add up all integers we got, if we have more
1111 * shift them. (Well I should use the macros in
1112 * mmsystem.h, right).
1114 pU->playParams.dwTo=0;
1115 for (k=0;k < j;k++)
1116 pU->playParams.dwTo+=a[k] << (8*(nrargs-k));
1117 i+=2;
1118 continue;
1120 if (!strcmp(keywords[i],"from") && (i+1 < nrofkeywords)) {
1121 dwFlags |= MCI_FROM;
1122 a[0]=a[1]=a[2]=a[3]=0;
1123 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1124 /* dito. */
1125 pU->playParams.dwFrom=0;
1126 for (k=0;k < j;k++)
1127 pU->playParams.dwFrom+=a[k]<<(8*(nrargs-k));
1128 i+=2;
1129 continue;
1131 switch (uDevTyp) {
1132 case MCI_DEVTYPE_VIDEODISC:
1133 FLAG1("slow",MCI_VD_PLAY_SLOW);
1134 FLAG1("fast",MCI_VD_PLAY_FAST);
1135 FLAG1("scan",MCI_VD_PLAY_SCAN);
1136 FLAG1("reverse",MCI_VD_PLAY_REVERSE);
1137 if (!STRCMP(keywords[i],"speed") && (i+1 < nrofkeywords)) {
1138 dwFlags |= MCI_VD_PLAY_SPEED;
1139 sscanf(keywords[i+1],"%ld",&(pU->vdplayParams.dwSpeed));
1140 i+=2;
1141 continue;
1143 break;
1144 case MCI_DEVTYPE_ANIMATION:
1145 FLAG1("slow",MCI_ANIM_PLAY_SLOW);
1146 FLAG1("fast",MCI_ANIM_PLAY_FAST);
1147 FLAG1("scan",MCI_ANIM_PLAY_SCAN);
1148 FLAG1("reverse",MCI_ANIM_PLAY_REVERSE);
1149 if (!STRCMP(keywords[i],"speed") && (i+1 < nrofkeywords)) {
1150 dwFlags |= MCI_ANIM_PLAY_SPEED;
1151 sscanf(keywords[i+1],"%ld",&(pU->animplayParams.dwSpeed));
1152 i+=2;
1153 continue;
1155 break;
1157 i++;
1159 res = mciSendCommandA(wDevID, MCI_PLAY, dwFlags, (DWORD)pU);
1160 free(pU);
1161 return res;
1164 /* seek to a specified position
1165 * Arguments:
1166 * "to start" seek to start of medium
1167 * "to end" seek to end of medium
1168 * "to <time>" seek to <time> specified in current timeformat
1170 static DWORD
1171 MCISTR_Seek(_MCISTR_PROTO_) {
1172 int i,res,timef,nrargs,j,k,a[4];
1173 char *parsestr;
1174 MCI_SEEK_PARMS *seekParams = xmalloc(sizeof(MCI_SEEK_PARMS));
1176 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1177 if (res) return res;
1178 switch (timef) {
1179 case MCI_FORMAT_MILLISECONDS:
1180 case MCI_FORMAT_FRAMES:
1181 case MCI_FORMAT_BYTES:
1182 case MCI_FORMAT_SAMPLES:
1183 nrargs=1;
1184 parsestr="%d";
1185 break;
1186 case MCI_FORMAT_HMS:
1187 case MCI_FORMAT_MSF:
1188 parsestr="%d:%d:%d";
1189 nrargs=3;
1190 break;
1191 case MCI_FORMAT_TMSF:
1192 parsestr="%d:%d:%d:%d";
1193 nrargs=4;
1194 break;
1195 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1196 parsestr="%d";
1197 nrargs=1;
1198 break;
1200 seekParams->dwCallback=hwndCallback;
1201 i=0;
1202 while (i < nrofkeywords) {
1203 if ( !STRCMP(keywords[i],"to") && (i+1 < nrofkeywords)) {
1204 if (!STRCMP(keywords[i+1],"start")) {
1205 dwFlags|=MCI_SEEK_TO_START;
1206 seekParams->dwTo=0;
1207 i+=2;
1208 continue;
1210 if (!STRCMP(keywords[i+1],"end")) {
1211 dwFlags|=MCI_SEEK_TO_END;
1212 seekParams->dwTo=0;
1213 i+=2;
1214 continue;
1216 dwFlags|=MCI_TO;
1217 i+=2;
1218 a[0]=a[1]=a[2]=a[3]=0;
1219 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1220 seekParams->dwTo=0;
1221 for (k=0;k < j;k++)
1222 seekParams->dwTo+=a[k] << (8*(nrargs-k));
1223 continue;
1225 switch (uDevTyp) {
1226 case MCI_DEVTYPE_VIDEODISC:
1227 FLAG1("reverse",MCI_VD_SEEK_REVERSE);
1228 break;
1230 i++;
1232 res = mciSendCommandA(wDevID, MCI_SEEK, dwFlags, (DWORD)seekParams);
1233 free(seekParams);
1234 return res;
1237 /* close media/driver */
1238 static DWORD
1239 MCISTR_Close(_MCISTR_PROTO_)
1241 MCI_GENERIC_PARMS* closeParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1242 int res;
1244 res = mciSendCommandA(wDevID, MCI_CLOSE, dwFlags, (DWORD)closeParams);
1245 free(closeParams);
1246 return res;
1249 /* return information.
1250 * Arguments:
1251 * "product" return product name (human readable)
1252 * "file" return filename
1253 * Animation:
1254 * "text" returns text?
1255 * Overlay:
1256 * "text" returns text?
1258 static DWORD
1259 MCISTR_Info(_MCISTR_PROTO_)
1261 MCI_INFO_PARMS16* infoParams = xmalloc(sizeof(MCI_INFO_PARMS16));
1262 DWORD sflags;
1263 int i,res;
1265 sflags = dwFlags;
1266 i=0;
1267 while (i < nrofkeywords) {
1268 FLAG1("product",MCI_INFO_PRODUCT);
1269 FLAG1("file",MCI_INFO_FILE);
1270 switch (uDevTyp) {
1271 case MCI_DEVTYPE_ANIMATION:
1272 FLAG1("text",MCI_ANIM_INFO_TEXT);
1273 break;
1274 case MCI_DEVTYPE_OVERLAY:
1275 FLAG1("text",MCI_OVLY_INFO_TEXT);
1276 break;
1278 i++;
1280 if (dwFlags == sflags)
1281 return MCIERR_MISSING_STRING_ARGUMENT;
1282 /* MCI driver will fill in lpstrReturn, dwRetSize.
1283 * FIXME: I don't know if this is correct behaviour
1285 res = mciSendCommandA(wDevID, MCI_INFO, dwFlags, (DWORD)infoParams);
1286 if (res==0)
1287 _MCI_STR(infoParams->lpstrReturn);
1288 free(infoParams);
1289 return res;
1292 /* query MCI driver itself for information
1293 * Arguments:
1294 * "installname" return install name of <device> (system.ini)
1295 * "quantity" return nr of installed drivers
1296 * "open" open drivers only (additional flag)
1297 * "name <nr>" return nr of devices with <devicetyp>
1298 * "name all" return nr of all devices
1300 * FIXME: mciSysInfo16() is broken I think.
1302 static DWORD
1303 MCISTR_Sysinfo(_MCISTR_PROTO_) {
1304 MCI_SYSINFO_PARMS16 sysinfoParams;
1305 int i,res;
1307 sysinfoParams.lpstrReturn = lpstrReturnString;
1308 sysinfoParams.dwRetSize = uReturnLength;
1309 sysinfoParams.wDeviceType = uDevTyp;
1311 for (i = 0; i < nrofkeywords; i++) {
1312 FLAG1("installname",MCI_SYSINFO_INSTALLNAME);
1313 FLAG1("quantity",MCI_SYSINFO_INSTALLNAME);
1314 FLAG1("open",MCI_SYSINFO_OPEN);
1315 if (!strcmp(keywords[i],"name") && (i+1 < nrofkeywords)) {
1316 sscanf(keywords[i+1],"%ld",&(sysinfoParams.dwNumber));
1317 dwFlags |= MCI_SYSINFO_NAME;
1318 i++;
1321 res = mciSendCommand16(0, MCI_SYSINFO, dwFlags, (DWORD)&sysinfoParams);
1323 if (dwFlags & MCI_SYSINFO_QUANTITY) {
1324 char buf[100];
1326 sprintf(buf,"%ld",*(long*)lpstrReturnString);
1327 _MCI_STR(buf);
1329 /* no need to copy anything back, mciSysInfo did it for us */
1330 return res;
1333 /* load file
1334 * Argument: "<filename>"
1335 * Overlay: "at <left> <top> <right> <bottom>" additional
1337 static DWORD
1338 MCISTR_Load(_MCISTR_PROTO_) {
1339 union U {
1340 MCI_LOAD_PARMS16 loadParams;
1341 MCI_OVLY_LOAD_PARMS16 ovlyloadParams;
1343 union U *pU = xmalloc(sizeof(union U));
1344 int i,len,res;
1345 char *s;
1347 i=len=0;
1348 while (i < nrofkeywords) {
1349 switch (uDevTyp) {
1350 case MCI_DEVTYPE_OVERLAY:
1351 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1352 dwFlags |= MCI_OVLY_RECT;
1353 sscanf(keywords[i+1],"%hd",&(pU->ovlyloadParams.rc.left));
1354 sscanf(keywords[i+2],"%hd",&(pU->ovlyloadParams.rc.top));
1355 sscanf(keywords[i+3],"%hd",&(pU->ovlyloadParams.rc.right));
1356 sscanf(keywords[i+4],"%hd",&(pU->ovlyloadParams.rc.bottom));
1357 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1358 continue;
1360 break;
1362 len+=strlen(keywords[i])+1;
1363 i++;
1365 s=(char*)xmalloc(len);
1366 *s='\0';
1367 while (i < nrofkeywords) {
1368 strcat(s,keywords[i]);
1369 i++;
1370 if (i < nrofkeywords) strcat(s," ");
1372 pU->loadParams.lpfilename=s;
1373 dwFlags |= MCI_LOAD_FILE;
1374 res = mciSendCommandA(wDevID, MCI_LOAD, dwFlags, (DWORD)pU);
1375 free(s);
1376 free(pU);
1377 return res;
1380 /* save to file
1381 * Argument: "<filename>"
1382 * Overlay: "at <left> <top> <right> <bottom>" additional
1384 static DWORD
1385 MCISTR_Save(_MCISTR_PROTO_) {
1386 union U {
1387 MCI_SAVE_PARMS saveParams;
1388 MCI_OVLY_SAVE_PARMS16 ovlysaveParams;
1390 union U *pU = xmalloc(sizeof(union U));
1391 int i,len,res;
1392 char *s;
1394 i=0;len=0;
1395 while (i < nrofkeywords) {
1396 switch (uDevTyp) {
1397 case MCI_DEVTYPE_OVERLAY:
1398 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1399 dwFlags |= MCI_OVLY_RECT;
1400 sscanf(keywords[i+1],"%hd",&(pU->ovlysaveParams.rc.left));
1401 sscanf(keywords[i+2],"%hd",&(pU->ovlysaveParams.rc.top));
1402 sscanf(keywords[i+3],"%hd",&(pU->ovlysaveParams.rc.right));
1403 sscanf(keywords[i+4],"%hd",&(pU->ovlysaveParams.rc.bottom));
1404 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1405 continue;
1407 break;
1409 len+=strlen(keywords[i])+1;
1410 i++;
1412 s=(char*)xmalloc(len);
1413 *s='\0';
1414 while (i < nrofkeywords) {
1415 strcat(s,keywords[i]);
1416 i++;
1417 if (i < nrofkeywords) strcat(s," ");
1419 pU->saveParams.lpfilename=s;
1420 dwFlags |= MCI_LOAD_FILE;
1421 res = mciSendCommandA(wDevID, MCI_SAVE, dwFlags, (DWORD)pU);
1422 free(s);
1423 free(pU);
1424 return res;
1427 /* prepare device for input/output
1428 * (only applyable to waveform audio)
1430 static DWORD
1431 MCISTR_Cue(_MCISTR_PROTO_) {
1432 MCI_GENERIC_PARMS *cueParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1433 int i,res;
1435 for (i = 0; i < nrofkeywords; i++) {
1436 switch (uDevTyp) {
1437 case MCI_DEVTYPE_WAVEFORM_AUDIO:
1438 FLAG1("input", MCI_WAVE_INPUT);
1439 FLAG1("output", MCI_WAVE_OUTPUT);
1440 break;
1443 res = mciSendCommandA(wDevID, MCI_CUE, dwFlags, (DWORD)cueParams);
1444 free(cueParams);
1445 return res;
1448 /* delete information */
1449 static DWORD
1450 MCISTR_Delete(_MCISTR_PROTO_) {
1451 int timef,nrargs,i,j,k,a[4],res;
1452 char *parsestr;
1453 MCI_WAVE_DELETE_PARMS *deleteParams = xmalloc(sizeof(MCI_WAVE_DELETE_PARMS));
1455 /* only implemented for waveform audio */
1456 if (uDevTyp != MCI_DEVTYPE_WAVEFORM_AUDIO)
1457 return MCIERR_UNSUPPORTED_FUNCTION; /* well it fits */
1458 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1459 if (res) return res;
1460 switch (timef) {
1461 case MCI_FORMAT_MILLISECONDS:
1462 case MCI_FORMAT_FRAMES:
1463 case MCI_FORMAT_BYTES:
1464 case MCI_FORMAT_SAMPLES:
1465 nrargs=1;
1466 parsestr="%d";
1467 break;
1468 case MCI_FORMAT_HMS:
1469 case MCI_FORMAT_MSF:
1470 parsestr="%d:%d:%d";
1471 nrargs=3;
1472 break;
1473 case MCI_FORMAT_TMSF:
1474 parsestr="%d:%d:%d:%d";
1475 nrargs=4;
1476 break;
1477 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1478 parsestr="%d";
1479 nrargs=1;
1480 break;
1482 i=0;
1483 while (i < nrofkeywords) {
1484 if (!strcmp(keywords[i],"to") && (i+1 < nrofkeywords)) {
1485 dwFlags |= MCI_TO;
1486 a[0]=a[1]=a[2]=a[3]=0;
1487 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1488 /* add up all integers we got, if we have more
1489 * shift them. (Well I should use the macros in
1490 * mmsystem.h, right).
1492 deleteParams->dwTo=0;
1493 for (k=0;k < j;k++)
1494 deleteParams->dwTo+=a[k]<<(8*(nrargs-k));
1495 i+=2;
1496 continue;
1498 if (!strcmp(keywords[i],"from") && (i+1 < nrofkeywords)) {
1499 dwFlags |= MCI_FROM;
1500 a[0]=a[1]=a[2]=a[3]=0;
1501 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1502 /* dito. */
1503 deleteParams->dwFrom=0;
1504 for (k=0;k < j;k++)
1505 deleteParams->dwFrom+=a[k]<<(8*(nrargs-k));
1506 i+=2;
1507 continue;
1509 i++;
1511 res = mciSendCommandA(wDevID, MCI_DELETE, dwFlags, (DWORD)deleteParams);
1512 free(deleteParams);
1513 return res;
1516 /* send command to device. only applies to videodisc */
1517 static DWORD
1518 MCISTR_Escape(_MCISTR_PROTO_)
1520 MCI_VD_ESCAPE_PARMS16 *escapeParams = xmalloc(sizeof(MCI_VD_ESCAPE_PARMS16));
1521 int i,len,res;
1522 char *s;
1524 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1525 return MCIERR_UNSUPPORTED_FUNCTION;
1526 i=0;len=0;
1527 while (i < nrofkeywords) {
1528 len+=strlen(keywords[i])+1;
1529 i++;
1531 s=(char*)malloc(len);
1532 *s='\0';
1533 while (i < nrofkeywords) {
1534 strcat(s,keywords[i]);
1535 i++;
1536 if (i < nrofkeywords) strcat(s," ");
1538 escapeParams->lpstrCommand = s;
1539 dwFlags |= MCI_VD_ESCAPE_STRING;
1540 res = mciSendCommandA(wDevID, MCI_ESCAPE, dwFlags, (DWORD)escapeParams);
1541 free(s);
1542 free(escapeParams);
1543 return res;
1546 /* unfreeze [part of] the overlayed video
1547 * only applyable to Overlay devices
1549 static DWORD
1550 MCISTR_Unfreeze(_MCISTR_PROTO_)
1552 MCI_OVLY_RECT_PARMS16 *unfreezeParams = xmalloc(sizeof(MCI_OVLY_RECT_PARMS16));
1553 int i,res;
1555 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1556 return MCIERR_UNSUPPORTED_FUNCTION;
1557 i=0;while (i < nrofkeywords) {
1558 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1559 sscanf(keywords[i+1],"%hd",&(unfreezeParams->rc.left));
1560 sscanf(keywords[i+2],"%hd",&(unfreezeParams->rc.top));
1561 sscanf(keywords[i+3],"%hd",&(unfreezeParams->rc.right));
1562 sscanf(keywords[i+4],"%hd",&(unfreezeParams->rc.bottom));
1563 dwFlags |= MCI_OVLY_RECT;
1564 i+=5;
1565 continue;
1567 i++;
1569 res = mciSendCommandA(wDevID, MCI_UNFREEZE, dwFlags, (DWORD)unfreezeParams);
1570 free(unfreezeParams);
1571 return res;
1573 /* freeze [part of] the overlayed video
1574 * only applyable to Overlay devices
1576 static DWORD
1577 MCISTR_Freeze(_MCISTR_PROTO_)
1579 MCI_OVLY_RECT_PARMS16 *freezeParams = xmalloc(sizeof(MCI_OVLY_RECT_PARMS16));
1580 int i,res;
1582 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1583 return MCIERR_UNSUPPORTED_FUNCTION;
1584 i=0;while (i < nrofkeywords) {
1585 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1586 sscanf(keywords[i+1],"%hd",&(freezeParams->rc.left));
1587 sscanf(keywords[i+2],"%hd",&(freezeParams->rc.top));
1588 sscanf(keywords[i+3],"%hd",&(freezeParams->rc.right));
1589 sscanf(keywords[i+4],"%hd",&(freezeParams->rc.bottom));
1590 dwFlags |= MCI_OVLY_RECT;
1591 i+=5;
1592 continue;
1594 i++;
1596 res = mciSendCommandA(wDevID, MCI_FREEZE, dwFlags, (DWORD)freezeParams);
1597 free(freezeParams);
1598 return res;
1601 /* copy parts of image to somewhere else
1602 * "source [at <left> <top> <right> <bottom>]" source is framebuffer [or rect]
1603 * "destination [at <left> <top> <right> <bottom>]" destination is framebuffer [or rect]
1604 * Overlay:
1605 * "frame [at <left> <top> <right> <bottom>]" frame is framebuffer [or rect]
1606 * where the video input is placed
1607 * "video [at <left> <top> <right> <bottom>]" video is whole video [or rect]
1608 * (defining part of input to
1609 * be displayed)
1611 * FIXME: This whole junk is passing multiple rectangles.
1612 * I don't know how to do that with the present interface.
1613 * (Means code below is broken)
1615 static DWORD
1616 MCISTR_Put(_MCISTR_PROTO_) {
1617 union U {
1618 MCI_OVLY_RECT_PARMS16 ovlyputParams;
1619 MCI_ANIM_RECT_PARMS16 animputParams;
1621 union U *pU = xmalloc(sizeof(union U));
1622 int i,res;
1623 i=0;while (i < nrofkeywords) {
1624 switch (uDevTyp) {
1625 case MCI_DEVTYPE_ANIMATION:
1626 FLAG1("source",MCI_ANIM_PUT_SOURCE);
1627 FLAG1("destination",MCI_ANIM_PUT_DESTINATION);
1628 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1629 sscanf(keywords[i+1],"%hd",&(pU->animputParams.rc.left));
1630 sscanf(keywords[i+2],"%hd",&(pU->animputParams.rc.top));
1631 sscanf(keywords[i+3],"%hd",&(pU->animputParams.rc.right));
1632 sscanf(keywords[i+4],"%hd",&(pU->animputParams.rc.bottom));
1633 dwFlags |= MCI_ANIM_RECT;
1634 i+=5;
1635 continue;
1637 break;
1638 case MCI_DEVTYPE_OVERLAY:
1639 FLAG1("source",MCI_OVLY_PUT_SOURCE);
1640 FLAG1("destination",MCI_OVLY_PUT_DESTINATION);
1641 FLAG1("video",MCI_OVLY_PUT_VIDEO);
1642 FLAG1("frame",MCI_OVLY_PUT_FRAME);
1643 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1644 sscanf(keywords[i+1],"%hd",&(pU->ovlyputParams.rc.left));
1645 sscanf(keywords[i+2],"%hd",&(pU->ovlyputParams.rc.top));
1646 sscanf(keywords[i+3],"%hd",&(pU->ovlyputParams.rc.right));
1647 sscanf(keywords[i+4],"%hd",&(pU->ovlyputParams.rc.bottom));
1648 dwFlags |= MCI_OVLY_RECT;
1649 i+=5;
1650 continue;
1652 break;
1654 i++;
1656 res = mciSendCommandA(wDevID, MCI_PUT, dwFlags, (DWORD)pU);
1657 free(pU);
1658 return res;
1661 /* palette behaviour changing
1662 * (Animation only)
1663 * "normal" realize the palette normally
1664 * "background" realize the palette as background palette
1666 static DWORD
1667 MCISTR_Realize(_MCISTR_PROTO_)
1669 MCI_GENERIC_PARMS *realizeParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1670 int i,res;
1672 if (uDevTyp != MCI_DEVTYPE_ANIMATION)
1673 return MCIERR_UNSUPPORTED_FUNCTION;
1674 i=0;
1675 while (i < nrofkeywords) {
1676 FLAG1("background",MCI_ANIM_REALIZE_BKGD);
1677 FLAG1("normal",MCI_ANIM_REALIZE_NORM);
1678 i++;
1680 res = mciSendCommandA(wDevID, MCI_REALIZE, dwFlags, (DWORD)realizeParams);
1681 free(realizeParams);
1682 return res;
1685 /* videodisc spinning
1686 * "up"
1687 * "down"
1689 static DWORD
1690 MCISTR_Spin(_MCISTR_PROTO_)
1692 MCI_GENERIC_PARMS *spinParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1693 int i,res;
1695 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1696 return MCIERR_UNSUPPORTED_FUNCTION;
1697 i=0;
1698 while (i < nrofkeywords) {
1699 FLAG1("up",MCI_VD_SPIN_UP);
1700 FLAG1("down",MCI_VD_SPIN_UP);
1701 i++;
1703 res = mciSendCommandA(wDevID, MCI_SPIN, dwFlags, (DWORD)spinParams);
1704 free(spinParams);
1705 return res;
1708 /* step single frames
1709 * "reverse" optional flag
1710 * "by <nr>" for <nr> frames
1712 static DWORD
1713 MCISTR_Step(_MCISTR_PROTO_) {
1714 union U {
1715 MCI_ANIM_STEP_PARMS animstepParams;
1716 MCI_VD_STEP_PARMS vdstepParams;
1718 union U *pU = xmalloc(sizeof(union U));
1719 int i,res;
1721 i=0;
1722 while (i < nrofkeywords) {
1723 switch (uDevTyp) {
1724 case MCI_DEVTYPE_ANIMATION:
1725 FLAG1("reverse",MCI_ANIM_STEP_REVERSE);
1726 if (!STRCMP(keywords[i],"by") && (i+1 < nrofkeywords)) {
1727 sscanf(keywords[i+1],"%ld",&(pU->animstepParams.dwFrames));
1728 dwFlags |= MCI_ANIM_STEP_FRAMES;
1729 i+=2;
1730 continue;
1732 break;
1733 case MCI_DEVTYPE_VIDEODISC:
1734 FLAG1("reverse",MCI_VD_STEP_REVERSE);
1735 if (!STRCMP(keywords[i],"by") && (i+1 < nrofkeywords)) {
1736 sscanf(keywords[i+1],"%ld",&(pU->vdstepParams.dwFrames));
1737 dwFlags |= MCI_VD_STEP_FRAMES;
1738 i+=2;
1739 continue;
1741 break;
1743 i++;
1745 res = mciSendCommandA(wDevID, MCI_STEP, dwFlags, (DWORD)pU);
1746 free(pU);
1747 return res;
1750 /* update animation window
1751 * Arguments:
1752 * "at <left> <top> <right> <bottom>" only in this rectangle
1753 * "hdc" device context
1755 static DWORD
1756 MCISTR_Update(_MCISTR_PROTO_) {
1757 int i,res;
1758 MCI_ANIM_UPDATE_PARMS16 *updateParams = xmalloc(sizeof(MCI_ANIM_UPDATE_PARMS16));
1760 i=0;
1761 while (i<nrofkeywords) {
1762 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1763 sscanf(keywords[i+1],"%hd",&(updateParams->rc.left));
1764 sscanf(keywords[i+2],"%hd",&(updateParams->rc.top));
1765 sscanf(keywords[i+3],"%hd",&(updateParams->rc.right));
1766 sscanf(keywords[i+4],"%hd",&(updateParams->rc.bottom));
1767 dwFlags |= MCI_ANIM_RECT;
1768 i+=5;
1769 continue;
1771 if (!STRCMP(keywords[i],"hdc") && (i+1 < nrofkeywords)) {
1772 dwFlags |= MCI_ANIM_UPDATE_HDC;
1773 sscanf(keywords[i+1],"%hd",&(updateParams->hDC));
1774 i+=2;
1775 continue;
1777 i++;
1779 res = mciSendCommandA(wDevID, MCI_UPDATE, dwFlags, (DWORD)updateParams);
1780 free(updateParams);
1781 return res;
1784 /* where command for animation and overlay drivers.
1785 * just returns the specified rectangle as a string
1786 * Arguments:
1787 * "source"
1788 * "destination"
1789 * Overlay special:
1790 * "video"
1791 * "frame"
1793 static DWORD
1794 MCISTR_Where(_MCISTR_PROTO_) {
1795 union U {
1796 MCI_ANIM_RECT_PARMS16 animwhereParams;
1797 MCI_OVLY_RECT_PARMS16 ovlywhereParams;
1799 union U *pU = xmalloc(sizeof(union U));
1800 int i,res;
1802 i=0;
1803 while (i < nrofkeywords) {
1804 switch (uDevTyp) {
1805 case MCI_DEVTYPE_ANIMATION:
1806 FLAG1("source",MCI_ANIM_WHERE_SOURCE);
1807 FLAG1("destination",MCI_ANIM_WHERE_DESTINATION);
1808 break;
1809 case MCI_DEVTYPE_OVERLAY:
1810 FLAG1("source",MCI_OVLY_WHERE_SOURCE);
1811 FLAG1("destination",MCI_OVLY_WHERE_DESTINATION);
1812 FLAG1("video",MCI_OVLY_WHERE_VIDEO);
1813 FLAG1("frame",MCI_OVLY_WHERE_FRAME);
1814 break;
1816 i++;
1818 res = mciSendCommandA(wDevID, MCI_WHERE, dwFlags, (DWORD)pU);
1819 if (res==0) {
1820 char buf[100];
1821 switch (uDevTyp) {
1822 case MCI_DEVTYPE_ANIMATION:
1823 sprintf(buf,"%d %d %d %d",
1824 pU->animwhereParams.rc.left,
1825 pU->animwhereParams.rc.top,
1826 pU->animwhereParams.rc.right,
1827 pU->animwhereParams.rc.bottom
1829 break;
1830 case MCI_DEVTYPE_OVERLAY:
1831 sprintf(buf,"%d %d %d %d",
1832 pU->ovlywhereParams.rc.left,
1833 pU->ovlywhereParams.rc.top,
1834 pU->ovlywhereParams.rc.right,
1835 pU->ovlywhereParams.rc.bottom
1837 break;
1838 default:strcpy(buf,"0 0 0 0");break;
1840 _MCI_STR(buf);
1842 free(pU);
1843 return res;
1846 static DWORD
1847 MCISTR_Window(_MCISTR_PROTO_) {
1848 int i,res;
1849 char *s;
1850 union U {
1851 MCI_ANIM_WINDOW_PARMS16 animwindowParams;
1852 MCI_OVLY_WINDOW_PARMS16 ovlywindowParams;
1854 union U *pU = xmalloc(sizeof(union U));
1856 s=NULL;
1857 i=0;
1858 while (i < nrofkeywords) {
1859 switch (uDevTyp) {
1860 case MCI_DEVTYPE_ANIMATION:
1861 if (!STRCMP(keywords[i],"handle") && (i+1 < nrofkeywords)) {
1862 dwFlags |= MCI_ANIM_WINDOW_HWND;
1863 if (!STRCMP(keywords[i+1],"default"))
1864 pU->animwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1865 else
1866 sscanf(keywords[i+1],"%hd",&(pU->animwindowParams.hWnd));
1867 i+=2;
1868 continue;
1870 if (!STRCMP(keywords[i],"state") && (i+1 < nrofkeywords)) {
1871 dwFlags |= MCI_ANIM_WINDOW_STATE;
1872 if (!STRCMP(keywords[i+1],"hide"))
1873 pU->animwindowParams.nCmdShow = SW_HIDE;
1874 if (!STRCMP(keywords[i+1],"iconic"))
1875 pU->animwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1876 if (!STRCMP(keywords[i+1],"minimized"))
1877 pU->animwindowParams.nCmdShow = SW_SHOWMINIMIZED;
1878 if (!STRCMP(keywords[i+1],"maximized"))
1879 pU->animwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1880 if (!STRCMP(keywords[i+1],"minimize"))
1881 pU->animwindowParams.nCmdShow = SW_MINIMIZE;
1882 if (!STRCMP(keywords[i+1],"normal"))
1883 pU->animwindowParams.nCmdShow = SW_NORMAL;
1884 if (!STRCMP(keywords[i+1],"show"))
1885 pU->animwindowParams.nCmdShow = SW_SHOW;
1886 if (!STRCMP(keywords[i+1],"no") && (i+2 < nrofkeywords)) {
1887 if (!STRCMP(keywords[i+2],"active"))
1888 pU->animwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1889 if (!STRCMP(keywords[i+2],"action"))
1890 pU->animwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1891 i++;
1893 i+=2;
1894 continue;
1896 /* text is enclosed in " ... " as it seems */
1897 if (!STRCMP(keywords[i],"text")) {
1898 char *t;
1899 int len,j,k;
1901 if (keywords[i+1][0]!='"') {
1902 i++;
1903 continue;
1905 dwFlags |= MCI_ANIM_WINDOW_TEXT;
1906 len = strlen(keywords[i+1])+1;
1907 j = i+2;
1908 while (j < nrofkeywords) {
1909 len += strlen(keywords[j])+1;
1910 if (strchr(keywords[j],'"'))
1911 break;
1912 j++;
1914 s=(char*)xmalloc(len);
1915 strcpy(s,keywords[i+1]+1);
1916 k=j;j=i+2;
1917 while (j <= k) {
1918 strcat(s," ");
1919 strcat(s,keywords[j]);
1921 if ((t=strchr(s,'"'))) *t='\0';
1922 /* FIXME: segmented pointer? */
1923 pU->animwindowParams.lpstrText = s;
1924 i=k+1;
1925 continue;
1927 FLAG1("stretch",MCI_ANIM_WINDOW_ENABLE_STRETCH);
1928 break;
1929 case MCI_DEVTYPE_OVERLAY:
1930 if (!STRCMP(keywords[i],"handle") && (i+1 < nrofkeywords)) {
1931 dwFlags |= MCI_OVLY_WINDOW_HWND;
1932 if (!STRCMP(keywords[i+1],"default"))
1933 pU->ovlywindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1934 else
1935 sscanf(keywords[i+1],"%hd",&(pU->ovlywindowParams.hWnd));
1936 i+=2;
1937 continue;
1939 if (!STRCMP(keywords[i],"state") && (i+1 < nrofkeywords)) {
1940 dwFlags |= MCI_OVLY_WINDOW_STATE;
1941 if (!STRCMP(keywords[i+1],"hide"))
1942 pU->ovlywindowParams.nCmdShow = SW_HIDE;
1943 if (!STRCMP(keywords[i+1],"iconic"))
1944 pU->ovlywindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1945 if (!STRCMP(keywords[i+1],"minimized"))
1946 pU->ovlywindowParams.nCmdShow = SW_SHOWMINIMIZED;
1947 if (!STRCMP(keywords[i+1],"maximized"))
1948 pU->ovlywindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1949 if (!STRCMP(keywords[i+1],"minimize"))
1950 pU->ovlywindowParams.nCmdShow = SW_MINIMIZE;
1951 if (!STRCMP(keywords[i+1],"normal"))
1952 pU->ovlywindowParams.nCmdShow = SW_NORMAL;
1953 if (!STRCMP(keywords[i+1],"show"))
1954 pU->ovlywindowParams.nCmdShow = SW_SHOW;
1955 if (!STRCMP(keywords[i+1],"no") && (i+2 < nrofkeywords)) {
1956 if (!STRCMP(keywords[i+2],"active"))
1957 pU->ovlywindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1958 if (!STRCMP(keywords[i+2],"action"))
1959 pU->ovlywindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1960 i++;
1962 i+=2;
1963 continue;
1965 /* text is enclosed in " ... " as it seems */
1966 if (!STRCMP(keywords[i],"text")) {
1967 char *t;
1968 int len,j,k;
1970 if (keywords[i+1][0]!='"') {
1971 i++;
1972 continue;
1974 dwFlags |= MCI_OVLY_WINDOW_TEXT;
1975 len = strlen(keywords[i+1])+1;
1976 j = i+2;
1977 while (j < nrofkeywords) {
1978 len += strlen(keywords[j])+1;
1979 if (strchr(keywords[j],'"'))
1980 break;
1981 j++;
1983 s=(char*)xmalloc(len);
1984 strcpy(s,keywords[i+1]+1);
1985 k=j;j=i+2;
1986 while (j<=k) {
1987 strcat(s," ");
1988 strcat(s,keywords[j]);
1990 if ((t=strchr(s,'"'))) *t='\0';
1991 /* FIXME: segmented pointer? */
1992 pU->ovlywindowParams.lpstrText = s;
1993 i=k+1;
1994 continue;
1996 FLAG1("stretch",MCI_OVLY_WINDOW_ENABLE_STRETCH);
1997 break;
1999 i++;
2001 res = mciSendCommandA(wDevID, MCI_WINDOW, dwFlags, (DWORD)pU);
2002 if (s) free(s);
2003 free(pU);
2004 return res;
2007 struct _MCISTR_cmdtable {
2008 char *cmd;
2009 DWORD (*fun)(_MCISTR_PROTO_);
2010 } MCISTR_cmdtable[]={
2011 {"break", MCISTR_Break},
2012 {"capability", MCISTR_Capability},
2013 {"close", MCISTR_Close},
2014 {"cue", MCISTR_Cue},
2015 {"delete", MCISTR_Delete},
2016 {"escape", MCISTR_Escape},
2017 {"freeze", MCISTR_Freeze},
2018 {"info", MCISTR_Info},
2019 {"load", MCISTR_Load},
2020 {"open", MCISTR_Open},
2021 {"pause", MCISTR_Pause},
2022 {"play", MCISTR_Play},
2023 {"put", MCISTR_Put},
2024 {"realize", MCISTR_Realize},
2025 {"record", MCISTR_Record},
2026 {"resume", MCISTR_Resume},
2027 {"save", MCISTR_Save},
2028 {"seek", MCISTR_Seek},
2029 {"set", MCISTR_Set},
2030 {"spin", MCISTR_Spin},
2031 {"status", MCISTR_Status},
2032 {"step", MCISTR_Step},
2033 {"stop", MCISTR_Stop},
2034 {"sysinfo", MCISTR_Sysinfo},
2035 {"unfreeze", MCISTR_Unfreeze},
2036 {"update", MCISTR_Update},
2037 {"where", MCISTR_Where},
2038 {"window", MCISTR_Window},
2039 {NULL, NULL}
2042 /**************************************************************************
2043 * mciSendString16 [MMSYSTEM.702]
2045 /* The usercode sends a string with a command (and flags) expressed in
2046 * words in it... We do our best to call aprobiate drivers,
2047 * and return a errorcode AND a readable string (if lpstrRS!=NULL)
2048 * Info gathered by watching cool134.exe and from Borland's mcistrwh.hlp
2050 /* FIXME: "all" is a valid devicetype and we should access all devices if
2051 * it is used. (imagine "close all"). Not implemented yet.
2053 DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2054 UINT16 uReturnLength, HWND16 hwndCallback)
2056 char *cmd,*dev,*args,**keywords,*filename;
2057 WORD uDevTyp=0,wDevID=0;
2058 DWORD dwFlags;
2059 int res=0,i,nrofkeywords;
2061 TRACE(mci,"('%s', %p, %d, %X)\n",
2062 lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2064 /* format is <command> <device> <optargs> */
2065 cmd=strdup(lpstrCommand);
2066 dev=strchr(cmd,' ');
2067 if (dev==NULL) {
2068 free(cmd);
2069 return MCIERR_MISSING_DEVICE_NAME;
2071 *dev++='\0';
2072 args=strchr(dev,' ');
2073 if (args!=NULL) *args++='\0';
2074 CharUpperA(dev);
2075 if (args!=NULL) {
2076 char *s;
2077 i=1;/* nrofkeywords = nrofspaces+1 */
2078 s=args;
2079 while ((s=strchr(s,' '))!=NULL) i++,s++;
2080 keywords=(char**)xmalloc(sizeof(char*)*(i+2));
2081 nrofkeywords=i;
2082 s=args;i=0;
2083 while (s && i < nrofkeywords) {
2084 keywords[i++]=s;
2085 s=strchr(s,' ');
2086 if (s) *s++='\0';
2088 keywords[i]=NULL;
2089 } else {
2090 nrofkeywords=0;
2091 keywords=(char**)xmalloc(sizeof(char*));
2093 dwFlags = 0; /* default flags */
2094 for (i=0;i < nrofkeywords;) {
2095 /* take care, there is also a "device type" capability */
2096 if ((!STRCMP(keywords[i],"type")) && (i < nrofkeywords-1)) {
2097 filename = dev;
2098 dev = keywords[i+1];
2099 memcpy(keywords+i,keywords+(i+2),(nrofkeywords-i-2)*sizeof(char *));
2100 nrofkeywords -= 2;
2101 continue;
2103 if (!STRCMP(keywords[i],"wait")) {
2104 dwFlags |= MCI_WAIT;
2105 memcpy(keywords+i,keywords+(i+1),(nrofkeywords-i-1)*sizeof(char *));
2106 nrofkeywords--;
2107 continue;
2109 if (!STRCMP(keywords[i],"notify")) {
2110 dwFlags |= MCI_NOTIFY;
2111 memcpy(keywords+i,keywords+(i+1),(nrofkeywords-i-1)*sizeof(char *));
2112 nrofkeywords--;
2113 continue;
2115 i++;
2118 /* FIXME: this code should be moved to mmsystem.c */
2119 /* determine wDevID and uDevTyp for all commands except "open" */
2120 if (STRCMP(cmd,"open")!=0) {
2121 wDevID = MCI_FirstDevID();
2122 while (1) {
2123 LPSTR dname;
2125 dname=MCI_GetOpenDrv(wDevID)->lpstrAlias;
2126 if (dname==NULL)
2127 dname=MCI_GetOpenDrv(wDevID)->lpstrDeviceType;
2128 if (dname != NULL && !STRCMP(dname,dev))
2129 break;
2130 wDevID = MCI_NextDevID(wDevID);
2131 if (!MCI_DevIDValid(wDevID)) {
2132 TRACE(mci, "MAXMCIDRIVERS reached!\n");
2133 free(keywords);free(cmd);
2134 return MCIERR_INVALID_DEVICE_NAME;
2137 uDevTyp=MCI_GetDrv(wDevID)->modp.wType;
2139 /* end of FIXME */
2141 for (i=0;MCISTR_cmdtable[i].cmd!=NULL;i++) {
2142 if (!STRCMP(MCISTR_cmdtable[i].cmd,cmd)) {
2143 res=MCISTR_cmdtable[i].fun(
2144 wDevID,uDevTyp,lpstrReturnString,
2145 uReturnLength,dev,(LPSTR*)keywords,nrofkeywords,
2146 dwFlags,hwndCallback
2148 break;
2151 if (MCISTR_cmdtable[i].cmd!=NULL) {
2152 free(keywords);free(cmd);
2153 return res;
2155 FIXME(mci,"('%s', %p, %u, %X): unimplemented, please report.\n",
2156 lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2157 free(keywords);free(cmd);
2158 return MCIERR_MISSING_COMMAND_STRING;
2161 /**************************************************************************
2162 * mciSendString32A [MMSYSTEM.702][WINMM.51]
2164 DWORD WINAPI mciSendStringA(LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2165 UINT uReturnLength, HWND hwndCallback)
2167 return mciSendString16(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2170 /**************************************************************************
2171 * mciSendString32W [WINMM.52]
2173 DWORD WINAPI mciSendStringW(LPCWSTR lpwstrCommand, LPSTR lpstrReturnString,
2174 UINT uReturnLength, HWND hwndCallback)
2176 LPSTR lpstrCommand;
2177 UINT ret;
2179 /* FIXME: is there something to do with lpstrReturnString ? */
2180 lpstrCommand = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrCommand);
2181 ret = mciSendString16(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2182 HeapFree(GetProcessHeap(), 0, lpstrCommand);
2183 return ret;