Release 970525
[wine/multimedia.git] / multimedia / mcistring.c
blob429f2b23658345fa59987913fb94374ab15ec0ac
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 #include <unistd.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <fcntl.h>
14 #include <sys/ioctl.h>
15 #include "windows.h"
16 #include "heap.h"
17 #include "ldt.h"
18 #include "user.h"
19 #include "driver.h"
20 #include "mmsystem.h"
21 #include "stddebug.h"
22 #include "debug.h"
23 #include "xmalloc.h"
26 extern MCI_OPEN_DRIVER_PARMS mciDrv[MAXMCIDRIVERS];
28 /* FIXME: I need to remember the aliasname of a spec. driver.
29 * and this is the easiest way. *sigh*
31 extern MCI_OPEN_PARMS mciOpenDrv[MAXMCIDRIVERS];
33 #define GetDrv(wDevID) (&mciDrv[MMSYSTEM_DevIDToIndex(wDevID)])
34 #define GetOpenDrv(wDevID) (&mciOpenDrv[MMSYSTEM_DevIDToIndex(wDevID)])
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 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
62 /* copy string to return pointer including necessary checks
63 * for use in mciSendString()
65 #define _MCI_STR(s) do {\
66 dprintf_mci(stddeb,"->returns \"%s\"",s);\
67 if (lpstrReturnString) {\
68 lstrcpyn32A(lpstrReturnString,s,uReturnLength);\
69 dprintf_mci(stddeb,"-->\"%s\"\n",lpstrReturnString);\
71 } while(0)
73 /* calling DriverProc. We need to pass the struct as SEGMENTED POINTER. */
74 #define _MCI_CALL_DRIVER(cmd,params) \
75 switch(uDevTyp) {\
76 case MCI_DEVTYPE_CD_AUDIO:\
77 res=CDAUDIO_DriverProc(GetDrv(wDevID)->wDeviceID,0,cmd,dwFlags, (DWORD)(params));\
78 break;\
79 case MCI_DEVTYPE_WAVEFORM_AUDIO:\
80 res=WAVE_DriverProc(GetDrv(wDevID)->wDeviceID,0,cmd,dwFlags,(DWORD)(params));\
81 break;\
82 case MCI_DEVTYPE_SEQUENCER:\
83 res=MIDI_DriverProc(GetDrv(wDevID)->wDeviceID,0,cmd,dwFlags,(DWORD)(params));\
84 break;\
85 case MCI_DEVTYPE_ANIMATION:\
86 res=ANIM_DriverProc(GetDrv(wDevID)->wDeviceID,0,cmd,dwFlags,(DWORD)(params));\
87 break;\
88 case MCI_DEVTYPE_DIGITAL_VIDEO:\
89 dprintf_mci(stddeb,"_MCI_CALL_DRIVER //No DIGITAL_VIDEO yet !\n");\
90 res=MCIERR_DEVICE_NOT_INSTALLED;\
91 break;\
92 default:\
93 dprintf_mci(stddeb,"_MCI_CALL_DRIVER //Invalid Device Name '%s' !\n",dev);\
94 res=MCIERR_INVALID_DEVICE_NAME;\
95 break;\
97 /* print a DWORD in the specified timeformat */
98 static void
99 _MCISTR_printtf(char *buf,UINT16 uDevType,DWORD timef,DWORD val) {
100 *buf='\0';
101 switch (timef) {
102 case MCI_FORMAT_MILLISECONDS:
103 case MCI_FORMAT_FRAMES:
104 case MCI_FORMAT_BYTES:
105 case MCI_FORMAT_SAMPLES:
106 case MCI_VD_FORMAT_TRACK:
107 /*case MCI_SEQ_FORMAT_SONGPTR: sameas MCI_VD_FORMAT_TRACK */
108 sprintf(buf,"%ld",val);
109 break;
110 case MCI_FORMAT_HMS:
111 /* well, the macros have the same content*/
112 /*FALLTRHOUGH*/
113 case MCI_FORMAT_MSF:
114 sprintf(buf,"%d:%d:%d",
115 MCI_HMS_HOUR(val),
116 MCI_HMS_MINUTE(val),
117 MCI_HMS_SECOND(val)
119 break;
120 case MCI_FORMAT_TMSF:
121 sprintf(buf,"%d:%d:%d:%d",
122 MCI_TMSF_TRACK(val),
123 MCI_TMSF_MINUTE(val),
124 MCI_TMSF_SECOND(val),
125 MCI_TMSF_FRAME(val)
127 break;
128 default:
129 fprintf(stdnimp,__FILE__":MCISTR_Status:missing timeformat for %ld, report.\n",timef);
130 strcpy(buf,"0"); /* hmm */
131 break;
133 return;
135 /* possible different return types */
136 #define _MCISTR_int 1
137 #define _MCISTR_time 2
138 #define _MCISTR_bool 3
139 #define _MCISTR_tfname 4
140 #define _MCISTR_mode 5
141 #define _MCISTR_divtype 6
142 #define _MCISTR_seqtype 7
143 #define _MCISTR_vdmtype 8
144 #define _MCISTR_devtype 9
146 static void
147 _MCISTR_convreturn(int type,DWORD dwReturn,LPSTR lpstrReturnString,
148 WORD uReturnLength,WORD uDevTyp,int timef
150 switch (type) {
151 case _MCISTR_vdmtype:
152 switch (dwReturn) {
153 case MCI_VD_MEDIA_CLV:_MCI_STR("CLV");break;
154 case MCI_VD_MEDIA_CAV:_MCI_STR("CAV");break;
155 default:
156 case MCI_VD_MEDIA_OTHER:_MCI_STR("other");break;
158 break;
159 case _MCISTR_seqtype:
160 switch (dwReturn) {
161 case MCI_SEQ_NONE:_MCI_STR("none");break;
162 case MCI_SEQ_SMPTE:_MCI_STR("smpte");break;
163 case MCI_SEQ_FILE:_MCI_STR("file");break;
164 case MCI_SEQ_MIDI:_MCI_STR("midi");break;
165 default:fprintf(stdnimp,__FILE__":MCISTR_Status:missing sequencer mode %ld\n",dwReturn);
167 break;
168 case _MCISTR_mode:
169 switch (dwReturn) {
170 case MCI_MODE_NOT_READY:_MCI_STR("not ready");break;
171 case MCI_MODE_STOP:_MCI_STR("stopped");break;
172 case MCI_MODE_PLAY:_MCI_STR("playing");break;
173 case MCI_MODE_RECORD:_MCI_STR("recording");break;
174 case MCI_MODE_SEEK:_MCI_STR("seeking");break;
175 case MCI_MODE_PAUSE:_MCI_STR("paused");break;
176 case MCI_MODE_OPEN:_MCI_STR("open");break;
177 default:break;
179 break;
180 case _MCISTR_bool:
181 if (dwReturn)
182 _MCI_STR("true");
183 else
184 _MCI_STR("false");
185 break;
186 case _MCISTR_int:{
187 char buf[16];
188 sprintf(buf,"%ld",dwReturn);
189 _MCI_STR(buf);
190 break;
192 case _MCISTR_time: {
193 char buf[100];
194 _MCISTR_printtf(buf,uDevTyp,timef,dwReturn);
195 _MCI_STR(buf);
196 break;
198 case _MCISTR_tfname:
199 switch (timef) {
200 case MCI_FORMAT_MILLISECONDS:_MCI_STR("milliseconds");break;
201 case MCI_FORMAT_FRAMES:_MCI_STR("frames");break;
202 case MCI_FORMAT_BYTES:_MCI_STR("bytes");break;
203 case MCI_FORMAT_SAMPLES:_MCI_STR("samples");break;
204 case MCI_FORMAT_HMS:_MCI_STR("hms");break;
205 case MCI_FORMAT_MSF:_MCI_STR("msf");break;
206 case MCI_FORMAT_TMSF:_MCI_STR("tmsf");break;
207 default:
208 fprintf(stdnimp,__FILE__":MCISTR_Status:missing timeformat for %d, report.\n",timef);
209 break;
211 break;
212 case _MCISTR_divtype:
213 switch (dwReturn) {
214 case MCI_SEQ_DIV_PPQN:_MCI_STR("PPQN");break;
215 case MCI_SEQ_DIV_SMPTE_24:_MCI_STR("SMPTE 24 frame");break;
216 case MCI_SEQ_DIV_SMPTE_25:_MCI_STR("SMPTE 25 frame");break;
217 case MCI_SEQ_DIV_SMPTE_30:_MCI_STR("SMPTE 30 frame");break;
218 case MCI_SEQ_DIV_SMPTE_30DROP:_MCI_STR("SMPTE 30 frame drop");break;
220 case _MCISTR_devtype:
221 switch (dwReturn) {
222 case MCI_DEVTYPE_VCR:_MCI_STR("vcr");break;
223 case MCI_DEVTYPE_VIDEODISC:_MCI_STR("videodisc");break;
224 case MCI_DEVTYPE_CD_AUDIO:_MCI_STR("cd audio");break;
225 case MCI_DEVTYPE_OVERLAY:_MCI_STR("overlay");break;
226 case MCI_DEVTYPE_DAT:_MCI_STR("dat");break;
227 case MCI_DEVTYPE_SCANNER:_MCI_STR("scanner");break;
228 case MCI_DEVTYPE_ANIMATION:_MCI_STR("animation");break;
229 case MCI_DEVTYPE_DIGITAL_VIDEO:_MCI_STR("digital video");break;
230 case MCI_DEVTYPE_OTHER:_MCI_STR("other");break;
231 case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio");break;
232 case MCI_DEVTYPE_SEQUENCER:_MCI_STR("sequencer");break;
233 default:fprintf(stdnimp,__FILE__":_MCISTR_convreturn:unknown device type %ld, report.\n",dwReturn);break;
235 break;
236 default:
237 fprintf(stdnimp,__FILE__":_MCISTR_convreturn:unknown resulttype %d, report.\n",type);
238 break;
242 #define FLAG1(str,flag) \
243 if (!STRCMP(keywords[i],str)) {\
244 dwFlags |= flag;\
245 i++;\
246 continue;\
248 #define FLAG2(str1,str2,flag) \
249 if (!STRCMP(keywords[i],str1) && (i+1<nrofkeywords) && !STRCMP(keywords[i+1],str2)) {\
250 dwFlags |= flag;\
251 i+=2;\
252 continue;\
255 /* All known subcommands are implemented in single functions to avoid
256 * bloat and a xxxx lines long mciSendString(). All commands are of the
257 * format MCISTR_Cmd(_MCISTR_PROTO_) where _MCISTR_PROTO_ is the above
258 * defined line of arguments. (This is just for easy enhanceability.)
259 * All functions return the MCIERR_ errorvalue as DWORD. Returnvalues
260 * for the calls are in lpstrReturnString (If I mention return values
261 * in function headers, I mean returnvalues in lpstrReturnString.)
262 * Integers are sprintf("%d")ed integers. Boolean values are
263 * "true" and "false".
264 * timeformat depending values are "%d" "%d:%d" "%d:%d:%d" "%d:%d:%d:%d"
265 * FIXME: is above line correct?
267 * Preceding every function is a list of implemented/known arguments.
268 * Feel free to add missing arguments.
273 * Opens the specified MCI driver.
274 * Arguments: <name>
275 * Optional:
276 * "shareable"
277 * "alias <aliasname>"
278 * "element <elementname>"
279 * Additional:
280 * waveform audio:
281 * "buffer <nrBytesPerSec>"
282 * Animation:
283 * "nostatic" increaste nr of nonstatic colours
284 * "parent <windowhandle>"
285 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
286 * "style child" WS_CHILD
287 * "style overlap" WS_OVERLAPPED
288 * "style popup" WS_POPUP
289 * Overlay:
290 * "parent <windowhandle>"
291 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
292 * "style child" WS_CHILD
293 * "style overlap" WS_OVERLAPPED
294 * "style popup" WS_POPUP
295 * Returns nothing.
297 static DWORD
298 MCISTR_Open(_MCISTR_PROTO_) {
299 int res,i;
300 char *s;
301 union U {
302 MCI_OPEN_PARMS openParams;
303 MCI_WAVE_OPEN_PARMS waveopenParams;
304 MCI_ANIM_OPEN_PARMS animopenParams;
305 MCI_OVLY_OPEN_PARMS ovlyopenParams;
307 union U *pU = SEGPTR_NEW(union U);
309 pU->openParams.lpstrElementName = NULL;
310 s=strchr(dev,'!');
311 if (s!=NULL) {
312 *s++='\0';
313 pU->openParams.lpstrElementName=SEGPTR_GET(SEGPTR_STRDUP(s));
314 dwFlags |= MCI_OPEN_ELEMENT;
316 if (!STRCMP(dev,"cdaudio")) {
317 uDevTyp=MCI_DEVTYPE_CD_AUDIO;
318 } else if (!STRCMP(dev,"waveaudio")) {
319 uDevTyp=MCI_DEVTYPE_WAVEFORM_AUDIO;
320 } else if (!STRCMP(dev,"sequencer")) {
321 uDevTyp=MCI_DEVTYPE_SEQUENCER;
322 } else if (!STRCMP(dev,"animation1")) {
323 uDevTyp=MCI_DEVTYPE_ANIMATION;
324 } else if (!STRCMP(dev,"avivideo")) {
325 uDevTyp=MCI_DEVTYPE_DIGITAL_VIDEO;
326 } else {
327 SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrElementName));
328 SEGPTR_FREE(pU);
329 return MCIERR_INVALID_DEVICE_NAME;
331 wDevID=MMSYSTEM_FirstDevID();
332 while(GetDrv(wDevID)->wType) {
333 wDevID = MMSYSTEM_NextDevID(wDevID);
334 if (!MMSYSTEM_DevIDValid(wDevID)) {
335 dprintf_mci(stddeb, __FILE__":MCISTR_Open:MAXMCIDRIVERS reached!\n");
336 SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrElementName));
337 SEGPTR_FREE(pU);
338 return MCIERR_INTERNAL;
341 GetDrv(wDevID)->wType = uDevTyp;
342 GetDrv(wDevID)->wDeviceID = 0; /* FIXME? for multiple devices */
343 pU->openParams.dwCallback = 0;
344 pU->openParams.wDeviceID = wDevID;
345 pU->ovlyopenParams.dwStyle = 0;
346 pU->animopenParams.dwStyle = 0;
347 pU->openParams.lpstrDeviceType = SEGPTR_GET(SEGPTR_STRDUP(dev));
348 pU->openParams.lpstrAlias = NULL;
349 dwFlags |= MCI_OPEN_TYPE;
350 i=0;
351 while (i<nrofkeywords) {
352 FLAG1("shareable",MCI_OPEN_SHAREABLE);
353 if (!strcmp(keywords[i],"alias") && (i+1<nrofkeywords)) {
354 dwFlags |= MCI_OPEN_ALIAS;
355 pU->openParams.lpstrAlias=SEGPTR_GET(SEGPTR_STRDUP(keywords[i+1]));
356 i+=2;
357 continue;
359 if (!strcmp(keywords[i],"element") && (i+1<nrofkeywords)) {
360 dwFlags |= MCI_OPEN_ELEMENT;
361 pU->openParams.lpstrElementName=SEGPTR_GET(SEGPTR_STRDUP(keywords[i+1]));
362 i+=2;
363 continue;
365 switch (uDevTyp) {
366 case MCI_DEVTYPE_ANIMATION:
367 case MCI_DEVTYPE_DIGITAL_VIDEO:
368 FLAG1("nostatic",MCI_ANIM_OPEN_NOSTATIC);
369 if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
370 dwFlags |= MCI_ANIM_OPEN_PARENT;
371 sscanf(keywords[i+1],"%hu",&(pU->animopenParams.hWndParent));
372 i+=2;
373 continue;
375 if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
376 DWORD st;
378 dwFlags |= MCI_ANIM_OPEN_WS;
379 if (!STRCMP(keywords[i+1],"popup")) {
380 pU->animopenParams.dwStyle |= WS_POPUP;
381 } else if (!STRCMP(keywords[i+1],"overlap")) {
382 pU->animopenParams.dwStyle |= WS_OVERLAPPED;
383 } else if (!STRCMP(keywords[i+1],"child")) {
384 pU->animopenParams.dwStyle |= WS_CHILD;
385 } else if (sscanf(keywords[i+1],"%ld",&st)) {
386 pU->animopenParams.dwStyle |= st;
387 } else
388 fprintf(stdnimp,__FILE__":MCISTR_Open:unknown 'style' keyword %s, please report.\n",keywords[i+1]);
389 i+=2;
390 continue;
392 break;
393 case MCI_DEVTYPE_WAVEFORM_AUDIO:
394 if (!STRCMP(keywords[i],"buffer") && (i+1<nrofkeywords)) {
395 dwFlags |= MCI_WAVE_OPEN_BUFFER;
396 sscanf(keywords[i+1],"%ld",&(pU->waveopenParams.dwBufferSeconds));
398 break;
399 case MCI_DEVTYPE_OVERLAY:
400 /* looks just like anim, but without NOSTATIC */
401 if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
402 dwFlags |= MCI_OVLY_OPEN_PARENT;
403 sscanf(keywords[i+1],"%hd",&(pU->ovlyopenParams.hWndParent));
404 i+=2;
405 continue;
407 if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
408 DWORD st;
410 dwFlags |= MCI_OVLY_OPEN_WS;
411 if (!STRCMP(keywords[i+1],"popup")) {
412 pU->ovlyopenParams.dwStyle |= WS_POPUP;
413 } else if (!STRCMP(keywords[i+1],"overlap")) {
414 pU->ovlyopenParams.dwStyle |= WS_OVERLAPPED;
415 } else if (!STRCMP(keywords[i+1],"child")) {
416 pU->ovlyopenParams.dwStyle |= WS_CHILD;
417 } else if (sscanf(keywords[i+1],"%ld",&st)) {
418 pU->ovlyopenParams.dwStyle |= st;
419 } else
420 fprintf(stdnimp,__FILE__":MCISTR_Open:unknown 'style' keyword %s, please report.\n",keywords[i+1]);
421 i+=2;
422 continue;
424 break;
426 fprintf(stdnimp,__FILE__":MCISTR_Open:unknown parameter passed %s, please report.\n",keywords[i]);
427 i++;
429 _MCI_CALL_DRIVER( MCI_OPEN, SEGPTR_GET(pU) );
430 if (res==0)
431 memcpy(GetOpenDrv(wDevID),&pU->openParams,sizeof(MCI_OPEN_PARMS));
432 else {
433 SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrElementName));
434 SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrDeviceType));
435 SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrAlias));
437 SEGPTR_FREE(pU);
438 return res;
441 /* A help function for a lot of others ...
442 * for instance status/play/record/seek etc.
444 DWORD
445 _MCISTR_determine_timeformat(LPCSTR dev,WORD wDevID,WORD uDevTyp,int *timef)
447 int res;
448 DWORD dwFlags = MCI_STATUS_ITEM;
449 MCI_STATUS_PARMS *statusParams = SEGPTR_NEW(MCI_STATUS_PARMS);
451 if (!statusParams) return 0;
452 statusParams->dwItem = MCI_STATUS_TIME_FORMAT;
453 statusParams->dwReturn = 0;
454 _MCI_CALL_DRIVER( MCI_STATUS, SEGPTR_GET(statusParams) );
455 if (res==0) *timef = statusParams->dwReturn;
456 SEGPTR_FREE(statusParams);
457 return res;
460 /* query status of MCI drivers
461 * Arguments:
462 * Required:
463 * "mode" - returns "not ready" "paused" "playing" "stopped" "open"
464 * "parked" "recording" "seeking" ....
465 * Basics:
466 * "current track" - returns current track as integer
467 * "length [track <nr>]" - returns length [of track <nr>] in current
468 * timeformat
469 * "number of tracks" - returns number of tracks as integer
470 * "position [track <nr>]" - returns position [in track <nr>] in current
471 * timeformat
472 * "ready" - checks if device is ready to play, -> bool
473 * "start position" - returns start position in timeformat
474 * "time format" - returns timeformat (list of possible values:
475 * "ms" "msf" "milliseconds" "hmsf" "tmsf" "frames"
476 * "bytes" "samples" "hms")
477 * "media present" - returns if media is present as bool
478 * Animation:
479 * "forward" - returns "true" if device is playing forwards
480 * "speed" - returns speed for device
481 * "palette handle" - returns palette handle
482 * "window handle" - returns window handle
483 * "stretch" - returns stretch bool
484 * MIDI sequencer:
485 * "division type" - ? returns "PPQN" "SMPTE 24 frame"
486 * "SMPTE 25 frame" "SMPTE 30 frame" "SMPTE 30 drop frame"
487 * "tempo" - current tempo in (PPQN? speed in frames, SMPTE*? speed in hsmf)
488 * "offset" - offset in dito.
489 * "port" - midi port as integer
490 * "slave" - slave device ("midi","file","none","smpte")
491 * "master" - masterdevice (dito.)
492 * Overlay:
493 * "window handle" - see animation
494 * "stretch" - dito
495 * Video Disc:
496 * "speed" - speed as integer
497 * "forward" - returns bool (when playing forward)
498 * "side" - returns 1 or 2
499 * "media type" - returns "CAV" "CLV" "other"
500 * "disc size" - returns "8" or "12"
501 * WAVEFORM audio:
502 * "input" - base queries on input set
503 * "output" - base queries on output set
504 * "format tag" - return integer format tag
505 * "channels" - return integer nr of channels
506 * "bytespersec" - return average nr of bytes/sec
507 * "samplespersec" - return nr of samples per sec
508 * "bitspersample" - return bitspersample
509 * "alignment" - return block alignment
510 * "level" - return level?
513 #define ITEM1(str,item,xtype) \
514 if (!STRCMP(keywords[i],str)) {\
515 statusParams->dwItem = item;\
516 type = xtype;\
517 i++;\
518 continue;\
520 #define ITEM2(str1,str2,item,xtype) \
521 if ( !STRCMP(keywords[i],str1) &&\
522 (i+1<nrofkeywords) &&\
523 !STRCMP(keywords[i+1],str2)\
524 ) {\
525 statusParams->dwItem = item;\
526 type = xtype;\
527 i+=2;\
528 continue;\
530 #define ITEM3(str1,str2,str3,item,xtype) \
531 if ( !STRCMP(keywords[i],str1) &&\
532 (i+2<nrofkeywords) &&\
533 !STRCMP(keywords[i+1],str2) &&\
534 !STRCMP(keywords[i+2],str3)\
535 ) {\
536 statusParams->dwItem = item;\
537 type = xtype;\
538 i+=3;\
539 continue;\
541 static DWORD
542 MCISTR_Status(_MCISTR_PROTO_) {
543 MCI_STATUS_PARMS *statusParams = SEGPTR_NEW(MCI_STATUS_PARMS);
544 int type = 0,i,res,timef;
546 statusParams->dwCallback = 0;
547 dwFlags |= MCI_STATUS_ITEM;
548 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
549 if (res) return res;
551 statusParams->dwReturn = 0;
552 statusParams->dwItem = 0;
553 i = 0;
555 while (i<nrofkeywords) {
556 if (!STRCMP(keywords[i],"track") && (i+1<nrofkeywords)) {
557 sscanf(keywords[i+1],"%ld",&(statusParams->dwTrack));
558 dwFlags |= MCI_TRACK;
559 i+=2;
560 continue;
562 FLAG1("start",MCI_STATUS_START);
563 /* generic things */
564 ITEM2("current","track",MCI_STATUS_CURRENT_TRACK,_MCISTR_time);
565 ITEM2("time","format",MCI_STATUS_TIME_FORMAT,_MCISTR_tfname);
566 ITEM1("ready",MCI_STATUS_READY,_MCISTR_bool);
567 ITEM1("mode",MCI_STATUS_MODE,_MCISTR_mode);
568 ITEM3("number","of","tracks",MCI_STATUS_NUMBER_OF_TRACKS,_MCISTR_int);
569 ITEM1("length",MCI_STATUS_LENGTH,_MCISTR_time);
570 ITEM1("position",MCI_STATUS_POSITION,_MCISTR_time);
571 ITEM2("media","present",MCI_STATUS_MEDIA_PRESENT,_MCISTR_bool);
573 switch (uDevTyp) {
574 case MCI_DEVTYPE_ANIMATION:
575 case MCI_DEVTYPE_DIGITAL_VIDEO:
576 ITEM2("palette","handle",MCI_ANIM_STATUS_HPAL,_MCISTR_int);
577 ITEM2("window","handle",MCI_ANIM_STATUS_HWND,_MCISTR_int);
578 ITEM1("stretch",MCI_ANIM_STATUS_STRETCH,_MCISTR_bool);
579 ITEM1("speed",MCI_ANIM_STATUS_SPEED,_MCISTR_int);
580 ITEM1("forward",MCI_ANIM_STATUS_FORWARD,_MCISTR_bool);
581 break;
582 case MCI_DEVTYPE_SEQUENCER:
583 /* just completing the list, not working correctly */
584 ITEM2("division","type",MCI_SEQ_STATUS_DIVTYPE,_MCISTR_divtype);
585 /* tempo ... PPQN in frames/second, SMPTE in hmsf */
586 ITEM1("tempo",MCI_SEQ_STATUS_TEMPO,_MCISTR_int);
587 ITEM1("port",MCI_SEQ_STATUS_PORT,_MCISTR_int);
588 ITEM1("slave",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
589 ITEM1("master",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
590 /* offset ... PPQN in frames/second, SMPTE in hmsf */
591 ITEM1("offset",MCI_SEQ_STATUS_SLAVE,_MCISTR_time);
592 break;
593 case MCI_DEVTYPE_OVERLAY:
594 ITEM2("window","handle",MCI_OVLY_STATUS_HWND,_MCISTR_int);
595 ITEM1("stretch",MCI_OVLY_STATUS_STRETCH,_MCISTR_bool);
596 break;
597 case MCI_DEVTYPE_VIDEODISC:
598 ITEM1("speed",MCI_VD_STATUS_SPEED,_MCISTR_int);
599 ITEM1("forward",MCI_VD_STATUS_FORWARD,_MCISTR_bool);
600 ITEM1("side",MCI_VD_STATUS_SIDE,_MCISTR_int);
601 ITEM2("media","type",MCI_VD_STATUS_SIDE,_MCISTR_vdmtype);
602 /* returns 8 or 12 */
603 ITEM2("disc","size",MCI_VD_STATUS_DISC_SIZE,_MCISTR_int);
604 break;
605 case MCI_DEVTYPE_WAVEFORM_AUDIO:
606 /* I am not quite sure if foll. 2 lines are right. */
607 FLAG1("input",MCI_WAVE_INPUT);
608 FLAG1("output",MCI_WAVE_OUTPUT);
610 ITEM2("format","tag",MCI_WAVE_STATUS_FORMATTAG,_MCISTR_int);
611 ITEM1("channels",MCI_WAVE_STATUS_CHANNELS,_MCISTR_int);
612 ITEM1("bytespersec",MCI_WAVE_STATUS_AVGBYTESPERSEC,_MCISTR_int);
613 ITEM1("samplespersec",MCI_WAVE_STATUS_SAMPLESPERSEC,_MCISTR_int);
614 ITEM1("bitspersample",MCI_WAVE_STATUS_BITSPERSAMPLE,_MCISTR_int);
615 ITEM1("alignment",MCI_WAVE_STATUS_BLOCKALIGN,_MCISTR_int);
616 ITEM1("level",MCI_WAVE_STATUS_LEVEL,_MCISTR_int);
617 break;
619 fprintf(stdnimp,__FILE__":MCISTR_Status:unknown keyword '%s'\n",keywords[i]);
620 i++;
622 if (!statusParams->dwItem)
623 return MCIERR_MISSING_STRING_ARGUMENT;
625 _MCI_CALL_DRIVER( MCI_STATUS, SEGPTR_GET(statusParams) );
626 if (res==0)
627 _MCISTR_convreturn(type,statusParams->dwReturn,lpstrReturnString,uReturnLength,uDevTyp,timef);
628 SEGPTR_FREE(statusParams);
629 return res;
631 #undef ITEM1
632 #undef ITEM2
633 #undef ITEM3
635 /* set specified parameters in respective MCI drivers
636 * Arguments:
637 * "door open" eject media or somesuch
638 * "door close" load media
639 * "time format <timeformatname>" "ms" "milliseconds" "msf" "hmsf"
640 * "tmsf" "SMPTE 24" "SMPTE 25" "SMPTE 30"
641 * "SMPTE drop 30"
642 * "audio [all|left|right] [on|off]" sets specified audiochannel on or off
643 * "video [on|off]" sets video on/off
644 * Waveform audio:
645 * "formattag pcm" sets format to pcm
646 * "formattag <nr>" sets integer formattag value
647 * "any input" accept input from any known source
648 * "any output" output to any known destination
649 * "input <nr>" input from source <nr>
650 * "output <nr>" output to destination <nr>
651 * "channels <nr>" sets nr of channels
652 * "bytespersec <nr>" sets average bytes per second
653 * "samplespersec <nr>" sets average samples per second (1 sample can
654 * be 2 bytes!)
655 * "alignment <nr>" sets the blockalignment to <nr>
656 * "bitspersample <nr>" sets the nr of bits per sample
657 * Sequencer:
658 * "master [midi|file|smpte|none]" sets the midi master device
659 * "slave [midi|file|smpte|none]" sets the midi master device
660 * "port mapper" midioutput to portmapper
661 * "port <nr>" midioutput to specified port
662 * "tempo <nr>" tempo of track (depends on timeformat/divtype)
663 * "offset <nr>" start offset?
665 static DWORD
666 MCISTR_Set(_MCISTR_PROTO_) {
667 union U {
668 MCI_SET_PARMS setParams;
669 MCI_WAVE_SET_PARMS wavesetParams;
670 MCI_SEQ_SET_PARMS seqsetParams;
672 union U *pU = SEGPTR_NEW(union U);
673 int i,res;
675 pU->setParams.dwCallback = 0;
676 i = 0;
677 while (i<nrofkeywords) {
678 FLAG2("door","open",MCI_SET_DOOR_OPEN);
679 FLAG2("door","closed",MCI_SET_DOOR_CLOSED);
681 if ( !STRCMP(keywords[i],"time") &&
682 (i+2<nrofkeywords) &&
683 !STRCMP(keywords[i+1],"format")
685 dwFlags |= MCI_SET_TIME_FORMAT;
687 /* FIXME:is this a shortcut for milliseconds or
688 * minutes:seconds? */
689 if (!STRCMP(keywords[i+2],"ms"))
690 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
692 if (!STRCMP(keywords[i+2],"milliseconds"))
693 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
694 if (!STRCMP(keywords[i+2],"msf"))
695 pU->setParams.dwTimeFormat = MCI_FORMAT_MSF;
696 if (!STRCMP(keywords[i+2],"hms"))
697 pU->setParams.dwTimeFormat = MCI_FORMAT_HMS;
698 if (!STRCMP(keywords[i+2],"frames"))
699 pU->setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
700 if (!STRCMP(keywords[i+2],"track"))
701 pU->setParams.dwTimeFormat = MCI_VD_FORMAT_TRACK;
702 if (!STRCMP(keywords[i+2],"bytes"))
703 pU->setParams.dwTimeFormat = MCI_FORMAT_BYTES;
704 if (!STRCMP(keywords[i+2],"samples"))
705 pU->setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
706 if (!STRCMP(keywords[i+2],"tmsf"))
707 pU->setParams.dwTimeFormat = MCI_FORMAT_TMSF;
708 if ( !STRCMP(keywords[i+2],"song") &&
709 (i+3<nrofkeywords) &&
710 !STRCMP(keywords[i+3],"pointer")
712 pU->setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR;
713 if (!STRCMP(keywords[i+2],"smpte") && (i+3<nrofkeywords)) {
714 if (!STRCMP(keywords[i+3],"24"))
715 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
716 if (!STRCMP(keywords[i+3],"25"))
717 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
718 if (!STRCMP(keywords[i+3],"30"))
719 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
720 if (!STRCMP(keywords[i+3],"drop") && (i+4<nrofkeywords) && !STRCMP(keywords[i+4],"30")) {
721 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
722 i++;
724 i++;
725 /*FALLTHROUGH*/
727 i+=3;
728 continue;
730 if (!STRCMP(keywords[i],"audio") && (i+1<nrofkeywords)) {
731 dwFlags |= MCI_SET_AUDIO;
732 if (!STRCMP(keywords[i+1],"all"))
733 pU->setParams.dwAudio = MCI_SET_AUDIO_ALL;
734 if (!STRCMP(keywords[i+1],"left"))
735 pU->setParams.dwAudio = MCI_SET_AUDIO_LEFT;
736 if (!STRCMP(keywords[i+1],"right"))
737 pU->setParams.dwAudio = MCI_SET_AUDIO_RIGHT;
738 i+=2;
739 continue;
741 FLAG1("video",MCI_SET_VIDEO);
742 FLAG1("on",MCI_SET_ON);
743 FLAG1("off",MCI_SET_OFF);
744 switch (uDevTyp) {
745 case MCI_DEVTYPE_WAVEFORM_AUDIO:
746 FLAG2("any","input",MCI_WAVE_SET_ANYINPUT);
747 FLAG2("any","output",MCI_WAVE_SET_ANYOUTPUT);
749 if ( !STRCMP(keywords[i],"formattag") &&
750 (i+1<nrofkeywords) &&
751 !STRCMP(keywords[i+1],"pcm")
753 dwFlags |= MCI_WAVE_SET_FORMATTAG;
754 pU->wavesetParams.wFormatTag = WAVE_FORMAT_PCM;
755 i+=2;
756 continue;
759 /* <keyword> <integer> */
760 #define WII(str,flag,fmt,element) \
761 if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
762 sscanf(keywords[i+1],fmt,&(pU->wavesetParams. element ));\
763 dwFlags |= flag;\
764 i+=2;\
765 continue;\
767 WII("formattag",MCI_WAVE_SET_FORMATTAG,"%hu",wFormatTag);
768 WII("channels",MCI_WAVE_SET_CHANNELS,"%hu",nChannels);
769 WII("bytespersec",MCI_WAVE_SET_AVGBYTESPERSEC,"%lu",nAvgBytesPerSec);
770 WII("samplespersec",MCI_WAVE_SET_SAMPLESPERSEC,"%lu",nSamplesPerSec);
771 WII("alignment",MCI_WAVE_SET_BLOCKALIGN,"%hu",nBlockAlign);
772 WII("bitspersample",MCI_WAVE_SET_BITSPERSAMPLE,"%hu",wBitsPerSample);
773 WII("input",MCI_WAVE_INPUT,"%hu",wInput);
774 WII("output",MCI_WAVE_OUTPUT,"%hu",wOutput);
775 #undef WII
776 break;
777 case MCI_DEVTYPE_SEQUENCER:
778 if (!STRCMP(keywords[i],"master") && (i+1<nrofkeywords)) {
779 dwFlags |= MCI_SEQ_SET_MASTER;
780 if (!STRCMP(keywords[i+1],"midi"))
781 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
782 if (!STRCMP(keywords[i+1],"file"))
783 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
784 if (!STRCMP(keywords[i+1],"smpte"))
785 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
786 if (!STRCMP(keywords[i+1],"none"))
787 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
788 i+=2;
789 continue;
791 if (!STRCMP(keywords[i],"slave") && (i+1<nrofkeywords)) {
792 dwFlags |= MCI_SEQ_SET_SLAVE;
793 if (!STRCMP(keywords[i+1],"midi"))
794 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
795 if (!STRCMP(keywords[i+1],"file"))
796 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
797 if (!STRCMP(keywords[i+1],"smpte"))
798 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
799 if (!STRCMP(keywords[i+1],"none"))
800 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
801 i+=2;
802 continue;
804 if ( !STRCMP(keywords[i],"port") &&
805 (i+1<nrofkeywords) &&
806 !STRCMP(keywords[i+1],"mapper")
808 pU->seqsetParams.dwPort=-1;/* FIXME:not sure*/
809 dwFlags |= MCI_SEQ_SET_PORT;
810 i+=2;
811 continue;
813 #define SII(str,flag,element) \
814 if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
815 sscanf(keywords[i+1],"%ld",&(pU->seqsetParams. element ));\
816 dwFlags |= flag;\
817 i+=2;\
818 continue;\
820 SII("tempo",MCI_SEQ_SET_TEMPO,dwTempo);
821 SII("port",MCI_SEQ_SET_PORT,dwPort);
822 SII("offset",MCI_SEQ_SET_PORT,dwOffset);
824 i++;
826 if (!dwFlags)
827 return MCIERR_MISSING_STRING_ARGUMENT;
828 _MCI_CALL_DRIVER( MCI_SET, SEGPTR_GET(pU) );
829 SEGPTR_FREE(pU);
830 return res;
833 /* specify break key
834 * Arguments:
835 * "off" disable break
836 * "on <keyid>" enable break on key with keyid
837 * (I strongly suspect, that there is another parameter:
838 * "window <handle>"
839 * but I don't see it mentioned in my documentation.
840 * Returns nothing.
842 static DWORD
843 MCISTR_Break(_MCISTR_PROTO_)
845 MCI_BREAK_PARMS *breakParams = SEGPTR_NEW(MCI_BREAK_PARMS);
846 int res,i;
848 if (!breakParams) return 0;
849 /*breakParams.hwndBreak ? */
850 for (i = 0; i < nrofkeywords; i++)
852 FLAG1("off",MCI_BREAK_OFF);
853 if (!strcmp(keywords[i],"on") && (nrofkeywords>i+1)) {
854 dwFlags&=~MCI_BREAK_OFF;
855 dwFlags|=MCI_BREAK_KEY;
856 sscanf(keywords[i+1],"%d",&(breakParams->nVirtKey));
857 i+=2;
858 continue;
861 _MCI_CALL_DRIVER( MCI_BREAK, SEGPTR_GET(breakParams) );
862 SEGPTR_FREE(breakParams);
863 return res;
866 #define ITEM1(str,item,xtype) \
867 if (!STRCMP(keywords[i],str)) {\
868 gdcParams->dwItem = item;\
869 type = xtype;\
870 i++;\
871 continue;\
873 #define ITEM2(str1,str2,item,xtype) \
874 if ( !STRCMP(keywords[i],str1) &&\
875 (i+1<nrofkeywords) &&\
876 !STRCMP(keywords[i+1],str2)\
877 ) {\
878 gdcParams->dwItem = item;\
879 type = xtype;\
880 i+=2;\
881 continue;\
883 #define ITEM3(str1,str2,str3,item,xtype) \
884 if ( !STRCMP(keywords[i],str1) &&\
885 (i+2<nrofkeywords) &&\
886 !STRCMP(keywords[i+1],str2) &&\
887 !STRCMP(keywords[i+2],str3)\
888 ) {\
889 gdcParams->dwItem = item;\
890 type = xtype;\
891 i+=3;\
892 continue;\
894 /* get device capabilities of MCI drivers
895 * Arguments:
896 * Generic:
897 * "device type" returns device name as string
898 * "has audio" returns bool
899 * "has video" returns bool
900 * "uses files" returns bool
901 * "compound device" returns bool
902 * "can record" returns bool
903 * "can play" returns bool
904 * "can eject" returns bool
905 * "can save" returns bool
906 * Animation:
907 * "palettes" returns nr of available palette entries
908 * "windows" returns nr of available windows
909 * "can reverse" returns bool
910 * "can stretch" returns bool
911 * "slow play rate" returns the slow playrate
912 * "fast play rate" returns the fast playrate
913 * "normal play rate" returns the normal playrate
914 * Overlay:
915 * "windows" returns nr of available windows
916 * "can stretch" returns bool
917 * "can freeze" returns bool
918 * Videodisc:
919 * "cav" assume CAV discs (default if no disk inserted)
920 * "clv" assume CLV discs
921 * "can reverse" returns bool
922 * "slow play rate" returns the slow playrate
923 * "fast play rate" returns the fast playrate
924 * "normal play rate" returns the normal playrate
925 * Waveform audio:
926 * "inputs" returns nr of inputdevices
927 * "outputs" returns nr of outputdevices
929 static DWORD
930 MCISTR_Capability(_MCISTR_PROTO_) {
931 MCI_GETDEVCAPS_PARMS *gdcParams = SEGPTR_NEW(MCI_GETDEVCAPS_PARMS);
932 int type=0,i,res;
934 gdcParams->dwCallback = 0;
935 if (!nrofkeywords)
936 return MCIERR_MISSING_STRING_ARGUMENT;
937 /* well , thats default */
938 dwFlags |= MCI_GETDEVCAPS_ITEM;
939 gdcParams->dwItem = 0;
940 i=0;
941 while (i<nrofkeywords) {
942 ITEM2("device","type",MCI_GETDEVCAPS_DEVICE_TYPE,_MCISTR_devtype);
943 ITEM2("has","audio",MCI_GETDEVCAPS_HAS_AUDIO,_MCISTR_bool);
944 ITEM2("has","video",MCI_GETDEVCAPS_HAS_VIDEO,_MCISTR_bool);
945 ITEM2("uses","files",MCI_GETDEVCAPS_USES_FILES,_MCISTR_bool);
946 ITEM2("compound","device",MCI_GETDEVCAPS_COMPOUND_DEVICE,_MCISTR_bool);
947 ITEM2("can","record",MCI_GETDEVCAPS_CAN_RECORD,_MCISTR_bool);
948 ITEM2("can","play",MCI_GETDEVCAPS_CAN_PLAY,_MCISTR_bool);
949 ITEM2("can","eject",MCI_GETDEVCAPS_CAN_EJECT,_MCISTR_bool);
950 ITEM2("can","save",MCI_GETDEVCAPS_CAN_SAVE,_MCISTR_bool);
951 switch (uDevTyp) {
952 case MCI_DEVTYPE_ANIMATION:
953 ITEM1("palettes",MCI_ANIM_GETDEVCAPS_PALETTES,_MCISTR_int);
954 ITEM1("windows",MCI_ANIM_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
955 ITEM2("can","reverse",MCI_ANIM_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
956 ITEM2("can","stretch",MCI_ANIM_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
957 ITEM3("slow","play","rate",MCI_ANIM_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
958 ITEM3("fast","play","rate",MCI_ANIM_GETDEVCAPS_FAST_RATE,_MCISTR_int);
959 ITEM3("normal","play","rate",MCI_ANIM_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
960 break;
961 case MCI_DEVTYPE_OVERLAY:
962 ITEM1("windows",MCI_OVLY_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
963 ITEM2("can","freeze",MCI_OVLY_GETDEVCAPS_CAN_FREEZE,_MCISTR_bool);
964 ITEM2("can","stretch",MCI_OVLY_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
965 break;
966 case MCI_DEVTYPE_VIDEODISC:
967 FLAG1("cav",MCI_VD_GETDEVCAPS_CAV);
968 FLAG1("clv",MCI_VD_GETDEVCAPS_CLV);
969 ITEM2("can","reverse",MCI_VD_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
970 ITEM3("slow","play","rate",MCI_VD_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
971 ITEM3("fast","play","rate",MCI_VD_GETDEVCAPS_FAST_RATE,_MCISTR_int);
972 ITEM3("normal","play","rate",MCI_VD_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
973 break;
974 case MCI_DEVTYPE_WAVEFORM_AUDIO:
975 ITEM1("inputs",MCI_WAVE_GETDEVCAPS_INPUTS,_MCISTR_int);
976 ITEM1("outputs",MCI_WAVE_GETDEVCAPS_OUTPUTS,_MCISTR_int);
977 break;
979 i++;
981 _MCI_CALL_DRIVER( MCI_GETDEVCAPS, SEGPTR_GET(gdcParams) );
982 /* no timeformat needed */
983 if (res==0)
984 _MCISTR_convreturn( type, gdcParams->dwReturn, lpstrReturnString,
985 uReturnLength, uDevTyp, 0 );
986 SEGPTR_FREE(gdcParams);
987 return res;
989 #undef ITEM1
990 #undef ITEM2
991 #undef ITEM3
992 /* resumes operation of device. no arguments, no return values */
993 static DWORD
994 MCISTR_Resume(_MCISTR_PROTO_)
996 MCI_GENERIC_PARMS *genParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
997 int res;
998 genParams->dwCallback = 0;
999 _MCI_CALL_DRIVER( MCI_RESUME, SEGPTR_GET(genParams) );
1000 return res;
1003 /* pauses operation of device. no arguments, no return values */
1004 static DWORD
1005 MCISTR_Pause(_MCISTR_PROTO_)
1007 MCI_GENERIC_PARMS *genParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
1008 int res;
1009 genParams->dwCallback = 0;
1010 _MCI_CALL_DRIVER( MCI_PAUSE, SEGPTR_GET(genParams) );
1011 return res;
1014 /* stops operation of device. no arguments, no return values */
1015 static DWORD
1016 MCISTR_Stop(_MCISTR_PROTO_)
1018 MCI_GENERIC_PARMS *genParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
1019 int res;
1020 genParams->dwCallback = 0;
1021 _MCI_CALL_DRIVER( MCI_STOP, SEGPTR_GET(genParams) );
1022 return res;
1025 /* starts recording.
1026 * Arguments:
1027 * "overwrite" overwrite existing things
1028 * "insert" insert at current position
1029 * "to <time>" record up to <time> (specified in timeformat)
1030 * "from <time>" record from <time> (specified in timeformat)
1032 static DWORD
1033 MCISTR_Record(_MCISTR_PROTO_) {
1034 int i,res,timef,nrargs,j,k,a[4];
1035 char *parsestr;
1036 MCI_RECORD_PARMS *recordParams = SEGPTR_NEW(MCI_RECORD_PARMS);
1038 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1039 if (res) return res;
1041 switch (timef) {
1042 case MCI_FORMAT_MILLISECONDS:
1043 case MCI_FORMAT_FRAMES:
1044 case MCI_FORMAT_BYTES:
1045 case MCI_FORMAT_SAMPLES:
1046 nrargs=1;
1047 parsestr="%d";
1048 break;
1049 case MCI_FORMAT_HMS:
1050 case MCI_FORMAT_MSF:
1051 parsestr="%d:%d:%d";
1052 nrargs=3;
1053 break;
1054 case MCI_FORMAT_TMSF:
1055 parsestr="%d:%d:%d:%d";
1056 nrargs=4;
1057 break;
1058 default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
1059 parsestr="%d";
1060 nrargs=1;
1061 break;
1063 recordParams->dwCallback = 0;
1064 i = 0;
1065 while (i<nrofkeywords) {
1066 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1067 dwFlags |= MCI_TO;
1068 a[0]=a[1]=a[2]=a[3]=0;
1069 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1070 /* add up all integers we got, if we have more
1071 * shift them. (Well I should use the macros in
1072 * mmsystem.h, right).
1074 recordParams->dwTo=0;
1075 for (k=0;k<j;k++)
1076 recordParams->dwTo+=a[k]<<(8*(nrargs-k));
1077 i+=2;
1078 continue;
1080 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1081 dwFlags |= MCI_FROM;
1082 a[0]=a[1]=a[2]=a[3]=0;
1083 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1084 /* dito. */
1085 recordParams->dwFrom=0;
1086 for (k=0;k<j;k++)
1087 recordParams->dwFrom+=a[k]<<(8*(nrargs-k));
1088 i+=2;
1089 continue;
1091 FLAG1("insert",MCI_RECORD_INSERT);
1092 FLAG1("overwrite",MCI_RECORD_OVERWRITE);
1093 i++;
1095 _MCI_CALL_DRIVER( MCI_RECORD, SEGPTR_GET(recordParams) );
1096 SEGPTR_FREE(recordParams);
1097 return res;
1100 /* play media
1101 * Arguments:
1102 * "to <time>" play up to <time> (specified in set timeformat)
1103 * "from <time>" play from <time> (specified in set timeformat)
1104 * Animation:
1105 * "slow" play slow
1106 * "fast" play fast
1107 * "scan" play as fast as possible (with audio disabled perhaps)
1108 * "reverse" play reverse
1109 * "speed <fps>" play with specified frames per second
1110 * Videodisc:
1111 * "slow" play slow
1112 * "fast" play fast
1113 * "scan" play as fast as possible (with audio disabled perhaps)
1114 * "reverse" play reverse
1115 * "speed <fps>" play with specified frames per second
1117 static DWORD
1118 MCISTR_Play(_MCISTR_PROTO_) {
1119 int i,res,timef,nrargs,j,k,a[4];
1120 char *parsestr;
1121 union U {
1122 MCI_PLAY_PARMS playParams;
1123 MCI_VD_PLAY_PARMS vdplayParams;
1124 MCI_ANIM_PLAY_PARMS animplayParams;
1126 union U *pU = SEGPTR_NEW(union U);
1128 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1129 if (res) return res;
1130 switch (timef) {
1131 case MCI_FORMAT_MILLISECONDS:
1132 case MCI_FORMAT_FRAMES:
1133 case MCI_FORMAT_BYTES:
1134 case MCI_FORMAT_SAMPLES:
1135 nrargs=1;
1136 parsestr="%d";
1137 break;
1138 case MCI_FORMAT_HMS:
1139 case MCI_FORMAT_MSF:
1140 parsestr="%d:%d:%d";
1141 nrargs=3;
1142 break;
1143 case MCI_FORMAT_TMSF:
1144 parsestr="%d:%d:%d:%d";
1145 nrargs=4;
1146 break;
1147 default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
1148 parsestr="%d";
1149 nrargs=1;
1150 break;
1152 pU->playParams.dwCallback=0;
1153 i=0;
1154 while (i<nrofkeywords) {
1155 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1156 dwFlags |= MCI_TO;
1157 a[0]=a[1]=a[2]=a[3]=0;
1158 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1159 /* add up all integers we got, if we have more
1160 * shift them. (Well I should use the macros in
1161 * mmsystem.h, right).
1163 pU->playParams.dwTo=0;
1164 for (k=0;k<j;k++)
1165 pU->playParams.dwTo+=a[k]<<(8*(nrargs-k));
1166 i+=2;
1167 continue;
1169 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1170 dwFlags |= MCI_FROM;
1171 a[0]=a[1]=a[2]=a[3]=0;
1172 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1173 /* dito. */
1174 pU->playParams.dwFrom=0;
1175 for (k=0;k<j;k++)
1176 pU->playParams.dwFrom+=a[k]<<(8*(nrargs-k));
1177 i+=2;
1178 continue;
1180 switch (uDevTyp) {
1181 case MCI_DEVTYPE_VIDEODISC:
1182 FLAG1("slow",MCI_VD_PLAY_SLOW);
1183 FLAG1("fast",MCI_VD_PLAY_FAST);
1184 FLAG1("scan",MCI_VD_PLAY_SCAN);
1185 FLAG1("reverse",MCI_VD_PLAY_REVERSE);
1186 if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
1187 dwFlags |= MCI_VD_PLAY_SPEED;
1188 sscanf(keywords[i+1],"%ld",&(pU->vdplayParams.dwSpeed));
1189 i+=2;
1190 continue;
1192 break;
1193 case MCI_DEVTYPE_ANIMATION:
1194 FLAG1("slow",MCI_ANIM_PLAY_SLOW);
1195 FLAG1("fast",MCI_ANIM_PLAY_FAST);
1196 FLAG1("scan",MCI_ANIM_PLAY_SCAN);
1197 FLAG1("reverse",MCI_ANIM_PLAY_REVERSE);
1198 if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
1199 dwFlags |= MCI_ANIM_PLAY_SPEED;
1200 sscanf(keywords[i+1],"%ld",&(pU->animplayParams.dwSpeed));
1201 i+=2;
1202 continue;
1204 break;
1206 i++;
1208 _MCI_CALL_DRIVER( MCI_PLAY, SEGPTR_GET(pU) );
1209 SEGPTR_FREE(pU);
1210 return res;
1213 /* seek to a specified position
1214 * Arguments:
1215 * "to start" seek to start of medium
1216 * "to end" seek to end of medium
1217 * "to <time>" seek to <time> specified in current timeformat
1219 static DWORD
1220 MCISTR_Seek(_MCISTR_PROTO_) {
1221 int i,res,timef,nrargs,j,k,a[4];
1222 char *parsestr;
1223 MCI_SEEK_PARMS *seekParams = SEGPTR_NEW(MCI_SEEK_PARMS);
1225 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1226 if (res) return res;
1227 switch (timef) {
1228 case MCI_FORMAT_MILLISECONDS:
1229 case MCI_FORMAT_FRAMES:
1230 case MCI_FORMAT_BYTES:
1231 case MCI_FORMAT_SAMPLES:
1232 nrargs=1;
1233 parsestr="%d";
1234 break;
1235 case MCI_FORMAT_HMS:
1236 case MCI_FORMAT_MSF:
1237 parsestr="%d:%d:%d";
1238 nrargs=3;
1239 break;
1240 case MCI_FORMAT_TMSF:
1241 parsestr="%d:%d:%d:%d";
1242 nrargs=4;
1243 break;
1244 default:fprintf(stdnimp,"mciSendString:SEEK:unknown timeformat %d, please report.\n",timef);
1245 parsestr="%d";
1246 nrargs=1;
1247 break;
1249 seekParams->dwCallback=0;
1250 i=0;
1251 while (i<nrofkeywords) {
1252 if ( !STRCMP(keywords[i],"to") && (i+1<nrofkeywords)) {
1253 if (!STRCMP(keywords[i+1],"start")) {
1254 dwFlags|=MCI_SEEK_TO_START;
1255 seekParams->dwTo=0;
1256 i+=2;
1257 continue;
1259 if (!STRCMP(keywords[i+1],"end")) {
1260 dwFlags|=MCI_SEEK_TO_END;
1261 seekParams->dwTo=0;
1262 i+=2;
1263 continue;
1265 dwFlags|=MCI_TO;
1266 i+=2;
1267 a[0]=a[1]=a[2]=a[3]=0;
1268 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1269 seekParams->dwTo=0;
1270 for (k=0;k<j;k++)
1271 seekParams->dwTo+=a[k]<<(8*(nrargs-k));
1272 continue;
1274 switch (uDevTyp) {
1275 case MCI_DEVTYPE_VIDEODISC:
1276 FLAG1("reverse",MCI_VD_SEEK_REVERSE);
1277 break;
1279 i++;
1281 _MCI_CALL_DRIVER( MCI_SEEK, SEGPTR_GET(seekParams) );
1282 SEGPTR_FREE(seekParams);
1283 return res;
1286 /* close media/driver */
1287 static DWORD
1288 MCISTR_Close(_MCISTR_PROTO_)
1290 MCI_GENERIC_PARMS *closeParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
1291 int res;
1292 _MCI_CALL_DRIVER( MCI_CLOSE, SEGPTR_GET(closeParams) );
1293 SEGPTR_FREE(closeParams);
1294 return res;
1297 /* return information.
1298 * Arguments:
1299 * "product" return product name (human readable)
1300 * "file" return filename
1301 * Animation:
1302 * "text" returns text?
1303 * Overlay:
1304 * "text" returns text?
1306 static DWORD
1307 MCISTR_Info(_MCISTR_PROTO_)
1309 MCI_INFO_PARMS *infoParams = SEGPTR_NEW(MCI_INFO_PARMS);
1310 DWORD sflags;
1311 int i,res;
1313 sflags = dwFlags;
1314 i=0;while (i<nrofkeywords) {
1315 FLAG1("product",MCI_INFO_PRODUCT);
1316 FLAG1("file",MCI_INFO_FILE);
1317 switch (uDevTyp) {
1318 case MCI_DEVTYPE_ANIMATION:
1319 FLAG1("text",MCI_ANIM_INFO_TEXT);
1320 break;
1321 case MCI_DEVTYPE_OVERLAY:
1322 FLAG1("text",MCI_OVLY_INFO_TEXT);
1323 break;
1325 i++;
1327 if (dwFlags == sflags)
1328 return MCIERR_MISSING_STRING_ARGUMENT;
1329 /* MCI driver will fill in lpstrReturn, dwRetSize.
1330 * FIXME: I don't know if this is correct behaviour
1332 _MCI_CALL_DRIVER( MCI_INFO, SEGPTR_GET(infoParams) );
1333 if (res==0)
1334 _MCI_STR(infoParams->lpstrReturn);
1335 SEGPTR_FREE(infoParams);
1336 return res;
1339 DWORD mciSysInfo(DWORD dwFlags,LPMCI_SYSINFO_PARMS lpParms);
1341 /* query MCI driver itself for information
1342 * Arguments:
1343 * "installname" return install name of <device> (system.ini)
1344 * "quantity" return nr of installed drivers
1345 * "open" open drivers only (additional flag)
1346 * "name <nr>" return nr of devices with <devicetyp>
1347 * "name all" return nr of all devices
1349 * FIXME: mciSysInfo() is broken I think.
1351 static DWORD
1352 MCISTR_Sysinfo(_MCISTR_PROTO_) {
1353 MCI_SYSINFO_PARMS sysinfoParams;
1354 int i,res;
1356 sysinfoParams.lpstrReturn = lpstrReturnString;
1357 sysinfoParams.dwRetSize = uReturnLength;
1358 sysinfoParams.wDeviceType = uDevTyp;
1359 i=0;
1360 while (i<nrofkeywords) {
1361 FLAG1("installname",MCI_SYSINFO_INSTALLNAME);
1362 FLAG1("quantity",MCI_SYSINFO_INSTALLNAME);
1363 FLAG1("open",MCI_SYSINFO_OPEN);
1364 if (!strcmp(keywords[i],"name") && (i+1<nrofkeywords)) {
1365 sscanf(keywords[i+1],"%ld",&(sysinfoParams.dwNumber));
1366 dwFlags |= MCI_SYSINFO_NAME;
1367 i+=2;
1368 continue;
1370 i++;
1372 res=mciSysInfo(dwFlags,&sysinfoParams);
1373 if (dwFlags & MCI_SYSINFO_QUANTITY) {
1374 char buf[100];
1376 sprintf(buf,"%ld",*(long*)PTR_SEG_TO_LIN(lpstrReturnString));
1377 _MCI_STR(buf);
1379 /* no need to copy anything back, mciSysInfo did it for us */
1380 return res;
1383 /* load file
1384 * Argument: "<filename>"
1385 * Overlay: "at <left> <top> <right> <bottom>" additional
1387 static DWORD
1388 MCISTR_Load(_MCISTR_PROTO_) {
1389 union U {
1390 MCI_LOAD_PARMS loadParams;
1391 MCI_OVLY_LOAD_PARMS ovlyloadParams;
1393 union U *pU = SEGPTR_NEW(union U);
1394 int i,len,res;
1395 char *s;
1397 i=0;len=0;
1398 while (i<nrofkeywords) {
1399 switch (uDevTyp) {
1400 case MCI_DEVTYPE_OVERLAY:
1401 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1402 dwFlags |= MCI_OVLY_RECT;
1403 sscanf(keywords[i+1],"%hd",&(pU->ovlyloadParams.rc.left));
1404 sscanf(keywords[i+2],"%hd",&(pU->ovlyloadParams.rc.top));
1405 sscanf(keywords[i+3],"%hd",&(pU->ovlyloadParams.rc.right));
1406 sscanf(keywords[i+4],"%hd",&(pU->ovlyloadParams.rc.bottom));
1407 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1408 continue;
1410 break;
1412 len+=strlen(keywords[i])+1;
1413 i++;
1415 s=(char*)SEGPTR_ALLOC(len);
1416 *s='\0';
1417 while (i<nrofkeywords) {
1418 strcat(s,keywords[i]);
1419 i++;
1420 if (i<nrofkeywords) strcat(s," ");
1422 pU->loadParams.lpfilename=(LPSTR)SEGPTR_GET(s);
1423 dwFlags |= MCI_LOAD_FILE;
1424 _MCI_CALL_DRIVER( MCI_LOAD, SEGPTR_GET(pU) );
1425 SEGPTR_FREE(s);
1426 SEGPTR_FREE(pU);
1427 return res;
1430 /* save to file
1431 * Argument: "<filename>"
1432 * Overlay: "at <left> <top> <right> <bottom>" additional
1434 static DWORD
1435 MCISTR_Save(_MCISTR_PROTO_) {
1436 union U {
1437 MCI_SAVE_PARMS saveParams;
1438 MCI_OVLY_SAVE_PARMS ovlysaveParams;
1440 union U *pU = SEGPTR_NEW(union U);
1441 int i,len,res;
1442 char *s;
1444 i=0;len=0;
1445 while (i<nrofkeywords) {
1446 switch (uDevTyp) {
1447 case MCI_DEVTYPE_OVERLAY:
1448 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1449 dwFlags |= MCI_OVLY_RECT;
1450 sscanf(keywords[i+1],"%hd",&(pU->ovlysaveParams.rc.left));
1451 sscanf(keywords[i+2],"%hd",&(pU->ovlysaveParams.rc.top));
1452 sscanf(keywords[i+3],"%hd",&(pU->ovlysaveParams.rc.right));
1453 sscanf(keywords[i+4],"%hd",&(pU->ovlysaveParams.rc.bottom));
1454 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1455 continue;
1457 break;
1459 len+=strlen(keywords[i])+1;
1460 i++;
1462 s=(char*)SEGPTR_ALLOC(len);
1463 *s='\0';
1464 while (i<nrofkeywords) {
1465 strcat(s,keywords[i]);
1466 i++;
1467 if (i<nrofkeywords) strcat(s," ");
1469 pU->saveParams.lpfilename=(LPSTR)SEGPTR_GET(s);
1470 dwFlags |= MCI_LOAD_FILE;
1471 _MCI_CALL_DRIVER( MCI_SAVE, SEGPTR_GET(pU) );
1472 SEGPTR_FREE(s);
1473 SEGPTR_FREE(pU);
1474 return res;
1477 /* prepare device for input/output
1478 * (only applyable to waveform audio)
1480 static DWORD
1481 MCISTR_Cue(_MCISTR_PROTO_) {
1482 MCI_GENERIC_PARMS *cueParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
1483 int i,res;
1485 i=0;
1486 while (i<nrofkeywords) {
1487 switch (uDevTyp) {
1488 case MCI_DEVTYPE_WAVEFORM_AUDIO:
1489 FLAG1("input",MCI_WAVE_INPUT);
1490 FLAG1("output",MCI_WAVE_OUTPUT);
1491 break;
1493 i++;
1495 _MCI_CALL_DRIVER( MCI_CUE, SEGPTR_GET(cueParams) );
1496 SEGPTR_FREE(cueParams);
1497 return res;
1500 /* delete information */
1501 static DWORD
1502 MCISTR_Delete(_MCISTR_PROTO_) {
1503 int timef,nrargs,i,j,k,a[4],res;
1504 char *parsestr;
1505 MCI_WAVE_DELETE_PARMS *deleteParams = SEGPTR_NEW(MCI_WAVE_DELETE_PARMS);
1507 /* only implemented for waveform audio */
1508 if (uDevTyp != MCI_DEVTYPE_WAVEFORM_AUDIO)
1509 return MCIERR_UNSUPPORTED_FUNCTION; /* well it fits */
1510 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1511 if (res) return res;
1512 switch (timef) {
1513 case MCI_FORMAT_MILLISECONDS:
1514 case MCI_FORMAT_FRAMES:
1515 case MCI_FORMAT_BYTES:
1516 case MCI_FORMAT_SAMPLES:
1517 nrargs=1;
1518 parsestr="%d";
1519 break;
1520 case MCI_FORMAT_HMS:
1521 case MCI_FORMAT_MSF:
1522 parsestr="%d:%d:%d";
1523 nrargs=3;
1524 break;
1525 case MCI_FORMAT_TMSF:
1526 parsestr="%d:%d:%d:%d";
1527 nrargs=4;
1528 break;
1529 default:fprintf(stdnimp,"mciSendString:DELETE:unknown timeformat %d, please report.\n",timef);
1530 parsestr="%d";
1531 nrargs=1;
1532 break;
1534 i=0;
1535 while (i<nrofkeywords) {
1536 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1537 dwFlags |= MCI_TO;
1538 a[0]=a[1]=a[2]=a[3]=0;
1539 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1540 /* add up all integers we got, if we have more
1541 * shift them. (Well I should use the macros in
1542 * mmsystem.h, right).
1544 deleteParams->dwTo=0;
1545 for (k=0;k<j;k++)
1546 deleteParams->dwTo+=a[k]<<(8*(nrargs-k));
1547 i+=2;
1548 continue;
1550 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1551 dwFlags |= MCI_FROM;
1552 a[0]=a[1]=a[2]=a[3]=0;
1553 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1554 /* dito. */
1555 deleteParams->dwFrom=0;
1556 for (k=0;k<j;k++)
1557 deleteParams->dwFrom+=a[k]<<(8*(nrargs-k));
1558 i+=2;
1559 continue;
1561 i++;
1563 _MCI_CALL_DRIVER( MCI_DELETE, SEGPTR_GET(deleteParams) );
1564 SEGPTR_FREE(deleteParams);
1565 return res;
1568 /* send command to device. only applies to videodisc */
1569 static DWORD
1570 MCISTR_Escape(_MCISTR_PROTO_)
1572 MCI_VD_ESCAPE_PARMS *escapeParams = SEGPTR_NEW(MCI_VD_ESCAPE_PARMS);
1573 int i,len,res;
1574 char *s;
1576 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1577 return MCIERR_UNSUPPORTED_FUNCTION;
1578 i=0;len=0;
1579 while (i<nrofkeywords) {
1580 len+=strlen(keywords[i])+1;
1581 i++;
1583 s=(char*)SEGPTR_ALLOC(len);
1584 *s='\0';
1585 while (i<nrofkeywords) {
1586 strcat(s,keywords[i]);
1587 i++;
1588 if (i<nrofkeywords) strcat(s," ");
1590 escapeParams->lpstrCommand = (LPSTR)SEGPTR_GET(s);
1591 dwFlags |= MCI_VD_ESCAPE_STRING;
1592 _MCI_CALL_DRIVER( MCI_ESCAPE, SEGPTR_GET(escapeParams) );
1593 SEGPTR_FREE(s);
1594 SEGPTR_FREE(escapeParams);
1595 return res;
1598 /* unfreeze [part of] the overlayed video
1599 * only applyable to Overlay devices
1601 static DWORD
1602 MCISTR_Unfreeze(_MCISTR_PROTO_)
1604 MCI_OVLY_RECT_PARMS *unfreezeParams = SEGPTR_NEW(MCI_OVLY_RECT_PARMS);
1605 int i,res;
1607 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1608 return MCIERR_UNSUPPORTED_FUNCTION;
1609 i=0;while (i<nrofkeywords) {
1610 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1611 sscanf(keywords[i+1],"%hd",&(unfreezeParams->rc.left));
1612 sscanf(keywords[i+2],"%hd",&(unfreezeParams->rc.top));
1613 sscanf(keywords[i+3],"%hd",&(unfreezeParams->rc.right));
1614 sscanf(keywords[i+4],"%hd",&(unfreezeParams->rc.bottom));
1615 dwFlags |= MCI_OVLY_RECT;
1616 i+=5;
1617 continue;
1619 i++;
1621 _MCI_CALL_DRIVER( MCI_UNFREEZE, SEGPTR_GET(unfreezeParams) );
1622 SEGPTR_FREE(unfreezeParams);
1623 return res;
1625 /* freeze [part of] the overlayed video
1626 * only applyable to Overlay devices
1628 static DWORD
1629 MCISTR_Freeze(_MCISTR_PROTO_)
1631 MCI_OVLY_RECT_PARMS *freezeParams = SEGPTR_NEW(MCI_OVLY_RECT_PARMS);
1632 int i,res;
1634 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1635 return MCIERR_UNSUPPORTED_FUNCTION;
1636 i=0;while (i<nrofkeywords) {
1637 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1638 sscanf(keywords[i+1],"%hd",&(freezeParams->rc.left));
1639 sscanf(keywords[i+2],"%hd",&(freezeParams->rc.top));
1640 sscanf(keywords[i+3],"%hd",&(freezeParams->rc.right));
1641 sscanf(keywords[i+4],"%hd",&(freezeParams->rc.bottom));
1642 dwFlags |= MCI_OVLY_RECT;
1643 i+=5;
1644 continue;
1646 i++;
1648 _MCI_CALL_DRIVER( MCI_FREEZE, SEGPTR_GET(freezeParams) );
1649 SEGPTR_FREE(freezeParams);
1650 return res;
1653 /* copy parts of image to somewhere else
1654 * "source [at <left> <top> <right> <bottom>]" source is framebuffer [or rect]
1655 * "destination [at <left> <top> <right> <bottom>]" destination is framebuffer [or rect]
1656 * Overlay:
1657 * "frame [at <left> <top> <right> <bottom>]" frame is framebuffer [or rect]
1658 * where the video input is placed
1659 * "video [at <left> <top> <right> <bottom>]" video is whole video [or rect]
1660 * (defining part of input to
1661 * be displayed)
1663 * FIXME: This whole junk is passing multiple rectangles.
1664 * I don't know how to do that with the present interface.
1665 * (Means code below is broken)
1667 static DWORD
1668 MCISTR_Put(_MCISTR_PROTO_) {
1669 union U {
1670 MCI_OVLY_RECT_PARMS ovlyputParams;
1671 MCI_ANIM_RECT_PARMS animputParams;
1673 union U *pU = SEGPTR_NEW(union U);
1674 int i,res;
1675 i=0;while (i<nrofkeywords) {
1676 switch (uDevTyp) {
1677 case MCI_DEVTYPE_ANIMATION:
1678 FLAG1("source",MCI_ANIM_PUT_SOURCE);
1679 FLAG1("destination",MCI_ANIM_PUT_DESTINATION);
1680 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1681 sscanf(keywords[i+1],"%hd",&(pU->animputParams.rc.left));
1682 sscanf(keywords[i+2],"%hd",&(pU->animputParams.rc.top));
1683 sscanf(keywords[i+3],"%hd",&(pU->animputParams.rc.right));
1684 sscanf(keywords[i+4],"%hd",&(pU->animputParams.rc.bottom));
1685 dwFlags |= MCI_ANIM_RECT;
1686 i+=5;
1687 continue;
1689 break;
1690 case MCI_DEVTYPE_OVERLAY:
1691 FLAG1("source",MCI_OVLY_PUT_SOURCE);
1692 FLAG1("destination",MCI_OVLY_PUT_DESTINATION);
1693 FLAG1("video",MCI_OVLY_PUT_VIDEO);
1694 FLAG1("frame",MCI_OVLY_PUT_FRAME);
1695 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1696 sscanf(keywords[i+1],"%hd",&(pU->ovlyputParams.rc.left));
1697 sscanf(keywords[i+2],"%hd",&(pU->ovlyputParams.rc.top));
1698 sscanf(keywords[i+3],"%hd",&(pU->ovlyputParams.rc.right));
1699 sscanf(keywords[i+4],"%hd",&(pU->ovlyputParams.rc.bottom));
1700 dwFlags |= MCI_OVLY_RECT;
1701 i+=5;
1702 continue;
1704 break;
1706 i++;
1708 _MCI_CALL_DRIVER( MCI_PUT, SEGPTR_GET(pU) );
1709 SEGPTR_FREE(pU);
1710 return res;
1713 /* palette behaviour changing
1714 * (Animation only)
1715 * "normal" realize the palette normally
1716 * "background" realize the palette as background palette
1718 static DWORD
1719 MCISTR_Realize(_MCISTR_PROTO_)
1721 MCI_GENERIC_PARMS *realizeParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
1722 int i,res;
1724 if (uDevTyp != MCI_DEVTYPE_ANIMATION)
1725 return MCIERR_UNSUPPORTED_FUNCTION;
1726 i=0;
1727 while (i<nrofkeywords) {
1728 FLAG1("background",MCI_ANIM_REALIZE_BKGD);
1729 FLAG1("normal",MCI_ANIM_REALIZE_NORM);
1730 i++;
1732 _MCI_CALL_DRIVER( MCI_REALIZE, SEGPTR_GET(realizeParams) );
1733 SEGPTR_FREE(realizeParams);
1734 return res;
1737 /* videodisc spinning
1738 * "up"
1739 * "down"
1741 static DWORD
1742 MCISTR_Spin(_MCISTR_PROTO_)
1744 MCI_GENERIC_PARMS *spinParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
1745 int i,res;
1747 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1748 return MCIERR_UNSUPPORTED_FUNCTION;
1749 i=0;
1750 while (i<nrofkeywords) {
1751 FLAG1("up",MCI_VD_SPIN_UP);
1752 FLAG1("down",MCI_VD_SPIN_UP);
1753 i++;
1755 _MCI_CALL_DRIVER( MCI_SPIN, SEGPTR_GET(spinParams) );
1756 SEGPTR_FREE(spinParams);
1757 return res;
1760 /* step single frames
1761 * "reverse" optional flag
1762 * "by <nr>" for <nr> frames
1764 static DWORD
1765 MCISTR_Step(_MCISTR_PROTO_) {
1766 union U {
1767 MCI_ANIM_STEP_PARMS animstepParams;
1768 MCI_VD_STEP_PARMS vdstepParams;
1770 union U *pU = SEGPTR_NEW(union U);
1771 int i,res;
1773 i=0;
1774 while (i<nrofkeywords) {
1775 switch (uDevTyp) {
1776 case MCI_DEVTYPE_ANIMATION:
1777 FLAG1("reverse",MCI_ANIM_STEP_REVERSE);
1778 if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
1779 sscanf(keywords[i+1],"%ld",&(pU->animstepParams.dwFrames));
1780 dwFlags |= MCI_ANIM_STEP_FRAMES;
1781 i+=2;
1782 continue;
1784 break;
1785 case MCI_DEVTYPE_VIDEODISC:
1786 FLAG1("reverse",MCI_VD_STEP_REVERSE);
1787 if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
1788 sscanf(keywords[i+1],"%ld",&(pU->vdstepParams.dwFrames));
1789 dwFlags |= MCI_VD_STEP_FRAMES;
1790 i+=2;
1791 continue;
1793 break;
1795 i++;
1797 _MCI_CALL_DRIVER( MCI_STEP, SEGPTR_GET(pU) );
1798 SEGPTR_FREE(pU);
1799 return res;
1802 /* update animation window
1803 * Arguments:
1804 * "at <left> <top> <right> <bottom>" only in this rectangle
1805 * "hdc" device context
1807 static DWORD
1808 MCISTR_Update(_MCISTR_PROTO_) {
1809 int i,res;
1810 MCI_ANIM_UPDATE_PARMS *updateParams = SEGPTR_NEW(MCI_ANIM_UPDATE_PARMS);
1812 i=0;
1813 while (i<nrofkeywords) {
1814 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1815 sscanf(keywords[i+1],"%hd",&(updateParams->rc.left));
1816 sscanf(keywords[i+2],"%hd",&(updateParams->rc.top));
1817 sscanf(keywords[i+3],"%hd",&(updateParams->rc.right));
1818 sscanf(keywords[i+4],"%hd",&(updateParams->rc.bottom));
1819 dwFlags |= MCI_ANIM_RECT;
1820 i+=5;
1821 continue;
1823 if (!STRCMP(keywords[i],"hdc") && (i+1<nrofkeywords)) {
1824 dwFlags |= MCI_ANIM_UPDATE_HDC;
1825 sscanf(keywords[i+1],"%hd",&(updateParams->hDC));
1826 i+=2;
1827 continue;
1829 i++;
1831 _MCI_CALL_DRIVER( MCI_UPDATE, SEGPTR_GET(updateParams) );
1832 SEGPTR_FREE(updateParams);
1833 return res;
1836 /* where command for animation and overlay drivers.
1837 * just returns the specified rectangle as a string
1838 * Arguments:
1839 * "source"
1840 * "destination"
1841 * Overlay special:
1842 * "video"
1843 * "frame"
1845 static DWORD
1846 MCISTR_Where(_MCISTR_PROTO_) {
1847 union U {
1848 MCI_ANIM_RECT_PARMS animwhereParams;
1849 MCI_OVLY_RECT_PARMS ovlywhereParams;
1851 union U *pU = SEGPTR_NEW(union U);
1852 int i,res;
1854 i=0;
1855 while (i<nrofkeywords) {
1856 switch (uDevTyp) {
1857 case MCI_DEVTYPE_ANIMATION:
1858 FLAG1("source",MCI_ANIM_WHERE_SOURCE);
1859 FLAG1("destination",MCI_ANIM_WHERE_DESTINATION);
1860 break;
1861 case MCI_DEVTYPE_OVERLAY:
1862 FLAG1("source",MCI_OVLY_WHERE_SOURCE);
1863 FLAG1("destination",MCI_OVLY_WHERE_DESTINATION);
1864 FLAG1("video",MCI_OVLY_WHERE_VIDEO);
1865 FLAG1("frame",MCI_OVLY_WHERE_FRAME);
1866 break;
1868 i++;
1870 _MCI_CALL_DRIVER( MCI_WHERE, SEGPTR_GET(pU) );
1871 if (res==0) {
1872 char buf[100];
1873 switch (uDevTyp) {
1874 case MCI_DEVTYPE_ANIMATION:
1875 sprintf(buf,"%d %d %d %d",
1876 pU->animwhereParams.rc.left,
1877 pU->animwhereParams.rc.top,
1878 pU->animwhereParams.rc.right,
1879 pU->animwhereParams.rc.bottom
1881 break;
1882 case MCI_DEVTYPE_OVERLAY:
1883 sprintf(buf,"%d %d %d %d",
1884 pU->ovlywhereParams.rc.left,
1885 pU->ovlywhereParams.rc.top,
1886 pU->ovlywhereParams.rc.right,
1887 pU->ovlywhereParams.rc.bottom
1889 break;
1890 default:strcpy(buf,"0 0 0 0");break;
1892 _MCI_STR(buf);
1894 SEGPTR_FREE(pU);
1895 return res;
1898 static DWORD
1899 MCISTR_Window(_MCISTR_PROTO_) {
1900 int i,res;
1901 char *s;
1902 union U {
1903 MCI_ANIM_WINDOW_PARMS animwindowParams;
1904 MCI_OVLY_WINDOW_PARMS ovlywindowParams;
1906 union U *pU = SEGPTR_NEW(union U);
1908 s=NULL;
1909 i=0;
1910 while (i<nrofkeywords) {
1911 switch (uDevTyp) {
1912 case MCI_DEVTYPE_ANIMATION:
1913 if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
1914 dwFlags |= MCI_ANIM_WINDOW_HWND;
1915 if (!STRCMP(keywords[i+1],"default"))
1916 pU->animwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1917 else
1918 sscanf(keywords[i+1],"%hd",&(pU->animwindowParams.hWnd));
1919 i+=2;
1920 continue;
1922 if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
1923 dwFlags |= MCI_ANIM_WINDOW_STATE;
1924 if (!STRCMP(keywords[i+1],"hide"))
1925 pU->animwindowParams.nCmdShow = SW_HIDE;
1926 if (!STRCMP(keywords[i+1],"iconic"))
1927 pU->animwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1928 if (!STRCMP(keywords[i+1],"minimized"))
1929 pU->animwindowParams.nCmdShow = SW_SHOWMINIMIZED;
1930 if (!STRCMP(keywords[i+1],"maximized"))
1931 pU->animwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1932 if (!STRCMP(keywords[i+1],"minimize"))
1933 pU->animwindowParams.nCmdShow = SW_MINIMIZE;
1934 if (!STRCMP(keywords[i+1],"normal"))
1935 pU->animwindowParams.nCmdShow = SW_NORMAL;
1936 if (!STRCMP(keywords[i+1],"show"))
1937 pU->animwindowParams.nCmdShow = SW_SHOW;
1938 if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
1939 if (!STRCMP(keywords[i+2],"active"))
1940 pU->animwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1941 if (!STRCMP(keywords[i+2],"action"))
1942 pU->animwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1943 i++;
1945 i+=2;
1946 continue;
1948 /* text is enclosed in " ... " as it seems */
1949 if (!STRCMP(keywords[i],"text")) {
1950 char *t;
1951 int len,j,k;
1953 if (keywords[i+1][0]!='"') {
1954 i++;
1955 continue;
1957 dwFlags |= MCI_ANIM_WINDOW_TEXT;
1958 len = strlen(keywords[i+1])+1;
1959 j = i+2;
1960 while (j<nrofkeywords) {
1961 len += strlen(keywords[j])+1;
1962 if (strchr(keywords[j],'"'))
1963 break;
1964 j++;
1966 s=(char*)xmalloc(len);
1967 strcpy(s,keywords[i+1]+1);
1968 k=j;j=i+2;
1969 while (j<=k) {
1970 strcat(s," ");
1971 strcat(s,keywords[j]);
1973 if ((t=strchr(s,'"'))) *t='\0';
1974 /* FIXME: segmented pointer? */
1975 pU->animwindowParams.lpstrText = s;
1976 i=k+1;
1977 continue;
1979 FLAG1("stretch",MCI_ANIM_WINDOW_ENABLE_STRETCH);
1980 break;
1981 case MCI_DEVTYPE_OVERLAY:
1982 if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
1983 dwFlags |= MCI_OVLY_WINDOW_HWND;
1984 if (!STRCMP(keywords[i+1],"default"))
1985 pU->ovlywindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1986 else
1987 sscanf(keywords[i+1],"%hd",&(pU->ovlywindowParams.hWnd));
1988 i+=2;
1989 continue;
1991 if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
1992 dwFlags |= MCI_OVLY_WINDOW_STATE;
1993 if (!STRCMP(keywords[i+1],"hide"))
1994 pU->ovlywindowParams.nCmdShow = SW_HIDE;
1995 if (!STRCMP(keywords[i+1],"iconic"))
1996 pU->ovlywindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1997 if (!STRCMP(keywords[i+1],"minimized"))
1998 pU->ovlywindowParams.nCmdShow = SW_SHOWMINIMIZED;
1999 if (!STRCMP(keywords[i+1],"maximized"))
2000 pU->ovlywindowParams.nCmdShow = SW_SHOWMAXIMIZED;
2001 if (!STRCMP(keywords[i+1],"minimize"))
2002 pU->ovlywindowParams.nCmdShow = SW_MINIMIZE;
2003 if (!STRCMP(keywords[i+1],"normal"))
2004 pU->ovlywindowParams.nCmdShow = SW_NORMAL;
2005 if (!STRCMP(keywords[i+1],"show"))
2006 pU->ovlywindowParams.nCmdShow = SW_SHOW;
2007 if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
2008 if (!STRCMP(keywords[i+2],"active"))
2009 pU->ovlywindowParams.nCmdShow = SW_SHOWNOACTIVATE;
2010 if (!STRCMP(keywords[i+2],"action"))
2011 pU->ovlywindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
2012 i++;
2014 i+=2;
2015 continue;
2017 /* text is enclosed in " ... " as it seems */
2018 if (!STRCMP(keywords[i],"text")) {
2019 char *t;
2020 int len,j,k;
2022 if (keywords[i+1][0]!='"') {
2023 i++;
2024 continue;
2026 dwFlags |= MCI_OVLY_WINDOW_TEXT;
2027 len = strlen(keywords[i+1])+1;
2028 j = i+2;
2029 while (j<nrofkeywords) {
2030 len += strlen(keywords[j])+1;
2031 if (strchr(keywords[j],'"'))
2032 break;
2033 j++;
2035 s=(char*)xmalloc(len);
2036 strcpy(s,keywords[i+1]+1);
2037 k=j;j=i+2;
2038 while (j<=k) {
2039 strcat(s," ");
2040 strcat(s,keywords[j]);
2042 if ((t=strchr(s,'"'))) *t='\0';
2043 /* FIXME: segmented pointer? */
2044 pU->ovlywindowParams.lpstrText = s;
2045 i=k+1;
2046 continue;
2048 FLAG1("stretch",MCI_OVLY_WINDOW_ENABLE_STRETCH);
2049 break;
2051 i++;
2053 _MCI_CALL_DRIVER( MCI_WINDOW, SEGPTR_GET(pU) );
2054 if (s) free(s);
2055 SEGPTR_FREE(pU);
2056 return res;
2059 struct _MCISTR_cmdtable {
2060 char *cmd;
2061 DWORD (*fun)(_MCISTR_PROTO_);
2062 } MCISTR_cmdtable[]={
2063 {"break", MCISTR_Break},
2064 {"capability", MCISTR_Capability},
2065 {"close", MCISTR_Close},
2066 {"cue", MCISTR_Cue},
2067 {"delete", MCISTR_Delete},
2068 {"escape", MCISTR_Escape},
2069 {"freeze", MCISTR_Freeze},
2070 {"info", MCISTR_Info},
2071 {"load", MCISTR_Load},
2072 {"open", MCISTR_Open},
2073 {"pause", MCISTR_Pause},
2074 {"play", MCISTR_Play},
2075 {"put", MCISTR_Put},
2076 {"realize", MCISTR_Realize},
2077 {"record", MCISTR_Record},
2078 {"resume", MCISTR_Resume},
2079 {"save", MCISTR_Save},
2080 {"seek", MCISTR_Seek},
2081 {"set", MCISTR_Set},
2082 {"spin", MCISTR_Spin},
2083 {"status", MCISTR_Status},
2084 {"step", MCISTR_Step},
2085 {"stop", MCISTR_Stop},
2086 {"sysinfo", MCISTR_Sysinfo},
2087 {"unfreeze", MCISTR_Unfreeze},
2088 {"update", MCISTR_Update},
2089 {"where", MCISTR_Where},
2090 {"window", MCISTR_Window},
2091 {NULL, NULL}
2093 /**************************************************************************
2094 * mciSendString [MMSYSTEM.702]
2096 /* The usercode sends a string with a command (and flags) expressed in
2097 * words in it... We do our best to call aprobiate drivers,
2098 * and return a errorcode AND a readable string (if lpstrRS!=NULL)
2099 * Info gathered by watching cool134.exe and from Borland's mcistrwh.hlp
2101 /* FIXME: "all" is a valid devicetype and we should access all devices if
2102 * it is used. (imagine "close all"). Not implemented yet.
2104 DWORD mciSendString (LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2105 UINT16 uReturnLength, HWND16 hwndCallback)
2107 char *cmd,*dev,*args,**keywords;
2108 WORD uDevTyp=0,wDevID=0;
2109 DWORD dwFlags;
2110 int res=0,i,nrofkeywords;
2112 dprintf_mci(stddeb,"mciSendString('%s', %p, %d, %X)\n", lpstrCommand,
2113 lpstrReturnString, uReturnLength, hwndCallback
2115 /* format is <command> <device> <optargs> */
2116 cmd=strdup(lpstrCommand);
2117 dev=strchr(cmd,' ');
2118 if (dev==NULL) {
2119 free(cmd);
2120 return MCIERR_MISSING_DEVICE_NAME;
2122 *dev++='\0';
2123 args=strchr(dev,' ');
2124 if (args!=NULL) *args++='\0';
2125 CharUpper32A(dev);
2126 if (args!=NULL) {
2127 char *s;
2128 i=1;/* nrofkeywords = nrofspaces+1 */
2129 s=args;
2130 while ((s=strchr(s,' '))!=NULL) i++,s++;
2131 keywords=(char**)xmalloc(sizeof(char*)*(i+2));
2132 nrofkeywords=i;
2133 s=args;i=0;
2134 while (s && i<nrofkeywords) {
2135 keywords[i++]=s;
2136 s=strchr(s,' ');
2137 if (s) *s++='\0';
2139 keywords[i]=NULL;
2140 } else {
2141 nrofkeywords=0;
2142 keywords=(char**)xmalloc(sizeof(char*));
2144 dwFlags = 0; /* default flags */
2145 for (i=0;i<nrofkeywords;) {
2146 if (!STRCMP(keywords[i],"wait")) {
2147 dwFlags |= MCI_WAIT;
2148 memcpy(keywords+i,keywords+(i+1),nrofkeywords-i-1);
2149 nrofkeywords--;
2150 continue;
2152 if (!STRCMP(keywords[i],"notify")) {
2153 /* how should we callback? I don't know. */
2154 /*dwFlags |= MCI_NOTIFY;*/
2155 memcpy(keywords+i,keywords+(i+1),nrofkeywords-i-1);
2156 nrofkeywords--;
2157 continue;
2159 i++;
2162 /* determine wDevID and uDevTyp for all commands except "open" */
2163 if (STRCMP(cmd,"open")!=0) {
2164 wDevID = MMSYSTEM_FirstDevID();
2165 while (1) {
2166 SEGPTR dname;
2168 dname=(SEGPTR)GetOpenDrv(wDevID)->lpstrAlias;
2169 if (dname==NULL)
2170 dname=(SEGPTR)GetOpenDrv(wDevID)->lpstrDeviceType;
2171 if ((dname!=NULL)&&(!STRCMP(PTR_SEG_TO_LIN(dname),dev)))
2172 break;
2173 wDevID = MMSYSTEM_NextDevID(wDevID);
2174 if (!MMSYSTEM_DevIDValid(wDevID)) {
2175 dprintf_mci(stddeb, __FILE__":mciSendString:MAXMCIDRIVERS reached!\n");
2176 free(keywords);free(cmd);
2177 return MCIERR_INTERNAL;
2180 uDevTyp=GetDrv(wDevID)->wType;
2183 for (i=0;MCISTR_cmdtable[i].cmd!=NULL;i++) {
2184 if (!STRCMP(MCISTR_cmdtable[i].cmd,cmd)) {
2185 res=MCISTR_cmdtable[i].fun(
2186 wDevID,uDevTyp,lpstrReturnString,
2187 uReturnLength,dev,(LPSTR*)keywords,nrofkeywords,
2188 dwFlags
2190 break;
2193 if (MCISTR_cmdtable[i].cmd!=NULL) {
2194 free(keywords);free(cmd);
2195 return res;
2197 fprintf(stdnimp,"mciSendString('%s', %p, %u, %X) // unimplemented, please report.\n", lpstrCommand,
2198 lpstrReturnString, uReturnLength, hwndCallback
2200 free(keywords);free(cmd);
2201 return MCIERR_MISSING_COMMAND_STRING;