* Sync up to trunk HEAD (r62286).
[reactos.git] / dll / win32 / mciqtz32 / mciqtz.c
1 /*
2 * DirectShow MCI Driver
3 *
4 * Copyright 2009 Christian Costa
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #define WIN32_NO_STATUS
22 #define WIN32_LEAN_AND_MEAN
23
24 #include <stdarg.h>
25 #include <windef.h>
26 //#include "winbase.h"
27 //#include "winuser.h"
28 #include <mmddk.h>
29 #include <wine/debug.h>
30 #include "mciqtz_private.h"
31 #include <digitalv.h>
32 #include <wownt32.h>
33
34 WINE_DEFAULT_DEBUG_CHANNEL(mciqtz);
35
36 static DWORD MCIQTZ_mciClose(UINT, DWORD, LPMCI_GENERIC_PARMS);
37 static DWORD MCIQTZ_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
38
39 /*======================================================================*
40 * MCI QTZ implementation *
41 *======================================================================*/
42
43 static HINSTANCE MCIQTZ_hInstance = 0;
44
45 /***********************************************************************
46 * DllMain (MCIQTZ.0)
47 */
48 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
49 {
50 switch (fdwReason) {
51 case DLL_PROCESS_ATTACH:
52 DisableThreadLibraryCalls(hInstDLL);
53 MCIQTZ_hInstance = hInstDLL;
54 break;
55 }
56 return TRUE;
57 }
58
59 /**************************************************************************
60 * MCIQTZ_mciGetOpenDev [internal]
61 */
62 static WINE_MCIQTZ* MCIQTZ_mciGetOpenDev(UINT wDevID)
63 {
64 WINE_MCIQTZ* wma = (WINE_MCIQTZ*)mciGetDriverData(wDevID);
65
66 if (!wma) {
67 WARN("Invalid wDevID=%u\n", wDevID);
68 return NULL;
69 }
70 return wma;
71 }
72
73 /**************************************************************************
74 * MCIQTZ_drvOpen [internal]
75 */
76 static DWORD MCIQTZ_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
77 {
78 WINE_MCIQTZ* wma;
79 static const WCHAR mciAviWStr[] = {'M','C','I','A','V','I',0};
80
81 TRACE("(%s, %p)\n", debugstr_w(str), modp);
82
83 /* session instance */
84 if (!modp)
85 return 0xFFFFFFFF;
86
87 wma = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIQTZ));
88 if (!wma)
89 return 0;
90
91 modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
92 wma->wDevID = modp->wDeviceID;
93 modp->wCustomCommandTable = wma->command_table = mciLoadCommandResource(MCIQTZ_hInstance, mciAviWStr, 0);
94 mciSetDriverData(wma->wDevID, (DWORD_PTR)wma);
95
96 return modp->wDeviceID;
97 }
98
99 /**************************************************************************
100 * MCIQTZ_drvClose [internal]
101 */
102 static DWORD MCIQTZ_drvClose(DWORD dwDevID)
103 {
104 WINE_MCIQTZ* wma;
105
106 TRACE("(%04x)\n", dwDevID);
107
108 wma = MCIQTZ_mciGetOpenDev(dwDevID);
109
110 if (wma) {
111 /* finish all outstanding things */
112 MCIQTZ_mciClose(dwDevID, MCI_WAIT, NULL);
113
114 mciFreeCommandResource(wma->command_table);
115 mciSetDriverData(dwDevID, 0);
116 HeapFree(GetProcessHeap(), 0, wma);
117 return 1;
118 }
119
120 return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
121 }
122
123 /**************************************************************************
124 * MCIQTZ_drvConfigure [internal]
125 */
126 static DWORD MCIQTZ_drvConfigure(DWORD dwDevID)
127 {
128 WINE_MCIQTZ* wma;
129
130 TRACE("(%04x)\n", dwDevID);
131
132 wma = MCIQTZ_mciGetOpenDev(dwDevID);
133 if (!wma)
134 return 0;
135
136 MCIQTZ_mciStop(dwDevID, MCI_WAIT, NULL);
137
138 MessageBoxA(0, "Sample QTZ Wine Driver !", "MM-Wine Driver", MB_OK);
139
140 return 1;
141 }
142
143 /***************************************************************************
144 * MCIQTZ_mciOpen [internal]
145 */
146 static DWORD MCIQTZ_mciOpen(UINT wDevID, DWORD dwFlags,
147 LPMCI_DGV_OPEN_PARMSW lpOpenParms)
148 {
149 WINE_MCIQTZ* wma;
150 HRESULT hr;
151 DWORD style = 0;
152 RECT rc = { 0, 0, 0, 0 };
153
154 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpOpenParms);
155
156 if (!lpOpenParms)
157 return MCIERR_NULL_PARAMETER_BLOCK;
158
159 wma = MCIQTZ_mciGetOpenDev(wDevID);
160 if (!wma)
161 return MCIERR_INVALID_DEVICE_ID;
162
163 MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
164
165 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
166 wma->uninit = SUCCEEDED(hr);
167
168 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&wma->pgraph);
169 if (FAILED(hr)) {
170 TRACE("Cannot create filtergraph (hr = %x)\n", hr);
171 goto err;
172 }
173
174 hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IMediaControl, (LPVOID*)&wma->pmctrl);
175 if (FAILED(hr)) {
176 TRACE("Cannot get IMediaControl interface (hr = %x)\n", hr);
177 goto err;
178 }
179
180 hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IMediaSeeking, (void**)&wma->seek);
181 if (FAILED(hr)) {
182 TRACE("Cannot get IMediaSeeking interface (hr = %x)\n", hr);
183 goto err;
184 }
185
186 hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IMediaEvent, (void**)&wma->mevent);
187 if (FAILED(hr)) {
188 TRACE("Cannot get IMediaEvent interface (hr = %x)\n", hr);
189 goto err;
190 }
191
192 hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IVideoWindow, (void**)&wma->vidwin);
193 if (FAILED(hr)) {
194 TRACE("Cannot get IVideoWindow interface (hr = %x)\n", hr);
195 goto err;
196 }
197
198 hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IBasicVideo, (void**)&wma->vidbasic);
199 if (FAILED(hr)) {
200 TRACE("Cannot get IBasicVideo interface (hr = %x)\n", hr);
201 goto err;
202 }
203
204 if (!(dwFlags & MCI_OPEN_ELEMENT) || (dwFlags & MCI_OPEN_ELEMENT_ID)) {
205 TRACE("Wrong dwFlags %x\n", dwFlags);
206 goto err;
207 }
208
209 if (!lpOpenParms->lpstrElementName || !lpOpenParms->lpstrElementName[0]) {
210 TRACE("Invalid filename specified\n");
211 goto err;
212 }
213
214 TRACE("Open file %s\n", debugstr_w(lpOpenParms->lpstrElementName));
215
216 hr = IGraphBuilder_RenderFile(wma->pgraph, lpOpenParms->lpstrElementName, NULL);
217 if (FAILED(hr)) {
218 TRACE("Cannot render file (hr = %x)\n", hr);
219 goto err;
220 }
221
222 IVideoWindow_put_AutoShow(wma->vidwin, OAFALSE);
223 IVideoWindow_put_Visible(wma->vidwin, OAFALSE);
224 if (dwFlags & MCI_DGV_OPEN_WS)
225 style = lpOpenParms->dwStyle;
226 if (dwFlags & MCI_DGV_OPEN_PARENT) {
227 IVideoWindow_put_MessageDrain(wma->vidwin, (OAHWND)lpOpenParms->hWndParent);
228 IVideoWindow_put_WindowState(wma->vidwin, SW_HIDE);
229 IVideoWindow_put_WindowStyle(wma->vidwin, style|WS_CHILD);
230 IVideoWindow_put_Owner(wma->vidwin, (OAHWND)lpOpenParms->hWndParent);
231 GetClientRect(lpOpenParms->hWndParent, &rc);
232 IVideoWindow_SetWindowPosition(wma->vidwin, rc.left, rc.top, rc.right - rc.top, rc.bottom - rc.top);
233 wma->parent = (HWND)lpOpenParms->hWndParent;
234 }
235 else if (style)
236 IVideoWindow_put_WindowStyle(wma->vidwin, style);
237 IBasicVideo_GetVideoSize(wma->vidbasic, &rc.right, &rc.bottom);
238 wma->opened = TRUE;
239
240 if (dwFlags & MCI_NOTIFY)
241 mciDriverNotify(HWND_32(LOWORD(lpOpenParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
242
243 return 0;
244
245 err:
246 if (wma->vidbasic)
247 IBasicVideo_Release(wma->vidbasic);
248 wma->vidbasic = NULL;
249 if (wma->seek)
250 IMediaSeeking_Release(wma->seek);
251 wma->seek = NULL;
252 if (wma->vidwin)
253 IVideoWindow_Release(wma->vidwin);
254 wma->vidwin = NULL;
255 if (wma->pgraph)
256 IGraphBuilder_Release(wma->pgraph);
257 wma->pgraph = NULL;
258 if (wma->mevent)
259 IMediaEvent_Release(wma->mevent);
260 wma->mevent = NULL;
261 if (wma->pmctrl)
262 IMediaControl_Release(wma->pmctrl);
263 wma->pmctrl = NULL;
264
265 if (wma->uninit)
266 CoUninitialize();
267 wma->uninit = 0;
268
269 return MCIERR_INTERNAL;
270 }
271
272 /***************************************************************************
273 * MCIQTZ_mciClose [internal]
274 */
275 static DWORD MCIQTZ_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
276 {
277 WINE_MCIQTZ* wma;
278
279 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
280
281 wma = MCIQTZ_mciGetOpenDev(wDevID);
282 if (!wma)
283 return MCIERR_INVALID_DEVICE_ID;
284
285 MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
286
287 if (wma->opened) {
288 IVideoWindow_Release(wma->vidwin);
289 IBasicVideo_Release(wma->vidbasic);
290 IMediaSeeking_Release(wma->seek);
291 IMediaEvent_Release(wma->mevent);
292 IGraphBuilder_Release(wma->pgraph);
293 IMediaControl_Release(wma->pmctrl);
294 if (wma->uninit)
295 CoUninitialize();
296 wma->opened = FALSE;
297 }
298
299 return 0;
300 }
301
302 /***************************************************************************
303 * MCIQTZ_mciPlay [internal]
304 */
305 static DWORD MCIQTZ_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
306 {
307 WINE_MCIQTZ* wma;
308 HRESULT hr;
309 REFERENCE_TIME time1 = 0, time2 = 0;
310 GUID format;
311 DWORD pos1;
312
313 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
314
315 if (!lpParms)
316 return MCIERR_NULL_PARAMETER_BLOCK;
317
318 wma = MCIQTZ_mciGetOpenDev(wDevID);
319 if (!wma)
320 return MCIERR_INVALID_DEVICE_ID;
321
322 IMediaSeeking_GetTimeFormat(wma->seek, &format);
323 if (dwFlags & MCI_FROM) {
324 if (IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME))
325 time1 = lpParms->dwFrom * 10000;
326 else
327 time1 = lpParms->dwFrom;
328 pos1 = AM_SEEKING_AbsolutePositioning;
329 } else
330 pos1 = AM_SEEKING_NoPositioning;
331 if (dwFlags & MCI_TO) {
332 if (IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME))
333 time2 = lpParms->dwTo * 10000;
334 else
335 time2 = lpParms->dwTo;
336 } else
337 IMediaSeeking_GetDuration(wma->seek, &time2);
338 IMediaSeeking_SetPositions(wma->seek, &time1, pos1, &time2, AM_SEEKING_AbsolutePositioning);
339
340 hr = IMediaControl_Run(wma->pmctrl);
341 if (FAILED(hr)) {
342 TRACE("Cannot run filtergraph (hr = %x)\n", hr);
343 return MCIERR_INTERNAL;
344 }
345
346 IVideoWindow_put_Visible(wma->vidwin, OATRUE);
347
348 if (dwFlags & MCI_NOTIFY)
349 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
350 return 0;
351 }
352
353 /***************************************************************************
354 * MCIQTZ_mciSeek [internal]
355 */
356 static DWORD MCIQTZ_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
357 {
358 WINE_MCIQTZ* wma;
359 HRESULT hr;
360 LONGLONG newpos;
361
362 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
363
364 if (!lpParms)
365 return MCIERR_NULL_PARAMETER_BLOCK;
366
367 wma = MCIQTZ_mciGetOpenDev(wDevID);
368 if (!wma)
369 return MCIERR_INVALID_DEVICE_ID;
370
371 MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
372
373 if (dwFlags & MCI_SEEK_TO_START) {
374 newpos = 0;
375 } else if (dwFlags & MCI_SEEK_TO_END) {
376 FIXME("MCI_SEEK_TO_END not implemented yet\n");
377 return MCIERR_INTERNAL;
378 } else if (dwFlags & MCI_TO) {
379 FIXME("MCI_TO not implemented yet\n");
380 return MCIERR_INTERNAL;
381 } else {
382 WARN("dwFlag doesn't tell where to seek to...\n");
383 return MCIERR_MISSING_PARAMETER;
384 }
385
386 hr = IMediaSeeking_SetPositions(wma->seek, &newpos, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
387 if (FAILED(hr)) {
388 FIXME("Cannot set position (hr = %x)\n", hr);
389 return MCIERR_INTERNAL;
390 }
391
392 if (dwFlags & MCI_NOTIFY)
393 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
394
395 return 0;
396 }
397
398 /***************************************************************************
399 * MCIQTZ_mciStop [internal]
400 */
401 static DWORD MCIQTZ_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
402 {
403 WINE_MCIQTZ* wma;
404 HRESULT hr;
405
406 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
407
408 wma = MCIQTZ_mciGetOpenDev(wDevID);
409 if (!wma)
410 return MCIERR_INVALID_DEVICE_ID;
411
412 if (!wma->opened)
413 return 0;
414
415 hr = IMediaControl_Stop(wma->pmctrl);
416 if (FAILED(hr)) {
417 TRACE("Cannot stop filtergraph (hr = %x)\n", hr);
418 return MCIERR_INTERNAL;
419 }
420
421 if (!wma->parent)
422 IVideoWindow_put_Visible(wma->vidwin, OAFALSE);
423
424 return 0;
425 }
426
427 /***************************************************************************
428 * MCIQTZ_mciPause [internal]
429 */
430 static DWORD MCIQTZ_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
431 {
432 WINE_MCIQTZ* wma;
433 HRESULT hr;
434
435 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
436
437 wma = MCIQTZ_mciGetOpenDev(wDevID);
438 if (!wma)
439 return MCIERR_INVALID_DEVICE_ID;
440
441 hr = IMediaControl_Pause(wma->pmctrl);
442 if (FAILED(hr)) {
443 TRACE("Cannot pause filtergraph (hr = %x)\n", hr);
444 return MCIERR_INTERNAL;
445 }
446
447 return 0;
448 }
449
450 /***************************************************************************
451 * MCIQTZ_mciGetDevCaps [internal]
452 */
453 static DWORD MCIQTZ_mciGetDevCaps(UINT wDevID, DWORD dwFlags, LPMCI_GETDEVCAPS_PARMS lpParms)
454 {
455 WINE_MCIQTZ* wma;
456
457 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
458
459 if (!lpParms)
460 return MCIERR_NULL_PARAMETER_BLOCK;
461
462 wma = MCIQTZ_mciGetOpenDev(wDevID);
463 if (!wma)
464 return MCIERR_INVALID_DEVICE_ID;
465
466 if (!(dwFlags & MCI_GETDEVCAPS_ITEM))
467 return MCIERR_MISSING_PARAMETER;
468
469 switch (lpParms->dwItem) {
470 case MCI_GETDEVCAPS_CAN_RECORD:
471 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
472 TRACE("MCI_GETDEVCAPS_CAN_RECORD = %08x\n", lpParms->dwReturn);
473 break;
474 case MCI_GETDEVCAPS_HAS_AUDIO:
475 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
476 TRACE("MCI_GETDEVCAPS_HAS_AUDIO = %08x\n", lpParms->dwReturn);
477 break;
478 case MCI_GETDEVCAPS_HAS_VIDEO:
479 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
480 TRACE("MCI_GETDEVCAPS_HAS_VIDEO = %08x\n", lpParms->dwReturn);
481 break;
482 case MCI_GETDEVCAPS_DEVICE_TYPE:
483 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_DIGITAL_VIDEO, MCI_DEVTYPE_DIGITAL_VIDEO);
484 TRACE("MCI_GETDEVCAPS_DEVICE_TYPE = %08x\n", lpParms->dwReturn);
485 break;
486 case MCI_GETDEVCAPS_USES_FILES:
487 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
488 TRACE("MCI_GETDEVCAPS_USES_FILES = %08x\n", lpParms->dwReturn);
489 break;
490 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
491 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
492 TRACE("MCI_GETDEVCAPS_COMPOUND_DEVICE = %08x\n", lpParms->dwReturn);
493 break;
494 case MCI_GETDEVCAPS_CAN_EJECT:
495 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
496 TRACE("MCI_GETDEVCAPS_EJECT = %08x\n", lpParms->dwReturn);
497 break;
498 case MCI_GETDEVCAPS_CAN_PLAY:
499 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
500 TRACE("MCI_GETDEVCAPS_CAN_PLAY = %08x\n", lpParms->dwReturn);
501 break;
502 case MCI_GETDEVCAPS_CAN_SAVE:
503 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
504 TRACE("MCI_GETDEVCAPS_CAN_SAVE = %08x\n", lpParms->dwReturn);
505 break;
506 case MCI_DGV_GETDEVCAPS_CAN_REVERSE:
507 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
508 TRACE("MCI_DGV_GETDEVCAPS_CAN_REVERSE = %08x\n", lpParms->dwReturn);
509 break;
510 case MCI_DGV_GETDEVCAPS_CAN_STRETCH:
511 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); /* FIXME */
512 TRACE("MCI_DGV_GETDEVCAPS_CAN_STRETCH = %08x\n", lpParms->dwReturn);
513 break;
514 case MCI_DGV_GETDEVCAPS_CAN_LOCK:
515 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
516 TRACE("MCI_DGV_GETDEVCAPS_CAN_LOCK = %08x\n", lpParms->dwReturn);
517 break;
518 case MCI_DGV_GETDEVCAPS_CAN_FREEZE:
519 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
520 TRACE("MCI_DGV_GETDEVCAPS_CAN_FREEZE = %08x\n", lpParms->dwReturn);
521 break;
522 case MCI_DGV_GETDEVCAPS_CAN_STR_IN:
523 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
524 TRACE("MCI_DGV_GETDEVCAPS_CAN_STRETCH_INPUT = %08x\n", lpParms->dwReturn);
525 break;
526 case MCI_DGV_GETDEVCAPS_HAS_STILL:
527 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
528 TRACE("MCI_DGV_GETDEVCAPS_HAS_STILL = %08x\n", lpParms->dwReturn);
529 break;
530 case MCI_DGV_GETDEVCAPS_CAN_TEST:
531 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); /* FIXME */
532 TRACE("MCI_DGV_GETDEVCAPS_CAN_TEST = %08x\n", lpParms->dwReturn);
533 break;
534 case MCI_DGV_GETDEVCAPS_MAX_WINDOWS:
535 lpParms->dwReturn = 1;
536 TRACE("MCI_DGV_GETDEVCAPS_MAX_WINDOWS = %u\n", lpParms->dwReturn);
537 return 0;
538 default:
539 WARN("Unknown capability %08x\n", lpParms->dwItem);
540 /* Fall through */
541 case MCI_DGV_GETDEVCAPS_MAXIMUM_RATE: /* unknown to w2k */
542 case MCI_DGV_GETDEVCAPS_MINIMUM_RATE: /* unknown to w2k */
543 return MCIERR_UNSUPPORTED_FUNCTION;
544 }
545
546 return MCI_RESOURCE_RETURNED;
547 }
548
549 /***************************************************************************
550 * MCIQTZ_mciSet [internal]
551 */
552 static DWORD MCIQTZ_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SET_PARMS lpParms)
553 {
554 WINE_MCIQTZ* wma;
555
556 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
557
558 if (!lpParms)
559 return MCIERR_NULL_PARAMETER_BLOCK;
560
561 wma = MCIQTZ_mciGetOpenDev(wDevID);
562 if (!wma)
563 return MCIERR_INVALID_DEVICE_ID;
564
565 if (dwFlags & MCI_SET_TIME_FORMAT) {
566 switch (lpParms->dwTimeFormat) {
567 case MCI_FORMAT_MILLISECONDS:
568 TRACE("MCI_SET_TIME_FORMAT = MCI_FORMAT_MILLISECONDS\n");
569 wma->time_format = MCI_FORMAT_MILLISECONDS;
570 break;
571 case MCI_FORMAT_FRAMES:
572 TRACE("MCI_SET_TIME_FORMAT = MCI_FORMAT_FRAMES\n");
573 wma->time_format = MCI_FORMAT_FRAMES;
574 break;
575 default:
576 WARN("Bad time format %u\n", lpParms->dwTimeFormat);
577 return MCIERR_BAD_TIME_FORMAT;
578 }
579 }
580
581 if (dwFlags & MCI_SET_DOOR_OPEN)
582 FIXME("MCI_SET_DOOR_OPEN not implemented yet\n");
583 if (dwFlags & MCI_SET_DOOR_CLOSED)
584 FIXME("MCI_SET_DOOR_CLOSED not implemented yet\n");
585 if (dwFlags & MCI_SET_AUDIO)
586 FIXME("MCI_SET_AUDIO not implemented yet\n");
587 if (dwFlags & MCI_SET_VIDEO)
588 FIXME("MCI_SET_VIDEO not implemented yet\n");
589 if (dwFlags & MCI_SET_ON)
590 FIXME("MCI_SET_ON not implemented yet\n");
591 if (dwFlags & MCI_SET_OFF)
592 FIXME("MCI_SET_OFF not implemented yet\n");
593 if (dwFlags & MCI_SET_AUDIO_LEFT)
594 FIXME("MCI_SET_AUDIO_LEFT not implemented yet\n");
595 if (dwFlags & MCI_SET_AUDIO_RIGHT)
596 FIXME("MCI_SET_AUDIO_RIGHT not implemented yet\n");
597
598 if (dwFlags & ~0x7f03 /* All MCI_SET flags mask */)
599 ERR("Unknown flags %08x\n", dwFlags & ~0x7f03);
600
601 return 0;
602 }
603
604 /***************************************************************************
605 * MCIQTZ_mciStatus [internal]
606 */
607 static DWORD MCIQTZ_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STATUS_PARMSW lpParms)
608 {
609 WINE_MCIQTZ* wma;
610 HRESULT hr;
611
612 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
613
614 if (!lpParms)
615 return MCIERR_NULL_PARAMETER_BLOCK;
616
617 wma = MCIQTZ_mciGetOpenDev(wDevID);
618 if (!wma)
619 return MCIERR_INVALID_DEVICE_ID;
620
621 if (!(dwFlags & MCI_STATUS_ITEM)) {
622 WARN("No status item specified\n");
623 return MCIERR_UNRECOGNIZED_COMMAND;
624 }
625
626 switch (lpParms->dwItem) {
627 case MCI_STATUS_LENGTH: {
628 LONGLONG duration = -1;
629 GUID format;
630 switch (wma->time_format) {
631 case MCI_FORMAT_MILLISECONDS: format = TIME_FORMAT_MEDIA_TIME; break;
632 case MCI_FORMAT_FRAMES: format = TIME_FORMAT_FRAME; break;
633 default: ERR("Unhandled format %x\n", wma->time_format); break;
634 }
635 hr = IMediaSeeking_SetTimeFormat(wma->seek, &format);
636 if (FAILED(hr)) {
637 FIXME("Cannot set time format (hr = %x)\n", hr);
638 lpParms->dwReturn = 0;
639 break;
640 }
641 hr = IMediaSeeking_GetDuration(wma->seek, &duration);
642 if (FAILED(hr) || duration < 0) {
643 FIXME("Cannot read duration (hr = %x)\n", hr);
644 lpParms->dwReturn = 0;
645 } else if (wma->time_format != MCI_FORMAT_MILLISECONDS)
646 lpParms->dwReturn = duration;
647 else
648 lpParms->dwReturn = duration / 10000;
649 break;
650 }
651 case MCI_STATUS_POSITION: {
652 REFERENCE_TIME curpos;
653
654 hr = IMediaSeeking_GetCurrentPosition(wma->seek, &curpos);
655 if (FAILED(hr)) {
656 FIXME("Cannot get position (hr = %x)\n", hr);
657 return MCIERR_INTERNAL;
658 }
659 lpParms->dwReturn = curpos / 10000;
660 break;
661 }
662 case MCI_STATUS_NUMBER_OF_TRACKS:
663 FIXME("MCI_STATUS_NUMBER_OF_TRACKS not implemented yet\n");
664 return MCIERR_UNRECOGNIZED_COMMAND;
665 case MCI_STATUS_MODE: {
666 LONG state = State_Stopped;
667 IMediaControl_GetState(wma->pmctrl, -1, &state);
668 if (state == State_Stopped)
669 lpParms->dwReturn = MCI_MODE_STOP;
670 else if (state == State_Running) {
671 LONG code;
672 LONG_PTR p1, p2;
673
674 lpParms->dwReturn = MCI_MODE_PLAY;
675
676 do {
677 hr = IMediaEvent_GetEvent(wma->mevent, &code, &p1, &p2, 0);
678 if (hr == S_OK && code == EC_COMPLETE){
679 lpParms->dwReturn = MCI_MODE_STOP;
680 IMediaControl_Stop(wma->pmctrl);
681 }
682 } while (hr == S_OK);
683
684 } else if (state == State_Paused)
685 lpParms->dwReturn = MCI_MODE_PAUSE;
686 break;
687 }
688 case MCI_STATUS_MEDIA_PRESENT:
689 FIXME("MCI_STATUS_MEDIA_PRESENT not implemented yet\n");
690 return MCIERR_UNRECOGNIZED_COMMAND;
691 case MCI_STATUS_TIME_FORMAT:
692 lpParms->dwReturn = wma->time_format;
693 break;
694 case MCI_STATUS_READY:
695 FIXME("MCI_STATUS_READY not implemented yet\n");
696 return MCIERR_UNRECOGNIZED_COMMAND;
697 case MCI_STATUS_CURRENT_TRACK:
698 FIXME("MCI_STATUS_CURRENT_TRACK not implemented yet\n");
699 return MCIERR_UNRECOGNIZED_COMMAND;
700 default:
701 FIXME("Unknown command %08X\n", lpParms->dwItem);
702 return MCIERR_UNRECOGNIZED_COMMAND;
703 }
704
705 if (dwFlags & MCI_NOTIFY)
706 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
707
708 return 0;
709 }
710
711 /***************************************************************************
712 * MCIQTZ_mciWhere [internal]
713 */
714 static DWORD MCIQTZ_mciWhere(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
715 {
716 WINE_MCIQTZ* wma;
717 HRESULT hr;
718 HWND hWnd;
719 RECT rc;
720 DWORD ret = MCIERR_UNRECOGNIZED_COMMAND;
721
722 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
723
724 if (!lpParms)
725 return MCIERR_NULL_PARAMETER_BLOCK;
726
727 wma = MCIQTZ_mciGetOpenDev(wDevID);
728 if (!wma)
729 return MCIERR_INVALID_DEVICE_ID;
730
731 hr = IVideoWindow_get_Owner(wma->vidwin, (OAHWND*)&hWnd);
732 if (FAILED(hr)) {
733 TRACE("No video stream, returning no window error\n");
734 return MCIERR_NO_WINDOW;
735 }
736
737 if (dwFlags & MCI_DGV_WHERE_SOURCE) {
738 if (dwFlags & MCI_DGV_WHERE_MAX)
739 FIXME("MCI_DGV_WHERE_SOURCE_MAX stub %s\n", wine_dbgstr_rect(&rc));
740 IBasicVideo_GetSourcePosition(wma->vidbasic, &rc.left, &rc.top, &rc.right, &rc.bottom);
741 TRACE("MCI_DGV_WHERE_SOURCE %s\n", wine_dbgstr_rect(&rc));
742 }
743 if (dwFlags & MCI_DGV_WHERE_DESTINATION) {
744 if (dwFlags & MCI_DGV_WHERE_MAX)
745 FIXME("MCI_DGV_WHERE_DESTINATION_MAX stub %s\n", wine_dbgstr_rect(&rc));
746 IBasicVideo_GetDestinationPosition(wma->vidbasic, &rc.left, &rc.top, &rc.right, &rc.bottom);
747 TRACE("MCI_DGV_WHERE_DESTINATION %s\n", wine_dbgstr_rect(&rc));
748 }
749 if (dwFlags & MCI_DGV_WHERE_FRAME) {
750 if (dwFlags & MCI_DGV_WHERE_MAX)
751 FIXME("MCI_DGV_WHERE_FRAME_MAX not supported yet\n");
752 else
753 FIXME("MCI_DGV_WHERE_FRAME not supported yet\n");
754 goto out;
755 }
756 if (dwFlags & MCI_DGV_WHERE_VIDEO) {
757 if (dwFlags & MCI_DGV_WHERE_MAX)
758 FIXME("MCI_DGV_WHERE_VIDEO_MAX not supported yet\n");
759 else
760 FIXME("MCI_DGV_WHERE_VIDEO not supported yet\n");
761 goto out;
762 }
763 if (dwFlags & MCI_DGV_WHERE_WINDOW) {
764 if (dwFlags & MCI_DGV_WHERE_MAX) {
765 GetWindowRect(GetDesktopWindow(), &rc);
766 rc.right -= rc.left;
767 rc.bottom -= rc.top;
768 TRACE("MCI_DGV_WHERE_WINDOW_MAX %s\n", wine_dbgstr_rect(&rc));
769 } else {
770 IVideoWindow_GetWindowPosition(wma->vidwin, &rc.left, &rc.top, &rc.right, &rc.bottom);
771 TRACE("MCI_DGV_WHERE_WINDOW %s\n", wine_dbgstr_rect(&rc));
772 }
773 }
774 ret = 0;
775 out:
776 lpParms->rc = rc;
777 return ret;
778 }
779
780 /***************************************************************************
781 * MCIQTZ_mciWindow [internal]
782 */
783 static DWORD MCIQTZ_mciWindow(UINT wDevID, DWORD dwFlags, LPMCI_DGV_WINDOW_PARMSW lpParms)
784 {
785 WINE_MCIQTZ *wma = MCIQTZ_mciGetOpenDev(wDevID);
786
787 TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
788
789 if (!lpParms)
790 return MCIERR_NULL_PARAMETER_BLOCK;
791 if (!wma)
792 return MCIERR_INVALID_DEVICE_ID;
793 if (dwFlags & MCI_TEST)
794 return 0;
795
796 if (dwFlags & MCI_DGV_WINDOW_HWND && (IsWindow(lpParms->hWnd) || !lpParms->hWnd)) {
797 LONG visible = OATRUE;
798 LONG style = 0;
799 TRACE("Setting hWnd to %p\n", lpParms->hWnd);
800 IVideoWindow_get_Visible(wma->vidwin, &visible);
801 IVideoWindow_put_Visible(wma->vidwin, OAFALSE);
802 IVideoWindow_get_WindowStyle(wma->vidwin, &style);
803 style &= ~WS_CHILD;
804 if (lpParms->hWnd)
805 IVideoWindow_put_WindowStyle(wma->vidwin, style|WS_CHILD);
806 else
807 IVideoWindow_put_WindowStyle(wma->vidwin, style);
808 IVideoWindow_put_Owner(wma->vidwin, (OAHWND)lpParms->hWnd);
809 IVideoWindow_put_MessageDrain(wma->vidwin, (OAHWND)lpParms->hWnd);
810 IVideoWindow_put_Visible(wma->vidwin, visible);
811 wma->parent = lpParms->hWnd;
812 }
813 if (dwFlags & MCI_DGV_WINDOW_STATE) {
814 TRACE("Setting nCmdShow to %d\n", lpParms->nCmdShow);
815 IVideoWindow_put_WindowState(wma->vidwin, lpParms->nCmdShow);
816 }
817 if (dwFlags & MCI_DGV_WINDOW_TEXT) {
818 TRACE("Setting caption to %s\n", debugstr_w(lpParms->lpstrText));
819 IVideoWindow_put_Caption(wma->vidwin, lpParms->lpstrText);
820 }
821 return 0;
822 }
823
824 /******************************************************************************
825 * MCIAVI_mciUpdate [internal]
826 */
827 static DWORD MCIQTZ_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
828 {
829 WINE_MCIQTZ *wma;
830 DWORD res = 0;
831
832 TRACE("%04x, %08x, %p\n", wDevID, dwFlags, lpParms);
833
834 if (!lpParms)
835 return MCIERR_NULL_PARAMETER_BLOCK;
836
837 wma = MCIQTZ_mciGetOpenDev(wDevID);
838 if (!wma)
839 return MCIERR_INVALID_DEVICE_ID;
840
841 if (dwFlags & MCI_DGV_UPDATE_HDC) {
842 LONG state, size;
843 BYTE *data;
844 BITMAPINFO *info;
845 HRESULT hr;
846 RECT src, dest;
847 LONG visible = OATRUE;
848
849 res = MCIERR_INTERNAL;
850 IMediaControl_GetState(wma->pmctrl, -1, &state);
851 if (state == State_Running)
852 return MCIERR_UNSUPPORTED_FUNCTION;
853 /* If in stopped state, nothing has been drawn to screen
854 * moving to pause, which is needed for the old dib renderer, will result
855 * in a single frame drawn, so hide the window here */
856 IVideoWindow_get_Visible(wma->vidwin, &visible);
857 if (wma->parent)
858 IVideoWindow_put_Visible(wma->vidwin, OAFALSE);
859 /* FIXME: Should we check the original state and restore it? */
860 IMediaControl_Pause(wma->pmctrl);
861 IMediaControl_GetState(wma->pmctrl, -1, &state);
862 if (FAILED(hr = IBasicVideo_GetCurrentImage(wma->vidbasic, &size, NULL))) {
863 WARN("Could not get image size (hr = %x)\n", hr);
864 goto out;
865 }
866 data = HeapAlloc(GetProcessHeap(), 0, size);
867 info = (BITMAPINFO*)data;
868 IBasicVideo_GetCurrentImage(wma->vidbasic, &size, (LONG*)data);
869 data += info->bmiHeader.biSize;
870
871 IBasicVideo_GetSourcePosition(wma->vidbasic, &src.left, &src.top, &src.right, &src.bottom);
872 IBasicVideo_GetDestinationPosition(wma->vidbasic, &dest.left, &dest.top, &dest.right, &dest.bottom);
873 StretchDIBits(lpParms->hDC,
874 dest.left, dest.top, dest.right + dest.left, dest.bottom + dest.top,
875 src.left, src.top, src.right + src.left, src.bottom + src.top,
876 data, info, DIB_RGB_COLORS, SRCCOPY);
877 HeapFree(GetProcessHeap(), 0, data);
878 res = 0;
879 out:
880 if (wma->parent)
881 IVideoWindow_put_Visible(wma->vidwin, visible);
882 }
883 else if (dwFlags)
884 FIXME("Unhandled flags %x\n", dwFlags);
885 return res;
886 }
887
888 /***************************************************************************
889 * MCIQTZ_mciSetAudio [internal]
890 */
891 static DWORD MCIQTZ_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
892 {
893 WINE_MCIQTZ *wma;
894
895 FIXME("(%04x, %08x, %p) : stub\n", wDevID, dwFlags, lpParms);
896
897 if (!lpParms)
898 return MCIERR_NULL_PARAMETER_BLOCK;
899
900 wma = MCIQTZ_mciGetOpenDev(wDevID);
901 if (!wma)
902 return MCIERR_INVALID_DEVICE_ID;
903
904 MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
905
906 return 0;
907 }
908
909 /*======================================================================*
910 * MCI QTZ entry points *
911 *======================================================================*/
912
913 /**************************************************************************
914 * DriverProc (MCIQTZ.@)
915 */
916 LRESULT CALLBACK MCIQTZ_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
917 LPARAM dwParam1, LPARAM dwParam2)
918 {
919 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
920 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
921
922 switch (wMsg) {
923 case DRV_LOAD: return 1;
924 case DRV_FREE: return 1;
925 case DRV_OPEN: return MCIQTZ_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
926 case DRV_CLOSE: return MCIQTZ_drvClose(dwDevID);
927 case DRV_ENABLE: return 1;
928 case DRV_DISABLE: return 1;
929 case DRV_QUERYCONFIGURE: return 1;
930 case DRV_CONFIGURE: return MCIQTZ_drvConfigure(dwDevID);
931 case DRV_INSTALL: return DRVCNF_RESTART;
932 case DRV_REMOVE: return DRVCNF_RESTART;
933 }
934
935 /* session instance */
936 if (dwDevID == 0xFFFFFFFF)
937 return 1;
938
939 switch (wMsg) {
940 case MCI_OPEN_DRIVER: return MCIQTZ_mciOpen (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSW) dwParam2);
941 case MCI_CLOSE_DRIVER: return MCIQTZ_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
942 case MCI_PLAY: return MCIQTZ_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
943 case MCI_SEEK: return MCIQTZ_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
944 case MCI_STOP: return MCIQTZ_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
945 case MCI_PAUSE: return MCIQTZ_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
946 case MCI_GETDEVCAPS: return MCIQTZ_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
947 case MCI_SET: return MCIQTZ_mciSet (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS) dwParam2);
948 case MCI_STATUS: return MCIQTZ_mciStatus (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW) dwParam2);
949 case MCI_WHERE: return MCIQTZ_mciWhere (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS) dwParam2);
950 /* Digital Video specific */
951 case MCI_SETAUDIO: return MCIQTZ_mciSetAudio (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
952 case MCI_UPDATE:
953 return MCIQTZ_mciUpdate(dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)dwParam2);
954 case MCI_WINDOW:
955 return MCIQTZ_mciWindow(dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSW)dwParam2);
956 case MCI_PUT:
957 case MCI_RECORD:
958 case MCI_RESUME:
959 case MCI_INFO:
960 case MCI_LOAD:
961 case MCI_SAVE:
962 case MCI_FREEZE:
963 case MCI_REALIZE:
964 case MCI_UNFREEZE:
965 case MCI_STEP:
966 case MCI_COPY:
967 case MCI_CUT:
968 case MCI_DELETE:
969 case MCI_PASTE:
970 case MCI_CUE:
971 /* Digital Video specific */
972 case MCI_CAPTURE:
973 case MCI_MONITOR:
974 case MCI_RESERVE:
975 case MCI_SIGNAL:
976 case MCI_SETVIDEO:
977 case MCI_QUALITY:
978 case MCI_LIST:
979 case MCI_UNDO:
980 case MCI_CONFIGURE:
981 case MCI_RESTORE:
982 FIXME("Unimplemented command [%08X]\n", wMsg);
983 break;
984 case MCI_SPIN:
985 case MCI_ESCAPE:
986 WARN("Unsupported command [%08X]\n", wMsg);
987 break;
988 case MCI_OPEN:
989 case MCI_CLOSE:
990 FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
991 break;
992 default:
993 TRACE("Sending msg [%08X] to default driver proc\n", wMsg);
994 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
995 }
996
997 return MCIERR_UNRECOGNIZED_COMMAND;
998 }