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