msxml3: Support setting unlimited nesting depth for a reader.
[wine] / dlls / quartz / control.c
1 /*
2  * Filter Seeking and Control Interfaces
3  *
4  * Copyright 2003 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 /* FIXME: critical sections */
21
22 #include "quartz_private.h"
23 #include "control_private.h"
24
25 #include "uuids.h"
26 #include "wine/debug.h"
27
28 #include <assert.h>
29
30 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
31
32 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl;
33
34 typedef struct PassThruImpl {
35     const ISeekingPassThruVtbl *IPassThru_vtbl;
36     const IUnknownVtbl *IInner_vtbl;
37     const IMediaSeekingVtbl *IMediaSeeking_vtbl;
38
39     LONG ref;
40     IUnknown * pUnkOuter;
41     IPin * pin;
42     BOOL bUnkOuterValid;
43     BOOL bAggregatable;
44     BOOL renderer;
45     CRITICAL_SECTION time_cs;
46     BOOL timevalid;
47     REFERENCE_TIME time_earliest;
48 } PassThruImpl;
49
50 static HRESULT WINAPI SeekInner_QueryInterface(IUnknown * iface,
51                                           REFIID riid,
52                                           LPVOID *ppvObj) {
53     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
54     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
55
56     if (This->bAggregatable)
57         This->bUnkOuterValid = TRUE;
58
59     if (IsEqualGUID(&IID_IUnknown, riid))
60     {
61         *ppvObj = &(This->IInner_vtbl);
62         TRACE("   returning IUnknown interface (%p)\n", *ppvObj);
63     } else if (IsEqualGUID(&IID_ISeekingPassThru, riid)) {
64         *ppvObj = &(This->IPassThru_vtbl);
65         TRACE("   returning ISeekingPassThru interface (%p)\n", *ppvObj);
66     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
67         *ppvObj = &(This->IMediaSeeking_vtbl);
68         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
69     } else {
70         *ppvObj = NULL;
71         FIXME("unknown interface %s\n", debugstr_guid(riid));
72         return E_NOINTERFACE;
73     }
74
75     IUnknown_AddRef((IUnknown *)(*ppvObj));
76     return S_OK;
77 }
78
79 static ULONG WINAPI SeekInner_AddRef(IUnknown * iface) {
80     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
81     ULONG ref = InterlockedIncrement(&This->ref);
82
83     TRACE("(%p)->(): new ref = %d\n", This, ref);
84
85     return ref;
86 }
87
88 static ULONG WINAPI SeekInner_Release(IUnknown * iface) {
89     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
90     ULONG ref = InterlockedDecrement(&This->ref);
91
92     TRACE("(%p)->(): new ref = %d\n", This, ref);
93
94     if (ref == 0)
95     {
96         This->time_cs.DebugInfo->Spare[0] = 0;
97         DeleteCriticalSection(&This->time_cs);
98         CoTaskMemFree(This);
99     }
100     return ref;
101 }
102
103 static const IUnknownVtbl IInner_VTable =
104 {
105     SeekInner_QueryInterface,
106     SeekInner_AddRef,
107     SeekInner_Release
108 };
109
110 /* Generic functions for aggregation */
111 static HRESULT SeekOuter_QueryInterface(PassThruImpl *This, REFIID riid, LPVOID *ppv)
112 {
113     if (This->bAggregatable)
114         This->bUnkOuterValid = TRUE;
115
116     if (This->pUnkOuter)
117     {
118         if (This->bAggregatable)
119             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
120
121         if (IsEqualIID(riid, &IID_IUnknown))
122         {
123             HRESULT hr;
124
125             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
126             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
127             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
128             This->bAggregatable = TRUE;
129             return hr;
130         }
131
132         *ppv = NULL;
133         return E_NOINTERFACE;
134     }
135
136     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
137 }
138
139 static ULONG SeekOuter_AddRef(PassThruImpl *This)
140 {
141     if (This->pUnkOuter && This->bUnkOuterValid)
142         return IUnknown_AddRef(This->pUnkOuter);
143     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
144 }
145
146 static ULONG SeekOuter_Release(PassThruImpl *This)
147 {
148     if (This->pUnkOuter && This->bUnkOuterValid)
149         return IUnknown_Release(This->pUnkOuter);
150     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
151 }
152
153 static HRESULT WINAPI SeekingPassThru_QueryInterface(ISeekingPassThru *iface, REFIID riid, LPVOID *ppvObj)
154 {
155     ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
156
157     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
158
159     return SeekOuter_QueryInterface(This, riid, ppvObj);
160 }
161
162 static ULONG WINAPI SeekingPassThru_AddRef(ISeekingPassThru *iface)
163 {
164     ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
165
166     TRACE("(%p/%p)->()\n", This, iface);
167
168     return SeekOuter_AddRef(This);
169 }
170
171 static ULONG WINAPI SeekingPassThru_Release(ISeekingPassThru *iface)
172 {
173     ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
174
175     TRACE("(%p/%p)->()\n", This, iface);
176
177     return SeekOuter_Release(This);
178 }
179
180 static HRESULT WINAPI SeekingPassThru_Init(ISeekingPassThru *iface, BOOL renderer, IPin *pin)
181 {
182     ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
183
184     TRACE("(%p/%p)->(%d, %p)\n", This, iface, renderer, pin);
185
186     if (This->pin)
187         FIXME("Re-initializing?\n");
188
189     This->renderer = renderer;
190     This->pin = pin;
191
192     return S_OK;
193 }
194
195 static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl =
196 {
197     SeekingPassThru_QueryInterface,
198     SeekingPassThru_AddRef,
199     SeekingPassThru_Release,
200     SeekingPassThru_Init
201 };
202
203 HRESULT SeekingPassThru_create(IUnknown *pUnkOuter, LPVOID *ppObj)
204 {
205     PassThruImpl *fimpl;
206
207     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
208
209     *ppObj = fimpl = CoTaskMemAlloc(sizeof(*fimpl));
210     if (!fimpl)
211         return E_OUTOFMEMORY;
212
213     fimpl->pUnkOuter = pUnkOuter;
214     fimpl->bUnkOuterValid = FALSE;
215     fimpl->bAggregatable = FALSE;
216     fimpl->IInner_vtbl = &IInner_VTable;
217     fimpl->IPassThru_vtbl = &ISeekingPassThru_Vtbl;
218     fimpl->IMediaSeeking_vtbl = &IMediaSeekingPassThru_Vtbl;
219     fimpl->ref = 1;
220     fimpl->pin = NULL;
221     fimpl->timevalid = 0;
222     InitializeCriticalSection(&fimpl->time_cs);
223     fimpl->time_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PassThruImpl.time_cs");
224     return S_OK;
225 }
226
227 static HRESULT WINAPI MediaSeekingPassThru_QueryInterface(IMediaSeeking *iface, REFIID riid, LPVOID *ppvObj)
228 {
229     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
230
231     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
232
233     return SeekOuter_QueryInterface(This, riid, ppvObj);
234 }
235
236 static ULONG WINAPI MediaSeekingPassThru_AddRef(IMediaSeeking *iface)
237 {
238     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
239
240     TRACE("(%p/%p)->()\n", iface, This);
241
242     return SeekOuter_AddRef(This);
243 }
244
245 static ULONG WINAPI MediaSeekingPassThru_Release(IMediaSeeking *iface)
246 {
247     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
248
249     TRACE("(%p/%p)->()\n", iface, This);
250
251     return SeekOuter_Release(This);
252 }
253
254 static HRESULT get_connected(PassThruImpl *This, IMediaSeeking **seek) {
255     HRESULT hr;
256     IPin *pin;
257     *seek = NULL;
258     hr = IPin_ConnectedTo(This->pin, &pin);
259     if (FAILED(hr))
260         return VFW_E_NOT_CONNECTED;
261     hr = IPin_QueryInterface(pin, &IID_IMediaSeeking, (void**)seek);
262     IPin_Release(pin);
263     if (FAILED(hr))
264         hr = E_NOTIMPL;
265     return hr;
266 }
267
268 static HRESULT WINAPI MediaSeekingPassThru_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
269 {
270     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
271     IMediaSeeking *seek;
272     HRESULT hr;
273     TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
274     hr = get_connected(This, &seek);
275     if (SUCCEEDED(hr)) {
276         hr = IMediaSeeking_GetCapabilities(seek, pCapabilities);
277         IMediaSeeking_Release(seek);
278     }
279     else
280         return E_NOTIMPL;
281     return hr;
282 }
283
284 static HRESULT WINAPI MediaSeekingPassThru_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
285 {
286     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
287     IMediaSeeking *seek;
288     HRESULT hr;
289     TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
290     hr = get_connected(This, &seek);
291     if (SUCCEEDED(hr)) {
292         hr = IMediaSeeking_CheckCapabilities(seek, pCapabilities);
293         IMediaSeeking_Release(seek);
294     }
295     else
296         return E_NOTIMPL;
297     return hr;
298 }
299
300 static HRESULT WINAPI MediaSeekingPassThru_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat)
301 {
302     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
303     IMediaSeeking *seek;
304     HRESULT hr;
305     TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat));
306     hr = get_connected(This, &seek);
307     if (SUCCEEDED(hr)) {
308         hr = IMediaSeeking_IsFormatSupported(seek, pFormat);
309         IMediaSeeking_Release(seek);
310     }
311     else
312         return E_NOTIMPL;
313     return hr;
314 }
315
316 static HRESULT WINAPI MediaSeekingPassThru_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat)
317 {
318     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
319     IMediaSeeking *seek;
320     HRESULT hr;
321     TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
322     hr = get_connected(This, &seek);
323     if (SUCCEEDED(hr)) {
324         hr = IMediaSeeking_QueryPreferredFormat(seek, pFormat);
325         IMediaSeeking_Release(seek);
326     }
327     else
328         return E_NOTIMPL;
329     return hr;
330 }
331
332 static HRESULT WINAPI MediaSeekingPassThru_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat)
333 {
334     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
335     IMediaSeeking *seek;
336     HRESULT hr;
337     TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
338     hr = get_connected(This, &seek);
339     if (SUCCEEDED(hr)) {
340         hr = IMediaSeeking_GetTimeFormat(seek, pFormat);
341         IMediaSeeking_Release(seek);
342     }
343     else
344         return E_NOTIMPL;
345     return hr;
346 }
347
348 static HRESULT WINAPI MediaSeekingPassThru_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
349 {
350     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
351     IMediaSeeking *seek;
352     HRESULT hr;
353     TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat));
354     hr = get_connected(This, &seek);
355     if (SUCCEEDED(hr)) {
356         hr = IMediaSeeking_IsUsingTimeFormat(seek, pFormat);
357         IMediaSeeking_Release(seek);
358     }
359     else
360         return E_NOTIMPL;
361     return hr;
362 }
363
364 static HRESULT WINAPI MediaSeekingPassThru_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
365 {
366     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
367     IMediaSeeking *seek;
368     HRESULT hr;
369     TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat));
370     hr = get_connected(This, &seek);
371     if (SUCCEEDED(hr)) {
372         hr = IMediaSeeking_SetTimeFormat(seek, pFormat);
373         IMediaSeeking_Release(seek);
374     }
375     else
376         return E_NOTIMPL;
377     return hr;
378 }
379
380 static HRESULT WINAPI MediaSeekingPassThru_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration)
381 {
382     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
383     IMediaSeeking *seek;
384     HRESULT hr;
385     TRACE("(%p/%p)->(%p)\n", iface, This, pDuration);
386     hr = get_connected(This, &seek);
387     if (SUCCEEDED(hr)) {
388         hr = IMediaSeeking_GetDuration(seek, pDuration);
389         IMediaSeeking_Release(seek);
390     }
391     else
392         return E_NOTIMPL;
393     return hr;
394 }
395
396 static HRESULT WINAPI MediaSeekingPassThru_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop)
397 {
398     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
399     IMediaSeeking *seek;
400     HRESULT hr;
401     TRACE("(%p/%p)->(%p)\n", iface, This, pStop);
402     hr = get_connected(This, &seek);
403     if (SUCCEEDED(hr)) {
404         hr = IMediaSeeking_GetStopPosition(seek, pStop);
405         IMediaSeeking_Release(seek);
406     }
407     else
408         return E_NOTIMPL;
409     return hr;
410 }
411
412 static HRESULT WINAPI MediaSeekingPassThru_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent)
413 {
414     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
415     IMediaSeeking *seek;
416     HRESULT hr = S_OK;
417     TRACE("(%p/%p)->(%p)\n", iface, This, pCurrent);
418     if (!pCurrent)
419         return E_POINTER;
420     EnterCriticalSection(&This->time_cs);
421     if (This->timevalid)
422         *pCurrent = This->time_earliest;
423     else
424         hr = E_FAIL;
425     LeaveCriticalSection(&This->time_cs);
426     if (SUCCEEDED(hr)) {
427         hr = IMediaSeeking_ConvertTimeFormat(iface, pCurrent, NULL, *pCurrent, &TIME_FORMAT_MEDIA_TIME);
428         return hr;
429     }
430     hr = get_connected(This, &seek);
431     if (SUCCEEDED(hr)) {
432         hr = IMediaSeeking_GetCurrentPosition(seek, pCurrent);
433         IMediaSeeking_Release(seek);
434     }
435     else
436         return E_NOTIMPL;
437     return hr;
438 }
439
440 static HRESULT WINAPI MediaSeekingPassThru_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat)
441 {
442     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
443     IMediaSeeking *seek;
444     HRESULT hr;
445     TRACE("(%p/%p)->(%p,%s,%x%08x,%s)\n", iface, This, pTarget, debugstr_guid(pTargetFormat), (DWORD)(Source>>32), (DWORD)Source, debugstr_guid(pSourceFormat));
446     hr = get_connected(This, &seek);
447     if (SUCCEEDED(hr)) {
448         hr = IMediaSeeking_ConvertTimeFormat(seek, pTarget, pTargetFormat, Source, pSourceFormat);
449         IMediaSeeking_Release(seek);
450     }
451     else
452         return E_NOTIMPL;
453     return hr;
454 }
455
456 static HRESULT WINAPI MediaSeekingPassThru_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags)
457 {
458     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
459     IMediaSeeking *seek;
460     HRESULT hr;
461     TRACE("(%p/%p)->(%p,%x,%p,%x)\n", iface, This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
462     hr = get_connected(This, &seek);
463     if (SUCCEEDED(hr)) {
464         hr = IMediaSeeking_SetPositions(seek, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
465         IMediaSeeking_Release(seek);
466     } else if (hr == VFW_E_NOT_CONNECTED)
467         hr = S_OK;
468     return hr;
469 }
470
471 static HRESULT WINAPI MediaSeekingPassThru_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop)
472 {
473     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
474     IMediaSeeking *seek;
475     HRESULT hr;
476     TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop);
477     hr = get_connected(This, &seek);
478     if (SUCCEEDED(hr)) {
479         hr = IMediaSeeking_GetPositions(seek, pCurrent, pStop);
480         IMediaSeeking_Release(seek);
481     }
482     else
483         return E_NOTIMPL;
484     return hr;
485 }
486
487 static HRESULT WINAPI MediaSeekingPassThru_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest)
488 {
489     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
490     IMediaSeeking *seek;
491     HRESULT hr;
492     TRACE("(%p/%p)->(%p,%p)\n", iface, This, pEarliest, pLatest);
493     hr = get_connected(This, &seek);
494     if (SUCCEEDED(hr)) {
495         hr = IMediaSeeking_GetAvailable(seek, pEarliest, pLatest);
496         IMediaSeeking_Release(seek);
497     }
498     else
499         return E_NOTIMPL;
500     return hr;
501 }
502
503 static HRESULT WINAPI MediaSeekingPassThru_SetRate(IMediaSeeking * iface, double dRate)
504 {
505     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
506     IMediaSeeking *seek;
507     HRESULT hr;
508     TRACE("(%p/%p)->(%e)\n", iface, This, dRate);
509     hr = get_connected(This, &seek);
510     if (SUCCEEDED(hr)) {
511         hr = IMediaSeeking_SetRate(seek, dRate);
512         IMediaSeeking_Release(seek);
513     }
514     else
515         return E_NOTIMPL;
516     return hr;
517 }
518
519 static HRESULT WINAPI MediaSeekingPassThru_GetRate(IMediaSeeking * iface, double * dRate)
520 {
521     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
522     IMediaSeeking *seek;
523     HRESULT hr;
524     TRACE("(%p/%p)->(%p)\n", iface, This, dRate);
525     hr = get_connected(This, &seek);
526     if (SUCCEEDED(hr)) {
527         hr = IMediaSeeking_GetRate(seek, dRate);
528         IMediaSeeking_Release(seek);
529     }
530     else
531         return E_NOTIMPL;
532     return hr;
533 }
534
535 static HRESULT WINAPI MediaSeekingPassThru_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll)
536 {
537     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
538     IMediaSeeking *seek;
539     HRESULT hr;
540     TRACE("(%p)\n", pPreroll);
541     hr = get_connected(This, &seek);
542     if (SUCCEEDED(hr)) {
543         hr = IMediaSeeking_GetPreroll(seek, pPreroll);
544         IMediaSeeking_Release(seek);
545     }
546     else
547         return E_NOTIMPL;
548     return hr;
549 }
550
551 void MediaSeekingPassThru_RegisterMediaTime(IUnknown *iface, REFERENCE_TIME start) {
552     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
553     EnterCriticalSection(&This->time_cs);
554     This->time_earliest = start;
555     This->timevalid = 1;
556     LeaveCriticalSection(&This->time_cs);
557 }
558
559 void MediaSeekingPassThru_ResetMediaTime(IUnknown *iface) {
560     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
561     EnterCriticalSection(&This->time_cs);
562     This->timevalid = 0;
563     LeaveCriticalSection(&This->time_cs);
564 }
565
566 void MediaSeekingPassThru_EOS(IUnknown *iface) {
567     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
568     REFERENCE_TIME time;
569     HRESULT hr;
570     hr = IMediaSeeking_GetStopPosition((IMediaSeeking*)&This->IMediaSeeking_vtbl, &time);
571     EnterCriticalSection(&This->time_cs);
572     if (SUCCEEDED(hr)) {
573         This->timevalid = 1;
574         This->time_earliest = time;
575     } else
576         This->timevalid = 0;
577     LeaveCriticalSection(&This->time_cs);
578 }
579
580 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl =
581 {
582     MediaSeekingPassThru_QueryInterface,
583     MediaSeekingPassThru_AddRef,
584     MediaSeekingPassThru_Release,
585     MediaSeekingPassThru_GetCapabilities,
586     MediaSeekingPassThru_CheckCapabilities,
587     MediaSeekingPassThru_IsFormatSupported,
588     MediaSeekingPassThru_QueryPreferredFormat,
589     MediaSeekingPassThru_GetTimeFormat,
590     MediaSeekingPassThru_IsUsingTimeFormat,
591     MediaSeekingPassThru_SetTimeFormat,
592     MediaSeekingPassThru_GetDuration,
593     MediaSeekingPassThru_GetStopPosition,
594     MediaSeekingPassThru_GetCurrentPosition,
595     MediaSeekingPassThru_ConvertTimeFormat,
596     MediaSeekingPassThru_SetPositions,
597     MediaSeekingPassThru_GetPositions,
598     MediaSeekingPassThru_GetAvailable,
599     MediaSeekingPassThru_SetRate,
600     MediaSeekingPassThru_GetRate,
601     MediaSeekingPassThru_GetPreroll
602 };