xref: /reactos/dll/directx/ksproxy/proxy.cpp (revision fb5d5ecd)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS WDM Streaming ActiveMovie Proxy
4  * FILE:            dll/directx/ksproxy/proxy.cpp
5  * PURPOSE:         IKsProxy interface
6  *
7  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 #include "precomp.h"
10 
11 const GUID IID_IPersistPropertyBag = {0x37D84F60, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
12 const GUID IID_ISpecifyPropertyPages = {0xB196B28B, 0xBAB4, 0x101A, {0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}};
13 const GUID IID_IPersistStream = {0x00000109, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
14 const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
15 const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}};
16 const GUID IID_IKsAggregateControl = {0x7F40EAC0, 0x3947, 0x11D2, {0x87, 0x4E, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
17 const GUID IID_IKsClockPropertySet = {0x5C5CBD84, 0xE755, 0x11D0, {0xAC, 0x18, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
18 const GUID IID_IKsTopology             = {0x28F54683, 0x06FD, 0x11D2, {0xB2, 0x7A, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
19 const GUID IID_IKsClock            = {0x877E4351, 0x6FEA, 0x11D0, {0xB8, 0x63, 0x00, 0xAA, 0x00, 0xA2, 0x16, 0xA1}};
20 /*
21     Needs IKsClock, IKsNotifyEvent
22 */
23 
24 class CKsProxy : public IBaseFilter,
25                  public IAMovieSetup,
26                  public IPersistPropertyBag,
27                  public IKsObject,
28                  public IPersistStream,
29                  public IAMDeviceRemoval,
30                  public ISpecifyPropertyPages,
31                  public IReferenceClock,
32                  public IMediaSeeking,
33                  public IKsPropertySet,
34                  public IKsClock,
35                  public IKsClockPropertySet,
36                  public IAMFilterMiscFlags,
37                  public IKsControl,
38                  public IKsTopology,
39                  public IKsAggregateControl
40 
41 {
42 public:
43     typedef std::vector<IUnknown *>ProxyPluginVector;
44     typedef std::vector<IPin *> PinVector;
45 
46     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
47 
48     STDMETHODIMP_(ULONG) AddRef()
49     {
50         InterlockedIncrement(&m_Ref);
51         return m_Ref;
52     }
53     STDMETHODIMP_(ULONG) Release()
54     {
55         InterlockedDecrement(&m_Ref);
56         if (!m_Ref)
57         {
58             //delete this;
59             return 0;
60         }
61         return m_Ref;
62     }
63 
64     // IBaseFilter methods
65     HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
66     HRESULT STDMETHODCALLTYPE Stop( void);
67     HRESULT STDMETHODCALLTYPE Pause( void);
68     HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
69     HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *State);
70     HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
71     HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **pClock);
72     HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
73     HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
74     HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
75     HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
76     HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
77 
78     //IReferenceClock
79     HRESULT STDMETHODCALLTYPE GetTime(REFERENCE_TIME *pTime);
80     HRESULT STDMETHODCALLTYPE AdviseTime(REFERENCE_TIME baseTime, REFERENCE_TIME streamTime, HEVENT hEvent, DWORD_PTR *pdwAdviseCookie);
81     HRESULT STDMETHODCALLTYPE AdvisePeriodic(REFERENCE_TIME startTime, REFERENCE_TIME periodTime, HSEMAPHORE hSemaphore, DWORD_PTR *pdwAdviseCookie);
82     HRESULT STDMETHODCALLTYPE Unadvise(DWORD_PTR dwAdviseCookie);
83 
84     //IMediaSeeking
85     HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities);
86     HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities);
87     HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat);
88     HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat);
89     HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat);
90     HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat);
91     HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat);
92     HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration);
93     HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop);
94     HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent);
95     HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
96     HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
97     HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
98     HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
99     HRESULT STDMETHODCALLTYPE SetRate(double dRate);
100     HRESULT STDMETHODCALLTYPE GetRate(double *pdRate);
101     HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll);
102 
103     //IKsPropertySet
104     HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData);
105     HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned);
106     HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport);
107 
108     //IAMFilterMiscFlags
109     ULONG STDMETHODCALLTYPE GetMiscFlags( void);
110 
111     //IKsControl
112     HRESULT STDMETHODCALLTYPE KsProperty(PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned);
113     HRESULT STDMETHODCALLTYPE KsMethod(PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned);
114     HRESULT STDMETHODCALLTYPE KsEvent(PKSEVENT Event, ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned);
115 
116     //IKsTopolology
117     HRESULT STDMETHODCALLTYPE CreateNodeInstance(ULONG NodeId, ULONG Flags, ACCESS_MASK DesiredAccess, IUnknown* UnkOuter, REFGUID InterfaceId, LPVOID* Interface);
118 
119     //IKsAggregateControl
120     HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass);
121     HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass);
122 
123     //IKsClockPropertySet
124     HRESULT STDMETHODCALLTYPE KsGetTime(LONGLONG* Time);
125     HRESULT STDMETHODCALLTYPE KsSetTime(LONGLONG Time);
126     HRESULT STDMETHODCALLTYPE KsGetPhysicalTime(LONGLONG* Time);
127     HRESULT STDMETHODCALLTYPE KsSetPhysicalTime(LONGLONG Time);
128     HRESULT STDMETHODCALLTYPE KsGetCorrelatedTime(KSCORRELATED_TIME* CorrelatedTime);
129     HRESULT STDMETHODCALLTYPE KsSetCorrelatedTime(KSCORRELATED_TIME* CorrelatedTime);
130     HRESULT STDMETHODCALLTYPE KsGetCorrelatedPhysicalTime(KSCORRELATED_TIME* CorrelatedTime);
131     HRESULT STDMETHODCALLTYPE KsSetCorrelatedPhysicalTime(KSCORRELATED_TIME* CorrelatedTime);
132     HRESULT STDMETHODCALLTYPE KsGetResolution(KSRESOLUTION* Resolution);
133     HRESULT STDMETHODCALLTYPE KsGetState(KSSTATE* State);
134 
135 
136     //IAMovieSetup methods
137     HRESULT STDMETHODCALLTYPE Register( void);
138     HRESULT STDMETHODCALLTYPE Unregister( void);
139 
140     // IPersistPropertyBag methods
141     HRESULT STDMETHODCALLTYPE InitNew( void);
142     HRESULT STDMETHODCALLTYPE Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog);
143     HRESULT STDMETHODCALLTYPE Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties);
144 
145     // IKsObject
146     HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
147 
148     // IKsClock
149     HANDLE STDMETHODCALLTYPE KsGetClockHandle();
150 
151     //IAMDeviceRemoval
152     HRESULT STDMETHODCALLTYPE DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink);
153     HRESULT STDMETHODCALLTYPE Reassociate(void);
154     HRESULT STDMETHODCALLTYPE Disassociate( void);
155 
156     //IPersistStream
157     HRESULT STDMETHODCALLTYPE IsDirty( void);
158     HRESULT STDMETHODCALLTYPE Load(IStream *pStm);
159     HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty);
160     HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize);
161 
162     // ISpecifyPropertyPages
163     HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages);
164 
165 
166     CKsProxy();
167     ~CKsProxy()
168     {
169         if (m_hDevice)
170             CloseHandle(m_hDevice);
171     };
172 
173     HRESULT STDMETHODCALLTYPE GetSupportedSets(LPGUID * pOutGuid, PULONG NumGuids);
174     HRESULT STDMETHODCALLTYPE LoadProxyPlugins(LPGUID pGuids, ULONG NumGuids);
175     HRESULT STDMETHODCALLTYPE GetNumberOfPins(PULONG NumPins);
176     HRESULT STDMETHODCALLTYPE GetPinInstanceCount(ULONG PinId, PKSPIN_CINSTANCES Instances);
177     HRESULT STDMETHODCALLTYPE GetPinDataflow(ULONG PinId, KSPIN_DATAFLOW * DataFlow);
178     HRESULT STDMETHODCALLTYPE GetPinName(ULONG PinId, KSPIN_DATAFLOW DataFlow, ULONG PinCount, LPWSTR * OutPinName);
179     HRESULT STDMETHODCALLTYPE GetPinCommunication(ULONG PinId, KSPIN_COMMUNICATION * Communication);
180     HRESULT STDMETHODCALLTYPE CreatePins();
181     HRESULT STDMETHODCALLTYPE GetMediaSeekingFormats(PKSMULTIPLE_ITEM *FormatList);
182     HRESULT STDMETHODCALLTYPE CreateClockInstance();
183     HRESULT STDMETHODCALLTYPE PerformClockProperty(ULONG PropertyId, ULONG PropertyFlags, PVOID OutputBuffer, ULONG OutputBufferSize);
184     HRESULT STDMETHODCALLTYPE SetPinState(KSSTATE State);
185 
186 
187 protected:
188     LONG m_Ref;
189     IFilterGraph *m_pGraph;
190     IReferenceClock * m_ReferenceClock;
191     FILTER_STATE m_FilterState;
192     HANDLE m_hDevice;
193     ProxyPluginVector m_Plugins;
194     PinVector m_Pins;
195     LPWSTR m_DevicePath;
196     CLSID m_DeviceInterfaceGUID;
197     HANDLE m_hClock;
198     CRITICAL_SECTION m_Lock;
199 };
200 
201 CKsProxy::CKsProxy() : m_Ref(0),
202                        m_pGraph(0),
203                        m_FilterState(State_Stopped),
204                        m_hDevice(0),
205                        m_Plugins(),
206                        m_Pins(),
207                        m_DevicePath(0),
208                        m_hClock(0)
209 {
210     m_ReferenceClock = this;
211     InitializeCriticalSection(&m_Lock);
212 }
213 
214 
215 HRESULT
216 STDMETHODCALLTYPE
217 CKsProxy::QueryInterface(
218     IN  REFIID refiid,
219     OUT PVOID* Output)
220 {
221     *Output = NULL;
222 
223     if (IsEqualGUID(refiid, IID_IUnknown) ||
224         IsEqualGUID(refiid, IID_IBaseFilter))
225     {
226         *Output = PVOID(this);
227         reinterpret_cast<IUnknown*>(*Output)->AddRef();
228         return NOERROR;
229     }
230     else if (IsEqualGUID(refiid, IID_IPersistPropertyBag))
231     {
232         *Output = (IPersistPropertyBag*)(this);
233         reinterpret_cast<IPersistPropertyBag*>(*Output)->AddRef();
234         return NOERROR;
235     }
236     else if (IsEqualGUID(refiid, IID_IAMDeviceRemoval))
237     {
238         *Output = (IAMDeviceRemoval*)(this);
239         reinterpret_cast<IAMDeviceRemoval*>(*Output)->AddRef();
240         return NOERROR;
241     }
242     else if (IsEqualGUID(refiid, IID_IPersistStream))
243     {
244         *Output = (IPersistStream*)(this);
245         reinterpret_cast<IPersistStream*>(*Output)->AddRef();
246         return NOERROR;
247     }
248     else if (IsEqualGUID(refiid, IID_IPersist))
249     {
250         *Output = (IPersistStream*)(this);
251         reinterpret_cast<IPersist*>(*Output)->AddRef();
252         return NOERROR;
253     }
254     else if (IsEqualGUID(refiid, IID_IKsObject))
255     {
256         *Output = (IKsObject*)(this);
257         reinterpret_cast<IKsObject*>(*Output)->AddRef();
258         return NOERROR;
259     }
260     else if (IsEqualGUID(refiid, IID_IKsClock))
261     {
262         *Output = (IKsClock*)(this);
263         reinterpret_cast<IKsClock*>(*Output)->AddRef();
264         return NOERROR;
265     }
266     else if (IsEqualGUID(refiid, IID_IReferenceClock))
267     {
268         if (!m_hClock)
269         {
270             HRESULT hr = CreateClockInstance();
271             if (FAILED(hr))
272                 return hr;
273         }
274 
275         *Output = (IReferenceClock*)(this);
276         reinterpret_cast<IReferenceClock*>(*Output)->AddRef();
277         return NOERROR;
278     }
279     else if (IsEqualGUID(refiid, IID_IMediaSeeking))
280     {
281         *Output = (IMediaSeeking*)(this);
282         reinterpret_cast<IMediaSeeking*>(*Output)->AddRef();
283         return NOERROR;
284     }
285     else if (IsEqualGUID(refiid, IID_IAMFilterMiscFlags))
286     {
287         *Output = (IAMFilterMiscFlags*)(this);
288         reinterpret_cast<IAMFilterMiscFlags*>(*Output)->AddRef();
289         return NOERROR;
290     }
291     else if (IsEqualGUID(refiid, IID_IKsControl))
292     {
293         *Output = (IKsControl*)(this);
294         reinterpret_cast<IKsControl*>(*Output)->AddRef();
295         return NOERROR;
296     }
297     else if (IsEqualGUID(refiid, IID_IKsPropertySet))
298     {
299         *Output = (IKsPropertySet*)(this);
300         reinterpret_cast<IKsPropertySet*>(*Output)->AddRef();
301         return NOERROR;
302     }
303     else if (IsEqualGUID(refiid, IID_IKsTopology))
304     {
305         *Output = (IKsTopology*)(this);
306         reinterpret_cast<IKsTopology*>(*Output)->AddRef();
307         return NOERROR;
308     }
309     else if (IsEqualGUID(refiid, IID_IKsAggregateControl))
310     {
311         *Output = (IKsAggregateControl*)(this);
312         reinterpret_cast<IKsAggregateControl*>(*Output)->AddRef();
313         return NOERROR;
314     }
315     else if (IsEqualGUID(refiid, IID_IKsClockPropertySet))
316     {
317         if (!m_hClock)
318         {
319             HRESULT hr = CreateClockInstance();
320             if (FAILED(hr))
321                 return hr;
322         }
323 
324         *Output = (IKsClockPropertySet*)(this);
325         reinterpret_cast<IKsClockPropertySet*>(*Output)->AddRef();
326         return NOERROR;
327     }
328     else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages))
329     {
330         *Output = (ISpecifyPropertyPages*)(this);
331         reinterpret_cast<ISpecifyPropertyPages*>(*Output)->AddRef();
332         return NOERROR;
333     }
334 
335     for(ULONG Index = 0; Index < m_Plugins.size(); Index++)
336     {
337         if (m_Pins[Index])
338         {
339             HRESULT hr = m_Plugins[Index]->QueryInterface(refiid, Output);
340             if (SUCCEEDED(hr))
341             {
342 #ifdef KSPROXY_TRACE
343                 WCHAR Buffer[100];
344                 LPOLESTR lpstr;
345                 StringFromCLSID(refiid, &lpstr);
346                 swprintf(Buffer, L"CKsProxy::QueryInterface plugin %lu supports interface %s\n", Index, lpstr);
347                 OutputDebugStringW(Buffer);
348                 CoTaskMemFree(lpstr);
349 #endif
350                 return hr;
351             }
352         }
353     }
354 #ifdef KSPROXY_TRACE
355     WCHAR Buffer[MAX_PATH];
356     LPOLESTR lpstr;
357     StringFromCLSID(refiid, &lpstr);
358     swprintf(Buffer, L"CKsProxy::QueryInterface: NoInterface for %s !!!\n", lpstr);
359     OutputDebugStringW(Buffer);
360     CoTaskMemFree(lpstr);
361 #endif
362 
363     return E_NOINTERFACE;
364 }
365 
366 //-------------------------------------------------------------------
367 // ISpecifyPropertyPages
368 //
369 
370 HRESULT
371 STDMETHODCALLTYPE
372 CKsProxy::GetPages(CAUUID *pPages)
373 {
374 #ifdef KSPROXY_TRACE
375     OutputDebugStringW(L"CKsProxy::GetPages NotImplemented\n");
376 #endif
377 
378     if (!pPages)
379         return E_POINTER;
380 
381     pPages->cElems = 0;
382     pPages->pElems = NULL;
383 
384     return S_OK;
385 }
386 
387 //-------------------------------------------------------------------
388 // IKsClockPropertySet interface
389 //
390 
391 HRESULT
392 STDMETHODCALLTYPE
393 CKsProxy::CreateClockInstance()
394 {
395     HRESULT hr;
396     HANDLE hPin = INVALID_HANDLE_VALUE;
397     ULONG Index;
398     PIN_DIRECTION PinDir;
399     IKsObject *pObject;
400     KSCLOCK_CREATE ClockCreate;
401 
402     // find output pin and handle
403     for(Index = 0; Index < m_Pins.size(); Index++)
404     {
405         //get pin
406         IPin * pin = m_Pins[Index];
407         if (!pin)
408             continue;
409 
410         // get direction
411         hr = pin->QueryDirection(&PinDir);
412         if (FAILED(hr))
413             continue;
414 
415         // query IKsObject interface
416         hr = pin->QueryInterface(IID_IKsObject, (void**)&pObject);
417         if (FAILED(hr))
418             continue;
419 
420 
421         // get pin handle
422         hPin = pObject->KsGetObjectHandle();
423 
424         //release IKsObject
425         pObject->Release();
426 
427         if (hPin != INVALID_HANDLE_VALUE)
428             break;
429     }
430 
431     if (hPin == INVALID_HANDLE_VALUE)
432     {
433         // clock can only be instantiated on a pin handle
434         return E_NOTIMPL;
435     }
436 
437     if (m_hClock)
438     {
439         // release clock handle
440         CloseHandle(m_hClock);
441     }
442 
443     //setup clock create request
444     ClockCreate.CreateFlags = 0;
445 
446     // setup clock create request
447     hr = KsCreateClock(hPin, &ClockCreate, &m_hClock); // FIXME KsCreateClock returns NTSTATUS
448     if (SUCCEEDED(hr))
449     {
450         // failed to create clock
451         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
452     }
453 
454     return S_OK;
455 }
456 
457 HRESULT
458 STDMETHODCALLTYPE
459 CKsProxy::PerformClockProperty(
460     ULONG PropertyId,
461     ULONG PropertyFlags,
462     PVOID OutputBuffer,
463     ULONG OutputBufferSize)
464 {
465     KSPROPERTY Property;
466     HRESULT hr;
467     ULONG BytesReturned;
468 
469     if (!m_hClock)
470     {
471         // create clock
472         hr = CreateClockInstance();
473         if (FAILED(hr))
474             return hr;
475     }
476 
477     // setup request
478     Property.Set = KSPROPSETID_Clock;
479     Property.Id = PropertyId;
480     Property.Flags = PropertyFlags;
481 
482     hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)OutputBuffer, OutputBufferSize, &BytesReturned);
483 
484     return hr;
485 }
486 
487 HRESULT
488 STDMETHODCALLTYPE
489 CKsProxy::KsGetTime(
490     LONGLONG* Time)
491 {
492 #ifdef KSPROXY_TRACE
493     OutputDebugStringW(L"CKsProxy::KsGetTime\n");
494 #endif
495 
496     return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG));
497 }
498 
499 HRESULT
500 STDMETHODCALLTYPE
501 CKsProxy::KsSetTime(
502     LONGLONG Time)
503 {
504 #ifdef KSPROXY_TRACE
505     OutputDebugStringW(L"CKsProxy::KsSetTime\n");
506 #endif
507 
508     return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG));
509 }
510 
511 HRESULT
512 STDMETHODCALLTYPE
513 CKsProxy::KsGetPhysicalTime(
514     LONGLONG* Time)
515 {
516 #ifdef KSPROXY_TRACE
517     OutputDebugStringW(L"CKsProxy::KsGetPhysicalTime\n");
518 #endif
519 
520     return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG));
521 }
522 
523 HRESULT
524 STDMETHODCALLTYPE
525 CKsProxy::KsSetPhysicalTime(
526     LONGLONG Time)
527 {
528 #ifdef KSPROXY_TRACE
529     OutputDebugStringW(L"CKsProxy::KsSetPhysicalTime\n");
530 #endif
531 
532     return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG));
533 }
534 
535 HRESULT
536 STDMETHODCALLTYPE
537 CKsProxy::KsGetCorrelatedTime(
538     KSCORRELATED_TIME* CorrelatedTime)
539 {
540 #ifdef KSPROXY_TRACE
541     OutputDebugStringW(L"CKsProxy::KsGetCorrelatedTime\n");
542 #endif
543 
544     return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
545 }
546 
547 HRESULT
548 STDMETHODCALLTYPE
549 CKsProxy::KsSetCorrelatedTime(
550     KSCORRELATED_TIME* CorrelatedTime)
551 {
552 #ifdef KSPROXY_TRACE
553     OutputDebugStringW(L"CKsProxy::KsSetCorrelatedTime\n");
554 #endif
555     return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
556 }
557 
558 HRESULT
559 STDMETHODCALLTYPE
560 CKsProxy::KsGetCorrelatedPhysicalTime(
561     KSCORRELATED_TIME* CorrelatedTime)
562 {
563 #ifdef KSPROXY_TRACE
564     OutputDebugStringW(L"CKsProxy::KsGetCorrelatedPhysicalTime\n");
565 #endif
566     return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
567 }
568 
569 HRESULT
570 STDMETHODCALLTYPE
571 CKsProxy::KsSetCorrelatedPhysicalTime(
572     KSCORRELATED_TIME* CorrelatedTime)
573 {
574 #ifdef KSPROXY_TRACE
575     OutputDebugStringW(L"CKsProxy::KsSetCorrelatedPhysicalTime\n");
576 #endif
577 
578     return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
579 }
580 
581 HRESULT
582 STDMETHODCALLTYPE
583 CKsProxy::KsGetResolution(
584     KSRESOLUTION* Resolution)
585 {
586 #ifdef KSPROXY_TRACE
587     OutputDebugStringW(L"CKsProxy::KsGetResolution\n");
588 #endif
589     return PerformClockProperty(KSPROPERTY_CLOCK_RESOLUTION, KSPROPERTY_TYPE_GET, (PVOID)Resolution, sizeof(KSRESOLUTION));
590 }
591 
592 HRESULT
593 STDMETHODCALLTYPE
594 CKsProxy::KsGetState(
595     KSSTATE* State)
596 {
597 #ifdef KSPROXY_TRACE
598     OutputDebugStringW(L"CKsProxy::KsGetState\n");
599 #endif
600     return PerformClockProperty(KSPROPERTY_CLOCK_STATE, KSPROPERTY_TYPE_GET, (PVOID)State, sizeof(KSSTATE));
601 }
602 
603 //-------------------------------------------------------------------
604 // IReferenceClock interface
605 //
606 HRESULT
607 STDMETHODCALLTYPE
608 CKsProxy::GetTime(
609     REFERENCE_TIME *pTime)
610 {
611     HRESULT hr;
612     KSPROPERTY Property;
613     ULONG BytesReturned;
614 
615 #ifdef KSPROXY_TRACE
616     OutputDebugStringW(L"CKsProxy::GetTime\n");
617 #endif
618 
619     if (!pTime)
620         return E_POINTER;
621 
622     //
623     //FIXME locks
624     //
625 
626     if (!m_hClock)
627     {
628         // create clock
629         hr = CreateClockInstance();
630         if (FAILED(hr))
631             return hr;
632     }
633 
634     // setup request
635     Property.Set = KSPROPSETID_Clock;
636     Property.Id = KSPROPERTY_CLOCK_TIME;
637     Property.Flags = KSPROPERTY_TYPE_GET;
638 
639     // perform request
640     hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pTime, sizeof(REFERENCE_TIME), &BytesReturned);
641 
642     // TODO
643     // increment value
644     //
645 
646     return hr;
647 }
648 
649 HRESULT
650 STDMETHODCALLTYPE
651 CKsProxy::AdviseTime(
652     REFERENCE_TIME baseTime,
653     REFERENCE_TIME streamTime,
654     HEVENT hEvent,
655     DWORD_PTR *pdwAdviseCookie)
656 {
657     HRESULT hr;
658     KSEVENT Property;
659     ULONG BytesReturned;
660     PKSEVENT_TIME_MARK Event;
661 
662 #ifdef KSPROXY_TRACE
663     OutputDebugStringW(L"CKsProxy::AdviseTime\n");
664 #endif
665 
666     //
667     //FIXME locks
668     //
669 
670     if (!pdwAdviseCookie)
671         return E_POINTER;
672 
673     if (!m_hClock)
674     {
675         // create clock
676         hr = CreateClockInstance();
677         if (FAILED(hr))
678             return hr;
679     }
680 
681     // allocate event entry
682     Event = (PKSEVENT_TIME_MARK)CoTaskMemAlloc(sizeof(KSEVENT_TIME_MARK));
683     if (Event)
684     {
685         // setup request
686         Property.Set = KSEVENTSETID_Clock;
687         Property.Id = KSEVENT_CLOCK_POSITION_MARK;
688         Property.Flags = KSEVENT_TYPE_ENABLE;
689 
690         Event->EventData.NotificationType = KSEVENTF_EVENT_HANDLE;
691         Event->EventData.EventHandle.Event = (HANDLE)hEvent;
692         Event->EventData.Alignment.Alignment[0] = 0;
693         Event->EventData.Alignment.Alignment[1] = 0;
694         Event->MarkTime = baseTime + streamTime;
695 
696         // perform request
697         hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_MARK), &BytesReturned);
698         if (SUCCEEDED(hr))
699         {
700             // store event handle
701             *pdwAdviseCookie = (DWORD_PTR)Event;
702         }
703         else
704         {
705             // failed to enable event
706             CoTaskMemFree(Event);
707         }
708     }
709     else
710     {
711          hr = E_OUTOFMEMORY;
712     }
713 
714     return hr;
715 }
716 
717 HRESULT
718 STDMETHODCALLTYPE
719 CKsProxy::AdvisePeriodic(
720     REFERENCE_TIME startTime,
721     REFERENCE_TIME periodTime,
722     HSEMAPHORE hSemaphore,
723     DWORD_PTR *pdwAdviseCookie)
724 {
725     HRESULT hr;
726     KSEVENT Property;
727     ULONG BytesReturned;
728     PKSEVENT_TIME_INTERVAL Event;
729 
730 #ifdef KSPROXY_TRACE
731     OutputDebugStringW(L"CKsProxy::AdvisePeriodic\n");
732 #endif
733 
734     //
735     //FIXME locks
736     //
737 
738     if (!pdwAdviseCookie)
739         return E_POINTER;
740 
741     if (!m_hClock)
742     {
743         // create clock
744         hr = CreateClockInstance();
745         if (FAILED(hr))
746             return hr;
747     }
748 
749     // allocate event entry
750     Event = (PKSEVENT_TIME_INTERVAL)CoTaskMemAlloc(sizeof(KSEVENT_TIME_INTERVAL));
751     if (Event)
752     {
753         // setup request
754         Property.Set = KSEVENTSETID_Clock;
755         Property.Id = KSEVENT_CLOCK_INTERVAL_MARK;
756         Property.Flags = KSEVENT_TYPE_ENABLE;
757 
758         Event->EventData.NotificationType = KSEVENTF_SEMAPHORE_HANDLE;
759         Event->EventData.SemaphoreHandle.Semaphore = (HANDLE)hSemaphore;
760         Event->EventData.SemaphoreHandle.Reserved = 0;
761         Event->EventData.SemaphoreHandle.Adjustment = 1;
762         Event->TimeBase = startTime;
763         Event->Interval = periodTime;
764 
765         // perform request
766         hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_INTERVAL), &BytesReturned);
767         if (SUCCEEDED(hr))
768         {
769             // store event handle
770             *pdwAdviseCookie = (DWORD_PTR)Event;
771         }
772         else
773         {
774             // failed to enable event
775             CoTaskMemFree(Event);
776         }
777     }
778     else
779     {
780          hr = E_OUTOFMEMORY;
781     }
782 
783     return hr;
784 }
785 
786 HRESULT
787 STDMETHODCALLTYPE
788 CKsProxy::Unadvise(
789     DWORD_PTR dwAdviseCookie)
790 {
791     HRESULT hr;
792     ULONG BytesReturned;
793 
794 #ifdef KSPROXY_TRACE
795     OutputDebugStringW(L"CKsProxy::Unadvise\n");
796 #endif
797 
798     if (m_hClock)
799     {
800         //lets disable the event
801         hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_DISABLE_EVENT, (PVOID)dwAdviseCookie, sizeof(KSEVENTDATA), 0, 0, &BytesReturned);
802         if (SUCCEEDED(hr))
803         {
804             // lets free event data
805             CoTaskMemFree((LPVOID)dwAdviseCookie);
806         }
807     }
808     else
809     {
810         // no clock available
811         hr = E_FAIL;
812     }
813 
814     return hr;
815 }
816 
817 //-------------------------------------------------------------------
818 // IMediaSeeking interface
819 //
820 HRESULT
821 STDMETHODCALLTYPE
822 CKsProxy::GetCapabilities(
823     DWORD *pCapabilities)
824 {
825     KSPROPERTY Property;
826     ULONG BytesReturned, Index;
827     HRESULT hr = S_OK;
828     DWORD TempCaps;
829 
830     Property.Set = KSPROPSETID_MediaSeeking;
831     Property.Id = KSPROPERTY_MEDIASEEKING_CAPABILITIES;
832     Property.Flags = KSPROPERTY_TYPE_GET;
833 
834 #ifdef KSPROXY_TRACE
835     OutputDebugStringW(L"CKsProxy::GetCapabilities\n");
836 #endif
837 
838 
839     if (!pCapabilities)
840         return E_POINTER;
841 
842 
843     *pCapabilities = (KS_SEEKING_CanSeekAbsolute | KS_SEEKING_CanSeekForwards | KS_SEEKING_CanSeekBackwards | KS_SEEKING_CanGetCurrentPos |
844                       KS_SEEKING_CanGetStopPos | KS_SEEKING_CanGetDuration | KS_SEEKING_CanPlayBackwards);
845 
846     KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pCapabilities, sizeof(KS_SEEKING_CAPABILITIES), &BytesReturned);
847     // check if plugins support it
848     for(Index = 0; Index < m_Plugins.size(); Index++)
849     {
850         // get plugin
851         IUnknown * Plugin = m_Plugins[Index];
852 
853         if (!Plugin)
854            continue;
855 
856         // query for IMediaSeeking interface
857         IMediaSeeking *pSeek = NULL;
858         hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
859         if (FAILED(hr))
860         {
861             *pCapabilities = 0;
862             return hr;
863         }
864 
865         TempCaps = 0;
866         // set time format
867         hr = pSeek->GetCapabilities(&TempCaps);
868         if (SUCCEEDED(hr))
869         {
870             // and with supported flags
871             *pCapabilities = (*pCapabilities & TempCaps);
872         }
873         // release IMediaSeeking interface
874         pSeek->Release();
875     }
876     return hr;
877 }
878 
879 HRESULT
880 STDMETHODCALLTYPE
881 CKsProxy::CheckCapabilities(
882     DWORD *pCapabilities)
883 {
884     DWORD Capabilities;
885     HRESULT hr;
886 
887 #ifdef KSPROXY_TRACE
888     OutputDebugStringW(L"CKsProxy::CheckCapabilities\n");
889 #endif
890 
891     if (!pCapabilities)
892         return E_POINTER;
893 
894     if (!*pCapabilities)
895         return E_FAIL;
896 
897     hr = GetCapabilities(&Capabilities);
898     if (SUCCEEDED(hr))
899     {
900         if ((Capabilities | *pCapabilities) == Capabilities)
901         {
902             // all present
903             return S_OK;
904         }
905 
906         Capabilities = (Capabilities & *pCapabilities);
907         if (Capabilities)
908         {
909             // not all present
910             *pCapabilities = Capabilities;
911             return S_FALSE;
912         }
913         // no capabilities are present
914         return E_FAIL;
915     }
916 
917     return hr;
918 }
919 
920 HRESULT
921 STDMETHODCALLTYPE
922 CKsProxy::GetMediaSeekingFormats(
923     PKSMULTIPLE_ITEM *FormatList)
924 {
925     KSPROPERTY Property;
926     HRESULT hr;
927     ULONG BytesReturned;
928 
929     Property.Set = KSPROPSETID_MediaSeeking;
930     Property.Id = KSPROPERTY_MEDIASEEKING_FORMATS;
931     Property.Flags = KSPROPERTY_TYPE_GET;
932 
933     // query for format size list
934     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
935 
936     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA))
937     {
938         // allocate format list
939         *FormatList = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(BytesReturned);
940         if (!*FormatList)
941         {
942             // not enough memory
943             return E_OUTOFMEMORY;
944         }
945 
946         // get format list
947         hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)*FormatList, BytesReturned, &BytesReturned);
948         if (FAILED(hr))
949         {
950             // failed to query format list
951             CoTaskMemFree(FormatList);
952         }
953     }
954     return hr;
955 }
956 
957 HRESULT
958 STDMETHODCALLTYPE
959 CKsProxy::IsFormatSupported(
960     const GUID *pFormat)
961 {
962     PKSMULTIPLE_ITEM FormatList;
963     LPGUID pGuid;
964     ULONG Index;
965     HRESULT hr = S_FALSE;
966 
967 #ifdef KSPROXY_TRACE
968     WCHAR Buffer[100];
969     LPOLESTR pstr;
970     StringFromCLSID(*pFormat, &pstr);
971     swprintf(Buffer, L"CKsProxy::IsFormatSupported %s\n",pstr);
972     OutputDebugStringW(Buffer);
973 #endif
974 
975     if (!pFormat)
976         return E_POINTER;
977 
978     // get media formats
979     hr = GetMediaSeekingFormats(&FormatList);
980     if (SUCCEEDED(hr))
981     {
982 #ifdef KSPROXY_TRACE
983         swprintf(Buffer, L"CKsProxy::IsFormatSupported NumFormat %lu\n",FormatList->Count);
984         OutputDebugStringW(Buffer);
985 #endif
986 
987         //iterate through format list
988         pGuid = (LPGUID)(FormatList + 1);
989         for(Index = 0; Index < FormatList->Count; Index++)
990         {
991             if (IsEqualGUID(*pGuid, *pFormat))
992             {
993                 CoTaskMemFree(FormatList);
994                 return S_OK;
995             }
996             pGuid++;
997         }
998         // free format list
999         CoTaskMemFree(FormatList);
1000     }
1001 
1002     // check if all plugins support it
1003     for(Index = 0; Index < m_Plugins.size(); Index++)
1004     {
1005         // get plugin
1006         IUnknown * Plugin = m_Plugins[Index];
1007 
1008         if (!Plugin)
1009             continue;
1010 
1011         // query for IMediaSeeking interface
1012         IMediaSeeking *pSeek = NULL;
1013         hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1014         if (FAILED(hr))
1015         {
1016             // plugin does not support interface
1017             hr = S_FALSE;
1018 #ifdef KSPROXY_TRACE
1019             OutputDebugStringW(L"CKsProxy::IsFormatSupported plugin does not support IMediaSeeking interface\n");
1020 #endif
1021             break;
1022         }
1023 
1024         // query if it is supported
1025         hr = pSeek->IsFormatSupported(pFormat);
1026         // release interface
1027         pSeek->Release();
1028 
1029         if (FAILED(hr) || hr == S_FALSE)
1030             break;
1031     }
1032 
1033     return hr;
1034 }
1035 
1036 HRESULT
1037 STDMETHODCALLTYPE
1038 CKsProxy::QueryPreferredFormat(
1039     GUID *pFormat)
1040 {
1041     PKSMULTIPLE_ITEM FormatList;
1042     HRESULT hr;
1043     ULONG Index;
1044 
1045 #ifdef KSPROXY_TRACE
1046     OutputDebugStringW(L"CKsProxy::QueryPreferredFormat\n");
1047 #endif
1048 
1049     if (!pFormat)
1050         return E_POINTER;
1051 
1052     hr = GetMediaSeekingFormats(&FormatList);
1053     if (SUCCEEDED(hr))
1054     {
1055         if (FormatList->Count)
1056         {
1057             CopyMemory(pFormat, (FormatList + 1), sizeof(GUID));
1058             CoTaskMemFree(FormatList);
1059             return S_OK;
1060         }
1061         CoTaskMemFree(FormatList);
1062     }
1063     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1064     {
1065         // check if plugins support it
1066         for(Index = 0; Index < m_Plugins.size(); Index++)
1067         {
1068             // get plugin
1069             IUnknown * Plugin = m_Plugins[Index];
1070 
1071             if (!Plugin)
1072                continue;
1073 
1074             // query for IMediaSeeking interface
1075             IMediaSeeking *pSeek = NULL;
1076             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1077             if (SUCCEEDED(hr))
1078             {
1079                 // get preferred time format
1080                 hr = pSeek->QueryPreferredFormat(pFormat);
1081                 // release IMediaSeeking interface
1082                 pSeek->Release();
1083 
1084                 if (hr != S_FALSE)
1085                     return hr;
1086             }
1087         }
1088         hr = S_FALSE;
1089     }
1090 
1091     return hr;
1092 }
1093 
1094 HRESULT
1095 STDMETHODCALLTYPE
1096 CKsProxy::GetTimeFormat(
1097     GUID *pFormat)
1098 {
1099     KSPROPERTY Property;
1100     ULONG BytesReturned, Index;
1101     HRESULT hr;
1102 
1103     Property.Set = KSPROPSETID_MediaSeeking;
1104     Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT;
1105     Property.Flags = KSPROPERTY_TYPE_GET;
1106 
1107 #ifdef KSPROXY_TRACE
1108     OutputDebugStringW(L"CKsProxy::GetTimeFormat\n");
1109 #endif
1110 
1111     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned);
1112     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1113     {
1114         // check if plugins support it
1115         for(Index = 0; Index < m_Plugins.size(); Index++)
1116         {
1117             hr = E_NOTIMPL;
1118             // get plugin
1119             IUnknown * Plugin = m_Plugins[Index];
1120 
1121             if (!Plugin)
1122                continue;
1123 
1124             // query for IMediaSeeking interface
1125             IMediaSeeking *pSeek = NULL;
1126             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1127             if (SUCCEEDED(hr))
1128             {
1129                 // set time format
1130                 hr = pSeek->GetTimeFormat(pFormat);
1131                 // release IMediaSeeking interface
1132                 pSeek->Release();
1133 
1134                 if (hr != S_FALSE)
1135                     break;
1136             }
1137         }
1138     }
1139     return hr;
1140 }
1141 
1142 HRESULT
1143 STDMETHODCALLTYPE
1144 CKsProxy::IsUsingTimeFormat(
1145     const GUID *pFormat)
1146 {
1147     GUID Format;
1148 
1149 #ifdef KSPROXY_TRACE
1150     OutputDebugStringW(L"CKsProxy::IsUsingTimeFormat\n");
1151 #endif
1152 
1153     if (FAILED(QueryPreferredFormat(&Format)))
1154         return S_FALSE;
1155 
1156     if (IsEqualGUID(Format, *pFormat))
1157         return S_OK;
1158     else
1159         return S_FALSE;
1160 }
1161 
1162 HRESULT
1163 STDMETHODCALLTYPE
1164 CKsProxy::SetTimeFormat(
1165     const GUID *pFormat)
1166 {
1167     KSPROPERTY Property;
1168     ULONG BytesReturned, Index;
1169     HRESULT hr;
1170 
1171     Property.Set = KSPROPSETID_MediaSeeking;
1172     Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT;
1173     Property.Flags = KSPROPERTY_TYPE_SET;
1174 
1175 #ifdef KSPROXY_TRACE
1176     OutputDebugStringW(L"CKsProxy::SetTimeFormat\n");
1177 #endif
1178 
1179     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned);
1180     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1181     {
1182         // check if plugins support it
1183         for(Index = 0; Index < m_Plugins.size(); Index++)
1184         {
1185             hr = E_NOTIMPL;
1186             // get plugin
1187             IUnknown * Plugin = m_Plugins[Index];
1188 
1189             if (!Plugin)
1190                continue;
1191 
1192             // query for IMediaSeeking interface
1193             IMediaSeeking *pSeek = NULL;
1194             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1195             if (FAILED(hr))
1196             {
1197                 //not supported
1198                 break;
1199             }
1200             // set time format
1201             hr = pSeek->SetTimeFormat(pFormat);
1202             // release IMediaSeeking interface
1203             pSeek->Release();
1204 
1205             if (FAILED(hr))
1206                 break;
1207         }
1208     }
1209     return hr;
1210 }
1211 
1212 HRESULT
1213 STDMETHODCALLTYPE
1214 CKsProxy::GetDuration(
1215     LONGLONG *pDuration)
1216 {
1217     KSPROPERTY Property;
1218     ULONG BytesReturned, Index;
1219     HRESULT hr;
1220 
1221     Property.Set = KSPROPSETID_MediaSeeking;
1222     Property.Id = KSPROPERTY_MEDIASEEKING_DURATION;
1223     Property.Flags = KSPROPERTY_TYPE_GET;
1224 
1225 #ifdef KSPROXY_TRACE
1226     OutputDebugStringW(L"CKsProxy::GetDuration\n");
1227 #endif
1228 
1229     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pDuration, sizeof(LONGLONG), &BytesReturned);
1230     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1231     {
1232         // check if plugins support it
1233         for(Index = 0; Index < m_Plugins.size(); Index++)
1234         {
1235             hr = E_NOTIMPL;
1236             // get plugin
1237             IUnknown * Plugin = m_Plugins[Index];
1238 
1239             if (!Plugin)
1240                continue;
1241 
1242             // query for IMediaSeeking interface
1243             IMediaSeeking *pSeek = NULL;
1244             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1245             if (SUCCEEDED(hr))
1246             {
1247                 // get duration
1248                 hr = pSeek->GetStopPosition(pDuration);
1249                 // release IMediaSeeking interface
1250                 pSeek->Release();
1251 
1252                 if (hr != S_FALSE) // plugin implements it
1253                      break;
1254             }
1255         }
1256     }
1257     return hr;
1258 }
1259 
1260 HRESULT
1261 STDMETHODCALLTYPE
1262 CKsProxy::GetStopPosition(
1263     LONGLONG *pStop)
1264 {
1265     KSPROPERTY Property;
1266     ULONG BytesReturned, Index;
1267     HRESULT hr;
1268 
1269     Property.Set = KSPROPSETID_MediaSeeking;
1270     Property.Id = KSPROPERTY_MEDIASEEKING_STOPPOSITION;
1271     Property.Flags = KSPROPERTY_TYPE_GET;
1272 
1273 #ifdef KSPROXY_TRACE
1274     OutputDebugStringW(L"CKsProxy::GetStopPosition\n");
1275 #endif
1276 
1277     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pStop, sizeof(LONGLONG), &BytesReturned);
1278     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1279     {
1280         // check if plugins support it
1281         for(Index = 0; Index < m_Plugins.size(); Index++)
1282         {
1283             hr = E_NOTIMPL;
1284             // get plugin
1285             IUnknown * Plugin = m_Plugins[Index];
1286 
1287             if (!Plugin)
1288                continue;
1289 
1290             // query for IMediaSeeking interface
1291             IMediaSeeking *pSeek = NULL;
1292             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1293             if (SUCCEEDED(hr))
1294             {
1295                 // get stop position
1296                 hr = pSeek->GetStopPosition(pStop);
1297                 // release IMediaSeeking interface
1298                 pSeek->Release();
1299 
1300                 if (hr != S_FALSE) // plugin implements it
1301                      break;
1302             }
1303         }
1304     }
1305     return hr;
1306 }
1307 
1308 HRESULT
1309 STDMETHODCALLTYPE
1310 CKsProxy::GetCurrentPosition(
1311     LONGLONG *pCurrent)
1312 {
1313     KSPROPERTY Property;
1314     ULONG BytesReturned, Index;
1315     HRESULT hr;
1316 
1317     Property.Set = KSPROPSETID_MediaSeeking;
1318     Property.Id = KSPROPERTY_MEDIASEEKING_POSITION;
1319     Property.Flags = KSPROPERTY_TYPE_GET;
1320 
1321 #ifdef KSPROXY_TRACE
1322     OutputDebugStringW(L"CKsProxy::GetCurrentPosition\n");
1323 #endif
1324 
1325     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pCurrent, sizeof(LONGLONG), &BytesReturned);
1326     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1327     {
1328         // check if plugins support it
1329         for(Index = 0; Index < m_Plugins.size(); Index++)
1330         {
1331             hr = E_NOTIMPL;
1332             // get plugin
1333             IUnknown * Plugin = m_Plugins[Index];
1334 
1335             if (!Plugin)
1336                continue;
1337 
1338             // query for IMediaSeeking interface
1339             IMediaSeeking *pSeek = NULL;
1340             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1341             if (SUCCEEDED(hr))
1342             {
1343                 // get current position
1344                 hr = pSeek->GetCurrentPosition(pCurrent);
1345                 // release IMediaSeeking interface
1346                 pSeek->Release();
1347 
1348                 if (hr != S_FALSE) // plugin implements it
1349                      break;
1350             }
1351         }
1352     }
1353     return hr;
1354 }
1355 
1356 HRESULT
1357 STDMETHODCALLTYPE
1358 CKsProxy::ConvertTimeFormat(
1359     LONGLONG *pTarget,
1360     const GUID *pTargetFormat,
1361     LONGLONG Source,
1362     const GUID *pSourceFormat)
1363 {
1364     KSP_TIMEFORMAT Property;
1365     ULONG BytesReturned, Index;
1366     GUID SourceFormat, TargetFormat;
1367     HRESULT hr;
1368 
1369     Property.Property.Set = KSPROPSETID_MediaSeeking;
1370     Property.Property.Id = KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT;
1371     Property.Property.Flags = KSPROPERTY_TYPE_GET;
1372 
1373 #ifdef KSPROXY_TRACE
1374     OutputDebugStringW(L"CKsProxy::ConvertTimeFormat\n");
1375 #endif
1376 
1377     if (!pTargetFormat)
1378     {
1379         // get current format
1380         hr = GetTimeFormat(&TargetFormat);
1381         if (FAILED(hr))
1382             return hr;
1383 
1384         pTargetFormat = &TargetFormat;
1385     }
1386 
1387     if (!pSourceFormat)
1388     {
1389         // get current format
1390         hr = GetTimeFormat(&SourceFormat);
1391         if (FAILED(hr))
1392             return hr;
1393 
1394         pSourceFormat = &SourceFormat;
1395     }
1396 
1397     Property.SourceFormat = *pSourceFormat;
1398     Property.TargetFormat = *pTargetFormat;
1399     Property.Time = Source;
1400 
1401 
1402     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_TIMEFORMAT), (PVOID)pTarget, sizeof(LONGLONG), &BytesReturned);
1403     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1404     {
1405         //default error
1406         hr = E_NOTIMPL;
1407 
1408         // check if plugins support it
1409         for(Index = 0; Index < m_Plugins.size(); Index++)
1410         {
1411             // get plugin
1412             IUnknown * Plugin = m_Plugins[Index];
1413 
1414             if (!Plugin)
1415                continue;
1416 
1417             // query for IMediaSeeking interface
1418             IMediaSeeking *pSeek = NULL;
1419             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1420             if (SUCCEEDED(hr))
1421             {
1422                 // convert time format
1423                 hr = pSeek->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
1424                 // release IMediaSeeking interface
1425                 pSeek->Release();
1426 
1427                 if (hr != S_FALSE) // plugin implements it
1428                      break;
1429             }
1430         }
1431     }
1432 
1433     return hr;
1434 }
1435 
1436 HRESULT
1437 STDMETHODCALLTYPE
1438 CKsProxy::SetPositions(
1439     LONGLONG *pCurrent,
1440     DWORD dwCurrentFlags,
1441     LONGLONG *pStop,
1442     DWORD dwStopFlags)
1443 {
1444     KSPROPERTY Property;
1445     KSPROPERTY_POSITIONS Positions;
1446     ULONG BytesReturned, Index;
1447     HRESULT hr;
1448 
1449     Property.Set = KSPROPSETID_MediaSeeking;
1450     Property.Id = KSPROPERTY_MEDIASEEKING_POSITIONS;
1451     Property.Flags = KSPROPERTY_TYPE_SET;
1452 
1453     Positions.Current = *pCurrent;
1454     Positions.CurrentFlags = (KS_SEEKING_FLAGS)dwCurrentFlags;
1455     Positions.Stop = *pStop;
1456     Positions.StopFlags = (KS_SEEKING_FLAGS)dwStopFlags;
1457 
1458 #ifdef KSPROXY_TRACE
1459     OutputDebugStringW(L"CKsProxy::SetPositions\n");
1460 #endif
1461 
1462     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Positions, sizeof(KSPROPERTY_POSITIONS), &BytesReturned);
1463     if (SUCCEEDED(hr))
1464     {
1465         if (dwCurrentFlags & AM_SEEKING_ReturnTime)
1466         {
1467             // retrieve current position
1468             hr = GetCurrentPosition(pCurrent);
1469         }
1470 
1471         if (SUCCEEDED(hr))
1472         {
1473             if (dwStopFlags & AM_SEEKING_ReturnTime)
1474             {
1475                 // retrieve current position
1476                 hr = GetStopPosition(pStop);
1477             }
1478         }
1479         return hr;
1480     }
1481     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1482     {
1483         hr = E_NOTIMPL;
1484 
1485         // check if plugins support it
1486         for(Index = 0; Index < m_Plugins.size(); Index++)
1487         {
1488             // get plugin
1489             IUnknown * Plugin = m_Plugins[Index];
1490 
1491             if (!Plugin)
1492                continue;
1493 
1494             // query for IMediaSeeking interface
1495             IMediaSeeking *pSeek = NULL;
1496             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1497             if (SUCCEEDED(hr))
1498             {
1499                 // set positions
1500                 hr = pSeek->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
1501                 // release IMediaSeeking interface
1502                 pSeek->Release();
1503 
1504                 if (FAILED(hr))
1505                     break;
1506             }
1507         }
1508     }
1509 
1510     return hr;
1511 }
1512 
1513 HRESULT
1514 STDMETHODCALLTYPE
1515 CKsProxy::GetPositions(
1516     LONGLONG *pCurrent,
1517     LONGLONG *pStop)
1518 {
1519     HRESULT hr;
1520 
1521 #ifdef KSPROXY_TRACE
1522     OutputDebugStringW(L"CKsProxy::GetPositions\n");
1523 #endif
1524 
1525     hr = GetCurrentPosition(pCurrent);
1526     if (SUCCEEDED(hr))
1527         hr = GetStopPosition(pStop);
1528 
1529     return hr;
1530 }
1531 
1532 HRESULT
1533 STDMETHODCALLTYPE
1534 CKsProxy::GetAvailable(
1535     LONGLONG *pEarliest,
1536     LONGLONG *pLatest)
1537 {
1538     KSPROPERTY Property;
1539     KSPROPERTY_MEDIAAVAILABLE Media;
1540     ULONG BytesReturned, Index;
1541     HRESULT hr;
1542 
1543     Property.Set = KSPROPSETID_MediaSeeking;
1544     Property.Id = KSPROPERTY_MEDIASEEKING_AVAILABLE;
1545     Property.Flags = KSPROPERTY_TYPE_GET;
1546 
1547 #ifdef KSPROXY_TRACE
1548     OutputDebugStringW(L"CKsProxy::GetAvailable\n");
1549 #endif
1550 
1551     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Media, sizeof(KSPROPERTY_MEDIAAVAILABLE), &BytesReturned);
1552     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1553     {
1554         // check if plugins support it
1555         for(Index = 0; Index < m_Plugins.size(); Index++)
1556         {
1557             hr = E_NOTIMPL;
1558             // get plugin
1559             IUnknown * Plugin = m_Plugins[Index];
1560 
1561             if (!Plugin)
1562                continue;
1563 
1564             // query for IMediaSeeking interface
1565             IMediaSeeking *pSeek = NULL;
1566             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1567             if (SUCCEEDED(hr))
1568             {
1569                 // delegate call
1570                 hr = pSeek->GetAvailable(pEarliest, pLatest);
1571                 // release IMediaSeeking interface
1572                 pSeek->Release();
1573 
1574                 if (hr != S_FALSE) // plugin implements it
1575                      break;
1576             }
1577         }
1578     }
1579     else if (SUCCEEDED(hr))
1580     {
1581         *pEarliest = Media.Earliest;
1582         *pLatest = Media.Latest;
1583     }
1584 
1585     return hr;
1586 }
1587 
1588 HRESULT
1589 STDMETHODCALLTYPE
1590 CKsProxy::SetRate(
1591     double dRate)
1592 {
1593 #ifdef KSPROXY_TRACE
1594     OutputDebugStringW(L"CKsProxy::SetRate\n");
1595 #endif
1596     return E_NOTIMPL;
1597 }
1598 
1599 HRESULT
1600 STDMETHODCALLTYPE
1601 CKsProxy::GetRate(
1602     double *pdRate)
1603 {
1604 #ifdef KSPROXY_TRACE
1605     OutputDebugStringW(L"CKsProxy::GetRate\n");
1606 #endif
1607     return E_NOTIMPL;
1608 }
1609 
1610 HRESULT
1611 STDMETHODCALLTYPE
1612 CKsProxy::GetPreroll(
1613     LONGLONG *pllPreroll)
1614 {
1615     KSPROPERTY Property;
1616     ULONG BytesReturned, Index;
1617     HRESULT hr;
1618 
1619     Property.Set = KSPROPSETID_MediaSeeking;
1620     Property.Id = KSPROPERTY_MEDIASEEKING_PREROLL;
1621     Property.Flags = KSPROPERTY_TYPE_GET;
1622 
1623 #ifdef KSPROXY_TRACE
1624     OutputDebugStringW(L"CKsProxy::GetPreroll\n");
1625 #endif
1626 
1627     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pllPreroll, sizeof(LONGLONG), &BytesReturned);
1628     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1629     {
1630         // check if all plugins support it
1631         for(Index = 0; Index < m_Plugins.size(); Index++)
1632         {
1633             // get plugin
1634             IUnknown * Plugin = m_Plugins[Index];
1635 
1636             if (!Plugin)
1637                continue;
1638 
1639             // query for IMediaSeeking interface
1640             IMediaSeeking *pSeek = NULL;
1641             hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1642             if (SUCCEEDED(hr))
1643             {
1644                 // get preroll
1645                 hr = pSeek->GetPreroll(pllPreroll);
1646                 // release IMediaSeeking interface
1647                 pSeek->Release();
1648 
1649                 if (hr != S_FALSE) // plugin implements it
1650                      break;
1651             }
1652         }
1653         hr = E_NOTIMPL;
1654     }
1655     return hr;
1656 }
1657 
1658 //-------------------------------------------------------------------
1659 // IAMFilterMiscFlags interface
1660 //
1661 
1662 ULONG
1663 STDMETHODCALLTYPE
1664 CKsProxy::GetMiscFlags()
1665 {
1666     ULONG Index;
1667     ULONG Flags = 0;
1668     HRESULT hr;
1669     PIN_DIRECTION PinDirection;
1670     KSPIN_COMMUNICATION Communication;
1671 
1672 
1673     for(Index = 0; Index < m_Pins.size(); Index++)
1674     {
1675         // get current pin
1676         IPin * pin = m_Pins[Index];
1677         // query direction
1678         hr = pin->QueryDirection(&PinDirection);
1679         if (SUCCEEDED(hr))
1680         {
1681             if (PinDirection == PINDIR_INPUT)
1682             {
1683                 if (SUCCEEDED(GetPinCommunication(Index, //FIXME verify PinId
1684                                         &Communication)))
1685                 {
1686                     if (Communication != KSPIN_COMMUNICATION_NONE && Communication != KSPIN_COMMUNICATION_BRIDGE)
1687                     {
1688                         Flags |= AM_FILTER_MISC_FLAGS_IS_SOURCE;
1689                     }
1690                 }
1691             }
1692         }
1693     }
1694 
1695 #ifdef KSPROXY_TRACE
1696     WCHAR Buffer[100];
1697     swprintf(Buffer, L"CKsProxy::GetMiscFlags stub Flags %x\n", Flags);
1698     OutputDebugStringW(Buffer);
1699 #endif
1700 
1701     return Flags;
1702 }
1703 
1704 //-------------------------------------------------------------------
1705 // IKsControl
1706 //
1707 HRESULT
1708 STDMETHODCALLTYPE
1709 CKsProxy::KsProperty(
1710     PKSPROPERTY Property,
1711     ULONG PropertyLength,
1712     LPVOID PropertyData,
1713     ULONG DataLength,
1714     ULONG* BytesReturned)
1715 {
1716 #ifdef KSPROXY_TRACE
1717     OutputDebugStringW(L"CKsProxy::KsProperty\n");
1718 #endif
1719 
1720     assert(m_hDevice != 0);
1721     return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned);
1722 }
1723 
1724 HRESULT
1725 STDMETHODCALLTYPE
1726 CKsProxy::KsMethod(
1727     PKSMETHOD Method,
1728     ULONG MethodLength,
1729     LPVOID MethodData,
1730     ULONG DataLength,
1731     ULONG* BytesReturned)
1732 {
1733 #ifdef KSPROXY_TRACE
1734     OutputDebugStringW(L"CKsProxy::KsMethod\n");
1735 #endif
1736 
1737     assert(m_hDevice != 0);
1738     return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned);
1739 }
1740 
1741 HRESULT
1742 STDMETHODCALLTYPE
1743 CKsProxy::KsEvent(
1744     PKSEVENT Event,
1745     ULONG EventLength,
1746     LPVOID EventData,
1747     ULONG DataLength,
1748     ULONG* BytesReturned)
1749 {
1750 #ifdef KSPROXY_TRACE
1751     OutputDebugStringW(L"CKsProxy::KsEvent\n");
1752 #endif
1753 
1754     assert(m_hDevice != 0);
1755     if (EventLength)
1756         return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned);
1757     else
1758         return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_DISABLE_EVENT, (PVOID)Event, EventLength, NULL, 0, BytesReturned);
1759 }
1760 
1761 
1762 //-------------------------------------------------------------------
1763 // IKsPropertySet
1764 //
1765 HRESULT
1766 STDMETHODCALLTYPE
1767 CKsProxy::Set(
1768     REFGUID guidPropSet,
1769     DWORD dwPropID,
1770     LPVOID pInstanceData,
1771     DWORD cbInstanceData,
1772     LPVOID pPropData,
1773     DWORD cbPropData)
1774 {
1775     ULONG BytesReturned;
1776 
1777 #ifdef KSPROXY_TRACE
1778     OutputDebugStringW(L"CKsProxy::Set\n");
1779 #endif
1780 
1781     if (cbInstanceData)
1782     {
1783         PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
1784         if (!Property)
1785             return E_OUTOFMEMORY;
1786 
1787         Property->Set = guidPropSet;
1788         Property->Id = dwPropID;
1789         Property->Flags = KSPROPERTY_TYPE_SET;
1790 
1791         CopyMemory((Property+1), pInstanceData, cbInstanceData);
1792 
1793         HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
1794         CoTaskMemFree(Property);
1795         return hr;
1796     }
1797     else
1798     {
1799         KSPROPERTY Property;
1800 
1801         Property.Set = guidPropSet;
1802         Property.Id = dwPropID;
1803         Property.Flags = KSPROPERTY_TYPE_SET;
1804 
1805         HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
1806         return hr;
1807     }
1808 }
1809 
1810 HRESULT
1811 STDMETHODCALLTYPE
1812 CKsProxy::Get(
1813     REFGUID guidPropSet,
1814     DWORD dwPropID,
1815     LPVOID pInstanceData,
1816     DWORD cbInstanceData,
1817     LPVOID pPropData,
1818     DWORD cbPropData,
1819     DWORD *pcbReturned)
1820 {
1821     ULONG BytesReturned;
1822 
1823 #ifdef KSPROXY_TRACE
1824     OutputDebugStringW(L"CKsProxy::Get\n");
1825 #endif
1826 
1827     if (cbInstanceData)
1828     {
1829         PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
1830         if (!Property)
1831             return E_OUTOFMEMORY;
1832 
1833         Property->Set = guidPropSet;
1834         Property->Id = dwPropID;
1835         Property->Flags = KSPROPERTY_TYPE_GET;
1836 
1837         CopyMemory((Property+1), pInstanceData, cbInstanceData);
1838 
1839         HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
1840         CoTaskMemFree(Property);
1841         return hr;
1842     }
1843     else
1844     {
1845         KSPROPERTY Property;
1846 
1847         Property.Set = guidPropSet;
1848         Property.Id = dwPropID;
1849         Property.Flags = KSPROPERTY_TYPE_GET;
1850 
1851         HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
1852         return hr;
1853     }
1854 }
1855 
1856 HRESULT
1857 STDMETHODCALLTYPE
1858 CKsProxy::QuerySupported(
1859     REFGUID guidPropSet,
1860     DWORD dwPropID,
1861     DWORD *pTypeSupport)
1862 {
1863     KSPROPERTY Property;
1864     ULONG BytesReturned;
1865 
1866 #ifdef KSPROXY_TRACE
1867     OutputDebugStringW(L"CKsProxy::QuerySupported\n");
1868 #endif
1869 
1870     Property.Set = guidPropSet;
1871     Property.Id = dwPropID;
1872     Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
1873 
1874     return KsProperty(&Property, sizeof(KSPROPERTY), pTypeSupport, sizeof(DWORD), &BytesReturned);
1875 }
1876 
1877 
1878 //-------------------------------------------------------------------
1879 // IKsTopology interface
1880 //
1881 HRESULT
1882 STDMETHODCALLTYPE
1883 CKsProxy::CreateNodeInstance(
1884     ULONG NodeId,
1885     ULONG Flags,
1886     ACCESS_MASK DesiredAccess,
1887     IUnknown* UnkOuter,
1888     REFGUID InterfaceId,
1889     LPVOID* Interface)
1890 {
1891     HRESULT hr;
1892 
1893 #ifdef KSPROXY_TRACE
1894     OutputDebugStringW(L"CKsProxy::CreateNodeInstance\n");
1895 #endif
1896 
1897     *Interface = NULL;
1898 
1899     if (IsEqualIID(IID_IUnknown, InterfaceId) || !UnkOuter)
1900     {
1901         hr = CKsNode_Constructor(UnkOuter, m_hDevice, NodeId, DesiredAccess, InterfaceId, Interface);
1902     }
1903     else
1904     {
1905         // interface not supported
1906         hr = E_NOINTERFACE;
1907     }
1908 
1909     return hr;
1910 }
1911 
1912 //-------------------------------------------------------------------
1913 // IKsAggregateControl interface
1914 //
1915 HRESULT
1916 STDMETHODCALLTYPE
1917 CKsProxy::KsAddAggregate(
1918     IN REFGUID AggregateClass)
1919 {
1920 #ifdef KSPROXY_TRACE
1921     OutputDebugStringW(L"CKsProxy::KsAddAggregate NotImplemented\n");
1922 #endif
1923     return E_NOTIMPL;
1924 }
1925 
1926 HRESULT
1927 STDMETHODCALLTYPE
1928 CKsProxy::KsRemoveAggregate(
1929     REFGUID AggregateClass)
1930 {
1931 #ifdef KSPROXY_TRACE
1932     OutputDebugStringW(L"CKsProxy::KsRemoveAggregate NotImplemented\n");
1933 #endif
1934 
1935     return E_NOTIMPL;
1936 }
1937 
1938 
1939 //-------------------------------------------------------------------
1940 // IPersistStream interface
1941 //
1942 
1943 HRESULT
1944 STDMETHODCALLTYPE
1945 CKsProxy::IsDirty()
1946 {
1947 #ifdef KSPROXY_TRACE
1948     OutputDebugStringW(L"CKsProxy::IsDirty Notimplemented\n");
1949 #endif
1950     return E_NOTIMPL;
1951 }
1952 
1953 HRESULT
1954 STDMETHODCALLTYPE
1955 CKsProxy::Load(
1956     IStream *pStm)
1957 {
1958     HRESULT hr;
1959     WCHAR Buffer[1000];
1960     AM_MEDIA_TYPE MediaType;
1961     ULONG BytesReturned;
1962     LONG Length;
1963 
1964     ULONG PinId;
1965     LPOLESTR pMajor, pSub, pFormat;
1966 
1967 #ifdef KSPROXY_TRACE
1968     OutputDebugStringW(L"CKsProxy::Load\n");
1969 #endif
1970 
1971 #if 0
1972     ULONG Version = ReadInt(pStm, hr);
1973     if (Version != 1)
1974         return E_FAIL;
1975 #endif
1976 
1977     hr = pStm->Read(&Length, sizeof(ULONG), &BytesReturned);
1978     swprintf(Buffer, L"Length hr %x hr length %lu\n", hr, Length);
1979     OutputDebugStringW(Buffer);
1980 
1981     do
1982     {
1983         hr = pStm->Read(&PinId, sizeof(ULONG), &BytesReturned);
1984         swprintf(Buffer, L"Read: hr %08x PinId %lx BytesReturned %lu\n", hr, PinId, BytesReturned);
1985         OutputDebugStringW(Buffer);
1986 
1987         if (FAILED(hr) || !BytesReturned)
1988             break;
1989 
1990         Length -= BytesReturned;
1991 
1992         hr = pStm->Read(&MediaType, sizeof(AM_MEDIA_TYPE), &BytesReturned);
1993         if (FAILED(hr) || BytesReturned != sizeof(AM_MEDIA_TYPE))
1994         {
1995             swprintf(Buffer, L"Read failed with %lx\n", hr);
1996             OutputDebugStringW(Buffer);
1997             break;
1998         }
1999 
2000 
2001         StringFromIID(MediaType.majortype, &pMajor);
2002         StringFromIID(MediaType.subtype , &pSub);
2003         StringFromIID(MediaType.formattype, &pFormat);
2004 
2005         swprintf(Buffer, L"BytesReturned %lu majortype %s subtype %s bFixedSizeSamples %u bTemporalCompression %u lSampleSize %u formattype %s, pUnk %p cbFormat %u pbFormat %p\n", BytesReturned, pMajor, pSub, MediaType.bFixedSizeSamples, MediaType.bTemporalCompression, MediaType.lSampleSize, pFormat, MediaType.pUnk, MediaType.cbFormat, MediaType.pbFormat);
2006         OutputDebugStringW(Buffer);
2007 
2008         Length -= BytesReturned;
2009 
2010 
2011         if (MediaType.cbFormat)
2012         {
2013             MediaType.pbFormat = (BYTE*)CoTaskMemAlloc(MediaType.cbFormat);
2014             if (!MediaType.pbFormat)
2015                 return E_OUTOFMEMORY;
2016 
2017             hr = pStm->Read(&MediaType.pbFormat, sizeof(MediaType.cbFormat), &BytesReturned);
2018             if (FAILED(hr))
2019             {
2020                 swprintf(Buffer, L"ReadFormat failed with %lx\n", hr);
2021                 OutputDebugStringW(Buffer);
2022                 break;
2023             }
2024             Length -= BytesReturned;
2025         }
2026 
2027     }while(Length > 0);
2028 
2029     return S_OK;
2030 }
2031 
2032 HRESULT
2033 STDMETHODCALLTYPE
2034 CKsProxy::Save(
2035     IStream *pStm,
2036     BOOL fClearDirty)
2037 {
2038 #ifdef KSPROXY_TRACE
2039     OutputDebugStringW(L"CKsProxy::Save Notimplemented\n");
2040 #endif
2041 
2042     return E_NOTIMPL;
2043 }
2044 
2045 HRESULT
2046 STDMETHODCALLTYPE
2047 CKsProxy::GetSizeMax(
2048     ULARGE_INTEGER *pcbSize)
2049 {
2050 #ifdef KSPROXY_TRACE
2051     OutputDebugStringW(L"CKsProxy::GetSizeMax Notimplemented\n");
2052 #endif
2053 
2054     return E_NOTIMPL;
2055 }
2056 
2057 //-------------------------------------------------------------------
2058 // IAMDeviceRemoval interface
2059 //
2060 
2061 HRESULT
2062 STDMETHODCALLTYPE
2063 CKsProxy::DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink)
2064 {
2065 #ifdef KSPROXY_TRACE
2066     OutputDebugStringW(L"CKsProxy::DeviceInfo\n");
2067 #endif
2068 
2069     if (!m_DevicePath)
2070     {
2071         // object not initialized
2072         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
2073     }
2074 
2075     // copy device interface guid
2076     CopyMemory(pclsidInterfaceClass, &m_DeviceInterfaceGUID, sizeof(GUID));
2077 
2078     if (pwszSymbolicLink)
2079     {
2080         *pwszSymbolicLink = (LPWSTR)CoTaskMemAlloc((wcslen(m_DevicePath)+1) * sizeof(WCHAR));
2081         if (!*pwszSymbolicLink)
2082             return E_OUTOFMEMORY;
2083 
2084         wcscpy(*pwszSymbolicLink, m_DevicePath);
2085     }
2086     return S_OK;
2087 }
2088 HRESULT
2089 STDMETHODCALLTYPE
2090 CKsProxy::Reassociate(void)
2091 {
2092 #ifdef KSPROXY_TRACE
2093     OutputDebugStringW(L"CKsProxy::Reassociate\n");
2094 #endif
2095 
2096     if (!m_DevicePath || m_hDevice)
2097     {
2098         // file path not available
2099         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
2100     }
2101 
2102     m_hDevice = CreateFileW(m_DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
2103     if (!m_hDevice)
2104     {
2105         // failed to open device
2106         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
2107     }
2108 
2109     // success
2110     return NOERROR;
2111 }
2112 
2113 HRESULT
2114 STDMETHODCALLTYPE
2115 CKsProxy::Disassociate(void)
2116 {
2117 #ifdef KSPROXY_TRACE
2118     OutputDebugStringW(L"CKsProxy::Disassociate\n");
2119 #endif
2120 
2121     if (!m_hDevice)
2122         return E_HANDLE;
2123 
2124     CloseHandle(m_hDevice);
2125     m_hDevice = NULL;
2126     return NOERROR;
2127 }
2128 
2129 //-------------------------------------------------------------------
2130 // IKsClock interface
2131 //
2132 
2133 HANDLE
2134 STDMETHODCALLTYPE
2135 CKsProxy::KsGetClockHandle()
2136 {
2137 #ifdef KSPROXY_TRACE
2138     OutputDebugStringW(L"CKsProxy::KsGetClockHandle\n");
2139 #endif
2140 
2141     return m_hClock;
2142 }
2143 
2144 
2145 //-------------------------------------------------------------------
2146 // IKsObject interface
2147 //
2148 
2149 HANDLE
2150 STDMETHODCALLTYPE
2151 CKsProxy::KsGetObjectHandle()
2152 {
2153 #ifdef KSPROXY_TRACE
2154     OutputDebugStringW(L"CKsProxy::KsGetObjectHandle\n");
2155 #endif
2156 
2157     return m_hDevice;
2158 }
2159 
2160 //-------------------------------------------------------------------
2161 // IPersistPropertyBag interface
2162 //
2163 HRESULT
2164 STDMETHODCALLTYPE
2165 CKsProxy::InitNew( void)
2166 {
2167 #ifdef KSPROXY_TRACE
2168     OutputDebugStringW(L"CKsProxy::InitNew\n");
2169 #endif
2170 
2171     return S_OK;
2172 }
2173 
2174 HRESULT
2175 STDMETHODCALLTYPE
2176 CKsProxy::GetSupportedSets(
2177     LPGUID * pOutGuid,
2178     PULONG NumGuids)
2179 {
2180     KSPROPERTY Property;
2181     LPGUID pGuid;
2182     ULONG NumProperty = 0;
2183     ULONG NumMethods = 0;
2184     ULONG NumEvents = 0;
2185     ULONG Length;
2186     ULONG BytesReturned;
2187     HRESULT hr;
2188 
2189     Property.Set = GUID_NULL;
2190     Property.Id = 0;
2191     Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
2192 
2193     KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumProperty);
2194     KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumMethods);
2195     KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumEvents);
2196 
2197     Length = NumProperty + NumMethods + NumEvents;
2198 
2199     // allocate guid buffer
2200     pGuid = (LPGUID)CoTaskMemAlloc(Length);
2201     if (!pGuid)
2202     {
2203         // failed
2204         return E_OUTOFMEMORY;
2205     }
2206 
2207     NumProperty /= sizeof(GUID);
2208     NumMethods /= sizeof(GUID);
2209     NumEvents /= sizeof(GUID);
2210 
2211     // get all properties
2212     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pGuid, Length, &BytesReturned);
2213     if (FAILED(hr))
2214     {
2215         CoTaskMemFree(pGuid);
2216         return E_FAIL;
2217     }
2218     Length -= BytesReturned;
2219 
2220     // get all methods
2221     if (Length)
2222     {
2223         hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty], Length, &BytesReturned);
2224         if (FAILED(hr))
2225         {
2226             CoTaskMemFree(pGuid);
2227             return E_FAIL;
2228         }
2229         Length -= BytesReturned;
2230     }
2231 
2232     // get all events
2233     if (Length)
2234     {
2235         hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty+NumMethods], Length, &BytesReturned);
2236         if (FAILED(hr))
2237         {
2238             CoTaskMemFree(pGuid);
2239             return E_FAIL;
2240         }
2241         Length -= BytesReturned;
2242     }
2243 
2244 #ifdef KSPROXY_TRACE
2245     WCHAR Buffer[200];
2246     swprintf(Buffer, L"NumProperty %lu NumMethods %lu NumEvents %lu\n", NumProperty, NumMethods, NumEvents);
2247     OutputDebugStringW(Buffer);
2248 #endif
2249 
2250     *pOutGuid = pGuid;
2251     *NumGuids = NumProperty+NumEvents+NumMethods;
2252     return S_OK;
2253 }
2254 
2255 HRESULT
2256 STDMETHODCALLTYPE
2257 CKsProxy::LoadProxyPlugins(
2258     LPGUID pGuids,
2259     ULONG NumGuids)
2260 {
2261     ULONG Index;
2262     LPOLESTR pStr;
2263     HKEY hKey, hSubKey;
2264     HRESULT hr;
2265     IUnknown * pUnknown;
2266 
2267     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\MediaInterfaces", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2268     {
2269         OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed to open MediaInterfaces key\n");
2270         return E_FAIL;
2271     }
2272 
2273     // enumerate all sets
2274     for(Index = 0; Index < NumGuids; Index++)
2275     {
2276         // convert to string
2277         hr = StringFromCLSID(pGuids[Index], &pStr);
2278         if (FAILED(hr))
2279             return E_FAIL;
2280 
2281         // now try open class key
2282         if (RegOpenKeyExW(hKey, pStr, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
2283         {
2284             // no plugin for that set exists
2285             CoTaskMemFree(pStr);
2286             continue;
2287         }
2288 
2289         // try load plugin
2290         hr = CoCreateInstance(pGuids[Index], (IBaseFilter*)this, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
2291         if (SUCCEEDED(hr))
2292         {
2293             // store plugin
2294             m_Plugins.push_back(pUnknown);
2295         }
2296         // close key
2297         RegCloseKey(hSubKey);
2298     }
2299 
2300     // close media interfaces key
2301     RegCloseKey(hKey);
2302     return S_OK;
2303 }
2304 
2305 HRESULT
2306 STDMETHODCALLTYPE
2307 CKsProxy::GetNumberOfPins(
2308     PULONG NumPins)
2309 {
2310     KSPROPERTY Property;
2311     ULONG BytesReturned;
2312 
2313     // setup request
2314     Property.Set = KSPROPSETID_Pin;
2315     Property.Id = KSPROPERTY_PIN_CTYPES;
2316     Property.Flags = KSPROPERTY_TYPE_GET;
2317 
2318     return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)NumPins, sizeof(ULONG), &BytesReturned);
2319 }
2320 
2321 HRESULT
2322 STDMETHODCALLTYPE
2323 CKsProxy::GetPinInstanceCount(
2324     ULONG PinId,
2325     PKSPIN_CINSTANCES Instances)
2326 {
2327     KSP_PIN Property;
2328     ULONG BytesReturned;
2329 
2330     // setup request
2331     Property.Property.Set = KSPROPSETID_Pin;
2332     Property.Property.Id = KSPROPERTY_PIN_CINSTANCES;
2333     Property.Property.Flags = KSPROPERTY_TYPE_GET;
2334     Property.PinId = PinId;
2335     Property.Reserved = 0;
2336 
2337     return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Instances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
2338 }
2339 
2340 HRESULT
2341 STDMETHODCALLTYPE
2342 CKsProxy::GetPinCommunication(
2343     ULONG PinId,
2344     KSPIN_COMMUNICATION * Communication)
2345 {
2346     KSP_PIN Property;
2347     ULONG BytesReturned;
2348 
2349     // setup request
2350     Property.Property.Set = KSPROPSETID_Pin;
2351     Property.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
2352     Property.Property.Flags = KSPROPERTY_TYPE_GET;
2353     Property.PinId = PinId;
2354     Property.Reserved = 0;
2355 
2356     return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
2357 }
2358 
2359 HRESULT
2360 STDMETHODCALLTYPE
2361 CKsProxy::GetPinDataflow(
2362     ULONG PinId,
2363     KSPIN_DATAFLOW * DataFlow)
2364 {
2365     KSP_PIN Property;
2366     ULONG BytesReturned;
2367 
2368     // setup request
2369     Property.Property.Set = KSPROPSETID_Pin;
2370     Property.Property.Id = KSPROPERTY_PIN_DATAFLOW;
2371     Property.Property.Flags = KSPROPERTY_TYPE_GET;
2372     Property.PinId = PinId;
2373     Property.Reserved = 0;
2374 
2375     return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
2376 }
2377 
2378 HRESULT
2379 STDMETHODCALLTYPE
2380 CKsProxy::GetPinName(
2381     ULONG PinId,
2382     KSPIN_DATAFLOW DataFlow,
2383     ULONG PinCount,
2384     LPWSTR * OutPinName)
2385 {
2386     KSP_PIN Property;
2387     LPWSTR PinName;
2388     ULONG BytesReturned;
2389     HRESULT hr;
2390     WCHAR Buffer[100];
2391 
2392     // setup request
2393     Property.Property.Set = KSPROPSETID_Pin;
2394     Property.Property.Id = KSPROPERTY_PIN_NAME;
2395     Property.Property.Flags = KSPROPERTY_TYPE_GET;
2396     Property.PinId = PinId;
2397     Property.Reserved = 0;
2398 
2399     // #1 try get it from pin directly
2400     hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
2401 
2402     if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA))
2403     {
2404         // allocate pin name
2405         PinName = (LPWSTR)CoTaskMemAlloc(BytesReturned);
2406         if (!PinName)
2407             return E_OUTOFMEMORY;
2408 
2409         // retry with allocated buffer
2410         hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), PinName, BytesReturned, &BytesReturned);
2411         if (SUCCEEDED(hr))
2412         {
2413             *OutPinName = PinName;
2414             return hr;
2415         }
2416 
2417         //free buffer
2418         CoTaskMemFree(PinName);
2419     }
2420 
2421     //
2422     // TODO: retrieve pin name from topology node
2423     //
2424 
2425     if (DataFlow == KSPIN_DATAFLOW_IN)
2426     {
2427         swprintf(Buffer, L"Input%lu", PinCount);
2428     }
2429     else
2430     {
2431         swprintf(Buffer, L"Output%lu", PinCount);
2432     }
2433 
2434     // allocate pin name
2435     PinName = (LPWSTR)CoTaskMemAlloc((wcslen(Buffer)+1) * sizeof(WCHAR));
2436     if (!PinName)
2437         return E_OUTOFMEMORY;
2438 
2439     // copy pin name
2440     wcscpy(PinName, Buffer);
2441 
2442     // store result
2443     *OutPinName = PinName;
2444     // done
2445     return S_OK;
2446 }
2447 
2448 HRESULT
2449 STDMETHODCALLTYPE
2450 CKsProxy::CreatePins()
2451 {
2452     ULONG NumPins, Index;
2453     KSPIN_CINSTANCES Instances;
2454     KSPIN_DATAFLOW DataFlow;
2455     KSPIN_COMMUNICATION Communication;
2456     HRESULT hr;
2457     LPWSTR PinName;
2458     IPin * pPin;
2459     ULONG InputPin = 0;
2460     ULONG OutputPin = 0;
2461 
2462     // get number of pins
2463     hr = GetNumberOfPins(&NumPins);
2464     if (FAILED(hr))
2465         return hr;
2466 
2467     for(Index = 0; Index < NumPins; Index++)
2468     {
2469         // query current instance count
2470         hr = GetPinInstanceCount(Index, &Instances);
2471         if (FAILED(hr))
2472         {
2473 #ifdef KSPROXY_TRACE
2474             WCHAR Buffer[100];
2475             swprintf(Buffer, L"CKsProxy::CreatePins GetPinInstanceCount failed with %lx\n", hr);
2476             OutputDebugStringW(Buffer);
2477 #endif
2478             continue;
2479         }
2480 
2481 
2482         // query pin communication;
2483         hr = GetPinCommunication(Index, &Communication);
2484         if (FAILED(hr))
2485         {
2486 #ifdef KSPROXY_TRACE
2487             WCHAR Buffer[100];
2488             swprintf(Buffer, L"CKsProxy::CreatePins GetPinCommunication failed with %lx\n", hr);
2489             OutputDebugStringW(Buffer);
2490 #endif
2491             continue;
2492         }
2493 
2494         if (Instances.CurrentCount == Instances.PossibleCount)
2495         {
2496             // already maximum reached for this pin
2497 #ifdef KSPROXY_TRACE
2498             WCHAR Buffer[100];
2499             swprintf(Buffer, L"CKsProxy::CreatePins Instances.CurrentCount == Instances.PossibleCount\n");
2500             OutputDebugStringW(Buffer);
2501 #endif
2502             continue;
2503         }
2504 
2505         // get direction of pin
2506         hr = GetPinDataflow(Index, &DataFlow);
2507         if (FAILED(hr))
2508         {
2509 #ifdef KSPROXY_TRACE
2510             WCHAR Buffer[100];
2511             swprintf(Buffer, L"CKsProxy::CreatePins GetPinDataflow failed with %lx\n", hr);
2512             OutputDebugStringW(Buffer);
2513 #endif
2514             continue;
2515         }
2516 
2517         if (DataFlow == KSPIN_DATAFLOW_IN)
2518             hr = GetPinName(Index, DataFlow, InputPin, &PinName);
2519         else
2520             hr = GetPinName(Index, DataFlow, OutputPin, &PinName);
2521 
2522         if (FAILED(hr))
2523         {
2524 #ifdef KSPROXY_TRACE
2525             WCHAR Buffer[100];
2526             swprintf(Buffer, L"CKsProxy::CreatePins GetPinName failed with %lx\n", hr);
2527             OutputDebugStringW(Buffer);
2528 #endif
2529             continue;
2530         }
2531 
2532         // construct the pins
2533         if (DataFlow == KSPIN_DATAFLOW_IN)
2534         {
2535             hr = CInputPin_Constructor((IBaseFilter*)this, PinName, m_hDevice, Index, Communication, IID_IPin, (void**)&pPin);
2536             if (FAILED(hr))
2537             {
2538 #ifdef KSPROXY_TRACE
2539                 WCHAR Buffer[100];
2540                 swprintf(Buffer, L"CKsProxy::CreatePins CInputPin_Constructor failed with %lx\n", hr);
2541                 OutputDebugStringW(Buffer);
2542 #endif
2543                 CoTaskMemFree(PinName);
2544                 continue;
2545             }
2546             InputPin++;
2547         }
2548         else
2549         {
2550             hr = COutputPin_Constructor((IBaseFilter*)this, PinName, Index, Communication, IID_IPin, (void**)&pPin);
2551             if (FAILED(hr))
2552             {
2553 #ifdef KSPROXY_TRACE
2554                 WCHAR Buffer[100];
2555                 swprintf(Buffer, L"CKsProxy::CreatePins COutputPin_Constructor failed with %lx\n", hr);
2556                 OutputDebugStringW(Buffer);
2557 #endif
2558                 CoTaskMemFree(PinName);
2559                 continue;
2560             }
2561             OutputPin++;
2562         }
2563 
2564         // store pins
2565         m_Pins.push_back(pPin);
2566 
2567 #ifdef KSPROXY_TRACE
2568         WCHAR Buffer[100];
2569         swprintf(Buffer, L"Index %lu DataFlow %lu Name %s\n", Index, DataFlow, PinName);
2570         OutputDebugStringW(Buffer);
2571 #endif
2572 
2573     }
2574 
2575     return S_OK;
2576 }
2577 
2578 HRESULT
2579 STDMETHODCALLTYPE
2580 CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
2581 {
2582     HRESULT hr;
2583     VARIANT varName;
2584     LPGUID pGuid;
2585     ULONG NumGuids = 0;
2586     HDEVINFO hList;
2587     SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
2588 
2589 #ifdef KSPROXY_TRACE
2590     WCHAR Buffer[100];
2591     OutputDebugStringW(L"CKsProxy::Load\n");
2592 #endif
2593 
2594     // read device path
2595     varName.vt = VT_BSTR;
2596     hr = pPropBag->Read(L"DevicePath", &varName, pErrorLog);
2597 
2598     if (FAILED(hr))
2599     {
2600 #ifdef KSPROXY_TRACE
2601         swprintf(Buffer, L"CKsProxy::Load Read %lx\n", hr);
2602         OutputDebugStringW(Buffer);
2603 #endif
2604         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
2605     }
2606 
2607 #ifdef KSPROXY_TRACE
2608     OutputDebugStringW(L"DevicePath: ");
2609     OutputDebugStringW(varName.bstrVal);
2610     OutputDebugStringW(L"\n");
2611 #endif
2612 
2613     // create device list
2614     hList = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
2615     if (hList == INVALID_HANDLE_VALUE)
2616     {
2617         // failed to create device list
2618         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
2619     }
2620 
2621     DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2622     if (!SetupDiOpenDeviceInterfaceW(hList, (PCWSTR)varName.bstrVal, 0, &DeviceInterfaceData))
2623     {
2624         // failed to open device interface
2625         SetupDiDestroyDeviceInfoList(hList);
2626     }
2627 
2628     // FIXME handle device interface links(aliases)
2629     CopyMemory(&m_DeviceInterfaceGUID, &DeviceInterfaceData.InterfaceClassGuid, sizeof(GUID));
2630 
2631     // close device info list
2632    SetupDiDestroyDeviceInfoList(hList);
2633 
2634     // open device
2635     m_hDevice = CreateFileW(varName.bstrVal, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
2636 
2637     if (m_hDevice == INVALID_HANDLE_VALUE)
2638     {
2639         // failed to open device
2640 #ifdef KSPROXY_TRACE
2641         swprintf(Buffer, L"CKsProxy:: failed to open device with %lx\n", GetLastError());
2642         OutputDebugStringW(Buffer);
2643 #endif
2644         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
2645     }
2646 
2647     // store device path
2648     m_DevicePath = varName.bstrVal;
2649 
2650     // get all supported sets
2651     hr = GetSupportedSets(&pGuid, &NumGuids);
2652     if (FAILED(hr))
2653     {
2654         CloseHandle(m_hDevice);
2655         m_hDevice = NULL;
2656         return hr;
2657     }
2658 
2659     // load all proxy plugins
2660     hr = LoadProxyPlugins(pGuid, NumGuids);
2661     if (FAILED(hr))
2662     {
2663 #if 0 //HACK
2664         CloseHandle(m_hDevice);
2665         m_hDevice = NULL;
2666         return hr;
2667 #endif
2668         OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed!\n");
2669     }
2670 
2671     // free sets
2672     CoTaskMemFree(pGuid);
2673 
2674     // now create the input / output pins
2675     hr = CreatePins();
2676 
2677 #ifdef KSPROXY_TRACE
2678     swprintf(Buffer, L"CKsProxy::Load CreatePins %lx\n", hr);
2679     OutputDebugStringW(Buffer);
2680 #endif
2681 
2682     //HACK
2683     hr = S_OK;
2684 
2685     return hr;
2686 }
2687 
2688 HRESULT
2689 STDMETHODCALLTYPE
2690 CKsProxy::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
2691 {
2692 #ifdef KSPROXY_TRACE
2693     OutputDebugStringW(L"CKsProxy::Save\n");
2694 #endif
2695     return E_NOTIMPL;
2696 }
2697 
2698 //-------------------------------------------------------------------
2699 // IBaseFilter interface
2700 //
2701 
2702 HRESULT
2703 STDMETHODCALLTYPE
2704 CKsProxy::GetClassID(
2705     CLSID *pClassID)
2706 {
2707 #ifdef KSPROXY_TRACE
2708     OutputDebugStringW(L"CKsProxy::GetClassID\n");
2709 #endif
2710     CopyMemory(pClassID, &CLSID_Proxy, sizeof(GUID));
2711 
2712     return S_OK;
2713 }
2714 
2715 HRESULT
2716 STDMETHODCALLTYPE
2717 CKsProxy::Stop()
2718 {
2719     HRESULT hr;
2720 
2721 #ifdef KSPROXY_TRACE
2722     OutputDebugStringW(L"CKsProxy::Stop\n");
2723 #endif
2724 
2725     EnterCriticalSection(&m_Lock);
2726 
2727     hr = SetPinState(KSSTATE_STOP);
2728     if (SUCCEEDED(hr))
2729         m_FilterState = State_Stopped;
2730 
2731     LeaveCriticalSection(&m_Lock);
2732 
2733     return hr;
2734 }
2735 
2736 HRESULT
2737 STDMETHODCALLTYPE
2738 CKsProxy::Pause()
2739 {
2740     HRESULT hr = S_OK;
2741 
2742 #ifdef KSPROXY_TRACE
2743     OutputDebugStringW(L"CKsProxy::Pause\n");
2744 #endif
2745 
2746     EnterCriticalSection(&m_Lock);
2747 
2748     if (m_FilterState == State_Running)
2749     {
2750         hr = SetPinState(KSSTATE_STOP);
2751     }
2752     if (SUCCEEDED(hr))
2753     {
2754         if (m_FilterState == State_Stopped)
2755         {
2756             hr = SetPinState(KSSTATE_PAUSE);
2757         }
2758     }
2759 
2760     if (SUCCEEDED(hr))
2761         m_FilterState = State_Paused;
2762 
2763     LeaveCriticalSection(&m_Lock);
2764     return hr;
2765 
2766 }
2767 
2768 HRESULT
2769 STDMETHODCALLTYPE
2770 CKsProxy::Run(
2771     REFERENCE_TIME tStart)
2772 {
2773     HRESULT hr;
2774 
2775 #ifdef KSPROXY_TRACE
2776     OutputDebugStringW(L"CKsProxy::Run\n");
2777 #endif
2778 
2779     EnterCriticalSection(&m_Lock);
2780 
2781     if (m_FilterState == State_Stopped)
2782     {
2783         LeaveCriticalSection(&m_Lock);
2784         // setting filter state to pause
2785         hr = Pause();
2786         if (FAILED(hr))
2787             return hr;
2788 
2789         EnterCriticalSection(&m_Lock);
2790         assert(m_FilterState == State_Paused);
2791     }
2792 
2793     hr = SetPinState(KSSTATE_RUN);
2794 
2795     if (SUCCEEDED(hr))
2796     {
2797         m_FilterState = State_Running;
2798     }
2799 
2800     LeaveCriticalSection(&m_Lock);
2801     return hr;
2802 }
2803 
2804 HRESULT
2805 STDMETHODCALLTYPE
2806 CKsProxy::SetPinState(
2807     KSSTATE State)
2808 {
2809     HRESULT hr = S_OK;
2810     ULONG Index;
2811     IKsObject *pObject;
2812     ULONG BytesReturned;
2813     KSPROPERTY Property;
2814     PIN_INFO PinInfo;
2815 
2816     Property.Set = KSPROPSETID_Connection;
2817     Property.Id = KSPROPERTY_CONNECTION_STATE;
2818     Property.Flags = KSPROPERTY_TYPE_SET;
2819 
2820     // set all pins to running state
2821     for(Index = 0; Index < m_Pins.size(); Index++)
2822     {
2823         IPin * Pin = m_Pins[Index];
2824         if (!Pin)
2825             continue;
2826 
2827         //check if the pin is connected
2828         IPin * TempPin;
2829         hr = Pin->ConnectedTo(&TempPin);
2830         if (FAILED(hr))
2831         {
2832             // skip unconnected pins
2833             continue;
2834         }
2835 
2836         // release connected pin
2837         TempPin->Release();
2838 
2839         // query for the pin info
2840         hr = Pin->QueryPinInfo(&PinInfo);
2841 
2842         if (SUCCEEDED(hr))
2843         {
2844             if (PinInfo.pFilter)
2845                 PinInfo.pFilter->Release();
2846 
2847             if (PinInfo.dir == PINDIR_OUTPUT)
2848             {
2849                 hr = COutputPin_SetState(Pin, State);
2850                 if (SUCCEEDED(hr))
2851                     continue;
2852             }
2853         }
2854 
2855         //query IKsObject interface
2856         hr = Pin->QueryInterface(IID_IKsObject, (void**)&pObject);
2857 
2858         // get pin handle
2859         HANDLE hPin = pObject->KsGetObjectHandle();
2860 
2861         // sanity check
2862         assert(hPin && hPin != INVALID_HANDLE_VALUE);
2863 
2864         // now set state
2865         hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
2866 
2867 #ifdef KSPROXY_TRACE
2868         WCHAR Buffer[100];
2869         swprintf(Buffer, L"CKsProxy::SetPinState Index %u State %u hr %lx\n", Index, State, hr);
2870         OutputDebugStringW(Buffer);
2871 #endif
2872 
2873         if (FAILED(hr))
2874             return hr;
2875     }
2876     return hr;
2877 }
2878 
2879 HRESULT
2880 STDMETHODCALLTYPE
2881 CKsProxy::GetState(
2882     DWORD dwMilliSecsTimeout,
2883     FILTER_STATE *State)
2884 {
2885     if (!State)
2886         return E_POINTER;
2887 
2888     *State = m_FilterState;
2889     return S_OK;
2890 }
2891 
2892 HRESULT
2893 STDMETHODCALLTYPE
2894 CKsProxy::SetSyncSource(
2895     IReferenceClock *pClock)
2896 {
2897     HRESULT hr;
2898     IKsClock *pKsClock;
2899     HANDLE hClock, hPin;
2900     ULONG Index;
2901     IPin * pin;
2902     IKsObject * pObject;
2903     KSPROPERTY Property;
2904     ULONG BytesReturned;
2905     PIN_DIRECTION PinDir;
2906 
2907 #ifdef KSPROXY_TRACE
2908     OutputDebugStringW(L"CKsProxy::SetSyncSource\n");
2909 #endif
2910 
2911     // FIXME
2912     // need locks
2913 
2914     if (pClock)
2915     {
2916         hr = pClock->QueryInterface(IID_IKsClock, (void**)&pKsClock);
2917         if (FAILED(hr))
2918         {
2919             hr = m_ReferenceClock->QueryInterface(IID_IKsClock, (void**)&pKsClock);
2920             if (FAILED(hr))
2921                 return hr;
2922         }
2923 
2924         // get clock handle
2925         hClock = pKsClock->KsGetClockHandle();
2926 
2927         // release IKsClock interface
2928         pKsClock->Release();
2929         m_hClock = hClock;
2930     }
2931     else
2932     {
2933         // no clock handle
2934         m_hClock = NULL;
2935     }
2936 
2937 
2938     // distribute clock to all pins
2939     for(Index = 0; Index < m_Pins.size(); Index++)
2940     {
2941         // get current pin
2942         pin = m_Pins[Index];
2943         if (!pin)
2944             continue;
2945 
2946         // get IKsObject interface
2947         hr = pin->QueryInterface(IID_IKsObject, (void **)&pObject);
2948         if (SUCCEEDED(hr))
2949         {
2950             // get pin handle
2951             hPin = pObject->KsGetObjectHandle();
2952             if (hPin != INVALID_HANDLE_VALUE && hPin)
2953             {
2954                 // set clock
2955                 Property.Set = KSPROPSETID_Stream;
2956                 Property.Id = KSPROPERTY_STREAM_MASTERCLOCK;
2957                 Property.Flags = KSPROPERTY_TYPE_SET;
2958 
2959                 // set master clock
2960                 hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&m_hClock, sizeof(HANDLE), &BytesReturned);
2961 
2962                 if (FAILED(hr))
2963                 {
2964                     if (hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND) &&
2965                         hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND))
2966                     {
2967                         // failed to set master clock
2968                         pObject->Release();
2969                         WCHAR Buffer[100];
2970                         swprintf(Buffer, L"CKsProxy::SetSyncSource KSPROPERTY_STREAM_MASTERCLOCK failed with %lx\n", hr);
2971                         OutputDebugStringW(Buffer);
2972                         return hr;
2973                     }
2974                 }
2975             }
2976             // release IKsObject
2977             pObject->Release();
2978         }
2979 
2980         // now get the direction
2981         hr = pin->QueryDirection(&PinDir);
2982         if (SUCCEEDED(hr))
2983         {
2984             if (PinDir == PINDIR_OUTPUT)
2985             {
2986                 // notify pin via
2987                 //CBaseStreamControl::SetSyncSource(pClock)
2988             }
2989         }
2990     }
2991 
2992     if (pClock)
2993     {
2994         pClock->AddRef();
2995     }
2996 
2997     if (m_ReferenceClock)
2998     {
2999         m_ReferenceClock->Release();
3000     }
3001 
3002     m_ReferenceClock = pClock;
3003 #ifdef KSPROXY_TRACE
3004     OutputDebugStringW(L"CKsProxy::SetSyncSource done\n");
3005 #endif
3006     return S_OK;
3007 }
3008 
3009 HRESULT
3010 STDMETHODCALLTYPE
3011 CKsProxy::GetSyncSource(
3012     IReferenceClock **pClock)
3013 {
3014 #ifdef KSPROXY_TRACE
3015     OutputDebugStringW(L"CKsProxy::GetSyncSource\n");
3016 #endif
3017 
3018     if (!pClock)
3019         return E_POINTER;
3020 
3021     if (m_ReferenceClock)
3022         m_ReferenceClock->AddRef();
3023 
3024     *pClock = m_ReferenceClock;
3025     return S_OK;
3026 }
3027 
3028 HRESULT
3029 STDMETHODCALLTYPE
3030 CKsProxy::EnumPins(
3031     IEnumPins **ppEnum)
3032 {
3033     return CEnumPins_fnConstructor(m_Pins, IID_IEnumPins, (void**)ppEnum);
3034 }
3035 
3036 HRESULT
3037 STDMETHODCALLTYPE
3038 CKsProxy::FindPin(
3039     LPCWSTR Id, IPin **ppPin)
3040 {
3041     ULONG PinId;
3042 
3043 #ifdef KSPROXY_TRACE
3044     OutputDebugStringW(L"CKsProxy::FindPin\n");
3045 #endif
3046 
3047     if (!ppPin)
3048         return E_POINTER;
3049 
3050     // convert to pin
3051     int ret = swscanf(Id, L"%u", &PinId);
3052 
3053     if (!ret || ret == EOF)
3054     {
3055         // invalid id
3056         return VFW_E_NOT_FOUND;
3057     }
3058 
3059     if (PinId >= m_Pins.size() || m_Pins[PinId] == NULL)
3060     {
3061         // invalid id
3062         return VFW_E_NOT_FOUND;
3063     }
3064 
3065     // found pin
3066     *ppPin = m_Pins[PinId];
3067     m_Pins[PinId]->AddRef();
3068 
3069     return S_OK;
3070 }
3071 
3072 
3073 HRESULT
3074 STDMETHODCALLTYPE
3075 CKsProxy::QueryFilterInfo(
3076     FILTER_INFO *pInfo)
3077 {
3078     if (!pInfo)
3079         return E_POINTER;
3080 
3081 #ifdef KSPROXY_TRACE
3082     OutputDebugStringW(L"CKsProxy::QueryFilterInfo\n");
3083 #endif
3084 
3085     pInfo->achName[0] = L'\0';
3086     pInfo->pGraph = m_pGraph;
3087 
3088     if (m_pGraph)
3089         m_pGraph->AddRef();
3090 
3091     return S_OK;
3092 }
3093 
3094 HRESULT
3095 STDMETHODCALLTYPE
3096 CKsProxy::JoinFilterGraph(
3097     IFilterGraph *pGraph,
3098     LPCWSTR pName)
3099 {
3100 #ifdef KSPROXY_TRACE
3101     WCHAR Buffer[100];
3102     swprintf(Buffer, L"CKsProxy::JoinFilterGraph pName %s pGraph %p m_Ref %u\n", pName, pGraph, m_Ref);
3103     OutputDebugStringW(Buffer);
3104 #endif
3105 
3106     if (pGraph)
3107     {
3108         // joining filter graph
3109         m_pGraph = pGraph;
3110     }
3111     else
3112     {
3113         // leaving graph
3114         m_pGraph = 0;
3115     }
3116 
3117     return S_OK;
3118 }
3119 
3120 
3121 HRESULT
3122 STDMETHODCALLTYPE
3123 CKsProxy::QueryVendorInfo(
3124     LPWSTR *pVendorInfo)
3125 {
3126 #ifdef KSPROXY_TRACE
3127     OutputDebugStringW(L"CKsProxy::QueryVendorInfo\n");
3128 #endif
3129     return StringFromCLSID(CLSID_Proxy, pVendorInfo);
3130 }
3131 
3132 //-------------------------------------------------------------------
3133 // IAMovieSetup interface
3134 //
3135 
3136 HRESULT
3137 STDMETHODCALLTYPE
3138 CKsProxy::Register()
3139 {
3140 #ifdef KSPROXY_TRACE
3141     OutputDebugStringW(L"CKsProxy::Register : NotImplemented\n");
3142 #endif
3143 
3144     return E_NOTIMPL;
3145 }
3146 
3147 HRESULT
3148 STDMETHODCALLTYPE
3149 CKsProxy::Unregister()
3150 {
3151 #ifdef KSPROXY_TRACE
3152     OutputDebugStringW(L"CKsProxy::Unregister : NotImplemented\n");
3153 #endif
3154     return E_NOTIMPL;
3155 }
3156 
3157 HRESULT
3158 WINAPI
3159 CKsProxy_Constructor(
3160     IUnknown * pUnkOuter,
3161     REFIID riid,
3162     LPVOID * ppv)
3163 {
3164 #ifdef KSPROXY_TRACE
3165     WCHAR Buffer[100];
3166     LPOLESTR pstr;
3167     StringFromCLSID(riid, &pstr);
3168     swprintf(Buffer, L"CKsProxy_Constructor pUnkOuter %p riid %s\n", pUnkOuter, pstr);
3169     OutputDebugStringW(Buffer);
3170 #endif
3171 
3172     CKsProxy * handler = new CKsProxy();
3173 
3174     if (!handler)
3175         return E_OUTOFMEMORY;
3176 
3177     if (FAILED(handler->QueryInterface(riid, ppv)))
3178     {
3179         /* not supported */
3180         delete handler;
3181         return E_NOINTERFACE;
3182     }
3183 
3184     return S_OK;
3185 }
3186