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