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