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