oleaut32: Use widl to generate the coclasses registrations.
[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 "winreg.h"
33 #include "shlwapi.h"
34 #include "dshow.h"
35 #include "wine/debug.h"
36 #include "quartz_private.h"
37 #include "ole2.h"
38 #include "olectl.h"
39 #include "strmif.h"
40 #include "vfwmsgs.h"
41 #include "evcode.h"
42 #include "wine/unicode.h"
43
44
45 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
46
47 typedef struct {
48     HWND     hWnd;      /* Target window */
49     UINT     msg;       /* User window message */
50     LONG_PTR instance;  /* User data */
51     int      disabled;  /* Disabled messages posting */
52 } WndNotify;
53
54 typedef struct {
55     LONG lEventCode;   /* Event code */
56     LONG_PTR lParam1;  /* Param1 */
57     LONG_PTR lParam2;  /* Param2 */
58 } Event;
59
60 /* messages ring implementation for queuing events (taken from winmm) */
61 #define EVENTS_RING_BUFFER_INCREMENT      64
62 typedef struct {
63     Event* messages;
64     int ring_buffer_size;
65     int msg_tosave;
66     int msg_toget;
67     CRITICAL_SECTION msg_crst;
68     HANDLE msg_event; /* Signaled for no empty queue */
69 } EventsQueue;
70
71 static int EventsQueue_Init(EventsQueue* omr)
72 {
73     omr->msg_toget = 0;
74     omr->msg_tosave = 0;
75     omr->msg_event = CreateEventW(NULL, TRUE, FALSE, NULL);
76     omr->ring_buffer_size = EVENTS_RING_BUFFER_INCREMENT;
77     omr->messages = CoTaskMemAlloc(omr->ring_buffer_size * sizeof(Event));
78     ZeroMemory(omr->messages, omr->ring_buffer_size * sizeof(Event));
79
80     InitializeCriticalSection(&omr->msg_crst);
81     omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": EventsQueue.msg_crst");
82     return TRUE;
83 }
84
85 static int EventsQueue_Destroy(EventsQueue* omr)
86 {
87     CloseHandle(omr->msg_event);
88     CoTaskMemFree(omr->messages);
89     omr->msg_crst.DebugInfo->Spare[0] = 0;
90     DeleteCriticalSection(&omr->msg_crst);
91     return TRUE;
92 }
93
94 static int EventsQueue_PutEvent(EventsQueue* omr, const Event* evt)
95 {
96     EnterCriticalSection(&omr->msg_crst);
97     if ((omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size)))
98     {
99         int old_ring_buffer_size = omr->ring_buffer_size;
100         omr->ring_buffer_size += EVENTS_RING_BUFFER_INCREMENT;
101         TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
102         omr->messages = CoTaskMemRealloc(omr->messages, omr->ring_buffer_size * sizeof(Event));
103         /* Now we need to rearrange the ring buffer so that the new
104            buffers just allocated are in between omr->msg_tosave and
105            omr->msg_toget.
106         */
107         if (omr->msg_tosave < omr->msg_toget)
108         {
109             memmove(&(omr->messages[omr->msg_toget + EVENTS_RING_BUFFER_INCREMENT]),
110                     &(omr->messages[omr->msg_toget]),
111                     sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
112                     );
113             omr->msg_toget += EVENTS_RING_BUFFER_INCREMENT;
114         }
115     }
116     omr->messages[omr->msg_tosave] = *evt;
117     SetEvent(omr->msg_event);
118     omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
119     LeaveCriticalSection(&omr->msg_crst);
120     return TRUE;
121 }
122
123 static int EventsQueue_GetEvent(EventsQueue* omr, Event* evt, LONG msTimeOut)
124 {
125     if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
126         return FALSE;
127         
128     EnterCriticalSection(&omr->msg_crst);
129
130     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
131     {
132         LeaveCriticalSection(&omr->msg_crst);
133         return FALSE;
134     }
135
136     *evt = omr->messages[omr->msg_toget];
137     omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
138
139     /* Mark the buffer as empty if needed */
140     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
141         ResetEvent(omr->msg_event);
142
143     LeaveCriticalSection(&omr->msg_crst);
144     return TRUE;
145 }
146
147 #define MAX_ITF_CACHE_ENTRIES 3
148 typedef struct _ITF_CACHE_ENTRY {
149    const IID* riid;
150    IBaseFilter* filter;
151    IUnknown* iface;
152 } ITF_CACHE_ENTRY;
153
154 typedef struct _IFilterGraphImpl {
155     const IFilterGraph2Vtbl *IFilterGraph2_vtbl;
156     const IMediaControlVtbl *IMediaControl_vtbl;
157     const IMediaSeekingVtbl *IMediaSeeking_vtbl;
158     const IBasicAudioVtbl *IBasicAudio_vtbl;
159     const IBasicVideo2Vtbl *IBasicVideo_vtbl;
160     const IVideoWindowVtbl *IVideoWindow_vtbl;
161     const IMediaEventExVtbl *IMediaEventEx_vtbl;
162     const IMediaFilterVtbl *IMediaFilter_vtbl;
163     const IMediaEventSinkVtbl *IMediaEventSink_vtbl;
164     const IGraphConfigVtbl *IGraphConfig_vtbl;
165     const IMediaPositionVtbl *IMediaPosition_vtbl;
166     const IUnknownVtbl * IInner_vtbl;
167     /* IAMGraphStreams */
168     /* IAMStats */
169     /* IFilterChain */
170     /* IFilterMapper2 */
171     /* IGraphVersion */
172     /* IQueueCommand */
173     /* IRegisterServiceProvider */
174     /* IResourceMananger */
175     /* IServiceProvider */
176     /* IVideoFrameStep */
177
178     LONG ref;
179     IUnknown *punkFilterMapper2;
180     IFilterMapper2 * pFilterMapper2;
181     IBaseFilter ** ppFiltersInGraph;
182     LPWSTR * pFilterNames;
183     int nFilters;
184     int filterCapacity;
185     LONG nameIndex;
186     IReferenceClock *refClock;
187     EventsQueue evqueue;
188     HANDLE hEventCompletion;
189     int CompletionStatus;
190     WndNotify notif;
191     int nRenderers;
192     int EcCompleteCount;
193     int HandleEcComplete;
194     int HandleEcRepaint;
195     int HandleEcClockChanged;
196     OAFilterState state;
197     CRITICAL_SECTION cs;
198     ITF_CACHE_ENTRY ItfCacheEntries[MAX_ITF_CACHE_ENTRIES];
199     int nItfCacheEntries;
200     IUnknown * pUnkOuter;
201     BOOL bUnkOuterValid;
202     BOOL bAggregatable;
203     BOOL defaultclock;
204     GUID timeformatseek;
205     REFERENCE_TIME start_time;
206     REFERENCE_TIME pause_time;
207     LONGLONG stop_position;
208     LONG recursioncount;
209 } IFilterGraphImpl;
210
211 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
212                                           REFIID riid, LPVOID * ppv);
213 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This);
214 static ULONG Filtergraph_Release(IFilterGraphImpl *This);
215
216 static HRESULT WINAPI FilterGraphInner_QueryInterface(IUnknown * iface,
217                                           REFIID riid,
218                                           LPVOID *ppvObj) {
219     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
220     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
221     
222     if (This->bAggregatable)
223         This->bUnkOuterValid = TRUE;
224
225     if (IsEqualGUID(&IID_IUnknown, riid)) {
226         *ppvObj = &(This->IInner_vtbl);
227         TRACE("   returning IUnknown interface (%p)\n", *ppvObj);
228     } else if (IsEqualGUID(&IID_IFilterGraph, riid) ||
229         IsEqualGUID(&IID_IFilterGraph2, riid) ||
230         IsEqualGUID(&IID_IGraphBuilder, riid)) {
231         *ppvObj = &(This->IFilterGraph2_vtbl);
232         TRACE("   returning IGraphBuilder interface (%p)\n", *ppvObj);
233     } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
234         *ppvObj = &(This->IMediaControl_vtbl);
235         TRACE("   returning IMediaControl interface (%p)\n", *ppvObj);
236     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
237         *ppvObj = &(This->IMediaSeeking_vtbl);
238         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
239     } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
240         *ppvObj = &(This->IBasicAudio_vtbl);
241         TRACE("   returning IBasicAudio interface (%p)\n", *ppvObj);
242     } else if (IsEqualGUID(&IID_IBasicVideo, riid) ||
243                IsEqualGUID(&IID_IBasicVideo2, riid)) {
244         *ppvObj = &(This->IBasicVideo_vtbl);
245         TRACE("   returning IBasicVideo2 interface (%p)\n", *ppvObj);
246     } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
247         *ppvObj = &(This->IVideoWindow_vtbl);
248         TRACE("   returning IVideoWindow interface (%p)\n", *ppvObj);
249     } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
250            IsEqualGUID(&IID_IMediaEventEx, riid)) {
251         *ppvObj = &(This->IMediaEventEx_vtbl);
252         TRACE("   returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
253     } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
254           IsEqualGUID(&IID_IPersist, riid)) {
255         *ppvObj = &(This->IMediaFilter_vtbl);
256         TRACE("   returning IMediaFilter interface (%p)\n", *ppvObj);
257     } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
258         *ppvObj = &(This->IMediaEventSink_vtbl);
259         TRACE("   returning IMediaEventSink interface (%p)\n", *ppvObj);
260     } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
261         *ppvObj = &(This->IGraphConfig_vtbl);
262         TRACE("   returning IGraphConfig interface (%p)\n", *ppvObj);
263     } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
264         *ppvObj = &(This->IMediaPosition_vtbl);
265         TRACE("   returning IMediaPosition interface (%p)\n", *ppvObj);
266     } else if (IsEqualGUID(&IID_IFilterMapper, riid)) {
267         TRACE("   requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj);
268         return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
269     } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) {
270         *ppvObj = This->pFilterMapper2;
271         TRACE("   returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj);
272     } else {
273         *ppvObj = NULL;
274         FIXME("unknown interface %s\n", debugstr_guid(riid));
275         return E_NOINTERFACE;
276     }
277
278     IUnknown_AddRef((IUnknown *)(*ppvObj));
279     return S_OK;
280 }
281
282 static ULONG WINAPI FilterGraphInner_AddRef(IUnknown * iface) {
283     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
284     ULONG ref = InterlockedIncrement(&This->ref);
285
286     TRACE("(%p)->(): new ref = %d\n", This, ref);
287     
288     return ref;
289 }
290
291 static ULONG WINAPI FilterGraphInner_Release(IUnknown * iface)
292 {
293     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
294     ULONG ref = InterlockedDecrement(&This->ref);
295
296     TRACE("(%p)->(): new ref = %d\n", This, ref);
297
298     if (ref == 0) {
299         int i;
300
301         This->ref = 1; /* guard against reentrancy (aggregation). */
302
303         IMediaControl_Stop((IMediaControl*)&(This->IMediaControl_vtbl));
304
305         while (This->nFilters)
306             IFilterGraph2_RemoveFilter((IFilterGraph2*)This, This->ppFiltersInGraph[0]);
307
308         if (This->refClock)
309             IReferenceClock_Release(This->refClock);
310
311         for (i = 0; i < This->nItfCacheEntries; i++)
312         {
313             if (This->ItfCacheEntries[i].iface)
314                 IUnknown_Release(This->ItfCacheEntries[i].iface);
315         }
316
317         /* AddRef on controlling IUnknown, to compensate for Release of cached IFilterMapper2 interface below.
318
319          * NOTE: Filtergraph_AddRef isn't suitable, because bUnkOuterValid may be FALSE but punkOuter non-NULL
320          * and already passed as punkOuter to filtermapper in FilterGraph_create - this will happen in case of
321          * CoCreateInstance of filtergraph with non-null pUnkOuter and REFIID other than IID_Unknown that is
322          * cleaning up after error. */
323         if (This->pUnkOuter) IUnknown_AddRef(This->pUnkOuter);
324         else IUnknown_AddRef((IUnknown*)&This->IInner_vtbl);
325
326         IFilterMapper2_Release(This->pFilterMapper2);
327         IUnknown_Release(This->punkFilterMapper2);
328
329         CloseHandle(This->hEventCompletion);
330         EventsQueue_Destroy(&This->evqueue);
331         This->cs.DebugInfo->Spare[0] = 0;
332         DeleteCriticalSection(&This->cs);
333         CoTaskMemFree(This->ppFiltersInGraph);
334         CoTaskMemFree(This->pFilterNames);
335         CoTaskMemFree(This);
336     }
337     return ref;
338 }
339
340
341 /*** IUnknown methods ***/
342 static HRESULT WINAPI FilterGraph2_QueryInterface(IFilterGraph2 *iface,
343                                                   REFIID riid,
344                                                   LPVOID*ppvObj) {
345     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
346     
347     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
348     return Filtergraph_QueryInterface(This, riid, ppvObj);
349 }
350
351 static ULONG WINAPI FilterGraph2_AddRef(IFilterGraph2 *iface) {
352     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
353     
354     TRACE("(%p/%p)->() calling FilterGraph AddRef\n", This, iface);
355     
356     return Filtergraph_AddRef(This);
357 }
358
359 static ULONG WINAPI FilterGraph2_Release(IFilterGraph2 *iface) {
360     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
361     
362     TRACE("(%p/%p)->() calling FilterGraph Release\n", This, iface);
363
364     return Filtergraph_Release(This);
365 }
366
367 /*** IFilterGraph methods ***/
368 static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface,
369                                              IBaseFilter *pFilter,
370                                              LPCWSTR pName) {
371     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
372     HRESULT hr;
373     int i,j;
374     WCHAR* wszFilterName = NULL;
375     int duplicate_name = FALSE;
376
377     TRACE("(%p/%p)->(%p, %s (%p))\n", This, iface, pFilter, debugstr_w(pName), pName);
378
379     if (!pFilter)
380         return E_POINTER;
381
382     wszFilterName = CoTaskMemAlloc( (pName ? strlenW(pName) + 6 : 5) * sizeof(WCHAR) );
383
384     if (pName)
385     {
386         /* Check if name already exists */
387         for(i = 0; i < This->nFilters; i++)
388             if (!strcmpW(This->pFilterNames[i], pName))
389             {
390                 duplicate_name = TRUE;
391                 break;
392             }
393     }
394
395     /* If no name given or name already existing, generate one */
396     if (!pName || duplicate_name)
397     {
398         static const WCHAR wszFmt1[] = {'%','s',' ','%','0','4','d',0};
399         static const WCHAR wszFmt2[] = {'%','0','4','d',0};
400
401         for (j = 0; j < 10000 ; j++)
402         {
403             /* Create name */
404             if (pName)
405                 sprintfW(wszFilterName, wszFmt1, pName, This->nameIndex);
406             else
407                 sprintfW(wszFilterName, wszFmt2, This->nameIndex);
408             TRACE("Generated name %s\n", debugstr_w(wszFilterName));
409
410             /* Check if the generated name already exists */
411             for(i = 0; i < This->nFilters; i++)
412                 if (!strcmpW(This->pFilterNames[i], wszFilterName))
413                     break;
414
415             /* Compute next index and exit if generated name is suitable */
416             if (This->nameIndex++ == 10000)
417                 This->nameIndex = 1;
418             if (i == This->nFilters)
419                 break;
420         }
421         /* Unable to find a suitable name */
422         if (j == 10000)
423         {
424             CoTaskMemFree(wszFilterName);
425             return VFW_E_DUPLICATE_NAME;
426         }
427     }
428     else
429         memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
430
431     if (This->nFilters + 1 > This->filterCapacity)
432     {
433         int newCapacity = This->filterCapacity ? 2 * This->filterCapacity : 1;
434         IBaseFilter ** ppNewFilters = CoTaskMemAlloc(newCapacity * sizeof(IBaseFilter*));
435         LPWSTR * pNewNames = CoTaskMemAlloc(newCapacity * sizeof(LPWSTR));
436         memcpy(ppNewFilters, This->ppFiltersInGraph, This->nFilters * sizeof(IBaseFilter*));
437         memcpy(pNewNames, This->pFilterNames, This->nFilters * sizeof(LPWSTR));
438         if (This->filterCapacity)
439         {
440             CoTaskMemFree(This->ppFiltersInGraph);
441             CoTaskMemFree(This->pFilterNames);
442         }
443         This->ppFiltersInGraph = ppNewFilters;
444         This->pFilterNames = pNewNames;
445         This->filterCapacity = newCapacity;
446     }
447
448     hr = IBaseFilter_JoinFilterGraph(pFilter, (IFilterGraph *)This, wszFilterName);
449
450     if (SUCCEEDED(hr))
451     {
452         IBaseFilter_AddRef(pFilter);
453         This->ppFiltersInGraph[This->nFilters] = pFilter;
454         This->pFilterNames[This->nFilters] = wszFilterName;
455         This->nFilters++;
456         IBaseFilter_SetSyncSource(pFilter, This->refClock);
457     }
458     else
459         CoTaskMemFree(wszFilterName);
460
461     if (SUCCEEDED(hr) && duplicate_name)
462         return VFW_S_DUPLICATE_NAME;
463         
464     return hr;
465 }
466
467 static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilter *pFilter)
468 {
469     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
470     int i;
471     HRESULT hr = E_FAIL;
472
473     TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
474
475     /* FIXME: check graph is stopped */
476
477     for (i = 0; i < This->nFilters; i++)
478     {
479         if (This->ppFiltersInGraph[i] == pFilter)
480         {
481             IEnumPins *penumpins = NULL;
482             FILTER_STATE state;
483
484             TRACE("Removing filter %s\n", debugstr_w(This->pFilterNames[i]));
485             IBaseFilter_GetState(pFilter, 0, &state);
486             if (state == State_Running)
487                 IBaseFilter_Pause(pFilter);
488             if (state != State_Stopped)
489                 IBaseFilter_Stop(pFilter);
490
491             hr = IBaseFilter_EnumPins(pFilter, &penumpins);
492             if (SUCCEEDED(hr)) {
493                 IPin *ppin;
494                 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
495                 {
496                     IPin *victim = NULL;
497                     HRESULT h;
498                     IPin_ConnectedTo(ppin, &victim);
499                     if (victim)
500                     {
501                         h = IPin_Disconnect(victim);
502                         TRACE("Disconnect other side: %08x\n", h);
503                         if (h == VFW_E_NOT_STOPPED)
504                         {
505                             PIN_INFO pinfo;
506                             IPin_QueryPinInfo(victim, &pinfo);
507
508                             IBaseFilter_GetState(pinfo.pFilter, 0, &state);
509                             if (state == State_Running)
510                                 IBaseFilter_Pause(pinfo.pFilter);
511                             IBaseFilter_Stop(pinfo.pFilter);
512                             IBaseFilter_Release(pinfo.pFilter);
513                             h = IPin_Disconnect(victim);
514                             TRACE("Disconnect retry: %08x\n", h);
515                         }
516                         IPin_Release(victim);
517                     }
518                     h = IPin_Disconnect(ppin);
519                     TRACE("Disconnect 2: %08x\n", h);
520
521                     IPin_Release(ppin);
522                 }
523                 IEnumPins_Release(penumpins);
524             }
525
526             hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, This->pFilterNames[i]);
527             if (SUCCEEDED(hr))
528             {
529                 IBaseFilter_SetSyncSource(pFilter, NULL);
530                 IBaseFilter_Release(pFilter);
531                 CoTaskMemFree(This->pFilterNames[i]);
532                 memmove(This->ppFiltersInGraph+i, This->ppFiltersInGraph+i+1, sizeof(IBaseFilter*)*(This->nFilters - 1 - i));
533                 memmove(This->pFilterNames+i, This->pFilterNames+i+1, sizeof(LPWSTR)*(This->nFilters - 1 - i));
534                 This->nFilters--;
535                 /* Invalidate interfaces in the cache */
536                 for (i = 0; i < This->nItfCacheEntries; i++)
537                     if (pFilter == This->ItfCacheEntries[i].filter)
538                     {
539                         IUnknown_Release(This->ItfCacheEntries[i].iface);
540                         This->ItfCacheEntries[i].iface = NULL;
541                         This->ItfCacheEntries[i].filter = NULL;
542                     }
543                 return S_OK;
544             }
545             break;
546         }
547     }
548
549     return hr; /* FIXME: check this error code */
550 }
551
552 static HRESULT WINAPI FilterGraph2_EnumFilters(IFilterGraph2 *iface,
553                                               IEnumFilters **ppEnum) {
554     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
555
556     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
557
558     return IEnumFiltersImpl_Construct(This->ppFiltersInGraph, This->nFilters, ppEnum);
559 }
560
561 static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface,
562                                                     LPCWSTR pName,
563                                                     IBaseFilter **ppFilter) {
564     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
565     int i;
566
567     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_w(pName), pName, ppFilter);
568
569     if (!ppFilter)
570         return E_POINTER;
571
572     for (i = 0; i < This->nFilters; i++)
573     {
574         if (!strcmpW(pName, This->pFilterNames[i]))
575         {
576             *ppFilter = This->ppFiltersInGraph[i];
577             IBaseFilter_AddRef(*ppFilter);
578             return S_OK;
579         }
580     }
581
582     *ppFilter = NULL;
583     return VFW_E_NOT_FOUND;
584 }
585
586 /* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
587  * A circular connection will be formed if from the filter of the output pin, the input pin can be reached
588  */
589 static HRESULT CheckCircularConnection(IFilterGraphImpl *This, IPin *out, IPin *in)
590 {
591 #if 1
592     HRESULT hr;
593     PIN_INFO info_out, info_in;
594
595     hr = IPin_QueryPinInfo(out, &info_out);
596     if (FAILED(hr))
597         return hr;
598     if (info_out.dir != PINDIR_OUTPUT)
599     {
600         IBaseFilter_Release(info_out.pFilter);
601         return E_UNEXPECTED;
602     }
603
604     hr = IPin_QueryPinInfo(in, &info_in);
605     if (SUCCEEDED(hr))
606         IBaseFilter_Release(info_in.pFilter);
607     if (FAILED(hr))
608         goto out;
609     if (info_in.dir != PINDIR_INPUT)
610     {
611         hr = E_UNEXPECTED;
612         goto out;
613     }
614
615     if (info_out.pFilter == info_in.pFilter)
616         hr = VFW_E_CIRCULAR_GRAPH;
617     else
618     {
619         IEnumPins *enumpins;
620         IPin *test;
621
622         hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
623         if (FAILED(hr))
624             goto out;
625
626         IEnumPins_Reset(enumpins);
627         while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
628         {
629             PIN_DIRECTION dir = PINDIR_OUTPUT;
630             IPin_QueryDirection(test, &dir);
631             if (dir == PINDIR_INPUT)
632             {
633                 IPin *victim = NULL;
634                 IPin_ConnectedTo(test, &victim);
635                 if (victim)
636                 {
637                     hr = CheckCircularConnection(This, victim, in);
638                     IPin_Release(victim);
639                     if (FAILED(hr))
640                     {
641                         IPin_Release(test);
642                         break;
643                     }
644                 }
645             }
646             IPin_Release(test);
647         }
648         IEnumPins_Release(enumpins);
649     }
650
651 out:
652     IBaseFilter_Release(info_out.pFilter);
653     if (FAILED(hr))
654         ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
655     return hr;
656 #else
657     /* Debugging filtergraphs not enabled */
658     return S_OK;
659 #endif
660 }
661
662
663 /* NOTE: despite the implication, it doesn't matter which
664  * way round you put in the input and output pins */
665 static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface,
666                                                  IPin *ppinIn,
667                                                  IPin *ppinOut,
668                                                  const AM_MEDIA_TYPE *pmt) {
669     PIN_DIRECTION dir;
670     HRESULT hr;
671
672     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
673
674     TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
675
676     /* FIXME: check pins are in graph */
677
678     if (TRACE_ON(quartz))
679     {
680         PIN_INFO PinInfo;
681
682         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
683         if (FAILED(hr))
684             return hr;
685
686         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
687         IBaseFilter_Release(PinInfo.pFilter);
688
689         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
690         if (FAILED(hr))
691             return hr;
692
693         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
694         IBaseFilter_Release(PinInfo.pFilter);
695     }
696
697     hr = IPin_QueryDirection(ppinIn, &dir);
698     if (SUCCEEDED(hr))
699     {
700         if (dir == PINDIR_INPUT)
701         {
702             hr = CheckCircularConnection(This, ppinOut, ppinIn);
703             if (SUCCEEDED(hr))
704                 hr = IPin_Connect(ppinOut, ppinIn, pmt);
705         }
706         else
707         {
708             hr = CheckCircularConnection(This, ppinIn, ppinOut);
709             if (SUCCEEDED(hr))
710                 hr = IPin_Connect(ppinIn, ppinOut, pmt);
711         }
712     }
713
714     return hr;
715 }
716
717 static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface,
718                                              IPin *ppin) {
719     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
720     IPin *pConnectedTo = NULL;
721     HRESULT hr;
722     PIN_DIRECTION pindir;
723
724     IPin_QueryDirection(ppin, &pindir);
725     hr = IPin_ConnectedTo(ppin, &pConnectedTo);
726     if (FAILED(hr)) {
727         TRACE("Querying connected to failed: %x\n", hr);
728         return hr; 
729     }
730     IPin_Disconnect(ppin);
731     IPin_Disconnect(pConnectedTo);
732     if (pindir == PINDIR_INPUT)
733         hr = IPin_Connect(pConnectedTo, ppin, NULL);
734     else
735         hr = IPin_Connect(ppin, pConnectedTo, NULL);
736     IPin_Release(pConnectedTo);
737     if (FAILED(hr))
738         WARN("Reconnecting pins failed, pins are not connected now..\n");
739     TRACE("(%p->%p) -- %p %p -> %x\n", iface, This, ppin, pConnectedTo, hr);
740     return hr;
741 }
742
743 static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
744 {
745     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
746
747     TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
748
749     if (!ppin)
750        return E_POINTER;
751
752     return IPin_Disconnect(ppin);
753 }
754
755 static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface) {
756     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
757     IReferenceClock *pClock = NULL;
758     HRESULT hr = S_OK;
759     int i;
760
761     TRACE("(%p/%p)->() live sources not handled properly!\n", iface, This);
762
763     EnterCriticalSection(&This->cs);
764
765     for (i = 0; i < This->nFilters; ++i)
766     {
767         DWORD miscflags;
768         IAMFilterMiscFlags *flags = NULL;
769         IUnknown_QueryInterface(This->ppFiltersInGraph[i], &IID_IAMFilterMiscFlags, (void**)&flags);
770         if (!flags)
771             continue;
772         miscflags = IAMFilterMiscFlags_GetMiscFlags(flags);
773         IUnknown_Release(flags);
774         if (miscflags == AM_FILTER_MISC_FLAGS_IS_RENDERER)
775             IUnknown_QueryInterface(This->ppFiltersInGraph[i], &IID_IReferenceClock, (void**)&pClock);
776         if (pClock)
777             break;
778     }
779
780     if (!pClock)
781         hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
782
783     if (SUCCEEDED(hr))
784     {
785         hr = IMediaFilter_SetSyncSource((IMediaFilter*)&(This->IMediaFilter_vtbl), pClock);
786         This->defaultclock = TRUE;
787         IReferenceClock_Release(pClock);
788     }
789     LeaveCriticalSection(&This->cs);
790
791     return hr;
792 }
793
794 static HRESULT GetFilterInfo(IMoniker* pMoniker, GUID* pclsid, VARIANT* pvar)
795 {
796     static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
797     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
798     IPropertyBag * pPropBagCat = NULL;
799     HRESULT hr;
800
801     VariantInit(pvar);
802
803     hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
804
805     if (SUCCEEDED(hr))
806         hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
807
808     if (SUCCEEDED(hr))
809         hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid);
810
811     VariantClear(pvar);
812
813     if (SUCCEEDED(hr))
814         hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
815
816     if (SUCCEEDED(hr))
817         TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_UNION(pvar, bstrVal)));
818
819     if (pPropBagCat)
820         IPropertyBag_Release(pPropBagCat);
821
822     return hr;
823 }
824
825 static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
826 {
827     HRESULT hr;
828     ULONG nb = 0;
829
830     TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
831     hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
832     if (hr == S_OK) {
833         /* Rendered input */
834     } else if (hr == S_FALSE) {
835         *pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
836         hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
837         if (hr != S_OK) {
838             WARN("Error (%x)\n", hr);
839         }
840     } else if (hr == E_NOTIMPL) {
841         /* Input connected to all outputs */
842         IEnumPins* penumpins;
843         IPin* ppin;
844         int i = 0;
845         TRACE("E_NOTIMPL\n");
846         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
847         if (FAILED(hr)) {
848             WARN("filter Enumpins failed (%x)\n", hr);
849             return hr;
850         }
851         i = 0;
852         /* Count output pins */
853         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
854             PIN_DIRECTION pindir;
855             IPin_QueryDirection(ppin, &pindir);
856             if (pindir == PINDIR_OUTPUT)
857                 i++;
858             IPin_Release(ppin);
859         }
860         *pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
861         /* Retrieve output pins */
862         IEnumPins_Reset(penumpins);
863         i = 0;
864         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
865             PIN_DIRECTION pindir;
866             IPin_QueryDirection(ppin, &pindir);
867             if (pindir == PINDIR_OUTPUT)
868                 (*pppins)[i++] = ppin;
869             else
870                 IPin_Release(ppin);
871         }
872         IEnumPins_Release(penumpins);
873         nb = i;
874         if (FAILED(hr)) {
875             WARN("Next failed (%x)\n", hr);
876             return hr;
877         }
878     } else if (FAILED(hr)) {
879         WARN("Cannot get internal connection (%x)\n", hr);
880         return hr;
881     }
882
883     *pnb = nb;
884     return S_OK;
885 }
886
887 /*** IGraphBuilder methods ***/
888 static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
889 {
890     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
891     HRESULT hr;
892     AM_MEDIA_TYPE* mt = NULL;
893     IEnumMediaTypes* penummt = NULL;
894     ULONG nbmt;
895     IEnumPins* penumpins;
896     IEnumMoniker* pEnumMoniker;
897     GUID tab[2];
898     ULONG nb;
899     IMoniker* pMoniker;
900     ULONG pin;
901     PIN_INFO PinInfo;
902     CLSID FilterCLSID;
903     PIN_DIRECTION dir;
904
905     TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
906
907     if (TRACE_ON(quartz))
908     {
909         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
910         if (FAILED(hr))
911             return hr;
912
913         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
914         IBaseFilter_Release(PinInfo.pFilter);
915
916         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
917         if (FAILED(hr))
918             return hr;
919
920         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
921         IBaseFilter_Release(PinInfo.pFilter);
922     }
923
924     EnterCriticalSection(&This->cs);
925     ++This->recursioncount;
926     if (This->recursioncount >= 5)
927     {
928         WARN("Recursion count has reached %d\n", This->recursioncount);
929         hr = VFW_E_CANNOT_CONNECT;
930         goto out;
931     }
932
933     hr = IPin_QueryDirection(ppinOut, &dir);
934     if (FAILED(hr))
935         goto out;
936
937     if (dir == PINDIR_INPUT)
938     {
939         IPin *temp;
940
941         temp = ppinIn;
942         ppinIn = ppinOut;
943         ppinOut = temp;
944     }
945
946     hr = CheckCircularConnection(This, ppinOut, ppinIn);
947     if (FAILED(hr))
948         goto out;
949
950     /* Try direct connection first */
951     hr = IPin_Connect(ppinOut, ppinIn, NULL);
952     if (SUCCEEDED(hr))
953         goto out;
954
955     TRACE("Direct connection failed, trying to render using extra filters\n");
956
957     hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
958     if (FAILED(hr))
959         goto out;
960
961     hr = IBaseFilter_GetClassID(PinInfo.pFilter, &FilterCLSID);
962     IBaseFilter_Release(PinInfo.pFilter);
963     if (FAILED(hr))
964         goto out;
965
966     /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream 
967      * filter to the minor mediatype of input pin of the renderer */
968     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
969     if (FAILED(hr))
970     {
971         WARN("EnumMediaTypes (%x)\n", hr);
972         goto out;
973     }
974
975     hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
976     if (FAILED(hr)) {
977         WARN("IEnumMediaTypes_Next (%x)\n", hr);
978         goto out;
979     }
980
981     if (!nbmt)
982     {
983         WARN("No media type found!\n");
984         hr = VFW_E_INVALIDMEDIATYPE;
985         goto out;
986     }
987     TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
988     TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
989
990     /* Try to find a suitable filter that can connect to the pin to render */
991     tab[0] = mt->majortype;
992     tab[1] = mt->subtype;
993     hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
994     if (FAILED(hr)) {
995         WARN("Unable to enum filters (%x)\n", hr);
996         goto out;
997     }
998
999     hr = VFW_E_CANNOT_RENDER;
1000     while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1001     {
1002         VARIANT var;
1003         GUID clsid;
1004         IPin** ppins;
1005         IPin* ppinfilter = NULL;
1006         IBaseFilter* pfilter = NULL;
1007
1008         hr = GetFilterInfo(pMoniker, &clsid, &var);
1009         IMoniker_Release(pMoniker);
1010         if (FAILED(hr)) {
1011             WARN("Unable to retrieve filter info (%x)\n", hr);
1012             goto error;
1013         }
1014
1015         if (IsEqualGUID(&clsid, &FilterCLSID)) {
1016             /* Skip filter (same as the one the output pin belongs to) */
1017             goto error;
1018         }
1019
1020         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
1021         if (FAILED(hr)) {
1022             WARN("Unable to create filter (%x), trying next one\n", hr);
1023             goto error;
1024         }
1025
1026         hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
1027         if (FAILED(hr)) {
1028             WARN("Unable to add filter (%x)\n", hr);
1029             IBaseFilter_Release(pfilter);
1030             pfilter = NULL;
1031             goto error;
1032         }
1033
1034         VariantClear(&var);
1035
1036         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1037         if (FAILED(hr)) {
1038             WARN("Enumpins (%x)\n", hr);
1039             goto error;
1040         }
1041
1042         hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
1043         IEnumPins_Release(penumpins);
1044
1045         if (FAILED(hr)) {
1046             WARN("Obtaining next pin: (%x)\n", hr);
1047             goto error;
1048         }
1049         if (pin == 0) {
1050             WARN("Cannot use this filter: no pins\n");
1051             goto error;
1052         }
1053
1054         hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1055         if (FAILED(hr)) {
1056             TRACE("Cannot connect to filter (%x), trying next one\n", hr);
1057             goto error;
1058         }
1059         TRACE("Successfully connected to filter, follow chain...\n");
1060
1061         /* Render all output pins of the filter by calling IFilterGraph2_Connect on each of them */
1062         hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
1063
1064         if (SUCCEEDED(hr)) {
1065             unsigned int i;
1066             if (nb == 0) {
1067                 IPin_Disconnect(ppinfilter);
1068                 IPin_Disconnect(ppinOut);
1069                 goto error;
1070             }
1071             TRACE("pins to consider: %d\n", nb);
1072             for(i = 0; i < nb; i++)
1073             {
1074                 LPWSTR pinname = NULL;
1075
1076                 TRACE("Processing pin %u\n", i);
1077
1078                 hr = IPin_QueryId(ppins[i], &pinname);
1079                 if (SUCCEEDED(hr))
1080                 {
1081                     if (pinname[0] == '~')
1082                     {
1083                         TRACE("Pinname=%s, skipping\n", debugstr_w(pinname));
1084                         hr = E_FAIL;
1085                     }
1086                     else
1087                         hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn);
1088                     CoTaskMemFree(pinname);
1089                 }
1090
1091                 if (FAILED(hr)) {
1092                    TRACE("Cannot connect pin %p (%x)\n", ppinfilter, hr);
1093                 }
1094                 IPin_Release(ppins[i]);
1095                 if (SUCCEEDED(hr)) break;
1096             }
1097             while (++i < nb) IPin_Release(ppins[i]);
1098             CoTaskMemFree(ppins);
1099             IPin_Release(ppinfilter);
1100             IBaseFilter_Release(pfilter);
1101             if (FAILED(hr))
1102             {
1103                 IPin_Disconnect(ppinfilter);
1104                 IPin_Disconnect(ppinOut);
1105                 IFilterGraph2_RemoveFilter(iface, pfilter);
1106                 continue;
1107             }
1108             break;
1109         }
1110
1111 error:
1112         VariantClear(&var);
1113         if (ppinfilter) IPin_Release(ppinfilter);
1114         if (pfilter) {
1115             IFilterGraph2_RemoveFilter(iface, pfilter);
1116             IBaseFilter_Release(pfilter);
1117         }
1118     }
1119
1120 out:
1121     if (penummt)
1122         IEnumMediaTypes_Release(penummt);
1123     if (mt)
1124         DeleteMediaType(mt);
1125     --This->recursioncount;
1126     LeaveCriticalSection(&This->cs);
1127     TRACE("--> %08x\n", hr);
1128     return SUCCEEDED(hr) ? S_OK : hr;
1129 }
1130
1131 static HRESULT FilterGraph2_RenderRecurse(IFilterGraphImpl *This, IPin *ppinOut)
1132 {
1133     /* This pin has been connected now, try to call render on all pins that aren't connected */
1134     IPin *to = NULL;
1135     PIN_INFO info;
1136     IEnumPins *enumpins = NULL;
1137     BOOL renderany = FALSE;
1138     BOOL renderall = TRUE;
1139
1140     IPin_QueryPinInfo(ppinOut, &info);
1141
1142     IBaseFilter_EnumPins(info.pFilter, &enumpins);
1143     /* Don't need to hold a reference, IEnumPins does */
1144     IBaseFilter_Release(info.pFilter);
1145
1146     IEnumPins_Reset(enumpins);
1147     while (IEnumPins_Next(enumpins, 1, &to, NULL) == S_OK)
1148     {
1149         PIN_DIRECTION dir = PINDIR_INPUT;
1150
1151         IPin_QueryDirection(to, &dir);
1152
1153         if (dir == PINDIR_OUTPUT)
1154         {
1155             IPin *out = NULL;
1156
1157             IPin_ConnectedTo(to, &out);
1158             if (!out)
1159             {
1160                 HRESULT hr;
1161                 hr = IFilterGraph2_Render((IFilterGraph2 *)&This->IFilterGraph2_vtbl, to);
1162                 if (SUCCEEDED(hr))
1163                     renderany = TRUE;
1164                 else
1165                     renderall = FALSE;
1166             }
1167             else
1168                 IPin_Release(out);
1169         }
1170
1171         IPin_Release(to);
1172     }
1173
1174     IEnumPins_Release(enumpins);
1175
1176     if (renderall)
1177         return S_OK;
1178
1179     if (renderany)
1180         return VFW_S_PARTIAL_RENDER;
1181
1182     return VFW_E_CANNOT_RENDER;
1183 }
1184
1185 /* Ogg hates me if I create a direct rendering method
1186  *
1187  * It can only connect to a pin properly once, so use a recursive method that does
1188  *
1189  *  +----+ --- (PIN 1) (Render is called on this pin)
1190  *  |    |
1191  *  +----+ --- (PIN 2)
1192  *
1193  *  Enumerate possible renderers that EXACTLY match the requested type
1194  *
1195  *  If none is available, try to add intermediate filters that can connect to the input pin
1196  *  then call Render on that intermediate pin's output pins
1197  *  if it succeeds: Render returns success, if it doesn't, the intermediate filter is removed,
1198  *  and another filter that can connect to the input pin is tried
1199  *  if we run out of filters that can, give up and return VFW_E_CANNOT_RENDER
1200  *  It's recursive, but fun!
1201  */
1202
1203 static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *ppinOut)
1204 {
1205     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1206     IEnumMediaTypes* penummt;
1207     AM_MEDIA_TYPE* mt;
1208     ULONG nbmt;
1209     HRESULT hr;
1210
1211     IEnumMoniker* pEnumMoniker;
1212     GUID tab[4];
1213     ULONG nb;
1214     IMoniker* pMoniker;
1215     INT x;
1216
1217     TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
1218
1219     if (TRACE_ON(quartz))
1220     {
1221         PIN_INFO PinInfo;
1222
1223         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
1224         if (FAILED(hr))
1225             return hr;
1226
1227         TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
1228         IBaseFilter_Release(PinInfo.pFilter);
1229     }
1230
1231     /* Try to find out if there is a renderer for the specified subtype already, and use that
1232      */
1233     EnterCriticalSection(&This->cs);
1234     for (x = 0; x < This->nFilters; ++x)
1235     {
1236         IEnumPins *enumpins = NULL;
1237         IPin *pin = NULL;
1238
1239         hr = IBaseFilter_EnumPins(This->ppFiltersInGraph[x], &enumpins);
1240
1241         if (FAILED(hr) || !enumpins)
1242             continue;
1243
1244         IEnumPins_Reset(enumpins);
1245         while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
1246         {
1247             IPin *to = NULL;
1248             PIN_DIRECTION dir = PINDIR_OUTPUT;
1249
1250             IPin_QueryDirection(pin, &dir);
1251             if (dir != PINDIR_INPUT)
1252             {
1253                 IPin_Release(pin);
1254                 continue;
1255             }
1256             IPin_ConnectedTo(pin, &to);
1257
1258             if (to == NULL)
1259             {
1260                 hr = FilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL);
1261                 if (SUCCEEDED(hr))
1262                 {
1263                     TRACE("Connected successfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
1264                     IPin_Release(pin);
1265
1266                     hr = FilterGraph2_RenderRecurse(This, pin);
1267                     if (FAILED(hr))
1268                     {
1269                         IPin_Disconnect(ppinOut);
1270                         IPin_Disconnect(pin);
1271                         continue;
1272                     }
1273                     IEnumPins_Release(enumpins);
1274                     LeaveCriticalSection(&This->cs);
1275                     return hr;
1276                 }
1277                 WARN("Could not connect!\n");
1278             }
1279             else
1280                 IPin_Release(to);
1281
1282             IPin_Release(pin);
1283         }
1284         IEnumPins_Release(enumpins);
1285     }
1286
1287     LeaveCriticalSection(&This->cs);
1288
1289     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
1290     if (FAILED(hr)) {
1291         WARN("EnumMediaTypes (%x)\n", hr);
1292         return hr;
1293     }
1294
1295     IEnumMediaTypes_Reset(penummt);
1296
1297     /* Looks like no existing renderer of the kind exists
1298      * Try adding new ones
1299      */
1300     tab[0] = tab[1] = GUID_NULL;
1301     while (SUCCEEDED(hr))
1302     {
1303         hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
1304         if (FAILED(hr)) {
1305             WARN("IEnumMediaTypes_Next (%x)\n", hr);
1306             break;
1307         }
1308         if (!nbmt)
1309         {
1310             hr = VFW_E_CANNOT_RENDER;
1311             break;
1312         }
1313         else
1314         {
1315             TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1316             TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1317
1318             /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
1319             if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&tab[1], &mt->subtype))
1320             {
1321                 DeleteMediaType(mt);
1322                 continue;
1323             }
1324
1325             /* Try to find a suitable renderer with the same media type */
1326             tab[0] = mt->majortype;
1327             tab[1] = mt->subtype;
1328             hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1329             if (FAILED(hr))
1330             {
1331                 WARN("Unable to enum filters (%x)\n", hr);
1332                 break;
1333             }
1334         }
1335         hr = E_FAIL;
1336
1337         while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1338         {
1339             VARIANT var;
1340             GUID clsid;
1341             IPin* ppinfilter;
1342             IBaseFilter* pfilter = NULL;
1343             IEnumPins* penumpins = NULL;
1344             ULONG pin;
1345
1346             hr = GetFilterInfo(pMoniker, &clsid, &var);
1347             IMoniker_Release(pMoniker);
1348             if (FAILED(hr)) {
1349                 WARN("Unable to retrieve filter info (%x)\n", hr);
1350                 goto error;
1351             }
1352
1353             hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
1354             if (FAILED(hr))
1355             {
1356                 WARN("Unable to create filter (%x), trying next one\n", hr);
1357                 goto error;
1358             }
1359
1360             hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
1361             if (FAILED(hr)) {
1362                 WARN("Unable to add filter (%x)\n", hr);
1363                 IBaseFilter_Release(pfilter);
1364                 pfilter = NULL;
1365                 goto error;
1366             }
1367
1368             hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1369             if (FAILED(hr)) {
1370                 WARN("Splitter Enumpins (%x)\n", hr);
1371                 goto error;
1372             }
1373
1374             while ((hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin)) == S_OK)
1375             {
1376                 PIN_DIRECTION dir;
1377
1378                 if (pin == 0) {
1379                     WARN("No Pin\n");
1380                     hr = E_FAIL;
1381                     goto error;
1382                 }
1383
1384                 hr = IPin_QueryDirection(ppinfilter, &dir);
1385                 if (FAILED(hr)) {
1386                     IPin_Release(ppinfilter);
1387                     WARN("QueryDirection failed (%x)\n", hr);
1388                     goto error;
1389                 }
1390                 if (dir != PINDIR_INPUT) {
1391                     IPin_Release(ppinfilter);
1392                     continue; /* Wrong direction */
1393                 }
1394
1395                 /* Connect the pin to the "Renderer" */
1396                 hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1397                 IPin_Release(ppinfilter);
1398
1399                 if (FAILED(hr)) {
1400                     WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_UNION(&var, bstrVal)), hr);
1401                     goto error;
1402                 }
1403                 TRACE("Connected, recursing %s\n",  debugstr_w(V_UNION(&var, bstrVal)));
1404
1405                 VariantClear(&var);
1406
1407                 hr = FilterGraph2_RenderRecurse(This, ppinfilter);
1408                 if (FAILED(hr)) {
1409                     WARN("Unable to connect recursively (%x)\n", hr);
1410                     goto error;
1411                 }
1412                 IBaseFilter_Release(pfilter);
1413                 break;
1414             }
1415             if (SUCCEEDED(hr)) {
1416                 IEnumPins_Release(penumpins);
1417                 break; /* out of IEnumMoniker_Next loop */
1418             }
1419
1420             /* IEnumPins_Next failed, all other failure case caught by goto error */
1421             WARN("IEnumPins_Next (%x)\n", hr);
1422             /* goto error */
1423
1424 error:
1425             VariantClear(&var);
1426             if (penumpins)
1427                 IEnumPins_Release(penumpins);
1428             if (pfilter) {
1429                 IFilterGraph2_RemoveFilter(iface, pfilter);
1430                 IBaseFilter_Release(pfilter);
1431             }
1432             if (SUCCEEDED(hr)) DebugBreak();
1433         }
1434
1435         IEnumMoniker_Release(pEnumMoniker);
1436         if (nbmt)
1437             DeleteMediaType(mt);
1438         if (SUCCEEDED(hr))
1439             break;
1440         hr = S_OK;
1441     }
1442
1443     IEnumMediaTypes_Release(penummt);
1444     return hr;
1445 }
1446
1447 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface,
1448                                               LPCWSTR lpcwstrFile,
1449                                               LPCWSTR lpcwstrPlayList)
1450 {
1451     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1452     static const WCHAR string[] = {'R','e','a','d','e','r',0};
1453     IBaseFilter* preader = NULL;
1454     IPin* ppinreader = NULL;
1455     IEnumPins* penumpins = NULL;
1456     HRESULT hr;
1457     BOOL partial = FALSE;
1458     HRESULT any = FALSE;
1459
1460     TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1461
1462     if (lpcwstrPlayList != NULL)
1463         return E_INVALIDARG;
1464
1465     hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader);
1466     if (FAILED(hr))
1467         return hr;
1468
1469     if (SUCCEEDED(hr))
1470         hr = IBaseFilter_EnumPins(preader, &penumpins);
1471     if (SUCCEEDED(hr))
1472     {
1473         while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1474         {
1475             PIN_DIRECTION dir;
1476
1477             IPin_QueryDirection(ppinreader, &dir);
1478             if (dir == PINDIR_OUTPUT)
1479             {
1480                 INT i;
1481
1482                 hr = IFilterGraph2_Render(iface, ppinreader);
1483                 TRACE("Render %08x\n", hr);
1484
1485                 for (i = 0; i < This->nFilters; ++i)
1486                     TRACE("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i]));
1487
1488                 if (SUCCEEDED(hr))
1489                     any = TRUE;
1490                 if (hr != S_OK)
1491                     partial = TRUE;
1492             }
1493             IPin_Release(ppinreader);
1494         }
1495         IEnumPins_Release(penumpins);
1496
1497         if (!any)
1498             hr = VFW_E_CANNOT_RENDER;
1499         else if (partial)
1500             hr = VFW_S_PARTIAL_RENDER;
1501         else
1502             hr = S_OK;
1503     }
1504     IBaseFilter_Release(preader);
1505
1506     TRACE("--> %08x\n", hr);
1507     return hr;
1508 }
1509
1510 /* Some filters implement their own asynchronous reader (Theoretically they all should, try to load it first */
1511 static HRESULT GetFileSourceFilter(LPCOLESTR pszFileName, IBaseFilter **filter)
1512 {
1513     static const WCHAR wszReg[] = {'M','e','d','i','a',' ','T','y','p','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1514     HRESULT hr = S_OK;
1515     HKEY extkey;
1516     LONG lRet;
1517
1518     lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszReg, 0, KEY_READ, &extkey);
1519     hr = HRESULT_FROM_WIN32(lRet);
1520
1521     if (SUCCEEDED(hr))
1522     {
1523         static const WCHAR filtersource[] = {'S','o','u','r','c','e',' ','F','i','l','t','e','r',0};
1524         WCHAR *ext = PathFindExtensionW(pszFileName);
1525         WCHAR clsid_key[39];
1526         GUID clsid;
1527         DWORD size = sizeof(clsid_key);
1528         HKEY pathkey;
1529
1530         if (!ext)
1531         {
1532             CloseHandle(extkey);
1533             return E_FAIL;
1534         }
1535
1536         lRet = RegOpenKeyExW(extkey, ext, 0, KEY_READ, &pathkey);
1537         hr = HRESULT_FROM_WIN32(lRet);
1538         CloseHandle(extkey);
1539         if (FAILED(hr))
1540             return hr;
1541
1542         lRet = RegQueryValueExW(pathkey, filtersource, NULL, NULL, (LPBYTE)clsid_key, &size);
1543         hr = HRESULT_FROM_WIN32(lRet);
1544         CloseHandle(pathkey);
1545         if (FAILED(hr))
1546             return hr;
1547
1548         CLSIDFromString(clsid_key, &clsid);
1549
1550         TRACE("CLSID: %s\n", debugstr_guid(&clsid));
1551         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
1552         if (SUCCEEDED(hr))
1553         {
1554             IFileSourceFilter *source = NULL;
1555             hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID*)&source);
1556             if (SUCCEEDED(hr))
1557                 IFileSourceFilter_Release(source);
1558             else
1559                 IBaseFilter_Release(*filter);
1560         }
1561     }
1562     if (FAILED(hr))
1563         *filter = NULL;
1564     return hr;
1565 }
1566
1567 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface,
1568                                                    LPCWSTR lpcwstrFileName,
1569                                                    LPCWSTR lpcwstrFilterName,
1570                                                    IBaseFilter **ppFilter) {
1571     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1572     HRESULT hr;
1573     IBaseFilter* preader;
1574     IFileSourceFilter* pfile = NULL;
1575     AM_MEDIA_TYPE mt;
1576     WCHAR* filename;
1577
1578     TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
1579
1580     /* Try from file name first, then fall back to default asynchronous reader */
1581     hr = GetFileSourceFilter(lpcwstrFileName, &preader);
1582
1583     if (FAILED(hr))
1584         hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader);
1585     if (FAILED(hr)) {
1586         WARN("Unable to create file source filter (%x)\n", hr);
1587         return hr;
1588     }
1589
1590     hr = IFilterGraph2_AddFilter(iface, preader, lpcwstrFilterName);
1591     if (FAILED(hr)) {
1592         WARN("Unable add filter (%x)\n", hr);
1593         IBaseFilter_Release(preader);
1594         return hr;
1595     }
1596
1597     hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
1598     if (FAILED(hr)) {
1599         WARN("Unable to get IFileSourceInterface (%x)\n", hr);
1600         goto error;
1601     }
1602
1603     /* Load the file in the file source filter */
1604     hr = IFileSourceFilter_Load(pfile, lpcwstrFileName, NULL);
1605     if (FAILED(hr)) {
1606         WARN("Load (%x)\n", hr);
1607         goto error;
1608     }
1609
1610     IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
1611     if (FAILED(hr)) {
1612         WARN("GetCurFile (%x)\n", hr);
1613         goto error;
1614     }
1615
1616     TRACE("File %s\n", debugstr_w(filename));
1617     TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
1618     TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
1619
1620     if (ppFilter)
1621         *ppFilter = preader;
1622     IFileSourceFilter_Release(pfile);
1623
1624     return S_OK;
1625     
1626 error:
1627     if (pfile)
1628         IFileSourceFilter_Release(pfile);
1629     IFilterGraph2_RemoveFilter(iface, preader);
1630     IBaseFilter_Release(preader);
1631        
1632     return hr;
1633 }
1634
1635 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface,
1636                                               DWORD_PTR hFile) {
1637     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1638
1639     TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1640
1641     return S_OK;
1642 }
1643
1644 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface) {
1645     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1646
1647     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1648
1649     return S_OK;
1650 }
1651
1652 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface) {
1653     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1654
1655     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1656
1657     return S_OK;
1658 }
1659
1660 /*** IFilterGraph2 methods ***/
1661 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
1662                                                              IMoniker *pMoniker,
1663                                                              IBindCtx *pCtx,
1664                                                              LPCWSTR lpcwstrFilterName,
1665                                                              IBaseFilter **ppFilter) {
1666     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1667
1668     TRACE("(%p/%p)->(%p %p %s %p): stub !!!\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1669
1670     return S_OK;
1671 }
1672
1673 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface,
1674                                                IPin *ppin,
1675                                                const AM_MEDIA_TYPE *pmt) {
1676     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1677
1678     TRACE("(%p/%p)->(%p %p): stub !!!\n", This, iface, ppin, pmt);
1679
1680     return S_OK;
1681 }
1682
1683 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface,
1684                                             IPin *pPinOut,
1685                                             DWORD dwFlags,
1686                                             DWORD *pvContext) {
1687     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1688
1689     TRACE("(%p/%p)->(%p %08x %p): stub !!!\n", This, iface, pPinOut, dwFlags, pvContext);
1690
1691     return S_OK;
1692 }
1693
1694
1695 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1696 {
1697     FilterGraph2_QueryInterface,
1698     FilterGraph2_AddRef,
1699     FilterGraph2_Release,
1700     FilterGraph2_AddFilter,
1701     FilterGraph2_RemoveFilter,
1702     FilterGraph2_EnumFilters,
1703     FilterGraph2_FindFilterByName,
1704     FilterGraph2_ConnectDirect,
1705     FilterGraph2_Reconnect,
1706     FilterGraph2_Disconnect,
1707     FilterGraph2_SetDefaultSyncSource,
1708     FilterGraph2_Connect,
1709     FilterGraph2_Render,
1710     FilterGraph2_RenderFile,
1711     FilterGraph2_AddSourceFilter,
1712     FilterGraph2_SetLogFile,
1713     FilterGraph2_Abort,
1714     FilterGraph2_ShouldOperationContinue,
1715     FilterGraph2_AddSourceFilterForMoniker,
1716     FilterGraph2_ReconnectEx,
1717     FilterGraph2_RenderEx
1718 };
1719
1720 /*** IUnknown methods ***/
1721 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface,
1722                                                   REFIID riid,
1723                                                   LPVOID*ppvObj) {
1724     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1725
1726     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1727
1728     return Filtergraph_QueryInterface(This, riid, ppvObj);
1729 }
1730
1731 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface) {
1732     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1733
1734     TRACE("(%p/%p)->()\n", This, iface);
1735
1736     return Filtergraph_AddRef(This);
1737 }
1738
1739 static ULONG WINAPI MediaControl_Release(IMediaControl *iface) {
1740     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1741
1742     TRACE("(%p/%p)->()\n", This, iface);
1743
1744     return Filtergraph_Release(This);
1745
1746 }
1747
1748 /*** IDispatch methods ***/
1749 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface,
1750                                                     UINT*pctinfo) {
1751     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1752
1753     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1754
1755     return S_OK;
1756 }
1757
1758 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface,
1759                                                UINT iTInfo,
1760                                                LCID lcid,
1761                                                ITypeInfo**ppTInfo) {
1762     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1763
1764     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1765
1766     return S_OK;
1767 }
1768
1769 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface,
1770                                                  REFIID riid,
1771                                                  LPOLESTR*rgszNames,
1772                                                  UINT cNames,
1773                                                  LCID lcid,
1774                                                  DISPID*rgDispId) {
1775     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1776
1777     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1778
1779     return S_OK;
1780 }
1781
1782 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface,
1783                                           DISPID dispIdMember,
1784                                           REFIID riid,
1785                                           LCID lcid,
1786                                           WORD wFlags,
1787                                           DISPPARAMS*pDispParams,
1788                                           VARIANT*pVarResult,
1789                                           EXCEPINFO*pExepInfo,
1790                                           UINT*puArgErr) {
1791     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1792
1793     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);
1794
1795     return S_OK;
1796 }
1797
1798 typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *, DWORD_PTR data);
1799
1800 static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter, DWORD_PTR data)
1801 {
1802     HRESULT hr;
1803     IPin* pInputPin;
1804     IPin** ppPins;
1805     ULONG nb;
1806     ULONG i;
1807     PIN_INFO PinInfo;
1808
1809     TRACE("%p %p\n", pGraph, pOutputPin);
1810     PinInfo.pFilter = NULL;
1811
1812     hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
1813
1814     if (SUCCEEDED(hr))
1815     {
1816         hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
1817         if (SUCCEEDED(hr))
1818             hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
1819         IPin_Release(pInputPin);
1820     }
1821
1822     if (SUCCEEDED(hr))
1823     {
1824         if (nb == 0)
1825         {
1826             TRACE("Reached a renderer\n");
1827             /* Count renderers for end of stream notification */
1828             pGraph->nRenderers++;
1829         }
1830         else
1831         {
1832             for(i = 0; i < nb; i++)
1833             {
1834                 /* Explore the graph downstream from this pin
1835                  * FIXME: We should prevent exploring from a pin more than once. This can happens when
1836                  * several input pins are connected to the same output (a MUX for instance). */
1837                 ExploreGraph(pGraph, ppPins[i], FoundFilter, data);
1838                 IPin_Release(ppPins[i]);
1839             }
1840
1841             CoTaskMemFree(ppPins);
1842         }
1843         TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
1844
1845         FoundFilter(PinInfo.pFilter, data);
1846     }
1847
1848     if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
1849     return hr;
1850 }
1851
1852 static HRESULT WINAPI SendRun(IBaseFilter *pFilter, DWORD_PTR data)
1853 {
1854     REFERENCE_TIME time = *(REFERENCE_TIME*)data;
1855     return IBaseFilter_Run(pFilter, time);
1856 }
1857
1858 static HRESULT WINAPI SendPause(IBaseFilter *pFilter, DWORD_PTR data)
1859 {
1860     return IBaseFilter_Pause(pFilter);
1861 }
1862
1863 static HRESULT WINAPI SendStop(IBaseFilter *pFilter, DWORD_PTR data)
1864 {
1865     return IBaseFilter_Stop(pFilter);
1866 }
1867
1868 static HRESULT WINAPI SendGetState(IBaseFilter *pFilter, DWORD_PTR data)
1869 {
1870     FILTER_STATE state;
1871     DWORD time_end = data;
1872     DWORD time_now = GetTickCount();
1873     LONG wait;
1874
1875     if (time_end == INFINITE)
1876     {
1877         wait = INFINITE;
1878     }
1879     else if (time_end > time_now)
1880     {
1881         wait = time_end - time_now;
1882     }
1883     else
1884         wait = 0;
1885
1886     return IBaseFilter_GetState(pFilter, wait, &state);
1887 }
1888
1889
1890 static HRESULT SendFilterMessage(IMediaControl *iface, fnFoundFilter FoundFilter, DWORD_PTR data)
1891 {
1892     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1893     int i;
1894     IBaseFilter* pfilter;
1895     IEnumPins* pEnum;
1896     HRESULT hr;
1897     IPin* pPin;
1898     DWORD dummy;
1899     PIN_DIRECTION dir;
1900     TRACE("(%p/%p)->()\n", This, iface);
1901
1902     /* Explorer the graph from source filters to renderers, determine renderers
1903      * number and run filters from renderers to source filters */
1904     This->nRenderers = 0;
1905     ResetEvent(This->hEventCompletion);
1906
1907     for(i = 0; i < This->nFilters; i++)
1908     {
1909         BOOL source = TRUE;
1910         pfilter = This->ppFiltersInGraph[i];
1911         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
1912         if (hr != S_OK)
1913         {
1914             WARN("Enum pins failed %x\n", hr);
1915             continue;
1916         }
1917         /* Check if it is a source filter */
1918         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1919         {
1920             IPin_QueryDirection(pPin, &dir);
1921             IPin_Release(pPin);
1922             if (dir == PINDIR_INPUT)
1923             {
1924                 source = FALSE;
1925                 break;
1926             }
1927         }
1928         if (source)
1929         {
1930             TRACE("Found a source filter %p\n", pfilter);
1931             IEnumPins_Reset(pEnum);
1932             while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1933             {
1934                 /* Explore the graph downstream from this pin */
1935                 ExploreGraph(This, pPin, FoundFilter, data);
1936                 IPin_Release(pPin);
1937             }
1938             FoundFilter(pfilter, data);
1939         }
1940         IEnumPins_Release(pEnum);
1941     }
1942
1943     return S_FALSE;
1944 }
1945
1946 /*** IMediaControl methods ***/
1947 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface) {
1948     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1949     TRACE("(%p/%p)->()\n", This, iface);
1950
1951     EnterCriticalSection(&This->cs);
1952     if (This->state == State_Running)
1953         goto out;
1954     This->EcCompleteCount = 0;
1955
1956     if (This->defaultclock && !This->refClock)
1957         IFilterGraph2_SetDefaultSyncSource((IFilterGraph2*)This);
1958
1959     if (This->refClock)
1960     {
1961         REFERENCE_TIME now;
1962         IReferenceClock_GetTime(This->refClock, &now);
1963         if (This->state == State_Stopped)
1964             This->start_time = now + 500000;
1965         else if (This->pause_time >= 0)
1966             This->start_time += now - This->pause_time;
1967         else
1968             This->start_time = now;
1969     }
1970     else This->start_time = 0;
1971
1972     SendFilterMessage(iface, SendRun, (DWORD_PTR)&This->start_time);
1973     This->state = State_Running;
1974 out:
1975     LeaveCriticalSection(&This->cs);
1976     return S_FALSE;
1977 }
1978
1979 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface) {
1980     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1981     TRACE("(%p/%p)->()\n", This, iface);
1982
1983     EnterCriticalSection(&This->cs);
1984     if (This->state == State_Paused)
1985         goto out;
1986
1987     if (This->state == State_Running && This->refClock && This->start_time >= 0)
1988         IReferenceClock_GetTime(This->refClock, &This->pause_time);
1989     else
1990         This->pause_time = -1;
1991
1992     SendFilterMessage(iface, SendPause, 0);
1993     This->state = State_Paused;
1994 out:
1995     LeaveCriticalSection(&This->cs);
1996     return S_FALSE;
1997 }
1998
1999 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface) {
2000     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2001     TRACE("(%p/%p)->()\n", This, iface);
2002
2003     if (This->state == State_Stopped) return S_OK;
2004
2005     EnterCriticalSection(&This->cs);
2006     if (This->state == State_Running) SendFilterMessage(iface, SendPause, 0);
2007     SendFilterMessage(iface, SendStop, 0);
2008     This->state = State_Stopped;
2009     LeaveCriticalSection(&This->cs);
2010     return S_OK;
2011 }
2012
2013 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface,
2014                                             LONG msTimeout,
2015                                             OAFilterState *pfs) {
2016     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2017     DWORD end;
2018
2019     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pfs);
2020
2021     if (!pfs)
2022         return E_POINTER;
2023
2024     EnterCriticalSection(&This->cs);
2025
2026     *pfs = This->state;
2027     if (msTimeout > 0)
2028     {
2029         end = GetTickCount() + msTimeout;
2030     }
2031     else if (msTimeout < 0)
2032     {
2033         end = INFINITE;
2034     }
2035     else
2036     {
2037         end = 0;
2038     }
2039     if (end)
2040         SendFilterMessage(iface, SendGetState, end);
2041
2042     LeaveCriticalSection(&This->cs);
2043
2044     return S_OK;
2045 }
2046
2047 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface,
2048                                               BSTR strFilename) {
2049     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2050
2051     FIXME("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename);
2052
2053     return S_OK;
2054 }
2055
2056 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface,
2057                                                    BSTR strFilename,
2058                                                    IDispatch **ppUnk) {
2059     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2060
2061     FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
2062
2063     return S_OK;
2064 }
2065
2066 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface,
2067                                                         IDispatch **ppUnk) {
2068     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2069
2070     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2071
2072     return S_OK;
2073 }
2074
2075 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface,
2076                                                            IDispatch **ppUnk) {
2077     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2078
2079     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2080
2081     return S_OK;
2082 }
2083
2084 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface) {
2085     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2086
2087     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
2088
2089     return S_OK;
2090 }
2091
2092
2093 static const IMediaControlVtbl IMediaControl_VTable =
2094 {
2095     MediaControl_QueryInterface,
2096     MediaControl_AddRef,
2097     MediaControl_Release,
2098     MediaControl_GetTypeInfoCount,
2099     MediaControl_GetTypeInfo,
2100     MediaControl_GetIDsOfNames,
2101     MediaControl_Invoke,
2102     MediaControl_Run,
2103     MediaControl_Pause,
2104     MediaControl_Stop,
2105     MediaControl_GetState,
2106     MediaControl_RenderFile,
2107     MediaControl_AddSourceFilter,
2108     MediaControl_get_FilterCollection,
2109     MediaControl_get_RegFilterCollection,
2110     MediaControl_StopWhenReady
2111 };
2112
2113
2114 /*** IUnknown methods ***/
2115 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface,
2116                                                   REFIID riid,
2117                                                   LPVOID*ppvObj) {
2118     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2119
2120     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2121
2122     return Filtergraph_QueryInterface(This, riid, ppvObj);
2123 }
2124
2125 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface) {
2126     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2127
2128     TRACE("(%p/%p)->()\n", This, iface);
2129
2130     return Filtergraph_AddRef(This);
2131 }
2132
2133 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface) {
2134     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2135
2136     TRACE("(%p/%p)->()\n", This, iface);
2137
2138     return Filtergraph_Release(This);
2139 }
2140
2141 typedef HRESULT (WINAPI *fnFoundSeek)(IFilterGraphImpl *This, IMediaSeeking*, DWORD_PTR arg);
2142
2143 static HRESULT all_renderers_seek(IFilterGraphImpl *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
2144     BOOL allnotimpl = TRUE;
2145     int i;
2146     HRESULT hr, hr_return = S_OK;
2147
2148     TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
2149     /* Send a message to all renderers, they are responsible for broadcasting it further */
2150
2151     for(i = 0; i < This->nFilters; i++)
2152     {
2153         IMediaSeeking *seek = NULL;
2154         IBaseFilter* pfilter = This->ppFiltersInGraph[i];
2155         IAMFilterMiscFlags *flags = NULL;
2156         ULONG filterflags;
2157         IUnknown_QueryInterface(pfilter, &IID_IAMFilterMiscFlags, (void**)&flags);
2158         if (!flags)
2159             continue;
2160         filterflags = IAMFilterMiscFlags_GetMiscFlags(flags);
2161         IUnknown_Release(flags);
2162         if (filterflags != AM_FILTER_MISC_FLAGS_IS_RENDERER)
2163             continue;
2164
2165         IBaseFilter_QueryInterface(pfilter, &IID_IMediaSeeking, (void**)&seek);
2166         if (!seek)
2167             continue;
2168         hr = FoundSeek(This, seek, arg);
2169         IMediaSeeking_Release(seek);
2170         if (hr_return != E_NOTIMPL)
2171             allnotimpl = FALSE;
2172         if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
2173             hr_return = hr;
2174     }
2175
2176     if (allnotimpl)
2177         return E_NOTIMPL;
2178     return hr_return;
2179 }
2180
2181 static HRESULT WINAPI FoundCapabilities(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pcaps)
2182 {
2183     HRESULT hr;
2184     DWORD caps = 0;
2185
2186     hr = IMediaSeeking_GetCapabilities(seek, &caps);
2187     if (FAILED(hr))
2188         return hr;
2189
2190     /* Only add common capabilities everything supports */
2191     *(DWORD*)pcaps &= caps;
2192
2193     return hr;
2194 }
2195
2196 /*** IMediaSeeking methods ***/
2197 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface,
2198                                                    DWORD *pCapabilities) {
2199     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2200     HRESULT hr;
2201     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2202
2203     if (!pCapabilities)
2204         return E_POINTER;
2205
2206     EnterCriticalSection(&This->cs);
2207     *pCapabilities = 0xffffffff;
2208
2209     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2210     LeaveCriticalSection(&This->cs);
2211
2212     return hr;
2213 }
2214
2215 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface,
2216                                                      DWORD *pCapabilities) {
2217     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2218     DWORD originalcaps;
2219     HRESULT hr;
2220     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2221
2222     if (!pCapabilities)
2223         return E_POINTER;
2224
2225     EnterCriticalSection(&This->cs);
2226     originalcaps = *pCapabilities;
2227     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2228     LeaveCriticalSection(&This->cs);
2229
2230     if (FAILED(hr))
2231         return hr;
2232
2233     if (!*pCapabilities)
2234         return E_FAIL;
2235     if (*pCapabilities != originalcaps)
2236         return S_FALSE;
2237     return S_OK;
2238 }
2239
2240 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface,
2241                                                      const GUID *pFormat) {
2242     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2243
2244     if (!pFormat)
2245         return E_POINTER;
2246
2247     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2248
2249     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2250     {
2251         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2252         return S_FALSE;
2253     }
2254
2255     return S_OK;
2256 }
2257
2258 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface,
2259                                                         GUID *pFormat) {
2260     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2261
2262     if (!pFormat)
2263         return E_POINTER;
2264
2265     FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2266     memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2267
2268     return S_OK;
2269 }
2270
2271 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface,
2272                                                  GUID *pFormat) {
2273     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2274
2275     if (!pFormat)
2276         return E_POINTER;
2277
2278     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2279     memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2280
2281     return S_OK;
2282 }
2283
2284 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface,
2285                                                      const GUID *pFormat) {
2286     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2287
2288     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2289     if (!pFormat)
2290         return E_POINTER;
2291
2292     if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2293         return S_FALSE;
2294
2295     return S_OK;
2296 }
2297
2298 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface,
2299                                                  const GUID *pFormat) {
2300     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2301
2302     if (!pFormat)
2303         return E_POINTER;
2304
2305     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2306
2307     if (This->state != State_Stopped)
2308         return VFW_E_WRONG_STATE;
2309
2310     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2311     {
2312         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2313         return E_INVALIDARG;
2314     }
2315
2316     return S_OK;
2317 }
2318
2319 static HRESULT WINAPI FoundDuration(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pduration)
2320 {
2321     HRESULT hr;
2322     LONGLONG duration = 0, *pdur = (LONGLONG*)pduration;
2323
2324     hr = IMediaSeeking_GetDuration(seek, &duration);
2325     if (FAILED(hr))
2326         return hr;
2327
2328     if (*pdur < duration)
2329         *pdur = duration;
2330     return hr;
2331 }
2332
2333 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface,
2334                                                LONGLONG *pDuration) {
2335     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2336     HRESULT hr;
2337
2338     TRACE("(%p/%p)->(%p)\n", This, iface, pDuration);
2339
2340     if (!pDuration)
2341         return E_POINTER;
2342
2343     EnterCriticalSection(&This->cs);
2344     *pDuration = 0;
2345     hr = all_renderers_seek(This, FoundDuration, (DWORD_PTR)pDuration);
2346     LeaveCriticalSection(&This->cs);
2347
2348     TRACE("--->%08x\n", hr);
2349     return hr;
2350 }
2351
2352 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface,
2353                                                    LONGLONG *pStop) {
2354     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2355     HRESULT hr = S_OK;
2356
2357     TRACE("(%p/%p)->(%p)\n", This, iface, pStop);
2358
2359     if (!pStop)
2360         return E_POINTER;
2361
2362     EnterCriticalSection(&This->cs);
2363     if (This->stop_position < 0)
2364         /* Stop position not set, use duration instead */
2365         hr = IMediaSeeking_GetDuration(iface, pStop);
2366     else
2367         *pStop = This->stop_position;
2368     LeaveCriticalSection(&This->cs);
2369
2370     return hr;
2371 }
2372
2373 static HRESULT WINAPI FoundCurrentPosition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pposition)
2374 {
2375     HRESULT hr;
2376     LONGLONG pos = 0, *ppos = (LONGLONG*)pposition;
2377
2378     hr = IMediaSeeking_GetCurrentPosition(seek, &pos);
2379     if (FAILED(hr))
2380         return hr;
2381
2382     if (*ppos < 0 || pos < *ppos)
2383         *ppos = pos;
2384     return hr;
2385 }
2386
2387 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface,
2388                                                       LONGLONG *pCurrent) {
2389     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2390     HRESULT hr;
2391
2392     if (!pCurrent)
2393         return E_POINTER;
2394
2395     EnterCriticalSection(&This->cs);
2396     *pCurrent = -1;
2397     hr = all_renderers_seek(This, FoundCurrentPosition, (DWORD_PTR)pCurrent);
2398     if (hr == E_NOTIMPL) {
2399         *pCurrent = 0;
2400         hr = S_OK;
2401     }
2402     LeaveCriticalSection(&This->cs);
2403
2404     TRACE("Time: %u.%03u\n", (DWORD)(*pCurrent / 10000000), (DWORD)((*pCurrent / 10000)%1000));
2405
2406     return hr;
2407 }
2408
2409 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface,
2410                                                      LONGLONG *pTarget,
2411                                                      const GUID *pTargetFormat,
2412                                                      LONGLONG Source,
2413                                                      const GUID *pSourceFormat) {
2414     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2415
2416     FIXME("(%p/%p)->(%p, %p, 0x%s, %p): stub !!!\n", This, iface, pTarget,
2417         pTargetFormat, wine_dbgstr_longlong(Source), pSourceFormat);
2418
2419     return S_OK;
2420 }
2421
2422 struct pos_args {
2423     LONGLONG* current, *stop;
2424     DWORD curflags, stopflags;
2425 };
2426
2427 static HRESULT WINAPI found_setposition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pargs)
2428 {
2429     struct pos_args *args = (void*)pargs;
2430
2431     return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags);
2432 }
2433
2434 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface,
2435                                                 LONGLONG *pCurrent,
2436                                                 DWORD dwCurrentFlags,
2437                                                 LONGLONG *pStop,
2438                                                 DWORD dwStopFlags) {
2439     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2440     HRESULT hr = S_OK;
2441     FILTER_STATE state;
2442     struct pos_args args;
2443
2444     TRACE("(%p/%p)->(%p, %08x, %p, %08x)\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
2445
2446     EnterCriticalSection(&This->cs);
2447     state = This->state;
2448     TRACE("State: %s\n", state == State_Running ? "Running" : (state == State_Paused ? "Paused" : (state == State_Stopped ? "Stopped" : "UNKNOWN")));
2449
2450     if ((dwCurrentFlags & 0x7) != AM_SEEKING_AbsolutePositioning &&
2451         (dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2452         FIXME("Adjust method %x not handled yet!\n", dwCurrentFlags & 0x7);
2453
2454     if ((dwStopFlags & 0x7) == AM_SEEKING_AbsolutePositioning)
2455         This->stop_position = *pStop;
2456     else if ((dwStopFlags & 0x7) != AM_SEEKING_NoPositioning)
2457         FIXME("Stop position not handled yet!\n");
2458
2459     args.current = pCurrent;
2460     args.stop = pStop;
2461     args.curflags = dwCurrentFlags;
2462     args.stopflags = dwStopFlags;
2463     hr = all_renderers_seek(This, found_setposition, (DWORD_PTR)&args);
2464
2465     if ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning) {
2466         if (This->state == State_Running)
2467             FIXME("Seeking while graph is running is not properly supported!\n");
2468         This->pause_time = This->start_time = -1;
2469     }
2470     LeaveCriticalSection(&This->cs);
2471
2472     return hr;
2473 }
2474
2475 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
2476                                                 LONGLONG *pCurrent,
2477                                                 LONGLONG *pStop) {
2478     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2479     HRESULT hr;
2480
2481     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pCurrent, pStop);
2482     hr = IMediaSeeking_GetCurrentPosition(iface, pCurrent);
2483     if (SUCCEEDED(hr))
2484         hr = IMediaSeeking_GetStopPosition(iface, pStop);
2485
2486     return hr;
2487 }
2488
2489 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
2490                                                 LONGLONG *pEarliest,
2491                                                 LONGLONG *pLatest) {
2492     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2493
2494     FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2495
2496     return S_OK;
2497 }
2498
2499 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface,
2500                                            double dRate) {
2501     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2502
2503     FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2504
2505     return S_OK;
2506 }
2507
2508 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface,
2509                                            double *pdRate) {
2510     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2511
2512     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2513
2514     return S_OK;
2515 }
2516
2517 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface,
2518                                               LONGLONG *pllPreroll) {
2519     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2520
2521     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2522
2523     return S_OK;
2524 }
2525
2526
2527 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2528 {
2529     MediaSeeking_QueryInterface,
2530     MediaSeeking_AddRef,
2531     MediaSeeking_Release,
2532     MediaSeeking_GetCapabilities,
2533     MediaSeeking_CheckCapabilities,
2534     MediaSeeking_IsFormatSupported,
2535     MediaSeeking_QueryPreferredFormat,
2536     MediaSeeking_GetTimeFormat,
2537     MediaSeeking_IsUsingTimeFormat,
2538     MediaSeeking_SetTimeFormat,
2539     MediaSeeking_GetDuration,
2540     MediaSeeking_GetStopPosition,
2541     MediaSeeking_GetCurrentPosition,
2542     MediaSeeking_ConvertTimeFormat,
2543     MediaSeeking_SetPositions,
2544     MediaSeeking_GetPositions,
2545     MediaSeeking_GetAvailable,
2546     MediaSeeking_SetRate,
2547     MediaSeeking_GetRate,
2548     MediaSeeking_GetPreroll
2549 };
2550
2551 static inline IFilterGraphImpl *impl_from_IMediaPosition( IMediaPosition *iface )
2552 {
2553     return (IFilterGraphImpl *)((char*)iface - FIELD_OFFSET(IFilterGraphImpl, IMediaPosition_vtbl));
2554 }
2555
2556 /*** IUnknown methods ***/
2557 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj)
2558 {
2559     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2560
2561     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2562     return Filtergraph_QueryInterface(This, riid, ppvObj);
2563 }
2564
2565 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
2566 {
2567     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2568
2569     TRACE("(%p/%p)->()\n", This, iface);
2570     return Filtergraph_AddRef(This);
2571 }
2572
2573 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
2574 {
2575     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2576
2577     TRACE("(%p/%p)->()\n", This, iface);
2578     return Filtergraph_Release(This);
2579 }
2580
2581 /*** IDispatch methods ***/
2582 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo){
2583     FIXME("(%p) stub!\n", iface);
2584     return E_NOTIMPL;
2585 }
2586
2587 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo){
2588     FIXME("(%p) stub!\n", iface);
2589     return E_NOTIMPL;
2590 }
2591
2592 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId){
2593     FIXME("(%p) stub!\n", iface);
2594     return E_NOTIMPL;
2595 }
2596
2597 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr){
2598     FIXME("(%p) stub!\n", iface);
2599     return E_NOTIMPL;
2600 }
2601
2602 /*** IMediaPosition methods ***/
2603 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
2604 {
2605     LONGLONG duration;
2606     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2607     HRESULT hr = IMediaSeeking_GetDuration( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &duration );
2608     if (SUCCEEDED(hr)) *plength = duration;
2609     return hr;
2610 }
2611
2612 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
2613 {
2614     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2615     LONGLONG reftime = llTime;
2616
2617     return IMediaSeeking_SetPositions((IMediaSeeking *)&This->IMediaSeeking_vtbl,
2618                                       &reftime, AM_SEEKING_AbsolutePositioning,
2619                                       NULL, AM_SEEKING_NoPositioning);
2620 }
2621
2622 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
2623 {
2624     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2625     LONGLONG pos;
2626     HRESULT hr = IMediaSeeking_GetCurrentPosition( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &pos );
2627     if (SUCCEEDED(hr)) *pllTime = pos;
2628     return hr;
2629 }
2630
2631 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
2632 {
2633     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2634     LONGLONG pos;
2635     HRESULT hr = IMediaSeeking_GetStopPosition( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &pos );
2636     if (SUCCEEDED(hr)) *pllTime = pos;
2637     return hr;
2638 }
2639
2640 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
2641 {
2642     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2643     LONGLONG reftime = llTime;
2644
2645     return IMediaSeeking_SetPositions((IMediaSeeking *)&This->IMediaSeeking_vtbl,
2646                                       NULL, AM_SEEKING_NoPositioning,
2647                                       &reftime, AM_SEEKING_AbsolutePositioning);
2648 }
2649
2650 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime){
2651     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2652     return E_NOTIMPL;
2653 }
2654
2655 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime){
2656     FIXME("(%p)->(%f) stub!\n", iface, llTime);
2657     return E_NOTIMPL;
2658 }
2659
2660 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2661 {
2662     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2663     return IMediaSeeking_SetRate((IMediaSeeking *)&This->IMediaSeeking_vtbl, dRate);
2664 }
2665
2666 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2667 {
2668     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2669     return IMediaSeeking_GetRate((IMediaSeeking *)&This->IMediaSeeking_vtbl, pdRate);
2670 }
2671
2672 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward){
2673     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2674     return E_NOTIMPL;
2675 }
2676
2677 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward){
2678     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2679     return E_NOTIMPL;
2680 }
2681
2682
2683 static const IMediaPositionVtbl IMediaPosition_VTable =
2684 {
2685     MediaPosition_QueryInterface,
2686     MediaPosition_AddRef,
2687     MediaPosition_Release,
2688     MediaPosition_GetTypeInfoCount,
2689     MediaPosition_GetTypeInfo,
2690     MediaPosition_GetIDsOfNames,
2691     MediaPosition_Invoke,
2692     MediaPosition_get_Duration,
2693     MediaPosition_put_CurrentPosition,
2694     MediaPosition_get_CurrentPosition,
2695     MediaPosition_get_StopTime,
2696     MediaPosition_put_StopTime,
2697     MediaPosition_get_PrerollTime,
2698     MediaPosition_put_PrerollTime,
2699     MediaPosition_put_Rate,
2700     MediaPosition_get_Rate,
2701     MediaPosition_CanSeekForward,
2702     MediaPosition_CanSeekBackward
2703 };
2704
2705 static HRESULT GetTargetInterface(IFilterGraphImpl* pGraph, REFIID riid, LPVOID* ppvObj)
2706 {
2707     HRESULT hr = E_NOINTERFACE;
2708     int i;
2709     int entry;
2710
2711     /* Check if the interface type is already registered */
2712     for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2713         if (riid == pGraph->ItfCacheEntries[entry].riid)
2714         {
2715             if (pGraph->ItfCacheEntries[entry].iface)
2716             {
2717                 /* Return the interface if available */
2718                 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2719                 return S_OK;
2720             }
2721             break;
2722         }
2723
2724     if (entry >= MAX_ITF_CACHE_ENTRIES)
2725     {
2726         FIXME("Not enough space to store interface in the cache\n");
2727         return E_OUTOFMEMORY;
2728     }
2729
2730     /* Find a filter supporting the requested interface */
2731     for (i = 0; i < pGraph->nFilters; i++)
2732     {
2733         hr = IBaseFilter_QueryInterface(pGraph->ppFiltersInGraph[i], riid, ppvObj);
2734         if (hr == S_OK)
2735         {
2736             pGraph->ItfCacheEntries[entry].riid = riid;
2737             pGraph->ItfCacheEntries[entry].filter = pGraph->ppFiltersInGraph[i];
2738             pGraph->ItfCacheEntries[entry].iface = *ppvObj;
2739             if (entry >= pGraph->nItfCacheEntries)
2740                 pGraph->nItfCacheEntries++;
2741             return S_OK;
2742         }
2743         if (hr != E_NOINTERFACE)
2744             return hr;
2745     }
2746
2747     return hr;
2748 }
2749
2750 /*** IUnknown methods ***/
2751 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface,
2752                                                 REFIID riid,
2753                                                 LPVOID*ppvObj) {
2754     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2755
2756     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2757
2758     return Filtergraph_QueryInterface(This, riid, ppvObj);
2759 }
2760
2761 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface) {
2762     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2763
2764     TRACE("(%p/%p)->()\n", This, iface);
2765
2766     return Filtergraph_AddRef(This);
2767 }
2768
2769 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface) {
2770     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2771
2772     TRACE("(%p/%p)->()\n", This, iface);
2773
2774     return Filtergraph_Release(This);
2775 }
2776
2777 /*** IDispatch methods ***/
2778 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface,
2779                                                   UINT*pctinfo) {
2780     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2781     IBasicAudio* pBasicAudio;
2782     HRESULT hr;
2783
2784     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
2785
2786     EnterCriticalSection(&This->cs);
2787
2788     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2789
2790     if (hr == S_OK)
2791         hr = IBasicAudio_GetTypeInfoCount(pBasicAudio, pctinfo);
2792
2793     LeaveCriticalSection(&This->cs);
2794
2795     return hr;
2796 }
2797
2798 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface,
2799                                              UINT iTInfo,
2800                                              LCID lcid,
2801                                              ITypeInfo**ppTInfo) {
2802     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2803     IBasicAudio* pBasicAudio;
2804     HRESULT hr;
2805
2806     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
2807
2808     EnterCriticalSection(&This->cs);
2809
2810     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2811
2812     if (hr == S_OK)
2813         hr = IBasicAudio_GetTypeInfo(pBasicAudio, iTInfo, lcid, ppTInfo);
2814
2815     LeaveCriticalSection(&This->cs);
2816
2817     return hr;
2818 }
2819
2820 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface,
2821                                                REFIID riid,
2822                                                LPOLESTR*rgszNames,
2823                                                UINT cNames,
2824                                                LCID lcid,
2825                                                DISPID*rgDispId) {
2826     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2827     IBasicAudio* pBasicAudio;
2828     HRESULT hr;
2829
2830     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
2831
2832     EnterCriticalSection(&This->cs);
2833
2834     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2835
2836     if (hr == S_OK)
2837         hr = IBasicAudio_GetIDsOfNames(pBasicAudio, riid, rgszNames, cNames, lcid, rgDispId);
2838
2839     LeaveCriticalSection(&This->cs);
2840
2841     return hr;
2842 }
2843
2844 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface,
2845                                         DISPID dispIdMember,
2846                                         REFIID riid,
2847                                         LCID lcid,
2848                                         WORD wFlags,
2849                                         DISPPARAMS*pDispParams,
2850                                         VARIANT*pVarResult,
2851                                         EXCEPINFO*pExepInfo,
2852                                         UINT*puArgErr) {
2853     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2854     IBasicAudio* pBasicAudio;
2855     HRESULT hr;
2856
2857     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);
2858
2859     EnterCriticalSection(&This->cs);
2860
2861     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2862
2863     if (hr == S_OK)
2864         hr = IBasicAudio_Invoke(pBasicAudio, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2865
2866     LeaveCriticalSection(&This->cs);
2867
2868     return hr;
2869 }
2870
2871 /*** IBasicAudio methods ***/
2872 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface,
2873                                             LONG lVolume) {
2874     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2875     IBasicAudio* pBasicAudio;
2876     HRESULT hr;
2877
2878     TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
2879
2880     EnterCriticalSection(&This->cs);
2881
2882     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2883
2884     if (hr == S_OK)
2885         hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
2886
2887     LeaveCriticalSection(&This->cs);
2888
2889     return hr;
2890 }
2891
2892 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface,
2893                                             LONG *plVolume) {
2894     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2895     IBasicAudio* pBasicAudio;
2896     HRESULT hr;
2897
2898     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
2899
2900     EnterCriticalSection(&This->cs);
2901
2902     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2903
2904     if (hr == S_OK)
2905         hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
2906
2907     LeaveCriticalSection(&This->cs);
2908
2909     return hr;
2910 }
2911
2912 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface,
2913                                              LONG lBalance) {
2914     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2915     IBasicAudio* pBasicAudio;
2916     HRESULT hr;
2917
2918     TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
2919
2920     EnterCriticalSection(&This->cs);
2921
2922     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2923
2924     if (hr == S_OK)
2925         hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
2926
2927     LeaveCriticalSection(&This->cs);
2928
2929     return hr;
2930 }
2931
2932 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface,
2933                                              LONG *plBalance) {
2934     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2935     IBasicAudio* pBasicAudio;
2936     HRESULT hr;
2937
2938     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
2939
2940     EnterCriticalSection(&This->cs);
2941
2942     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2943
2944     if (hr == S_OK)
2945         hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
2946
2947     LeaveCriticalSection(&This->cs);
2948
2949     return hr;
2950 }
2951
2952 static const IBasicAudioVtbl IBasicAudio_VTable =
2953 {
2954     BasicAudio_QueryInterface,
2955     BasicAudio_AddRef,
2956     BasicAudio_Release,
2957     BasicAudio_GetTypeInfoCount,
2958     BasicAudio_GetTypeInfo,
2959     BasicAudio_GetIDsOfNames,
2960     BasicAudio_Invoke,
2961     BasicAudio_put_Volume,
2962     BasicAudio_get_Volume,
2963     BasicAudio_put_Balance,
2964     BasicAudio_get_Balance
2965 };
2966
2967 /*** IUnknown methods ***/
2968 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface,
2969                                                 REFIID riid,
2970                                                 LPVOID*ppvObj) {
2971     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2972
2973     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2974
2975     return Filtergraph_QueryInterface(This, riid, ppvObj);
2976 }
2977
2978 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface) {
2979     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2980
2981     TRACE("(%p/%p)->()\n", This, iface);
2982
2983     return Filtergraph_AddRef(This);
2984 }
2985
2986 static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface) {
2987     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2988
2989     TRACE("(%p/%p)->()\n", This, iface);
2990
2991     return Filtergraph_Release(This);
2992 }
2993
2994 /*** IDispatch methods ***/
2995 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface,
2996                                                   UINT*pctinfo) {
2997     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2998     IBasicVideo* pBasicVideo;
2999     HRESULT hr;
3000
3001     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3002
3003     EnterCriticalSection(&This->cs);
3004
3005     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3006
3007     if (hr == S_OK)
3008         hr = IBasicVideo_GetTypeInfoCount(pBasicVideo, pctinfo);
3009
3010     LeaveCriticalSection(&This->cs);
3011
3012     return hr;
3013 }
3014
3015 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface,
3016                                              UINT iTInfo,
3017                                              LCID lcid,
3018                                              ITypeInfo**ppTInfo) {
3019     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3020     IBasicVideo* pBasicVideo;
3021     HRESULT hr;
3022
3023     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3024
3025     EnterCriticalSection(&This->cs);
3026
3027     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3028
3029     if (hr == S_OK)
3030         hr = IBasicVideo_GetTypeInfo(pBasicVideo, iTInfo, lcid, ppTInfo);
3031
3032     LeaveCriticalSection(&This->cs);
3033
3034     return hr;
3035 }
3036
3037 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface,
3038                                                REFIID riid,
3039                                                LPOLESTR*rgszNames,
3040                                                UINT cNames,
3041                                                LCID lcid,
3042                                                DISPID*rgDispId) {
3043     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3044     IBasicVideo* pBasicVideo;
3045     HRESULT hr;
3046
3047     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3048
3049     EnterCriticalSection(&This->cs);
3050
3051     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3052
3053     if (hr == S_OK)
3054         hr = IBasicVideo_GetIDsOfNames(pBasicVideo, riid, rgszNames, cNames, lcid, rgDispId);
3055
3056     LeaveCriticalSection(&This->cs);
3057
3058     return hr;
3059 }
3060
3061 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface,
3062                                         DISPID dispIdMember,
3063                                         REFIID riid,
3064                                         LCID lcid,
3065                                         WORD wFlags,
3066                                         DISPPARAMS*pDispParams,
3067                                         VARIANT*pVarResult,
3068                                         EXCEPINFO*pExepInfo,
3069                                         UINT*puArgErr) {
3070     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3071     IBasicVideo* pBasicVideo;
3072     HRESULT hr;
3073
3074     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);
3075
3076     EnterCriticalSection(&This->cs);
3077
3078     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3079
3080     if (hr == S_OK)
3081         hr = IBasicVideo_Invoke(pBasicVideo, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3082
3083     LeaveCriticalSection(&This->cs);
3084
3085     return hr;
3086 }
3087
3088 /*** IBasicVideo methods ***/
3089 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface,
3090                                                      REFTIME *pAvgTimePerFrame) {
3091     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3092     IBasicVideo* pBasicVideo;
3093     HRESULT hr;
3094
3095     TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
3096
3097     EnterCriticalSection(&This->cs);
3098
3099     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3100
3101     if (hr == S_OK)
3102         hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3103
3104     LeaveCriticalSection(&This->cs);
3105
3106     return hr;
3107 }
3108
3109 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface,
3110                                              LONG *pBitRate) {
3111     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3112     IBasicVideo* pBasicVideo;
3113     HRESULT hr;
3114
3115     TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
3116
3117     EnterCriticalSection(&This->cs);
3118
3119     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3120
3121     if (hr == S_OK)
3122         hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3123
3124     LeaveCriticalSection(&This->cs);
3125
3126     return hr;
3127 }
3128
3129 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface,
3130                                                   LONG *pBitErrorRate) {
3131     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3132     IBasicVideo* pBasicVideo;
3133     HRESULT hr;
3134
3135     TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
3136
3137     EnterCriticalSection(&This->cs);
3138
3139     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3140
3141     if (hr == S_OK)
3142         hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3143
3144     LeaveCriticalSection(&This->cs);
3145
3146     return hr;
3147 }
3148
3149 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface,
3150                                                 LONG *pVideoWidth) {
3151     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3152     IBasicVideo* pBasicVideo;
3153     HRESULT hr;
3154
3155     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
3156
3157     EnterCriticalSection(&This->cs);
3158
3159     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3160
3161     if (hr == S_OK)
3162         hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3163
3164     LeaveCriticalSection(&This->cs);
3165
3166     return hr;
3167 }
3168
3169 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface,
3170                                                  LONG *pVideoHeight) {
3171     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3172     IBasicVideo* pBasicVideo;
3173     HRESULT hr;
3174
3175     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
3176
3177     EnterCriticalSection(&This->cs);
3178
3179     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3180
3181     if (hr == S_OK)
3182         hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3183
3184     LeaveCriticalSection(&This->cs);
3185
3186     return hr;
3187 }
3188
3189 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface,
3190                                                 LONG SourceLeft) {
3191     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3192     IBasicVideo* pBasicVideo;
3193     HRESULT hr;
3194
3195     TRACE("(%p/%p)->(%d)\n", This, iface, SourceLeft);
3196
3197     EnterCriticalSection(&This->cs);
3198
3199     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3200
3201     if (hr == S_OK)
3202         hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3203
3204     LeaveCriticalSection(&This->cs);
3205
3206     return hr;
3207 }
3208
3209 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface,
3210                                                 LONG *pSourceLeft) {
3211     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3212     IBasicVideo* pBasicVideo;
3213     HRESULT hr;
3214
3215     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
3216
3217     EnterCriticalSection(&This->cs);
3218
3219     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3220
3221     if (hr == S_OK)
3222         hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3223
3224     LeaveCriticalSection(&This->cs);
3225
3226     return hr;
3227 }
3228
3229 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface,
3230                                                  LONG SourceWidth) {
3231     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3232     IBasicVideo* pBasicVideo;
3233     HRESULT hr;
3234
3235     TRACE("(%p/%p)->(%d)\n", This, iface, SourceWidth);
3236
3237     EnterCriticalSection(&This->cs);
3238
3239     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3240
3241     if (hr == S_OK)
3242         hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3243
3244     LeaveCriticalSection(&This->cs);
3245
3246     return hr;
3247 }
3248
3249 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface,
3250                                                  LONG *pSourceWidth) {
3251     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3252     IBasicVideo* pBasicVideo;
3253     HRESULT hr;
3254
3255     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
3256
3257     EnterCriticalSection(&This->cs);
3258
3259     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3260
3261     if (hr == S_OK)
3262         hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3263
3264     LeaveCriticalSection(&This->cs);
3265
3266     return hr;
3267 }
3268
3269 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface,
3270                                                LONG SourceTop) {
3271     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3272     IBasicVideo* pBasicVideo;
3273     HRESULT hr;
3274
3275     TRACE("(%p/%p)->(%d)\n", This, iface, SourceTop);
3276
3277     EnterCriticalSection(&This->cs);
3278
3279     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3280
3281     if (hr == S_OK)
3282         hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3283
3284     LeaveCriticalSection(&This->cs);
3285
3286     return hr;
3287 }
3288
3289 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface,
3290                                                LONG *pSourceTop) {
3291     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3292     IBasicVideo* pBasicVideo;
3293     HRESULT hr;
3294
3295     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
3296
3297     EnterCriticalSection(&This->cs);
3298
3299     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3300
3301     if (hr == S_OK)
3302         hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3303
3304     LeaveCriticalSection(&This->cs);
3305
3306     return hr;
3307 }
3308
3309 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface,
3310                                                   LONG SourceHeight) {
3311     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3312     IBasicVideo* pBasicVideo;
3313     HRESULT hr;
3314
3315     TRACE("(%p/%p)->(%d)\n", This, iface, SourceHeight);
3316
3317     EnterCriticalSection(&This->cs);
3318
3319     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3320
3321     if (hr == S_OK)
3322         hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3323
3324     LeaveCriticalSection(&This->cs);
3325
3326     return hr;
3327 }
3328
3329 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface,
3330                                                   LONG *pSourceHeight) {
3331     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3332     IBasicVideo* pBasicVideo;
3333     HRESULT hr;
3334
3335     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
3336
3337     EnterCriticalSection(&This->cs);
3338
3339     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3340
3341     if (hr == S_OK)
3342         hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3343
3344     LeaveCriticalSection(&This->cs);
3345
3346     return hr;
3347 }
3348
3349 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface,
3350                                                      LONG DestinationLeft) {
3351     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3352     IBasicVideo* pBasicVideo;
3353     HRESULT hr;
3354
3355     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationLeft);
3356
3357     EnterCriticalSection(&This->cs);
3358
3359     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3360
3361     if (hr == S_OK)
3362         hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3363
3364     LeaveCriticalSection(&This->cs);
3365
3366     return hr;
3367 }
3368
3369 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface,
3370                                                      LONG *pDestinationLeft) {
3371     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3372     IBasicVideo* pBasicVideo;
3373     HRESULT hr;
3374
3375     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
3376
3377     EnterCriticalSection(&This->cs);
3378
3379     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3380
3381     if (hr == S_OK)
3382         hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3383
3384     LeaveCriticalSection(&This->cs);
3385
3386     return hr;
3387 }
3388
3389 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface,
3390                                                       LONG DestinationWidth) {
3391     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3392     IBasicVideo* pBasicVideo;
3393     HRESULT hr;
3394
3395     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationWidth);
3396
3397     EnterCriticalSection(&This->cs);
3398
3399     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3400
3401     if (hr == S_OK)
3402         hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3403
3404     LeaveCriticalSection(&This->cs);
3405
3406     return hr;
3407 }
3408
3409 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface,
3410                                                       LONG *pDestinationWidth) {
3411     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3412     IBasicVideo* pBasicVideo;
3413     HRESULT hr;
3414
3415     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
3416
3417     EnterCriticalSection(&This->cs);
3418
3419     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3420
3421     if (hr == S_OK)
3422         hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3423
3424     LeaveCriticalSection(&This->cs);
3425
3426     return hr;
3427 }
3428
3429 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface,
3430                                                     LONG DestinationTop) {
3431     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3432     IBasicVideo* pBasicVideo;
3433     HRESULT hr;
3434
3435     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationTop);
3436
3437     EnterCriticalSection(&This->cs);
3438
3439     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3440
3441     if (hr == S_OK)
3442         hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3443
3444     LeaveCriticalSection(&This->cs);
3445
3446     return hr;
3447 }
3448
3449 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface,
3450                                                     LONG *pDestinationTop) {
3451     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3452     IBasicVideo* pBasicVideo;
3453     HRESULT hr;
3454
3455     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
3456
3457     EnterCriticalSection(&This->cs);
3458
3459     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3460
3461     if (hr == S_OK)
3462         hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3463
3464     LeaveCriticalSection(&This->cs);
3465
3466     return hr;
3467 }
3468
3469 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface,
3470                                                        LONG DestinationHeight) {
3471     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3472     IBasicVideo* pBasicVideo;
3473     HRESULT hr;
3474
3475     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationHeight);
3476
3477     EnterCriticalSection(&This->cs);
3478
3479     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3480
3481     if (hr == S_OK)
3482         hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3483
3484     LeaveCriticalSection(&This->cs);
3485
3486     return hr;
3487 }
3488
3489 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo2 *iface,
3490                                                        LONG *pDestinationHeight) {
3491     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3492     IBasicVideo* pBasicVideo;
3493     HRESULT hr;
3494
3495     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
3496
3497     EnterCriticalSection(&This->cs);
3498
3499     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3500
3501     if (hr == S_OK)
3502         hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3503
3504     LeaveCriticalSection(&This->cs);
3505
3506     return hr;
3507 }
3508
3509 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface,
3510                                                    LONG Left,
3511                                                    LONG Top,
3512                                                    LONG Width,
3513                                                    LONG Height) {
3514     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3515     IBasicVideo* pBasicVideo;
3516     HRESULT hr;
3517
3518     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3519
3520     EnterCriticalSection(&This->cs);
3521
3522     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3523
3524     if (hr == S_OK)
3525         hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
3526
3527     LeaveCriticalSection(&This->cs);
3528
3529     return hr;
3530 }
3531
3532 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface,
3533                                                    LONG *pLeft,
3534                                                    LONG *pTop,
3535                                                    LONG *pWidth,
3536                                                    LONG *pHeight) {
3537     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3538     IBasicVideo* pBasicVideo;
3539     HRESULT hr;
3540
3541     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3542
3543     EnterCriticalSection(&This->cs);
3544
3545     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3546
3547     if (hr == S_OK)
3548         hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3549
3550     LeaveCriticalSection(&This->cs);
3551
3552     return hr;
3553 }
3554
3555 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo2 *iface) {
3556     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3557     IBasicVideo* pBasicVideo;
3558     HRESULT hr;
3559
3560     TRACE("(%p/%p)->()\n", This, iface);
3561
3562     EnterCriticalSection(&This->cs);
3563
3564     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3565
3566     if (hr == S_OK)
3567         hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3568
3569     LeaveCriticalSection(&This->cs);
3570
3571     return hr;
3572 }
3573
3574 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface,
3575                                                         LONG Left,
3576                                                         LONG Top,
3577                                                         LONG Width,
3578                                                         LONG Height) {
3579     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3580     IBasicVideo* pBasicVideo;
3581     HRESULT hr;
3582
3583     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3584
3585     EnterCriticalSection(&This->cs);
3586
3587     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3588
3589     if (hr == S_OK)
3590         hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
3591
3592     LeaveCriticalSection(&This->cs);
3593
3594     return hr;
3595 }
3596
3597 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface,
3598                                                         LONG *pLeft,
3599                                                         LONG *pTop,
3600                                                         LONG *pWidth,
3601                                                         LONG *pHeight) {
3602     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3603     IBasicVideo* pBasicVideo;
3604     HRESULT hr;
3605
3606     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3607
3608     EnterCriticalSection(&This->cs);
3609
3610     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3611
3612     if (hr == S_OK)
3613         hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3614
3615     LeaveCriticalSection(&This->cs);
3616
3617     return hr;
3618 }
3619
3620 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo2 *iface) {
3621     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3622     IBasicVideo* pBasicVideo;
3623     HRESULT hr;
3624
3625     TRACE("(%p/%p)->()\n", This, iface);
3626
3627     EnterCriticalSection(&This->cs);
3628
3629     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3630
3631     if (hr == S_OK)
3632         hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3633
3634     LeaveCriticalSection(&This->cs);
3635
3636     return hr;
3637 }
3638
3639 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface,
3640                                               LONG *pWidth,
3641                                               LONG *pHeight) {
3642     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3643     IBasicVideo* pBasicVideo;
3644     HRESULT hr;
3645
3646     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3647
3648     EnterCriticalSection(&This->cs);
3649
3650     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3651
3652     if (hr == S_OK)
3653         hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3654
3655     LeaveCriticalSection(&This->cs);
3656
3657     return hr;
3658 }
3659
3660 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface,
3661                                                         LONG StartIndex,
3662                                                         LONG Entries,
3663                                                         LONG *pRetrieved,
3664                                                         LONG *pPalette) {
3665     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3666     IBasicVideo* pBasicVideo;
3667     HRESULT hr;
3668
3669     TRACE("(%p/%p)->(%d, %d, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
3670
3671     EnterCriticalSection(&This->cs);
3672
3673     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3674
3675     if (hr == S_OK)
3676         hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
3677
3678     LeaveCriticalSection(&This->cs);
3679
3680     return hr;
3681 }
3682
3683 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo2 *iface,
3684                                                  LONG *pBufferSize,
3685                                                  LONG *pDIBImage) {
3686     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3687     IBasicVideo* pBasicVideo;
3688     HRESULT hr;
3689
3690     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
3691
3692     EnterCriticalSection(&This->cs);
3693
3694     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3695
3696     if (hr == S_OK)
3697         hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3698
3699     LeaveCriticalSection(&This->cs);
3700
3701     return hr;
3702 }
3703
3704 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo2 *iface) {
3705     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3706     IBasicVideo* pBasicVideo;
3707     HRESULT hr;
3708
3709     TRACE("(%p/%p)->()\n", This, iface);
3710
3711     EnterCriticalSection(&This->cs);
3712
3713     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3714
3715     if (hr == S_OK)
3716         hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3717
3718     LeaveCriticalSection(&This->cs);
3719
3720     return hr;
3721 }
3722
3723 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo2 *iface) {
3724     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3725     IBasicVideo* pBasicVideo;
3726     HRESULT hr;
3727
3728     TRACE("(%p/%p)->()\n", This, iface);
3729
3730     EnterCriticalSection(&This->cs);
3731
3732     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3733
3734     if (hr == S_OK)
3735         hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3736
3737     LeaveCriticalSection(&This->cs);
3738
3739     return hr;
3740 }
3741
3742 static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX, LONG *plAspectY) {
3743     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3744     IBasicVideo2 *pBasicVideo2;
3745     HRESULT hr;
3746
3747     TRACE("(%p/%p)->()\n", This, iface);
3748
3749     EnterCriticalSection(&This->cs);
3750
3751     hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
3752
3753     if (hr == S_OK)
3754         hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
3755
3756     LeaveCriticalSection(&This->cs);
3757
3758     return hr;
3759 }
3760
3761 static const IBasicVideo2Vtbl IBasicVideo_VTable =
3762 {
3763     BasicVideo_QueryInterface,
3764     BasicVideo_AddRef,
3765     BasicVideo_Release,
3766     BasicVideo_GetTypeInfoCount,
3767     BasicVideo_GetTypeInfo,
3768     BasicVideo_GetIDsOfNames,
3769     BasicVideo_Invoke,
3770     BasicVideo_get_AvgTimePerFrame,
3771     BasicVideo_get_BitRate,
3772     BasicVideo_get_BitErrorRate,
3773     BasicVideo_get_VideoWidth,
3774     BasicVideo_get_VideoHeight,
3775     BasicVideo_put_SourceLeft,
3776     BasicVideo_get_SourceLeft,
3777     BasicVideo_put_SourceWidth,
3778     BasicVideo_get_SourceWidth,
3779     BasicVideo_put_SourceTop,
3780     BasicVideo_get_SourceTop,
3781     BasicVideo_put_SourceHeight,
3782     BasicVideo_get_SourceHeight,
3783     BasicVideo_put_DestinationLeft,
3784     BasicVideo_get_DestinationLeft,
3785     BasicVideo_put_DestinationWidth,
3786     BasicVideo_get_DestinationWidth,
3787     BasicVideo_put_DestinationTop,
3788     BasicVideo_get_DestinationTop,
3789     BasicVideo_put_DestinationHeight,
3790     BasicVideo_get_DestinationHeight,
3791     BasicVideo_SetSourcePosition,
3792     BasicVideo_GetSourcePosition,
3793     BasicVideo_SetDefaultSourcePosition,
3794     BasicVideo_SetDestinationPosition,
3795     BasicVideo_GetDestinationPosition,
3796     BasicVideo_SetDefaultDestinationPosition,
3797     BasicVideo_GetVideoSize,
3798     BasicVideo_GetVideoPaletteEntries,
3799     BasicVideo_GetCurrentImage,
3800     BasicVideo_IsUsingDefaultSource,
3801     BasicVideo_IsUsingDefaultDestination,
3802     BasicVideo2_GetPreferredAspectRatio
3803 };
3804
3805
3806 /*** IUnknown methods ***/
3807 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface,
3808                                                  REFIID riid,
3809                                                  LPVOID*ppvObj) {
3810     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3811
3812     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
3813
3814     return Filtergraph_QueryInterface(This, riid, ppvObj);
3815 }
3816
3817 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface) {
3818     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3819
3820     TRACE("(%p/%p)->()\n", This, iface);
3821
3822     return Filtergraph_AddRef(This);
3823 }
3824
3825 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface) {
3826     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3827
3828     TRACE("(%p/%p)->()\n", This, iface);
3829
3830     return Filtergraph_Release(This);
3831 }
3832
3833 /*** IDispatch methods ***/
3834 static HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface,
3835                                                    UINT*pctinfo) {
3836     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3837     IVideoWindow* pVideoWindow;
3838     HRESULT hr;
3839
3840     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3841
3842     EnterCriticalSection(&This->cs);
3843
3844     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3845
3846     if (hr == S_OK)
3847         hr = IVideoWindow_GetTypeInfoCount(pVideoWindow, pctinfo);
3848
3849     LeaveCriticalSection(&This->cs);
3850
3851     return hr;
3852 }
3853
3854 static HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface,
3855                                               UINT iTInfo,
3856                                               LCID lcid,
3857                                               ITypeInfo**ppTInfo) {
3858     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3859     IVideoWindow* pVideoWindow;
3860     HRESULT hr;
3861
3862     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3863
3864     EnterCriticalSection(&This->cs);
3865
3866     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3867
3868     if (hr == S_OK)
3869         hr = IVideoWindow_GetTypeInfo(pVideoWindow, iTInfo, lcid, ppTInfo);
3870
3871     LeaveCriticalSection(&This->cs);
3872
3873     return hr;
3874 }
3875
3876 static HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface,
3877                                                 REFIID riid,
3878                                                 LPOLESTR*rgszNames,
3879                                                 UINT cNames,
3880                                                 LCID lcid,
3881                                                 DISPID*rgDispId) {
3882     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3883     IVideoWindow* pVideoWindow;
3884     HRESULT hr;
3885
3886     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3887
3888     EnterCriticalSection(&This->cs);
3889
3890     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3891
3892     if (hr == S_OK)
3893         hr = IVideoWindow_GetIDsOfNames(pVideoWindow, riid, rgszNames, cNames, lcid, rgDispId);
3894
3895     LeaveCriticalSection(&This->cs);
3896
3897     return hr;
3898 }
3899
3900 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface,
3901                                          DISPID dispIdMember,
3902                                          REFIID riid,
3903                                          LCID lcid,
3904                                          WORD wFlags,
3905                                          DISPPARAMS*pDispParams,
3906                                          VARIANT*pVarResult,
3907                                          EXCEPINFO*pExepInfo,
3908                                          UINT*puArgErr) {
3909     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3910     IVideoWindow* pVideoWindow;
3911     HRESULT hr;
3912
3913     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);
3914
3915     EnterCriticalSection(&This->cs);
3916
3917     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3918
3919     if (hr == S_OK)
3920         hr = IVideoWindow_Invoke(pVideoWindow, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3921
3922     LeaveCriticalSection(&This->cs);
3923
3924     return hr;
3925 }
3926
3927
3928 /*** IVideoWindow methods ***/
3929 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface,
3930                                               BSTR strCaption) {
3931     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3932     IVideoWindow* pVideoWindow;
3933     HRESULT hr;
3934     
3935     TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
3936
3937     EnterCriticalSection(&This->cs);
3938
3939     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3940
3941     if (hr == S_OK)
3942         hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
3943
3944     LeaveCriticalSection(&This->cs);
3945
3946     return hr;
3947 }
3948
3949 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface,
3950                                               BSTR *strCaption) {
3951     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3952     IVideoWindow* pVideoWindow;
3953     HRESULT hr;
3954
3955     TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
3956
3957     EnterCriticalSection(&This->cs);
3958
3959     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3960
3961     if (hr == S_OK)
3962         hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
3963
3964     LeaveCriticalSection(&This->cs);
3965
3966     return hr;
3967 }
3968
3969 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface,
3970                                                   LONG WindowStyle) {
3971     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3972     IVideoWindow* pVideoWindow;
3973     HRESULT hr;
3974
3975     TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyle);
3976
3977     EnterCriticalSection(&This->cs);
3978
3979     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3980
3981     if (hr == S_OK)
3982         hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
3983
3984     LeaveCriticalSection(&This->cs);
3985
3986     return hr;
3987 }
3988
3989 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface,
3990                                                   LONG *WindowStyle) {
3991     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3992     IVideoWindow* pVideoWindow;
3993     HRESULT hr;
3994
3995     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
3996
3997     EnterCriticalSection(&This->cs);
3998
3999     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4000
4001     if (hr == S_OK)
4002         hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
4003
4004     LeaveCriticalSection(&This->cs);
4005
4006     return hr;
4007 }
4008
4009 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface,
4010                                                     LONG WindowStyleEx) {
4011     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4012     IVideoWindow* pVideoWindow;
4013     HRESULT hr;
4014
4015     TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyleEx);
4016
4017     EnterCriticalSection(&This->cs);
4018
4019     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4020
4021     if (hr == S_OK)
4022         hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
4023
4024     LeaveCriticalSection(&This->cs);
4025
4026     return hr;
4027 }
4028
4029 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface,
4030                                                     LONG *WindowStyleEx) {
4031     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4032     IVideoWindow* pVideoWindow;
4033     HRESULT hr;
4034
4035     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
4036
4037     EnterCriticalSection(&This->cs);
4038
4039     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4040
4041     if (hr == S_OK)
4042         hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
4043
4044     LeaveCriticalSection(&This->cs);
4045
4046     return hr;
4047 }
4048
4049 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface,
4050                                                LONG AutoShow) {
4051     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4052     IVideoWindow* pVideoWindow;
4053     HRESULT hr;
4054
4055     TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow);
4056
4057     EnterCriticalSection(&This->cs);
4058
4059     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4060
4061     if (hr == S_OK)
4062         hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
4063
4064     LeaveCriticalSection(&This->cs);
4065
4066     return hr;
4067 }
4068
4069 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface,
4070                                                LONG *AutoShow) {
4071     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4072     IVideoWindow* pVideoWindow;
4073     HRESULT hr;
4074
4075     TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
4076
4077     EnterCriticalSection(&This->cs);
4078
4079     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4080
4081     if (hr == S_OK)
4082         hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
4083
4084     LeaveCriticalSection(&This->cs);
4085
4086     return hr;
4087 }
4088
4089 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface,
4090                                                   LONG WindowState) {
4091     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4092     IVideoWindow* pVideoWindow;
4093     HRESULT hr;
4094
4095     TRACE("(%p/%p)->(%d)\n", This, iface, WindowState);
4096
4097     EnterCriticalSection(&This->cs);
4098
4099     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4100
4101     if (hr == S_OK)
4102         hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
4103
4104     LeaveCriticalSection(&This->cs);
4105
4106     return hr;
4107 }
4108
4109 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface,
4110                                                   LONG *WindowState) {
4111     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4112     IVideoWindow* pVideoWindow;
4113     HRESULT hr;
4114
4115     TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
4116
4117     EnterCriticalSection(&This->cs);
4118
4119     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4120
4121     if (hr == S_OK)
4122         hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
4123
4124     LeaveCriticalSection(&This->cs);
4125
4126     return hr;
4127 }
4128
4129 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface,
4130                                                         LONG BackgroundPalette) {
4131     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4132     IVideoWindow* pVideoWindow;
4133     HRESULT hr;
4134
4135     TRACE("(%p/%p)->(%d)\n", This, iface, BackgroundPalette);
4136
4137     EnterCriticalSection(&This->cs);
4138
4139     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4140
4141     if (hr == S_OK)
4142         hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
4143
4144     LeaveCriticalSection(&This->cs);
4145
4146     return hr;
4147 }
4148
4149 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
4150                                                         LONG *pBackgroundPalette) {
4151     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4152     IVideoWindow* pVideoWindow;
4153     HRESULT hr;
4154
4155     TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
4156
4157     EnterCriticalSection(&This->cs);
4158
4159     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4160
4161     if (hr == S_OK)
4162         hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
4163
4164     LeaveCriticalSection(&This->cs);
4165
4166     return hr;
4167 }
4168
4169 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface,
4170                                               LONG Visible) {
4171     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4172     IVideoWindow* pVideoWindow;
4173     HRESULT hr;
4174
4175     TRACE("(%p/%p)->(%d)\n", This, iface, Visible);
4176
4177     EnterCriticalSection(&This->cs);
4178
4179     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4180
4181     if (hr == S_OK)
4182         hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
4183
4184     LeaveCriticalSection(&This->cs);
4185
4186     return hr;
4187 }
4188
4189 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface,
4190                                               LONG *pVisible) {
4191     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4192     IVideoWindow* pVideoWindow;
4193     HRESULT hr;
4194
4195     TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
4196
4197     EnterCriticalSection(&This->cs);
4198
4199     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4200
4201     if (hr == S_OK)
4202         hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
4203
4204     LeaveCriticalSection(&This->cs);
4205
4206     return hr;
4207 }
4208
4209 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface,
4210                                            LONG Left) {
4211     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4212     IVideoWindow* pVideoWindow;
4213     HRESULT hr;
4214
4215     TRACE("(%p/%p)->(%d)\n", This, iface, Left);
4216
4217     EnterCriticalSection(&This->cs);
4218
4219     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4220
4221     if (hr == S_OK)
4222         hr = IVideoWindow_put_Left(pVideoWindow, Left);
4223
4224     LeaveCriticalSection(&This->cs);
4225
4226     return hr;
4227 }
4228
4229 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface,
4230                                            LONG *pLeft) {
4231     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4232     IVideoWindow* pVideoWindow;
4233     HRESULT hr;
4234
4235     TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
4236
4237     EnterCriticalSection(&This->cs);
4238
4239     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4240
4241     if (hr == S_OK)
4242         hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
4243
4244     LeaveCriticalSection(&This->cs);
4245
4246     return hr;
4247 }
4248
4249 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface,
4250                                             LONG Width) {
4251     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4252     IVideoWindow* pVideoWindow;
4253     HRESULT hr;
4254
4255     TRACE("(%p/%p)->(%d)\n", This, iface, Width);
4256
4257     EnterCriticalSection(&This->cs);
4258
4259     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4260
4261     if (hr == S_OK)
4262         hr = IVideoWindow_put_Width(pVideoWindow, Width);
4263
4264     LeaveCriticalSection(&This->cs);
4265
4266     return hr;
4267 }
4268
4269 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface,
4270                                             LONG *pWidth) {
4271     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4272     IVideoWindow* pVideoWindow;
4273     HRESULT hr;
4274
4275     TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
4276
4277     EnterCriticalSection(&This->cs);
4278
4279     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4280
4281     if (hr == S_OK)
4282         hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
4283
4284     LeaveCriticalSection(&This->cs);
4285
4286     return hr;
4287 }
4288
4289 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface,
4290                                           LONG Top) {
4291     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4292     IVideoWindow* pVideoWindow;
4293     HRESULT hr;
4294
4295     TRACE("(%p/%p)->(%d)\n", This, iface, Top);
4296
4297     EnterCriticalSection(&This->cs);
4298
4299     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4300
4301     if (hr == S_OK)
4302         hr = IVideoWindow_put_Top(pVideoWindow, Top);
4303
4304     LeaveCriticalSection(&This->cs);
4305
4306     return hr;
4307 }
4308
4309 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface,
4310                                           LONG *pTop) {
4311     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4312     IVideoWindow* pVideoWindow;
4313     HRESULT hr;
4314
4315     TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
4316
4317     EnterCriticalSection(&This->cs);
4318
4319     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4320
4321     if (hr == S_OK)
4322         hr = IVideoWindow_get_Top(pVideoWindow, pTop);
4323
4324     LeaveCriticalSection(&This->cs);
4325
4326     return hr;
4327 }
4328
4329 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface,
4330                                              LONG Height) {
4331     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4332     IVideoWindow* pVideoWindow;
4333     HRESULT hr;
4334
4335     TRACE("(%p/%p)->(%d)\n", This, iface, Height);
4336
4337     EnterCriticalSection(&This->cs);
4338
4339     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4340
4341     if (hr == S_OK)
4342         hr = IVideoWindow_put_Height(pVideoWindow, Height);
4343
4344     LeaveCriticalSection(&This->cs);
4345
4346     return hr;
4347 }
4348
4349 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface,
4350                                              LONG *pHeight) {
4351     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4352     IVideoWindow* pVideoWindow;
4353     HRESULT hr;
4354
4355     TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
4356
4357     EnterCriticalSection(&This->cs);
4358
4359     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4360
4361     if (hr == S_OK)
4362         hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
4363
4364     LeaveCriticalSection(&This->cs);
4365
4366     return hr;
4367 }
4368
4369 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface,
4370                                             OAHWND Owner) {
4371     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4372     IVideoWindow* pVideoWindow;
4373     HRESULT hr;
4374
4375     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
4376
4377     EnterCriticalSection(&This->cs);
4378
4379     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4380
4381     if (hr == S_OK)
4382         hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
4383
4384     LeaveCriticalSection(&This->cs);
4385
4386     return hr;
4387 }
4388
4389 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface,
4390                                             OAHWND *Owner) {
4391     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4392     IVideoWindow* pVideoWindow;
4393     HRESULT hr;
4394
4395     TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
4396
4397     EnterCriticalSection(&This->cs);
4398
4399     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4400
4401     if (hr == S_OK)
4402         hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
4403
4404     LeaveCriticalSection(&This->cs);
4405
4406     return hr;
4407 }
4408
4409 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface,
4410                                                    OAHWND Drain) {
4411     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4412     IVideoWindow* pVideoWindow;
4413     HRESULT hr;
4414
4415     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
4416
4417     EnterCriticalSection(&This->cs);
4418
4419     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4420
4421     if (hr == S_OK)
4422         hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
4423
4424     LeaveCriticalSection(&This->cs);
4425
4426     return hr;
4427 }
4428
4429 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface,
4430                                                    OAHWND *Drain) {
4431     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4432     IVideoWindow* pVideoWindow;
4433     HRESULT hr;
4434
4435     TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
4436
4437     EnterCriticalSection(&This->cs);
4438
4439     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4440
4441     if (hr == S_OK)
4442         hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
4443
4444     LeaveCriticalSection(&This->cs);
4445
4446     return hr;
4447 }
4448
4449 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface,
4450                                                   LONG *Color) {
4451     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4452     IVideoWindow* pVideoWindow;
4453     HRESULT hr;
4454
4455     TRACE("(%p/%p)->(%p)\n", This, iface, Color);
4456
4457     EnterCriticalSection(&This->cs);
4458
4459     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4460
4461     if (hr == S_OK)
4462         hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
4463
4464     LeaveCriticalSection(&This->cs);
4465
4466     return hr;
4467 }
4468
4469 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface,
4470                                                   LONG Color) {
4471     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4472     IVideoWindow* pVideoWindow;
4473     HRESULT hr;
4474
4475     TRACE("(%p/%p)->(%d)\n", This, iface, Color);
4476
4477     EnterCriticalSection(&This->cs);
4478
4479     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4480
4481     if (hr == S_OK)
4482         hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
4483
4484     LeaveCriticalSection(&This->cs);
4485
4486     return hr;
4487 }
4488
4489 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface,
4490                                                      LONG *FullScreenMode) {
4491     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4492     IVideoWindow* pVideoWindow;
4493     HRESULT hr;
4494
4495     TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
4496
4497     EnterCriticalSection(&This->cs);
4498
4499     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4500
4501     if (hr == S_OK)
4502         hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
4503
4504     LeaveCriticalSection(&This->cs);
4505
4506     return hr;
4507 }
4508
4509 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface,
4510                                                      LONG FullScreenMode) {
4511     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4512     IVideoWindow* pVideoWindow;
4513     HRESULT hr;
4514
4515     TRACE("(%p/%p)->(%d)\n", This, iface, FullScreenMode);
4516
4517     EnterCriticalSection(&This->cs);
4518
4519     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4520
4521     if (hr == S_OK)
4522         hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
4523
4524     LeaveCriticalSection(&This->cs);
4525
4526     return hr;
4527 }
4528
4529 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface,
4530                                                       LONG Focus) {
4531     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4532     IVideoWindow* pVideoWindow;
4533     HRESULT hr;
4534
4535     TRACE("(%p/%p)->(%d)\n", This, iface, Focus);
4536
4537     EnterCriticalSection(&This->cs);
4538
4539     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4540
4541     if (hr == S_OK)
4542         hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
4543
4544     LeaveCriticalSection(&This->cs);
4545
4546     return hr;
4547 }
4548
4549 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface,
4550                                                      OAHWND hwnd,
4551                                                      LONG uMsg,
4552                                                      LONG_PTR wParam,
4553                                                      LONG_PTR lParam) {
4554     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4555     IVideoWindow* pVideoWindow;
4556     HRESULT hr;
4557
4558     TRACE("(%p/%p)->(%08lx, %d, %08lx, %08lx)\n", This, iface, hwnd, uMsg, wParam, lParam);
4559
4560     EnterCriticalSection(&This->cs);
4561
4562     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4563
4564     if (hr == S_OK)
4565         hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
4566
4567     LeaveCriticalSection(&This->cs);
4568
4569     return hr;
4570 }
4571
4572 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface,
4573                                                     LONG Left,
4574                                                     LONG Top,
4575                                                     LONG Width,
4576                                                     LONG Height) {
4577     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4578     IVideoWindow* pVideoWindow;
4579     HRESULT hr;
4580
4581     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
4582
4583     EnterCriticalSection(&This->cs);
4584
4585     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4586
4587     if (hr == S_OK)
4588         hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
4589
4590     LeaveCriticalSection(&This->cs);
4591
4592     return hr;
4593 }
4594
4595 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface,
4596                                                     LONG *pLeft,
4597                                                     LONG *pTop,
4598                                                     LONG *pWidth,
4599                                                     LONG *pHeight) {
4600     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4601     IVideoWindow* pVideoWindow;
4602     HRESULT hr;
4603
4604     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4605
4606     EnterCriticalSection(&This->cs);
4607
4608     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4609
4610     if (hr == S_OK)
4611         hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4612
4613     LeaveCriticalSection(&This->cs);
4614
4615     return hr;
4616 }
4617
4618 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface,
4619                                                        LONG *pWidth,
4620                                                        LONG *pHeight) {
4621     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4622     IVideoWindow* pVideoWindow;
4623     HRESULT hr;
4624
4625     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4626
4627     EnterCriticalSection(&This->cs);
4628
4629     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4630
4631     if (hr == S_OK)
4632         hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
4633
4634     LeaveCriticalSection(&This->cs);
4635
4636     return hr;
4637 }
4638
4639 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface,
4640                                                        LONG *pWidth,
4641                                                        LONG *pHeight) {
4642     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4643     IVideoWindow* pVideoWindow;
4644     HRESULT hr;
4645
4646     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4647
4648     EnterCriticalSection(&This->cs);
4649
4650     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4651
4652     if (hr == S_OK)
4653         hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
4654
4655     LeaveCriticalSection(&This->cs);
4656
4657     return hr;
4658 }
4659
4660 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface,
4661                                                      LONG *pLeft,
4662                                                      LONG *pTop,
4663                                                      LONG *pWidth,
4664                                                      LONG *pHeight) {
4665     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4666     IVideoWindow* pVideoWindow;
4667     HRESULT hr;
4668
4669     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4670
4671     EnterCriticalSection(&This->cs);
4672
4673     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4674
4675     if (hr == S_OK)
4676         hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4677
4678     LeaveCriticalSection(&This->cs);
4679
4680     return hr;
4681 }
4682
4683 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface,
4684                                              LONG HideCursor) {
4685     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4686     IVideoWindow* pVideoWindow;
4687     HRESULT hr;
4688
4689     TRACE("(%p/%p)->(%d)\n", This, iface, HideCursor);
4690
4691     EnterCriticalSection(&This->cs);
4692
4693     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4694
4695     if (hr == S_OK)
4696         hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
4697
4698     LeaveCriticalSection(&This->cs);
4699
4700     return hr;
4701 }
4702
4703 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface,
4704                                                  LONG *CursorHidden) {
4705     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4706     IVideoWindow* pVideoWindow;
4707     HRESULT hr;
4708
4709     TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
4710
4711     EnterCriticalSection(&This->cs);
4712
4713     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4714
4715     if (hr == S_OK)
4716         hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
4717
4718     LeaveCriticalSection(&This->cs);
4719
4720     return hr;
4721 }
4722
4723
4724 static const IVideoWindowVtbl IVideoWindow_VTable =
4725 {
4726     VideoWindow_QueryInterface,
4727     VideoWindow_AddRef,
4728     VideoWindow_Release,
4729     VideoWindow_GetTypeInfoCount,
4730     VideoWindow_GetTypeInfo,
4731     VideoWindow_GetIDsOfNames,
4732     VideoWindow_Invoke,
4733     VideoWindow_put_Caption,
4734     VideoWindow_get_Caption,
4735     VideoWindow_put_WindowStyle,
4736     VideoWindow_get_WindowStyle,
4737     VideoWindow_put_WindowStyleEx,
4738     VideoWindow_get_WindowStyleEx,
4739     VideoWindow_put_AutoShow,
4740     VideoWindow_get_AutoShow,
4741     VideoWindow_put_WindowState,
4742     VideoWindow_get_WindowState,
4743     VideoWindow_put_BackgroundPalette,
4744     VideoWindow_get_BackgroundPalette,
4745     VideoWindow_put_Visible,
4746     VideoWindow_get_Visible,
4747     VideoWindow_put_Left,
4748     VideoWindow_get_Left,
4749     VideoWindow_put_Width,
4750     VideoWindow_get_Width,
4751     VideoWindow_put_Top,
4752     VideoWindow_get_Top,
4753     VideoWindow_put_Height,
4754     VideoWindow_get_Height,
4755     VideoWindow_put_Owner,
4756     VideoWindow_get_Owner,
4757     VideoWindow_put_MessageDrain,
4758     VideoWindow_get_MessageDrain,
4759     VideoWindow_get_BorderColor,
4760     VideoWindow_put_BorderColor,
4761     VideoWindow_get_FullScreenMode,
4762     VideoWindow_put_FullScreenMode,
4763     VideoWindow_SetWindowForeground,
4764     VideoWindow_NotifyOwnerMessage,
4765     VideoWindow_SetWindowPosition,
4766     VideoWindow_GetWindowPosition,
4767     VideoWindow_GetMinIdealImageSize,
4768     VideoWindow_GetMaxIdealImageSize,
4769     VideoWindow_GetRestorePosition,
4770     VideoWindow_HideCursor,
4771     VideoWindow_IsCursorHidden
4772 };
4773
4774
4775 /*** IUnknown methods ***/
4776 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface,
4777                                                 REFIID riid,
4778                                                 LPVOID*ppvObj) {
4779     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4780
4781     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
4782
4783     return Filtergraph_QueryInterface(This, riid, ppvObj);
4784 }
4785
4786 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface) {
4787     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4788
4789     TRACE("(%p/%p)->()\n", This, iface);
4790
4791     return Filtergraph_AddRef(This);
4792 }
4793
4794 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface) {
4795     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4796
4797     TRACE("(%p/%p)->()\n", This, iface);
4798
4799     return Filtergraph_Release(This);
4800 }
4801
4802 /*** IDispatch methods ***/
4803 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface,
4804                                                   UINT*pctinfo) {
4805     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4806
4807     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
4808
4809     return S_OK;
4810 }
4811
4812 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface,
4813                                              UINT iTInfo,
4814                                              LCID lcid,
4815                                              ITypeInfo**ppTInfo) {
4816     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4817
4818     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
4819
4820     return S_OK;
4821 }
4822
4823 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface,
4824                                                REFIID riid,
4825                                                LPOLESTR*rgszNames,
4826                                                UINT cNames,
4827                                                LCID lcid,
4828                                                DISPID*rgDispId) {
4829     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4830
4831     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
4832
4833     return S_OK;
4834 }
4835
4836 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface,
4837                                         DISPID dispIdMember,
4838                                         REFIID riid,
4839                                         LCID lcid,
4840                                         WORD wFlags,
4841                                         DISPPARAMS*pDispParams,
4842                                         VARIANT*pVarResult,
4843                                         EXCEPINFO*pExepInfo,
4844                                         UINT*puArgErr) {
4845     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4846
4847     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);
4848
4849     return S_OK;
4850 }
4851
4852 /*** IMediaEvent methods ***/
4853 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface,
4854                                                 OAEVENT *hEvent) {
4855     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4856
4857     TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
4858
4859     *hEvent = (OAEVENT)This->evqueue.msg_event;
4860
4861     return S_OK;
4862 }
4863
4864 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface,
4865                                           LONG *lEventCode,
4866                                           LONG_PTR *lParam1,
4867                                           LONG_PTR *lParam2,
4868                                           LONG msTimeout) {
4869     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4870     Event evt;
4871
4872     TRACE("(%p/%p)->(%p, %p, %p, %d)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
4873
4874     if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
4875     {
4876         *lEventCode = evt.lEventCode;
4877         *lParam1 = evt.lParam1;
4878         *lParam2 = evt.lParam2;
4879         return S_OK;
4880     }
4881
4882     *lEventCode = 0;
4883     return E_ABORT;
4884 }
4885
4886 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface,
4887                                                    LONG msTimeout,
4888                                                    LONG *pEvCode) {
4889     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4890
4891     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pEvCode);
4892
4893     if (This->state != State_Running)
4894         return VFW_E_WRONG_STATE;
4895
4896     if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
4897     {
4898         *pEvCode = This->CompletionStatus;
4899         return S_OK;
4900     }
4901
4902     *pEvCode = 0;
4903     return E_ABORT;
4904 }
4905
4906 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface,
4907                                                        LONG lEvCode) {
4908     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4909
4910     TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
4911
4912     if (lEvCode == EC_COMPLETE)
4913         This->HandleEcComplete = FALSE;
4914     else if (lEvCode == EC_REPAINT)
4915         This->HandleEcRepaint = FALSE;
4916     else if (lEvCode == EC_CLOCK_CHANGED)
4917         This->HandleEcClockChanged = FALSE;
4918     else
4919         return S_FALSE;
4920
4921     return S_OK;
4922 }
4923
4924 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface,
4925                                                         LONG lEvCode) {
4926     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4927
4928     TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
4929
4930     if (lEvCode == EC_COMPLETE)
4931         This->HandleEcComplete = TRUE;
4932     else if (lEvCode == EC_REPAINT)
4933         This->HandleEcRepaint = TRUE;
4934     else if (lEvCode == EC_CLOCK_CHANGED)
4935         This->HandleEcClockChanged = TRUE;
4936     else
4937         return S_FALSE;
4938
4939     return S_OK;
4940 }
4941
4942 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface,
4943                                                  LONG lEvCode,
4944                                                  LONG_PTR lParam1,
4945                                                  LONG_PTR lParam2) {
4946     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4947
4948     TRACE("(%p/%p)->(%d, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
4949
4950     return S_OK;
4951 }
4952
4953 /*** IMediaEventEx methods ***/
4954 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface,
4955                                                  OAHWND hwnd,
4956                                                  LONG lMsg,
4957                                                  LONG_PTR lInstanceData) {
4958     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4959
4960     TRACE("(%p/%p)->(%08lx, %d, %08lx)\n", This, iface, hwnd, lMsg, lInstanceData);
4961
4962     This->notif.hWnd = (HWND)hwnd;
4963     This->notif.msg = lMsg;
4964     This->notif.instance = lInstanceData;
4965
4966     return S_OK;
4967 }
4968
4969 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface,
4970                                                 LONG lNoNotifyFlags) {
4971     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4972
4973     TRACE("(%p/%p)->(%d)\n", This, iface, lNoNotifyFlags);
4974
4975     if ((lNoNotifyFlags != 0) && (lNoNotifyFlags != 1))
4976         return E_INVALIDARG;
4977
4978     This->notif.disabled = lNoNotifyFlags;
4979
4980     return S_OK;
4981 }
4982
4983 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface,
4984                                                 LONG *lplNoNotifyFlags) {
4985     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4986
4987     TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
4988
4989     if (!lplNoNotifyFlags)
4990         return E_POINTER;
4991
4992     *lplNoNotifyFlags = This->notif.disabled;
4993
4994     return S_OK;
4995 }
4996
4997
4998 static const IMediaEventExVtbl IMediaEventEx_VTable =
4999 {
5000     MediaEvent_QueryInterface,
5001     MediaEvent_AddRef,
5002     MediaEvent_Release,
5003     MediaEvent_GetTypeInfoCount,
5004     MediaEvent_GetTypeInfo,
5005     MediaEvent_GetIDsOfNames,
5006     MediaEvent_Invoke,
5007     MediaEvent_GetEventHandle,
5008     MediaEvent_GetEvent,
5009     MediaEvent_WaitForCompletion,
5010     MediaEvent_CancelDefaultHandling,
5011     MediaEvent_RestoreDefaultHandling,
5012     MediaEvent_FreeEventParams,
5013     MediaEvent_SetNotifyWindow,
5014     MediaEvent_SetNotifyFlags,
5015     MediaEvent_GetNotifyFlags
5016 };
5017
5018
5019 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID riid, LPVOID *ppv)
5020 {
5021     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5022
5023     return Filtergraph_QueryInterface(This, riid, ppv);
5024 }
5025
5026 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
5027 {
5028     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5029
5030     return Filtergraph_AddRef(This);
5031 }
5032
5033 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
5034 {
5035     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5036
5037     return Filtergraph_Release(This);
5038 }
5039
5040 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
5041 {
5042     FIXME("(%p): stub\n", pClassID);
5043
5044     return E_NOTIMPL;
5045 }
5046
5047 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
5048 {
5049     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5050     return MediaControl_Stop((IMediaControl*)&This->IMediaControl_vtbl);
5051 }
5052
5053 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
5054 {
5055     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5056     return MediaControl_Pause((IMediaControl*)&This->IMediaControl_vtbl);
5057 }
5058
5059 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME tStart)
5060 {
5061     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5062     if (tStart)
5063         FIXME("Run called with non-null tStart: %x%08x\n",
5064               (int)(tStart>>32), (int)tStart);
5065     return MediaControl_Run((IMediaControl*)&This->IMediaControl_vtbl);
5066 }
5067
5068 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD dwMsTimeout, FILTER_STATE * pState)
5069 {
5070     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5071     return MediaControl_GetState((IMediaControl*)&This->IMediaControl_vtbl, dwMsTimeout, (OAFilterState*)pState);
5072 }
5073
5074 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
5075 {
5076     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5077     HRESULT hr = S_OK;
5078     int i;
5079
5080     TRACE("(%p/%p)->(%p)\n", iface, This, pClock);
5081
5082     EnterCriticalSection(&This->cs);
5083     {
5084         for (i = 0;i < This->nFilters;i++)
5085         {
5086             hr = IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], pClock);
5087             if (FAILED(hr))
5088                 break;
5089         }
5090
5091         if (FAILED(hr))
5092         {
5093             for(;i >= 0;i--)
5094                 IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], This->refClock);
5095         }
5096         else
5097         {
5098             if (This->refClock)
5099                 IReferenceClock_Release(This->refClock);
5100             This->refClock = pClock;
5101             if (This->refClock)
5102                 IReferenceClock_AddRef(This->refClock);
5103             This->defaultclock = FALSE;
5104
5105             if (This->HandleEcClockChanged)
5106             {
5107                 IMediaEventSink *pEventSink;
5108                 HRESULT eshr;
5109
5110                 eshr = IMediaFilter_QueryInterface(iface, &IID_IMediaEventSink, (LPVOID)&pEventSink);
5111                 if (SUCCEEDED(eshr))
5112                 {
5113                     IMediaEventSink_Notify(pEventSink, EC_CLOCK_CHANGED, 0, 0);
5114                     IMediaEventSink_Release(pEventSink);
5115                 }
5116             }
5117         }
5118     }
5119     LeaveCriticalSection(&This->cs);
5120
5121     return hr;
5122 }
5123
5124 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
5125 {
5126     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5127
5128     TRACE("(%p/%p)->(%p)\n", iface, This, ppClock);
5129
5130     if (!ppClock)
5131         return E_POINTER;
5132
5133     EnterCriticalSection(&This->cs);
5134     {
5135         *ppClock = This->refClock;
5136         if (*ppClock)
5137             IReferenceClock_AddRef(*ppClock);
5138     }
5139     LeaveCriticalSection(&This->cs);
5140
5141     return S_OK;
5142 }
5143
5144 static const IMediaFilterVtbl IMediaFilter_VTable =
5145 {
5146     MediaFilter_QueryInterface,
5147     MediaFilter_AddRef,
5148     MediaFilter_Release,
5149     MediaFilter_GetClassID,
5150     MediaFilter_Stop,
5151     MediaFilter_Pause,
5152     MediaFilter_Run,
5153     MediaFilter_GetState,
5154     MediaFilter_SetSyncSource,
5155     MediaFilter_GetSyncSource
5156 };
5157
5158 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID riid, LPVOID *ppv)
5159 {
5160     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
5161
5162     return Filtergraph_QueryInterface(This, riid, ppv);
5163 }
5164
5165 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
5166 {
5167     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
5168
5169     return Filtergraph_AddRef(This);
5170 }
5171
5172 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
5173 {
5174     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
5175
5176     return Filtergraph_Release(This);
5177 }
5178
5179 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, LONG EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
5180 {
5181     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
5182     Event evt;
5183
5184     TRACE("(%p/%p)->(%d, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
5185
5186     /* We need thread safety here, let's use the events queue's one */
5187     EnterCriticalSection(&This->evqueue.msg_crst);
5188
5189     if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
5190     {
5191         TRACE("Process EC_COMPLETE notification\n");
5192         if (++This->EcCompleteCount == This->nRenderers)
5193         {
5194             evt.lEventCode = EC_COMPLETE;
5195             evt.lParam1 = S_OK;
5196             evt.lParam2 = 0;
5197             TRACE("Send EC_COMPLETE to app\n");
5198             EventsQueue_PutEvent(&This->evqueue, &evt);
5199             if (!This->notif.disabled && This->notif.hWnd)
5200             {
5201                 TRACE("Send Window message\n");
5202                 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5203             }
5204             This->CompletionStatus = EC_COMPLETE;
5205             SetEvent(This->hEventCompletion);
5206         }
5207     }
5208     else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
5209     {
5210         /* FIXME: Not handled yet */
5211     }
5212     else
5213     {
5214         evt.lEventCode = EventCode;
5215         evt.lParam1 = EventParam1;
5216         evt.lParam2 = EventParam2;
5217         EventsQueue_PutEvent(&This->evqueue, &evt);
5218         if (!This->notif.disabled && This->notif.hWnd)
5219             PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5220     }
5221
5222     LeaveCriticalSection(&This->evqueue.msg_crst);
5223     return S_OK;
5224 }
5225
5226 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
5227 {
5228     MediaEventSink_QueryInterface,
5229     MediaEventSink_AddRef,
5230     MediaEventSink_Release,
5231     MediaEventSink_Notify
5232 };
5233
5234 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID riid, LPVOID *ppv)
5235 {
5236     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5237
5238     return Filtergraph_QueryInterface(This, riid, ppv);
5239 }
5240
5241 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
5242 {
5243     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5244
5245     return Filtergraph_AddRef(This);
5246 }
5247
5248 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
5249 {
5250     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5251
5252     return Filtergraph_Release(This);
5253 }
5254
5255 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface,
5256                                             IPin* pOutputPin,
5257                                             IPin* pInputPin,
5258                                             const AM_MEDIA_TYPE* pmtFirstConnection,
5259                                             IBaseFilter* pUsingFilter,
5260                                             HANDLE hAbortEvent,
5261                                             DWORD dwFlags)
5262 {
5263     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5264
5265     FIXME("(%p)->(%p, %p, %p, %p, %p, %x): stub!\n", This, pOutputPin, pInputPin, pmtFirstConnection, pUsingFilter, hAbortEvent, dwFlags);
5266     
5267     return E_NOTIMPL;
5268 }
5269
5270 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface,
5271                                               IGraphConfigCallback* pCallback,
5272                                               PVOID pvContext,
5273                                               DWORD dwFlags,
5274                                               HANDLE hAbortEvent)
5275 {
5276     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5277     HRESULT hr;
5278
5279     WARN("(%p)->(%p, %p, %x, %p): partial stub!\n", This, pCallback, pvContext, dwFlags, hAbortEvent);
5280
5281     if (hAbortEvent)
5282         FIXME("The parameter hAbortEvent is not handled!\n");
5283
5284     EnterCriticalSection(&This->cs);
5285
5286     hr = IGraphConfigCallback_Reconfigure(pCallback, pvContext, dwFlags);
5287
5288     LeaveCriticalSection(&This->cs);
5289
5290     return hr;
5291 }
5292
5293 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface,
5294                                                    IBaseFilter* pFilter)
5295 {
5296     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5297
5298     FIXME("(%p)->(%p): stub!\n", This, pFilter);
5299     
5300     return E_NOTIMPL;
5301 }
5302
5303 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface,
5304                                                   IEnumFilters** pEnum)
5305 {
5306     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5307
5308     FIXME("(%p)->(%p): stub!\n", This, pEnum);
5309     
5310     return E_NOTIMPL;
5311 }
5312
5313 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface,
5314                                                         IBaseFilter* pFilter)
5315 {
5316     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5317
5318     FIXME("(%p)->(%p): stub!\n", This, pFilter);
5319     
5320     return E_NOTIMPL;
5321 }
5322
5323 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface,
5324                                                REFERENCE_TIME* prtStart)
5325 {
5326     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5327
5328     FIXME("(%p)->(%p): stub!\n", This, prtStart);
5329     
5330     return E_NOTIMPL;
5331 }
5332
5333 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface,
5334                                                   IPin* pOutputPin,
5335                                                   IPinConnection* pConnection,
5336                                                   HANDLE hEventAbort)
5337 {
5338     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5339
5340     FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
5341     
5342     return E_NOTIMPL;
5343 }
5344
5345 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface,
5346                                                  IBaseFilter* pFilter,
5347                                                  DWORD dwFlags)
5348 {
5349     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5350
5351     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5352     
5353     return E_NOTIMPL;
5354 }
5355
5356 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface,
5357                                                  IBaseFilter* pFilter,
5358                                                  DWORD* dwFlags)
5359 {
5360     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5361
5362     FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
5363     
5364     return E_NOTIMPL;
5365 }
5366
5367 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface,
5368                                                  IBaseFilter* pFilter,
5369                                                  DWORD dwFlags)
5370 {
5371     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5372
5373     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5374     
5375     return E_NOTIMPL;
5376 }
5377
5378 static const IGraphConfigVtbl IGraphConfig_VTable =
5379 {
5380     GraphConfig_QueryInterface,
5381     GraphConfig_AddRef,
5382     GraphConfig_Release,
5383     GraphConfig_Reconnect,
5384     GraphConfig_Reconfigure,
5385     GraphConfig_AddFilterToCache,
5386     GraphConfig_EnumCacheFilter,
5387     GraphConfig_RemoveFilterFromCache,
5388     GraphConfig_GetStartTime,
5389     GraphConfig_PushThroughData,
5390     GraphConfig_SetFilterFlags,
5391     GraphConfig_GetFilterFlags,
5392     GraphConfig_RemoveFilterEx
5393 };
5394
5395 static const IUnknownVtbl IInner_VTable =
5396 {
5397     FilterGraphInner_QueryInterface,
5398     FilterGraphInner_AddRef,
5399     FilterGraphInner_Release
5400 };
5401
5402 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
5403                                           REFIID riid,
5404                                           LPVOID * ppv) {
5405     if (This->bAggregatable)
5406         This->bUnkOuterValid = TRUE;
5407
5408     if (This->pUnkOuter)
5409     {
5410         if (This->bAggregatable)
5411             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
5412
5413         if (IsEqualIID(riid, &IID_IUnknown))
5414         {
5415             HRESULT hr;
5416
5417             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
5418             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
5419             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
5420             This->bAggregatable = TRUE;
5421             return hr;
5422         }
5423
5424         *ppv = NULL;
5425         return E_NOINTERFACE;
5426     }
5427
5428     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
5429 }
5430
5431 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This) {
5432     if (This->pUnkOuter && This->bUnkOuterValid)
5433         return IUnknown_AddRef(This->pUnkOuter);
5434     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
5435 }
5436
5437 static ULONG Filtergraph_Release(IFilterGraphImpl *This) {
5438     if (This->pUnkOuter && This->bUnkOuterValid)
5439         return IUnknown_Release(This->pUnkOuter);
5440     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
5441 }
5442
5443 /* This is the only function that actually creates a FilterGraph class... */
5444 HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj)
5445 {
5446     IFilterGraphImpl *fimpl;
5447     HRESULT hr;
5448
5449     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
5450
5451     *ppObj = NULL;
5452
5453     fimpl = CoTaskMemAlloc(sizeof(*fimpl));
5454     fimpl->pUnkOuter = pUnkOuter;
5455     fimpl->bUnkOuterValid = FALSE;
5456     fimpl->bAggregatable = FALSE;
5457     fimpl->defaultclock = TRUE;
5458     fimpl->IInner_vtbl = &IInner_VTable;
5459     fimpl->IFilterGraph2_vtbl = &IFilterGraph2_VTable;
5460     fimpl->IMediaControl_vtbl = &IMediaControl_VTable;
5461     fimpl->IMediaSeeking_vtbl = &IMediaSeeking_VTable;
5462     fimpl->IBasicAudio_vtbl = &IBasicAudio_VTable;
5463     fimpl->IBasicVideo_vtbl = &IBasicVideo_VTable;
5464     fimpl->IVideoWindow_vtbl = &IVideoWindow_VTable;
5465     fimpl->IMediaEventEx_vtbl = &IMediaEventEx_VTable;
5466     fimpl->IMediaFilter_vtbl = &IMediaFilter_VTable;
5467     fimpl->IMediaEventSink_vtbl = &IMediaEventSink_VTable;
5468     fimpl->IGraphConfig_vtbl = &IGraphConfig_VTable;
5469     fimpl->IMediaPosition_vtbl = &IMediaPosition_VTable;
5470     fimpl->ref = 1;
5471     fimpl->ppFiltersInGraph = NULL;
5472     fimpl->pFilterNames = NULL;
5473     fimpl->nFilters = 0;
5474     fimpl->filterCapacity = 0;
5475     fimpl->nameIndex = 1;
5476     fimpl->refClock = NULL;
5477     fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
5478     fimpl->HandleEcComplete = TRUE;
5479     fimpl->HandleEcRepaint = TRUE;
5480     fimpl->HandleEcClockChanged = TRUE;
5481     fimpl->notif.hWnd = 0;
5482     fimpl->notif.disabled = FALSE;
5483     fimpl->nRenderers = 0;
5484     fimpl->EcCompleteCount = 0;
5485     fimpl->state = State_Stopped;
5486     EventsQueue_Init(&fimpl->evqueue);
5487     InitializeCriticalSection(&fimpl->cs);
5488     fimpl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IFilterGraphImpl.cs");
5489     fimpl->nItfCacheEntries = 0;
5490     memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
5491     fimpl->start_time = fimpl->pause_time = 0;
5492     fimpl->stop_position = -1;
5493     fimpl->punkFilterMapper2 = NULL;
5494     fimpl->recursioncount = 0;
5495
5496     /* create Filtermapper aggregated. */
5497     hr = CoCreateInstance(&CLSID_FilterMapper2, pUnkOuter ? pUnkOuter : (IUnknown*)&fimpl->IInner_vtbl, CLSCTX_INPROC_SERVER,
5498         &IID_IUnknown, (LPVOID*)&fimpl->punkFilterMapper2);
5499
5500     if (SUCCEEDED(hr)) {
5501         hr = IUnknown_QueryInterface(fimpl->punkFilterMapper2, &IID_IFilterMapper2,  (LPVOID*)&fimpl->pFilterMapper2);
5502     }
5503
5504     if (SUCCEEDED(hr)) {
5505         /* Release controlling IUnknown - compensate refcount increase from caching IFilterMapper2 interface. */
5506         if (pUnkOuter) IUnknown_Release(pUnkOuter);
5507         else IUnknown_Release((IUnknown*)&fimpl->IInner_vtbl);
5508     }
5509
5510     if (FAILED(hr)) {
5511         ERR("Unable to create filter mapper (%x)\n", hr);
5512         if (fimpl->punkFilterMapper2) IUnknown_Release(fimpl->punkFilterMapper2);
5513         CloseHandle(fimpl->hEventCompletion);
5514         EventsQueue_Destroy(&fimpl->evqueue);
5515         fimpl->cs.DebugInfo->Spare[0] = 0;
5516         DeleteCriticalSection(&fimpl->cs);
5517         CoTaskMemFree(fimpl);
5518         return hr;
5519     }
5520
5521     *ppObj = fimpl;
5522     return S_OK;
5523 }
5524
5525 HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj)
5526 {
5527     FIXME("CLSID_FilterGraphNoThread partially implemented - Forwarding to CLSID_FilterGraph\n");
5528     return FilterGraph_create(pUnkOuter, ppObj);
5529 }