source: trunk/DirectShowSpy/RunPropertyBag.h @ 312

Last change on this file since 312 was 312, checked in by roman, 8 years ago

Proper code sharing between Spy and external dependencies

File size: 13.8 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2014
3// Created by Roman Ryltsov roman@alax.info, http://alax.info
4//
5// This source code is published to complement DirectShowSpy developer powertoy
6// and demonstrate the internal use of APIs and tricks powering the tool. It is
7// allowed to freely re-use the portions of the code in other projects, commercial
8// or otherwise (provided that you don’t pretend that you wrote the original tool).
9//
10// Please keep in mind that DirectShowSpy is a developer tool, it is strongly recommended
11// that it is not shipped with release grade software. It is allowed to distribute
12// DirectShowSpy if only it is not registered with Windows by default and either
13// used privately, or registered on specific throubleshooting request. The advice applies
14// to hooking methods used by DirectShowSpy in general as well.
15
16#pragma once
17
18#include "Module_i.h"
19#include "Common.h"
20
21////////////////////////////////////////////////////////////
22// CRunPropertyBagHelper
23
24class CRunPropertyBagHelper
25{
26public:
27
28        ////////////////////////////////////////////////////////
29        // CSimpleSortTraitsT
30
31        class CNameSortTraits :
32                public CSimpleSortTraitsT<CString>
33        {
34        public:
35        // CNameSortTraits
36                static INT_PTR CompareElements(const CString& sElementA, const CString& sElementB, PARAMETERARGUMENT Parameter)
37                {
38                        return _tcsicmp(sElementA, sElementB);
39                }
40        };
41
42protected:
43        static CObjectPtr<CMemoryPropertyBag>& PropertyBagNeeded(CObjectPtr<CMemoryPropertyBag>& pPropertyBag)
44        {
45                if(!pPropertyBag)
46                        pPropertyBag.Construct();
47                return pPropertyBag;
48        }
49
50public:
51// CRunPropertyBagHelper
52        static CComVariantArray ReadRunPropertyBag(IUnknown* pBaseFilterUnknown, BOOL bAllowExtension = TRUE)
53        {
54                CComVariantArray vValue;
55                CRoArrayT<CComVariantArray> Array;
56                const CComQIPtr<DIRECTSHOWSPY_NAMESPACE_PREFIX IRunPropertyBagAware> pRunPropertyBagAware = pBaseFilterUnknown;
57                CComQIPtr<IPropertyBag2> pPropertyBag2;
58                #pragma region Extension
59                if(!pRunPropertyBagAware && bAllowExtension)
60                {
61                        CObjectPtr<CMemoryPropertyBag> pPropertyBag;
62                        #pragma region IQualProp
63                        const CComQIPtr<IQualProp, &IID_IQualProp> pQualProp = pBaseFilterUnknown;
64                        if(pQualProp)
65                                _ATLTRY
66                                {
67                                        INT nFramesDroppedInRenderer, nFramesDrawn, nAvgFrameRate, nJitter, nAvgSyncOffset, nDevSyncOffset;
68                                        __C(pQualProp->get_FramesDroppedInRenderer(&nFramesDroppedInRenderer));
69                                        __C(pQualProp->get_FramesDrawn(&nFramesDrawn));
70                                        __C(pQualProp->get_AvgFrameRate(&nAvgFrameRate));
71                                        __C(pQualProp->get_Jitter(&nJitter));
72                                        __C(pQualProp->get_AvgSyncOffset(&nAvgSyncOffset));
73                                        __C(pQualProp->get_DevSyncOffset(&nDevSyncOffset));
74                                        PropertyBagNeeded(pPropertyBag);
75                                        pPropertyBag->WriteValue(_T("FramesDroppedInRenderer"), CComVariant((LONG) nFramesDroppedInRenderer));
76                                        pPropertyBag->WriteValue(_T("FramesDrawn"), CComVariant((LONG) nFramesDrawn));
77                                        pPropertyBag->WriteValue(_T("AvgFrameRate"), CComVariant((DOUBLE) nAvgFrameRate / 100));
78                                        pPropertyBag->WriteValue(_T("Jitter"), CComVariant((LONG) nJitter));
79                                        pPropertyBag->WriteValue(_T("AvgSyncOffset"), CComVariant((LONG) nAvgSyncOffset));
80                                        pPropertyBag->WriteValue(_T("DevSyncOffset"), CComVariant((LONG) nDevSyncOffset));
81                                }
82                                _ATLCATCHALL()
83                                {
84                                        _Z_EXCEPTION();
85                                }
86                        #pragma endregion
87                        #pragma region IAMAudioRendererStats
88                        const CComQIPtr<IAMAudioRendererStats> pAmAudioRendererStats = pBaseFilterUnknown;
89                        if(pAmAudioRendererStats)
90                                _ATLTRY
91                                {
92                                        DWORD nDummy;
93                                        DWORD nBreakCount, nSlaveMode, nSilenceDuration, nLastBufferDuration, nDiscontinuityCount, nSlaveRate, nDropWriteDuration;
94                                        DWORD nHighestSlaveError, nLowestSlaveError, nLastHighSlaveError, nLastLowSlaveError;
95                                        DWORD nAccumulatedError, nBufferFullness;
96                                        //DWORD nJitter;
97                                        __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_BREAK_COUNT, &nBreakCount, &nDummy));
98                                        __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_MODE, &nSlaveMode, &nDummy));
99                                        __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SILENCE_DUR, &nSilenceDuration, &nDummy));
100                                        __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_LAST_BUFFER_DUR, &nLastBufferDuration, &nDummy));
101                                        __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_DISCONTINUITIES, &nDiscontinuityCount, &nDummy));
102                                        if(nSlaveMode)
103                                        {
104                                                __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_RATE, &nSlaveRate, &nDummy));
105                                                __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_DROPWRITE_DUR, &nDropWriteDuration, &nDummy));
106                                                __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_HIGHLOWERROR, &nHighestSlaveError, &nLowestSlaveError));
107                                                __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_LASTHIGHLOWERROR, &nLastHighSlaveError, &nLastLowSlaveError));
108                                                __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_ACCUMERROR, &nAccumulatedError, &nDummy));
109                                        }
110                                        __C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_BUFFERFULLNESS, &nBufferFullness, &nDummy));
111                                        //__C(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_JITTER, &nJitter, &nDummy));
112                                        PropertyBagNeeded(pPropertyBag);
113                                        pPropertyBag->WriteValue(_T("BreakCount"), CComVariant((LONG) nBreakCount));
114                                        pPropertyBag->WriteValue(_T("SlaveMode"), CComVariant((LONG) nSlaveMode));
115                                        pPropertyBag->WriteValue(_T("SilenceDuration"), CComVariant((LONG) nSilenceDuration));
116                                        pPropertyBag->WriteValue(_T("LastBufferDuration"), CComVariant((LONG) nLastBufferDuration));
117                                        pPropertyBag->WriteValue(_T("DiscontinuityCount"), CComVariant((LONG) nDiscontinuityCount));
118                                        if(nSlaveMode)
119                                        {
120                                                pPropertyBag->WriteValue(_T("SlaveRate"), CComVariant((LONG) nSlaveRate));
121                                                pPropertyBag->WriteValue(_T("DropWriteDuration"), CComVariant((LONG) nDropWriteDuration));
122                                                pPropertyBag->WriteValue(_T("HighestSlaveError"), CComVariant((LONG) nHighestSlaveError));
123                                                pPropertyBag->WriteValue(_T("LowestSlaveError"), CComVariant((LONG) nLowestSlaveError));
124                                                pPropertyBag->WriteValue(_T("LastHighSlaveError"), CComVariant((LONG) nLastHighSlaveError));
125                                                pPropertyBag->WriteValue(_T("LastLowSlaveError"), CComVariant((LONG) nLastLowSlaveError));
126                                                pPropertyBag->WriteValue(_T("AccumulatedError"), CComVariant((LONG) nAccumulatedError));
127                                        }
128                                        pPropertyBag->WriteValue(_T("BufferFullness"), CComVariant((LONG) nBufferFullness));
129                                        //pPropertyBag->WriteValue(_T("Jitter"), CComVariant((LONG) nJitter));
130                                }
131                                _ATLCATCHALL()
132                                {
133                                        _Z_EXCEPTION();
134                                }
135                        #pragma endregion
136                        if(pPropertyBag)
137                                pPropertyBag2 = pPropertyBag;
138                }
139                #pragma endregion
140                if(!pPropertyBag2 && pRunPropertyBagAware)
141                {
142                        CComPtr<IUnknown> pPropertyBagUnknown;
143                        __C(pRunPropertyBagAware->get_Value(&pPropertyBagUnknown));
144                        pPropertyBag2 = pPropertyBagUnknown;
145                }
146                if(pPropertyBag2)
147                {
148                        ULONG nPropertyCount = 0;
149                        __C(pPropertyBag2->CountProperties(&nPropertyCount));
150                        _Z4(atlTraceGeneral, 4, _T("nPropertyCount %d\n"), nPropertyCount);
151                        if(nPropertyCount)
152                        {
153                                CTempBufferT<PROPBAG2> pPropBags(nPropertyCount);
154                                ZeroMemory((PROPBAG2*) pPropBags, nPropertyCount * sizeof *pPropBags);
155                                ULONG nPropBagCount = 0;
156                                __C(pPropertyBag2->GetPropertyInfo(0, nPropertyCount, pPropBags, &nPropBagCount));
157                                _Z4(atlTraceGeneral, 4, _T("nPropBagCount %d\n"), nPropBagCount);
158                                CRoListT<CComHeapPtr<OLECHAR>> NameList;
159                                for(ULONG nIndex = 0; nIndex < nPropBagCount; nIndex++)
160                                        NameList.GetAt(NameList.AddTail()).Attach(pPropBags[nIndex].pstrName);
161                                CRoArrayT<CComVariantArray> ValueArray;
162                                __D(ValueArray.SetCount(nPropBagCount), E_OUTOFMEMORY);
163                                CTempBufferT<HRESULT> pnResults(nPropBagCount);
164                                __C(pPropertyBag2->Read(nPropBagCount, pPropBags, NULL, ValueArray.GetData(), pnResults));
165                                for(ULONG nIndex = 0; nIndex < nPropBagCount; nIndex++)
166                                        if(SUCCEEDED(pnResults[nIndex]))
167                                        {
168                                                CString sName(pPropBags[nIndex].pstrName);
169                                                _Z4(atlTraceGeneral, 4, _T("sName \"%s\"\n"), sName);
170                                                CComVariantArray vPropertyValue;
171                                                Array.Add(vPropertyValue.FromElements(2, CComVariant(sName), ValueArray[nIndex]));
172                                        }
173                                vValue.FromElementArray(Array);
174                        }
175                }
176                return vValue;
177        }
178        static CString GetPropertyBagText(CRoArrayT<CString>& NameArray, CRoMapT<CString, CComVariantArray>& Map)
179        {
180                CString sText;
181                _SortHelper::QuickSort<CNameSortTraits>(NameArray);
182                // SUGG: Nicer similar names, taking prefix at dot separator, also changing Foo-A-B into Foo (A; B)
183                for(SIZE_T nIndex = 0; nIndex < NameArray.GetCount(); nIndex++)
184                {
185                        const CString& sName = NameArray[nIndex];
186                        _Z4(atlTraceGeneral, 4, _T("sName \"%s\"\n"), sName);
187                        CString sValue;
188                        CComVariantArray vValue;
189                        if(!Map.Lookup(sName, vValue))
190                                continue;
191                        CString sComment;
192                        #pragma region Friendly Comment
193                        switch(vValue.vt)
194                        {
195                        #pragma region VT_I4
196                        case VT_I4:
197                                if(vValue.lVal < -999 || vValue.lVal > 999)
198                                        sComment = _StringHelper::FormatNumber(vValue.lVal);
199                                break;
200                        #pragma endregion
201                        #pragma region VT_R8
202                        case VT_R8:
203                                if(vValue.dblVal > -0.001 || vValue.dblVal < 0.001)
204                                        sComment = _StringHelper::FormatNumber(vValue.dblVal, 6);
205                                else 
206                                if(vValue.lVal < -999.0 || vValue.lVal > 999.0)
207                                        sComment = _StringHelper::FormatNumber(vValue.dblVal, 1);
208                                break;
209                        #pragma endregion
210                        }
211                        #pragma endregion
212                        const HRESULT nChangeTypeResult = vValue.ChangeType(VT_BSTR);
213                        _Z45_HRESULT(nChangeTypeResult);
214                        if(FAILED(nChangeTypeResult))
215                                continue;
216                        sText.AppendFormat(_T(" * ") _T("`%s`: `%s`"), sName, CString(vValue.bstrVal));
217                        if(!sComment.IsEmpty())
218                                sText.AppendFormat(_T(" // %s"), sComment);
219                        sText.Append(_T("\r\n"));
220                }
221                return sText;
222        }
223        static ATL_DEPRECATED("Convert IPropertyBag2 into VARIANT using ISpy or CSpy instead") CString GetPropertyBagText(IPropertyBag2* pPropertyBag2)
224        {
225                _A(pPropertyBag2);
226                CString sText;
227                ULONG nPropertyCount = 0;
228                __C(pPropertyBag2->CountProperties(&nPropertyCount));
229                _Z4(atlTraceGeneral, 4, _T("nPropertyCount %d\n"), nPropertyCount);
230                if(!nPropertyCount)
231                        return sText;
232                #pragma region Read
233                CTempBufferT<PROPBAG2> pPropBags(nPropertyCount);
234                ZeroMemory((PROPBAG2*) pPropBags, nPropertyCount * sizeof *pPropBags);
235                ULONG nPropBagCount = 0;
236                __C(pPropertyBag2->GetPropertyInfo(0, nPropertyCount, pPropBags, &nPropBagCount));
237                _Z4(atlTraceGeneral, 4, _T("nPropBagCount %d\n"), nPropBagCount);
238                CRoListT<CComHeapPtr<OLECHAR>> NameList;
239                for(ULONG nIndex = 0; nIndex < nPropBagCount; nIndex++)
240                        NameList.GetAt(NameList.AddTail()).Attach(pPropBags[nIndex].pstrName);
241                CRoArrayT<CComVariantArray> ValueArray;
242                __D(ValueArray.SetCount(nPropBagCount), E_OUTOFMEMORY);
243                CTempBufferT<HRESULT> pnResults(nPropBagCount);
244                __C(pPropertyBag2->Read(nPropBagCount, pPropBags, NULL, ValueArray.GetData(), pnResults));
245                #pragma endregion
246                CRoMapT<CString, CComVariantArray> Map;
247                CRoArrayT<CString> NameArray;
248                for(ULONG nIndex = 0; nIndex < nPropBagCount; nIndex++)
249                        if(SUCCEEDED(pnResults[nIndex]))
250                        {
251                                CString sName(pPropBags[nIndex].pstrName);
252                                _Z4(atlTraceGeneral, 4, _T("sName \"%s\"\n"), sName);
253                                NameArray.Add(sName);
254                                _W(Map.SetAt(sName, ValueArray[nIndex]));
255                        }
256                return GetPropertyBagText(NameArray, Map);
257        }
258        static CString GetPropertyBagText(CComVariantArray& vValue)
259        {
260                if(vValue.vt <= VT_NULL)
261                        return _T("");
262                CRoArrayT<CComVariantArray> Array;
263                vValue.ToElementArray(Array);
264                CRoMapT<CString, CComVariantArray> Map;
265                CRoArrayT<CString> NameArray;
266                for(SIZE_T nIndex = 0; nIndex < Array.GetCount(); nIndex++)
267                {
268                        CComVariantArray vPropertyName, vPropertyValue;
269                        Array[nIndex].ToElements(2, &vPropertyName, &vPropertyValue);
270                        __C(vPropertyName.ChangeType(VT_BSTR));
271                        CString sName(vPropertyName.bstrVal);
272                        _Z4(atlTraceGeneral, 4, _T("sName \"%s\"\n"), sName);
273                        NameArray.Add(sName);
274                        _W(Map.SetAt(sName, vPropertyValue));
275                }
276                return GetPropertyBagText(NameArray, Map);
277        }
278        static CString GetPropertyBagText(VARIANT vValue)
279        {
280                return GetPropertyBagText(reinterpret_cast<CComVariantArray&>(vValue));
281        }
282        __if_exists(ISpy)
283        {
284                static CString GetPropertyBagText(IUnknown* pBaseFilterUnknown, ISpy* pSpy = NULL)
285                {
286                        const CComQIPtr<IRunPropertyBagAware> pRunPropertyBagAware = pBaseFilterUnknown;
287                        CComQIPtr<ISpy> pEffectiveSpy = pSpy;
288                        if(!pEffectiveSpy && pRunPropertyBagAware)
289                                pEffectiveSpy = _FilterGraphHelper::GetFilterGraph(CComQIPtr<IBaseFilter>(pBaseFilterUnknown));
290                        if(pEffectiveSpy)
291                        {
292                                CComVariantArray vValue;
293                                __C(pEffectiveSpy->ReadRunPropertyBag(pBaseFilterUnknown, ATL_VARIANT_TRUE, &vValue));
294                                return GetPropertyBagText(vValue);
295                        }
296                        if(!pRunPropertyBagAware)
297                                return _T("");
298                        return GetPropertyBagText(ReadRunPropertyBag(pRunPropertyBagAware));
299                }
300        }
301};
302
303#if !defined(DIRECTSHOWSPY)
304
305////////////////////////////////////////////////////////////
306// CRunPropertyBagAwareT
307
308template <typename T>
309class ATL_NO_VTABLE CRunPropertyBagAwareT :
310        public IDispatchImpl<DIRECTSHOWSPY_NAMESPACE_PREFIX IRunPropertyBagAware, &__uuidof(DIRECTSHOWSPY_NAMESPACE_PREFIX IRunPropertyBagAware), &__uuidof(DIRECTSHOWSPY_NAMESPACE_PREFIX __AlaxInfoDirectShowSpy)>
311{
312public:
313// CRunPropertyBagAwareT
314
315// AlaxInfoDirectShowSpy::IRunPropertyBagAware
316        STDMETHOD(get_Value)(IUnknown** ppPropertyBagUnknown)
317        {
318                _Z4(atlTraceCOM, 4, _T("...\n"));
319                _ATLTRY
320                {
321                        __D(ppPropertyBagUnknown, E_POINTER);
322                        T* pT = static_cast<T*>(this);
323                        *ppPropertyBagUnknown = (IPropertyBag*) pT->CreatePerformancePropertyBag().Detach();
324                }
325                _ATLCATCH(Exception)
326                {
327                        _C(Exception);
328                }
329                return S_OK;
330        }
331};
332
333#endif // !defined(DIRECTSHOWSPY)
Note: See TracBrowser for help on using the repository browser.