5e939ebd465caa5f175a1d7d9e3c8450e5434fb6
[reactos.git] / reactos / dll / directx / ksproxy / proxy.cpp
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 (janderwald@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 GUID_NULL = {0x00000000L, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
13 const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}};
14 /*
15 Needs IKsClock, IKsNotifyEvent
16 */
17
18 class CKsProxy : public IBaseFilter,
19 public IAMovieSetup,
20 public IPersistPropertyBag,
21 public IKsObject
22 /*
23 public IPersistStream,
24 public ISpecifyPropertyPages,
25 public IReferenceClock,
26 public IMediaSeeking,
27 public IKsObject,
28 public IKsPropertySet,
29 public IKsClockPropertySet,
30 public IAMFilterMiscFlags,
31 public IKsControl,
32 public IKsTopology,
33 public IKsAggregateControl,
34 public IAMDeviceRemoval
35 */
36 {
37 public:
38 typedef std::vector<IUnknown *>ProxyPluginVector;
39 typedef std::vector<IPin *> PinVector;
40
41 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
42
43 STDMETHODIMP_(ULONG) AddRef()
44 {
45 InterlockedIncrement(&m_Ref);
46 return m_Ref;
47 }
48 STDMETHODIMP_(ULONG) Release()
49 {
50 InterlockedDecrement(&m_Ref);
51 if (!m_Ref)
52 {
53 delete this;
54 return 0;
55 }
56 return m_Ref;
57 }
58
59 // IBaseFilter methods
60 HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
61 HRESULT STDMETHODCALLTYPE Stop( void);
62 HRESULT STDMETHODCALLTYPE Pause( void);
63 HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
64 HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *State);
65 HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
66 HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **pClock);
67 HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
68 HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
69 HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
70 HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
71 HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
72
73 //IAMovieSetup methods
74 HRESULT STDMETHODCALLTYPE Register( void);
75 HRESULT STDMETHODCALLTYPE Unregister( void);
76
77 // IPersistPropertyBag methods
78 HRESULT STDMETHODCALLTYPE InitNew( void);
79 HRESULT STDMETHODCALLTYPE Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog);
80 HRESULT STDMETHODCALLTYPE Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties);
81
82 // IKsObject
83 HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
84
85 CKsProxy() : m_Ref(0), m_pGraph(0), m_ReferenceClock(0), m_FilterState(State_Stopped), m_hDevice(0), m_Plugins(), m_Pins() {};
86 virtual ~CKsProxy()
87 {
88 if (m_hDevice)
89 CloseHandle(m_hDevice);
90 };
91
92 HRESULT STDMETHODCALLTYPE GetSupportedSets(LPGUID * pOutGuid, PULONG NumGuids);
93 HRESULT STDMETHODCALLTYPE LoadProxyPlugins(LPGUID pGuids, ULONG NumGuids);
94 HRESULT STDMETHODCALLTYPE GetNumberOfPins(PULONG NumPins);
95 HRESULT STDMETHODCALLTYPE GetPinInstanceCount(ULONG PinId, PKSPIN_CINSTANCES Instances);
96 HRESULT STDMETHODCALLTYPE GetPinDataflow(ULONG PinId, KSPIN_DATAFLOW * DataFlow);
97 HRESULT STDMETHODCALLTYPE GetPinName(ULONG PinId, KSPIN_DATAFLOW DataFlow, ULONG PinCount, LPWSTR * OutPinName);
98 HRESULT STDMETHODCALLTYPE CreatePins();
99 protected:
100 LONG m_Ref;
101 IFilterGraph *m_pGraph;
102 IReferenceClock * m_ReferenceClock;
103 FILTER_STATE m_FilterState;
104 HANDLE m_hDevice;
105 ProxyPluginVector m_Plugins;
106 PinVector m_Pins;
107 };
108
109 HRESULT
110 STDMETHODCALLTYPE
111 CKsProxy::QueryInterface(
112 IN REFIID refiid,
113 OUT PVOID* Output)
114 {
115 *Output = NULL;
116
117 if (IsEqualGUID(refiid, IID_IUnknown) ||
118 IsEqualGUID(refiid, IID_IBaseFilter))
119 {
120 *Output = PVOID(this);
121 reinterpret_cast<IUnknown*>(*Output)->AddRef();
122 return NOERROR;
123 }
124 else if (IsEqualGUID(refiid, IID_IPersistPropertyBag))
125 {
126 *Output = (IPersistPropertyBag*)(this);
127 reinterpret_cast<IPersistPropertyBag*>(*Output)->AddRef();
128 return NOERROR;
129 }
130 if (IsEqualGUID(refiid, IID_IKsObject))
131 {
132 *Output = (IKsObject*)(this);
133 reinterpret_cast<IKsObject*>(*Output)->AddRef();
134 return NOERROR;
135 }
136
137 for(ULONG Index = 0; Index < m_Plugins.size(); Index++)
138 {
139 if (m_Pins[Index])
140 {
141 HRESULT hr = m_Plugins[Index]->QueryInterface(refiid, Output);
142 if (SUCCEEDED(hr))
143 {
144 WCHAR Buffer[100];
145 LPOLESTR lpstr;
146 StringFromCLSID(refiid, &lpstr);
147 swprintf(Buffer, L"CKsProxy::QueryInterface plugin %lu supports interface %s\n", Index, lpstr);
148 OutputDebugStringW(Buffer);
149 CoTaskMemFree(lpstr);
150 return hr;
151 }
152 }
153 }
154
155 WCHAR Buffer[MAX_PATH];
156 LPOLESTR lpstr;
157 StringFromCLSID(refiid, &lpstr);
158 swprintf(Buffer, L"CKsProxy::QueryInterface: NoInterface for %s !!!\n", lpstr);
159 OutputDebugStringW(Buffer);
160 CoTaskMemFree(lpstr);
161
162
163 return E_NOINTERFACE;
164 }
165
166 //-------------------------------------------------------------------
167 // IKsObject interface
168 //
169
170 HANDLE
171 STDMETHODCALLTYPE
172 CKsProxy::KsGetObjectHandle()
173 {
174 return m_hDevice;
175 }
176
177 //-------------------------------------------------------------------
178 // IPersistPropertyBag interface
179 //
180 HRESULT
181 STDMETHODCALLTYPE
182 CKsProxy::InitNew( void)
183 {
184 return S_OK;
185 }
186
187 HRESULT
188 STDMETHODCALLTYPE
189 CKsProxy::GetSupportedSets(
190 LPGUID * pOutGuid,
191 PULONG NumGuids)
192 {
193 KSPROPERTY Property;
194 LPGUID pGuid;
195 ULONG NumProperty = 0;
196 ULONG NumMethods = 0;
197 ULONG NumEvents = 0;
198 ULONG Length;
199 ULONG BytesReturned;
200 HRESULT hr;
201
202 Property.Set = GUID_NULL;
203 Property.Id = 0;
204 Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
205
206 KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumProperty);
207 KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumMethods);
208 KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumEvents);
209
210 Length = NumProperty + NumMethods + NumEvents;
211
212 // allocate guid buffer
213 pGuid = (LPGUID)CoTaskMemAlloc(Length);
214 if (!pGuid)
215 {
216 // failed
217 return E_OUTOFMEMORY;
218 }
219
220 NumProperty /= sizeof(GUID);
221 NumMethods /= sizeof(GUID);
222 NumEvents /= sizeof(GUID);
223
224 // get all properties
225 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pGuid, Length, &BytesReturned);
226 if (FAILED(hr))
227 {
228 CoTaskMemFree(pGuid);
229 return E_FAIL;
230 }
231 Length -= BytesReturned;
232
233 // get all methods
234 if (Length)
235 {
236 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty], Length, &BytesReturned);
237 if (FAILED(hr))
238 {
239 CoTaskMemFree(pGuid);
240 return E_FAIL;
241 }
242 Length -= BytesReturned;
243 }
244
245 // get all events
246 if (Length)
247 {
248 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty+NumMethods], Length, &BytesReturned);
249 if (FAILED(hr))
250 {
251 CoTaskMemFree(pGuid);
252 return E_FAIL;
253 }
254 Length -= BytesReturned;
255 }
256
257 #ifdef KSPROXY_TRACE
258 WCHAR Buffer[200];
259 swprintf(Buffer, L"NumProperty %lu NumMethods %lu NumEvents %lu\n", NumProperty, NumMethods, NumEvents);
260 OutputDebugStringW(Buffer);
261 #endif
262
263 *pOutGuid = pGuid;
264 *NumGuids = NumProperty+NumEvents+NumMethods;
265 return S_OK;
266 }
267
268 HRESULT
269 STDMETHODCALLTYPE
270 CKsProxy::LoadProxyPlugins(
271 LPGUID pGuids,
272 ULONG NumGuids)
273 {
274 ULONG Index;
275 LPOLESTR pStr;
276 HKEY hKey, hSubKey;
277 HRESULT hr;
278 IUnknown * pUnknown;
279
280 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\MediaInterfaces", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
281 {
282 OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed to open MediaInterfaces key\n");
283 return E_FAIL;
284 }
285
286 // enumerate all sets
287 for(Index = 0; Index < NumGuids; Index++)
288 {
289 // convert to string
290 hr = StringFromCLSID(pGuids[Index], &pStr);
291 if (FAILED(hr))
292 return E_FAIL;
293
294 // now try open class key
295 if (RegOpenKeyExW(hKey, pStr, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
296 {
297 // no plugin for that set exists
298 CoTaskMemFree(pStr);
299 continue;
300 }
301
302 // try load plugin
303 hr = CoCreateInstance(pGuids[Index], (IBaseFilter*)this, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
304 if (SUCCEEDED(hr))
305 {
306 // store plugin
307 m_Plugins.push_back(pUnknown);
308 }
309 // close key
310 RegCloseKey(hSubKey);
311 }
312
313 // close media interfaces key
314 RegCloseKey(hKey);
315 return S_OK;
316 }
317
318 HRESULT
319 STDMETHODCALLTYPE
320 CKsProxy::GetNumberOfPins(
321 PULONG NumPins)
322 {
323 KSPROPERTY Property;
324 ULONG BytesReturned;
325
326 // setup request
327 Property.Set = KSPROPSETID_Pin;
328 Property.Id = KSPROPERTY_PIN_CTYPES;
329 Property.Flags = KSPROPERTY_TYPE_GET;
330
331 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)NumPins, sizeof(ULONG), &BytesReturned);
332 }
333
334 HRESULT
335 STDMETHODCALLTYPE
336 CKsProxy::GetPinInstanceCount(
337 ULONG PinId,
338 PKSPIN_CINSTANCES Instances)
339 {
340 KSP_PIN Property;
341 ULONG BytesReturned;
342
343 // setup request
344 Property.Property.Set = KSPROPSETID_Pin;
345 Property.Property.Id = KSPROPERTY_PIN_CINSTANCES;
346 Property.Property.Flags = KSPROPERTY_TYPE_GET;
347 Property.PinId = PinId;
348 Property.Reserved = 0;
349
350 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Instances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
351 }
352
353 HRESULT
354 STDMETHODCALLTYPE
355 CKsProxy::GetPinDataflow(
356 ULONG PinId,
357 KSPIN_DATAFLOW * DataFlow)
358 {
359 KSP_PIN Property;
360 ULONG BytesReturned;
361
362 // setup request
363 Property.Property.Set = KSPROPSETID_Pin;
364 Property.Property.Id = KSPROPERTY_PIN_DATAFLOW;
365 Property.Property.Flags = KSPROPERTY_TYPE_GET;
366 Property.PinId = PinId;
367 Property.Reserved = 0;
368
369 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
370 }
371
372 HRESULT
373 STDMETHODCALLTYPE
374 CKsProxy::GetPinName(
375 ULONG PinId,
376 KSPIN_DATAFLOW DataFlow,
377 ULONG PinCount,
378 LPWSTR * OutPinName)
379 {
380 KSP_PIN Property;
381 LPWSTR PinName;
382 ULONG BytesReturned;
383 HRESULT hr;
384 WCHAR Buffer[100];
385
386 // setup request
387 Property.Property.Set = KSPROPSETID_Pin;
388 Property.Property.Id = KSPROPERTY_PIN_NAME;
389 Property.Property.Flags = KSPROPERTY_TYPE_GET;
390 Property.PinId = PinId;
391 Property.Reserved = 0;
392
393 // #1 try get it from pin directly
394 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
395
396 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA))
397 {
398 // allocate pin name
399 PinName = (LPWSTR)CoTaskMemAlloc(BytesReturned);
400 if (!PinName)
401 return E_OUTOFMEMORY;
402
403 // retry with allocated buffer
404 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), PinName, BytesReturned, &BytesReturned);
405 if (SUCCEEDED(hr))
406 {
407 *OutPinName = PinName;
408 return hr;
409 }
410
411 //free buffer
412 CoTaskMemFree(PinName);
413 }
414
415 //
416 // TODO: retrieve pin name from topology node
417 //
418
419 if (DataFlow == KSPIN_DATAFLOW_IN)
420 {
421 swprintf(Buffer, L"Input%lu", PinCount);
422 }
423 else
424 {
425 swprintf(Buffer, L"Output%lu", PinCount);
426 }
427
428 // allocate pin name
429 PinName = (LPWSTR)CoTaskMemAlloc((wcslen(Buffer)+1) * sizeof(WCHAR));
430 if (!PinName)
431 return E_OUTOFMEMORY;
432
433 // copy pin name
434 wcscpy(PinName, Buffer);
435
436 // store result
437 *OutPinName = PinName;
438 // done
439 return S_OK;
440 }
441
442 HRESULT
443 STDMETHODCALLTYPE
444 CKsProxy::CreatePins()
445 {
446 ULONG NumPins, Index;
447 KSPIN_CINSTANCES Instances;
448 KSPIN_DATAFLOW DataFlow;
449 HRESULT hr;
450 WCHAR Buffer[100];
451 LPWSTR PinName;
452 IPin * pPin;
453 ULONG InputPin = 0;
454 ULONG OutputPin = 0;
455
456 // get number of pins
457 hr = GetNumberOfPins(&NumPins);
458 if (FAILED(hr))
459 return hr;
460
461 for(Index = 0; Index < NumPins; Index++)
462 {
463 // query current instance count
464 hr = GetPinInstanceCount(Index, &Instances);
465 if (FAILED(hr))
466 continue;
467
468 if (Instances.CurrentCount == Instances.PossibleCount)
469 {
470 // already maximum reached for this pin
471 continue;
472 }
473
474 // get direction of pin
475 hr = GetPinDataflow(Index, &DataFlow);
476 if (FAILED(hr))
477 continue;
478
479 if (DataFlow == KSPIN_DATAFLOW_IN)
480 hr = GetPinName(Index, DataFlow, InputPin, &PinName);
481 else
482 hr = GetPinName(Index, DataFlow, OutputPin, &PinName);
483
484 if (FAILED(hr))
485 continue;
486
487 // construct the pins
488 if (DataFlow == KSPIN_DATAFLOW_IN)
489 {
490 hr = CInputPin_Constructor((IBaseFilter*)this, PinName, m_hDevice, Index, IID_IPin, (void**)&pPin);
491 if (FAILED(hr))
492 {
493 CoTaskMemFree(PinName);
494 continue;
495 }
496 InputPin++;
497 }
498 else
499 {
500 hr = COutputPin_Constructor((IBaseFilter*)this, PinName, IID_IPin, (void**)&pPin);
501 if (FAILED(hr))
502 {
503 CoTaskMemFree(PinName);
504 continue;
505 }
506 OutputPin++;
507 }
508
509 // store pins
510 m_Pins.push_back(pPin);
511
512 swprintf(Buffer, L"Index %lu DataFlow %lu Name %s\n", Index, DataFlow, PinName);
513 OutputDebugStringW(Buffer);
514 }
515
516 return S_OK;
517 }
518
519 HRESULT
520 STDMETHODCALLTYPE
521 CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
522 {
523 HRESULT hr;
524 WCHAR Buffer[100];
525 VARIANT varName;
526 LPGUID pGuid;
527 ULONG NumGuids = 0;
528
529 // read device path
530 varName.vt = VT_BSTR;
531 hr = pPropBag->Read(L"DevicePath", &varName, pErrorLog);
532
533 if (FAILED(hr))
534 {
535 swprintf(Buffer, L"CKsProxy::Load Read %lx\n", hr);
536 OutputDebugStringW(Buffer);
537 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
538 }
539
540 // open device
541 m_hDevice = CreateFileW(varName.bstrVal, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
542
543 if (m_hDevice == INVALID_HANDLE_VALUE)
544 {
545 // failed to open device
546 swprintf(Buffer, L"CKsProxy:: failed to open device with %lx\n", GetLastError());
547 OutputDebugStringW(Buffer);
548
549 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
550 }
551
552 // get all supported sets
553 hr = GetSupportedSets(&pGuid, &NumGuids);
554 if (FAILED(hr))
555 {
556 CloseHandle(m_hDevice);
557 m_hDevice = NULL;
558 return hr;
559 }
560
561 // load all proxy plugins
562 hr = LoadProxyPlugins(pGuid, NumGuids);
563 if (FAILED(hr))
564 {
565 CloseHandle(m_hDevice);
566 m_hDevice = NULL;
567 return hr;
568 }
569
570 // free sets
571 CoTaskMemFree(pGuid);
572
573 // now create the input / output pins
574 hr = CreatePins();
575
576 return hr;
577 }
578
579 HRESULT
580 STDMETHODCALLTYPE
581 CKsProxy::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
582 {
583 return E_NOTIMPL;
584 }
585
586 //-------------------------------------------------------------------
587 // IBaseFilter interface
588 //
589
590 HRESULT
591 STDMETHODCALLTYPE
592 CKsProxy::GetClassID(
593 CLSID *pClassID)
594 {
595 OutputDebugStringW(L"CKsProxy::GetClassID : NotImplemented\n");
596 return E_NOTIMPL;
597 }
598
599 HRESULT
600 STDMETHODCALLTYPE
601 CKsProxy::Stop()
602 {
603 OutputDebugStringW(L"CKsProxy::Stop : NotImplemented\n");
604 return E_NOTIMPL;
605 }
606
607 HRESULT
608 STDMETHODCALLTYPE
609 CKsProxy::Pause()
610 {
611 OutputDebugStringW(L"CKsProxy::Pause : NotImplemented\n");
612 return E_NOTIMPL;
613 }
614
615 HRESULT
616 STDMETHODCALLTYPE
617 CKsProxy::Run(
618 REFERENCE_TIME tStart)
619 {
620 OutputDebugStringW(L"CKsProxy::Run : NotImplemented\n");
621 return E_NOTIMPL;
622 }
623
624 HRESULT
625 STDMETHODCALLTYPE
626 CKsProxy::GetState(
627 DWORD dwMilliSecsTimeout,
628 FILTER_STATE *State)
629 {
630 *State = m_FilterState;
631 return S_OK;
632 }
633
634 HRESULT
635 STDMETHODCALLTYPE
636 CKsProxy::SetSyncSource(
637 IReferenceClock *pClock)
638 {
639 if (pClock)
640 {
641 pClock->AddRef();
642 }
643
644 if (m_ReferenceClock)
645 {
646 m_ReferenceClock->Release();
647 }
648
649 m_ReferenceClock = pClock;
650 return S_OK;
651 }
652
653 HRESULT
654 STDMETHODCALLTYPE
655 CKsProxy::GetSyncSource(
656 IReferenceClock **pClock)
657 {
658 if (!pClock)
659 return E_POINTER;
660
661 if (m_ReferenceClock)
662 m_ReferenceClock->AddRef();
663
664 *pClock = m_ReferenceClock;
665 return S_OK;
666 }
667
668 HRESULT
669 STDMETHODCALLTYPE
670 CKsProxy::EnumPins(
671 IEnumPins **ppEnum)
672 {
673 return CEnumPins_fnConstructor(m_Pins, IID_IEnumPins, (void**)ppEnum);
674 }
675
676 HRESULT
677 STDMETHODCALLTYPE
678 CKsProxy::FindPin(
679 LPCWSTR Id, IPin **ppPin)
680 {
681 ULONG PinId;
682
683 if (!ppPin)
684 return E_POINTER;
685
686 // convert to pin
687 int ret = swscanf(Id, L"%u", &PinId);
688
689 if (!ret || ret == EOF)
690 {
691 // invalid id
692 return VFW_E_NOT_FOUND;
693 }
694
695 if (PinId >= m_Pins.size() || m_Pins[PinId] == NULL)
696 {
697 // invalid id
698 return VFW_E_NOT_FOUND;
699 }
700
701 // found pin
702 *ppPin = m_Pins[PinId];
703 m_Pins[PinId]->AddRef();
704
705 return S_OK;
706 }
707
708
709 HRESULT
710 STDMETHODCALLTYPE
711 CKsProxy::QueryFilterInfo(
712 FILTER_INFO *pInfo)
713 {
714 if (!pInfo)
715 return E_POINTER;
716
717 pInfo->achName[0] = L'\0';
718 pInfo->pGraph = m_pGraph;
719
720 return S_OK;
721 }
722
723 HRESULT
724 STDMETHODCALLTYPE
725 CKsProxy::JoinFilterGraph(
726 IFilterGraph *pGraph,
727 LPCWSTR pName)
728 {
729 if (pGraph)
730 {
731 // joining filter graph
732 m_pGraph = pGraph;
733 }
734 else
735 {
736 // leaving graph
737 m_pGraph = 0;
738 }
739
740 return S_OK;
741 }
742
743
744 HRESULT
745 STDMETHODCALLTYPE
746 CKsProxy::QueryVendorInfo(
747 LPWSTR *pVendorInfo)
748 {
749 OutputDebugStringW(L"CKsProxy::QueryVendorInfo : NotImplemented\n");
750 return E_NOTIMPL;
751 }
752
753 //-------------------------------------------------------------------
754 // IAMovieSetup interface
755 //
756
757 HRESULT
758 STDMETHODCALLTYPE
759 CKsProxy::Register()
760 {
761 OutputDebugStringW(L"CKsProxy::Register : NotImplemented\n");
762 return E_NOTIMPL;
763 }
764
765 HRESULT
766 STDMETHODCALLTYPE
767 CKsProxy::Unregister()
768 {
769 OutputDebugStringW(L"CKsProxy::Unregister : NotImplemented\n");
770 return E_NOTIMPL;
771 }
772
773 HRESULT
774 WINAPI
775 CKsProxy_Constructor(
776 IUnknown * pUnkOuter,
777 REFIID riid,
778 LPVOID * ppv)
779 {
780 WCHAR Buffer[100];
781 LPOLESTR pstr;
782 StringFromCLSID(riid, &pstr);
783 swprintf(Buffer, L"CKsProxy_Constructor pUnkOuter %p riid %s\n", pUnkOuter, pstr);
784 OutputDebugStringW(Buffer);
785
786 CKsProxy * handler = new CKsProxy();
787
788 if (!handler)
789 return E_OUTOFMEMORY;
790
791 if (FAILED(handler->QueryInterface(riid, ppv)))
792 {
793 /* not supported */
794 delete handler;
795 return E_NOINTERFACE;
796 }
797
798 return S_OK;
799 }