Optimized include/*.h: (recursively) include all headers needed by
[wine/testsucceed.git] / multimedia / mcistring.c
blob8b82b6840346a413ddd3e53a6a147947e755ef07
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 "windows.h"
22 #include "heap.h"
23 #include "ldt.h"
24 #include "user.h"
25 #include "driver.h"
26 #include "mmsystem.h"
27 #include "multimedia.h"
28 #include "callback.h"
29 #include "debug.h"
30 #include "xmalloc.h"
32 /* FIXME the following definitions must be moved to mmsystem.c */
33 extern struct WINE_MCIDRIVER mciDrv[MAXMCIDRIVERS];
35 #define MCI_GetDrv(wDevID) (&mciDrv[MCI_DevIDToIndex(wDevID)])
36 #define MCI_GetOpenDrv(wDevID) (&(MCI_GetDrv(wDevID)->mop))
37 /* end of FIXME */
39 /* The reason why I just don't lowercase the keywords array in
40 * mciSendString is left as an exercise to the reader.
42 #define STRCMP(x,y) lstrcmpi32A(x,y)
44 /* standard function parameters for all functions */
45 #define _MCISTR_PROTO_ \
46 WORD wDevID, WORD uDevTyp, LPSTR lpstrReturnString, \
47 UINT16 uReturnLength, LPCSTR dev, LPSTR *keywords, \
48 UINT16 nrofkeywords, DWORD dwFlags, HWND16 hwndCallback
50 /* copy string to return pointer including necessary checks
51 * for use in mciSendString()
53 #define _MCI_STR(s) \
54 do { \
55 TRACE(mci, "->returns '%s'\n", s); \
56 if (lpstrReturnString) { \
57 lstrcpyn32A(lpstrReturnString, s, uReturnLength); \
58 TRACE(mci, "-->'%s'\n", lpstrReturnString); \
59 } \
60 } while(0)
62 /* print a DWORD in the specified timeformat */
63 static void
64 _MCISTR_printtf(char *buf,UINT16 uDevType,DWORD timef,DWORD val)
66 *buf = '\0';
67 switch (timef) {
68 case MCI_FORMAT_MILLISECONDS:
69 case MCI_FORMAT_FRAMES:
70 case MCI_FORMAT_BYTES:
71 case MCI_FORMAT_SAMPLES:
72 case MCI_VD_FORMAT_TRACK:
73 /*case MCI_SEQ_FORMAT_SONGPTR: sameas MCI_VD_FORMAT_TRACK */
74 sprintf(buf, "%ld",val);
75 break;
76 case MCI_FORMAT_HMS:
77 /* well, the macros have the same content*/
78 /*FALLTRHOUGH*/
79 case MCI_FORMAT_MSF:
80 sprintf(buf, "%d:%d:%d",
81 MCI_HMS_HOUR(val),
82 MCI_HMS_MINUTE(val),
83 MCI_HMS_SECOND(val));
84 break;
85 case MCI_FORMAT_TMSF:
86 sprintf(buf, "%d:%d:%d:%d",
87 MCI_TMSF_TRACK(val),
88 MCI_TMSF_MINUTE(val),
89 MCI_TMSF_SECOND(val),
90 MCI_TMSF_FRAME(val) );
91 break;
92 default:
93 FIXME(mci, "missing timeformat for %ld, report.\n",timef);
94 strcpy(buf,"0"); /* hmm */
95 break;
97 return;
99 /* possible different return types */
100 #define _MCISTR_int 1
101 #define _MCISTR_time 2
102 #define _MCISTR_bool 3
103 #define _MCISTR_tfname 4
104 #define _MCISTR_mode 5
105 #define _MCISTR_divtype 6
106 #define _MCISTR_seqtype 7
107 #define _MCISTR_vdmtype 8
108 #define _MCISTR_devtype 9
110 static void
111 _MCISTR_convreturn(int type,DWORD dwReturn,LPSTR lpstrReturnString,
112 WORD uReturnLength,WORD uDevTyp,int timef)
114 switch (type) {
115 case _MCISTR_vdmtype:
116 switch (dwReturn) {
117 case MCI_VD_MEDIA_CLV: _MCI_STR("CLV"); break;
118 case MCI_VD_MEDIA_CAV: _MCI_STR("CAV"); break;
119 default:
120 case MCI_VD_MEDIA_OTHER:_MCI_STR("other"); break;
122 break;
123 case _MCISTR_seqtype:
124 switch (dwReturn) {
125 case MCI_SEQ_NONE: _MCI_STR("none"); break;
126 case MCI_SEQ_SMPTE: _MCI_STR("smpte"); break;
127 case MCI_SEQ_FILE: _MCI_STR("file"); break;
128 case MCI_SEQ_MIDI: _MCI_STR("midi"); break;
129 default:FIXME(mci,"missing sequencer mode %ld\n",dwReturn);
131 break;
132 case _MCISTR_mode:
133 switch (dwReturn) {
134 case MCI_MODE_NOT_READY:_MCI_STR("not ready"); break;
135 case MCI_MODE_STOP: _MCI_STR("stopped"); break;
136 case MCI_MODE_PLAY: _MCI_STR("playing"); break;
137 case MCI_MODE_RECORD: _MCI_STR("recording"); break;
138 case MCI_MODE_SEEK: _MCI_STR("seeking"); break;
139 case MCI_MODE_PAUSE: _MCI_STR("paused"); break;
140 case MCI_MODE_OPEN: _MCI_STR("open"); break;
141 default:break;
143 break;
144 case _MCISTR_bool:
145 if (dwReturn)
146 _MCI_STR("true");
147 else
148 _MCI_STR("false");
149 break;
150 case _MCISTR_int:{
151 char buf[16];
152 sprintf(buf,"%ld",dwReturn);
153 _MCI_STR(buf);
154 break;
156 case _MCISTR_time: {
157 char buf[100];
158 _MCISTR_printtf(buf,uDevTyp,timef,dwReturn);
159 _MCI_STR(buf);
160 break;
162 case _MCISTR_tfname:
163 switch (timef) {
164 case MCI_FORMAT_MILLISECONDS: _MCI_STR("milliseconds"); break;
165 case MCI_FORMAT_FRAMES: _MCI_STR("frames"); break;
166 case MCI_FORMAT_BYTES: _MCI_STR("bytes"); break;
167 case MCI_FORMAT_SAMPLES: _MCI_STR("samples"); break;
168 case MCI_FORMAT_HMS: _MCI_STR("hms"); break;
169 case MCI_FORMAT_MSF: _MCI_STR("msf"); break;
170 case MCI_FORMAT_TMSF: _MCI_STR("tmsf"); break;
171 default:
172 FIXME(mci,"missing timefmt for %d, report.\n",timef);
173 break;
175 break;
176 case _MCISTR_divtype:
177 switch (dwReturn) {
178 case MCI_SEQ_DIV_PPQN: _MCI_STR("PPQN"); break;
179 case MCI_SEQ_DIV_SMPTE_24: _MCI_STR("SMPTE 24 frame"); break;
180 case MCI_SEQ_DIV_SMPTE_25: _MCI_STR("SMPTE 25 frame"); break;
181 case MCI_SEQ_DIV_SMPTE_30: _MCI_STR("SMPTE 30 frame"); break;
182 case MCI_SEQ_DIV_SMPTE_30DROP: _MCI_STR("SMPTE 30 frame drop");break;
184 case _MCISTR_devtype:
185 switch (dwReturn) {
186 case MCI_DEVTYPE_VCR: _MCI_STR("vcr"); break;
187 case MCI_DEVTYPE_VIDEODISC: _MCI_STR("videodisc"); break;
188 case MCI_DEVTYPE_CD_AUDIO: _MCI_STR("cd audio"); break;
189 case MCI_DEVTYPE_OVERLAY: _MCI_STR("overlay"); break;
190 case MCI_DEVTYPE_DAT: _MCI_STR("dat"); break;
191 case MCI_DEVTYPE_SCANNER: _MCI_STR("scanner"); break;
192 case MCI_DEVTYPE_ANIMATION: _MCI_STR("animation"); break;
193 case MCI_DEVTYPE_DIGITAL_VIDEO: _MCI_STR("digital video"); break;
194 case MCI_DEVTYPE_OTHER: _MCI_STR("other"); break;
195 case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio"); break;
196 case MCI_DEVTYPE_SEQUENCER: _MCI_STR("sequencer"); break;
197 default:FIXME(mci,"unknown device type %ld, report.\n",
198 dwReturn);break;
200 break;
201 default:
202 FIXME(mci,"unknown resulttype %d, report.\n",type);
203 break;
207 #define FLAG1(str,flag) \
208 if (!STRCMP(keywords[i],str)) { \
209 dwFlags |= flag; \
210 i++; \
211 continue; \
214 #define FLAG2(str1,str2,flag) \
215 if (!STRCMP(keywords[i],str1) && \
216 (i+1<nrofkeywords) && \
217 !STRCMP(keywords[i+1],str2)) { \
218 dwFlags |= flag; \
219 i+=2; \
220 continue; \
223 /* All known subcommands are implemented in single functions to avoid
224 * bloat and a xxxx lines long mciSendString(). All commands are of the
225 * format MCISTR_Cmd(_MCISTR_PROTO_) where _MCISTR_PROTO_ is the above
226 * defined line of arguments. (This is just for easy enhanceability.)
227 * All functions return the MCIERR_ errorvalue as DWORD. Returnvalues
228 * for the calls are in lpstrReturnString (If I mention return values
229 * in function headers, I mean returnvalues in lpstrReturnString.)
230 * Integers are sprintf("%d")ed integers. Boolean values are
231 * "true" and "false".
232 * timeformat depending values are "%d" "%d:%d" "%d:%d:%d" "%d:%d:%d:%d"
233 * FIXME: is above line correct?
235 * Preceding every function is a list of implemented/known arguments.
236 * Feel free to add missing arguments.
241 * Opens the specified MCI driver.
242 * Arguments: <name>
243 * Optional:
244 * "shareable"
245 * "alias <aliasname>"
246 * "element <elementname>"
247 * Additional:
248 * waveform audio:
249 * "buffer <nrBytesPerSec>"
250 * Animation:
251 * "nostatic" increaste nr of nonstatic colours
252 * "parent <windowhandle>"
253 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
254 * "style child" WS_CHILD
255 * "style overlap" WS_OVERLAPPED
256 * "style popup" WS_POPUP
257 * Overlay:
258 * "parent <windowhandle>"
259 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
260 * "style child" WS_CHILD
261 * "style overlap" WS_OVERLAPPED
262 * "style popup" WS_POPUP
263 * Returns nothing.
265 static DWORD
266 MCISTR_Open(_MCISTR_PROTO_)
268 int res,i;
269 char *s;
270 union U {
271 MCI_OPEN_PARMS16 openParams;
272 MCI_WAVE_OPEN_PARMS16 waveopenParams;
273 MCI_ANIM_OPEN_PARMS16 animopenParams;
274 MCI_OVLY_OPEN_PARMS16 ovlyopenParams;
276 union U *pU = xmalloc(sizeof(union U));
278 pU->openParams.lpstrElementName = NULL;
279 s = strchr(dev,'!');
280 if (s != NULL) {
281 *s++ = '\0';
282 pU->openParams.lpstrElementName = strdup(s);
283 dwFlags |= MCI_OPEN_ELEMENT;
285 uDevTyp = MCI_GetDevType(dev);
286 if (uDevTyp == 0) {
287 free(pU->openParams.lpstrElementName);
288 free(pU);
289 return MCIERR_INVALID_DEVICE_NAME;
292 pU->openParams.dwCallback = hwndCallback;
293 pU->openParams.wDeviceID = wDevID;
294 pU->openParams.wReserved0 = 0;
295 pU->ovlyopenParams.dwStyle = 0;
296 pU->animopenParams.dwStyle = 0;
297 pU->openParams.lpstrDeviceType = strdup(dev);
298 pU->openParams.lpstrAlias = NULL;
299 dwFlags |= MCI_OPEN_TYPE;
300 i = 0;
301 while (i < nrofkeywords) {
302 FLAG1("shareable",MCI_OPEN_SHAREABLE);
303 if (!STRCMP(keywords[i],"alias") && (i+1 < nrofkeywords)) {
304 dwFlags |= MCI_OPEN_ALIAS;
305 pU->openParams.lpstrAlias = strdup(keywords[i+1]);
306 i+=2;
307 continue;
309 if (!STRCMP(keywords[i],"element") && (i+1<nrofkeywords)) {
310 dwFlags |= MCI_OPEN_ELEMENT;
311 pU->openParams.lpstrElementName = strdup(keywords[i+1]);
312 i+=2;
313 continue;
315 switch (uDevTyp) {
316 case MCI_DEVTYPE_ANIMATION:
317 case MCI_DEVTYPE_DIGITAL_VIDEO:
318 FLAG1("nostatic",MCI_ANIM_OPEN_NOSTATIC);
319 if (!STRCMP(keywords[i],"parent") && (i+1 < nrofkeywords)) {
320 dwFlags |= MCI_ANIM_OPEN_PARENT;
321 sscanf(keywords[i+1], "%hu", &(pU->animopenParams.hWndParent));
322 i+=2;
323 continue;
325 if (!STRCMP(keywords[i], "style") && (i+1 < nrofkeywords)) {
326 DWORD st;
328 dwFlags |= MCI_ANIM_OPEN_WS;
329 if (!STRCMP(keywords[i+1],"popup")) {
330 pU->animopenParams.dwStyle |= WS_POPUP;
331 } else if (!STRCMP(keywords[i+1],"overlap")) {
332 pU->animopenParams.dwStyle |= WS_OVERLAPPED;
333 } else if (!STRCMP(keywords[i+1],"child")) {
334 pU->animopenParams.dwStyle |= WS_CHILD;
335 } else if (sscanf(keywords[i+1],"%ld",&st)) {
336 pU->animopenParams.dwStyle |= st;
337 } else
338 FIXME(mci, "unknown 'style' keyword %s, please report.\n", keywords[i+1]);
339 i+=2;
340 continue;
342 break;
343 case MCI_DEVTYPE_WAVEFORM_AUDIO:
344 if (!STRCMP(keywords[i],"buffer") && (i+1 < nrofkeywords)) {
345 dwFlags |= MCI_WAVE_OPEN_BUFFER;
346 sscanf(keywords[i+1], "%ld", &(pU->waveopenParams.dwBufferSeconds));
348 break;
349 case MCI_DEVTYPE_OVERLAY:
350 /* looks just like anim, but without NOSTATIC */
351 if (!STRCMP(keywords[i], "parent") && (i+1 < nrofkeywords)) {
352 dwFlags |= MCI_OVLY_OPEN_PARENT;
353 sscanf(keywords[i+1], "%hd", &(pU->ovlyopenParams.hWndParent));
354 i+=2;
355 continue;
357 if (!STRCMP(keywords[i],"style") && (i+1 < nrofkeywords)) {
358 DWORD st;
360 dwFlags |= MCI_OVLY_OPEN_WS;
361 if (!STRCMP(keywords[i+1],"popup")) {
362 pU->ovlyopenParams.dwStyle |= WS_POPUP;
363 } else if (!STRCMP(keywords[i+1],"overlap")) {
364 pU->ovlyopenParams.dwStyle |= WS_OVERLAPPED;
365 } else if (!STRCMP(keywords[i+1],"child")) {
366 pU->ovlyopenParams.dwStyle |= WS_CHILD;
367 } else if (sscanf(keywords[i+1],"%ld",&st)) {
368 pU->ovlyopenParams.dwStyle |= st;
369 } else
370 FIXME(mci,"unknown 'style' keyword %s, please report.\n",keywords[i+1]);
371 i+=2;
372 continue;
374 break;
376 FIXME(mci,"unknown parameter passed %s, please report.\n",
377 keywords[i]);
378 i++;
380 res = mciSendCommand32A(0, MCI_OPEN, dwFlags, (DWORD)pU);
382 free(pU->openParams.lpstrElementName);
383 free(pU->openParams.lpstrDeviceType);
384 free(pU->openParams.lpstrAlias);
385 free(pU);
386 return res;
389 /* A help function for a lot of others ...
390 * for instance status/play/record/seek etc.
392 DWORD
393 _MCISTR_determine_timeformat(LPCSTR dev,WORD wDevID,WORD uDevTyp,int *timef)
395 int res;
396 DWORD dwFlags = MCI_STATUS_ITEM;
397 MCI_STATUS_PARMS *statusParams = xmalloc(sizeof(MCI_STATUS_PARMS));
399 if (!statusParams) return 0;
400 statusParams->dwItem = MCI_STATUS_TIME_FORMAT;
401 statusParams->dwReturn = 0;
402 res = mciSendCommand32A(wDevID, MCI_STATUS, dwFlags, (DWORD)statusParams);
404 if (res==0) *timef = statusParams->dwReturn;
405 free(statusParams);
406 return res;
409 /* query status of MCI drivers
410 * Arguments:
411 * Required:
412 * "mode" - returns "not ready" "paused" "playing" "stopped" "open"
413 * "parked" "recording" "seeking" ....
414 * Basics:
415 * "current track" - returns current track as integer
416 * "length [track <nr>]" - returns length [of track <nr>] in current
417 * timeformat
418 * "number of tracks" - returns number of tracks as integer
419 * "position [track <nr>]" - returns position [in track <nr>] in current
420 * timeformat
421 * "ready" - checks if device is ready to play, -> bool
422 * "start position" - returns start position in timeformat
423 * "time format" - returns timeformat (list of possible values:
424 * "ms" "msf" "milliseconds" "hmsf" "tmsf" "frames"
425 * "bytes" "samples" "hms")
426 * "media present" - returns if media is present as bool
427 * Animation:
428 * "forward" - returns "true" if device is playing forwards
429 * "speed" - returns speed for device
430 * "palette handle" - returns palette handle
431 * "window handle" - returns window handle
432 * "stretch" - returns stretch bool
433 * MIDI sequencer:
434 * "division type" - ? returns "PPQN" "SMPTE 24 frame"
435 * "SMPTE 25 frame" "SMPTE 30 frame" "SMPTE 30 drop frame"
436 * "tempo" - current tempo in (PPQN? speed in frames, SMPTE*? speed in hsmf)
437 * "offset" - offset in dito.
438 * "port" - midi port as integer
439 * "slave" - slave device ("midi","file","none","smpte")
440 * "master" - masterdevice (dito.)
441 * Overlay:
442 * "window handle" - see animation
443 * "stretch" - dito
444 * Video Disc:
445 * "speed" - speed as integer
446 * "forward" - returns bool (when playing forward)
447 * "side" - returns 1 or 2
448 * "media type" - returns "CAV" "CLV" "other"
449 * "disc size" - returns "8" or "12"
450 * WAVEFORM audio:
451 * "input" - base queries on input set
452 * "output" - base queries on output set
453 * "format tag" - return integer format tag
454 * "channels" - return integer nr of channels
455 * "bytespersec" - return average nr of bytes/sec
456 * "samplespersec" - return nr of samples per sec
457 * "bitspersample" - return bitspersample
458 * "alignment" - return block alignment
459 * "level" - return level?
462 #define ITEM1(str,item,xtype) \
463 if (!STRCMP(keywords[i],str)) { \
464 statusParams->dwItem = item; \
465 type = xtype; \
466 i++; \
467 continue; \
469 #define ITEM2(str1,str2,item,xtype) \
470 if ( !STRCMP(keywords[i],str1) && \
471 (i+1 < nrofkeywords) && \
472 !STRCMP(keywords[i+1],str2)) { \
473 statusParams->dwItem = item; \
474 type = xtype; \
475 i+=2; \
476 continue; \
478 #define ITEM3(str1,str2,str3,item,xtype) \
479 if ( !STRCMP(keywords[i],str1) && \
480 (i+2 < nrofkeywords) && \
481 !STRCMP(keywords[i+1],str2) && \
482 !STRCMP(keywords[i+2],str3)) { \
483 statusParams->dwItem = item; \
484 type = xtype; \
485 i+=3; \
486 continue; \
489 static DWORD
490 MCISTR_Status(_MCISTR_PROTO_) {
491 MCI_STATUS_PARMS *statusParams = xmalloc(sizeof(MCI_STATUS_PARMS));
492 int type = 0,i,res,timef;
494 statusParams->dwCallback = hwndCallback;
495 dwFlags |= MCI_STATUS_ITEM;
496 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
497 if (res) return res;
499 statusParams->dwReturn = 0;
500 statusParams->dwItem = 0;
501 i = 0;
503 while (i < nrofkeywords) {
504 if (!STRCMP(keywords[i],"track") && (i+1 < nrofkeywords)) {
505 sscanf(keywords[i+1],"%ld",&(statusParams->dwTrack));
506 dwFlags |= MCI_TRACK;
507 i+=2;
508 continue;
510 FLAG1("start",MCI_STATUS_START);
511 /* generic things */
512 ITEM2("current","track",MCI_STATUS_CURRENT_TRACK,_MCISTR_time);
513 ITEM2("time","format",MCI_STATUS_TIME_FORMAT,_MCISTR_tfname);
514 ITEM1("ready",MCI_STATUS_READY,_MCISTR_bool);
515 ITEM1("mode",MCI_STATUS_MODE,_MCISTR_mode);
516 ITEM3("number","of","tracks",MCI_STATUS_NUMBER_OF_TRACKS,_MCISTR_int);
517 ITEM1("length",MCI_STATUS_LENGTH,_MCISTR_time);
518 ITEM1("position",MCI_STATUS_POSITION,_MCISTR_time);
519 ITEM2("media","present",MCI_STATUS_MEDIA_PRESENT,_MCISTR_bool);
521 switch (uDevTyp) {
522 case MCI_DEVTYPE_ANIMATION:
523 case MCI_DEVTYPE_DIGITAL_VIDEO:
524 ITEM2("palette","handle",MCI_ANIM_STATUS_HPAL,_MCISTR_int);
525 ITEM2("window","handle",MCI_ANIM_STATUS_HWND,_MCISTR_int);
526 ITEM1("stretch",MCI_ANIM_STATUS_STRETCH,_MCISTR_bool);
527 ITEM1("speed",MCI_ANIM_STATUS_SPEED,_MCISTR_int);
528 ITEM1("forward",MCI_ANIM_STATUS_FORWARD,_MCISTR_bool);
529 break;
530 case MCI_DEVTYPE_SEQUENCER:
531 /* just completing the list, not working correctly */
532 ITEM2("division","type",MCI_SEQ_STATUS_DIVTYPE,_MCISTR_divtype);
533 /* tempo ... PPQN in frames/second, SMPTE in hmsf */
534 ITEM1("tempo",MCI_SEQ_STATUS_TEMPO,_MCISTR_int);
535 ITEM1("port",MCI_SEQ_STATUS_PORT,_MCISTR_int);
536 ITEM1("slave",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
537 ITEM1("master",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
538 /* offset ... PPQN in frames/second, SMPTE in hmsf */
539 ITEM1("offset",MCI_SEQ_STATUS_SLAVE,_MCISTR_time);
540 break;
541 case MCI_DEVTYPE_OVERLAY:
542 ITEM2("window","handle",MCI_OVLY_STATUS_HWND,_MCISTR_int);
543 ITEM1("stretch",MCI_OVLY_STATUS_STRETCH,_MCISTR_bool);
544 break;
545 case MCI_DEVTYPE_VIDEODISC:
546 ITEM1("speed",MCI_VD_STATUS_SPEED,_MCISTR_int);
547 ITEM1("forward",MCI_VD_STATUS_FORWARD,_MCISTR_bool);
548 ITEM1("side",MCI_VD_STATUS_SIDE,_MCISTR_int);
549 ITEM2("media","type",MCI_VD_STATUS_SIDE,_MCISTR_vdmtype);
550 /* returns 8 or 12 */
551 ITEM2("disc","size",MCI_VD_STATUS_DISC_SIZE,_MCISTR_int);
552 break;
553 case MCI_DEVTYPE_WAVEFORM_AUDIO:
554 /* I am not quite sure if foll. 2 lines are right. */
555 FLAG1("input",MCI_WAVE_INPUT);
556 FLAG1("output",MCI_WAVE_OUTPUT);
558 ITEM2("format","tag",MCI_WAVE_STATUS_FORMATTAG,_MCISTR_int);
559 ITEM1("channels",MCI_WAVE_STATUS_CHANNELS,_MCISTR_int);
560 ITEM1("bytespersec",MCI_WAVE_STATUS_AVGBYTESPERSEC,_MCISTR_int);
561 ITEM1("samplespersec",MCI_WAVE_STATUS_SAMPLESPERSEC,_MCISTR_int);
562 ITEM1("bitspersample",MCI_WAVE_STATUS_BITSPERSAMPLE,_MCISTR_int);
563 ITEM1("alignment",MCI_WAVE_STATUS_BLOCKALIGN,_MCISTR_int);
564 ITEM1("level",MCI_WAVE_STATUS_LEVEL,_MCISTR_int);
565 break;
567 FIXME(mci,"unknown keyword '%s'\n",keywords[i]);
568 i++;
570 if (!statusParams->dwItem)
571 return MCIERR_MISSING_STRING_ARGUMENT;
573 res = mciSendCommand32A(wDevID, MCI_STATUS, dwFlags, (DWORD)statusParams);
575 if (res==0)
576 _MCISTR_convreturn(type,statusParams->dwReturn,lpstrReturnString,uReturnLength,uDevTyp,timef);
577 free(statusParams);
578 return res;
580 #undef ITEM1
581 #undef ITEM2
582 #undef ITEM3
584 /* set specified parameters in respective MCI drivers
585 * Arguments:
586 * "door open" eject media or somesuch
587 * "door close" load media
588 * "time format <timeformatname>" "ms" "milliseconds" "msf" "hmsf"
589 * "tmsf" "SMPTE 24" "SMPTE 25" "SMPTE 30"
590 * "SMPTE drop 30"
591 * "audio [all|left|right] [on|off]" sets specified audiochannel on or off
592 * "video [on|off]" sets video on/off
593 * Waveform audio:
594 * "formattag pcm" sets format to pcm
595 * "formattag <nr>" sets integer formattag value
596 * "any input" accept input from any known source
597 * "any output" output to any known destination
598 * "input <nr>" input from source <nr>
599 * "output <nr>" output to destination <nr>
600 * "channels <nr>" sets nr of channels
601 * "bytespersec <nr>" sets average bytes per second
602 * "samplespersec <nr>" sets average samples per second (1 sample can
603 * be 2 bytes!)
604 * "alignment <nr>" sets the blockalignment to <nr>
605 * "bitspersample <nr>" sets the nr of bits per sample
606 * Sequencer:
607 * "master [midi|file|smpte|none]" sets the midi master device
608 * "slave [midi|file|smpte|none]" sets the midi master device
609 * "port mapper" midioutput to portmapper
610 * "port <nr>" midioutput to specified port
611 * "tempo <nr>" tempo of track (depends on timeformat/divtype)
612 * "offset <nr>" start offset?
614 static DWORD
615 MCISTR_Set(_MCISTR_PROTO_) {
616 union U {
617 MCI_SET_PARMS setParams;
618 MCI_WAVE_SET_PARMS16 wavesetParams;
619 MCI_SEQ_SET_PARMS seqsetParams;
621 union U *pU = xmalloc(sizeof(union U));
622 int i,res;
624 pU->setParams.dwCallback = hwndCallback;
625 i = 0;
626 while (i < nrofkeywords) {
627 FLAG2("door","open",MCI_SET_DOOR_OPEN);
628 FLAG2("door","closed",MCI_SET_DOOR_CLOSED);
630 if ( !STRCMP(keywords[i],"time") &&
631 (i+2 < nrofkeywords) &&
632 !STRCMP(keywords[i+1],"format")
634 dwFlags |= MCI_SET_TIME_FORMAT;
636 /* FIXME:is this a shortcut for milliseconds or
637 * minutes:seconds? */
638 if (!STRCMP(keywords[i+2],"ms"))
639 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
641 if (!STRCMP(keywords[i+2],"milliseconds"))
642 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
643 if (!STRCMP(keywords[i+2],"msf"))
644 pU->setParams.dwTimeFormat = MCI_FORMAT_MSF;
645 if (!STRCMP(keywords[i+2],"hms"))
646 pU->setParams.dwTimeFormat = MCI_FORMAT_HMS;
647 if (!STRCMP(keywords[i+2],"frames"))
648 pU->setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
649 if (!STRCMP(keywords[i+2],"track"))
650 pU->setParams.dwTimeFormat = MCI_VD_FORMAT_TRACK;
651 if (!STRCMP(keywords[i+2],"bytes"))
652 pU->setParams.dwTimeFormat = MCI_FORMAT_BYTES;
653 if (!STRCMP(keywords[i+2],"samples"))
654 pU->setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
655 if (!STRCMP(keywords[i+2],"tmsf"))
656 pU->setParams.dwTimeFormat = MCI_FORMAT_TMSF;
657 if ( !STRCMP(keywords[i+2],"song") &&
658 (i+3 < nrofkeywords) &&
659 !STRCMP(keywords[i+3],"pointer")
661 pU->setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR;
662 if (!STRCMP(keywords[i+2],"smpte") && (i+3 < nrofkeywords)) {
663 if (!STRCMP(keywords[i+3],"24"))
664 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
665 if (!STRCMP(keywords[i+3],"25"))
666 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
667 if (!STRCMP(keywords[i+3],"30"))
668 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
669 if (!STRCMP(keywords[i+3],"drop") && (i+4 < nrofkeywords) && !STRCMP(keywords[i+4],"30")) {
670 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
671 i++;
673 i++;
674 /*FALLTHROUGH*/
676 i+=3;
677 continue;
679 if (!STRCMP(keywords[i],"audio") && (i+1 < nrofkeywords)) {
680 dwFlags |= MCI_SET_AUDIO;
681 if (!STRCMP(keywords[i+1],"all"))
682 pU->setParams.dwAudio = MCI_SET_AUDIO_ALL;
683 if (!STRCMP(keywords[i+1],"left"))
684 pU->setParams.dwAudio = MCI_SET_AUDIO_LEFT;
685 if (!STRCMP(keywords[i+1],"right"))
686 pU->setParams.dwAudio = MCI_SET_AUDIO_RIGHT;
687 i+=2;
688 continue;
690 FLAG1("video",MCI_SET_VIDEO);
691 FLAG1("on",MCI_SET_ON);
692 FLAG1("off",MCI_SET_OFF);
693 switch (uDevTyp) {
694 case MCI_DEVTYPE_WAVEFORM_AUDIO:
695 FLAG2("any","input",MCI_WAVE_SET_ANYINPUT);
696 FLAG2("any","output",MCI_WAVE_SET_ANYOUTPUT);
698 if ( !STRCMP(keywords[i],"formattag") &&
699 (i+1 < nrofkeywords) &&
700 !STRCMP(keywords[i+1],"pcm")
702 dwFlags |= MCI_WAVE_SET_FORMATTAG;
703 pU->wavesetParams.wFormatTag = WAVE_FORMAT_PCM;
704 i+=2;
705 continue;
708 /* <keyword> <integer> */
709 #define WII(str,flag,fmt,element) \
710 if (!STRCMP(keywords[i],str) && \
711 (i+1 < nrofkeywords)) { \
712 sscanf(keywords[i+1], fmt, \
713 &(pU->wavesetParams. element)); \
714 dwFlags |= flag; \
715 i+=2; \
716 continue; \
718 WII("formattag",MCI_WAVE_SET_FORMATTAG,"%hu",wFormatTag);
719 WII("channels",MCI_WAVE_SET_CHANNELS,"%hu",nChannels);
720 WII("bytespersec",MCI_WAVE_SET_AVGBYTESPERSEC,"%lu",nAvgBytesPerSec);
721 WII("samplespersec",MCI_WAVE_SET_SAMPLESPERSEC,"%lu",nSamplesPerSec);
722 WII("alignment",MCI_WAVE_SET_BLOCKALIGN,"%hu",nBlockAlign);
723 WII("bitspersample",MCI_WAVE_SET_BITSPERSAMPLE,"%hu",wBitsPerSample);
724 WII("input",MCI_WAVE_INPUT,"%hu",wInput);
725 WII("output",MCI_WAVE_OUTPUT,"%hu",wOutput);
726 #undef WII
727 break;
728 case MCI_DEVTYPE_SEQUENCER:
729 if (!STRCMP(keywords[i],"master") && (i+1 < nrofkeywords)) {
730 dwFlags |= MCI_SEQ_SET_MASTER;
731 if (!STRCMP(keywords[i+1],"midi"))
732 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
733 if (!STRCMP(keywords[i+1],"file"))
734 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
735 if (!STRCMP(keywords[i+1],"smpte"))
736 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
737 if (!STRCMP(keywords[i+1],"none"))
738 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
739 i+=2;
740 continue;
742 if (!STRCMP(keywords[i],"slave") && (i+1 < nrofkeywords)) {
743 dwFlags |= MCI_SEQ_SET_SLAVE;
744 if (!STRCMP(keywords[i+1],"midi"))
745 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
746 if (!STRCMP(keywords[i+1],"file"))
747 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
748 if (!STRCMP(keywords[i+1],"smpte"))
749 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
750 if (!STRCMP(keywords[i+1],"none"))
751 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
752 i+=2;
753 continue;
755 if ( !STRCMP(keywords[i],"port") &&
756 (i+1 < nrofkeywords) &&
757 !STRCMP(keywords[i+1],"mapper")
759 pU->seqsetParams.dwPort=-1;/* FIXME:not sure*/
760 dwFlags |= MCI_SEQ_SET_PORT;
761 i+=2;
762 continue;
764 #define SII(str,flag,element) \
765 if (!STRCMP(keywords[i],str) && (i+1 < nrofkeywords)) {\
766 sscanf(keywords[i+1],"%ld",&(pU->seqsetParams. element));\
767 dwFlags |= flag;\
768 i+=2;\
769 continue;\
771 SII("tempo",MCI_SEQ_SET_TEMPO,dwTempo);
772 SII("port",MCI_SEQ_SET_PORT,dwPort);
773 SII("offset",MCI_SEQ_SET_PORT,dwOffset);
775 i++;
777 if (!dwFlags)
778 return MCIERR_MISSING_STRING_ARGUMENT;
779 res = mciSendCommand32A(wDevID, MCI_SET, dwFlags, (DWORD)pU);
780 free(pU);
781 return res;
784 /* specify break key
785 * Arguments:
786 * "off" disable break
787 * "on <keyid>" enable break on key with keyid
788 * (I strongly suspect, that there is another parameter:
789 * "window <handle>"
790 * but I don't see it mentioned in my documentation.
791 * Returns nothing.
793 static DWORD
794 MCISTR_Break(_MCISTR_PROTO_)
796 MCI_BREAK_PARMS16 *breakParams = xmalloc(sizeof(MCI_BREAK_PARMS16));
797 int res,i;
799 if (!breakParams) return 0;
800 /*breakParams.hwndBreak ? */
801 for (i = 0; i < nrofkeywords; i++) {
802 FLAG1("off",MCI_BREAK_OFF);
803 if (!strcmp(keywords[i],"on") && (nrofkeywords>i+1)) {
804 dwFlags&=~MCI_BREAK_OFF;
805 dwFlags|=MCI_BREAK_KEY;
806 sscanf(keywords[i+1],"%hd",&(breakParams->nVirtKey));
807 i+=2;
808 continue;
811 res = mciSendCommand32A(wDevID, MCI_BREAK, dwFlags, (DWORD)breakParams);
812 free(breakParams);
813 return res;
816 #define ITEM1(str,item,xtype) \
817 if (!STRCMP(keywords[i],str)) { \
818 gdcParams->dwItem = item; \
819 type = xtype; \
820 i++; \
821 continue; \
823 #define ITEM2(str1,str2,item,xtype) \
824 if ( !STRCMP(keywords[i],str1) && \
825 (i+1 < nrofkeywords) && \
826 !STRCMP(keywords[i+1],str2)) { \
827 gdcParams->dwItem = item; \
828 type = xtype; \
829 i+=2; \
830 continue; \
832 #define ITEM3(str1,str2,str3,item,xtype) \
833 if ( !STRCMP(keywords[i],str1) && \
834 (i+2 < nrofkeywords) && \
835 !STRCMP(keywords[i+1],str2) && \
836 !STRCMP(keywords[i+2],str3)) { \
837 gdcParams->dwItem = item; \
838 type = xtype; \
839 i+=3; \
840 continue; \
843 /* get device capabilities of MCI drivers
844 * Arguments:
845 * Generic:
846 * "device type" returns device name as string
847 * "has audio" returns bool
848 * "has video" returns bool
849 * "uses files" returns bool
850 * "compound device" returns bool
851 * "can record" returns bool
852 * "can play" returns bool
853 * "can eject" returns bool
854 * "can save" returns bool
855 * Animation:
856 * "palettes" returns nr of available palette entries
857 * "windows" returns nr of available windows
858 * "can reverse" returns bool
859 * "can stretch" returns bool
860 * "slow play rate" returns the slow playrate
861 * "fast play rate" returns the fast playrate
862 * "normal play rate" returns the normal playrate
863 * Overlay:
864 * "windows" returns nr of available windows
865 * "can stretch" returns bool
866 * "can freeze" returns bool
867 * Videodisc:
868 * "cav" assume CAV discs (default if no disk inserted)
869 * "clv" assume CLV discs
870 * "can reverse" returns bool
871 * "slow play rate" returns the slow playrate
872 * "fast play rate" returns the fast playrate
873 * "normal play rate" returns the normal playrate
874 * Waveform audio:
875 * "inputs" returns nr of inputdevices
876 * "outputs" returns nr of outputdevices
878 static DWORD
879 MCISTR_Capability(_MCISTR_PROTO_) {
880 MCI_GETDEVCAPS_PARMS *gdcParams = xmalloc(sizeof(MCI_GETDEVCAPS_PARMS));
881 int type=0,i,res;
883 gdcParams->dwCallback = hwndCallback;
884 if (!nrofkeywords)
885 return MCIERR_MISSING_STRING_ARGUMENT;
886 /* well , thats default */
887 dwFlags |= MCI_GETDEVCAPS_ITEM;
888 gdcParams->dwItem = 0;
889 i=0;
890 while (i < nrofkeywords) {
891 ITEM2("device","type",MCI_GETDEVCAPS_DEVICE_TYPE,_MCISTR_devtype);
892 ITEM2("has","audio",MCI_GETDEVCAPS_HAS_AUDIO,_MCISTR_bool);
893 ITEM2("has","video",MCI_GETDEVCAPS_HAS_VIDEO,_MCISTR_bool);
894 ITEM2("uses","files",MCI_GETDEVCAPS_USES_FILES,_MCISTR_bool);
895 ITEM2("compound","device",MCI_GETDEVCAPS_COMPOUND_DEVICE,_MCISTR_bool);
896 ITEM2("can","record",MCI_GETDEVCAPS_CAN_RECORD,_MCISTR_bool);
897 ITEM2("can","play",MCI_GETDEVCAPS_CAN_PLAY,_MCISTR_bool);
898 ITEM2("can","eject",MCI_GETDEVCAPS_CAN_EJECT,_MCISTR_bool);
899 ITEM2("can","save",MCI_GETDEVCAPS_CAN_SAVE,_MCISTR_bool);
900 switch (uDevTyp) {
901 case MCI_DEVTYPE_ANIMATION:
902 ITEM1("palettes",MCI_ANIM_GETDEVCAPS_PALETTES,_MCISTR_int);
903 ITEM1("windows",MCI_ANIM_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
904 ITEM2("can","reverse",MCI_ANIM_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
905 ITEM2("can","stretch",MCI_ANIM_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
906 ITEM3("slow","play","rate",MCI_ANIM_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
907 ITEM3("fast","play","rate",MCI_ANIM_GETDEVCAPS_FAST_RATE,_MCISTR_int);
908 ITEM3("normal","play","rate",MCI_ANIM_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
909 break;
910 case MCI_DEVTYPE_OVERLAY:
911 ITEM1("windows",MCI_OVLY_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
912 ITEM2("can","freeze",MCI_OVLY_GETDEVCAPS_CAN_FREEZE,_MCISTR_bool);
913 ITEM2("can","stretch",MCI_OVLY_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
914 break;
915 case MCI_DEVTYPE_VIDEODISC:
916 FLAG1("cav",MCI_VD_GETDEVCAPS_CAV);
917 FLAG1("clv",MCI_VD_GETDEVCAPS_CLV);
918 ITEM2("can","reverse",MCI_VD_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
919 ITEM3("slow","play","rate",MCI_VD_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
920 ITEM3("fast","play","rate",MCI_VD_GETDEVCAPS_FAST_RATE,_MCISTR_int);
921 ITEM3("normal","play","rate",MCI_VD_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
922 break;
923 case MCI_DEVTYPE_WAVEFORM_AUDIO:
924 ITEM1("inputs",MCI_WAVE_GETDEVCAPS_INPUTS,_MCISTR_int);
925 ITEM1("outputs",MCI_WAVE_GETDEVCAPS_OUTPUTS,_MCISTR_int);
926 break;
928 i++;
930 res = mciSendCommand32A(wDevID, MCI_GETDEVCAPS, dwFlags, (DWORD)gdcParams);
932 /* no timeformat needed */
933 if (res==0)
934 _MCISTR_convreturn(type, gdcParams->dwReturn, lpstrReturnString,
935 uReturnLength, uDevTyp, 0);
936 free(gdcParams);
937 return res;
939 #undef ITEM1
940 #undef ITEM2
941 #undef ITEM3
942 /* resumes operation of device. no arguments, no return values */
943 static DWORD
944 MCISTR_Resume(_MCISTR_PROTO_)
946 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
947 int res;
948 genParams->dwCallback = hwndCallback;
949 res = mciSendCommand32A(wDevID, MCI_RESUME, dwFlags, (DWORD)genParams);
950 free(genParams);
951 return res;
954 /* pauses operation of device. no arguments, no return values */
955 static DWORD
956 MCISTR_Pause(_MCISTR_PROTO_)
958 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
959 int res;
960 genParams->dwCallback = hwndCallback;
961 res = mciSendCommand32A(wDevID, MCI_PAUSE, dwFlags, (DWORD)genParams);
962 free(genParams);
963 return res;
966 /* stops operation of device. no arguments, no return values */
967 static DWORD
968 MCISTR_Stop(_MCISTR_PROTO_)
970 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
971 int res;
972 genParams->dwCallback = hwndCallback;
973 res = mciSendCommand32A(wDevID, MCI_STOP, dwFlags, (DWORD)genParams);
974 free(genParams);
975 return res;
978 /* starts recording.
979 * Arguments:
980 * "overwrite" overwrite existing things
981 * "insert" insert at current position
982 * "to <time>" record up to <time> (specified in timeformat)
983 * "from <time>" record from <time> (specified in timeformat)
985 static DWORD
986 MCISTR_Record(_MCISTR_PROTO_) {
987 int i,res,timef,nrargs,j,k,a[4];
988 char *parsestr;
989 MCI_RECORD_PARMS *recordParams = xmalloc(sizeof(MCI_RECORD_PARMS));
991 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
992 if (res) return res;
994 switch (timef) {
995 case MCI_FORMAT_MILLISECONDS:
996 case MCI_FORMAT_FRAMES:
997 case MCI_FORMAT_BYTES:
998 case MCI_FORMAT_SAMPLES:
999 nrargs=1;
1000 parsestr="%d";
1001 break;
1002 case MCI_FORMAT_HMS:
1003 case MCI_FORMAT_MSF:
1004 parsestr="%d:%d:%d";
1005 nrargs=3;
1006 break;
1007 case MCI_FORMAT_TMSF:
1008 parsestr="%d:%d:%d:%d";
1009 nrargs=4;
1010 break;
1011 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1012 parsestr="%d";
1013 nrargs=1;
1014 break;
1016 recordParams->dwCallback = hwndCallback;
1017 i = 0;
1018 while (i < nrofkeywords) {
1019 if (!strcmp(keywords[i],"to") && (i+1 < nrofkeywords)) {
1020 dwFlags |= MCI_TO;
1021 a[0]=a[1]=a[2]=a[3]=0;
1022 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1023 /* add up all integers we got, if we have more
1024 * shift them. (Well I should use the macros in
1025 * mmsystem.h, right).
1027 recordParams->dwTo=0;
1028 for (k=0;k < j;k++)
1029 recordParams->dwTo+=a[k] << (8*(nrargs-k));
1030 i+=2;
1031 continue;
1033 if (!strcmp(keywords[i],"from") && (i+1 < nrofkeywords)) {
1034 dwFlags |= MCI_FROM;
1035 a[0]=a[1]=a[2]=a[3]=0;
1036 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1037 /* dito. */
1038 recordParams->dwFrom=0;
1039 for (k=0;k < j;k++)
1040 recordParams->dwFrom+=a[k]<<(8*(nrargs-k));
1041 i+=2;
1042 continue;
1044 FLAG1("insert",MCI_RECORD_INSERT);
1045 FLAG1("overwrite",MCI_RECORD_OVERWRITE);
1046 i++;
1048 res = mciSendCommand32A(wDevID, MCI_RECORD, dwFlags, (DWORD)recordParams);
1049 free(recordParams);
1050 return res;
1053 /* play media
1054 * Arguments:
1055 * "to <time>" play up to <time> (specified in set timeformat)
1056 * "from <time>" play from <time> (specified in set timeformat)
1057 * Animation:
1058 * "slow" play slow
1059 * "fast" play fast
1060 * "scan" play as fast as possible (with audio disabled perhaps)
1061 * "reverse" play reverse
1062 * "speed <fps>" play with specified frames per second
1063 * Videodisc:
1064 * "slow" play slow
1065 * "fast" play fast
1066 * "scan" play as fast as possible (with audio disabled perhaps)
1067 * "reverse" play reverse
1068 * "speed <fps>" play with specified frames per second
1070 static DWORD
1071 MCISTR_Play(_MCISTR_PROTO_) {
1072 int i,res,timef,nrargs,j,k,a[4];
1073 char *parsestr;
1074 union U {
1075 MCI_PLAY_PARMS playParams;
1076 MCI_VD_PLAY_PARMS vdplayParams;
1077 MCI_ANIM_PLAY_PARMS animplayParams;
1079 union U *pU = xmalloc(sizeof(union U));
1081 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1082 if (res) return res;
1083 switch (timef) {
1084 case MCI_FORMAT_MILLISECONDS:
1085 case MCI_FORMAT_FRAMES:
1086 case MCI_FORMAT_BYTES:
1087 case MCI_FORMAT_SAMPLES:
1088 nrargs=1;
1089 parsestr="%d";
1090 break;
1091 case MCI_FORMAT_HMS:
1092 case MCI_FORMAT_MSF:
1093 parsestr="%d:%d:%d";
1094 nrargs=3;
1095 break;
1096 case MCI_FORMAT_TMSF:
1097 parsestr="%d:%d:%d:%d";
1098 nrargs=4;
1099 break;
1100 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1101 parsestr="%d";
1102 nrargs=1;
1103 break;
1105 pU->playParams.dwCallback=hwndCallback;
1106 i=0;
1107 while (i < nrofkeywords) {
1108 if (!strcmp(keywords[i],"to") && (i+1 < nrofkeywords)) {
1109 dwFlags |= MCI_TO;
1110 a[0]=a[1]=a[2]=a[3]=0;
1111 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1112 /* add up all integers we got, if we have more
1113 * shift them. (Well I should use the macros in
1114 * mmsystem.h, right).
1116 pU->playParams.dwTo=0;
1117 for (k=0;k < j;k++)
1118 pU->playParams.dwTo+=a[k] << (8*(nrargs-k));
1119 i+=2;
1120 continue;
1122 if (!strcmp(keywords[i],"from") && (i+1 < nrofkeywords)) {
1123 dwFlags |= MCI_FROM;
1124 a[0]=a[1]=a[2]=a[3]=0;
1125 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1126 /* dito. */
1127 pU->playParams.dwFrom=0;
1128 for (k=0;k < j;k++)
1129 pU->playParams.dwFrom+=a[k]<<(8*(nrargs-k));
1130 i+=2;
1131 continue;
1133 switch (uDevTyp) {
1134 case MCI_DEVTYPE_VIDEODISC:
1135 FLAG1("slow",MCI_VD_PLAY_SLOW);
1136 FLAG1("fast",MCI_VD_PLAY_FAST);
1137 FLAG1("scan",MCI_VD_PLAY_SCAN);
1138 FLAG1("reverse",MCI_VD_PLAY_REVERSE);
1139 if (!STRCMP(keywords[i],"speed") && (i+1 < nrofkeywords)) {
1140 dwFlags |= MCI_VD_PLAY_SPEED;
1141 sscanf(keywords[i+1],"%ld",&(pU->vdplayParams.dwSpeed));
1142 i+=2;
1143 continue;
1145 break;
1146 case MCI_DEVTYPE_ANIMATION:
1147 FLAG1("slow",MCI_ANIM_PLAY_SLOW);
1148 FLAG1("fast",MCI_ANIM_PLAY_FAST);
1149 FLAG1("scan",MCI_ANIM_PLAY_SCAN);
1150 FLAG1("reverse",MCI_ANIM_PLAY_REVERSE);
1151 if (!STRCMP(keywords[i],"speed") && (i+1 < nrofkeywords)) {
1152 dwFlags |= MCI_ANIM_PLAY_SPEED;
1153 sscanf(keywords[i+1],"%ld",&(pU->animplayParams.dwSpeed));
1154 i+=2;
1155 continue;
1157 break;
1159 i++;
1161 res = mciSendCommand32A(wDevID, MCI_PLAY, dwFlags, (DWORD)pU);
1162 free(pU);
1163 return res;
1166 /* seek to a specified position
1167 * Arguments:
1168 * "to start" seek to start of medium
1169 * "to end" seek to end of medium
1170 * "to <time>" seek to <time> specified in current timeformat
1172 static DWORD
1173 MCISTR_Seek(_MCISTR_PROTO_) {
1174 int i,res,timef,nrargs,j,k,a[4];
1175 char *parsestr;
1176 MCI_SEEK_PARMS *seekParams = xmalloc(sizeof(MCI_SEEK_PARMS));
1178 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1179 if (res) return res;
1180 switch (timef) {
1181 case MCI_FORMAT_MILLISECONDS:
1182 case MCI_FORMAT_FRAMES:
1183 case MCI_FORMAT_BYTES:
1184 case MCI_FORMAT_SAMPLES:
1185 nrargs=1;
1186 parsestr="%d";
1187 break;
1188 case MCI_FORMAT_HMS:
1189 case MCI_FORMAT_MSF:
1190 parsestr="%d:%d:%d";
1191 nrargs=3;
1192 break;
1193 case MCI_FORMAT_TMSF:
1194 parsestr="%d:%d:%d:%d";
1195 nrargs=4;
1196 break;
1197 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1198 parsestr="%d";
1199 nrargs=1;
1200 break;
1202 seekParams->dwCallback=hwndCallback;
1203 i=0;
1204 while (i < nrofkeywords) {
1205 if ( !STRCMP(keywords[i],"to") && (i+1 < nrofkeywords)) {
1206 if (!STRCMP(keywords[i+1],"start")) {
1207 dwFlags|=MCI_SEEK_TO_START;
1208 seekParams->dwTo=0;
1209 i+=2;
1210 continue;
1212 if (!STRCMP(keywords[i+1],"end")) {
1213 dwFlags|=MCI_SEEK_TO_END;
1214 seekParams->dwTo=0;
1215 i+=2;
1216 continue;
1218 dwFlags|=MCI_TO;
1219 i+=2;
1220 a[0]=a[1]=a[2]=a[3]=0;
1221 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1222 seekParams->dwTo=0;
1223 for (k=0;k < j;k++)
1224 seekParams->dwTo+=a[k] << (8*(nrargs-k));
1225 continue;
1227 switch (uDevTyp) {
1228 case MCI_DEVTYPE_VIDEODISC:
1229 FLAG1("reverse",MCI_VD_SEEK_REVERSE);
1230 break;
1232 i++;
1234 res = mciSendCommand32A(wDevID, MCI_SEEK, dwFlags, (DWORD)seekParams);
1235 free(seekParams);
1236 return res;
1239 /* close media/driver */
1240 static DWORD
1241 MCISTR_Close(_MCISTR_PROTO_)
1243 MCI_GENERIC_PARMS* closeParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1244 int res;
1246 res = mciSendCommand32A(wDevID, MCI_CLOSE, dwFlags, (DWORD)closeParams);
1247 free(closeParams);
1248 return res;
1251 /* return information.
1252 * Arguments:
1253 * "product" return product name (human readable)
1254 * "file" return filename
1255 * Animation:
1256 * "text" returns text?
1257 * Overlay:
1258 * "text" returns text?
1260 static DWORD
1261 MCISTR_Info(_MCISTR_PROTO_)
1263 MCI_INFO_PARMS16* infoParams = xmalloc(sizeof(MCI_INFO_PARMS16));
1264 DWORD sflags;
1265 int i,res;
1267 sflags = dwFlags;
1268 i=0;
1269 while (i < nrofkeywords) {
1270 FLAG1("product",MCI_INFO_PRODUCT);
1271 FLAG1("file",MCI_INFO_FILE);
1272 switch (uDevTyp) {
1273 case MCI_DEVTYPE_ANIMATION:
1274 FLAG1("text",MCI_ANIM_INFO_TEXT);
1275 break;
1276 case MCI_DEVTYPE_OVERLAY:
1277 FLAG1("text",MCI_OVLY_INFO_TEXT);
1278 break;
1280 i++;
1282 if (dwFlags == sflags)
1283 return MCIERR_MISSING_STRING_ARGUMENT;
1284 /* MCI driver will fill in lpstrReturn, dwRetSize.
1285 * FIXME: I don't know if this is correct behaviour
1287 res = mciSendCommand32A(wDevID, MCI_INFO, dwFlags, (DWORD)infoParams);
1288 if (res==0)
1289 _MCI_STR(infoParams->lpstrReturn);
1290 free(infoParams);
1291 return res;
1294 /* query MCI driver itself for information
1295 * Arguments:
1296 * "installname" return install name of <device> (system.ini)
1297 * "quantity" return nr of installed drivers
1298 * "open" open drivers only (additional flag)
1299 * "name <nr>" return nr of devices with <devicetyp>
1300 * "name all" return nr of all devices
1302 * FIXME: mciSysInfo16() is broken I think.
1304 static DWORD
1305 MCISTR_Sysinfo(_MCISTR_PROTO_) {
1306 MCI_SYSINFO_PARMS16 sysinfoParams;
1307 int i,res;
1309 sysinfoParams.lpstrReturn = lpstrReturnString;
1310 sysinfoParams.dwRetSize = uReturnLength;
1311 sysinfoParams.wDeviceType = uDevTyp;
1313 for (i = 0; i < nrofkeywords; i++) {
1314 FLAG1("installname",MCI_SYSINFO_INSTALLNAME);
1315 FLAG1("quantity",MCI_SYSINFO_INSTALLNAME);
1316 FLAG1("open",MCI_SYSINFO_OPEN);
1317 if (!strcmp(keywords[i],"name") && (i+1 < nrofkeywords)) {
1318 sscanf(keywords[i+1],"%ld",&(sysinfoParams.dwNumber));
1319 dwFlags |= MCI_SYSINFO_NAME;
1320 i++;
1323 res = mciSendCommand16(0, MCI_SYSINFO, dwFlags, (DWORD)&sysinfoParams);
1325 if (dwFlags & MCI_SYSINFO_QUANTITY) {
1326 char buf[100];
1328 sprintf(buf,"%ld",*(long*)lpstrReturnString);
1329 _MCI_STR(buf);
1331 /* no need to copy anything back, mciSysInfo did it for us */
1332 return res;
1335 /* load file
1336 * Argument: "<filename>"
1337 * Overlay: "at <left> <top> <right> <bottom>" additional
1339 static DWORD
1340 MCISTR_Load(_MCISTR_PROTO_) {
1341 union U {
1342 MCI_LOAD_PARMS16 loadParams;
1343 MCI_OVLY_LOAD_PARMS16 ovlyloadParams;
1345 union U *pU = xmalloc(sizeof(union U));
1346 int i,len,res;
1347 char *s;
1349 i=len=0;
1350 while (i < nrofkeywords) {
1351 switch (uDevTyp) {
1352 case MCI_DEVTYPE_OVERLAY:
1353 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1354 dwFlags |= MCI_OVLY_RECT;
1355 sscanf(keywords[i+1],"%hd",&(pU->ovlyloadParams.rc.left));
1356 sscanf(keywords[i+2],"%hd",&(pU->ovlyloadParams.rc.top));
1357 sscanf(keywords[i+3],"%hd",&(pU->ovlyloadParams.rc.right));
1358 sscanf(keywords[i+4],"%hd",&(pU->ovlyloadParams.rc.bottom));
1359 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1360 continue;
1362 break;
1364 len+=strlen(keywords[i])+1;
1365 i++;
1367 s=(char*)xmalloc(len);
1368 *s='\0';
1369 while (i < nrofkeywords) {
1370 strcat(s,keywords[i]);
1371 i++;
1372 if (i < nrofkeywords) strcat(s," ");
1374 pU->loadParams.lpfilename=s;
1375 dwFlags |= MCI_LOAD_FILE;
1376 res = mciSendCommand32A(wDevID, MCI_LOAD, dwFlags, (DWORD)pU);
1377 free(s);
1378 free(pU);
1379 return res;
1382 /* save to file
1383 * Argument: "<filename>"
1384 * Overlay: "at <left> <top> <right> <bottom>" additional
1386 static DWORD
1387 MCISTR_Save(_MCISTR_PROTO_) {
1388 union U {
1389 MCI_SAVE_PARMS saveParams;
1390 MCI_OVLY_SAVE_PARMS16 ovlysaveParams;
1392 union U *pU = xmalloc(sizeof(union U));
1393 int i,len,res;
1394 char *s;
1396 i=0;len=0;
1397 while (i < nrofkeywords) {
1398 switch (uDevTyp) {
1399 case MCI_DEVTYPE_OVERLAY:
1400 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1401 dwFlags |= MCI_OVLY_RECT;
1402 sscanf(keywords[i+1],"%hd",&(pU->ovlysaveParams.rc.left));
1403 sscanf(keywords[i+2],"%hd",&(pU->ovlysaveParams.rc.top));
1404 sscanf(keywords[i+3],"%hd",&(pU->ovlysaveParams.rc.right));
1405 sscanf(keywords[i+4],"%hd",&(pU->ovlysaveParams.rc.bottom));
1406 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1407 continue;
1409 break;
1411 len+=strlen(keywords[i])+1;
1412 i++;
1414 s=(char*)xmalloc(len);
1415 *s='\0';
1416 while (i < nrofkeywords) {
1417 strcat(s,keywords[i]);
1418 i++;
1419 if (i < nrofkeywords) strcat(s," ");
1421 pU->saveParams.lpfilename=s;
1422 dwFlags |= MCI_LOAD_FILE;
1423 res = mciSendCommand32A(wDevID, MCI_SAVE, dwFlags, (DWORD)pU);
1424 free(s);
1425 free(pU);
1426 return res;
1429 /* prepare device for input/output
1430 * (only applyable to waveform audio)
1432 static DWORD
1433 MCISTR_Cue(_MCISTR_PROTO_) {
1434 MCI_GENERIC_PARMS *cueParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1435 int i,res;
1437 for (i = 0; i < nrofkeywords; i++) {
1438 switch (uDevTyp) {
1439 case MCI_DEVTYPE_WAVEFORM_AUDIO:
1440 FLAG1("input", MCI_WAVE_INPUT);
1441 FLAG1("output", MCI_WAVE_OUTPUT);
1442 break;
1445 res = mciSendCommand32A(wDevID, MCI_CUE, dwFlags, (DWORD)cueParams);
1446 free(cueParams);
1447 return res;
1450 /* delete information */
1451 static DWORD
1452 MCISTR_Delete(_MCISTR_PROTO_) {
1453 int timef,nrargs,i,j,k,a[4],res;
1454 char *parsestr;
1455 MCI_WAVE_DELETE_PARMS *deleteParams = xmalloc(sizeof(MCI_WAVE_DELETE_PARMS));
1457 /* only implemented for waveform audio */
1458 if (uDevTyp != MCI_DEVTYPE_WAVEFORM_AUDIO)
1459 return MCIERR_UNSUPPORTED_FUNCTION; /* well it fits */
1460 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1461 if (res) return res;
1462 switch (timef) {
1463 case MCI_FORMAT_MILLISECONDS:
1464 case MCI_FORMAT_FRAMES:
1465 case MCI_FORMAT_BYTES:
1466 case MCI_FORMAT_SAMPLES:
1467 nrargs=1;
1468 parsestr="%d";
1469 break;
1470 case MCI_FORMAT_HMS:
1471 case MCI_FORMAT_MSF:
1472 parsestr="%d:%d:%d";
1473 nrargs=3;
1474 break;
1475 case MCI_FORMAT_TMSF:
1476 parsestr="%d:%d:%d:%d";
1477 nrargs=4;
1478 break;
1479 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1480 parsestr="%d";
1481 nrargs=1;
1482 break;
1484 i=0;
1485 while (i < nrofkeywords) {
1486 if (!strcmp(keywords[i],"to") && (i+1 < nrofkeywords)) {
1487 dwFlags |= MCI_TO;
1488 a[0]=a[1]=a[2]=a[3]=0;
1489 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1490 /* add up all integers we got, if we have more
1491 * shift them. (Well I should use the macros in
1492 * mmsystem.h, right).
1494 deleteParams->dwTo=0;
1495 for (k=0;k < j;k++)
1496 deleteParams->dwTo+=a[k]<<(8*(nrargs-k));
1497 i+=2;
1498 continue;
1500 if (!strcmp(keywords[i],"from") && (i+1 < nrofkeywords)) {
1501 dwFlags |= MCI_FROM;
1502 a[0]=a[1]=a[2]=a[3]=0;
1503 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1504 /* dito. */
1505 deleteParams->dwFrom=0;
1506 for (k=0;k < j;k++)
1507 deleteParams->dwFrom+=a[k]<<(8*(nrargs-k));
1508 i+=2;
1509 continue;
1511 i++;
1513 res = mciSendCommand32A(wDevID, MCI_DELETE, dwFlags, (DWORD)deleteParams);
1514 free(deleteParams);
1515 return res;
1518 /* send command to device. only applies to videodisc */
1519 static DWORD
1520 MCISTR_Escape(_MCISTR_PROTO_)
1522 MCI_VD_ESCAPE_PARMS16 *escapeParams = xmalloc(sizeof(MCI_VD_ESCAPE_PARMS16));
1523 int i,len,res;
1524 char *s;
1526 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1527 return MCIERR_UNSUPPORTED_FUNCTION;
1528 i=0;len=0;
1529 while (i < nrofkeywords) {
1530 len+=strlen(keywords[i])+1;
1531 i++;
1533 s=(char*)malloc(len);
1534 *s='\0';
1535 while (i < nrofkeywords) {
1536 strcat(s,keywords[i]);
1537 i++;
1538 if (i < nrofkeywords) strcat(s," ");
1540 escapeParams->lpstrCommand = s;
1541 dwFlags |= MCI_VD_ESCAPE_STRING;
1542 res = mciSendCommand32A(wDevID, MCI_ESCAPE, dwFlags, (DWORD)escapeParams);
1543 free(s);
1544 free(escapeParams);
1545 return res;
1548 /* unfreeze [part of] the overlayed video
1549 * only applyable to Overlay devices
1551 static DWORD
1552 MCISTR_Unfreeze(_MCISTR_PROTO_)
1554 MCI_OVLY_RECT_PARMS16 *unfreezeParams = xmalloc(sizeof(MCI_OVLY_RECT_PARMS16));
1555 int i,res;
1557 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1558 return MCIERR_UNSUPPORTED_FUNCTION;
1559 i=0;while (i < nrofkeywords) {
1560 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1561 sscanf(keywords[i+1],"%hd",&(unfreezeParams->rc.left));
1562 sscanf(keywords[i+2],"%hd",&(unfreezeParams->rc.top));
1563 sscanf(keywords[i+3],"%hd",&(unfreezeParams->rc.right));
1564 sscanf(keywords[i+4],"%hd",&(unfreezeParams->rc.bottom));
1565 dwFlags |= MCI_OVLY_RECT;
1566 i+=5;
1567 continue;
1569 i++;
1571 res = mciSendCommand32A(wDevID, MCI_UNFREEZE, dwFlags, (DWORD)unfreezeParams);
1572 free(unfreezeParams);
1573 return res;
1575 /* freeze [part of] the overlayed video
1576 * only applyable to Overlay devices
1578 static DWORD
1579 MCISTR_Freeze(_MCISTR_PROTO_)
1581 MCI_OVLY_RECT_PARMS16 *freezeParams = xmalloc(sizeof(MCI_OVLY_RECT_PARMS16));
1582 int i,res;
1584 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1585 return MCIERR_UNSUPPORTED_FUNCTION;
1586 i=0;while (i < nrofkeywords) {
1587 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1588 sscanf(keywords[i+1],"%hd",&(freezeParams->rc.left));
1589 sscanf(keywords[i+2],"%hd",&(freezeParams->rc.top));
1590 sscanf(keywords[i+3],"%hd",&(freezeParams->rc.right));
1591 sscanf(keywords[i+4],"%hd",&(freezeParams->rc.bottom));
1592 dwFlags |= MCI_OVLY_RECT;
1593 i+=5;
1594 continue;
1596 i++;
1598 res = mciSendCommand32A(wDevID, MCI_FREEZE, dwFlags, (DWORD)freezeParams);
1599 free(freezeParams);
1600 return res;
1603 /* copy parts of image to somewhere else
1604 * "source [at <left> <top> <right> <bottom>]" source is framebuffer [or rect]
1605 * "destination [at <left> <top> <right> <bottom>]" destination is framebuffer [or rect]
1606 * Overlay:
1607 * "frame [at <left> <top> <right> <bottom>]" frame is framebuffer [or rect]
1608 * where the video input is placed
1609 * "video [at <left> <top> <right> <bottom>]" video is whole video [or rect]
1610 * (defining part of input to
1611 * be displayed)
1613 * FIXME: This whole junk is passing multiple rectangles.
1614 * I don't know how to do that with the present interface.
1615 * (Means code below is broken)
1617 static DWORD
1618 MCISTR_Put(_MCISTR_PROTO_) {
1619 union U {
1620 MCI_OVLY_RECT_PARMS16 ovlyputParams;
1621 MCI_ANIM_RECT_PARMS16 animputParams;
1623 union U *pU = xmalloc(sizeof(union U));
1624 int i,res;
1625 i=0;while (i < nrofkeywords) {
1626 switch (uDevTyp) {
1627 case MCI_DEVTYPE_ANIMATION:
1628 FLAG1("source",MCI_ANIM_PUT_SOURCE);
1629 FLAG1("destination",MCI_ANIM_PUT_DESTINATION);
1630 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1631 sscanf(keywords[i+1],"%hd",&(pU->animputParams.rc.left));
1632 sscanf(keywords[i+2],"%hd",&(pU->animputParams.rc.top));
1633 sscanf(keywords[i+3],"%hd",&(pU->animputParams.rc.right));
1634 sscanf(keywords[i+4],"%hd",&(pU->animputParams.rc.bottom));
1635 dwFlags |= MCI_ANIM_RECT;
1636 i+=5;
1637 continue;
1639 break;
1640 case MCI_DEVTYPE_OVERLAY:
1641 FLAG1("source",MCI_OVLY_PUT_SOURCE);
1642 FLAG1("destination",MCI_OVLY_PUT_DESTINATION);
1643 FLAG1("video",MCI_OVLY_PUT_VIDEO);
1644 FLAG1("frame",MCI_OVLY_PUT_FRAME);
1645 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1646 sscanf(keywords[i+1],"%hd",&(pU->ovlyputParams.rc.left));
1647 sscanf(keywords[i+2],"%hd",&(pU->ovlyputParams.rc.top));
1648 sscanf(keywords[i+3],"%hd",&(pU->ovlyputParams.rc.right));
1649 sscanf(keywords[i+4],"%hd",&(pU->ovlyputParams.rc.bottom));
1650 dwFlags |= MCI_OVLY_RECT;
1651 i+=5;
1652 continue;
1654 break;
1656 i++;
1658 res = mciSendCommand32A(wDevID, MCI_PUT, dwFlags, (DWORD)pU);
1659 free(pU);
1660 return res;
1663 /* palette behaviour changing
1664 * (Animation only)
1665 * "normal" realize the palette normally
1666 * "background" realize the palette as background palette
1668 static DWORD
1669 MCISTR_Realize(_MCISTR_PROTO_)
1671 MCI_GENERIC_PARMS *realizeParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1672 int i,res;
1674 if (uDevTyp != MCI_DEVTYPE_ANIMATION)
1675 return MCIERR_UNSUPPORTED_FUNCTION;
1676 i=0;
1677 while (i < nrofkeywords) {
1678 FLAG1("background",MCI_ANIM_REALIZE_BKGD);
1679 FLAG1("normal",MCI_ANIM_REALIZE_NORM);
1680 i++;
1682 res = mciSendCommand32A(wDevID, MCI_REALIZE, dwFlags, (DWORD)realizeParams);
1683 free(realizeParams);
1684 return res;
1687 /* videodisc spinning
1688 * "up"
1689 * "down"
1691 static DWORD
1692 MCISTR_Spin(_MCISTR_PROTO_)
1694 MCI_GENERIC_PARMS *spinParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1695 int i,res;
1697 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1698 return MCIERR_UNSUPPORTED_FUNCTION;
1699 i=0;
1700 while (i < nrofkeywords) {
1701 FLAG1("up",MCI_VD_SPIN_UP);
1702 FLAG1("down",MCI_VD_SPIN_UP);
1703 i++;
1705 res = mciSendCommand32A(wDevID, MCI_SPIN, dwFlags, (DWORD)spinParams);
1706 free(spinParams);
1707 return res;
1710 /* step single frames
1711 * "reverse" optional flag
1712 * "by <nr>" for <nr> frames
1714 static DWORD
1715 MCISTR_Step(_MCISTR_PROTO_) {
1716 union U {
1717 MCI_ANIM_STEP_PARMS animstepParams;
1718 MCI_VD_STEP_PARMS vdstepParams;
1720 union U *pU = xmalloc(sizeof(union U));
1721 int i,res;
1723 i=0;
1724 while (i < nrofkeywords) {
1725 switch (uDevTyp) {
1726 case MCI_DEVTYPE_ANIMATION:
1727 FLAG1("reverse",MCI_ANIM_STEP_REVERSE);
1728 if (!STRCMP(keywords[i],"by") && (i+1 < nrofkeywords)) {
1729 sscanf(keywords[i+1],"%ld",&(pU->animstepParams.dwFrames));
1730 dwFlags |= MCI_ANIM_STEP_FRAMES;
1731 i+=2;
1732 continue;
1734 break;
1735 case MCI_DEVTYPE_VIDEODISC:
1736 FLAG1("reverse",MCI_VD_STEP_REVERSE);
1737 if (!STRCMP(keywords[i],"by") && (i+1 < nrofkeywords)) {
1738 sscanf(keywords[i+1],"%ld",&(pU->vdstepParams.dwFrames));
1739 dwFlags |= MCI_VD_STEP_FRAMES;
1740 i+=2;
1741 continue;
1743 break;
1745 i++;
1747 res = mciSendCommand32A(wDevID, MCI_STEP, dwFlags, (DWORD)pU);
1748 free(pU);
1749 return res;
1752 /* update animation window
1753 * Arguments:
1754 * "at <left> <top> <right> <bottom>" only in this rectangle
1755 * "hdc" device context
1757 static DWORD
1758 MCISTR_Update(_MCISTR_PROTO_) {
1759 int i,res;
1760 MCI_ANIM_UPDATE_PARMS16 *updateParams = xmalloc(sizeof(MCI_ANIM_UPDATE_PARMS16));
1762 i=0;
1763 while (i<nrofkeywords) {
1764 if (!STRCMP(keywords[i],"at") && (i+4 < nrofkeywords)) {
1765 sscanf(keywords[i+1],"%hd",&(updateParams->rc.left));
1766 sscanf(keywords[i+2],"%hd",&(updateParams->rc.top));
1767 sscanf(keywords[i+3],"%hd",&(updateParams->rc.right));
1768 sscanf(keywords[i+4],"%hd",&(updateParams->rc.bottom));
1769 dwFlags |= MCI_ANIM_RECT;
1770 i+=5;
1771 continue;
1773 if (!STRCMP(keywords[i],"hdc") && (i+1 < nrofkeywords)) {
1774 dwFlags |= MCI_ANIM_UPDATE_HDC;
1775 sscanf(keywords[i+1],"%hd",&(updateParams->hDC));
1776 i+=2;
1777 continue;
1779 i++;
1781 res = mciSendCommand32A(wDevID, MCI_UPDATE, dwFlags, (DWORD)updateParams);
1782 free(updateParams);
1783 return res;
1786 /* where command for animation and overlay drivers.
1787 * just returns the specified rectangle as a string
1788 * Arguments:
1789 * "source"
1790 * "destination"
1791 * Overlay special:
1792 * "video"
1793 * "frame"
1795 static DWORD
1796 MCISTR_Where(_MCISTR_PROTO_) {
1797 union U {
1798 MCI_ANIM_RECT_PARMS16 animwhereParams;
1799 MCI_OVLY_RECT_PARMS16 ovlywhereParams;
1801 union U *pU = xmalloc(sizeof(union U));
1802 int i,res;
1804 i=0;
1805 while (i < nrofkeywords) {
1806 switch (uDevTyp) {
1807 case MCI_DEVTYPE_ANIMATION:
1808 FLAG1("source",MCI_ANIM_WHERE_SOURCE);
1809 FLAG1("destination",MCI_ANIM_WHERE_DESTINATION);
1810 break;
1811 case MCI_DEVTYPE_OVERLAY:
1812 FLAG1("source",MCI_OVLY_WHERE_SOURCE);
1813 FLAG1("destination",MCI_OVLY_WHERE_DESTINATION);
1814 FLAG1("video",MCI_OVLY_WHERE_VIDEO);
1815 FLAG1("frame",MCI_OVLY_WHERE_FRAME);
1816 break;
1818 i++;
1820 res = mciSendCommand32A(wDevID, MCI_WHERE, dwFlags, (DWORD)pU);
1821 if (res==0) {
1822 char buf[100];
1823 switch (uDevTyp) {
1824 case MCI_DEVTYPE_ANIMATION:
1825 sprintf(buf,"%d %d %d %d",
1826 pU->animwhereParams.rc.left,
1827 pU->animwhereParams.rc.top,
1828 pU->animwhereParams.rc.right,
1829 pU->animwhereParams.rc.bottom
1831 break;
1832 case MCI_DEVTYPE_OVERLAY:
1833 sprintf(buf,"%d %d %d %d",
1834 pU->ovlywhereParams.rc.left,
1835 pU->ovlywhereParams.rc.top,
1836 pU->ovlywhereParams.rc.right,
1837 pU->ovlywhereParams.rc.bottom
1839 break;
1840 default:strcpy(buf,"0 0 0 0");break;
1842 _MCI_STR(buf);
1844 free(pU);
1845 return res;
1848 static DWORD
1849 MCISTR_Window(_MCISTR_PROTO_) {
1850 int i,res;
1851 char *s;
1852 union U {
1853 MCI_ANIM_WINDOW_PARMS16 animwindowParams;
1854 MCI_OVLY_WINDOW_PARMS16 ovlywindowParams;
1856 union U *pU = xmalloc(sizeof(union U));
1858 s=NULL;
1859 i=0;
1860 while (i < nrofkeywords) {
1861 switch (uDevTyp) {
1862 case MCI_DEVTYPE_ANIMATION:
1863 if (!STRCMP(keywords[i],"handle") && (i+1 < nrofkeywords)) {
1864 dwFlags |= MCI_ANIM_WINDOW_HWND;
1865 if (!STRCMP(keywords[i+1],"default"))
1866 pU->animwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1867 else
1868 sscanf(keywords[i+1],"%hd",&(pU->animwindowParams.hWnd));
1869 i+=2;
1870 continue;
1872 if (!STRCMP(keywords[i],"state") && (i+1 < nrofkeywords)) {
1873 dwFlags |= MCI_ANIM_WINDOW_STATE;
1874 if (!STRCMP(keywords[i+1],"hide"))
1875 pU->animwindowParams.nCmdShow = SW_HIDE;
1876 if (!STRCMP(keywords[i+1],"iconic"))
1877 pU->animwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1878 if (!STRCMP(keywords[i+1],"minimized"))
1879 pU->animwindowParams.nCmdShow = SW_SHOWMINIMIZED;
1880 if (!STRCMP(keywords[i+1],"maximized"))
1881 pU->animwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1882 if (!STRCMP(keywords[i+1],"minimize"))
1883 pU->animwindowParams.nCmdShow = SW_MINIMIZE;
1884 if (!STRCMP(keywords[i+1],"normal"))
1885 pU->animwindowParams.nCmdShow = SW_NORMAL;
1886 if (!STRCMP(keywords[i+1],"show"))
1887 pU->animwindowParams.nCmdShow = SW_SHOW;
1888 if (!STRCMP(keywords[i+1],"no") && (i+2 < nrofkeywords)) {
1889 if (!STRCMP(keywords[i+2],"active"))
1890 pU->animwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1891 if (!STRCMP(keywords[i+2],"action"))
1892 pU->animwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1893 i++;
1895 i+=2;
1896 continue;
1898 /* text is enclosed in " ... " as it seems */
1899 if (!STRCMP(keywords[i],"text")) {
1900 char *t;
1901 int len,j,k;
1903 if (keywords[i+1][0]!='"') {
1904 i++;
1905 continue;
1907 dwFlags |= MCI_ANIM_WINDOW_TEXT;
1908 len = strlen(keywords[i+1])+1;
1909 j = i+2;
1910 while (j < nrofkeywords) {
1911 len += strlen(keywords[j])+1;
1912 if (strchr(keywords[j],'"'))
1913 break;
1914 j++;
1916 s=(char*)xmalloc(len);
1917 strcpy(s,keywords[i+1]+1);
1918 k=j;j=i+2;
1919 while (j <= k) {
1920 strcat(s," ");
1921 strcat(s,keywords[j]);
1923 if ((t=strchr(s,'"'))) *t='\0';
1924 /* FIXME: segmented pointer? */
1925 pU->animwindowParams.lpstrText = s;
1926 i=k+1;
1927 continue;
1929 FLAG1("stretch",MCI_ANIM_WINDOW_ENABLE_STRETCH);
1930 break;
1931 case MCI_DEVTYPE_OVERLAY:
1932 if (!STRCMP(keywords[i],"handle") && (i+1 < nrofkeywords)) {
1933 dwFlags |= MCI_OVLY_WINDOW_HWND;
1934 if (!STRCMP(keywords[i+1],"default"))
1935 pU->ovlywindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1936 else
1937 sscanf(keywords[i+1],"%hd",&(pU->ovlywindowParams.hWnd));
1938 i+=2;
1939 continue;
1941 if (!STRCMP(keywords[i],"state") && (i+1 < nrofkeywords)) {
1942 dwFlags |= MCI_OVLY_WINDOW_STATE;
1943 if (!STRCMP(keywords[i+1],"hide"))
1944 pU->ovlywindowParams.nCmdShow = SW_HIDE;
1945 if (!STRCMP(keywords[i+1],"iconic"))
1946 pU->ovlywindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1947 if (!STRCMP(keywords[i+1],"minimized"))
1948 pU->ovlywindowParams.nCmdShow = SW_SHOWMINIMIZED;
1949 if (!STRCMP(keywords[i+1],"maximized"))
1950 pU->ovlywindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1951 if (!STRCMP(keywords[i+1],"minimize"))
1952 pU->ovlywindowParams.nCmdShow = SW_MINIMIZE;
1953 if (!STRCMP(keywords[i+1],"normal"))
1954 pU->ovlywindowParams.nCmdShow = SW_NORMAL;
1955 if (!STRCMP(keywords[i+1],"show"))
1956 pU->ovlywindowParams.nCmdShow = SW_SHOW;
1957 if (!STRCMP(keywords[i+1],"no") && (i+2 < nrofkeywords)) {
1958 if (!STRCMP(keywords[i+2],"active"))
1959 pU->ovlywindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1960 if (!STRCMP(keywords[i+2],"action"))
1961 pU->ovlywindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1962 i++;
1964 i+=2;
1965 continue;
1967 /* text is enclosed in " ... " as it seems */
1968 if (!STRCMP(keywords[i],"text")) {
1969 char *t;
1970 int len,j,k;
1972 if (keywords[i+1][0]!='"') {
1973 i++;
1974 continue;
1976 dwFlags |= MCI_OVLY_WINDOW_TEXT;
1977 len = strlen(keywords[i+1])+1;
1978 j = i+2;
1979 while (j < nrofkeywords) {
1980 len += strlen(keywords[j])+1;
1981 if (strchr(keywords[j],'"'))
1982 break;
1983 j++;
1985 s=(char*)xmalloc(len);
1986 strcpy(s,keywords[i+1]+1);
1987 k=j;j=i+2;
1988 while (j<=k) {
1989 strcat(s," ");
1990 strcat(s,keywords[j]);
1992 if ((t=strchr(s,'"'))) *t='\0';
1993 /* FIXME: segmented pointer? */
1994 pU->ovlywindowParams.lpstrText = s;
1995 i=k+1;
1996 continue;
1998 FLAG1("stretch",MCI_OVLY_WINDOW_ENABLE_STRETCH);
1999 break;
2001 i++;
2003 res = mciSendCommand32A(wDevID, MCI_WINDOW, dwFlags, (DWORD)pU);
2004 if (s) free(s);
2005 free(pU);
2006 return res;
2009 struct _MCISTR_cmdtable {
2010 char *cmd;
2011 DWORD (*fun)(_MCISTR_PROTO_);
2012 } MCISTR_cmdtable[]={
2013 {"break", MCISTR_Break},
2014 {"capability", MCISTR_Capability},
2015 {"close", MCISTR_Close},
2016 {"cue", MCISTR_Cue},
2017 {"delete", MCISTR_Delete},
2018 {"escape", MCISTR_Escape},
2019 {"freeze", MCISTR_Freeze},
2020 {"info", MCISTR_Info},
2021 {"load", MCISTR_Load},
2022 {"open", MCISTR_Open},
2023 {"pause", MCISTR_Pause},
2024 {"play", MCISTR_Play},
2025 {"put", MCISTR_Put},
2026 {"realize", MCISTR_Realize},
2027 {"record", MCISTR_Record},
2028 {"resume", MCISTR_Resume},
2029 {"save", MCISTR_Save},
2030 {"seek", MCISTR_Seek},
2031 {"set", MCISTR_Set},
2032 {"spin", MCISTR_Spin},
2033 {"status", MCISTR_Status},
2034 {"step", MCISTR_Step},
2035 {"stop", MCISTR_Stop},
2036 {"sysinfo", MCISTR_Sysinfo},
2037 {"unfreeze", MCISTR_Unfreeze},
2038 {"update", MCISTR_Update},
2039 {"where", MCISTR_Where},
2040 {"window", MCISTR_Window},
2041 {NULL, NULL}
2044 /**************************************************************************
2045 * mciSendString16 [MMSYSTEM.702]
2047 /* The usercode sends a string with a command (and flags) expressed in
2048 * words in it... We do our best to call aprobiate drivers,
2049 * and return a errorcode AND a readable string (if lpstrRS!=NULL)
2050 * Info gathered by watching cool134.exe and from Borland's mcistrwh.hlp
2052 /* FIXME: "all" is a valid devicetype and we should access all devices if
2053 * it is used. (imagine "close all"). Not implemented yet.
2055 DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2056 UINT16 uReturnLength, HWND16 hwndCallback)
2058 char *cmd,*dev,*args,**keywords,*filename;
2059 WORD uDevTyp=0,wDevID=0;
2060 DWORD dwFlags;
2061 int res=0,i,nrofkeywords;
2063 TRACE(mci,"('%s', %p, %d, %X)\n",
2064 lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2066 /* format is <command> <device> <optargs> */
2067 cmd=strdup(lpstrCommand);
2068 dev=strchr(cmd,' ');
2069 if (dev==NULL) {
2070 free(cmd);
2071 return MCIERR_MISSING_DEVICE_NAME;
2073 *dev++='\0';
2074 args=strchr(dev,' ');
2075 if (args!=NULL) *args++='\0';
2076 CharUpper32A(dev);
2077 if (args!=NULL) {
2078 char *s;
2079 i=1;/* nrofkeywords = nrofspaces+1 */
2080 s=args;
2081 while ((s=strchr(s,' '))!=NULL) i++,s++;
2082 keywords=(char**)xmalloc(sizeof(char*)*(i+2));
2083 nrofkeywords=i;
2084 s=args;i=0;
2085 while (s && i < nrofkeywords) {
2086 keywords[i++]=s;
2087 s=strchr(s,' ');
2088 if (s) *s++='\0';
2090 keywords[i]=NULL;
2091 } else {
2092 nrofkeywords=0;
2093 keywords=(char**)xmalloc(sizeof(char*));
2095 dwFlags = 0; /* default flags */
2096 for (i=0;i < nrofkeywords;) {
2097 /* take care, there is also a "device type" capability */
2098 if ((!STRCMP(keywords[i],"type")) && (i < nrofkeywords-1)) {
2099 filename = dev;
2100 dev = keywords[i+1];
2101 memcpy(keywords+i,keywords+(i+2),(nrofkeywords-i-2)*sizeof(char *));
2102 nrofkeywords -= 2;
2103 continue;
2105 if (!STRCMP(keywords[i],"wait")) {
2106 dwFlags |= MCI_WAIT;
2107 memcpy(keywords+i,keywords+(i+1),(nrofkeywords-i-1)*sizeof(char *));
2108 nrofkeywords--;
2109 continue;
2111 if (!STRCMP(keywords[i],"notify")) {
2112 dwFlags |= MCI_NOTIFY;
2113 memcpy(keywords+i,keywords+(i+1),(nrofkeywords-i-1)*sizeof(char *));
2114 nrofkeywords--;
2115 continue;
2117 i++;
2120 /* FIXME: this code should be moved to mmsystem.c */
2121 /* determine wDevID and uDevTyp for all commands except "open" */
2122 if (STRCMP(cmd,"open")!=0) {
2123 wDevID = MCI_FirstDevID();
2124 while (1) {
2125 LPSTR dname;
2127 dname=MCI_GetOpenDrv(wDevID)->lpstrAlias;
2128 if (dname==NULL)
2129 dname=MCI_GetOpenDrv(wDevID)->lpstrDeviceType;
2130 if (dname != NULL && !STRCMP(dname,dev))
2131 break;
2132 wDevID = MCI_NextDevID(wDevID);
2133 if (!MCI_DevIDValid(wDevID)) {
2134 TRACE(mci, "MAXMCIDRIVERS reached!\n");
2135 free(keywords);free(cmd);
2136 return MCIERR_INVALID_DEVICE_NAME;
2139 uDevTyp=MCI_GetDrv(wDevID)->modp.wType;
2141 /* end of FIXME */
2143 for (i=0;MCISTR_cmdtable[i].cmd!=NULL;i++) {
2144 if (!STRCMP(MCISTR_cmdtable[i].cmd,cmd)) {
2145 res=MCISTR_cmdtable[i].fun(
2146 wDevID,uDevTyp,lpstrReturnString,
2147 uReturnLength,dev,(LPSTR*)keywords,nrofkeywords,
2148 dwFlags,hwndCallback
2150 break;
2153 if (MCISTR_cmdtable[i].cmd!=NULL) {
2154 free(keywords);free(cmd);
2155 return res;
2157 FIXME(mci,"('%s', %p, %u, %X): unimplemented, please report.\n",
2158 lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2159 free(keywords);free(cmd);
2160 return MCIERR_MISSING_COMMAND_STRING;
2163 /**************************************************************************
2164 * mciSendString32A [MMSYSTEM.702][WINMM.51]
2166 DWORD WINAPI mciSendString32A(LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2167 UINT32 uReturnLength, HWND32 hwndCallback)
2169 return mciSendString16(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2172 /**************************************************************************
2173 * mciSendString32W [WINMM.52]
2175 DWORD WINAPI mciSendString32W(LPCWSTR lpwstrCommand, LPSTR lpstrReturnString,
2176 UINT32 uReturnLength, HWND32 hwndCallback)
2178 LPSTR lpstrCommand;
2179 UINT32 ret;
2181 /* FIXME: is there something to do with lpstrReturnString ? */
2182 lpstrCommand = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrCommand);
2183 ret = mciSendString16(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2184 HeapFree(GetProcessHeap(), 0, lpstrCommand);
2185 return ret;