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