quartz: Add DebugInfo to critical sections.
[wine] / dlls / quartz / filtergraph.c
1 /*              DirectShow FilterGraph object (QUARTZ.DLL)
2  *
3  * Copyright 2002 Lionel Ulmer
4  * Copyright 2004 Christian Costa
5  *
6  * This file contains the (internal) driver registration functions,
7  * driver enumeration APIs and DirectDraw creation functions.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include <stdarg.h>
26
27 #define COBJMACROS
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "dshow.h"
33 #include "wine/debug.h"
34 #include "quartz_private.h"
35 #include "ole2.h"
36 #include "olectl.h"
37 #include "strmif.h"
38 #include "vfwmsgs.h"
39 #include "evcode.h"
40 #include "wine/unicode.h"
41
42
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
44
45 typedef struct {
46     HWND hWnd;      /* Target window */
47     long msg;       /* User window message */
48     long instance;  /* User data */
49     int  disabled;  /* Disabled messages posting */
50 } WndNotify;
51
52 typedef struct {
53     long lEventCode;   /* Event code */
54     LONG_PTR lParam1;  /* Param1 */
55     LONG_PTR lParam2;  /* Param2 */
56 } Event;
57
58 /* messages ring implementation for queuing events (taken from winmm) */
59 #define EVENTS_RING_BUFFER_INCREMENT      64
60 typedef struct {
61     Event* messages;
62     int ring_buffer_size;
63     int msg_tosave;
64     int msg_toget;
65     CRITICAL_SECTION msg_crst;
66     HANDLE msg_event; /* Signaled for no empty queue */
67 } EventsQueue;
68
69 static int EventsQueue_Init(EventsQueue* omr)
70 {
71     omr->msg_toget = 0;
72     omr->msg_tosave = 0;
73     omr->msg_event = CreateEventW(NULL, TRUE, FALSE, NULL);
74     omr->ring_buffer_size = EVENTS_RING_BUFFER_INCREMENT;
75     omr->messages = CoTaskMemAlloc(omr->ring_buffer_size * sizeof(Event));
76     ZeroMemory(omr->messages, omr->ring_buffer_size * sizeof(Event));
77
78     InitializeCriticalSection(&omr->msg_crst);
79     omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": EventsQueue.msg_crst");
80     return TRUE;
81 }
82
83 static int EventsQueue_Destroy(EventsQueue* omr)
84 {
85     CloseHandle(omr->msg_event);
86     CoTaskMemFree(omr->messages);
87     omr->msg_crst.DebugInfo->Spare[0] = 0;
88     DeleteCriticalSection(&omr->msg_crst);
89     return TRUE;
90 }
91
92 static int EventsQueue_PutEvent(EventsQueue* omr, Event* evt)
93 {
94     EnterCriticalSection(&omr->msg_crst);
95     if ((omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size)))
96     {
97         int old_ring_buffer_size = omr->ring_buffer_size;
98         omr->ring_buffer_size += EVENTS_RING_BUFFER_INCREMENT;
99         TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
100         omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(Event));
101         /* Now we need to rearrange the ring buffer so that the new
102            buffers just allocated are in between omr->msg_tosave and
103            omr->msg_toget.
104         */
105         if (omr->msg_tosave < omr->msg_toget)
106         {
107             memmove(&(omr->messages[omr->msg_toget + EVENTS_RING_BUFFER_INCREMENT]),
108                     &(omr->messages[omr->msg_toget]),
109                     sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
110                     );
111             omr->msg_toget += EVENTS_RING_BUFFER_INCREMENT;
112         }
113     }
114     omr->messages[omr->msg_tosave] = *evt;
115     SetEvent(omr->msg_event);
116     omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
117     LeaveCriticalSection(&omr->msg_crst);
118     return TRUE;
119 }
120
121 static int EventsQueue_GetEvent(EventsQueue* omr, Event* evt, long msTimeOut)
122 {
123     if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
124         return FALSE;
125         
126     EnterCriticalSection(&omr->msg_crst);
127
128     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
129     {
130         LeaveCriticalSection(&omr->msg_crst);
131         return FALSE;
132     }
133
134     *evt = omr->messages[omr->msg_toget];
135     omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
136
137     /* Mark the buffer as empty if needed */
138     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
139         ResetEvent(omr->msg_event);
140
141     LeaveCriticalSection(&omr->msg_crst);
142     return TRUE;
143 }
144
145 #define MAX_ITF_CACHE_ENTRIES 3
146 typedef struct _ITF_CACHE_ENTRY {
147    const IID* riid;
148    IBaseFilter* filter;
149    IUnknown* iface;
150 } ITF_CACHE_ENTRY;
151
152 typedef struct _IFilterGraphImpl {
153     const IGraphBuilderVtbl *IGraphBuilder_vtbl;
154     const IMediaControlVtbl *IMediaControl_vtbl;
155     const IMediaSeekingVtbl *IMediaSeeking_vtbl;
156     const IBasicAudioVtbl *IBasicAudio_vtbl;
157     const IBasicVideoVtbl *IBasicVideo_vtbl;
158     const IVideoWindowVtbl *IVideoWindow_vtbl;
159     const IMediaEventExVtbl *IMediaEventEx_vtbl;
160     const IMediaFilterVtbl *IMediaFilter_vtbl;
161     const IMediaEventSinkVtbl *IMediaEventSink_vtbl;
162     const IGraphConfigVtbl *IGraphConfig_vtbl;
163     const IMediaPositionVtbl *IMediaPosition_vtbl;
164     /* IAMGraphStreams */
165     /* IAMStats */
166     /* IBasicVideo2 */
167     /* IFilterChain */
168     /* IFilterGraph2 */
169     /* IFilterMapper2 */
170     /* IGraphVersion */
171     /* IQueueCommand */
172     /* IRegisterServiceProvider */
173     /* IResourceMananger */
174     /* IServiceProvider */
175     /* IVideoFrameStep */
176
177     LONG ref;
178     IFilterMapper2 * pFilterMapper2;
179     IBaseFilter ** ppFiltersInGraph;
180     LPWSTR * pFilterNames;
181     int nFilters;
182     int filterCapacity;
183     long nameIndex;
184     EventsQueue evqueue;
185     HANDLE hEventCompletion;
186     int CompletionStatus;
187     WndNotify notif;
188     int nRenderers;
189     int EcCompleteCount;
190     int HandleEcComplete;
191     int HandleEcRepaint;
192     OAFilterState state;
193     CRITICAL_SECTION cs;
194     ITF_CACHE_ENTRY ItfCacheEntries[MAX_ITF_CACHE_ENTRIES];
195     int nItfCacheEntries;
196 } IFilterGraphImpl;
197
198
199 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
200                                           REFIID riid,
201                                           LPVOID *ppvObj) {
202     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
203     
204     if (IsEqualGUID(&IID_IUnknown, riid) ||
205         IsEqualGUID(&IID_IFilterGraph, riid) ||
206         IsEqualGUID(&IID_IGraphBuilder, riid)) {
207         *ppvObj = &(This->IGraphBuilder_vtbl);
208         TRACE("   returning IGraphBuilder interface (%p)\n", *ppvObj);
209     } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
210         *ppvObj = &(This->IMediaControl_vtbl);
211         TRACE("   returning IMediaControl interface (%p)\n", *ppvObj);
212     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
213         *ppvObj = &(This->IMediaSeeking_vtbl);
214         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
215     } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
216         *ppvObj = &(This->IBasicAudio_vtbl);
217         TRACE("   returning IBasicAudio interface (%p)\n", *ppvObj);
218     } else if (IsEqualGUID(&IID_IBasicVideo, riid)) {
219         *ppvObj = &(This->IBasicVideo_vtbl);
220         TRACE("   returning IBasicVideo interface (%p)\n", *ppvObj);
221     } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
222         *ppvObj = &(This->IVideoWindow_vtbl);
223         TRACE("   returning IVideoWindow interface (%p)\n", *ppvObj);
224     } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
225            IsEqualGUID(&IID_IMediaEventEx, riid)) {
226         *ppvObj = &(This->IMediaEventEx_vtbl);
227         TRACE("   returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
228     } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
229           IsEqualGUID(&IID_IPersist, riid)) {
230         *ppvObj = &(This->IMediaFilter_vtbl);
231         TRACE("   returning IMediaFilter interface (%p)\n", *ppvObj);
232     } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
233         *ppvObj = &(This->IMediaEventSink_vtbl);
234         TRACE("   returning IMediaEventSink interface (%p)\n", *ppvObj);
235     } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
236         *ppvObj = &(This->IGraphConfig_vtbl);
237         TRACE("   returning IGraphConfig interface (%p)\n", *ppvObj);
238     } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
239         *ppvObj = &(This->IMediaPosition_vtbl);
240         TRACE("   returning IMediaPosition interface (%p)\n", *ppvObj);
241     } else {
242         *ppvObj = NULL;
243         FIXME("unknown interface %s\n", debugstr_guid(riid));
244         return E_NOINTERFACE;
245     }
246
247     InterlockedIncrement(&This->ref);
248     return S_OK;
249 }
250
251 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This) {
252     ULONG ref = InterlockedIncrement(&This->ref);
253
254     TRACE("(%p)->(): new ref = %d\n", This, ref);
255     
256     return ref;
257 }
258
259 static ULONG Filtergraph_Release(IFilterGraphImpl *This) {
260     ULONG ref = InterlockedDecrement(&This->ref);
261     
262     TRACE("(%p)->(): new ref = %d\n", This, ref);
263     
264     if (ref == 0) {
265         int i;
266         for (i = 0; i < This->nFilters; i++)
267             IBaseFilter_Release(This->ppFiltersInGraph[i]);
268         for (i = 0; i < This->nItfCacheEntries; i++)
269             IUnknown_Release(This->ItfCacheEntries[i].iface);
270         IFilterMapper2_Release(This->pFilterMapper2);
271         CloseHandle(This->hEventCompletion);
272         EventsQueue_Destroy(&This->evqueue);
273         This->cs.DebugInfo->Spare[0] = 0;
274         DeleteCriticalSection(&This->cs);
275         CoTaskMemFree(This->ppFiltersInGraph);
276         CoTaskMemFree(This->pFilterNames);
277         CoTaskMemFree(This);
278     }
279     return ref;
280 }
281
282
283 /*** IUnknown methods ***/
284 static HRESULT WINAPI GraphBuilder_QueryInterface(IGraphBuilder *iface,
285                                                   REFIID riid,
286                                                   LPVOID*ppvObj) {
287     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
288     
289     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
290     return Filtergraph_QueryInterface(This, riid, ppvObj);
291 }
292
293 static ULONG WINAPI GraphBuilder_AddRef(IGraphBuilder *iface) {
294     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
295     
296     TRACE("(%p/%p)->() calling FilterGraph AddRef\n", This, iface);
297     
298     return Filtergraph_AddRef(This);
299 }
300
301 static ULONG WINAPI GraphBuilder_Release(IGraphBuilder *iface) {
302     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
303     
304     TRACE("(%p/%p)->() calling FilterGraph Release\n", This, iface);
305
306     return Filtergraph_Release(This);
307 }
308
309 /*** IFilterGraph methods ***/
310 static HRESULT WINAPI GraphBuilder_AddFilter(IGraphBuilder *iface,
311                                              IBaseFilter *pFilter,
312                                              LPCWSTR pName) {
313     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
314     HRESULT hr;
315     int i,j;
316     WCHAR* wszFilterName = NULL;
317     int duplicate_name = FALSE;
318     
319     TRACE("(%p/%p)->(%p, %s (%p))\n", This, iface, pFilter, debugstr_w(pName), pName);
320
321     wszFilterName = (WCHAR*) CoTaskMemAlloc( (pName ? strlenW(pName) + 6 : 5) * sizeof(WCHAR) );
322     
323     if (pName)
324     {
325         /* Check if name already exists */
326         for(i = 0; i < This->nFilters; i++)
327             if (!strcmpW(This->pFilterNames[i], pName))
328             {
329                 duplicate_name = TRUE;
330                 break;
331             }
332     }
333
334     /* If no name given or name already existing, generate one */
335     if (!pName || duplicate_name)
336     {
337         static const WCHAR wszFmt1[] = {'%','s',' ','%','0','4','d',0};
338         static const WCHAR wszFmt2[] = {'%','0','4','d',0};
339
340         for (j = 0; j < 10000 ; j++)
341         {
342             /* Create name */
343             if (pName)
344                 sprintfW(wszFilterName, wszFmt1, pName, This->nameIndex);
345             else
346                 sprintfW(wszFilterName, wszFmt2, This->nameIndex);
347             TRACE("Generated name %s\n", debugstr_w(wszFilterName));
348
349             /* Check if the generated name already exists */
350             for(i = 0; i < This->nFilters; i++)
351                 if (!strcmpW(This->pFilterNames[i], wszFilterName))
352                     break;
353
354             /* Compute next index and exit if generated name is suitable */
355             if (This->nameIndex++ == 10000)
356                 This->nameIndex = 1;
357             if (i == This->nFilters)
358                 break;
359         }
360         /* Unable to find a suitable name */
361         if (j == 10000)
362         {
363             CoTaskMemFree(wszFilterName);
364             return VFW_E_DUPLICATE_NAME;
365         }
366     }
367     else
368         memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
369
370     if (This->nFilters + 1 > This->filterCapacity)
371     {
372         int newCapacity = This->filterCapacity ? 2 * This->filterCapacity : 1;
373         IBaseFilter ** ppNewFilters = CoTaskMemAlloc(newCapacity * sizeof(IBaseFilter*));
374         LPWSTR * pNewNames = CoTaskMemAlloc(newCapacity * sizeof(LPWSTR));
375         memcpy(ppNewFilters, This->ppFiltersInGraph, This->nFilters * sizeof(IBaseFilter*));
376         memcpy(pNewNames, This->pFilterNames, This->nFilters * sizeof(LPWSTR));
377         if (!This->filterCapacity)
378         {
379             CoTaskMemFree(This->ppFiltersInGraph);
380             CoTaskMemFree(This->pFilterNames);
381         }
382         This->ppFiltersInGraph = ppNewFilters;
383         This->pFilterNames = pNewNames;
384         This->filterCapacity = newCapacity;
385     }
386
387     hr = IBaseFilter_JoinFilterGraph(pFilter, (IFilterGraph *)This, wszFilterName);
388
389     if (SUCCEEDED(hr))
390     {
391         IBaseFilter_AddRef(pFilter);
392         This->ppFiltersInGraph[This->nFilters] = pFilter;
393         This->pFilterNames[This->nFilters] = wszFilterName;
394         This->nFilters++;
395     }
396     else
397         CoTaskMemFree(wszFilterName);
398
399     if (SUCCEEDED(hr) && duplicate_name)
400         return VFW_S_DUPLICATE_NAME;
401         
402     return hr;
403 }
404
405 static HRESULT WINAPI GraphBuilder_RemoveFilter(IGraphBuilder *iface,
406                                                 IBaseFilter *pFilter) {
407     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
408     int i;
409     HRESULT hr = E_FAIL;
410
411     TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
412
413     /* FIXME: check graph is stopped */
414
415     for (i = 0; i < This->nFilters; i++)
416     {
417         if (This->ppFiltersInGraph[i] == pFilter)
418         {
419             /* FIXME: disconnect pins */
420             hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, This->pFilterNames[i]);
421             if (SUCCEEDED(hr))
422             {
423                 IPin_Release(pFilter);
424                 CoTaskMemFree(This->pFilterNames[i]);
425                 memmove(This->ppFiltersInGraph+i, This->ppFiltersInGraph+i+1, sizeof(IBaseFilter*)*(This->nFilters - 1 - i));
426                 memmove(This->pFilterNames+i, This->pFilterNames+i+1, sizeof(LPWSTR)*(This->nFilters - 1 - i));
427                 This->nFilters--;
428                 /* Invalidate interfaces in the cache */
429                 for (i = 0; i < This->nItfCacheEntries; i++)
430                     if (pFilter == This->ItfCacheEntries[i].filter)
431                     {
432                         IUnknown_Release(This->ItfCacheEntries[i].iface);
433                         This->ItfCacheEntries[i].iface = NULL;
434                         This->ItfCacheEntries[i].filter = NULL;
435                     }
436                 return S_OK;
437             }
438             break;
439         }
440     }
441
442     return hr; /* FIXME: check this error code */
443 }
444
445 static HRESULT WINAPI GraphBuilder_EnumFilters(IGraphBuilder *iface,
446                                               IEnumFilters **ppEnum) {
447     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
448
449     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
450
451     return IEnumFiltersImpl_Construct(This->ppFiltersInGraph, This->nFilters, ppEnum);
452 }
453
454 static HRESULT WINAPI GraphBuilder_FindFilterByName(IGraphBuilder *iface,
455                                                     LPCWSTR pName,
456                                                     IBaseFilter **ppFilter) {
457     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
458     int i;
459
460     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_w(pName), pName, ppFilter);
461
462     *ppFilter = NULL;
463
464     for (i = 0; i < This->nFilters; i++)
465     {
466         if (!strcmpW(pName, This->pFilterNames[i]))
467         {
468             *ppFilter = This->ppFiltersInGraph[i];
469             IBaseFilter_AddRef(*ppFilter);
470             return S_OK;
471         }
472     }
473
474     return E_FAIL; /* FIXME: check this error code */
475 }
476
477 /* NOTE: despite the implication, it doesn't matter which
478  * way round you put in the input and output pins */
479 static HRESULT WINAPI GraphBuilder_ConnectDirect(IGraphBuilder *iface,
480                                                  IPin *ppinIn,
481                                                  IPin *ppinOut,
482                                                  const AM_MEDIA_TYPE *pmt) {
483     PIN_DIRECTION dir;
484     HRESULT hr;
485
486     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
487
488     TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
489
490     /* FIXME: check pins are in graph */
491
492     if (TRACE_ON(quartz))
493     {
494         PIN_INFO PinInfo;
495
496         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
497         if (FAILED(hr))
498             return hr;
499
500         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
501         IBaseFilter_Release(PinInfo.pFilter);
502
503         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
504         if (FAILED(hr))
505             return hr;
506
507         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
508         IBaseFilter_Release(PinInfo.pFilter);
509     }
510
511     hr = IPin_QueryDirection(ppinIn, &dir);
512     if (SUCCEEDED(hr))
513     {
514         if (dir == PINDIR_INPUT)
515             hr = IPin_Connect(ppinOut, ppinIn, pmt);
516         else
517             hr = IPin_Connect(ppinIn, ppinOut, pmt);
518     }
519
520     return hr;
521 }
522
523 static HRESULT WINAPI GraphBuilder_Reconnect(IGraphBuilder *iface,
524                                              IPin *ppin) {
525     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
526     IPin *pConnectedTo = NULL;
527     HRESULT hr;
528     PIN_DIRECTION pindir;
529
530     IPin_QueryDirection(ppin, &pindir);
531     hr = IPin_ConnectedTo(ppin, &pConnectedTo);
532     if (FAILED(hr)) {
533         TRACE("Querying connected to failed: %x\n", hr);
534         return hr; 
535     }
536     IPin_Disconnect(ppin);
537     IPin_Disconnect(pConnectedTo);
538     if (pindir == PINDIR_INPUT)
539         hr = IPin_Connect(pConnectedTo, ppin, NULL);
540     else
541         hr = IPin_Connect(ppin, pConnectedTo, NULL);
542     IPin_Release(pConnectedTo);
543     if (FAILED(hr))
544         ERR("Reconnecting pins failed, pins are not connected now..\n");
545     TRACE("(%p->%p) -- %p %p -> %x\n", iface, This, ppin, pConnectedTo, hr);
546     return hr;
547 }
548
549 static HRESULT WINAPI GraphBuilder_Disconnect(IGraphBuilder *iface,
550                                               IPin *ppin) {
551     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
552
553     TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
554
555     return IPin_Disconnect(ppin);
556 }
557
558 static HRESULT WINAPI GraphBuilder_SetDefaultSyncSource(IGraphBuilder *iface) {
559     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
560
561     TRACE("(%p/%p)->(): stub !!!\n", iface, This);
562
563     return S_OK;
564 }
565
566 static HRESULT GetFilterInfo(IMoniker* pMoniker, GUID* pclsid, VARIANT* pvar)
567 {
568     static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
569     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
570     IPropertyBag * pPropBagCat = NULL;
571     HRESULT hr;
572
573     VariantInit(pvar);
574     V_VT(pvar) = VT_BSTR;
575
576     hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
577
578     if (SUCCEEDED(hr))
579         hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
580
581     if (SUCCEEDED(hr))
582         hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid);
583
584     if (SUCCEEDED(hr))
585         hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
586
587     if (SUCCEEDED(hr))
588         TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_UNION(pvar, bstrVal)));
589
590     if (pPropBagCat)
591         IPropertyBag_Release(pPropBagCat);
592
593     return hr;
594 }
595
596 static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
597 {
598     HRESULT hr;
599     ULONG nb = 0;
600
601     TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
602     hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
603     if (hr == S_OK) {
604         /* Rendered input */
605     } else if (hr == S_FALSE) {
606         *pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
607         hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
608         if (hr != S_OK) {
609             ERR("Error (%x)\n", hr);
610         }
611     } else if (hr == E_NOTIMPL) {
612         /* Input connected to all outputs */
613         IEnumPins* penumpins;
614         IPin* ppin;
615         int i = 0;
616         TRACE("E_NOTIMPL\n");
617         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
618         if (FAILED(hr)) {
619             ERR("filter Enumpins failed (%x)\n", hr);
620             return hr;
621         }
622         i = 0;
623         /* Count output pins */
624         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
625             PIN_DIRECTION pindir;
626             IPin_QueryDirection(ppin, &pindir);
627             if (pindir == PINDIR_OUTPUT)
628                 i++;
629             IPin_Release(ppin);
630         }
631         *pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
632         /* Retrieve output pins */
633         IEnumPins_Reset(penumpins);
634         i = 0;
635         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
636             PIN_DIRECTION pindir;
637             IPin_QueryDirection(ppin, &pindir);
638             if (pindir == PINDIR_OUTPUT)
639                 (*pppins)[i++] = ppin;
640             else
641                 IPin_Release(ppin);
642         }
643         nb = i;
644         if (FAILED(hr)) {
645             ERR("Next failed (%x)\n", hr);
646             return hr;
647         }
648         IEnumPins_Release(penumpins);
649     } else if (FAILED(hr)) {
650         ERR("Cannot get internal connection (%x)\n", hr);
651         return hr;
652     }
653
654     *pnb = nb;
655     return S_OK;
656 }
657
658 /*** IGraphBuilder methods ***/
659 static HRESULT WINAPI GraphBuilder_Connect(IGraphBuilder *iface,
660                                            IPin *ppinOut,
661                                            IPin *ppinIn) {
662     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
663     HRESULT hr;
664     AM_MEDIA_TYPE* mt;
665     IEnumMediaTypes* penummt;
666     ULONG nbmt;
667     IEnumPins* penumpins;
668     IEnumMoniker* pEnumMoniker;
669     GUID tab[2];
670     ULONG nb;
671     IMoniker* pMoniker;
672     ULONG pin;
673     PIN_INFO PinInfo;
674     CLSID FilterCLSID;
675
676     TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
677
678     if (TRACE_ON(quartz))
679     {
680         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
681         if (FAILED(hr))
682             return hr;
683
684         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
685         IBaseFilter_Release(PinInfo.pFilter);
686
687         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
688         if (FAILED(hr))
689             return hr;
690
691         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
692         IBaseFilter_Release(PinInfo.pFilter);
693     }
694
695     /* Try direct connection first */
696     hr = IPin_Connect(ppinOut, ppinIn, NULL);
697     if (SUCCEEDED(hr)) {
698         return S_OK;
699     }
700     TRACE("Direct connection failed, trying to insert other filters\n");
701
702     hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
703     if (FAILED(hr))
704        return hr;
705
706     hr = IBaseFilter_GetClassID(PinInfo.pFilter, &FilterCLSID);
707     if (FAILED(hr))
708        return hr;
709
710     IBaseFilter_Release(PinInfo.pFilter);
711
712     /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream 
713      * filter to the minor mediatype of input pin of the renderer */
714     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
715     if (FAILED(hr)) {
716         ERR("EnumMediaTypes (%x)\n", hr);
717         return hr;
718     }
719
720     hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
721     if (FAILED(hr)) {
722         ERR("IEnumMediaTypes_Next (%x)\n", hr);
723         return hr;
724     }
725
726     if (!nbmt) {
727         ERR("No media type found!\n");
728         return S_OK;
729     }
730     TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
731     TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
732
733     /* Try to find a suitable filter that can connect to the pin to render */
734     tab[0] = mt->majortype;
735     tab[1] = mt->subtype;
736     hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
737     if (FAILED(hr)) {
738         ERR("Unable to enum filters (%x)\n", hr);
739         return hr;
740     }
741     
742     while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
743     {
744         VARIANT var;
745         GUID clsid;
746         IPin** ppins;
747         IPin* ppinfilter = NULL;
748         IBaseFilter* pfilter = NULL;
749
750         hr = GetFilterInfo(pMoniker, &clsid, &var);
751         IMoniker_Release(pMoniker);
752         if (FAILED(hr)) {
753             ERR("Unable to retrieve filter info (%x)\n", hr);
754             goto error;
755         }
756
757         if (IsEqualGUID(&clsid, &FilterCLSID)) {
758             /* Skip filter (same as the one the output pin belongs to) */
759             goto error;
760         }
761
762         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
763         if (FAILED(hr)) {
764             ERR("Unable to create filter (%x), trying next one\n", hr);
765             goto error;
766         }
767
768         hr = IGraphBuilder_AddFilter(iface, pfilter, NULL);
769         if (FAILED(hr)) {
770             ERR("Unable to add filter (%x)\n", hr);
771             IBaseFilter_Release(pfilter);
772             pfilter = NULL;
773             goto error;
774         }
775
776         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
777         if (FAILED(hr)) {
778             ERR("Enumpins (%x)\n", hr);
779             goto error;
780         }
781
782         hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
783         IEnumPins_Release(penumpins);
784
785         if (FAILED(hr)) {
786             ERR("Next (%x)\n", hr);
787             goto error;
788         }
789         if (pin == 0) {
790             ERR("No Pin\n");
791             goto error;
792         }
793
794         hr = IPin_Connect(ppinOut, ppinfilter, NULL);
795         if (FAILED(hr)) {
796             TRACE("Cannot connect to filter (%x), trying next one\n", hr);
797             goto error;
798         }
799         TRACE("Successfully connected to filter, follow chain...\n");
800
801         /* Render all output pins of the filter by calling IGraphBuilder_Render on each of them */
802         hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
803
804         if (SUCCEEDED(hr)) {
805             int i;
806             if (nb == 0) {
807                 IPin_Disconnect(ppinOut);
808                 goto error;
809             }
810             TRACE("pins to consider: %d\n", nb);
811             for(i = 0; i < nb; i++) {
812                 TRACE("Processing pin %d\n", i);
813                 hr = IGraphBuilder_Connect(iface, ppins[i], ppinIn);
814                 if (FAILED(hr)) {
815                    TRACE("Cannot render pin %p (%x)\n", ppinfilter, hr);
816                 }
817                 IPin_Release(ppins[i]);
818                 if (SUCCEEDED(hr)) break;
819             }
820             while (++i < nb) IPin_Release(ppins[i]);
821             CoTaskMemFree(ppins);
822             IPin_Release(ppinfilter);
823             break;
824         }
825
826 error:
827         if (ppinfilter) IPin_Release(ppinfilter);
828         if (pfilter) {
829             IGraphBuilder_RemoveFilter(iface, pfilter);
830             IBaseFilter_Release(pfilter);
831         }
832     }
833
834     IEnumMediaTypes_Release(penummt);
835     DeleteMediaType(mt);
836     
837     return S_OK;
838 }
839
840 static HRESULT WINAPI GraphBuilder_Render(IGraphBuilder *iface,
841                                           IPin *ppinOut) {
842     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
843     IEnumMediaTypes* penummt;
844     AM_MEDIA_TYPE* mt;
845     ULONG nbmt;
846     HRESULT hr;
847
848     IEnumMoniker* pEnumMoniker;
849     GUID tab[2];
850     ULONG nb;
851     IMoniker* pMoniker;
852
853     TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
854
855     if (TRACE_ON(quartz))
856     {
857         PIN_INFO PinInfo;
858
859         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
860         if (FAILED(hr))
861             return hr;
862
863         TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
864         IBaseFilter_Release(PinInfo.pFilter);
865     }
866
867     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
868     if (FAILED(hr)) {
869         ERR("EnumMediaTypes (%x)\n", hr);
870         return hr;
871     }
872
873     while(1)
874     {
875         hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
876         if (FAILED(hr)) {
877             ERR("IEnumMediaTypes_Next (%x)\n", hr);
878             return hr;
879         }
880         if (!nbmt)
881             break;
882         TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
883         TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
884
885         /* Try to find a suitable renderer with the same media type */
886         tab[0] = mt->majortype;
887         tab[1] = GUID_NULL;
888         hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, TRUE, FALSE, 0, NULL, NULL, NULL);
889         if (FAILED(hr)) {
890             ERR("Unable to enum filters (%x)\n", hr);
891             return hr;
892         }
893
894         while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
895         {
896             VARIANT var;
897             GUID clsid;
898             IPin* ppinfilter;
899             IBaseFilter* pfilter = NULL;
900             IEnumPins* penumpins;
901             ULONG pin;
902
903             hr = GetFilterInfo(pMoniker, &clsid, &var);
904             IMoniker_Release(pMoniker);
905             if (FAILED(hr)) {
906                 ERR("Unable to retrieve filter info (%x)\n", hr);
907                 goto error;
908             }
909
910             hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
911             if (FAILED(hr)) {
912                ERR("Unable to create filter (%x), trying next one\n", hr);
913                goto error;
914             }
915
916             hr = IGraphBuilder_AddFilter(iface, pfilter, NULL);
917             if (FAILED(hr)) {
918                 ERR("Unable to add filter (%x)\n", hr);
919                 pfilter = NULL;
920                 goto error;
921             }
922
923             hr = IBaseFilter_EnumPins(pfilter, &penumpins);
924             if (FAILED(hr)) {
925                 ERR("Splitter Enumpins (%x)\n", hr);
926                 goto error;
927             }
928             hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
929             if (FAILED(hr)) {
930                ERR("Next (%x)\n", hr);
931                goto error;
932             }
933             if (pin == 0) {
934                ERR("No Pin\n");
935                goto error;
936             }
937             IEnumPins_Release(penumpins);
938
939             /* Connect the pin to render to the renderer */
940             hr = IGraphBuilder_Connect(iface, ppinOut, ppinfilter);
941             if (FAILED(hr)) {
942                 TRACE("Unable to connect to renderer (%x)\n", hr);
943                 goto error;
944             }
945             break;
946
947 error:
948             if (pfilter) {
949                 IGraphBuilder_RemoveFilter(iface, pfilter);
950                 IBaseFilter_Release(pfilter);
951             }
952         }
953        
954         DeleteMediaType(mt);
955         break;  
956     }
957
958     IEnumMediaTypes_Release(penummt);
959     
960     return S_OK;
961 }
962
963 static HRESULT WINAPI GraphBuilder_RenderFile(IGraphBuilder *iface,
964                                               LPCWSTR lpcwstrFile,
965                                               LPCWSTR lpcwstrPlayList) {
966     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
967     static const WCHAR string[] = {'R','e','a','d','e','r',0};
968     IBaseFilter* preader = NULL;
969     IBaseFilter* psplitter = NULL;
970     IPin* ppinreader;
971     IPin* ppinsplitter;
972     IEnumPins* penumpins;
973     ULONG pin;
974     HRESULT hr;
975     IEnumMoniker* pEnumMoniker = NULL;
976     GUID tab[2];
977     IPin** ppins = NULL;
978     ULONG nb;
979     IMoniker* pMoniker;
980     IFileSourceFilter* pfile = NULL;
981     AM_MEDIA_TYPE mt;
982     WCHAR* filename;
983
984     TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
985
986     if (lpcwstrPlayList != NULL)
987         return E_INVALIDARG;
988
989     hr = IGraphBuilder_AddSourceFilter(iface, lpcwstrFile, string, &preader);
990
991     /* Retrieve file media type */
992     if (SUCCEEDED(hr))
993         hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
994     if (SUCCEEDED(hr)) {
995         hr = IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
996         IFileSourceFilter_Release(pfile);
997     }
998
999     if (SUCCEEDED(hr))
1000         hr = IBaseFilter_EnumPins(preader, &penumpins);
1001     if (SUCCEEDED(hr)) {
1002         hr = IEnumPins_Next(penumpins, 1, &ppinreader, &pin);
1003         IEnumPins_Release(penumpins);
1004     }
1005
1006     if (SUCCEEDED(hr)) {
1007         tab[0] = mt.majortype;
1008         tab[1] = mt.subtype;
1009         hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1010     }
1011
1012     if (FAILED(hr))
1013     {
1014         if (pEnumMoniker)
1015             IEnumMoniker_Release(pEnumMoniker);
1016         if (preader) {
1017              IGraphBuilder_RemoveFilter(iface, preader);
1018              IBaseFilter_Release(preader);
1019         }
1020         return hr;
1021     }
1022
1023     hr = VFW_E_CANNOT_RENDER;
1024     while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1025     {
1026         VARIANT var;
1027         GUID clsid;
1028
1029         hr = GetFilterInfo(pMoniker, &clsid, &var);
1030         IMoniker_Release(pMoniker);
1031         if (FAILED(hr)) {
1032             ERR("Unable to retrieve filter info (%x)\n", hr);
1033             continue;
1034         }
1035
1036         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&psplitter);
1037         if (FAILED(hr)) {
1038            ERR("Unable to create filter (%x), trying next one\n", hr);
1039            continue;
1040         }
1041
1042         hr = IGraphBuilder_AddFilter(iface, psplitter, NULL);
1043         if (FAILED(hr)) {
1044             ERR("Unable add filter (%x)\n", hr);
1045             IBaseFilter_Release(psplitter);
1046             continue;
1047         }
1048
1049         /* Connect file source and splitter filters together */
1050         /* Make the splitter analyze incoming data */
1051
1052         hr = IBaseFilter_EnumPins(psplitter, &penumpins);
1053         if (SUCCEEDED(hr)) {
1054             hr = IEnumPins_Next(penumpins, 1, &ppinsplitter, &pin);
1055             IEnumPins_Release(penumpins);
1056         }
1057
1058         if (SUCCEEDED(hr))
1059             hr = IPin_Connect(ppinreader, ppinsplitter, NULL);
1060
1061         /* Make sure there's some output pins in the filter */
1062         if (SUCCEEDED(hr))
1063             hr = GetInternalConnections(psplitter, ppinsplitter, &ppins, &nb);
1064         if (SUCCEEDED(hr)) {
1065             if(nb == 0) {
1066                 IPin_Disconnect(ppinreader);
1067                 TRACE("No output pins found in filter\n");
1068                 hr = VFW_E_CANNOT_RENDER;
1069             }
1070         }
1071
1072         IPin_Release(ppinsplitter);
1073         ppinsplitter = NULL;
1074
1075         if (SUCCEEDED(hr)) {
1076             TRACE("Successfully connected to filter\n");
1077             break;
1078         }
1079
1080         TRACE("Cannot connect to filter (%x), trying next one\n", hr);
1081
1082         if (ppins) {
1083             CoTaskMemFree(ppins);
1084             ppins = NULL;
1085         }
1086         IGraphBuilder_RemoveFilter(iface, psplitter);
1087         IBaseFilter_Release(psplitter);
1088         psplitter = NULL;
1089     }
1090
1091     /* Render all output pin of the splitter by calling IGraphBuilder_Render on each of them */
1092     if (SUCCEEDED(hr)) {
1093         int partial = 0;
1094         int i;
1095         TRACE("pins to consider: %d\n", nb);
1096         for(i = 0; i < nb; i++) {
1097             TRACE("Processing pin %d\n", i);
1098             hr = IGraphBuilder_Render(iface, ppins[i]);
1099             if (FAILED(hr)) {
1100                 ERR("Cannot render pin %p (%x)\n", ppins[i], hr);
1101                 partial = 1;
1102             }
1103             IPin_Release(ppins[i]);
1104         }
1105         CoTaskMemFree(ppins);
1106
1107         hr = (partial ? VFW_S_PARTIAL_RENDER : S_OK);
1108     }
1109
1110     return hr;
1111 }
1112
1113 static HRESULT WINAPI GraphBuilder_AddSourceFilter(IGraphBuilder *iface,
1114                                                    LPCWSTR lpcwstrFileName,
1115                                                    LPCWSTR lpcwstrFilterName,
1116                                                    IBaseFilter **ppFilter) {
1117     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
1118     HRESULT hr;
1119     IBaseFilter* preader;
1120     IFileSourceFilter* pfile = NULL;
1121     AM_MEDIA_TYPE mt;
1122     WCHAR* filename;
1123
1124     TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
1125
1126     /* Instantiate a file source filter */ 
1127     hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader);
1128     if (FAILED(hr)) {
1129         ERR("Unable to create file source filter (%x)\n", hr);
1130         return hr;
1131     }
1132
1133     hr = IGraphBuilder_AddFilter(iface, preader, lpcwstrFilterName);
1134     if (FAILED(hr)) {
1135         ERR("Unable add filter (%x)\n", hr);
1136         IBaseFilter_Release(preader);
1137         return hr;
1138     }
1139
1140     hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
1141     if (FAILED(hr)) {
1142         ERR("Unable to get IFileSourceInterface (%x)\n", hr);
1143         goto error;
1144     }
1145
1146     /* Load the file in the file source filter */
1147     hr = IFileSourceFilter_Load(pfile, lpcwstrFileName, NULL);
1148     if (FAILED(hr)) {
1149         ERR("Load (%x)\n", hr);
1150         goto error;
1151     }
1152     
1153     IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
1154     if (FAILED(hr)) {
1155         ERR("GetCurFile (%x)\n", hr);
1156         goto error;
1157     }
1158     TRACE("File %s\n", debugstr_w(filename));
1159     TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
1160     TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
1161
1162     if (ppFilter)
1163         *ppFilter = preader;
1164
1165     return S_OK;
1166     
1167 error:
1168     if (pfile)
1169         IFileSourceFilter_Release(pfile);
1170     IGraphBuilder_RemoveFilter(iface, preader);
1171     IBaseFilter_Release(preader);
1172        
1173     return hr;
1174 }
1175
1176 static HRESULT WINAPI GraphBuilder_SetLogFile(IGraphBuilder *iface,
1177                                               DWORD_PTR hFile) {
1178     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
1179
1180     TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1181
1182     return S_OK;
1183 }
1184
1185 static HRESULT WINAPI GraphBuilder_Abort(IGraphBuilder *iface) {
1186     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
1187
1188     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1189
1190     return S_OK;
1191 }
1192
1193 static HRESULT WINAPI GraphBuilder_ShouldOperationContinue(IGraphBuilder *iface) {
1194     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
1195
1196     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1197
1198     return S_OK;
1199 }
1200
1201
1202 static const IGraphBuilderVtbl IGraphBuilder_VTable =
1203 {
1204     GraphBuilder_QueryInterface,
1205     GraphBuilder_AddRef,
1206     GraphBuilder_Release,
1207     GraphBuilder_AddFilter,
1208     GraphBuilder_RemoveFilter,
1209     GraphBuilder_EnumFilters,
1210     GraphBuilder_FindFilterByName,
1211     GraphBuilder_ConnectDirect,
1212     GraphBuilder_Reconnect,
1213     GraphBuilder_Disconnect,
1214     GraphBuilder_SetDefaultSyncSource,
1215     GraphBuilder_Connect,
1216     GraphBuilder_Render,
1217     GraphBuilder_RenderFile,
1218     GraphBuilder_AddSourceFilter,
1219     GraphBuilder_SetLogFile,
1220     GraphBuilder_Abort,
1221     GraphBuilder_ShouldOperationContinue
1222 };
1223
1224 /*** IUnknown methods ***/
1225 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface,
1226                                                   REFIID riid,
1227                                                   LPVOID*ppvObj) {
1228     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1229
1230     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1231
1232     return Filtergraph_QueryInterface(This, riid, ppvObj);
1233 }
1234
1235 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface) {
1236     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1237
1238     TRACE("(%p/%p)->()\n", This, iface);
1239
1240     return Filtergraph_AddRef(This);
1241 }
1242
1243 static ULONG WINAPI MediaControl_Release(IMediaControl *iface) {
1244     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1245
1246     TRACE("(%p/%p)->()\n", This, iface);
1247
1248     return Filtergraph_Release(This);
1249
1250 }
1251
1252 /*** IDispatch methods ***/
1253 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface,
1254                                                     UINT*pctinfo) {
1255     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1256
1257     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1258
1259     return S_OK;
1260 }
1261
1262 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface,
1263                                                UINT iTInfo,
1264                                                LCID lcid,
1265                                                ITypeInfo**ppTInfo) {
1266     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1267
1268     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1269
1270     return S_OK;
1271 }
1272
1273 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface,
1274                                                  REFIID riid,
1275                                                  LPOLESTR*rgszNames,
1276                                                  UINT cNames,
1277                                                  LCID lcid,
1278                                                  DISPID*rgDispId) {
1279     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1280
1281     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1282
1283     return S_OK;
1284 }
1285
1286 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface,
1287                                           DISPID dispIdMember,
1288                                           REFIID riid,
1289                                           LCID lcid,
1290                                           WORD wFlags,
1291                                           DISPPARAMS*pDispParams,
1292                                           VARIANT*pVarResult,
1293                                           EXCEPINFO*pExepInfo,
1294                                           UINT*puArgErr) {
1295     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1296
1297     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1298
1299     return S_OK;
1300 }
1301
1302 typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *);
1303
1304 static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter)
1305 {
1306     HRESULT hr;
1307     IPin* pInputPin;
1308     IPin** ppPins;
1309     ULONG nb;
1310     ULONG i;
1311     PIN_INFO PinInfo;
1312
1313     TRACE("%p %p\n", pGraph, pOutputPin);
1314     PinInfo.pFilter = NULL;
1315
1316     hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
1317
1318     if (SUCCEEDED(hr))
1319         hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
1320
1321     if (SUCCEEDED(hr))
1322         hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
1323
1324     if (SUCCEEDED(hr))
1325     {
1326         if (nb == 0)
1327         {
1328             TRACE("Reached a renderer\n");
1329             /* Count renderers for end of stream notification */
1330             pGraph->nRenderers++;
1331         }
1332         else
1333         {
1334             for(i = 0; i < nb; i++)
1335             {
1336                 /* Explore the graph downstream from this pin
1337                  * FIXME: We should prevent exploring from a pin more than once. This can happens when
1338                  * several input pins are connected to the same output (a MUX for instance). */
1339                 ExploreGraph(pGraph, ppPins[i], FoundFilter);
1340                 IPin_Release(ppPins[i]);
1341             }
1342
1343             CoTaskMemFree(ppPins);
1344         }
1345         TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
1346         FoundFilter(PinInfo.pFilter);
1347     }
1348
1349     if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
1350     return hr;
1351 }
1352
1353 static HRESULT WINAPI SendRun(IBaseFilter *pFilter) {
1354    return IBaseFilter_Run(pFilter, 0);
1355 }
1356
1357 static HRESULT WINAPI SendPause(IBaseFilter *pFilter) {
1358    return IBaseFilter_Pause(pFilter);
1359 }
1360
1361 static HRESULT WINAPI SendStop(IBaseFilter *pFilter) {
1362    return IBaseFilter_Stop(pFilter);
1363 }
1364
1365 static HRESULT SendFilterMessage(IMediaControl *iface, fnFoundFilter FoundFilter) {
1366     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1367     int i;
1368     IBaseFilter* pfilter;
1369     IEnumPins* pEnum;
1370     HRESULT hr;
1371     IPin* pPin;
1372     DWORD dummy;
1373     PIN_DIRECTION dir;
1374     TRACE("(%p/%p)->()\n", This, iface);
1375
1376     /* Explorer the graph from source filters to renderers, determine renderers
1377      * number and run filters from renderers to source filters */
1378     This->nRenderers = 0;  
1379     ResetEvent(This->hEventCompletion);
1380
1381     for(i = 0; i < This->nFilters; i++)
1382     {
1383         BOOL source = TRUE;
1384         pfilter = This->ppFiltersInGraph[i];
1385         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
1386         if (hr != S_OK)
1387         {
1388             ERR("Enum pins failed %x\n", hr);
1389             continue;
1390         }
1391         /* Check if it is a source filter */
1392         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1393         {
1394             IPin_QueryDirection(pPin, &dir);
1395             IPin_Release(pPin);
1396             if (dir == PINDIR_INPUT)
1397             {
1398                 source = FALSE;
1399                 break;
1400             }
1401         }
1402         if (source)
1403         {
1404             TRACE("Found a source filter %p\n", pfilter);
1405             IEnumPins_Reset(pEnum);
1406             while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1407             {
1408                 /* Explore the graph downstream from this pin */
1409                 ExploreGraph(This, pPin, FoundFilter);
1410                 IPin_Release(pPin);
1411             }
1412             FoundFilter(pfilter);
1413         }
1414         IEnumPins_Release(pEnum);
1415     }
1416
1417     return S_FALSE;
1418 }
1419
1420 /*** IMediaControl methods ***/
1421 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface) {
1422     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1423     TRACE("(%p/%p)->()\n", This, iface);
1424
1425     if (This->state == State_Running) return S_OK;
1426
1427     EnterCriticalSection(&This->cs);
1428     SendFilterMessage(iface, SendRun);
1429     This->state = State_Running;
1430     LeaveCriticalSection(&This->cs);
1431     return S_FALSE;
1432 }
1433
1434 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface) {
1435     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1436     TRACE("(%p/%p)->()\n", This, iface);
1437
1438     if (This->state == State_Paused) return S_OK;
1439
1440     EnterCriticalSection(&This->cs);
1441     SendFilterMessage(iface, SendPause);
1442     This->state = State_Paused;
1443     LeaveCriticalSection(&This->cs);
1444     return S_FALSE;
1445 }
1446
1447 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface) {
1448     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1449     TRACE("(%p/%p)->()\n", This, iface);
1450
1451     if (This->state == State_Stopped) return S_OK;
1452
1453     EnterCriticalSection(&This->cs);
1454     if (This->state == State_Running) SendFilterMessage(iface, SendPause);
1455     SendFilterMessage(iface, SendStop);
1456     This->state = State_Stopped;
1457     LeaveCriticalSection(&This->cs);
1458     return S_FALSE;
1459 }
1460
1461 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface,
1462                                             LONG msTimeout,
1463                                             OAFilterState *pfs) {
1464     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1465
1466     TRACE("(%p/%p)->(%d, %p): semi-stub !!!\n", This, iface, msTimeout, pfs);
1467
1468     EnterCriticalSection(&This->cs);
1469
1470     *pfs = This->state;
1471
1472     LeaveCriticalSection(&This->cs);
1473
1474     return S_OK;
1475 }
1476
1477 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface,
1478                                               BSTR strFilename) {
1479     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1480
1481     TRACE("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename);
1482
1483     return S_OK;
1484 }
1485
1486 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface,
1487                                                    BSTR strFilename,
1488                                                    IDispatch **ppUnk) {
1489     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1490
1491     TRACE("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
1492
1493     return S_OK;
1494 }
1495
1496 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface,
1497                                                         IDispatch **ppUnk) {
1498     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1499
1500     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
1501
1502     return S_OK;
1503 }
1504
1505 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface,
1506                                                            IDispatch **ppUnk) {
1507     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1508
1509     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
1510
1511     return S_OK;
1512 }
1513
1514 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface) {
1515     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1516
1517     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1518
1519     return S_OK;
1520 }
1521
1522
1523 static const IMediaControlVtbl IMediaControl_VTable =
1524 {
1525     MediaControl_QueryInterface,
1526     MediaControl_AddRef,
1527     MediaControl_Release,
1528     MediaControl_GetTypeInfoCount,
1529     MediaControl_GetTypeInfo,
1530     MediaControl_GetIDsOfNames,
1531     MediaControl_Invoke,
1532     MediaControl_Run,
1533     MediaControl_Pause,
1534     MediaControl_Stop,
1535     MediaControl_GetState,
1536     MediaControl_RenderFile,
1537     MediaControl_AddSourceFilter,
1538     MediaControl_get_FilterCollection,
1539     MediaControl_get_RegFilterCollection,
1540     MediaControl_StopWhenReady
1541 };
1542
1543
1544 /*** IUnknown methods ***/
1545 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface,
1546                                                   REFIID riid,
1547                                                   LPVOID*ppvObj) {
1548     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1549
1550     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1551
1552     return Filtergraph_QueryInterface(This, riid, ppvObj);
1553 }
1554
1555 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface) {
1556     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1557
1558     TRACE("(%p/%p)->()\n", This, iface);
1559
1560     return Filtergraph_AddRef(This);
1561 }
1562
1563 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface) {
1564     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1565
1566     TRACE("(%p/%p)->()\n", This, iface);
1567
1568     return Filtergraph_Release(This);
1569 }
1570
1571 /*** IMediaSeeking methods ***/
1572 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface,
1573                                                    DWORD *pCapabilities) {
1574     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1575
1576     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pCapabilities);
1577
1578     return S_OK;
1579 }
1580
1581 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface,
1582                                                      DWORD *pCapabilities) {
1583     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1584
1585     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pCapabilities);
1586
1587     return S_OK;
1588 }
1589
1590 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface,
1591                                                      const GUID *pFormat) {
1592     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1593
1594     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1595
1596     return S_OK;
1597 }
1598
1599 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface,
1600                                                         GUID *pFormat) {
1601     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1602
1603     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1604
1605     return S_OK;
1606 }
1607
1608 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface,
1609                                                  GUID *pFormat) {
1610     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1611
1612     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1613
1614     return S_OK;
1615 }
1616
1617 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface,
1618                                                      const GUID *pFormat) {
1619     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1620
1621     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1622
1623     return S_OK;
1624 }
1625
1626 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface,
1627                                                  const GUID *pFormat) {
1628     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1629
1630     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1631
1632     return S_OK;
1633 }
1634
1635 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface,
1636                                                LONGLONG *pDuration) {
1637     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1638
1639     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDuration);
1640
1641     return S_OK;
1642 }
1643
1644 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface,
1645                                                    LONGLONG *pStop) {
1646     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1647
1648     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pStop);
1649
1650     return S_OK;
1651 }
1652
1653 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface,
1654                                                       LONGLONG *pCurrent) {
1655     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1656
1657     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pCurrent);
1658
1659     return S_OK;
1660 }
1661
1662 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface,
1663                                                      LONGLONG *pTarget,
1664                                                      const GUID *pTargetFormat,
1665                                                      LONGLONG Source,
1666                                                      const GUID *pSourceFormat) {
1667     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1668
1669     TRACE("(%p/%p)->(%p, %p, 0x%s, %p): stub !!!\n", This, iface, pTarget,
1670         pTargetFormat, wine_dbgstr_longlong(Source), pSourceFormat);
1671
1672     return S_OK;
1673 }
1674
1675 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface,
1676                                                 LONGLONG *pCurrent,
1677                                                 DWORD dwCurrentFlags,
1678                                                 LONGLONG *pStop,
1679                                                 DWORD dwStopFlags) {
1680     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1681
1682     TRACE("(%p/%p)->(%p, %08x, %p, %08x): stub !!!\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
1683
1684     return S_OK;
1685 }
1686
1687 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
1688                                                 LONGLONG *pCurrent,
1689                                                 LONGLONG *pStop) {
1690     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1691
1692     TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pCurrent, pStop);
1693
1694     return S_OK;
1695 }
1696
1697 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
1698                                                 LONGLONG *pEarliest,
1699                                                 LONGLONG *pLatest) {
1700     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1701
1702     TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
1703
1704     return S_OK;
1705 }
1706
1707 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface,
1708                                            double dRate) {
1709     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1710
1711     TRACE("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
1712
1713     return S_OK;
1714 }
1715
1716 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface,
1717                                            double *pdRate) {
1718     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1719
1720     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
1721
1722     return S_OK;
1723 }
1724
1725 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface,
1726                                               LONGLONG *pllPreroll) {
1727     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1728
1729     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
1730
1731     return S_OK;
1732 }
1733
1734
1735 static const IMediaSeekingVtbl IMediaSeeking_VTable =
1736 {
1737     MediaSeeking_QueryInterface,
1738     MediaSeeking_AddRef,
1739     MediaSeeking_Release,
1740     MediaSeeking_GetCapabilities,
1741     MediaSeeking_CheckCapabilities,
1742     MediaSeeking_IsFormatSupported,
1743     MediaSeeking_QueryPreferredFormat,
1744     MediaSeeking_GetTimeFormat,
1745     MediaSeeking_IsUsingTimeFormat,
1746     MediaSeeking_SetTimeFormat,
1747     MediaSeeking_GetDuration,
1748     MediaSeeking_GetStopPosition,
1749     MediaSeeking_GetCurrentPosition,
1750     MediaSeeking_ConvertTimeFormat,
1751     MediaSeeking_SetPositions,
1752     MediaSeeking_GetPositions,
1753     MediaSeeking_GetAvailable,
1754     MediaSeeking_SetRate,
1755     MediaSeeking_GetRate,
1756     MediaSeeking_GetPreroll
1757 };
1758
1759 /*** IUnknown methods ***/
1760 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj){
1761     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface);
1762
1763     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1764
1765     return Filtergraph_QueryInterface(This, riid, ppvObj);
1766 }
1767
1768 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface){
1769     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface);
1770
1771     TRACE("(%p/%p)->()\n", This, iface);
1772
1773     return Filtergraph_AddRef(This);
1774 }
1775
1776 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface){
1777     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface);
1778
1779     TRACE("(%p/%p)->()\n", This, iface);
1780
1781     return Filtergraph_Release(This);
1782 }
1783
1784 /*** IDispatch methods ***/
1785 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo){
1786     FIXME("(%p) stub!\n", iface);
1787     return E_NOTIMPL;
1788 }
1789
1790 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo){
1791     FIXME("(%p) stub!\n", iface);
1792     return E_NOTIMPL;
1793 }
1794
1795 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId){
1796     FIXME("(%p) stub!\n", iface);
1797     return E_NOTIMPL;
1798 }
1799
1800 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr){
1801     FIXME("(%p) stub!\n", iface);
1802     return E_NOTIMPL;
1803 }
1804
1805 /*** IMediaPosition methods ***/
1806 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength){
1807     FIXME("(%p)->(%p) stub!\n", iface, plength);
1808     return E_NOTIMPL;
1809 }
1810
1811 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime){
1812     FIXME("(%p)->(%f) stub!\n", iface, llTime);
1813     return E_NOTIMPL;
1814 }
1815
1816 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime){
1817     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
1818     return E_NOTIMPL;
1819 }
1820
1821 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime){
1822     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
1823     return E_NOTIMPL;
1824 }
1825
1826 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime){
1827     FIXME("(%p)->(%f) stub!\n", iface, llTime);
1828     return E_NOTIMPL;
1829 }
1830
1831 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime){
1832     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
1833     return E_NOTIMPL;
1834 }
1835
1836 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime){
1837     FIXME("(%p)->(%f) stub!\n", iface, llTime);
1838     return E_NOTIMPL;
1839 }
1840
1841 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate){
1842     FIXME("(%p)->(%f) stub!\n", iface, dRate);
1843     return E_NOTIMPL;
1844 }
1845
1846 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate){
1847     FIXME("(%p)->(%p) stub!\n", iface, pdRate);
1848     return E_NOTIMPL;
1849 }
1850
1851 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward){
1852     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
1853     return E_NOTIMPL;
1854 }
1855
1856 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward){
1857     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
1858     return E_NOTIMPL;
1859 }
1860
1861
1862 static const IMediaPositionVtbl IMediaPosition_VTable =
1863 {
1864     MediaPosition_QueryInterface,
1865     MediaPosition_AddRef,
1866     MediaPosition_Release,
1867     MediaPosition_GetTypeInfoCount,
1868     MediaPosition_GetTypeInfo,
1869     MediaPosition_GetIDsOfNames,
1870     MediaPosition_Invoke,
1871     MediaPosition_get_Duration,
1872     MediaPosition_put_CurrentPosition,
1873     MediaPosition_get_CurrentPosition,
1874     MediaPosition_get_StopTime,
1875     MediaPosition_put_StopTime,
1876     MediaPosition_get_PrerollTime,
1877     MediaPosition_put_PrerollTime,
1878     MediaPosition_put_Rate,
1879     MediaPosition_get_Rate,
1880     MediaPosition_CanSeekForward,
1881     MediaPosition_CanSeekBackward
1882 };
1883
1884 static HRESULT GetTargetInterface(IFilterGraphImpl* pGraph, REFIID riid, LPVOID* ppvObj)
1885 {
1886     HRESULT hr = E_NOINTERFACE;
1887     int i;
1888     int entry;
1889
1890     /* Check if the interface type is already registered */
1891     for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
1892         if (riid == pGraph->ItfCacheEntries[entry].riid)
1893         {
1894             if (pGraph->ItfCacheEntries[entry].iface)
1895             {
1896                 /* Return the interface if available */
1897                 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
1898                 return S_OK;
1899             }
1900             break;
1901         }
1902
1903     if (entry >= MAX_ITF_CACHE_ENTRIES)
1904     {
1905         FIXME("Not enough space to store interface in the cache\n");
1906         return E_OUTOFMEMORY;
1907     }
1908
1909     /* Find a filter supporting the requested interface */
1910     for (i = 0; i < pGraph->nFilters; i++)
1911     {
1912         hr = IBaseFilter_QueryInterface(pGraph->ppFiltersInGraph[i], riid, ppvObj);
1913         if (hr == S_OK)
1914         {
1915             pGraph->ItfCacheEntries[entry].riid = riid;
1916             pGraph->ItfCacheEntries[entry].filter = pGraph->ppFiltersInGraph[i];
1917             pGraph->ItfCacheEntries[entry].iface = (IUnknown*)*ppvObj;
1918             if (entry >= pGraph->nItfCacheEntries)
1919                 pGraph->nItfCacheEntries++;
1920             return S_OK;
1921         }
1922         if (hr != E_NOINTERFACE)
1923             return hr;
1924     }
1925
1926     return hr;
1927 }
1928
1929 /*** IUnknown methods ***/
1930 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface,
1931                                                 REFIID riid,
1932                                                 LPVOID*ppvObj) {
1933     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1934
1935     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1936
1937     return Filtergraph_QueryInterface(This, riid, ppvObj);
1938 }
1939
1940 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface) {
1941     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1942
1943     TRACE("(%p/%p)->()\n", This, iface);
1944
1945     return Filtergraph_AddRef(This);
1946 }
1947
1948 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface) {
1949     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1950
1951     TRACE("(%p/%p)->()\n", This, iface);
1952
1953     return Filtergraph_Release(This);
1954 }
1955
1956 /*** IDispatch methods ***/
1957 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface,
1958                                                   UINT*pctinfo) {
1959     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1960     IBasicAudio* pBasicAudio;
1961     HRESULT hr;
1962
1963     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
1964
1965     EnterCriticalSection(&This->cs);
1966
1967     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
1968
1969     if (hr == S_OK)
1970         hr = IBasicAudio_GetTypeInfoCount(pBasicAudio, pctinfo);
1971
1972     LeaveCriticalSection(&This->cs);
1973
1974     return hr;
1975 }
1976
1977 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface,
1978                                              UINT iTInfo,
1979                                              LCID lcid,
1980                                              ITypeInfo**ppTInfo) {
1981     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1982     IBasicAudio* pBasicAudio;
1983     HRESULT hr;
1984
1985     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
1986
1987     EnterCriticalSection(&This->cs);
1988
1989     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
1990
1991     if (hr == S_OK)
1992         hr = IBasicAudio_GetTypeInfo(pBasicAudio, iTInfo, lcid, ppTInfo);
1993
1994     LeaveCriticalSection(&This->cs);
1995
1996     return hr;
1997 }
1998
1999 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface,
2000                                                REFIID riid,
2001                                                LPOLESTR*rgszNames,
2002                                                UINT cNames,
2003                                                LCID lcid,
2004                                                DISPID*rgDispId) {
2005     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2006     IBasicAudio* pBasicAudio;
2007     HRESULT hr;
2008
2009     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
2010
2011     EnterCriticalSection(&This->cs);
2012
2013     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2014
2015     if (hr == S_OK)
2016         hr = IBasicAudio_GetIDsOfNames(pBasicAudio, riid, rgszNames, cNames, lcid, rgDispId);
2017
2018     LeaveCriticalSection(&This->cs);
2019
2020     return hr;
2021 }
2022
2023 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface,
2024                                         DISPID dispIdMember,
2025                                         REFIID riid,
2026                                         LCID lcid,
2027                                         WORD wFlags,
2028                                         DISPPARAMS*pDispParams,
2029                                         VARIANT*pVarResult,
2030                                         EXCEPINFO*pExepInfo,
2031                                         UINT*puArgErr) {
2032     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2033     IBasicAudio* pBasicAudio;
2034     HRESULT hr;
2035
2036     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2037
2038     EnterCriticalSection(&This->cs);
2039
2040     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2041
2042     if (hr == S_OK)
2043         hr = IBasicAudio_Invoke(pBasicAudio, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2044
2045     LeaveCriticalSection(&This->cs);
2046
2047     return hr;
2048 }
2049
2050 /*** IBasicAudio methods ***/
2051 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface,
2052                                             long lVolume) {
2053     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2054     IBasicAudio* pBasicAudio;
2055     HRESULT hr;
2056
2057     TRACE("(%p/%p)->(%ld)\n", This, iface, lVolume);
2058
2059     EnterCriticalSection(&This->cs);
2060
2061     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2062
2063     if (hr == S_OK)
2064         hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
2065
2066     LeaveCriticalSection(&This->cs);
2067
2068     return hr;
2069 }
2070
2071 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface,
2072                                             long *plVolume) {
2073     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2074     IBasicAudio* pBasicAudio;
2075     HRESULT hr;
2076
2077     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
2078
2079     EnterCriticalSection(&This->cs);
2080
2081     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2082
2083     if (hr == S_OK)
2084         hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
2085
2086     LeaveCriticalSection(&This->cs);
2087
2088     return hr;
2089 }
2090
2091 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface,
2092                                              long lBalance) {
2093     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2094     IBasicAudio* pBasicAudio;
2095     HRESULT hr;
2096
2097     TRACE("(%p/%p)->(%ld)\n", This, iface, lBalance);
2098
2099     EnterCriticalSection(&This->cs);
2100
2101     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2102
2103     if (hr == S_OK)
2104         hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
2105
2106     LeaveCriticalSection(&This->cs);
2107
2108     return hr;
2109 }
2110
2111 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface,
2112                                              long *plBalance) {
2113     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2114     IBasicAudio* pBasicAudio;
2115     HRESULT hr;
2116
2117     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
2118
2119     EnterCriticalSection(&This->cs);
2120
2121     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2122
2123     if (hr == S_OK)
2124         hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
2125
2126     LeaveCriticalSection(&This->cs);
2127
2128     return hr;
2129 }
2130
2131 static const IBasicAudioVtbl IBasicAudio_VTable =
2132 {
2133     BasicAudio_QueryInterface,
2134     BasicAudio_AddRef,
2135     BasicAudio_Release,
2136     BasicAudio_GetTypeInfoCount,
2137     BasicAudio_GetTypeInfo,
2138     BasicAudio_GetIDsOfNames,
2139     BasicAudio_Invoke,
2140     BasicAudio_put_Volume,
2141     BasicAudio_get_Volume,
2142     BasicAudio_put_Balance,
2143     BasicAudio_get_Balance
2144 };
2145
2146 /*** IUnknown methods ***/
2147 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo *iface,
2148                                                 REFIID riid,
2149                                                 LPVOID*ppvObj) {
2150     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2151
2152     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2153
2154     return Filtergraph_QueryInterface(This, riid, ppvObj);
2155 }
2156
2157 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo *iface) {
2158     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2159
2160     TRACE("(%p/%p)->()\n", This, iface);
2161
2162     return Filtergraph_AddRef(This);
2163 }
2164
2165 static ULONG WINAPI BasicVideo_Release(IBasicVideo *iface) {
2166     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2167
2168     TRACE("(%p/%p)->()\n", This, iface);
2169
2170     return Filtergraph_Release(This);
2171 }
2172
2173 /*** IDispatch methods ***/
2174 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo *iface,
2175                                                   UINT*pctinfo) {
2176     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2177     IBasicVideo* pBasicVideo;
2178     HRESULT hr;
2179
2180     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
2181
2182     EnterCriticalSection(&This->cs);
2183
2184     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2185
2186     if (hr == S_OK)
2187         hr = IBasicVideo_GetTypeInfoCount(pBasicVideo, pctinfo);
2188
2189     LeaveCriticalSection(&This->cs);
2190
2191     return hr;
2192 }
2193
2194 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo *iface,
2195                                              UINT iTInfo,
2196                                              LCID lcid,
2197                                              ITypeInfo**ppTInfo) {
2198     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2199     IBasicVideo* pBasicVideo;
2200     HRESULT hr;
2201
2202     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
2203
2204     EnterCriticalSection(&This->cs);
2205
2206     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2207
2208     if (hr == S_OK)
2209         hr = IBasicVideo_GetTypeInfo(pBasicVideo, iTInfo, lcid, ppTInfo);
2210
2211     LeaveCriticalSection(&This->cs);
2212
2213     return hr;
2214 }
2215
2216 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo *iface,
2217                                                REFIID riid,
2218                                                LPOLESTR*rgszNames,
2219                                                UINT cNames,
2220                                                LCID lcid,
2221                                                DISPID*rgDispId) {
2222     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2223     IBasicVideo* pBasicVideo;
2224     HRESULT hr;
2225
2226     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
2227
2228     EnterCriticalSection(&This->cs);
2229
2230     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2231
2232     if (hr == S_OK)
2233         hr = IBasicVideo_GetIDsOfNames(pBasicVideo, riid, rgszNames, cNames, lcid, rgDispId);
2234
2235     LeaveCriticalSection(&This->cs);
2236
2237     return hr;
2238 }
2239
2240 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo *iface,
2241                                         DISPID dispIdMember,
2242                                         REFIID riid,
2243                                         LCID lcid,
2244                                         WORD wFlags,
2245                                         DISPPARAMS*pDispParams,
2246                                         VARIANT*pVarResult,
2247                                         EXCEPINFO*pExepInfo,
2248                                         UINT*puArgErr) {
2249     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2250     IBasicVideo* pBasicVideo;
2251     HRESULT hr;
2252
2253     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2254
2255     EnterCriticalSection(&This->cs);
2256
2257     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2258
2259     if (hr == S_OK)
2260         hr = IBasicVideo_Invoke(pBasicVideo, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2261
2262     LeaveCriticalSection(&This->cs);
2263
2264     return hr;
2265 }
2266
2267 /*** IBasicVideo methods ***/
2268 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo *iface,
2269                                                      REFTIME *pAvgTimePerFrame) {
2270     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2271     IBasicVideo* pBasicVideo;
2272     HRESULT hr;
2273
2274     TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
2275
2276     EnterCriticalSection(&This->cs);
2277
2278     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2279
2280     if (hr == S_OK)
2281         hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
2282
2283     LeaveCriticalSection(&This->cs);
2284
2285     return hr;
2286 }
2287
2288 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo *iface,
2289                                              long *pBitRate) {
2290     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2291     IBasicVideo* pBasicVideo;
2292     HRESULT hr;
2293
2294     TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
2295
2296     EnterCriticalSection(&This->cs);
2297
2298     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2299
2300     if (hr == S_OK)
2301         hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
2302
2303     LeaveCriticalSection(&This->cs);
2304
2305     return hr;
2306 }
2307
2308 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo *iface,
2309                                                   long *pBitErrorRate) {
2310     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2311     IBasicVideo* pBasicVideo;
2312     HRESULT hr;
2313
2314     TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
2315
2316     EnterCriticalSection(&This->cs);
2317
2318     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2319
2320     if (hr == S_OK)
2321         hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
2322
2323     LeaveCriticalSection(&This->cs);
2324
2325     return hr;
2326 }
2327
2328 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo *iface,
2329                                                 long *pVideoWidth) {
2330     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2331     IBasicVideo* pBasicVideo;
2332     HRESULT hr;
2333
2334     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
2335
2336     EnterCriticalSection(&This->cs);
2337
2338     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2339
2340     if (hr == S_OK)
2341         hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
2342
2343     LeaveCriticalSection(&This->cs);
2344
2345     return hr;
2346 }
2347
2348 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo *iface,
2349                                                  long *pVideoHeight) {
2350     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2351     IBasicVideo* pBasicVideo;
2352     HRESULT hr;
2353
2354     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
2355
2356     EnterCriticalSection(&This->cs);
2357
2358     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2359
2360     if (hr == S_OK)
2361         hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
2362
2363     LeaveCriticalSection(&This->cs);
2364
2365     return hr;
2366 }
2367
2368 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo *iface,
2369                                                 long SourceLeft) {
2370     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2371     IBasicVideo* pBasicVideo;
2372     HRESULT hr;
2373
2374     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceLeft);
2375
2376     EnterCriticalSection(&This->cs);
2377
2378     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2379
2380     if (hr == S_OK)
2381         hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
2382
2383     LeaveCriticalSection(&This->cs);
2384
2385     return hr;
2386 }
2387
2388 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo *iface,
2389                                                 long *pSourceLeft) {
2390     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2391     IBasicVideo* pBasicVideo;
2392     HRESULT hr;
2393
2394     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
2395
2396     EnterCriticalSection(&This->cs);
2397
2398     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2399
2400     if (hr == S_OK)
2401         hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
2402
2403     LeaveCriticalSection(&This->cs);
2404
2405     return hr;
2406 }
2407
2408 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo *iface,
2409                                                  long SourceWidth) {
2410     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2411     IBasicVideo* pBasicVideo;
2412     HRESULT hr;
2413
2414     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceWidth);
2415
2416     EnterCriticalSection(&This->cs);
2417
2418     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2419
2420     if (hr == S_OK)
2421         hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
2422
2423     LeaveCriticalSection(&This->cs);
2424
2425     return hr;
2426 }
2427
2428 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo *iface,
2429                                                  long *pSourceWidth) {
2430     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2431     IBasicVideo* pBasicVideo;
2432     HRESULT hr;
2433
2434     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
2435
2436     EnterCriticalSection(&This->cs);
2437
2438     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2439
2440     if (hr == S_OK)
2441         hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
2442
2443     LeaveCriticalSection(&This->cs);
2444
2445     return hr;
2446 }
2447
2448 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo *iface,
2449                                                long SourceTop) {
2450     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2451     IBasicVideo* pBasicVideo;
2452     HRESULT hr;
2453
2454     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceTop);
2455
2456     EnterCriticalSection(&This->cs);
2457
2458     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2459
2460     if (hr == S_OK)
2461         hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
2462
2463     LeaveCriticalSection(&This->cs);
2464
2465     return hr;
2466 }
2467
2468 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo *iface,
2469                                                long *pSourceTop) {
2470     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2471     IBasicVideo* pBasicVideo;
2472     HRESULT hr;
2473
2474     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
2475
2476     EnterCriticalSection(&This->cs);
2477
2478     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2479
2480     if (hr == S_OK)
2481         hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
2482
2483     LeaveCriticalSection(&This->cs);
2484
2485     return hr;
2486 }
2487
2488 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo *iface,
2489                                                   long SourceHeight) {
2490     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2491     IBasicVideo* pBasicVideo;
2492     HRESULT hr;
2493
2494     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceHeight);
2495
2496     EnterCriticalSection(&This->cs);
2497
2498     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2499
2500     if (hr == S_OK)
2501         hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
2502
2503     LeaveCriticalSection(&This->cs);
2504
2505     return hr;
2506 }
2507
2508 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo *iface,
2509                                                   long *pSourceHeight) {
2510     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2511     IBasicVideo* pBasicVideo;
2512     HRESULT hr;
2513
2514     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
2515
2516     EnterCriticalSection(&This->cs);
2517
2518     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2519
2520     if (hr == S_OK)
2521         hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
2522
2523     LeaveCriticalSection(&This->cs);
2524
2525     return hr;
2526 }
2527
2528 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo *iface,
2529                                                      long DestinationLeft) {
2530     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2531     IBasicVideo* pBasicVideo;
2532     HRESULT hr;
2533
2534     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationLeft);
2535
2536     EnterCriticalSection(&This->cs);
2537
2538     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2539
2540     if (hr == S_OK)
2541         hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
2542
2543     LeaveCriticalSection(&This->cs);
2544
2545     return hr;
2546 }
2547
2548 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo *iface,
2549                                                      long *pDestinationLeft) {
2550     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2551     IBasicVideo* pBasicVideo;
2552     HRESULT hr;
2553
2554     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
2555
2556     EnterCriticalSection(&This->cs);
2557
2558     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2559
2560     if (hr == S_OK)
2561         hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
2562
2563     LeaveCriticalSection(&This->cs);
2564
2565     return hr;
2566 }
2567
2568 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo *iface,
2569                                                       long DestinationWidth) {
2570     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2571     IBasicVideo* pBasicVideo;
2572     HRESULT hr;
2573
2574     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationWidth);
2575
2576     EnterCriticalSection(&This->cs);
2577
2578     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2579
2580     if (hr == S_OK)
2581         hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
2582
2583     LeaveCriticalSection(&This->cs);
2584
2585     return hr;
2586 }
2587
2588 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo *iface,
2589                                                       long *pDestinationWidth) {
2590     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2591     IBasicVideo* pBasicVideo;
2592     HRESULT hr;
2593
2594     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
2595
2596     EnterCriticalSection(&This->cs);
2597
2598     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2599
2600     if (hr == S_OK)
2601         hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
2602
2603     LeaveCriticalSection(&This->cs);
2604
2605     return hr;
2606 }
2607
2608 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo *iface,
2609                                                     long DestinationTop) {
2610     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2611     IBasicVideo* pBasicVideo;
2612     HRESULT hr;
2613
2614     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationTop);
2615
2616     EnterCriticalSection(&This->cs);
2617
2618     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2619
2620     if (hr == S_OK)
2621         hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
2622
2623     LeaveCriticalSection(&This->cs);
2624
2625     return hr;
2626 }
2627
2628 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo *iface,
2629                                                     long *pDestinationTop) {
2630     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2631     IBasicVideo* pBasicVideo;
2632     HRESULT hr;
2633
2634     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
2635
2636     EnterCriticalSection(&This->cs);
2637
2638     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2639
2640     if (hr == S_OK)
2641         hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
2642
2643     LeaveCriticalSection(&This->cs);
2644
2645     return hr;
2646 }
2647
2648 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo *iface,
2649                                                        long DestinationHeight) {
2650     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2651     IBasicVideo* pBasicVideo;
2652     HRESULT hr;
2653
2654     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationHeight);
2655
2656     EnterCriticalSection(&This->cs);
2657
2658     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2659
2660     if (hr == S_OK)
2661         hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
2662
2663     LeaveCriticalSection(&This->cs);
2664
2665     return hr;
2666 }
2667
2668 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo *iface,
2669                                                        long *pDestinationHeight) {
2670     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2671     IBasicVideo* pBasicVideo;
2672     HRESULT hr;
2673
2674     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
2675
2676     EnterCriticalSection(&This->cs);
2677
2678     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2679
2680     if (hr == S_OK)
2681         hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
2682
2683     LeaveCriticalSection(&This->cs);
2684
2685     return hr;
2686 }
2687
2688 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo *iface,
2689                                                    long Left,
2690                                                    long Top,
2691                                                    long Width,
2692                                                    long Height) {
2693     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2694     IBasicVideo* pBasicVideo;
2695     HRESULT hr;
2696
2697     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
2698
2699     EnterCriticalSection(&This->cs);
2700
2701     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2702
2703     if (hr == S_OK)
2704         hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
2705
2706     LeaveCriticalSection(&This->cs);
2707
2708     return hr;
2709 }
2710
2711 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo *iface,
2712                                                    long *pLeft,
2713                                                    long *pTop,
2714                                                    long *pWidth,
2715                                                    long *pHeight) {
2716     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2717     IBasicVideo* pBasicVideo;
2718     HRESULT hr;
2719
2720     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
2721
2722     EnterCriticalSection(&This->cs);
2723
2724     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2725
2726     if (hr == S_OK)
2727         hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
2728
2729     LeaveCriticalSection(&This->cs);
2730
2731     return hr;
2732 }
2733
2734 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo *iface) {
2735     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2736     IBasicVideo* pBasicVideo;
2737     HRESULT hr;
2738
2739     TRACE("(%p/%p)->()\n", This, iface);
2740
2741     EnterCriticalSection(&This->cs);
2742
2743     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2744
2745     if (hr == S_OK)
2746         hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
2747
2748     LeaveCriticalSection(&This->cs);
2749
2750     return hr;
2751 }
2752
2753 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo *iface,
2754                                                         long Left,
2755                                                         long Top,
2756                                                         long Width,
2757                                                         long Height) {
2758     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2759     IBasicVideo* pBasicVideo;
2760     HRESULT hr;
2761
2762     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
2763
2764     EnterCriticalSection(&This->cs);
2765
2766     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2767
2768     if (hr == S_OK)
2769         hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
2770
2771     LeaveCriticalSection(&This->cs);
2772
2773     return hr;
2774 }
2775
2776 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo *iface,
2777                                                         long *pLeft,
2778                                                         long *pTop,
2779                                                         long *pWidth,
2780                                                         long *pHeight) {
2781     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2782     IBasicVideo* pBasicVideo;
2783     HRESULT hr;
2784
2785     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
2786
2787     EnterCriticalSection(&This->cs);
2788
2789     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2790
2791     if (hr == S_OK)
2792         hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
2793
2794     LeaveCriticalSection(&This->cs);
2795
2796     return hr;
2797 }
2798
2799 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo *iface) {
2800     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2801     IBasicVideo* pBasicVideo;
2802     HRESULT hr;
2803
2804     TRACE("(%p/%p)->()\n", This, iface);
2805
2806     EnterCriticalSection(&This->cs);
2807
2808     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2809
2810     if (hr == S_OK)
2811         hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
2812
2813     LeaveCriticalSection(&This->cs);
2814
2815     return hr;
2816 }
2817
2818 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo *iface,
2819                                               long *pWidth,
2820                                               long *pHeight) {
2821     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2822     IBasicVideo* pBasicVideo;
2823     HRESULT hr;
2824
2825     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
2826
2827     EnterCriticalSection(&This->cs);
2828
2829     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2830
2831     if (hr == S_OK)
2832         hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
2833
2834     LeaveCriticalSection(&This->cs);
2835
2836     return hr;
2837 }
2838
2839 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo *iface,
2840                                                         long StartIndex,
2841                                                         long Entries,
2842                                                         long *pRetrieved,
2843                                                         long *pPalette) {
2844     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2845     IBasicVideo* pBasicVideo;
2846     HRESULT hr;
2847
2848     TRACE("(%p/%p)->(%ld, %ld, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
2849
2850     EnterCriticalSection(&This->cs);
2851
2852     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2853
2854     if (hr == S_OK)
2855         hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
2856
2857     LeaveCriticalSection(&This->cs);
2858
2859     return hr;
2860 }
2861
2862 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo *iface,
2863                                                  long *pBufferSize,
2864                                                  long *pDIBImage) {
2865     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2866     IBasicVideo* pBasicVideo;
2867     HRESULT hr;
2868
2869     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
2870
2871     EnterCriticalSection(&This->cs);
2872
2873     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2874
2875     if (hr == S_OK)
2876         hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
2877
2878     LeaveCriticalSection(&This->cs);
2879
2880     return hr;
2881 }
2882
2883 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo *iface) {
2884     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2885     IBasicVideo* pBasicVideo;
2886     HRESULT hr;
2887
2888     TRACE("(%p/%p)->()\n", This, iface);
2889
2890     EnterCriticalSection(&This->cs);
2891
2892     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2893
2894     if (hr == S_OK)
2895         hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
2896
2897     LeaveCriticalSection(&This->cs);
2898
2899     return hr;
2900 }
2901
2902 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo *iface) {
2903     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2904     IBasicVideo* pBasicVideo;
2905     HRESULT hr;
2906
2907     TRACE("(%p/%p)->()\n", This, iface);
2908
2909     EnterCriticalSection(&This->cs);
2910
2911     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2912
2913     if (hr == S_OK)
2914         hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
2915
2916     LeaveCriticalSection(&This->cs);
2917
2918     return hr;
2919 }
2920
2921
2922 static const IBasicVideoVtbl IBasicVideo_VTable =
2923 {
2924     BasicVideo_QueryInterface,
2925     BasicVideo_AddRef,
2926     BasicVideo_Release,
2927     BasicVideo_GetTypeInfoCount,
2928     BasicVideo_GetTypeInfo,
2929     BasicVideo_GetIDsOfNames,
2930     BasicVideo_Invoke,
2931     BasicVideo_get_AvgTimePerFrame,
2932     BasicVideo_get_BitRate,
2933     BasicVideo_get_BitErrorRate,
2934     BasicVideo_get_VideoWidth,
2935     BasicVideo_get_VideoHeight,
2936     BasicVideo_put_SourceLeft,
2937     BasicVideo_get_SourceLeft,
2938     BasicVideo_put_SourceWidth,
2939     BasicVideo_get_SourceWidth,
2940     BasicVideo_put_SourceTop,
2941     BasicVideo_get_SourceTop,
2942     BasicVideo_put_SourceHeight,
2943     BasicVideo_get_SourceHeight,
2944     BasicVideo_put_DestinationLeft,
2945     BasicVideo_get_DestinationLeft,
2946     BasicVideo_put_DestinationWidth,
2947     BasicVideo_get_DestinationWidth,
2948     BasicVideo_put_DestinationTop,
2949     BasicVideo_get_DestinationTop,
2950     BasicVideo_put_DestinationHeight,
2951     BasicVideo_get_DestinationHeight,
2952     BasicVideo_SetSourcePosition,
2953     BasicVideo_GetSourcePosition,
2954     BasicVideo_SetDefaultSourcePosition,
2955     BasicVideo_SetDestinationPosition,
2956     BasicVideo_GetDestinationPosition,
2957     BasicVideo_SetDefaultDestinationPosition,
2958     BasicVideo_GetVideoSize,
2959     BasicVideo_GetVideoPaletteEntries,
2960     BasicVideo_GetCurrentImage,
2961     BasicVideo_IsUsingDefaultSource,
2962     BasicVideo_IsUsingDefaultDestination
2963 };
2964
2965
2966 /*** IUnknown methods ***/
2967 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface,
2968                                                  REFIID riid,
2969                                                  LPVOID*ppvObj) {
2970     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2971
2972     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2973
2974     return Filtergraph_QueryInterface(This, riid, ppvObj);
2975 }
2976
2977 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface) {
2978     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2979
2980     TRACE("(%p/%p)->()\n", This, iface);
2981
2982     return Filtergraph_AddRef(This);
2983 }
2984
2985 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface) {
2986     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2987
2988     TRACE("(%p/%p)->()\n", This, iface);
2989
2990     return Filtergraph_Release(This);
2991 }
2992
2993 /*** IDispatch methods ***/
2994 static HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface,
2995                                                    UINT*pctinfo) {
2996     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2997     IVideoWindow* pVideoWindow;
2998     HRESULT hr;
2999
3000     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3001
3002     EnterCriticalSection(&This->cs);
3003
3004     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3005
3006     if (hr == S_OK)
3007         hr = IVideoWindow_GetTypeInfoCount(pVideoWindow, pctinfo);
3008
3009     LeaveCriticalSection(&This->cs);
3010
3011     return hr;
3012 }
3013
3014 static HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface,
3015                                               UINT iTInfo,
3016                                               LCID lcid,
3017                                               ITypeInfo**ppTInfo) {
3018     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3019     IVideoWindow* pVideoWindow;
3020     HRESULT hr;
3021
3022     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3023
3024     EnterCriticalSection(&This->cs);
3025
3026     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3027
3028     if (hr == S_OK)
3029         hr = IVideoWindow_GetTypeInfo(pVideoWindow, iTInfo, lcid, ppTInfo);
3030
3031     LeaveCriticalSection(&This->cs);
3032
3033     return hr;
3034 }
3035
3036 static HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface,
3037                                                 REFIID riid,
3038                                                 LPOLESTR*rgszNames,
3039                                                 UINT cNames,
3040                                                 LCID lcid,
3041                                                 DISPID*rgDispId) {
3042     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3043     IVideoWindow* pVideoWindow;
3044     HRESULT hr;
3045
3046     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3047
3048     EnterCriticalSection(&This->cs);
3049
3050     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3051
3052     if (hr == S_OK)
3053         hr = IVideoWindow_GetIDsOfNames(pVideoWindow, riid, rgszNames, cNames, lcid, rgDispId);
3054
3055     LeaveCriticalSection(&This->cs);
3056
3057     return hr;
3058 }
3059
3060 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface,
3061                                          DISPID dispIdMember,
3062                                          REFIID riid,
3063                                          LCID lcid,
3064                                          WORD wFlags,
3065                                          DISPPARAMS*pDispParams,
3066                                          VARIANT*pVarResult,
3067                                          EXCEPINFO*pExepInfo,
3068                                          UINT*puArgErr) {
3069     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3070     IVideoWindow* pVideoWindow;
3071     HRESULT hr;
3072
3073     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3074
3075     EnterCriticalSection(&This->cs);
3076
3077     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3078
3079     if (hr == S_OK)
3080         hr = IVideoWindow_Invoke(pVideoWindow, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3081
3082     LeaveCriticalSection(&This->cs);
3083
3084     return hr;
3085 }
3086
3087
3088 /*** IVideoWindow methods ***/
3089 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface,
3090                                               BSTR strCaption) {
3091     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3092     IVideoWindow* pVideoWindow;
3093     HRESULT hr;
3094     
3095     TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
3096
3097     EnterCriticalSection(&This->cs);
3098
3099     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3100
3101     if (hr == S_OK)
3102         hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
3103
3104     LeaveCriticalSection(&This->cs);
3105
3106     return hr;
3107 }
3108
3109 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface,
3110                                               BSTR *strCaption) {
3111     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3112     IVideoWindow* pVideoWindow;
3113     HRESULT hr;
3114
3115     TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
3116
3117     EnterCriticalSection(&This->cs);
3118
3119     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3120
3121     if (hr == S_OK)
3122         hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
3123
3124     LeaveCriticalSection(&This->cs);
3125
3126     return hr;
3127 }
3128
3129 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface,
3130                                                   long WindowStyle) {
3131     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3132     IVideoWindow* pVideoWindow;
3133     HRESULT hr;
3134
3135     TRACE("(%p/%p)->(%ld)\n", This, iface, WindowStyle);
3136
3137     EnterCriticalSection(&This->cs);
3138
3139     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3140
3141     if (hr == S_OK)
3142         hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
3143
3144     LeaveCriticalSection(&This->cs);
3145
3146     return hr;
3147 }
3148
3149 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface,
3150                                                   long *WindowStyle) {
3151     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3152     IVideoWindow* pVideoWindow;
3153     HRESULT hr;
3154
3155     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
3156
3157     EnterCriticalSection(&This->cs);
3158
3159     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3160
3161     if (hr == S_OK)
3162         hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
3163
3164     LeaveCriticalSection(&This->cs);
3165
3166     return hr;
3167 }
3168
3169 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface,
3170                                                     long WindowStyleEx) {
3171     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3172     IVideoWindow* pVideoWindow;
3173     HRESULT hr;
3174
3175     TRACE("(%p/%p)->(%ld)\n", This, iface, WindowStyleEx);
3176
3177     EnterCriticalSection(&This->cs);
3178
3179     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3180
3181     if (hr == S_OK)
3182         hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
3183
3184     LeaveCriticalSection(&This->cs);
3185
3186     return hr;
3187 }
3188
3189 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface,
3190                                                     long *WindowStyleEx) {
3191     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3192     IVideoWindow* pVideoWindow;
3193     HRESULT hr;
3194
3195     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
3196
3197     EnterCriticalSection(&This->cs);
3198
3199     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3200
3201     if (hr == S_OK)
3202         hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
3203
3204     LeaveCriticalSection(&This->cs);
3205
3206     return hr;
3207 }
3208
3209 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface,
3210                                                long AutoShow) {
3211     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3212     IVideoWindow* pVideoWindow;
3213     HRESULT hr;
3214
3215     TRACE("(%p/%p)->(%ld)\n", This, iface, AutoShow);
3216
3217     EnterCriticalSection(&This->cs);
3218
3219     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3220
3221     if (hr == S_OK)
3222         hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
3223
3224     LeaveCriticalSection(&This->cs);
3225
3226     return hr;
3227 }
3228
3229 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface,
3230                                                long *AutoShow) {
3231     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3232     IVideoWindow* pVideoWindow;
3233     HRESULT hr;
3234
3235     TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
3236
3237     EnterCriticalSection(&This->cs);
3238
3239     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3240
3241     if (hr == S_OK)
3242         hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
3243
3244     LeaveCriticalSection(&This->cs);
3245
3246     return hr;
3247 }
3248
3249 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface,
3250                                                   long WindowState) {
3251     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3252     IVideoWindow* pVideoWindow;
3253     HRESULT hr;
3254
3255     TRACE("(%p/%p)->(%ld)\n", This, iface, WindowState);
3256
3257     EnterCriticalSection(&This->cs);
3258
3259     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3260
3261     if (hr == S_OK)
3262         hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
3263
3264     LeaveCriticalSection(&This->cs);
3265
3266     return hr;
3267 }
3268
3269 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface,
3270                                                   long *WindowState) {
3271     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3272     IVideoWindow* pVideoWindow;
3273     HRESULT hr;
3274
3275     TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
3276
3277     EnterCriticalSection(&This->cs);
3278
3279     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3280
3281     if (hr == S_OK)
3282         hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
3283
3284     LeaveCriticalSection(&This->cs);
3285
3286     return hr;
3287 }
3288
3289 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface,
3290                                                         long BackgroundPalette) {
3291     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3292     IVideoWindow* pVideoWindow;
3293     HRESULT hr;
3294
3295     TRACE("(%p/%p)->(%ld)\n", This, iface, BackgroundPalette);
3296
3297     EnterCriticalSection(&This->cs);
3298
3299     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3300
3301     if (hr == S_OK)
3302         hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
3303
3304     LeaveCriticalSection(&This->cs);
3305
3306     return hr;
3307 }
3308
3309 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
3310                                                         long *pBackgroundPalette) {
3311     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3312     IVideoWindow* pVideoWindow;
3313     HRESULT hr;
3314
3315     TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
3316
3317     EnterCriticalSection(&This->cs);
3318
3319     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3320
3321     if (hr == S_OK)
3322         hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
3323
3324     LeaveCriticalSection(&This->cs);
3325
3326     return hr;
3327 }
3328
3329 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface,
3330                                               long Visible) {
3331     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3332     IVideoWindow* pVideoWindow;
3333     HRESULT hr;
3334
3335     TRACE("(%p/%p)->(%ld)\n", This, iface, Visible);
3336
3337     EnterCriticalSection(&This->cs);
3338
3339     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3340
3341     if (hr == S_OK)
3342         hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
3343
3344     LeaveCriticalSection(&This->cs);
3345
3346     return hr;
3347 }
3348
3349 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface,
3350                                               long *pVisible) {
3351     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3352     IVideoWindow* pVideoWindow;
3353     HRESULT hr;
3354
3355     TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
3356
3357     EnterCriticalSection(&This->cs);
3358
3359     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3360
3361     if (hr == S_OK)
3362         hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
3363
3364     LeaveCriticalSection(&This->cs);
3365
3366     return hr;
3367 }
3368
3369 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface,
3370                                            long Left) {
3371     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3372     IVideoWindow* pVideoWindow;
3373     HRESULT hr;
3374
3375     TRACE("(%p/%p)->(%ld)\n", This, iface, Left);
3376
3377     EnterCriticalSection(&This->cs);
3378
3379     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3380
3381     if (hr == S_OK)
3382         hr = IVideoWindow_put_Left(pVideoWindow, Left);
3383
3384     LeaveCriticalSection(&This->cs);
3385
3386     return hr;
3387 }
3388
3389 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface,
3390                                            long *pLeft) {
3391     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3392     IVideoWindow* pVideoWindow;
3393     HRESULT hr;
3394
3395     TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
3396
3397     EnterCriticalSection(&This->cs);
3398
3399     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3400
3401     if (hr == S_OK)
3402         hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
3403
3404     LeaveCriticalSection(&This->cs);
3405
3406     return hr;
3407 }
3408
3409 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface,
3410                                             long Width) {
3411     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3412     IVideoWindow* pVideoWindow;
3413     HRESULT hr;
3414
3415     TRACE("(%p/%p)->(%ld)\n", This, iface, Width);
3416
3417     EnterCriticalSection(&This->cs);
3418
3419     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3420
3421     if (hr == S_OK)
3422         hr = IVideoWindow_put_Width(pVideoWindow, Width);
3423
3424     LeaveCriticalSection(&This->cs);
3425
3426     return hr;
3427 }
3428
3429 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface,
3430                                             long *pWidth) {
3431     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3432     IVideoWindow* pVideoWindow;
3433     HRESULT hr;
3434
3435     TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
3436
3437     EnterCriticalSection(&This->cs);
3438
3439     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3440
3441     if (hr == S_OK)
3442         hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
3443
3444     LeaveCriticalSection(&This->cs);
3445
3446     return hr;
3447 }
3448
3449 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface,
3450                                           long Top) {
3451     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3452     IVideoWindow* pVideoWindow;
3453     HRESULT hr;
3454
3455     TRACE("(%p/%p)->(%ld)\n", This, iface, Top);
3456
3457     EnterCriticalSection(&This->cs);
3458
3459     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3460
3461     if (hr == S_OK)
3462         hr = IVideoWindow_put_Top(pVideoWindow, Top);
3463
3464     LeaveCriticalSection(&This->cs);
3465
3466     return hr;
3467 }
3468
3469 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface,
3470                                           long *pTop) {
3471     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3472     IVideoWindow* pVideoWindow;
3473     HRESULT hr;
3474
3475     TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
3476
3477     EnterCriticalSection(&This->cs);
3478
3479     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3480
3481     if (hr == S_OK)
3482         hr = IVideoWindow_get_Top(pVideoWindow, pTop);
3483
3484     LeaveCriticalSection(&This->cs);
3485
3486     return hr;
3487 }
3488
3489 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface,
3490                                              long Height) {
3491     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3492     IVideoWindow* pVideoWindow;
3493     HRESULT hr;
3494
3495     TRACE("(%p/%p)->(%ld)\n", This, iface, Height);
3496
3497     EnterCriticalSection(&This->cs);
3498
3499     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3500
3501     if (hr == S_OK)
3502         hr = IVideoWindow_put_Height(pVideoWindow, Height);
3503
3504     LeaveCriticalSection(&This->cs);
3505
3506     return hr;
3507 }
3508
3509 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface,
3510                                              long *pHeight) {
3511     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3512     IVideoWindow* pVideoWindow;
3513     HRESULT hr;
3514
3515     TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
3516
3517     EnterCriticalSection(&This->cs);
3518
3519     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3520
3521     if (hr == S_OK)
3522         hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
3523
3524     LeaveCriticalSection(&This->cs);
3525
3526     return hr;
3527 }
3528
3529 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface,
3530                                             OAHWND Owner) {
3531     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3532     IVideoWindow* pVideoWindow;
3533     HRESULT hr;
3534
3535     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
3536
3537     EnterCriticalSection(&This->cs);
3538
3539     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3540
3541     if (hr == S_OK)
3542         hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
3543
3544     LeaveCriticalSection(&This->cs);
3545
3546     return hr;
3547 }
3548
3549 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface,
3550                                             OAHWND *Owner) {
3551     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3552     IVideoWindow* pVideoWindow;
3553     HRESULT hr;
3554
3555     TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
3556
3557     EnterCriticalSection(&This->cs);
3558
3559     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3560
3561     if (hr == S_OK)
3562         hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
3563
3564     LeaveCriticalSection(&This->cs);
3565
3566     return hr;
3567 }
3568
3569 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface,
3570                                                    OAHWND Drain) {
3571     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3572     IVideoWindow* pVideoWindow;
3573     HRESULT hr;
3574
3575     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
3576
3577     EnterCriticalSection(&This->cs);
3578
3579     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3580
3581     if (hr == S_OK)
3582         hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
3583
3584     LeaveCriticalSection(&This->cs);
3585
3586     return hr;
3587 }
3588
3589 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface,
3590                                                    OAHWND *Drain) {
3591     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3592     IVideoWindow* pVideoWindow;
3593     HRESULT hr;
3594
3595     TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
3596
3597     EnterCriticalSection(&This->cs);
3598
3599     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3600
3601     if (hr == S_OK)
3602         hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
3603
3604     LeaveCriticalSection(&This->cs);
3605
3606     return hr;
3607 }
3608
3609 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface,
3610                                                   long *Color) {
3611     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3612     IVideoWindow* pVideoWindow;
3613     HRESULT hr;
3614
3615     TRACE("(%p/%p)->(%p)\n", This, iface, Color);
3616
3617     EnterCriticalSection(&This->cs);
3618
3619     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3620
3621     if (hr == S_OK)
3622         hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
3623
3624     LeaveCriticalSection(&This->cs);
3625
3626     return hr;
3627 }
3628
3629 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface,
3630                                                   long Color) {
3631     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3632     IVideoWindow* pVideoWindow;
3633     HRESULT hr;
3634
3635     TRACE("(%p/%p)->(%ld)\n", This, iface, Color);
3636
3637     EnterCriticalSection(&This->cs);
3638
3639     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3640
3641     if (hr == S_OK)
3642         hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
3643
3644     LeaveCriticalSection(&This->cs);
3645
3646     return hr;
3647 }
3648
3649 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface,
3650                                                      long *FullScreenMode) {
3651     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3652     IVideoWindow* pVideoWindow;
3653     HRESULT hr;
3654
3655     TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
3656
3657     EnterCriticalSection(&This->cs);
3658
3659     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3660
3661     if (hr == S_OK)
3662         hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
3663
3664     LeaveCriticalSection(&This->cs);
3665
3666     return hr;
3667 }
3668
3669 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface,
3670                                                      long FullScreenMode) {
3671     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3672     IVideoWindow* pVideoWindow;
3673     HRESULT hr;
3674
3675     TRACE("(%p/%p)->(%ld)\n", This, iface, FullScreenMode);
3676
3677     EnterCriticalSection(&This->cs);
3678
3679     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3680
3681     if (hr == S_OK)
3682         hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
3683
3684     LeaveCriticalSection(&This->cs);
3685
3686     return hr;
3687 }
3688
3689 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface,
3690                                                       long Focus) {
3691     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3692     IVideoWindow* pVideoWindow;
3693     HRESULT hr;
3694
3695     TRACE("(%p/%p)->(%ld)\n", This, iface, Focus);
3696
3697     EnterCriticalSection(&This->cs);
3698
3699     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3700
3701     if (hr == S_OK)
3702         hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
3703
3704     LeaveCriticalSection(&This->cs);
3705
3706     return hr;
3707 }
3708
3709 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface,
3710                                                      OAHWND hwnd,
3711                                                      long uMsg,
3712                                                      LONG_PTR wParam,
3713                                                      LONG_PTR lParam) {
3714     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3715     IVideoWindow* pVideoWindow;
3716     HRESULT hr;
3717
3718     TRACE("(%p/%p)->(%08x, %ld, %08lx, %08lx)\n", This, iface, (DWORD) hwnd, uMsg, wParam, lParam);
3719
3720     EnterCriticalSection(&This->cs);
3721
3722     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3723
3724     if (hr == S_OK)
3725         hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
3726
3727     LeaveCriticalSection(&This->cs);
3728
3729     return hr;
3730 }
3731
3732 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface,
3733                                                     long Left,
3734                                                     long Top,
3735                                                     long Width,
3736                                                     long Height) {
3737     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3738     IVideoWindow* pVideoWindow;
3739     HRESULT hr;
3740     
3741     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
3742
3743     EnterCriticalSection(&This->cs);
3744
3745     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3746
3747     if (hr == S_OK)
3748         hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
3749
3750     LeaveCriticalSection(&This->cs);
3751
3752     return hr;
3753 }
3754
3755 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface,
3756                                                     long *pLeft,
3757                                                     long *pTop,
3758                                                     long *pWidth,
3759                                                     long *pHeight) {
3760     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3761     IVideoWindow* pVideoWindow;
3762     HRESULT hr;
3763
3764     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3765
3766     EnterCriticalSection(&This->cs);
3767
3768     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3769
3770     if (hr == S_OK)
3771         hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
3772
3773     LeaveCriticalSection(&This->cs);
3774
3775     return hr;
3776 }
3777
3778 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface,
3779                                                        long *pWidth,
3780                                                        long *pHeight) {
3781     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3782     IVideoWindow* pVideoWindow;
3783     HRESULT hr;
3784
3785     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3786
3787     EnterCriticalSection(&This->cs);
3788
3789     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3790
3791     if (hr == S_OK)
3792         hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
3793
3794     LeaveCriticalSection(&This->cs);
3795
3796     return hr;
3797 }
3798
3799 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface,
3800                                                        long *pWidth,
3801                                                        long *pHeight) {
3802     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3803     IVideoWindow* pVideoWindow;
3804     HRESULT hr;
3805
3806     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3807
3808     EnterCriticalSection(&This->cs);
3809
3810     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3811
3812     if (hr == S_OK)
3813         hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
3814
3815     LeaveCriticalSection(&This->cs);
3816
3817     return hr;
3818 }
3819
3820 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface,
3821                                                      long *pLeft,
3822                                                      long *pTop,
3823                                                      long *pWidth,
3824                                                      long *pHeight) {
3825     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3826     IVideoWindow* pVideoWindow;
3827     HRESULT hr;
3828
3829     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3830
3831     EnterCriticalSection(&This->cs);
3832
3833     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3834
3835     if (hr == S_OK)
3836         hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
3837
3838     LeaveCriticalSection(&This->cs);
3839
3840     return hr;
3841 }
3842
3843 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface,
3844                                              long HideCursor) {
3845     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3846     IVideoWindow* pVideoWindow;
3847     HRESULT hr;
3848
3849     TRACE("(%p/%p)->(%ld)\n", This, iface, HideCursor);
3850
3851     EnterCriticalSection(&This->cs);
3852
3853     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3854
3855     if (hr == S_OK)
3856         hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
3857
3858     LeaveCriticalSection(&This->cs);
3859
3860     return hr;
3861 }
3862
3863 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface,
3864                                                  long *CursorHidden) {
3865     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3866     IVideoWindow* pVideoWindow;
3867     HRESULT hr;
3868
3869     TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
3870
3871     EnterCriticalSection(&This->cs);
3872
3873     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3874
3875     if (hr == S_OK)
3876         hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
3877
3878     LeaveCriticalSection(&This->cs);
3879
3880     return hr;
3881 }
3882
3883
3884 static const IVideoWindowVtbl IVideoWindow_VTable =
3885 {
3886     VideoWindow_QueryInterface,
3887     VideoWindow_AddRef,
3888     VideoWindow_Release,
3889     VideoWindow_GetTypeInfoCount,
3890     VideoWindow_GetTypeInfo,
3891     VideoWindow_GetIDsOfNames,
3892     VideoWindow_Invoke,
3893     VideoWindow_put_Caption,
3894     VideoWindow_get_Caption,
3895     VideoWindow_put_WindowStyle,
3896     VideoWindow_get_WindowStyle,
3897     VideoWindow_put_WindowStyleEx,
3898     VideoWindow_get_WindowStyleEx,
3899     VideoWindow_put_AutoShow,
3900     VideoWindow_get_AutoShow,
3901     VideoWindow_put_WindowState,
3902     VideoWindow_get_WindowState,
3903     VideoWindow_put_BackgroundPalette,
3904     VideoWindow_get_BackgroundPalette,
3905     VideoWindow_put_Visible,
3906     VideoWindow_get_Visible,
3907     VideoWindow_put_Left,
3908     VideoWindow_get_Left,
3909     VideoWindow_put_Width,
3910     VideoWindow_get_Width,
3911     VideoWindow_put_Top,
3912     VideoWindow_get_Top,
3913     VideoWindow_put_Height,
3914     VideoWindow_get_Height,
3915     VideoWindow_put_Owner,
3916     VideoWindow_get_Owner,
3917     VideoWindow_put_MessageDrain,
3918     VideoWindow_get_MessageDrain,
3919     VideoWindow_get_BorderColor,
3920     VideoWindow_put_BorderColor,
3921     VideoWindow_get_FullScreenMode,
3922     VideoWindow_put_FullScreenMode,
3923     VideoWindow_SetWindowForeground,
3924     VideoWindow_NotifyOwnerMessage,
3925     VideoWindow_SetWindowPosition,
3926     VideoWindow_GetWindowPosition,
3927     VideoWindow_GetMinIdealImageSize,
3928     VideoWindow_GetMaxIdealImageSize,
3929     VideoWindow_GetRestorePosition,
3930     VideoWindow_HideCursor,
3931     VideoWindow_IsCursorHidden
3932 };
3933
3934
3935 /*** IUnknown methods ***/
3936 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface,
3937                                                 REFIID riid,
3938                                                 LPVOID*ppvObj) {
3939     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
3940
3941     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
3942
3943     return Filtergraph_QueryInterface(This, riid, ppvObj);
3944 }
3945
3946 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface) {
3947     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
3948
3949     TRACE("(%p/%p)->()\n", This, iface);
3950
3951     return Filtergraph_AddRef(This);
3952 }
3953
3954 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface) {
3955     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
3956
3957     TRACE("(%p/%p)->()\n", This, iface);
3958
3959     return Filtergraph_Release(This);
3960 }
3961
3962 /*** IDispatch methods ***/
3963 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface,
3964                                                   UINT*pctinfo) {
3965     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
3966
3967     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
3968
3969     return S_OK;
3970 }
3971
3972 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface,
3973                                              UINT iTInfo,
3974                                              LCID lcid,
3975                                              ITypeInfo**ppTInfo) {
3976     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
3977
3978     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
3979
3980     return S_OK;
3981 }
3982
3983 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface,
3984                                                REFIID riid,
3985                                                LPOLESTR*rgszNames,
3986                                                UINT cNames,
3987                                                LCID lcid,
3988                                                DISPID*rgDispId) {
3989     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
3990
3991     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3992
3993     return S_OK;
3994 }
3995
3996 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface,
3997                                         DISPID dispIdMember,
3998                                         REFIID riid,
3999                                         LCID lcid,
4000                                         WORD wFlags,
4001                                         DISPPARAMS*pDispParams,
4002                                         VARIANT*pVarResult,
4003                                         EXCEPINFO*pExepInfo,
4004                                         UINT*puArgErr) {
4005     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4006
4007     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4008
4009     return S_OK;
4010 }
4011
4012 /*** IMediaEvent methods ***/
4013 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface,
4014                                                 OAEVENT *hEvent) {
4015     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4016
4017     TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
4018
4019     *hEvent = (OAEVENT)This->evqueue.msg_event;
4020
4021     return S_OK;
4022 }
4023
4024 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface,
4025                                           long *lEventCode,
4026                                           LONG_PTR *lParam1,
4027                                           LONG_PTR *lParam2,
4028                                           long msTimeout) {
4029     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4030     Event evt;
4031
4032     TRACE("(%p/%p)->(%p, %p, %p, %ld)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
4033
4034     if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
4035     {
4036         *lEventCode = evt.lEventCode;
4037         *lParam1 = evt.lParam1;
4038         *lParam2 = evt.lParam2;
4039         return S_OK;
4040     }
4041
4042     *lEventCode = 0;
4043     return E_ABORT;
4044 }
4045
4046 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface,
4047                                                    long msTimeout,
4048                                                    long *pEvCode) {
4049     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4050
4051     TRACE("(%p/%p)->(%ld, %p)\n", This, iface, msTimeout, pEvCode);
4052
4053     if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
4054     {
4055         *pEvCode = This->CompletionStatus;
4056         return S_OK;
4057     }
4058
4059     *pEvCode = 0;
4060     return E_ABORT;
4061 }
4062
4063 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface,
4064                                                        long lEvCode) {
4065     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4066
4067     TRACE("(%p/%p)->(%ld)\n", This, iface, lEvCode);
4068
4069     if (lEvCode == EC_COMPLETE)
4070         This->HandleEcComplete = FALSE;
4071     else if (lEvCode == EC_REPAINT)
4072         This->HandleEcRepaint = FALSE;
4073     else
4074         return S_FALSE;
4075
4076     return S_OK;
4077 }
4078
4079 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface,
4080                                                         long lEvCode) {
4081     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4082
4083     TRACE("(%p/%p)->(%ld)\n", This, iface, lEvCode);
4084
4085     if (lEvCode == EC_COMPLETE)
4086         This->HandleEcComplete = TRUE;
4087     else if (lEvCode == EC_REPAINT)
4088         This->HandleEcRepaint = TRUE;
4089     else
4090         return S_FALSE;
4091
4092     return S_OK;
4093 }
4094
4095 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface,
4096                                                  long lEvCode,
4097                                                  LONG_PTR lParam1,
4098                                                  LONG_PTR lParam2) {
4099     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4100
4101     TRACE("(%p/%p)->(%ld, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
4102
4103     return S_OK;
4104 }
4105
4106 /*** IMediaEventEx methods ***/
4107 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface,
4108                                                  OAHWND hwnd,
4109                                                  long lMsg,
4110                                                  LONG_PTR lInstanceData) {
4111     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4112
4113     TRACE("(%p/%p)->(%08x, %ld, %08lx)\n", This, iface, (DWORD) hwnd, lMsg, lInstanceData);
4114
4115     This->notif.hWnd = (HWND)hwnd;
4116     This->notif.msg = lMsg;
4117     This->notif.instance = (long) lInstanceData;
4118
4119     return S_OK;
4120 }
4121
4122 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface,
4123                                                 long lNoNotifyFlags) {
4124     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4125
4126     TRACE("(%p/%p)->(%ld)\n", This, iface, lNoNotifyFlags);
4127
4128     if ((lNoNotifyFlags != 0) && (lNoNotifyFlags != 1))
4129         return E_INVALIDARG;
4130
4131     This->notif.disabled = lNoNotifyFlags;
4132
4133     return S_OK;
4134 }
4135
4136 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface,
4137                                                 long *lplNoNotifyFlags) {
4138     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4139
4140     TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
4141
4142     if (!lplNoNotifyFlags)
4143         return E_POINTER;
4144
4145     *lplNoNotifyFlags = This->notif.disabled;
4146
4147     return S_OK;
4148 }
4149
4150
4151 static const IMediaEventExVtbl IMediaEventEx_VTable =
4152 {
4153     MediaEvent_QueryInterface,
4154     MediaEvent_AddRef,
4155     MediaEvent_Release,
4156     MediaEvent_GetTypeInfoCount,
4157     MediaEvent_GetTypeInfo,
4158     MediaEvent_GetIDsOfNames,
4159     MediaEvent_Invoke,
4160     MediaEvent_GetEventHandle,
4161     MediaEvent_GetEvent,
4162     MediaEvent_WaitForCompletion,
4163     MediaEvent_CancelDefaultHandling,
4164     MediaEvent_RestoreDefaultHandling,
4165     MediaEvent_FreeEventParams,
4166     MediaEvent_SetNotifyWindow,
4167     MediaEvent_SetNotifyFlags,
4168     MediaEvent_GetNotifyFlags
4169 };
4170
4171
4172 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID riid, LPVOID *ppv)
4173 {
4174     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
4175
4176     return Filtergraph_QueryInterface(This, riid, ppv);
4177 }
4178
4179 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
4180 {
4181     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
4182
4183     return Filtergraph_AddRef(This);
4184 }
4185
4186 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
4187 {
4188     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
4189
4190     return Filtergraph_Release(This);
4191 }
4192
4193 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
4194 {
4195     FIXME("(%p): stub\n", pClassID);
4196
4197     return E_NOTIMPL;
4198 }
4199
4200 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
4201 {
4202     FIXME("(): stub\n");
4203
4204     return E_NOTIMPL;
4205 }
4206
4207 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
4208 {
4209     FIXME("(): stub\n");
4210
4211     return E_NOTIMPL;
4212 }
4213
4214 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME tStart)
4215 {
4216     FIXME("(0x%s): stub\n", wine_dbgstr_longlong(tStart));
4217
4218     return E_NOTIMPL;
4219 }
4220
4221 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD dwMsTimeout, FILTER_STATE * pState)
4222 {
4223     FIXME("(%d, %p): stub\n", dwMsTimeout, pState);
4224
4225     return E_NOTIMPL;
4226 }
4227
4228 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
4229 {
4230     FIXME("(%p): stub\n", pClock);
4231
4232     return E_NOTIMPL;
4233 }
4234
4235 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
4236 {
4237     FIXME("(%p): stub\n", ppClock);
4238
4239     return E_NOTIMPL;
4240 }
4241
4242 static const IMediaFilterVtbl IMediaFilter_VTable =
4243 {
4244     MediaFilter_QueryInterface,
4245     MediaFilter_AddRef,
4246     MediaFilter_Release,
4247     MediaFilter_GetClassID,
4248     MediaFilter_Stop,
4249     MediaFilter_Pause,
4250     MediaFilter_Run,
4251     MediaFilter_GetState,
4252     MediaFilter_SetSyncSource,
4253     MediaFilter_GetSyncSource
4254 };
4255
4256 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID riid, LPVOID *ppv)
4257 {
4258     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
4259
4260     return Filtergraph_QueryInterface(This, riid, ppv);
4261 }
4262
4263 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
4264 {
4265     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
4266
4267     return Filtergraph_AddRef(This);
4268 }
4269
4270 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
4271 {
4272     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
4273
4274     return Filtergraph_Release(This);
4275 }
4276
4277 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
4278 {
4279     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
4280     Event evt;
4281
4282     TRACE("(%p/%p)->(%ld, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
4283
4284     /* We need thread safety here, let's use the events queue's one */
4285     EnterCriticalSection(&This->evqueue.msg_crst);
4286
4287     if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
4288     {
4289         TRACE("Process EC_COMPLETE notification\n");
4290         if (++This->EcCompleteCount == This->nRenderers)
4291         {
4292             evt.lEventCode = EC_COMPLETE;
4293             evt.lParam1 = S_OK;
4294             evt.lParam2 = 0;
4295             TRACE("Send EC_COMPLETE to app\n");
4296             EventsQueue_PutEvent(&This->evqueue, &evt);
4297             if (!This->notif.disabled && This->notif.hWnd)
4298             {
4299                 TRACE("Send Window message\n");
4300                 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
4301             }
4302             This->CompletionStatus = EC_COMPLETE;
4303             SetEvent(This->hEventCompletion);
4304         }
4305     }
4306     else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
4307     {
4308         /* FIXME: Not handled yet */
4309     }
4310     else
4311     {
4312         evt.lEventCode = EventCode;
4313         evt.lParam1 = EventParam1;
4314         evt.lParam2 = EventParam2;
4315         EventsQueue_PutEvent(&This->evqueue, &evt);
4316         if (!This->notif.disabled && This->notif.hWnd)
4317             PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
4318     }
4319
4320     LeaveCriticalSection(&This->evqueue.msg_crst);
4321     return S_OK;
4322 }
4323
4324 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
4325 {
4326     MediaEventSink_QueryInterface,
4327     MediaEventSink_AddRef,
4328     MediaEventSink_Release,
4329     MediaEventSink_Notify
4330 };
4331
4332 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID riid, LPVOID *ppv)
4333 {
4334     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4335
4336     return Filtergraph_QueryInterface(This, riid, ppv);
4337 }
4338
4339 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
4340 {
4341     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
4342
4343     return Filtergraph_AddRef(This);
4344 }
4345
4346 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
4347 {
4348     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4349
4350     return Filtergraph_Release(This);
4351 }
4352
4353 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface,
4354                                             IPin* pOutputPin,
4355                                             IPin* pInputPin,
4356                                             const AM_MEDIA_TYPE* pmtFirstConnection,
4357                                             IBaseFilter* pUsingFilter,
4358                                             HANDLE hAbortEvent,
4359                                             DWORD dwFlags)
4360 {
4361     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4362
4363     FIXME("(%p)->(%p, %p, %p, %p, %p, %x): stub!\n", This, pOutputPin, pInputPin, pmtFirstConnection, pUsingFilter, hAbortEvent, dwFlags);
4364     
4365     return E_NOTIMPL;
4366 }
4367
4368 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface,
4369                                               IGraphConfigCallback* pCallback,
4370                                               PVOID pvContext,
4371                                               DWORD dwFlags,
4372                                               HANDLE hAbortEvent)
4373 {
4374     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4375
4376     FIXME("(%p)->(%p, %p, %x, %p): stub!\n", This, pCallback, pvContext, dwFlags, hAbortEvent);
4377     
4378     return E_NOTIMPL;
4379 }
4380
4381 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface,
4382                                                    IBaseFilter* pFilter)
4383 {
4384     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4385
4386     FIXME("(%p)->(%p): stub!\n", This, pFilter);
4387     
4388     return E_NOTIMPL;
4389 }
4390
4391 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface,
4392                                                   IEnumFilters** pEnum)
4393 {
4394     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4395
4396     FIXME("(%p)->(%p): stub!\n", This, pEnum);
4397     
4398     return E_NOTIMPL;
4399 }
4400
4401 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface,
4402                                                         IBaseFilter* pFilter)
4403 {
4404     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4405
4406     FIXME("(%p)->(%p): stub!\n", This, pFilter);
4407     
4408     return E_NOTIMPL;
4409 }
4410
4411 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface,
4412                                                REFERENCE_TIME* prtStart)
4413 {
4414     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4415
4416     FIXME("(%p)->(%p): stub!\n", This, prtStart);
4417     
4418     return E_NOTIMPL;
4419 }
4420
4421 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface,
4422                                                   IPin* pOutputPin,
4423                                                   IPinConnection* pConnection,
4424                                                   HANDLE hEventAbort)
4425 {
4426     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4427
4428     FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
4429     
4430     return E_NOTIMPL;
4431 }
4432
4433 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface,
4434                                                  IBaseFilter* pFilter,
4435                                                  DWORD dwFlags)
4436 {
4437     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4438
4439     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
4440     
4441     return E_NOTIMPL;
4442 }
4443
4444 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface,
4445                                                  IBaseFilter* pFilter,
4446                                                  DWORD* dwFlags)
4447 {
4448     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4449
4450     FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
4451     
4452     return E_NOTIMPL;
4453 }
4454
4455 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface,
4456                                                  IBaseFilter* pFilter,
4457                                                  DWORD dwFlags)
4458 {
4459     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
4460
4461     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
4462     
4463     return E_NOTIMPL;
4464 }
4465
4466 static const IGraphConfigVtbl IGraphConfig_VTable =
4467 {
4468     GraphConfig_QueryInterface,
4469     GraphConfig_AddRef,
4470     GraphConfig_Release,
4471     GraphConfig_Reconnect,
4472     GraphConfig_Reconfigure,
4473     GraphConfig_AddFilterToCache,
4474     GraphConfig_EnumCacheFilter,
4475     GraphConfig_RemoveFilterFromCache,
4476     GraphConfig_GetStartTime,
4477     GraphConfig_PushThroughData,
4478     GraphConfig_SetFilterFlags,
4479     GraphConfig_GetFilterFlags,
4480     GraphConfig_RemoveFilterEx
4481 };
4482
4483 /* This is the only function that actually creates a FilterGraph class... */
4484 HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj)
4485 {
4486     IFilterGraphImpl *fimpl;
4487     HRESULT hr;
4488
4489     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
4490
4491     if( pUnkOuter )
4492         return CLASS_E_NOAGGREGATION;
4493
4494     fimpl = CoTaskMemAlloc(sizeof(*fimpl));
4495     fimpl->IGraphBuilder_vtbl = &IGraphBuilder_VTable;
4496     fimpl->IMediaControl_vtbl = &IMediaControl_VTable;
4497     fimpl->IMediaSeeking_vtbl = &IMediaSeeking_VTable;
4498     fimpl->IBasicAudio_vtbl = &IBasicAudio_VTable;
4499     fimpl->IBasicVideo_vtbl = &IBasicVideo_VTable;
4500     fimpl->IVideoWindow_vtbl = &IVideoWindow_VTable;
4501     fimpl->IMediaEventEx_vtbl = &IMediaEventEx_VTable;
4502     fimpl->IMediaFilter_vtbl = &IMediaFilter_VTable;
4503     fimpl->IMediaEventSink_vtbl = &IMediaEventSink_VTable;
4504     fimpl->IGraphConfig_vtbl = &IGraphConfig_VTable;
4505     fimpl->IMediaPosition_vtbl = &IMediaPosition_VTable;
4506     fimpl->ref = 1;
4507     fimpl->ppFiltersInGraph = NULL;
4508     fimpl->pFilterNames = NULL;
4509     fimpl->nFilters = 0;
4510     fimpl->filterCapacity = 0;
4511     fimpl->nameIndex = 1;
4512     fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
4513     fimpl->HandleEcComplete = TRUE;
4514     fimpl->HandleEcRepaint = TRUE;
4515     fimpl->notif.hWnd = 0;
4516     fimpl->notif.disabled = FALSE;
4517     fimpl->nRenderers = 0;
4518     fimpl->EcCompleteCount = 0;
4519     fimpl->state = State_Stopped;
4520     EventsQueue_Init(&fimpl->evqueue);
4521     InitializeCriticalSection(&fimpl->cs);
4522     fimpl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IFilterGraphImpl.cs");
4523     fimpl->nItfCacheEntries = 0;
4524
4525     hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&fimpl->pFilterMapper2);
4526     if (FAILED(hr)) {
4527         ERR("Unable to create filter mapper (%x)\n", hr);
4528         return hr;
4529     }
4530
4531     *ppObj = fimpl;
4532     return S_OK;
4533 }
4534
4535 HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj)
4536 {
4537     FIXME("CLSID_FilterGraphNoThread partially implemented - Forwarding to CLSID_FilterGraph\n");
4538     return FilterGraph_create(pUnkOuter, ppObj);
4539 }