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