xref: /reactos/dll/win32/mciqtz32/mciqtz.c (revision 7abc8be1)
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 <math.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "mmddk.h"
27 #include "wine/debug.h"
28 #include "mciqtz_private.h"
29 #include "digitalv.h"
30 #include "wownt32.h"
31 
32 WINE_DEFAULT_DEBUG_CHANNEL(mciqtz);
33 
34 static DWORD MCIQTZ_mciClose(UINT, DWORD, LPMCI_GENERIC_PARMS);
35 static DWORD MCIQTZ_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
36 
37 /*======================================================================*
38  *                          MCI QTZ implementation                      *
39  *======================================================================*/
40 
41 static HINSTANCE MCIQTZ_hInstance = 0;
42 
43 /***********************************************************************
44  *              DllMain (MCIQTZ.0)
45  */
46 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
47 {
48     switch (fdwReason) {
49     case DLL_PROCESS_ATTACH:
50         DisableThreadLibraryCalls(hInstDLL);
51         MCIQTZ_hInstance = hInstDLL;
52         break;
53     }
54     return TRUE;
55 }
56 
57 /**************************************************************************
58  *                              MCIQTZ_mciGetOpenDev            [internal]
59  */
60 static WINE_MCIQTZ* MCIQTZ_mciGetOpenDev(UINT wDevID)
61 {
62     WINE_MCIQTZ* wma = (WINE_MCIQTZ*)mciGetDriverData(wDevID);
63 
64     if (!wma) {
65         WARN("Invalid wDevID=%u\n", wDevID);
66         return NULL;
67     }
68     return wma;
69 }
70 
71 /**************************************************************************
72  *                              MCIQTZ_drvOpen                  [internal]
73  */
74 static DWORD MCIQTZ_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
75 {
76     WINE_MCIQTZ* wma;
77     static const WCHAR mciAviWStr[] = {'M','C','I','A','V','I',0};
78 
79     TRACE("(%s, %p)\n", debugstr_w(str), modp);
80 
81     /* session instance */
82     if (!modp)
83         return 0xFFFFFFFF;
84 
85     wma = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIQTZ));
86     if (!wma)
87         return 0;
88 
89     wma->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
90     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
91     wma->wDevID = modp->wDeviceID;
92     modp->wCustomCommandTable = wma->command_table = mciLoadCommandResource(MCIQTZ_hInstance, mciAviWStr, 0);
93     mciSetDriverData(wma->wDevID, (DWORD_PTR)wma);
94 
95     return modp->wDeviceID;
96 }
97 
98 /**************************************************************************
99  *                              MCIQTZ_drvClose         [internal]
100  */
101 static DWORD MCIQTZ_drvClose(DWORD dwDevID)
102 {
103     WINE_MCIQTZ* wma;
104 
105     TRACE("(%04x)\n", dwDevID);
106 
107     wma = MCIQTZ_mciGetOpenDev(dwDevID);
108 
109     if (wma) {
110         /* finish all outstanding things */
111         MCIQTZ_mciClose(dwDevID, MCI_WAIT, NULL);
112 
113         mciFreeCommandResource(wma->command_table);
114         mciSetDriverData(dwDevID, 0);
115         CloseHandle(wma->stop_event);
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_mciNotify                [internal]
145  *
146  * Notifications in MCI work like a 1-element queue.
147  * Each new notification request supersedes the previous one.
148  */
149 static void MCIQTZ_mciNotify(DWORD_PTR hWndCallBack, WINE_MCIQTZ* wma, UINT wStatus)
150 {
151     MCIDEVICEID wDevID = wma->notify_devid;
152     HANDLE old = InterlockedExchangePointer(&wma->callback, NULL);
153     if (old) mciDriverNotify(old, wDevID, MCI_NOTIFY_SUPERSEDED);
154     mciDriverNotify(HWND_32(LOWORD(hWndCallBack)), wDevID, wStatus);
155 }
156 
157 /***************************************************************************
158  *                              MCIQTZ_mciOpen                  [internal]
159  */
160 static DWORD MCIQTZ_mciOpen(UINT wDevID, DWORD dwFlags,
161                             LPMCI_DGV_OPEN_PARMSW lpOpenParms)
162 {
163     WINE_MCIQTZ* wma;
164     HRESULT hr;
165     DWORD style = 0;
166     RECT rc = { 0, 0, 0, 0 };
167 
168     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpOpenParms);
169 
170     if(!lpOpenParms)
171         return MCIERR_NULL_PARAMETER_BLOCK;
172 
173     wma = MCIQTZ_mciGetOpenDev(wDevID);
174     if (!wma)
175         return MCIERR_INVALID_DEVICE_ID;
176 
177     MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
178 
179     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
180     wma->uninit = SUCCEEDED(hr);
181 
182     hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&wma->pgraph);
183     if (FAILED(hr)) {
184         TRACE("Cannot create filtergraph (hr = %x)\n", hr);
185         goto err;
186     }
187 
188     hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IMediaControl, (LPVOID*)&wma->pmctrl);
189     if (FAILED(hr)) {
190         TRACE("Cannot get IMediaControl interface (hr = %x)\n", hr);
191         goto err;
192     }
193 
194     hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IMediaSeeking, (void**)&wma->seek);
195     if (FAILED(hr)) {
196         TRACE("Cannot get IMediaSeeking interface (hr = %x)\n", hr);
197         goto err;
198     }
199 
200     hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IMediaEvent, (void**)&wma->mevent);
201     if (FAILED(hr)) {
202         TRACE("Cannot get IMediaEvent interface (hr = %x)\n", hr);
203         goto err;
204     }
205 
206     hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IVideoWindow, (void**)&wma->vidwin);
207     if (FAILED(hr)) {
208         TRACE("Cannot get IVideoWindow interface (hr = %x)\n", hr);
209         goto err;
210     }
211 
212     hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IBasicVideo, (void**)&wma->vidbasic);
213     if (FAILED(hr)) {
214         TRACE("Cannot get IBasicVideo interface (hr = %x)\n", hr);
215         goto err;
216     }
217 
218     hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IBasicAudio, (void**)&wma->audio);
219     if (FAILED(hr)) {
220         TRACE("Cannot get IBasicAudio interface (hr = %x)\n", hr);
221         goto err;
222     }
223 
224     if (!(dwFlags & MCI_OPEN_ELEMENT) || (dwFlags & MCI_OPEN_ELEMENT_ID)) {
225         TRACE("Wrong dwFlags %x\n", dwFlags);
226         goto err;
227     }
228 
229     if (!lpOpenParms->lpstrElementName || !lpOpenParms->lpstrElementName[0]) {
230         TRACE("Invalid filename specified\n");
231         goto err;
232     }
233 
234     TRACE("Open file %s\n", debugstr_w(lpOpenParms->lpstrElementName));
235 
236     hr = IGraphBuilder_RenderFile(wma->pgraph, lpOpenParms->lpstrElementName, NULL);
237     if (FAILED(hr)) {
238         TRACE("Cannot render file (hr = %x)\n", hr);
239         goto err;
240     }
241 
242     IVideoWindow_put_AutoShow(wma->vidwin, OAFALSE);
243     IVideoWindow_put_Visible(wma->vidwin, OAFALSE);
244     if (dwFlags & MCI_DGV_OPEN_WS)
245         style = lpOpenParms->dwStyle;
246     if (dwFlags & MCI_DGV_OPEN_PARENT) {
247         IVideoWindow_put_MessageDrain(wma->vidwin, (OAHWND)lpOpenParms->hWndParent);
248         IVideoWindow_put_WindowState(wma->vidwin, SW_HIDE);
249         IVideoWindow_put_WindowStyle(wma->vidwin, style|WS_CHILD);
250         IVideoWindow_put_Owner(wma->vidwin, (OAHWND)lpOpenParms->hWndParent);
251         GetClientRect(lpOpenParms->hWndParent, &rc);
252         IVideoWindow_SetWindowPosition(wma->vidwin, rc.left, rc.top, rc.right - rc.top, rc.bottom - rc.top);
253         wma->parent = (HWND)lpOpenParms->hWndParent;
254     }
255     else if (style)
256         IVideoWindow_put_WindowStyle(wma->vidwin, style);
257     IBasicVideo_GetVideoSize(wma->vidbasic, &rc.right, &rc.bottom);
258     wma->opened = TRUE;
259 
260     if (dwFlags & MCI_NOTIFY)
261         mciDriverNotify(HWND_32(LOWORD(lpOpenParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
262 
263     return 0;
264 
265 err:
266     if (wma->audio)
267         IBasicAudio_Release(wma->audio);
268     wma->audio = NULL;
269     if (wma->vidbasic)
270         IBasicVideo_Release(wma->vidbasic);
271     wma->vidbasic = NULL;
272     if (wma->seek)
273         IMediaSeeking_Release(wma->seek);
274     wma->seek = NULL;
275     if (wma->vidwin)
276         IVideoWindow_Release(wma->vidwin);
277     wma->vidwin = NULL;
278     if (wma->pgraph)
279         IGraphBuilder_Release(wma->pgraph);
280     wma->pgraph = NULL;
281     if (wma->mevent)
282         IMediaEvent_Release(wma->mevent);
283     wma->mevent = NULL;
284     if (wma->pmctrl)
285         IMediaControl_Release(wma->pmctrl);
286     wma->pmctrl = NULL;
287 
288     if (wma->uninit)
289         CoUninitialize();
290     wma->uninit = FALSE;
291 
292     return MCIERR_INTERNAL;
293 }
294 
295 /***************************************************************************
296  *                              MCIQTZ_mciClose                 [internal]
297  */
298 static DWORD MCIQTZ_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
299 {
300     WINE_MCIQTZ* wma;
301 
302     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
303 
304     wma = MCIQTZ_mciGetOpenDev(wDevID);
305     if (!wma)
306         return MCIERR_INVALID_DEVICE_ID;
307 
308     MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
309 
310     if (wma->opened) {
311         IVideoWindow_Release(wma->vidwin);
312         IBasicVideo_Release(wma->vidbasic);
313         IBasicAudio_Release(wma->audio);
314         IMediaSeeking_Release(wma->seek);
315         IMediaEvent_Release(wma->mevent);
316         IGraphBuilder_Release(wma->pgraph);
317         IMediaControl_Release(wma->pmctrl);
318         if (wma->uninit)
319             CoUninitialize();
320         wma->opened = FALSE;
321     }
322 
323     return 0;
324 }
325 
326 /***************************************************************************
327  *                              MCIQTZ_notifyThread             [internal]
328  */
329 static DWORD CALLBACK MCIQTZ_notifyThread(LPVOID parm)
330 {
331     WINE_MCIQTZ* wma = (WINE_MCIQTZ *)parm;
332     HRESULT hr;
333     HANDLE handle[2];
334     DWORD n = 0, ret = 0;
335 
336     handle[n++] = wma->stop_event;
337     IMediaEvent_GetEventHandle(wma->mevent, (OAEVENT *)&handle[n++]);
338 
339     for (;;) {
340         DWORD r;
341         HANDLE old;
342 
343         r = WaitForMultipleObjects(n, handle, FALSE, INFINITE);
344         if (r == WAIT_OBJECT_0) {
345             TRACE("got stop event\n");
346             old = InterlockedExchangePointer(&wma->callback, NULL);
347             if (old)
348                 mciDriverNotify(old, wma->notify_devid, MCI_NOTIFY_ABORTED);
349             break;
350         }
351         else if (r == WAIT_OBJECT_0+1) {
352             LONG event_code;
353             LONG_PTR p1, p2;
354             do {
355                 hr = IMediaEvent_GetEvent(wma->mevent, &event_code, &p1, &p2, 0);
356                 if (SUCCEEDED(hr)) {
357                     TRACE("got event_code = 0x%02x\n", event_code);
358                     IMediaEvent_FreeEventParams(wma->mevent, event_code, p1, p2);
359                 }
360             } while (hr == S_OK && event_code != EC_COMPLETE);
361             if (hr == S_OK && event_code == EC_COMPLETE) {
362                 /* Repeat the music by seeking and running again */
363                 if (wma->mci_flags & MCI_DGV_PLAY_REPEAT) {
364                     TRACE("repeat media as requested\n");
365                     IMediaControl_Stop(wma->pmctrl);
366                     IMediaSeeking_SetPositions(wma->seek,
367                                                &wma->seek_start,
368                                                AM_SEEKING_AbsolutePositioning,
369                                                &wma->seek_stop,
370                                                AM_SEEKING_AbsolutePositioning);
371                     IMediaControl_Run(wma->pmctrl);
372                     continue;
373                 }
374                 old = InterlockedExchangePointer(&wma->callback, NULL);
375                 if (old)
376                     mciDriverNotify(old, wma->notify_devid, MCI_NOTIFY_SUCCESSFUL);
377                 break;
378             }
379         }
380         else {
381             TRACE("Unknown error (%d)\n", (int)r);
382             break;
383         }
384     }
385 
386     hr = IMediaControl_Stop(wma->pmctrl);
387     if (FAILED(hr)) {
388         TRACE("Cannot stop filtergraph (hr = %x)\n", hr);
389         ret = MCIERR_INTERNAL;
390     }
391 
392     return ret;
393 }
394 
395 /***************************************************************************
396  *                              MCIQTZ_mciPlay                  [internal]
397  */
398 static DWORD MCIQTZ_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
399 {
400     WINE_MCIQTZ* wma;
401     HRESULT hr;
402     GUID format;
403     DWORD start_flags;
404 
405     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
406 
407     if(!lpParms)
408         return MCIERR_NULL_PARAMETER_BLOCK;
409 
410     wma = MCIQTZ_mciGetOpenDev(wDevID);
411     if (!wma)
412         return MCIERR_INVALID_DEVICE_ID;
413 
414     ResetEvent(wma->stop_event);
415     if (dwFlags & MCI_NOTIFY) {
416         HANDLE old;
417         old = InterlockedExchangePointer(&wma->callback, HWND_32(LOWORD(lpParms->dwCallback)));
418         if (old)
419             mciDriverNotify(old, wma->notify_devid, MCI_NOTIFY_ABORTED);
420     }
421 
422     wma->mci_flags = dwFlags;
423     IMediaSeeking_GetTimeFormat(wma->seek, &format);
424     if (dwFlags & MCI_FROM) {
425         if (IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME))
426             wma->seek_start = lpParms->dwFrom * 10000;
427         else
428             wma->seek_start = lpParms->dwFrom;
429         start_flags = AM_SEEKING_AbsolutePositioning;
430     } else {
431         wma->seek_start = 0;
432         start_flags = AM_SEEKING_NoPositioning;
433     }
434     if (dwFlags & MCI_TO) {
435         if (IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME))
436             wma->seek_stop = lpParms->dwTo * 10000;
437         else
438             wma->seek_stop = lpParms->dwTo;
439     } else {
440         wma->seek_stop = 0;
441         IMediaSeeking_GetDuration(wma->seek, &wma->seek_stop);
442     }
443     IMediaSeeking_SetPositions(wma->seek, &wma->seek_start, start_flags,
444                                &wma->seek_stop, AM_SEEKING_AbsolutePositioning);
445 
446     hr = IMediaControl_Run(wma->pmctrl);
447     if (FAILED(hr)) {
448         TRACE("Cannot run filtergraph (hr = %x)\n", hr);
449         return MCIERR_INTERNAL;
450     }
451 
452     IVideoWindow_put_Visible(wma->vidwin, OATRUE);
453 
454     wma->thread = CreateThread(NULL, 0, MCIQTZ_notifyThread, wma, 0, NULL);
455     if (!wma->thread) {
456         TRACE("Can't create thread\n");
457         return MCIERR_INTERNAL;
458     }
459     return 0;
460 }
461 
462 /***************************************************************************
463  *                              MCIQTZ_mciSeek                  [internal]
464  */
465 static DWORD MCIQTZ_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
466 {
467     WINE_MCIQTZ* wma;
468     HRESULT hr;
469     LONGLONG newpos;
470 
471     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
472 
473     if(!lpParms)
474         return MCIERR_NULL_PARAMETER_BLOCK;
475 
476     wma = MCIQTZ_mciGetOpenDev(wDevID);
477     if (!wma)
478         return MCIERR_INVALID_DEVICE_ID;
479 
480     MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
481 
482     if (dwFlags & MCI_SEEK_TO_START) {
483         newpos = 0;
484     } else if (dwFlags & MCI_SEEK_TO_END) {
485         FIXME("MCI_SEEK_TO_END not implemented yet\n");
486         return MCIERR_INTERNAL;
487     } else if (dwFlags & MCI_TO) {
488         FIXME("MCI_TO not implemented yet\n");
489         return MCIERR_INTERNAL;
490     } else {
491         WARN("dwFlag doesn't tell where to seek to...\n");
492         return MCIERR_MISSING_PARAMETER;
493     }
494 
495     hr = IMediaSeeking_SetPositions(wma->seek, &newpos, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
496     if (FAILED(hr)) {
497         FIXME("Cannot set position (hr = %x)\n", hr);
498         return MCIERR_INTERNAL;
499     }
500 
501     if (dwFlags & MCI_NOTIFY)
502         MCIQTZ_mciNotify(lpParms->dwCallback, wma, MCI_NOTIFY_SUCCESSFUL);
503 
504     return 0;
505 }
506 
507 /***************************************************************************
508  *                              MCIQTZ_mciStop                  [internal]
509  */
510 static DWORD MCIQTZ_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
511 {
512     WINE_MCIQTZ* wma;
513 
514     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
515 
516     wma = MCIQTZ_mciGetOpenDev(wDevID);
517     if (!wma)
518         return MCIERR_INVALID_DEVICE_ID;
519 
520     if (!wma->opened)
521         return 0;
522 
523     if (wma->thread) {
524         SetEvent(wma->stop_event);
525         WaitForSingleObject(wma->thread, INFINITE);
526         CloseHandle(wma->thread);
527         wma->thread = NULL;
528     }
529 
530     if (!wma->parent)
531         IVideoWindow_put_Visible(wma->vidwin, OAFALSE);
532 
533     return 0;
534 }
535 
536 /***************************************************************************
537  *                              MCIQTZ_mciPause                 [internal]
538  */
539 static DWORD MCIQTZ_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
540 {
541     WINE_MCIQTZ* wma;
542     HRESULT hr;
543 
544     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
545 
546     wma = MCIQTZ_mciGetOpenDev(wDevID);
547     if (!wma)
548         return MCIERR_INVALID_DEVICE_ID;
549 
550     hr = IMediaControl_Pause(wma->pmctrl);
551     if (FAILED(hr)) {
552         TRACE("Cannot pause filtergraph (hr = %x)\n", hr);
553         return MCIERR_INTERNAL;
554     }
555 
556     return 0;
557 }
558 
559 /***************************************************************************
560  *                              MCIQTZ_mciResume                 [internal]
561  */
562 static DWORD MCIQTZ_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
563 {
564     WINE_MCIQTZ* wma;
565     HRESULT hr;
566 
567     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
568 
569     wma = MCIQTZ_mciGetOpenDev(wDevID);
570     if (!wma)
571         return MCIERR_INVALID_DEVICE_ID;
572 
573     hr = IMediaControl_Run(wma->pmctrl);
574     if (FAILED(hr)) {
575         TRACE("Cannot run filtergraph (hr = %x)\n", hr);
576         return MCIERR_INTERNAL;
577     }
578 
579     return 0;
580 }
581 
582 /***************************************************************************
583  *                              MCIQTZ_mciGetDevCaps            [internal]
584  */
585 static DWORD MCIQTZ_mciGetDevCaps(UINT wDevID, DWORD dwFlags, LPMCI_GETDEVCAPS_PARMS lpParms)
586 {
587     WINE_MCIQTZ* wma;
588 
589     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
590 
591     if(!lpParms)
592         return MCIERR_NULL_PARAMETER_BLOCK;
593 
594     wma = MCIQTZ_mciGetOpenDev(wDevID);
595     if (!wma)
596         return MCIERR_INVALID_DEVICE_ID;
597 
598     if (!(dwFlags & MCI_GETDEVCAPS_ITEM))
599         return MCIERR_MISSING_PARAMETER;
600 
601     switch (lpParms->dwItem) {
602         case MCI_GETDEVCAPS_CAN_RECORD:
603             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
604             TRACE("MCI_GETDEVCAPS_CAN_RECORD = %08x\n", lpParms->dwReturn);
605             break;
606         case MCI_GETDEVCAPS_HAS_AUDIO:
607             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
608             TRACE("MCI_GETDEVCAPS_HAS_AUDIO = %08x\n", lpParms->dwReturn);
609             break;
610         case MCI_GETDEVCAPS_HAS_VIDEO:
611             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
612             TRACE("MCI_GETDEVCAPS_HAS_VIDEO = %08x\n", lpParms->dwReturn);
613             break;
614         case MCI_GETDEVCAPS_DEVICE_TYPE:
615             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_DIGITAL_VIDEO, MCI_DEVTYPE_DIGITAL_VIDEO);
616             TRACE("MCI_GETDEVCAPS_DEVICE_TYPE = %08x\n", lpParms->dwReturn);
617             break;
618         case MCI_GETDEVCAPS_USES_FILES:
619             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
620             TRACE("MCI_GETDEVCAPS_USES_FILES = %08x\n", lpParms->dwReturn);
621             break;
622         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
623             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
624             TRACE("MCI_GETDEVCAPS_COMPOUND_DEVICE = %08x\n", lpParms->dwReturn);
625             break;
626         case MCI_GETDEVCAPS_CAN_EJECT:
627             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
628             TRACE("MCI_GETDEVCAPS_EJECT = %08x\n", lpParms->dwReturn);
629             break;
630         case MCI_GETDEVCAPS_CAN_PLAY:
631             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
632             TRACE("MCI_GETDEVCAPS_CAN_PLAY = %08x\n", lpParms->dwReturn);
633             break;
634         case MCI_GETDEVCAPS_CAN_SAVE:
635             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
636             TRACE("MCI_GETDEVCAPS_CAN_SAVE = %08x\n", lpParms->dwReturn);
637             break;
638         case MCI_DGV_GETDEVCAPS_CAN_REVERSE:
639             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
640             TRACE("MCI_DGV_GETDEVCAPS_CAN_REVERSE = %08x\n", lpParms->dwReturn);
641             break;
642         case MCI_DGV_GETDEVCAPS_CAN_STRETCH:
643             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); /* FIXME */
644             TRACE("MCI_DGV_GETDEVCAPS_CAN_STRETCH = %08x\n", lpParms->dwReturn);
645             break;
646         case MCI_DGV_GETDEVCAPS_CAN_LOCK:
647             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
648             TRACE("MCI_DGV_GETDEVCAPS_CAN_LOCK = %08x\n", lpParms->dwReturn);
649             break;
650         case MCI_DGV_GETDEVCAPS_CAN_FREEZE:
651             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
652             TRACE("MCI_DGV_GETDEVCAPS_CAN_FREEZE = %08x\n", lpParms->dwReturn);
653             break;
654         case MCI_DGV_GETDEVCAPS_CAN_STR_IN:
655             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
656             TRACE("MCI_DGV_GETDEVCAPS_CAN_STRETCH_INPUT = %08x\n", lpParms->dwReturn);
657             break;
658         case MCI_DGV_GETDEVCAPS_HAS_STILL:
659             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
660             TRACE("MCI_DGV_GETDEVCAPS_HAS_STILL = %08x\n", lpParms->dwReturn);
661             break;
662         case MCI_DGV_GETDEVCAPS_CAN_TEST:
663             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); /* FIXME */
664             TRACE("MCI_DGV_GETDEVCAPS_CAN_TEST = %08x\n", lpParms->dwReturn);
665             break;
666         case MCI_DGV_GETDEVCAPS_MAX_WINDOWS:
667             lpParms->dwReturn = 1;
668             TRACE("MCI_DGV_GETDEVCAPS_MAX_WINDOWS = %u\n", lpParms->dwReturn);
669             return 0;
670         default:
671             WARN("Unknown capability %08x\n", lpParms->dwItem);
672             /* Fall through */
673         case MCI_DGV_GETDEVCAPS_MAXIMUM_RATE: /* unknown to w2k */
674         case MCI_DGV_GETDEVCAPS_MINIMUM_RATE: /* unknown to w2k */
675             return MCIERR_UNSUPPORTED_FUNCTION;
676     }
677 
678     return MCI_RESOURCE_RETURNED;
679 }
680 
681 /***************************************************************************
682  *                              MCIQTZ_mciSet                   [internal]
683  */
684 static DWORD MCIQTZ_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SET_PARMS lpParms)
685 {
686     WINE_MCIQTZ* wma;
687 
688     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
689 
690     if(!lpParms)
691         return MCIERR_NULL_PARAMETER_BLOCK;
692 
693     wma = MCIQTZ_mciGetOpenDev(wDevID);
694     if (!wma)
695         return MCIERR_INVALID_DEVICE_ID;
696 
697     if (dwFlags & MCI_SET_TIME_FORMAT) {
698         switch (lpParms->dwTimeFormat) {
699             case MCI_FORMAT_MILLISECONDS:
700                 TRACE("MCI_SET_TIME_FORMAT = MCI_FORMAT_MILLISECONDS\n");
701                 wma->time_format = MCI_FORMAT_MILLISECONDS;
702                 break;
703             case MCI_FORMAT_FRAMES:
704                 TRACE("MCI_SET_TIME_FORMAT = MCI_FORMAT_FRAMES\n");
705                 wma->time_format = MCI_FORMAT_FRAMES;
706                 break;
707             default:
708                 WARN("Bad time format %u\n", lpParms->dwTimeFormat);
709                 return MCIERR_BAD_TIME_FORMAT;
710         }
711     }
712 
713     if (dwFlags & MCI_SET_DOOR_OPEN)
714         FIXME("MCI_SET_DOOR_OPEN not implemented yet\n");
715     if (dwFlags & MCI_SET_DOOR_CLOSED)
716         FIXME("MCI_SET_DOOR_CLOSED not implemented yet\n");
717     if (dwFlags & MCI_SET_AUDIO)
718         FIXME("MCI_SET_AUDIO not implemented yet\n");
719     if (dwFlags & MCI_SET_VIDEO)
720         FIXME("MCI_SET_VIDEO not implemented yet\n");
721     if (dwFlags & MCI_SET_ON)
722         FIXME("MCI_SET_ON not implemented yet\n");
723     if (dwFlags & MCI_SET_OFF)
724         FIXME("MCI_SET_OFF not implemented yet\n");
725     if (dwFlags & MCI_SET_AUDIO_LEFT)
726         FIXME("MCI_SET_AUDIO_LEFT not implemented yet\n");
727     if (dwFlags & MCI_SET_AUDIO_RIGHT)
728         FIXME("MCI_SET_AUDIO_RIGHT not implemented yet\n");
729 
730     if (dwFlags & ~0x7f03 /* All MCI_SET flags mask */)
731         ERR("Unknown flags %08x\n", dwFlags & ~0x7f03);
732 
733     return 0;
734 }
735 
736 /***************************************************************************
737  *                              MCIQTZ_mciStatus                [internal]
738  */
739 static DWORD MCIQTZ_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STATUS_PARMSW lpParms)
740 {
741     WINE_MCIQTZ* wma;
742     HRESULT hr;
743     DWORD ret = MCI_INTEGER_RETURNED;
744 
745     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
746 
747     if(!lpParms)
748         return MCIERR_NULL_PARAMETER_BLOCK;
749 
750     wma = MCIQTZ_mciGetOpenDev(wDevID);
751     if (!wma)
752         return MCIERR_INVALID_DEVICE_ID;
753 
754     if (!(dwFlags & MCI_STATUS_ITEM)) {
755         WARN("No status item specified\n");
756         return MCIERR_UNRECOGNIZED_COMMAND;
757     }
758 
759     switch (lpParms->dwItem) {
760         case MCI_STATUS_LENGTH: {
761             LONGLONG duration = -1;
762             GUID format;
763             switch (wma->time_format) {
764                 case MCI_FORMAT_MILLISECONDS: format = TIME_FORMAT_MEDIA_TIME; break;
765                 case MCI_FORMAT_FRAMES: format = TIME_FORMAT_FRAME; break;
766                 default: ERR("Unhandled format %x\n", wma->time_format); break;
767             }
768             hr = IMediaSeeking_SetTimeFormat(wma->seek, &format);
769             if (FAILED(hr)) {
770                 FIXME("Cannot set time format (hr = %x)\n", hr);
771                 lpParms->dwReturn = 0;
772                 break;
773             }
774             hr = IMediaSeeking_GetDuration(wma->seek, &duration);
775             if (FAILED(hr) || duration < 0) {
776                 FIXME("Cannot read duration (hr = %x)\n", hr);
777                 lpParms->dwReturn = 0;
778             } else if (wma->time_format != MCI_FORMAT_MILLISECONDS)
779                 lpParms->dwReturn = duration;
780             else
781                 lpParms->dwReturn = duration / 10000;
782             break;
783         }
784         case MCI_STATUS_POSITION: {
785             REFERENCE_TIME curpos;
786 
787             hr = IMediaSeeking_GetCurrentPosition(wma->seek, &curpos);
788             if (FAILED(hr)) {
789                 FIXME("Cannot get position (hr = %x)\n", hr);
790                 return MCIERR_INTERNAL;
791             }
792             lpParms->dwReturn = curpos / 10000;
793             break;
794         }
795         case MCI_STATUS_NUMBER_OF_TRACKS:
796             FIXME("MCI_STATUS_NUMBER_OF_TRACKS not implemented yet\n");
797             return MCIERR_UNRECOGNIZED_COMMAND;
798         case MCI_STATUS_MODE: {
799             LONG state = State_Stopped;
800             IMediaControl_GetState(wma->pmctrl, -1, &state);
801             if (state == State_Stopped)
802                 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_STOP, MCI_MODE_STOP);
803             else if (state == State_Running) {
804                 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_PLAY, MCI_MODE_PLAY);
805                 if (!wma->thread || WaitForSingleObject(wma->thread, 0) == WAIT_OBJECT_0)
806                     lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_STOP, MCI_MODE_STOP);
807             } else if (state == State_Paused)
808                 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_MODE_PAUSE, MCI_MODE_PAUSE);
809             ret = MCI_RESOURCE_RETURNED;
810             break;
811         }
812         case MCI_STATUS_MEDIA_PRESENT:
813             FIXME("MCI_STATUS_MEDIA_PRESENT not implemented yet\n");
814             return MCIERR_UNRECOGNIZED_COMMAND;
815         case MCI_STATUS_TIME_FORMAT:
816             lpParms->dwReturn = MAKEMCIRESOURCE(wma->time_format,
817                                                 MCI_FORMAT_RETURN_BASE + wma->time_format);
818             ret = MCI_RESOURCE_RETURNED;
819             break;
820         case MCI_STATUS_READY:
821             FIXME("MCI_STATUS_READY not implemented yet\n");
822             return MCIERR_UNRECOGNIZED_COMMAND;
823         case MCI_STATUS_CURRENT_TRACK:
824             FIXME("MCI_STATUS_CURRENT_TRACK not implemented yet\n");
825             return MCIERR_UNRECOGNIZED_COMMAND;
826         default:
827             FIXME("Unknown command %08X\n", lpParms->dwItem);
828             return MCIERR_UNRECOGNIZED_COMMAND;
829     }
830 
831     if (dwFlags & MCI_NOTIFY)
832         MCIQTZ_mciNotify(lpParms->dwCallback, wma, MCI_NOTIFY_SUCCESSFUL);
833 
834     return ret;
835 }
836 
837 /***************************************************************************
838  *                              MCIQTZ_mciWhere                 [internal]
839  */
840 static DWORD MCIQTZ_mciWhere(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
841 {
842     WINE_MCIQTZ* wma;
843     HRESULT hr;
844     HWND hWnd;
845     RECT rc;
846     DWORD ret = MCIERR_UNRECOGNIZED_COMMAND;
847 
848     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
849 
850     if(!lpParms)
851         return MCIERR_NULL_PARAMETER_BLOCK;
852 
853     wma = MCIQTZ_mciGetOpenDev(wDevID);
854     if (!wma)
855         return MCIERR_INVALID_DEVICE_ID;
856 
857     hr = IVideoWindow_get_Owner(wma->vidwin, (OAHWND*)&hWnd);
858     if (FAILED(hr)) {
859         TRACE("No video stream, returning no window error\n");
860         return MCIERR_NO_WINDOW;
861     }
862 
863     if (dwFlags & MCI_DGV_WHERE_SOURCE) {
864         if (dwFlags & MCI_DGV_WHERE_MAX)
865             FIXME("MCI_DGV_WHERE_SOURCE_MAX stub\n");
866         IBasicVideo_GetSourcePosition(wma->vidbasic, &rc.left, &rc.top, &rc.right, &rc.bottom);
867         TRACE("MCI_DGV_WHERE_SOURCE %s\n", wine_dbgstr_rect(&rc));
868     }
869     if (dwFlags & MCI_DGV_WHERE_DESTINATION) {
870         if (dwFlags & MCI_DGV_WHERE_MAX)
871             FIXME("MCI_DGV_WHERE_DESTINATION_MAX stub\n");
872         IBasicVideo_GetDestinationPosition(wma->vidbasic, &rc.left, &rc.top, &rc.right, &rc.bottom);
873         TRACE("MCI_DGV_WHERE_DESTINATION %s\n", wine_dbgstr_rect(&rc));
874     }
875     if (dwFlags & MCI_DGV_WHERE_FRAME) {
876         if (dwFlags & MCI_DGV_WHERE_MAX)
877             FIXME("MCI_DGV_WHERE_FRAME_MAX not supported yet\n");
878         else
879             FIXME("MCI_DGV_WHERE_FRAME not supported yet\n");
880         goto out;
881     }
882     if (dwFlags & MCI_DGV_WHERE_VIDEO) {
883         if (dwFlags & MCI_DGV_WHERE_MAX)
884             FIXME("MCI_DGV_WHERE_VIDEO_MAX not supported yet\n");
885         else
886             FIXME("MCI_DGV_WHERE_VIDEO not supported yet\n");
887         goto out;
888     }
889     if (dwFlags & MCI_DGV_WHERE_WINDOW) {
890         if (dwFlags & MCI_DGV_WHERE_MAX) {
891             GetWindowRect(GetDesktopWindow(), &rc);
892             rc.right -= rc.left;
893             rc.bottom -= rc.top;
894             TRACE("MCI_DGV_WHERE_WINDOW_MAX %s\n", wine_dbgstr_rect(&rc));
895         } else {
896             IVideoWindow_GetWindowPosition(wma->vidwin, &rc.left, &rc.top, &rc.right, &rc.bottom);
897             TRACE("MCI_DGV_WHERE_WINDOW %s\n", wine_dbgstr_rect(&rc));
898         }
899     }
900     ret = 0;
901 out:
902     lpParms->rc = rc;
903     return ret;
904 }
905 
906 /***************************************************************************
907  *                              MCIQTZ_mciWindow                [internal]
908  */
909 static DWORD MCIQTZ_mciWindow(UINT wDevID, DWORD dwFlags, LPMCI_DGV_WINDOW_PARMSW lpParms)
910 {
911     WINE_MCIQTZ *wma = MCIQTZ_mciGetOpenDev(wDevID);
912 
913     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
914 
915     if(!lpParms)
916         return MCIERR_NULL_PARAMETER_BLOCK;
917 
918     if (!wma)
919         return MCIERR_INVALID_DEVICE_ID;
920     if (dwFlags & MCI_TEST)
921         return 0;
922 
923     if (dwFlags & MCI_DGV_WINDOW_HWND && (IsWindow(lpParms->hWnd) || !lpParms->hWnd)) {
924         LONG visible = OATRUE;
925         LONG style = 0;
926         TRACE("Setting hWnd to %p\n", lpParms->hWnd);
927         IVideoWindow_get_Visible(wma->vidwin, &visible);
928         IVideoWindow_put_Visible(wma->vidwin, OAFALSE);
929         IVideoWindow_get_WindowStyle(wma->vidwin, &style);
930         style &= ~WS_CHILD;
931         if (lpParms->hWnd)
932             IVideoWindow_put_WindowStyle(wma->vidwin, style|WS_CHILD);
933         else
934             IVideoWindow_put_WindowStyle(wma->vidwin, style);
935         IVideoWindow_put_Owner(wma->vidwin, (OAHWND)lpParms->hWnd);
936         IVideoWindow_put_MessageDrain(wma->vidwin, (OAHWND)lpParms->hWnd);
937         IVideoWindow_put_Visible(wma->vidwin, visible);
938         wma->parent = lpParms->hWnd;
939     }
940     if (dwFlags & MCI_DGV_WINDOW_STATE) {
941         TRACE("Setting nCmdShow to %d\n", lpParms->nCmdShow);
942         IVideoWindow_put_WindowState(wma->vidwin, lpParms->nCmdShow);
943     }
944     if (dwFlags & MCI_DGV_WINDOW_TEXT) {
945         TRACE("Setting caption to %s\n", debugstr_w(lpParms->lpstrText));
946         IVideoWindow_put_Caption(wma->vidwin, lpParms->lpstrText);
947     }
948     return 0;
949 }
950 
951 /***************************************************************************
952  *                              MCIQTZ_mciPut                   [internal]
953  */
954 static DWORD MCIQTZ_mciPut(UINT wDevID, DWORD dwFlags, MCI_GENERIC_PARMS *lpParms)
955 {
956     WINE_MCIQTZ *wma = MCIQTZ_mciGetOpenDev(wDevID);
957     MCI_DGV_RECT_PARMS *rectparms;
958     HRESULT hr;
959 
960     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
961 
962     if(!lpParms)
963         return MCIERR_NULL_PARAMETER_BLOCK;
964 
965     if (!wma)
966         return MCIERR_INVALID_DEVICE_ID;
967 
968     if (!(dwFlags & MCI_DGV_RECT)) {
969         FIXME("No support for non-RECT MCI_PUT\n");
970         return 1;
971     }
972 
973     if (dwFlags & MCI_TEST)
974         return 0;
975 
976     dwFlags &= ~MCI_DGV_RECT;
977     rectparms = (MCI_DGV_RECT_PARMS*)lpParms;
978 
979     if (dwFlags & MCI_DGV_PUT_DESTINATION) {
980         hr = IVideoWindow_SetWindowPosition(wma->vidwin,
981                 rectparms->rc.left, rectparms->rc.top,
982                 rectparms->rc.right - rectparms->rc.left,
983                 rectparms->rc.bottom - rectparms->rc.top);
984         if(FAILED(hr))
985             WARN("IVideoWindow_SetWindowPosition failed: 0x%x\n", hr);
986 
987         dwFlags &= ~MCI_DGV_PUT_DESTINATION;
988     }
989 
990     if (dwFlags & MCI_NOTIFY) {
991         MCIQTZ_mciNotify(lpParms->dwCallback, wma, MCI_NOTIFY_SUCCESSFUL);
992         dwFlags &= ~MCI_NOTIFY;
993     }
994 
995     if (dwFlags)
996         FIXME("No support for some flags: 0x%x\n", dwFlags);
997 
998     return 0;
999 }
1000 
1001 /******************************************************************************
1002  *              MCIAVI_mciUpdate            [internal]
1003  */
1004 static DWORD MCIQTZ_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
1005 {
1006     WINE_MCIQTZ *wma;
1007     DWORD res = 0;
1008 
1009     TRACE("%04x, %08x, %p\n", wDevID, dwFlags, lpParms);
1010 
1011     if(!lpParms)
1012         return MCIERR_NULL_PARAMETER_BLOCK;
1013 
1014     wma = MCIQTZ_mciGetOpenDev(wDevID);
1015     if (!wma)
1016         return MCIERR_INVALID_DEVICE_ID;
1017 
1018     if (dwFlags & MCI_DGV_UPDATE_HDC) {
1019         LONG state, size;
1020         BYTE *data;
1021         BITMAPINFO *info;
1022         HRESULT hr;
1023         RECT src, dest;
1024         LONG visible = OATRUE;
1025 
1026         res = MCIERR_INTERNAL;
1027         IMediaControl_GetState(wma->pmctrl, -1, &state);
1028         if (state == State_Running)
1029             return MCIERR_UNSUPPORTED_FUNCTION;
1030         /* If in stopped state, nothing has been drawn to screen
1031          * moving to pause, which is needed for the old dib renderer, will result
1032          * in a single frame drawn, so hide the window here */
1033         IVideoWindow_get_Visible(wma->vidwin, &visible);
1034         if (wma->parent)
1035             IVideoWindow_put_Visible(wma->vidwin, OAFALSE);
1036         /* FIXME: Should we check the original state and restore it? */
1037         IMediaControl_Pause(wma->pmctrl);
1038         IMediaControl_GetState(wma->pmctrl, -1, &state);
1039         if (FAILED(hr = IBasicVideo_GetCurrentImage(wma->vidbasic, &size, NULL))) {
1040             WARN("Could not get image size (hr = %x)\n", hr);
1041             goto out;
1042         }
1043         data = HeapAlloc(GetProcessHeap(), 0, size);
1044         info = (BITMAPINFO*)data;
1045         IBasicVideo_GetCurrentImage(wma->vidbasic, &size, (LONG*)data);
1046         data += info->bmiHeader.biSize;
1047 
1048         IBasicVideo_GetSourcePosition(wma->vidbasic, &src.left, &src.top, &src.right, &src.bottom);
1049         IBasicVideo_GetDestinationPosition(wma->vidbasic, &dest.left, &dest.top, &dest.right, &dest.bottom);
1050         StretchDIBits(lpParms->hDC,
1051               dest.left, dest.top, dest.right + dest.left, dest.bottom + dest.top,
1052               src.left, src.top, src.right + src.left, src.bottom + src.top,
1053               data, info, DIB_RGB_COLORS, SRCCOPY);
1054         HeapFree(GetProcessHeap(), 0, data);
1055         res = 0;
1056 out:
1057         if (wma->parent)
1058             IVideoWindow_put_Visible(wma->vidwin, visible);
1059     }
1060     else if (dwFlags)
1061         FIXME("Unhandled flags %x\n", dwFlags);
1062     return res;
1063 }
1064 
1065 /***************************************************************************
1066  *                              MCIQTZ_mciSetAudio              [internal]
1067  */
1068 static DWORD MCIQTZ_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
1069 {
1070     WINE_MCIQTZ *wma;
1071     DWORD ret = 0;
1072 
1073     TRACE("(%04x, %08x, %p)\n", wDevID, dwFlags, lpParms);
1074 
1075     if(!lpParms)
1076         return MCIERR_NULL_PARAMETER_BLOCK;
1077 
1078     wma = MCIQTZ_mciGetOpenDev(wDevID);
1079     if (!wma)
1080         return MCIERR_INVALID_DEVICE_ID;
1081 
1082     if (!(dwFlags & MCI_DGV_SETAUDIO_ITEM)) {
1083         FIXME("Unknown flags (%08x)\n", dwFlags);
1084         return 0;
1085     }
1086 
1087     if (dwFlags & MCI_DGV_SETAUDIO_ITEM) {
1088         switch (lpParms->dwItem) {
1089         case MCI_DGV_SETAUDIO_VOLUME:
1090             if (dwFlags & MCI_DGV_SETAUDIO_VALUE) {
1091                 long vol;
1092                 HRESULT hr;
1093                 if (lpParms->dwValue > 1000) {
1094                     ret = MCIERR_OUTOFRANGE;
1095                     break;
1096                 }
1097                 if (dwFlags & MCI_TEST)
1098                     break;
1099                 if (lpParms->dwValue != 0)
1100                     vol = (long)(2000.0 * (log10(lpParms->dwValue) - 3.0));
1101                 else
1102                     vol = -10000;
1103                 TRACE("Setting volume to %ld\n", vol);
1104                 hr = IBasicAudio_put_Volume(wma->audio, vol);
1105                 if (FAILED(hr)) {
1106                     WARN("Cannot set volume (hr = %x)\n", hr);
1107                     ret = MCIERR_INTERNAL;
1108                 }
1109             }
1110             break;
1111         default:
1112             FIXME("Unknown item %08x\n", lpParms->dwItem);
1113             break;
1114         }
1115     }
1116 
1117     return ret;
1118 }
1119 
1120 /*======================================================================*
1121  *                          MCI QTZ entry points                        *
1122  *======================================================================*/
1123 
1124 /**************************************************************************
1125  *                              DriverProc (MCIQTZ.@)
1126  */
1127 LRESULT CALLBACK MCIQTZ_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1128                                    LPARAM dwParam1, LPARAM dwParam2)
1129 {
1130     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1131           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1132 
1133     switch (wMsg) {
1134         case DRV_LOAD:                  return 1;
1135         case DRV_FREE:                  return 1;
1136         case DRV_OPEN:                  return MCIQTZ_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1137         case DRV_CLOSE:                 return MCIQTZ_drvClose(dwDevID);
1138         case DRV_ENABLE:                return 1;
1139         case DRV_DISABLE:               return 1;
1140         case DRV_QUERYCONFIGURE:        return 1;
1141         case DRV_CONFIGURE:             return MCIQTZ_drvConfigure(dwDevID);
1142         case DRV_INSTALL:               return DRVCNF_RESTART;
1143         case DRV_REMOVE:                return DRVCNF_RESTART;
1144     }
1145 
1146     /* session instance */
1147     if (dwDevID == 0xFFFFFFFF)
1148         return 1;
1149 
1150     switch (wMsg) {
1151         case MCI_OPEN_DRIVER:   return MCIQTZ_mciOpen      (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSW)     dwParam2);
1152         case MCI_CLOSE_DRIVER:  return MCIQTZ_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1153         case MCI_PLAY:          return MCIQTZ_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
1154         case MCI_SEEK:          return MCIQTZ_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
1155         case MCI_STOP:          return MCIQTZ_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1156         case MCI_PAUSE:         return MCIQTZ_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1157         case MCI_RESUME:        return MCIQTZ_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1158         case MCI_GETDEVCAPS:    return MCIQTZ_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
1159         case MCI_SET:           return MCIQTZ_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
1160         case MCI_STATUS:        return MCIQTZ_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW)   dwParam2);
1161         case MCI_WHERE:         return MCIQTZ_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1162         /* Digital Video specific */
1163         case MCI_SETAUDIO:      return MCIQTZ_mciSetAudio  (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
1164         case MCI_UPDATE:
1165             return MCIQTZ_mciUpdate(dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)dwParam2);
1166         case MCI_WINDOW:
1167             return MCIQTZ_mciWindow(dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSW)dwParam2);
1168         case MCI_PUT:
1169             return MCIQTZ_mciPut(dwDevID, dwParam1, (MCI_GENERIC_PARMS*)dwParam2);
1170         case MCI_RECORD:
1171         case MCI_INFO:
1172         case MCI_LOAD:
1173         case MCI_SAVE:
1174         case MCI_FREEZE:
1175         case MCI_REALIZE:
1176         case MCI_UNFREEZE:
1177         case MCI_STEP:
1178         case MCI_COPY:
1179         case MCI_CUT:
1180         case MCI_DELETE:
1181         case MCI_PASTE:
1182         case MCI_CUE:
1183         /* Digital Video specific */
1184         case MCI_CAPTURE:
1185         case MCI_MONITOR:
1186         case MCI_RESERVE:
1187         case MCI_SIGNAL:
1188         case MCI_SETVIDEO:
1189         case MCI_QUALITY:
1190         case MCI_LIST:
1191         case MCI_UNDO:
1192         case MCI_CONFIGURE:
1193         case MCI_RESTORE:
1194             FIXME("Unimplemented command [%08X]\n", wMsg);
1195             break;
1196         case MCI_SPIN:
1197         case MCI_ESCAPE:
1198             WARN("Unsupported command [%08X]\n", wMsg);
1199             break;
1200         case MCI_OPEN:
1201         case MCI_CLOSE:
1202             FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1203             break;
1204         default:
1205             TRACE("Sending msg [%08X] to default driver proc\n", wMsg);
1206             return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1207     }
1208 
1209     return MCIERR_UNRECOGNIZED_COMMAND;
1210 }
1211