A Fast Bresenham Type Algorithm For Drawing Ellipses by John Kennedy
[xy_vsfilter.git] / src / filters / BaseClasses / ctlutil.cpp
blob7deee69d1c5332e3650fa63856ec91697476449f
1 //------------------------------------------------------------------------------
2 // File: CtlUtil.cpp
3 //
4 // Desc: DirectShow base classes.
5 //
6 // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
7 //------------------------------------------------------------------------------
10 // Base classes implementing IDispatch parsing for the basic control dual
11 // interfaces. Derive from these and implement just the custom method and
12 // property methods. We also implement CPosPassThru that can be used by
13 // renderers and transforms to pass by IMediaPosition and IMediaSeeking
16 #include <streams.h>
17 #include <limits.h>
18 #include "seekpt.h"
20 // 'bool' non standard reserved word
21 #pragma warning(disable:4237)
24 // --- CBaseDispatch implementation ----------
25 CBaseDispatch::~CBaseDispatch()
27 if (m_pti) {
28 m_pti->Release();
33 // return 1 if we support GetTypeInfo
35 STDMETHODIMP
36 CBaseDispatch::GetTypeInfoCount(UINT * pctinfo)
38 CheckPointer(pctinfo,E_POINTER);
39 ValidateReadWritePtr(pctinfo,sizeof(UINT *));
40 *pctinfo = 1;
41 return S_OK;
45 typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)(
46 const OLECHAR FAR *szFile,
47 ITypeLib FAR* FAR* pptlib);
49 typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid,
50 WORD wVerMajor,
51 WORD wVerMinor,
52 LCID lcid,
53 ITypeLib FAR* FAR* pptlib);
55 // attempt to find our type library
57 STDMETHODIMP
58 CBaseDispatch::GetTypeInfo(
59 REFIID riid,
60 UINT itinfo,
61 LCID lcid,
62 ITypeInfo ** pptinfo)
64 CheckPointer(pptinfo,E_POINTER);
65 ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *));
66 HRESULT hr;
68 *pptinfo = NULL;
70 // we only support one type element
71 if (0 != itinfo) {
72 return TYPE_E_ELEMENTNOTFOUND;
75 if (NULL == pptinfo) {
76 return E_POINTER;
79 // always look for neutral
80 if (NULL == m_pti) {
82 LPLOADTYPELIB lpfnLoadTypeLib;
83 LPLOADREGTYPELIB lpfnLoadRegTypeLib;
84 ITypeLib *ptlib;
85 HINSTANCE hInst;
87 static const char szTypeLib[] = "LoadTypeLib";
88 static const char szRegTypeLib[] = "LoadRegTypeLib";
89 static const WCHAR szControl[] = L"control.tlb";
92 // Try to get the Ole32Aut.dll module handle.
95 hInst = LoadOLEAut32();
96 if (hInst == NULL) {
97 DWORD dwError = GetLastError();
98 return AmHresultFromWin32(dwError);
100 lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst,
101 szRegTypeLib);
102 if (lpfnLoadRegTypeLib == NULL) {
103 DWORD dwError = GetLastError();
104 return AmHresultFromWin32(dwError);
107 hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0
108 lcid, &ptlib);
110 if (FAILED(hr)) {
112 // attempt to load directly - this will fill the
113 // registry in if it finds it
115 lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib);
116 if (lpfnLoadTypeLib == NULL) {
117 DWORD dwError = GetLastError();
118 return AmHresultFromWin32(dwError);
121 hr = (*lpfnLoadTypeLib)(szControl, &ptlib);
122 if (FAILED(hr)) {
123 return hr;
127 hr = ptlib->GetTypeInfoOfGuid(
128 riid,
129 &m_pti);
131 ptlib->Release();
133 if (FAILED(hr)) {
134 return hr;
138 *pptinfo = m_pti;
139 m_pti->AddRef();
140 return S_OK;
144 STDMETHODIMP
145 CBaseDispatch::GetIDsOfNames(
146 REFIID riid,
147 OLECHAR ** rgszNames,
148 UINT cNames,
149 LCID lcid,
150 DISPID * rgdispid)
152 // although the IDispatch riid is dead, we use this to pass from
153 // the interface implementation class to us the iid we are talking about.
155 ITypeInfo * pti;
156 HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti);
158 if (SUCCEEDED(hr)) {
159 hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid);
161 pti->Release();
163 return hr;
167 // --- CMediaControl implementation ---------
169 CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) :
170 CUnknown(name, pUnk)
174 // expose our interfaces IMediaControl and IUnknown
176 STDMETHODIMP
177 CMediaControl::NonDelegatingQueryInterface(REFIID riid, void **ppv)
179 ValidateReadWritePtr(ppv,sizeof(PVOID));
180 if (riid == IID_IMediaControl) {
181 return GetInterface( (IMediaControl *) this, ppv);
182 } else {
183 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
188 // return 1 if we support GetTypeInfo
190 STDMETHODIMP
191 CMediaControl::GetTypeInfoCount(UINT * pctinfo)
193 return m_basedisp.GetTypeInfoCount(pctinfo);
197 // attempt to find our type library
199 STDMETHODIMP
200 CMediaControl::GetTypeInfo(
201 UINT itinfo,
202 LCID lcid,
203 ITypeInfo ** pptinfo)
205 return m_basedisp.GetTypeInfo(
206 IID_IMediaControl,
207 itinfo,
208 lcid,
209 pptinfo);
213 STDMETHODIMP
214 CMediaControl::GetIDsOfNames(
215 REFIID riid,
216 OLECHAR ** rgszNames,
217 UINT cNames,
218 LCID lcid,
219 DISPID * rgdispid)
221 return m_basedisp.GetIDsOfNames(
222 IID_IMediaControl,
223 rgszNames,
224 cNames,
225 lcid,
226 rgdispid);
230 STDMETHODIMP
231 CMediaControl::Invoke(
232 DISPID dispidMember,
233 REFIID riid,
234 LCID lcid,
235 WORD wFlags,
236 DISPPARAMS * pdispparams,
237 VARIANT * pvarResult,
238 EXCEPINFO * pexcepinfo,
239 UINT * puArgErr)
241 // this parameter is a dead leftover from an earlier interface
242 if (IID_NULL != riid) {
243 return DISP_E_UNKNOWNINTERFACE;
246 ITypeInfo * pti;
247 HRESULT hr = GetTypeInfo(0, lcid, &pti);
249 if (FAILED(hr)) {
250 return hr;
253 hr = pti->Invoke(
254 (IMediaControl *)this,
255 dispidMember,
256 wFlags,
257 pdispparams,
258 pvarResult,
259 pexcepinfo,
260 puArgErr);
262 pti->Release();
263 return hr;
267 // --- CMediaEvent implementation ----------
270 CMediaEvent::CMediaEvent(const TCHAR * name,LPUNKNOWN pUnk) :
271 CUnknown(name, pUnk)
276 // expose our interfaces IMediaEvent and IUnknown
278 STDMETHODIMP
279 CMediaEvent::NonDelegatingQueryInterface(REFIID riid, void **ppv)
281 ValidateReadWritePtr(ppv,sizeof(PVOID));
282 if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) {
283 return GetInterface( (IMediaEventEx *) this, ppv);
284 } else {
285 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
290 // return 1 if we support GetTypeInfo
292 STDMETHODIMP
293 CMediaEvent::GetTypeInfoCount(UINT * pctinfo)
295 return m_basedisp.GetTypeInfoCount(pctinfo);
299 // attempt to find our type library
301 STDMETHODIMP
302 CMediaEvent::GetTypeInfo(
303 UINT itinfo,
304 LCID lcid,
305 ITypeInfo ** pptinfo)
307 return m_basedisp.GetTypeInfo(
308 IID_IMediaEvent,
309 itinfo,
310 lcid,
311 pptinfo);
315 STDMETHODIMP
316 CMediaEvent::GetIDsOfNames(
317 REFIID riid,
318 OLECHAR ** rgszNames,
319 UINT cNames,
320 LCID lcid,
321 DISPID * rgdispid)
323 return m_basedisp.GetIDsOfNames(
324 IID_IMediaEvent,
325 rgszNames,
326 cNames,
327 lcid,
328 rgdispid);
332 STDMETHODIMP
333 CMediaEvent::Invoke(
334 DISPID dispidMember,
335 REFIID riid,
336 LCID lcid,
337 WORD wFlags,
338 DISPPARAMS * pdispparams,
339 VARIANT * pvarResult,
340 EXCEPINFO * pexcepinfo,
341 UINT * puArgErr)
343 // this parameter is a dead leftover from an earlier interface
344 if (IID_NULL != riid) {
345 return DISP_E_UNKNOWNINTERFACE;
348 ITypeInfo * pti;
349 HRESULT hr = GetTypeInfo(0, lcid, &pti);
351 if (FAILED(hr)) {
352 return hr;
355 hr = pti->Invoke(
356 (IMediaEvent *)this,
357 dispidMember,
358 wFlags,
359 pdispparams,
360 pvarResult,
361 pexcepinfo,
362 puArgErr);
364 pti->Release();
365 return hr;
369 // --- CMediaPosition implementation ----------
372 CMediaPosition::CMediaPosition(const TCHAR * name,LPUNKNOWN pUnk) :
373 CUnknown(name, pUnk)
377 CMediaPosition::CMediaPosition(const TCHAR * name,
378 LPUNKNOWN pUnk,
379 HRESULT * phr) :
380 CUnknown(name, pUnk)
382 UNREFERENCED_PARAMETER(phr);
386 // expose our interfaces IMediaPosition and IUnknown
388 STDMETHODIMP
389 CMediaPosition::NonDelegatingQueryInterface(REFIID riid, void **ppv)
391 ValidateReadWritePtr(ppv,sizeof(PVOID));
392 if (riid == IID_IMediaPosition) {
393 return GetInterface( (IMediaPosition *) this, ppv);
394 } else {
395 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
400 // return 1 if we support GetTypeInfo
402 STDMETHODIMP
403 CMediaPosition::GetTypeInfoCount(UINT * pctinfo)
405 return m_basedisp.GetTypeInfoCount(pctinfo);
409 // attempt to find our type library
411 STDMETHODIMP
412 CMediaPosition::GetTypeInfo(
413 UINT itinfo,
414 LCID lcid,
415 ITypeInfo ** pptinfo)
417 return m_basedisp.GetTypeInfo(
418 IID_IMediaPosition,
419 itinfo,
420 lcid,
421 pptinfo);
425 STDMETHODIMP
426 CMediaPosition::GetIDsOfNames(
427 REFIID riid,
428 OLECHAR ** rgszNames,
429 UINT cNames,
430 LCID lcid,
431 DISPID * rgdispid)
433 return m_basedisp.GetIDsOfNames(
434 IID_IMediaPosition,
435 rgszNames,
436 cNames,
437 lcid,
438 rgdispid);
442 STDMETHODIMP
443 CMediaPosition::Invoke(
444 DISPID dispidMember,
445 REFIID riid,
446 LCID lcid,
447 WORD wFlags,
448 DISPPARAMS * pdispparams,
449 VARIANT * pvarResult,
450 EXCEPINFO * pexcepinfo,
451 UINT * puArgErr)
453 // this parameter is a dead leftover from an earlier interface
454 if (IID_NULL != riid) {
455 return DISP_E_UNKNOWNINTERFACE;
458 ITypeInfo * pti;
459 HRESULT hr = GetTypeInfo(0, lcid, &pti);
461 if (FAILED(hr)) {
462 return hr;
465 hr = pti->Invoke(
466 (IMediaPosition *)this,
467 dispidMember,
468 wFlags,
469 pdispparams,
470 pvarResult,
471 pexcepinfo,
472 puArgErr);
474 pti->Release();
475 return hr;
479 // --- IMediaPosition and IMediaSeeking pass through class ----------
482 CPosPassThru::CPosPassThru(const TCHAR *pName,
483 LPUNKNOWN pUnk,
484 HRESULT *phr,
485 IPin *pPin) :
486 CMediaPosition(pName,pUnk),
487 m_pPin(pPin)
489 if (pPin == NULL) {
490 *phr = E_POINTER;
491 return;
496 // Expose our IMediaSeeking and IMediaPosition interfaces
498 STDMETHODIMP
499 CPosPassThru::NonDelegatingQueryInterface(REFIID riid,void **ppv)
501 CheckPointer(ppv,E_POINTER);
502 *ppv = NULL;
504 if (riid == IID_IMediaSeeking) {
505 return GetInterface( static_cast<IMediaSeeking *>(this), ppv);
507 return CMediaPosition::NonDelegatingQueryInterface(riid,ppv);
511 // Return the IMediaPosition interface from our peer
513 HRESULT
514 CPosPassThru::GetPeer(IMediaPosition ** ppMP)
516 *ppMP = NULL;
518 IPin *pConnected;
519 HRESULT hr = m_pPin->ConnectedTo(&pConnected);
520 if (FAILED(hr)) {
521 return E_NOTIMPL;
523 IMediaPosition * pMP;
524 hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP);
525 pConnected->Release();
526 if (FAILED(hr)) {
527 return E_NOTIMPL;
530 *ppMP = pMP;
531 return S_OK;
535 // Return the IMediaSeeking interface from our peer
537 HRESULT
538 CPosPassThru::GetPeerSeeking(IMediaSeeking ** ppMS)
540 *ppMS = NULL;
542 IPin *pConnected;
543 HRESULT hr = m_pPin->ConnectedTo(&pConnected);
544 if (FAILED(hr)) {
545 return E_NOTIMPL;
547 IMediaSeeking * pMS;
548 hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS);
549 pConnected->Release();
550 if (FAILED(hr)) {
551 return E_NOTIMPL;
554 *ppMS = pMS;
555 return S_OK;
559 // --- IMediaSeeking methods ----------
562 STDMETHODIMP
563 CPosPassThru::GetCapabilities(DWORD * pCaps)
565 IMediaSeeking* pMS;
566 HRESULT hr = GetPeerSeeking(&pMS);
567 if (FAILED(hr)) {
568 return hr;
571 hr = pMS->GetCapabilities(pCaps);
572 pMS->Release();
573 return hr;
576 STDMETHODIMP
577 CPosPassThru::CheckCapabilities(DWORD * pCaps)
579 IMediaSeeking* pMS;
580 HRESULT hr = GetPeerSeeking(&pMS);
581 if (FAILED(hr)) {
582 return hr;
585 hr = pMS->CheckCapabilities(pCaps);
586 pMS->Release();
587 return hr;
590 STDMETHODIMP
591 CPosPassThru::IsFormatSupported(const GUID * pFormat)
593 IMediaSeeking* pMS;
594 HRESULT hr = GetPeerSeeking(&pMS);
595 if (FAILED(hr)) {
596 return hr;
599 hr = pMS->IsFormatSupported(pFormat);
600 pMS->Release();
601 return hr;
605 STDMETHODIMP
606 CPosPassThru::QueryPreferredFormat(GUID *pFormat)
608 IMediaSeeking* pMS;
609 HRESULT hr = GetPeerSeeking(&pMS);
610 if (FAILED(hr)) {
611 return hr;
614 hr = pMS->QueryPreferredFormat(pFormat);
615 pMS->Release();
616 return hr;
620 STDMETHODIMP
621 CPosPassThru::SetTimeFormat(const GUID * pFormat)
623 IMediaSeeking* pMS;
624 HRESULT hr = GetPeerSeeking(&pMS);
625 if (FAILED(hr)) {
626 return hr;
629 hr = pMS->SetTimeFormat(pFormat);
630 pMS->Release();
631 return hr;
635 STDMETHODIMP
636 CPosPassThru::GetTimeFormat(GUID *pFormat)
638 IMediaSeeking* pMS;
639 HRESULT hr = GetPeerSeeking(&pMS);
640 if (FAILED(hr)) {
641 return hr;
644 hr = pMS->GetTimeFormat(pFormat);
645 pMS->Release();
646 return hr;
650 STDMETHODIMP
651 CPosPassThru::IsUsingTimeFormat(const GUID * pFormat)
653 IMediaSeeking* pMS;
654 HRESULT hr = GetPeerSeeking(&pMS);
655 if (FAILED(hr)) {
656 return hr;
659 hr = pMS->IsUsingTimeFormat(pFormat);
660 pMS->Release();
661 return hr;
665 STDMETHODIMP
666 CPosPassThru::ConvertTimeFormat(LONGLONG * pTarget, const GUID * pTargetFormat,
667 LONGLONG Source, const GUID * pSourceFormat )
669 IMediaSeeking* pMS;
670 HRESULT hr = GetPeerSeeking(&pMS);
671 if (FAILED(hr)) {
672 return hr;
675 hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat );
676 pMS->Release();
677 return hr;
681 STDMETHODIMP
682 CPosPassThru::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags
683 , LONGLONG * pStop, DWORD StopFlags )
685 IMediaSeeking* pMS;
686 HRESULT hr = GetPeerSeeking(&pMS);
687 if (FAILED(hr)) {
688 return hr;
691 hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags );
692 pMS->Release();
693 return hr;
696 STDMETHODIMP
697 CPosPassThru::GetPositions(LONGLONG *pCurrent, LONGLONG * pStop)
699 IMediaSeeking* pMS;
700 HRESULT hr = GetPeerSeeking(&pMS);
701 if (FAILED(hr)) {
702 return hr;
705 hr = pMS->GetPositions(pCurrent,pStop);
706 pMS->Release();
707 return hr;
710 HRESULT
711 CPosPassThru::GetSeekingLongLong
712 ( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * )
713 , LONGLONG * pll
716 IMediaSeeking* pMS;
717 HRESULT hr = GetPeerSeeking(&pMS);
718 if (SUCCEEDED(hr))
720 hr = (pMS->*pMethod)(pll);
721 pMS->Release();
723 return hr;
726 // If we don't have a current position then ask upstream
728 STDMETHODIMP
729 CPosPassThru::GetCurrentPosition(LONGLONG *pCurrent)
731 // Can we report the current position
732 HRESULT hr = GetMediaTime(pCurrent,NULL);
733 if (SUCCEEDED(hr)) hr = NOERROR;
734 else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent );
735 return hr;
739 STDMETHODIMP
740 CPosPassThru::GetStopPosition(LONGLONG *pStop)
742 return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );;
745 STDMETHODIMP
746 CPosPassThru::GetDuration(LONGLONG *pDuration)
748 return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );;
752 STDMETHODIMP
753 CPosPassThru::GetPreroll(LONGLONG *pllPreroll)
755 return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );;
759 STDMETHODIMP
760 CPosPassThru::GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest )
762 IMediaSeeking* pMS;
763 HRESULT hr = GetPeerSeeking(&pMS);
764 if (FAILED(hr)) {
765 return hr;
768 hr = pMS->GetAvailable( pEarliest, pLatest );
769 pMS->Release();
770 return hr;
774 STDMETHODIMP
775 CPosPassThru::GetRate(double * pdRate)
777 IMediaSeeking* pMS;
778 HRESULT hr = GetPeerSeeking(&pMS);
779 if (FAILED(hr)) {
780 return hr;
782 hr = pMS->GetRate(pdRate);
783 pMS->Release();
784 return hr;
788 STDMETHODIMP
789 CPosPassThru::SetRate(double dRate)
791 if (0.0 == dRate) {
792 return E_INVALIDARG;
795 IMediaSeeking* pMS;
796 HRESULT hr = GetPeerSeeking(&pMS);
797 if (FAILED(hr)) {
798 return hr;
800 hr = pMS->SetRate(dRate);
801 pMS->Release();
802 return hr;
808 // --- IMediaPosition methods ----------
811 STDMETHODIMP
812 CPosPassThru::get_Duration(REFTIME * plength)
814 IMediaPosition* pMP;
815 HRESULT hr = GetPeer(&pMP);
816 if (FAILED(hr)) {
817 return hr;
820 hr = pMP->get_Duration(plength);
821 pMP->Release();
822 return hr;
826 STDMETHODIMP
827 CPosPassThru::get_CurrentPosition(REFTIME * pllTime)
829 IMediaPosition* pMP;
830 HRESULT hr = GetPeer(&pMP);
831 if (FAILED(hr)) {
832 return hr;
834 hr = pMP->get_CurrentPosition(pllTime);
835 pMP->Release();
836 return hr;
840 STDMETHODIMP
841 CPosPassThru::put_CurrentPosition(REFTIME llTime)
843 IMediaPosition* pMP;
844 HRESULT hr = GetPeer(&pMP);
845 if (FAILED(hr)) {
846 return hr;
848 hr = pMP->put_CurrentPosition(llTime);
849 pMP->Release();
850 return hr;
854 STDMETHODIMP
855 CPosPassThru::get_StopTime(REFTIME * pllTime)
857 IMediaPosition* pMP;
858 HRESULT hr = GetPeer(&pMP);
859 if (FAILED(hr)) {
860 return hr;
862 hr = pMP->get_StopTime(pllTime);
863 pMP->Release();
864 return hr;
868 STDMETHODIMP
869 CPosPassThru::put_StopTime(REFTIME llTime)
871 IMediaPosition* pMP;
872 HRESULT hr = GetPeer(&pMP);
873 if (FAILED(hr)) {
874 return hr;
876 hr = pMP->put_StopTime(llTime);
877 pMP->Release();
878 return hr;
882 STDMETHODIMP
883 CPosPassThru::get_PrerollTime(REFTIME * pllTime)
885 IMediaPosition* pMP;
886 HRESULT hr = GetPeer(&pMP);
887 if (FAILED(hr)) {
888 return hr;
890 hr = pMP->get_PrerollTime(pllTime);
891 pMP->Release();
892 return hr;
896 STDMETHODIMP
897 CPosPassThru::put_PrerollTime(REFTIME llTime)
899 IMediaPosition* pMP;
900 HRESULT hr = GetPeer(&pMP);
901 if (FAILED(hr)) {
902 return hr;
904 hr = pMP->put_PrerollTime(llTime);
905 pMP->Release();
906 return hr;
910 STDMETHODIMP
911 CPosPassThru::get_Rate(double * pdRate)
913 IMediaPosition* pMP;
914 HRESULT hr = GetPeer(&pMP);
915 if (FAILED(hr)) {
916 return hr;
918 hr = pMP->get_Rate(pdRate);
919 pMP->Release();
920 return hr;
924 STDMETHODIMP
925 CPosPassThru::put_Rate(double dRate)
927 if (0.0 == dRate) {
928 return E_INVALIDARG;
931 IMediaPosition* pMP;
932 HRESULT hr = GetPeer(&pMP);
933 if (FAILED(hr)) {
934 return hr;
936 hr = pMP->put_Rate(dRate);
937 pMP->Release();
938 return hr;
942 STDMETHODIMP
943 CPosPassThru::CanSeekForward(LONG *pCanSeekForward)
945 IMediaPosition* pMP;
946 HRESULT hr = GetPeer(&pMP);
947 if (FAILED(hr)) {
948 return hr;
950 hr = pMP->CanSeekForward(pCanSeekForward);
951 pMP->Release();
952 return hr;
956 STDMETHODIMP
957 CPosPassThru::CanSeekBackward(LONG *pCanSeekBackward)
959 IMediaPosition* pMP;
960 HRESULT hr = GetPeer(&pMP);
961 if (FAILED(hr)) {
962 return hr;
964 hr = pMP->CanSeekBackward(pCanSeekBackward);
965 pMP->Release();
966 return hr;
970 // --- Implements the CRendererPosPassThru class ----------
973 // Media times (eg current frame, field, sample etc) are passed through the
974 // filtergraph in media samples. When a renderer gets a sample with media
975 // times in it, it will call one of the RegisterMediaTime methods we expose
976 // (one takes an IMediaSample, the other takes the media times direct). We
977 // store the media times internally and return them in GetCurrentPosition.
979 CRendererPosPassThru::CRendererPosPassThru(const TCHAR *pName,
980 LPUNKNOWN pUnk,
981 HRESULT *phr,
982 IPin *pPin) :
983 CPosPassThru(pName,pUnk,phr,pPin),
984 m_StartMedia(0),
985 m_EndMedia(0),
986 m_bReset(TRUE)
991 // Sets the media times the object should report
993 HRESULT
994 CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample)
996 ASSERT(pMediaSample);
997 LONGLONG StartMedia;
998 LONGLONG EndMedia;
1000 CAutoLock cAutoLock(&m_PositionLock);
1002 // Get the media times from the sample
1004 HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia);
1005 if (FAILED(hr))
1007 ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET);
1008 return hr;
1011 m_StartMedia = StartMedia;
1012 m_EndMedia = EndMedia;
1013 m_bReset = FALSE;
1014 return NOERROR;
1018 // Sets the media times the object should report
1020 HRESULT
1021 CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime)
1023 CAutoLock cAutoLock(&m_PositionLock);
1024 m_StartMedia = StartTime;
1025 m_EndMedia = EndTime;
1026 m_bReset = FALSE;
1027 return NOERROR;
1031 // Return the current media times registered in the object
1033 HRESULT
1034 CRendererPosPassThru::GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime)
1036 ASSERT(pStartTime);
1038 CAutoLock cAutoLock(&m_PositionLock);
1039 if (m_bReset == TRUE) {
1040 return E_FAIL;
1043 // We don't have to return the end time
1045 HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME );
1046 if (pEndTime && SUCCEEDED(hr)) {
1047 hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME );
1049 return hr;
1053 // Resets the media times we hold
1055 HRESULT
1056 CRendererPosPassThru::ResetMediaTime()
1058 CAutoLock cAutoLock(&m_PositionLock);
1059 m_StartMedia = 0;
1060 m_EndMedia = 0;
1061 m_bReset = TRUE;
1062 return NOERROR;
1065 // Intended to be called by the owing filter during EOS processing so
1066 // that the media times can be adjusted to the stop time. This ensures
1067 // that the GetCurrentPosition will actully get to the stop position.
1068 HRESULT
1069 CRendererPosPassThru::EOS()
1071 HRESULT hr;
1073 if ( m_bReset == TRUE ) hr = E_FAIL;
1074 else
1076 LONGLONG llStop;
1077 if SUCCEEDED(hr=GetStopPosition(&llStop))
1079 CAutoLock cAutoLock(&m_PositionLock);
1080 m_StartMedia =
1081 m_EndMedia = llStop;
1084 return hr;
1087 // -- CSourceSeeking implementation ------------
1089 CSourceSeeking::CSourceSeeking(
1090 const TCHAR * pName,
1091 LPUNKNOWN pUnk,
1092 HRESULT* phr,
1093 CCritSec * pLock) :
1094 CUnknown(pName, pUnk),
1095 m_pLock(pLock),
1096 m_rtStart((long)0)
1098 m_rtStop = _I64_MAX / 2;
1099 m_rtDuration = m_rtStop;
1100 m_dRateSeeking = 1.0;
1102 m_dwSeekingCaps = AM_SEEKING_CanSeekForwards
1103 | AM_SEEKING_CanSeekBackwards
1104 | AM_SEEKING_CanSeekAbsolute
1105 | AM_SEEKING_CanGetStopPos
1106 | AM_SEEKING_CanGetDuration;
1109 HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, void **ppv)
1111 if(riid == IID_IMediaSeeking) {
1112 CheckPointer(ppv, E_POINTER);
1113 return GetInterface(static_cast<IMediaSeeking *>(this), ppv);
1115 else {
1116 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1121 HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat)
1123 CheckPointer(pFormat, E_POINTER);
1124 // only seeking in time (REFERENCE_TIME units) is supported
1125 return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
1128 HRESULT CSourceSeeking::QueryPreferredFormat(GUID *pFormat)
1130 CheckPointer(pFormat, E_POINTER);
1131 *pFormat = TIME_FORMAT_MEDIA_TIME;
1132 return S_OK;
1135 HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat)
1137 CheckPointer(pFormat, E_POINTER);
1139 // nothing to set; just check that it's TIME_FORMAT_TIME
1140 return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG;
1143 HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat)
1145 CheckPointer(pFormat, E_POINTER);
1146 return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
1149 HRESULT CSourceSeeking::GetTimeFormat(GUID *pFormat)
1151 CheckPointer(pFormat, E_POINTER);
1152 *pFormat = TIME_FORMAT_MEDIA_TIME;
1153 return S_OK;
1156 HRESULT CSourceSeeking::GetDuration(LONGLONG *pDuration)
1158 CheckPointer(pDuration, E_POINTER);
1159 CAutoLock lock(m_pLock);
1160 *pDuration = m_rtDuration;
1161 return S_OK;
1164 HRESULT CSourceSeeking::GetStopPosition(LONGLONG *pStop)
1166 CheckPointer(pStop, E_POINTER);
1167 CAutoLock lock(m_pLock);
1168 *pStop = m_rtStop;
1169 return S_OK;
1172 HRESULT CSourceSeeking::GetCurrentPosition(LONGLONG *pCurrent)
1174 // GetCurrentPosition is typically supported only in renderers and
1175 // not in source filters.
1176 return E_NOTIMPL;
1179 HRESULT CSourceSeeking::GetCapabilities( DWORD * pCapabilities )
1181 CheckPointer(pCapabilities, E_POINTER);
1182 *pCapabilities = m_dwSeekingCaps;
1183 return S_OK;
1186 HRESULT CSourceSeeking::CheckCapabilities( DWORD * pCapabilities )
1188 CheckPointer(pCapabilities, E_POINTER);
1190 // make sure all requested capabilities are in our mask
1191 return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK;
1194 HRESULT CSourceSeeking::ConvertTimeFormat( LONGLONG * pTarget, const GUID * pTargetFormat,
1195 LONGLONG Source, const GUID * pSourceFormat )
1197 CheckPointer(pTarget, E_POINTER);
1198 // format guids can be null to indicate current format
1200 // since we only support TIME_FORMAT_MEDIA_TIME, we don't really
1201 // offer any conversions.
1202 if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME)
1204 if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME)
1206 *pTarget = Source;
1207 return S_OK;
1211 return E_INVALIDARG;
1215 HRESULT CSourceSeeking::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags
1216 , LONGLONG * pStop, DWORD StopFlags )
1218 DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask;
1219 DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask;
1221 if(StopFlags) {
1222 CheckPointer(pStop, E_POINTER);
1224 // accept only relative, incremental, or absolute positioning
1225 if(StopPosBits != StopFlags) {
1226 return E_INVALIDARG;
1230 if(CurrentFlags) {
1231 CheckPointer(pCurrent, E_POINTER);
1232 if(StartPosBits != AM_SEEKING_AbsolutePositioning &&
1233 StartPosBits != AM_SEEKING_RelativePositioning) {
1234 return E_INVALIDARG;
1239 // scope for autolock
1241 CAutoLock lock(m_pLock);
1243 // set start position
1244 if(StartPosBits == AM_SEEKING_AbsolutePositioning)
1246 m_rtStart = *pCurrent;
1248 else if(StartPosBits == AM_SEEKING_RelativePositioning)
1250 m_rtStart += *pCurrent;
1253 // set stop position
1254 if(StopPosBits == AM_SEEKING_AbsolutePositioning)
1256 m_rtStop = *pStop;
1258 else if(StopPosBits == AM_SEEKING_IncrementalPositioning)
1260 m_rtStop = m_rtStart + *pStop;
1262 else if(StopPosBits == AM_SEEKING_RelativePositioning)
1264 m_rtStop = m_rtStop + *pStop;
1269 HRESULT hr = S_OK;
1270 if(SUCCEEDED(hr) && StopPosBits) {
1271 hr = ChangeStop();
1273 if(StartPosBits) {
1274 hr = ChangeStart();
1277 return hr;
1281 HRESULT CSourceSeeking::GetPositions( LONGLONG * pCurrent, LONGLONG * pStop )
1283 if(pCurrent) {
1284 *pCurrent = m_rtStart;
1286 if(pStop) {
1287 *pStop = m_rtStop;
1290 return S_OK;;
1294 HRESULT CSourceSeeking::GetAvailable( LONGLONG * pEarliest, LONGLONG * pLatest )
1296 if(pEarliest) {
1297 *pEarliest = 0;
1299 if(pLatest) {
1300 CAutoLock lock(m_pLock);
1301 *pLatest = m_rtDuration;
1303 return S_OK;
1306 HRESULT CSourceSeeking::SetRate( double dRate)
1309 CAutoLock lock(m_pLock);
1310 m_dRateSeeking = dRate;
1312 return ChangeRate();
1315 HRESULT CSourceSeeking::GetRate( double * pdRate)
1317 CheckPointer(pdRate, E_POINTER);
1318 CAutoLock lock(m_pLock);
1319 *pdRate = m_dRateSeeking;
1320 return S_OK;
1323 HRESULT CSourceSeeking::GetPreroll(LONGLONG *pPreroll)
1325 CheckPointer(pPreroll, E_POINTER);
1326 *pPreroll = 0;
1327 return S_OK;
1334 // --- CSourcePosition implementation ----------
1337 CSourcePosition::CSourcePosition(const TCHAR * pName,
1338 LPUNKNOWN pUnk,
1339 HRESULT* phr,
1340 CCritSec * pLock) :
1341 CMediaPosition(pName, pUnk),
1342 m_pLock(pLock),
1343 m_Start(CRefTime((LONGLONG)0))
1345 m_Stop = _I64_MAX;
1346 m_Rate = 1.0;
1350 STDMETHODIMP
1351 CSourcePosition::get_Duration(REFTIME * plength)
1353 CheckPointer(plength,E_POINTER);
1354 ValidateReadWritePtr(plength,sizeof(REFTIME));
1355 CAutoLock lock(m_pLock);
1357 *plength = m_Duration;
1358 return S_OK;
1362 STDMETHODIMP
1363 CSourcePosition::put_CurrentPosition(REFTIME llTime)
1365 m_pLock->Lock();
1366 m_Start = llTime;
1367 m_pLock->Unlock();
1369 return ChangeStart();
1373 STDMETHODIMP
1374 CSourcePosition::get_StopTime(REFTIME * pllTime)
1376 CheckPointer(pllTime,E_POINTER);
1377 ValidateReadWritePtr(pllTime,sizeof(REFTIME));
1378 CAutoLock lock(m_pLock);
1380 *pllTime = m_Stop;
1381 return S_OK;
1385 STDMETHODIMP
1386 CSourcePosition::put_StopTime(REFTIME llTime)
1388 m_pLock->Lock();
1389 m_Stop = llTime;
1390 m_pLock->Unlock();
1392 return ChangeStop();
1396 STDMETHODIMP
1397 CSourcePosition::get_PrerollTime(REFTIME * pllTime)
1399 CheckPointer(pllTime,E_POINTER);
1400 ValidateReadWritePtr(pllTime,sizeof(REFTIME));
1401 return E_NOTIMPL;
1405 STDMETHODIMP
1406 CSourcePosition::put_PrerollTime(REFTIME llTime)
1408 return E_NOTIMPL;
1412 STDMETHODIMP
1413 CSourcePosition::get_Rate(double * pdRate)
1415 CheckPointer(pdRate,E_POINTER);
1416 ValidateReadWritePtr(pdRate,sizeof(double));
1417 CAutoLock lock(m_pLock);
1419 *pdRate = m_Rate;
1420 return S_OK;
1424 STDMETHODIMP
1425 CSourcePosition::put_Rate(double dRate)
1427 m_pLock->Lock();
1428 m_Rate = dRate;
1429 m_pLock->Unlock();
1431 return ChangeRate();
1435 // By default we can seek forwards
1437 STDMETHODIMP
1438 CSourcePosition::CanSeekForward(LONG *pCanSeekForward)
1440 CheckPointer(pCanSeekForward,E_POINTER);
1441 *pCanSeekForward = OATRUE;
1442 return S_OK;
1446 // By default we can seek backwards
1448 STDMETHODIMP
1449 CSourcePosition::CanSeekBackward(LONG *pCanSeekBackward)
1451 CheckPointer(pCanSeekBackward,E_POINTER);
1452 *pCanSeekBackward = OATRUE;
1453 return S_OK;
1457 // --- Implementation of CBasicAudio class ----------
1460 CBasicAudio::CBasicAudio(const TCHAR * pName,LPUNKNOWN punk) :
1461 CUnknown(pName, punk)
1465 // overriden to publicise our interfaces
1467 STDMETHODIMP
1468 CBasicAudio::NonDelegatingQueryInterface(REFIID riid, void **ppv)
1470 ValidateReadWritePtr(ppv,sizeof(PVOID));
1471 if (riid == IID_IBasicAudio) {
1472 return GetInterface( (IBasicAudio *) this, ppv);
1473 } else {
1474 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1479 STDMETHODIMP
1480 CBasicAudio::GetTypeInfoCount(UINT * pctinfo)
1482 return m_basedisp.GetTypeInfoCount(pctinfo);
1486 STDMETHODIMP
1487 CBasicAudio::GetTypeInfo(
1488 UINT itinfo,
1489 LCID lcid,
1490 ITypeInfo ** pptinfo)
1492 return m_basedisp.GetTypeInfo(
1493 IID_IBasicAudio,
1494 itinfo,
1495 lcid,
1496 pptinfo);
1500 STDMETHODIMP
1501 CBasicAudio::GetIDsOfNames(
1502 REFIID riid,
1503 OLECHAR ** rgszNames,
1504 UINT cNames,
1505 LCID lcid,
1506 DISPID * rgdispid)
1508 return m_basedisp.GetIDsOfNames(
1509 IID_IBasicAudio,
1510 rgszNames,
1511 cNames,
1512 lcid,
1513 rgdispid);
1517 STDMETHODIMP
1518 CBasicAudio::Invoke(
1519 DISPID dispidMember,
1520 REFIID riid,
1521 LCID lcid,
1522 WORD wFlags,
1523 DISPPARAMS * pdispparams,
1524 VARIANT * pvarResult,
1525 EXCEPINFO * pexcepinfo,
1526 UINT * puArgErr)
1528 // this parameter is a dead leftover from an earlier interface
1529 if (IID_NULL != riid) {
1530 return DISP_E_UNKNOWNINTERFACE;
1533 ITypeInfo * pti;
1534 HRESULT hr = GetTypeInfo(0, lcid, &pti);
1536 if (FAILED(hr)) {
1537 return hr;
1540 hr = pti->Invoke(
1541 (IBasicAudio *)this,
1542 dispidMember,
1543 wFlags,
1544 pdispparams,
1545 pvarResult,
1546 pexcepinfo,
1547 puArgErr);
1549 pti->Release();
1550 return hr;
1554 // --- IVideoWindow implementation ----------
1556 CBaseVideoWindow::CBaseVideoWindow(const TCHAR * pName,LPUNKNOWN punk) :
1557 CUnknown(pName, punk)
1562 // overriden to publicise our interfaces
1564 STDMETHODIMP
1565 CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, void **ppv)
1567 ValidateReadWritePtr(ppv,sizeof(PVOID));
1568 if (riid == IID_IVideoWindow) {
1569 return GetInterface( (IVideoWindow *) this, ppv);
1570 } else {
1571 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1576 STDMETHODIMP
1577 CBaseVideoWindow::GetTypeInfoCount(UINT * pctinfo)
1579 return m_basedisp.GetTypeInfoCount(pctinfo);
1583 STDMETHODIMP
1584 CBaseVideoWindow::GetTypeInfo(
1585 UINT itinfo,
1586 LCID lcid,
1587 ITypeInfo ** pptinfo)
1589 return m_basedisp.GetTypeInfo(
1590 IID_IVideoWindow,
1591 itinfo,
1592 lcid,
1593 pptinfo);
1597 STDMETHODIMP
1598 CBaseVideoWindow::GetIDsOfNames(
1599 REFIID riid,
1600 OLECHAR ** rgszNames,
1601 UINT cNames,
1602 LCID lcid,
1603 DISPID * rgdispid)
1605 return m_basedisp.GetIDsOfNames(
1606 IID_IVideoWindow,
1607 rgszNames,
1608 cNames,
1609 lcid,
1610 rgdispid);
1614 STDMETHODIMP
1615 CBaseVideoWindow::Invoke(
1616 DISPID dispidMember,
1617 REFIID riid,
1618 LCID lcid,
1619 WORD wFlags,
1620 DISPPARAMS * pdispparams,
1621 VARIANT * pvarResult,
1622 EXCEPINFO * pexcepinfo,
1623 UINT * puArgErr)
1625 // this parameter is a dead leftover from an earlier interface
1626 if (IID_NULL != riid) {
1627 return DISP_E_UNKNOWNINTERFACE;
1630 ITypeInfo * pti;
1631 HRESULT hr = GetTypeInfo(0, lcid, &pti);
1633 if (FAILED(hr)) {
1634 return hr;
1637 hr = pti->Invoke(
1638 (IVideoWindow *)this,
1639 dispidMember,
1640 wFlags,
1641 pdispparams,
1642 pvarResult,
1643 pexcepinfo,
1644 puArgErr);
1646 pti->Release();
1647 return hr;
1651 // --- IBasicVideo implementation ----------
1654 CBaseBasicVideo::CBaseBasicVideo(const TCHAR * pName,LPUNKNOWN punk) :
1655 CUnknown(pName, punk)
1660 // overriden to publicise our interfaces
1662 STDMETHODIMP
1663 CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, void **ppv)
1665 ValidateReadWritePtr(ppv,sizeof(PVOID));
1666 if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) {
1667 return GetInterface( static_cast<IBasicVideo2 *>(this), ppv);
1668 } else {
1669 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1674 STDMETHODIMP
1675 CBaseBasicVideo::GetTypeInfoCount(UINT * pctinfo)
1677 return m_basedisp.GetTypeInfoCount(pctinfo);
1681 STDMETHODIMP
1682 CBaseBasicVideo::GetTypeInfo(
1683 UINT itinfo,
1684 LCID lcid,
1685 ITypeInfo ** pptinfo)
1687 return m_basedisp.GetTypeInfo(
1688 IID_IBasicVideo,
1689 itinfo,
1690 lcid,
1691 pptinfo);
1695 STDMETHODIMP
1696 CBaseBasicVideo::GetIDsOfNames(
1697 REFIID riid,
1698 OLECHAR ** rgszNames,
1699 UINT cNames,
1700 LCID lcid,
1701 DISPID * rgdispid)
1703 return m_basedisp.GetIDsOfNames(
1704 IID_IBasicVideo,
1705 rgszNames,
1706 cNames,
1707 lcid,
1708 rgdispid);
1712 STDMETHODIMP
1713 CBaseBasicVideo::Invoke(
1714 DISPID dispidMember,
1715 REFIID riid,
1716 LCID lcid,
1717 WORD wFlags,
1718 DISPPARAMS * pdispparams,
1719 VARIANT * pvarResult,
1720 EXCEPINFO * pexcepinfo,
1721 UINT * puArgErr)
1723 // this parameter is a dead leftover from an earlier interface
1724 if (IID_NULL != riid) {
1725 return DISP_E_UNKNOWNINTERFACE;
1728 ITypeInfo * pti;
1729 HRESULT hr = GetTypeInfo(0, lcid, &pti);
1731 if (FAILED(hr)) {
1732 return hr;
1735 hr = pti->Invoke(
1736 (IBasicVideo *)this,
1737 dispidMember,
1738 wFlags,
1739 pdispparams,
1740 pvarResult,
1741 pexcepinfo,
1742 puArgErr);
1744 pti->Release();
1745 return hr;
1749 // --- Implementation of Deferred Commands ----------
1752 CDispParams::CDispParams(UINT nArgs, VARIANT* pArgs, HRESULT *phr)
1754 cNamedArgs = 0;
1755 rgdispidNamedArgs = NULL;
1756 cArgs = nArgs;
1758 if (cArgs) {
1759 rgvarg = new VARIANT[cArgs];
1760 if (NULL == rgvarg) {
1761 cArgs = 0;
1762 if (phr) {
1763 *phr = E_OUTOFMEMORY;
1765 return;
1768 for (UINT i = 0; i < cArgs; i++) {
1770 VARIANT * pDest = &rgvarg[i];
1771 VARIANT * pSrc = &pArgs[i];
1773 pDest->vt = pSrc->vt;
1774 switch(pDest->vt) {
1776 case VT_I4:
1777 pDest->lVal = pSrc->lVal;
1778 break;
1780 case VT_UI1:
1781 pDest->bVal = pSrc->bVal;
1782 break;
1784 case VT_I2:
1785 pDest->iVal = pSrc->iVal;
1786 break;
1788 case VT_R4:
1789 pDest->fltVal = pSrc->fltVal;
1790 break;
1792 case VT_R8:
1793 pDest->dblVal = pSrc->dblVal;
1794 break;
1796 case VT_BOOL:
1797 pDest->boolVal = pSrc->boolVal;
1798 break;
1800 case VT_ERROR:
1801 pDest->scode = pSrc->scode;
1802 break;
1804 case VT_CY:
1805 pDest->cyVal = pSrc->cyVal;
1806 break;
1808 case VT_DATE:
1809 pDest->date = pSrc->date;
1810 break;
1812 case VT_BSTR:
1813 if (pSrc->bstrVal == NULL) {
1814 pDest->bstrVal = NULL;
1815 } else {
1817 // a BSTR is a WORD followed by a UNICODE string.
1818 // the pointer points just after the WORD
1820 WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR)));
1821 OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))];
1822 if (pch) {
1823 WORD *pui = (WORD*)pch;
1824 *pui = len;
1825 pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR));
1826 CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR));
1827 } else {
1828 cArgs = i;
1829 if (phr) {
1830 *phr = E_OUTOFMEMORY;
1834 pDest->bstrVal = pSrc->bstrVal;
1835 break;
1837 case VT_UNKNOWN:
1838 pDest->punkVal = pSrc->punkVal;
1839 pDest->punkVal->AddRef();
1840 break;
1842 case VT_DISPATCH:
1843 pDest->pdispVal = pSrc->pdispVal;
1844 pDest->pdispVal->AddRef();
1845 break;
1847 default:
1848 // a type we haven't got round to adding yet!
1849 ASSERT(0);
1850 break;
1854 } else {
1855 rgvarg = NULL;
1861 CDispParams::~CDispParams()
1863 for (UINT i = 0; i < cArgs; i++) {
1864 switch(rgvarg[i].vt) {
1865 case VT_BSTR:
1866 if (rgvarg[i].bstrVal != NULL) {
1867 OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR));
1868 delete pch;
1870 break;
1872 case VT_UNKNOWN:
1873 rgvarg[i].punkVal->Release();
1874 break;
1876 case VT_DISPATCH:
1877 rgvarg[i].pdispVal->Release();
1878 break;
1881 delete[] rgvarg;
1885 // lifetime is controlled by refcounts (see defer.h)
1887 CDeferredCommand::CDeferredCommand(
1888 CCmdQueue * pQ,
1889 LPUNKNOWN pUnk,
1890 HRESULT * phr,
1891 LPUNKNOWN pUnkExecutor,
1892 REFTIME time,
1893 GUID* iid,
1894 long dispidMethod,
1895 short wFlags,
1896 long nArgs,
1897 VARIANT* pDispParams,
1898 VARIANT* pvarResult,
1899 short* puArgErr,
1900 BOOL bStream
1902 CUnknown(NAME("DeferredCommand"), pUnk),
1903 m_pQueue(pQ),
1904 m_pUnk(pUnkExecutor),
1905 m_iid(iid),
1906 m_dispidMethod(dispidMethod),
1907 m_wFlags(wFlags),
1908 m_DispParams(nArgs, pDispParams, phr),
1909 m_pvarResult(pvarResult),
1910 m_bStream(bStream),
1911 m_hrResult(E_ABORT)
1914 // convert REFTIME to REFERENCE_TIME
1915 COARefTime convertor(time);
1916 m_time = convertor;
1918 // no check of time validity - it's ok to queue a command that's
1919 // already late
1921 // check iid is supportable on pUnk by QueryInterface for it
1922 IUnknown * pInterface;
1923 HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface);
1924 if (FAILED(hr)) {
1925 *phr = hr;
1926 return;
1928 pInterface->Release();
1931 // !!! check dispidMethod and param/return types using typelib
1932 ITypeInfo *pti;
1933 hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti);
1934 if (FAILED(hr)) {
1935 *phr = hr;
1936 return;
1938 // !!! some sort of ITypeInfo validity check here
1939 pti->Release();
1942 // Fix up the dispid for put and get
1943 if (wFlags == DISPATCH_PROPERTYPUT) {
1944 m_DispParams.cNamedArgs = 1;
1945 m_DispId = DISPID_PROPERTYPUT;
1946 m_DispParams.rgdispidNamedArgs = &m_DispId;
1949 // all checks ok - add to queue
1950 hr = pQ->Insert(this);
1951 if (FAILED(hr)) {
1952 *phr = hr;
1957 // refcounts are held by caller of InvokeAt... and by list. So if
1958 // we get here, we can't be on the list
1960 #if 0
1961 CDeferredCommand::~CDeferredCommand()
1963 // this assert is invalid since if the queue is deleted while we are
1964 // still on the queue, we will have been removed by the queue and this
1965 // m_pQueue will not have been modified.
1966 // ASSERT(m_pQueue == NULL);
1968 // we don't hold a ref count on pUnk, which is the object that should
1969 // execute the command.
1970 // This is because there would otherwise be a circular refcount problem
1971 // since pUnk probably owns the CmdQueue object that has a refcount
1972 // on us.
1973 // The lifetime of pUnk is guaranteed by it being part of, or lifetime
1974 // controlled by, our parent object. As long as we are on the list, pUnk
1975 // must be valid. Once we are off the list, we do not use pUnk.
1978 #endif
1981 // overriden to publicise our interfaces
1983 STDMETHODIMP
1984 CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, void **ppv)
1986 ValidateReadWritePtr(ppv,sizeof(PVOID));
1987 if (riid == IID_IDeferredCommand) {
1988 return GetInterface( (IDeferredCommand *) this, ppv);
1989 } else {
1990 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1995 // remove from q. this will reduce the refcount by one (since the q
1996 // holds a count) but can't make us go away since he must have a
1997 // refcount in order to call this method.
1999 STDMETHODIMP
2000 CDeferredCommand::Cancel()
2002 if (m_pQueue == NULL) {
2003 return VFW_E_ALREADY_CANCELLED;
2006 HRESULT hr = m_pQueue->Remove(this);
2007 if (FAILED(hr)) {
2008 return hr;
2011 m_pQueue = NULL;
2012 return S_OK;
2016 STDMETHODIMP
2017 CDeferredCommand::Confidence(LONG* pConfidence)
2019 return E_NOTIMPL;
2023 STDMETHODIMP
2024 CDeferredCommand::GetHResult(HRESULT * phrResult)
2026 CheckPointer(phrResult,E_POINTER);
2027 ValidateReadWritePtr(phrResult,sizeof(HRESULT));
2029 if (m_pQueue != NULL) {
2030 return E_ABORT;
2032 *phrResult = m_hrResult;
2033 return S_OK;
2037 // set the time to be a new time (checking that it is valid) and
2038 // then requeue
2040 STDMETHODIMP
2041 CDeferredCommand::Postpone(REFTIME newtime)
2044 // check that this time is not past
2045 // convert REFTIME to REFERENCE_TIME
2046 COARefTime convertor(newtime);
2048 // check that the time has not passed
2049 if (m_pQueue->CheckTime(convertor, IsStreamTime())) {
2050 return VFW_E_TIME_ALREADY_PASSED;
2053 // extract from list
2054 HRESULT hr = m_pQueue->Remove(this);
2055 if (FAILED(hr)) {
2056 return hr;
2059 // change time
2060 m_time = convertor;
2062 // requeue
2063 hr = m_pQueue->Insert(this);
2065 return hr;
2069 HRESULT
2070 CDeferredCommand::Invoke()
2072 // check that we are still outstanding
2073 if (m_pQueue == NULL) {
2074 return VFW_E_ALREADY_CANCELLED;
2077 // get the type info
2078 ITypeInfo* pti;
2079 HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti);
2080 if (FAILED(hr)) {
2081 return hr;
2084 // qi for the expected interface and then invoke it. Note that we have to
2085 // treat the returned interface as IUnknown since we don't know its type.
2086 IUnknown* pInterface;
2088 hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface);
2089 if (FAILED(hr)) {
2090 pti->Release();
2091 return hr;
2094 EXCEPINFO expinfo;
2095 UINT uArgErr;
2096 m_hrResult = pti->Invoke(
2097 pInterface,
2098 GetMethod(),
2099 GetFlags(),
2100 GetParams(),
2101 GetResult(),
2102 &expinfo,
2103 &uArgErr);
2105 // release the interface we QI'd for
2106 pInterface->Release();
2107 pti->Release();
2110 // remove from list whether or not successful
2111 // or we loop indefinitely
2112 hr = m_pQueue->Remove(this);
2113 m_pQueue = NULL;
2114 return hr;
2119 // --- CCmdQueue methods ----------
2122 CCmdQueue::CCmdQueue() :
2123 m_listPresentation(NAME("Presentation time command list")),
2124 m_listStream(NAME("Stream time command list")),
2125 m_evDue(TRUE), // manual reset
2126 m_dwAdvise(0),
2127 m_pClock(NULL),
2128 m_bRunning(FALSE)
2133 CCmdQueue::~CCmdQueue()
2135 // empty all our lists
2137 // we hold a refcount on each, so traverse and Release each
2138 // entry then RemoveAll to empty the list
2139 POSITION pos = m_listPresentation.GetHeadPosition();
2141 while(pos) {
2142 CDeferredCommand* pCmd = m_listPresentation.GetNext(pos);
2143 pCmd->Release();
2145 m_listPresentation.RemoveAll();
2147 pos = m_listStream.GetHeadPosition();
2149 while(pos) {
2150 CDeferredCommand* pCmd = m_listStream.GetNext(pos);
2151 pCmd->Release();
2153 m_listStream.RemoveAll();
2155 if (m_pClock) {
2156 if (m_dwAdvise) {
2157 m_pClock->Unadvise(m_dwAdvise);
2158 m_dwAdvise = 0;
2160 m_pClock->Release();
2165 // returns a new CDeferredCommand object that will be initialised with
2166 // the parameters and will be added to the queue during construction.
2167 // returns S_OK if successfully created otherwise an error and
2168 // no object has been queued.
2170 HRESULT
2171 CCmdQueue::New(
2172 CDeferredCommand **ppCmd,
2173 LPUNKNOWN pUnk, // this object will execute command
2174 REFTIME time,
2175 GUID* iid,
2176 long dispidMethod,
2177 short wFlags,
2178 long cArgs,
2179 VARIANT* pDispParams,
2180 VARIANT* pvarResult,
2181 short* puArgErr,
2182 BOOL bStream
2185 CAutoLock lock(&m_Lock);
2187 HRESULT hr = S_OK;
2188 *ppCmd = NULL;
2190 CDeferredCommand* pCmd;
2191 pCmd = new CDeferredCommand(
2192 this,
2193 NULL, // not aggregated
2194 &hr,
2195 pUnk, // this guy will execute
2196 time,
2197 iid,
2198 dispidMethod,
2199 wFlags,
2200 cArgs,
2201 pDispParams,
2202 pvarResult,
2203 puArgErr,
2204 bStream);
2206 if (pCmd == NULL) {
2207 hr = E_OUTOFMEMORY;
2208 } else {
2209 *ppCmd = pCmd;
2211 return hr;
2215 HRESULT
2216 CCmdQueue::Insert(CDeferredCommand* pCmd)
2218 CAutoLock lock(&m_Lock);
2220 // addref the item
2221 pCmd->AddRef();
2223 CGenericList<CDeferredCommand> * pList;
2224 if (pCmd->IsStreamTime()) {
2225 pList = &m_listStream;
2226 } else {
2227 pList = &m_listPresentation;
2229 POSITION pos = pList->GetHeadPosition();
2231 // seek past all items that are before us
2232 while (pos &&
2233 (pList->Get(pos)->GetTime() <= pCmd->GetTime())) {
2235 pList->GetNext(pos);
2238 // now at end of list or in front of items that come later
2239 if (!pos) {
2240 pList->AddTail(pCmd);
2241 } else {
2242 pList->AddBefore(pos, pCmd);
2245 SetTimeAdvise();
2246 return S_OK;
2250 HRESULT
2251 CCmdQueue::Remove(CDeferredCommand* pCmd)
2253 CAutoLock lock(&m_Lock);
2254 HRESULT hr = S_OK;
2256 CGenericList<CDeferredCommand> * pList;
2257 if (pCmd->IsStreamTime()) {
2258 pList = &m_listStream;
2259 } else {
2260 pList = &m_listPresentation;
2262 POSITION pos = pList->GetHeadPosition();
2264 // traverse the list
2265 while (pos && (pList->Get(pos) != pCmd)) {
2266 pList->GetNext(pos);
2269 // did we drop off the end?
2270 if (!pos) {
2271 hr = VFW_E_NOT_FOUND;
2272 } else {
2274 // found it - now take off list
2275 pList->Remove(pos);
2277 // Insert did an AddRef, so release it
2278 pCmd->Release();
2280 // check that timer request is still for earliest time
2281 SetTimeAdvise();
2283 return hr;
2287 // set the clock used for timing
2289 HRESULT
2290 CCmdQueue::SetSyncSource(IReferenceClock* pClock)
2292 CAutoLock lock(&m_Lock);
2294 // addref the new clock first in case they are the same
2295 if (pClock) {
2296 pClock->AddRef();
2299 // kill any advise on the old clock
2300 if (m_pClock) {
2301 if (m_dwAdvise) {
2302 m_pClock->Unadvise(m_dwAdvise);
2303 m_dwAdvise = 0;
2305 m_pClock->Release();
2307 m_pClock = pClock;
2309 // set up a new advise
2310 SetTimeAdvise();
2311 return S_OK;
2315 // set up a timer event with the reference clock
2317 void
2318 CCmdQueue::SetTimeAdvise(void)
2320 // make sure we have a clock to use
2321 if (!m_pClock) {
2322 return;
2325 // reset the event whenever we are requesting a new signal
2326 m_evDue.Reset();
2328 // time 0 is earliest
2329 CRefTime current;
2331 // find the earliest presentation time
2332 if (m_listPresentation.GetCount() > 0) {
2334 POSITION pos = m_listPresentation.GetHeadPosition();
2335 current = m_listPresentation.Get(pos)->GetTime();
2338 // if we're running, check the stream times too
2339 if (m_bRunning) {
2341 CRefTime t;
2343 if (m_listStream.GetCount() > 0) {
2345 POSITION pos = m_listStream.GetHeadPosition();
2346 t = m_listStream.Get(pos)->GetTime();
2348 // add on stream time offset to get presentation time
2349 t += m_StreamTimeOffset;
2351 // is this earlier?
2352 if ((current == TimeZero) || (t < current)) {
2353 current = t;
2358 // need to change?
2359 if ((current > TimeZero) && (current != m_tCurrentAdvise)) {
2360 if (m_dwAdvise) {
2361 m_pClock->Unadvise(m_dwAdvise);
2362 // reset the event whenever we are requesting a new signal
2363 m_evDue.Reset();
2366 // ask for time advice - the first two params are either
2367 // stream time offset and stream time or
2368 // presentation time and 0. we always use the latter
2369 HRESULT hr = m_pClock->AdviseTime(
2370 (REFERENCE_TIME)current,
2371 TimeZero,
2372 (HEVENT) HANDLE(m_evDue),
2373 &m_dwAdvise);
2375 ASSERT(SUCCEEDED(hr));
2376 m_tCurrentAdvise = current;
2381 // switch to run mode. Streamtime to Presentation time mapping known.
2383 HRESULT
2384 CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset)
2386 CAutoLock lock(&m_Lock);
2388 m_StreamTimeOffset = tStreamTimeOffset;
2389 m_bRunning = TRUE;
2391 // ensure advise is accurate
2392 SetTimeAdvise();
2393 return S_OK;
2397 // switch to Stopped or Paused mode. Time mapping not known.
2399 HRESULT
2400 CCmdQueue::EndRun()
2402 CAutoLock lock(&m_Lock);
2404 m_bRunning = FALSE;
2406 // check timer setting - stream times
2407 SetTimeAdvise();
2408 return S_OK;
2412 // return a pointer to the next due command. Blocks for msTimeout
2413 // milliseconds until there is a due command.
2414 // Stream-time commands will only become due between Run and Endrun calls.
2415 // The command remains queued until invoked or cancelled.
2416 // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error).
2418 // returns an AddRef'd object
2420 HRESULT
2421 CCmdQueue::GetDueCommand(CDeferredCommand ** ppCmd, long msTimeout)
2423 // loop until we timeout or find a due command
2424 for (;;) {
2427 CAutoLock lock(&m_Lock);
2430 // find the earliest command
2431 CDeferredCommand * pCmd = NULL;
2433 // check the presentation time and the
2434 // stream time list to find the earliest
2436 if (m_listPresentation.GetCount() > 0) {
2437 POSITION pos = m_listPresentation.GetHeadPosition();
2438 pCmd = m_listPresentation.Get(pos);
2441 if (m_bRunning && (m_listStream.GetCount() > 0)) {
2442 POSITION pos = m_listStream.GetHeadPosition();
2443 CDeferredCommand* pStrm = m_listStream.Get(pos);
2445 CRefTime t = pStrm->GetTime() + m_StreamTimeOffset;
2446 if (!pCmd || (t < pCmd->GetTime())) {
2447 pCmd = pStrm;
2451 // if we have found one, is it due?
2452 if (pCmd) {
2453 if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) {
2455 // yes it's due - addref it
2456 pCmd->AddRef();
2457 *ppCmd = pCmd;
2458 return S_OK;
2463 // block until the advise is signalled
2464 if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) {
2465 return E_ABORT;
2471 // return a pointer to a command that will be due for a given time.
2472 // Pass in a stream time here. The stream time offset will be passed
2473 // in via the Run method.
2474 // Commands remain queued until invoked or cancelled.
2475 // This method will not block. It will report E_ABORT if there are no
2476 // commands due yet.
2478 // returns an AddRef'd object
2480 HRESULT
2481 CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, CDeferredCommand**ppCmd)
2483 CAutoLock lock(&m_Lock);
2485 CRefTime tStream(rtStream);
2487 // find the earliest stream and presentation time commands
2488 CDeferredCommand* pStream = NULL;
2489 if (m_listStream.GetCount() > 0) {
2490 POSITION pos = m_listStream.GetHeadPosition();
2491 pStream = m_listStream.Get(pos);
2493 CDeferredCommand* pPresent = NULL;
2494 if (m_listPresentation.GetCount() > 0) {
2495 POSITION pos = m_listPresentation.GetHeadPosition();
2496 pPresent = m_listPresentation.Get(pos);
2499 // is there a presentation time that has passed already
2500 if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) {
2501 pPresent->AddRef();
2502 *ppCmd = pPresent;
2503 return S_OK;
2506 // is there a stream time command due before this stream time
2507 if (pStream && (pStream->GetTime() <= tStream)) {
2508 pPresent->AddRef();
2509 *ppCmd = pStream;
2510 return S_OK;
2513 // if we are running, we can map presentation times to
2514 // stream time. In this case, is there a presentation time command
2515 // that will be due before this stream time is presented?
2516 if (m_bRunning && pPresent) {
2518 // this stream time will appear at...
2519 tStream += m_StreamTimeOffset;
2521 // due before that?
2522 if (pPresent->GetTime() <= tStream) {
2523 *ppCmd = pPresent;
2524 return S_OK;
2528 // no commands due yet
2529 return VFW_E_NOT_FOUND;