[290] | 1 | //////////////////////////////////////////////////////////// |
---|
[376] | 2 | // Copyright (C) Roman Ryltsov, 2008-2015 |
---|
[290] | 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 dont 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 | |
---|
[851] | 18 | #include "Common.h" |
---|
| 19 | |
---|
[290] | 20 | //////////////////////////////////////////////////////////// |
---|
| 21 | // CRunEventHelper |
---|
| 22 | |
---|
| 23 | class CRunEventHelper |
---|
| 24 | { |
---|
| 25 | public: |
---|
| 26 | |
---|
| 27 | //////////////////////////////////////////////////////// |
---|
| 28 | // CEventsT, CEvents |
---|
| 29 | |
---|
[310] | 30 | template <SIZE_T t_nItemCapacity = 256, SIZE_T t_nItemTextLength = 256> |
---|
[290] | 31 | class CEventsT |
---|
| 32 | { |
---|
| 33 | public: |
---|
| 34 | |
---|
| 35 | //////////////////////////////////////////////////// |
---|
| 36 | // CItem |
---|
| 37 | |
---|
| 38 | class CItem |
---|
| 39 | { |
---|
| 40 | public: |
---|
| 41 | ULONGLONG m_nTime; |
---|
| 42 | CHAR m_pszText[t_nItemTextLength]; |
---|
| 43 | |
---|
| 44 | public: |
---|
| 45 | // CItem |
---|
| 46 | CComVariantArray GetAsVariant(ULONGLONG nTime) const |
---|
| 47 | { |
---|
| 48 | CComVariantArray vValue; |
---|
[431] | 49 | vValue.FromElements(2, CComVariant((LONG) ((nTime - m_nTime) / 10000)), CComVariant(m_pszText)); |
---|
[290] | 50 | return vValue; |
---|
| 51 | } |
---|
| 52 | BOOL SetAsVariant(CComVariantArray& vValue) |
---|
| 53 | { |
---|
| 54 | if(vValue.vt != (VT_ARRAY | VT_VARIANT)) |
---|
| 55 | return FALSE; |
---|
| 56 | _A(vValue.GetDimensionCount() == 1); |
---|
| 57 | CRoArrayT<CComVariantArray> Array; |
---|
| 58 | vValue.ToElementArray(Array); |
---|
| 59 | if(Array.GetCount() < 2) |
---|
| 60 | return FALSE; |
---|
| 61 | m_nTime = Array[0].GetAsType(VT_I4).lVal * 10000; |
---|
| 62 | strncpy_s(m_pszText, CW2A(Array[1].GetAsType(VT_BSTR).bstrVal), _TRUNCATE); |
---|
| 63 | return TRUE; |
---|
| 64 | } |
---|
| 65 | BOOL SetAsVariant(VARIANT vValue) |
---|
| 66 | { |
---|
| 67 | return SetAsVariant(reinterpret_cast<CComVariantArray&>(vValue)); |
---|
| 68 | } |
---|
| 69 | CString GetText(ULONGLONG nTime) const |
---|
| 70 | { |
---|
| 71 | CString sText; |
---|
| 72 | sText.AppendFormat(_T("%Id"), (LONG) (nTime - m_nTime)); |
---|
| 73 | sText.AppendChar(_T('\t')); |
---|
| 74 | sText.Append(CA2CT(m_pszText)); |
---|
| 75 | return sText; |
---|
| 76 | } |
---|
| 77 | }; |
---|
| 78 | |
---|
| 79 | private: |
---|
| 80 | mutable CRoLightCriticalSection m_DataCriticalSection; |
---|
| 81 | BOOL m_bCapture; |
---|
| 82 | CItem m_pItems[t_nItemCapacity]; |
---|
| 83 | SIZE_T m_nItemIndex; |
---|
| 84 | SIZE_T m_nItemCount; |
---|
| 85 | BOOL m_bTrace; |
---|
| 86 | SIZE_T m_nTraceItemCount; |
---|
| 87 | |
---|
[355] | 88 | VOID InternalAddItem(ULONGLONG nTime, LPCSTR pszText) |
---|
| 89 | { |
---|
| 90 | CRoLightCriticalSectionLock DataLock(m_DataCriticalSection); |
---|
| 91 | if(!m_bCapture) |
---|
| 92 | return; |
---|
| 93 | CItem& Item = m_pItems[m_nItemIndex]; |
---|
| 94 | Item.m_nTime = nTime; |
---|
| 95 | strncpy_s(Item.m_pszText, pszText, _TRUNCATE); |
---|
| 96 | if(m_nItemCount < t_nItemCapacity) |
---|
| 97 | m_nItemCount++; |
---|
| 98 | ++m_nItemIndex %= t_nItemCapacity; |
---|
| 99 | if(m_bTrace && m_nTraceItemCount) |
---|
| 100 | m_nTraceItemCount--; |
---|
| 101 | } |
---|
| 102 | VOID InternalAddItemV(ULONGLONG nTime, LPCSTR pszFormat, va_list Arguments) |
---|
| 103 | { |
---|
| 104 | CRoLightCriticalSectionLock DataLock(m_DataCriticalSection); |
---|
| 105 | if(!m_bCapture) |
---|
| 106 | return; |
---|
| 107 | CItem& Item = m_pItems[m_nItemIndex]; |
---|
| 108 | Item.m_nTime = nTime; |
---|
| 109 | vsprintf_s(Item.m_pszText, pszFormat, Arguments); |
---|
| 110 | if(m_nItemCount < t_nItemCapacity) |
---|
| 111 | m_nItemCount++; |
---|
| 112 | ++m_nItemIndex %= t_nItemCapacity; |
---|
| 113 | if(m_bTrace && m_nTraceItemCount) |
---|
| 114 | m_nTraceItemCount--; |
---|
| 115 | } |
---|
| 116 | |
---|
[290] | 117 | public: |
---|
| 118 | // CEventsT |
---|
| 119 | CEventsT() : |
---|
| 120 | m_bCapture(FALSE), |
---|
| 121 | m_bTrace(FALSE) |
---|
| 122 | { |
---|
| 123 | } |
---|
| 124 | static SIZE_T GetCapacity() |
---|
| 125 | { |
---|
| 126 | return t_nItemCapacity; |
---|
| 127 | } |
---|
| 128 | BOOL IsCapture() const |
---|
| 129 | { |
---|
| 130 | CRoLightCriticalSectionLock DataLock(m_DataCriticalSection); |
---|
| 131 | return m_bCapture; |
---|
| 132 | } |
---|
| 133 | VOID SetCapture(BOOL bCapture) |
---|
| 134 | { |
---|
| 135 | CRoLightCriticalSectionLock DataLock(m_DataCriticalSection); |
---|
| 136 | if(m_bCapture == bCapture) |
---|
| 137 | return; |
---|
| 138 | m_bCapture = bCapture; |
---|
| 139 | if(bCapture) |
---|
| 140 | { |
---|
| 141 | m_nItemIndex = 0; |
---|
| 142 | m_nItemCount = 0; |
---|
| 143 | } |
---|
| 144 | } |
---|
| 145 | VOID AddItemV(ULONGLONG nTime, LPCSTR pszFormat, va_list Arguments) |
---|
| 146 | { |
---|
[355] | 147 | InternalAddItemV(nTime, pszFormat, Arguments); |
---|
[290] | 148 | } |
---|
| 149 | VOID AddItem(ULONGLONG nTime, LPCSTR pszFormat, ...) |
---|
| 150 | { |
---|
| 151 | va_list Arguments; |
---|
| 152 | va_start(Arguments, pszFormat); |
---|
| 153 | AddItemV(pszFormat, Arguments); |
---|
| 154 | va_end(Arguments); |
---|
| 155 | } |
---|
| 156 | VOID AddItem(LPCSTR pszFormat, ...) |
---|
| 157 | { |
---|
| 158 | va_list Arguments; |
---|
| 159 | va_start(Arguments, pszFormat); |
---|
| 160 | AddItemV(CMsAccurateFileTime::GetTime(), pszFormat, Arguments); |
---|
| 161 | va_end(Arguments); |
---|
| 162 | } |
---|
[355] | 163 | VOID AddItem(const CRoArrayT<CStringA>& Array) |
---|
| 164 | { |
---|
| 165 | InternalAddItem(CMsAccurateFileTime::GetTime(), _StringHelper::Join(Array, "\t")); |
---|
| 166 | } |
---|
[290] | 167 | CComVariantArray GetAsVariant() const |
---|
| 168 | { |
---|
| 169 | CComVariantArray vValue; |
---|
| 170 | CRoLightCriticalSectionLock DataLock(m_DataCriticalSection); |
---|
| 171 | if(m_bCapture && m_nItemCount) |
---|
| 172 | { |
---|
| 173 | const ULONGLONG nTime = CMsAccurateFileTime::GetTime(); |
---|
| 174 | CRoArrayT<CComVariantArray> Array; |
---|
| 175 | Array.SetCount(0, (INT) m_nItemCount); |
---|
| 176 | for(SIZE_T nItemIndex = 0; nItemIndex < m_nItemCount; nItemIndex++) |
---|
| 177 | { |
---|
| 178 | const CItem& Item = m_pItems[((m_nItemIndex - 1) - nItemIndex + t_nItemCapacity) % t_nItemCapacity]; |
---|
| 179 | Array.Add(Item.GetAsVariant(nTime)); |
---|
| 180 | } |
---|
| 181 | vValue.FromElementArray(Array); |
---|
| 182 | } |
---|
| 183 | return vValue; |
---|
| 184 | } |
---|
| 185 | SIZE_T GetText(CRoArrayT<CString>& Array) const |
---|
| 186 | { |
---|
| 187 | _A(Array.IsEmpty()); |
---|
| 188 | CRoLightCriticalSectionLock DataLock(m_DataCriticalSection); |
---|
| 189 | if(m_bCapture && m_nItemCount) |
---|
| 190 | { |
---|
| 191 | const ULONGLONG nTime = CMsAccurateFileTime::GetTime(); |
---|
| 192 | Array.SetCount(0, (INT) m_nItemCount); |
---|
| 193 | for(SIZE_T nItemIndex = 0; nItemIndex < m_nItemCount; nItemIndex++) |
---|
| 194 | { |
---|
| 195 | const CItem& Item = m_pItems[((m_nItemIndex - 1) - nItemIndex + t_nItemCapacity) % t_nItemCapacity]; |
---|
| 196 | Array.Add(Item.GetText(nTime)); |
---|
| 197 | } |
---|
| 198 | } |
---|
| 199 | return Array.GetCount(); |
---|
| 200 | } |
---|
| 201 | BOOL IsTrace() const |
---|
| 202 | { |
---|
| 203 | CRoLightCriticalSectionLock DataLock(m_DataCriticalSection); |
---|
| 204 | return m_bTrace && !m_nTraceItemCount; |
---|
| 205 | } |
---|
| 206 | VOID SetTrace(BOOL bTrace, SIZE_T nTraceItemCount = 0) |
---|
| 207 | { |
---|
| 208 | CRoLightCriticalSectionLock DataLock(m_DataCriticalSection); |
---|
| 209 | if(bTrace) |
---|
| 210 | { |
---|
| 211 | if(m_bTrace) |
---|
| 212 | return; // Stick to Existing Schedule |
---|
| 213 | m_bTrace = TRUE; |
---|
| 214 | m_nTraceItemCount = nTraceItemCount; |
---|
| 215 | } else |
---|
| 216 | m_bTrace = FALSE; |
---|
| 217 | } |
---|
| 218 | }; |
---|
| 219 | |
---|
| 220 | typedef CEventsT<> CEvents; |
---|
| 221 | |
---|
| 222 | public: |
---|
| 223 | // CRunEventHelper |
---|
[310] | 224 | }; |
---|
| 225 | |
---|
[312] | 226 | #if !defined(DIRECTSHOWSPY) |
---|
[310] | 227 | |
---|
| 228 | //////////////////////////////////////////////////////////// |
---|
| 229 | // CRunEventAwareT |
---|
| 230 | |
---|
| 231 | template <typename T> |
---|
| 232 | class ATL_NO_VTABLE CRunEventAwareT : |
---|
[312] | 233 | public IDispatchImpl<DIRECTSHOWSPY_NAMESPACE_PREFIX IRunEventAware, &__uuidof(DIRECTSHOWSPY_NAMESPACE_PREFIX IRunEventAware), &__uuidof(DIRECTSHOWSPY_NAMESPACE_PREFIX __AlaxInfoDirectShowSpy)> |
---|
[310] | 234 | { |
---|
| 235 | protected: |
---|
| 236 | CRunEventHelper::CEvents m_Events; |
---|
| 237 | |
---|
| 238 | public: |
---|
| 239 | // CRunEventAwareT |
---|
| 240 | |
---|
| 241 | // AlaxInfoDirectShowSpy::IRunEventAware |
---|
| 242 | STDMETHOD(get_Value)(VARIANT* pvEvents) |
---|
| 243 | { |
---|
| 244 | _Z4(atlTraceCOM, 4, _T("...\n")); |
---|
| 245 | _ATLTRY |
---|
| 246 | { |
---|
| 247 | __D(pvEvents, E_POINTER); |
---|
| 248 | VariantInit(pvEvents); |
---|
| 249 | T* pT = static_cast<T*>(this); |
---|
| 250 | //CRoCriticalSectionLock DataLock(pT->GetDataCriticalSection()); |
---|
| 251 | _V(m_Events.GetAsVariant().Detach(pvEvents)); |
---|
| 252 | } |
---|
| 253 | _ATLCATCH(Exception) |
---|
| 254 | { |
---|
| 255 | _C(Exception); |
---|
| 256 | } |
---|
| 257 | return S_OK; |
---|
| 258 | } |
---|
| 259 | STDMETHOD(get_Capture)(VARIANT_BOOL* pbCapture) |
---|
| 260 | { |
---|
| 261 | _Z4(atlTraceCOM, 4, _T("...\n")); |
---|
| 262 | _ATLTRY |
---|
| 263 | { |
---|
| 264 | __D(pbCapture, E_POINTER); |
---|
| 265 | T* pT = static_cast<T*>(this); |
---|
| 266 | //CRoCriticalSectionLock DataLock(pT->GetDataCriticalSection()); |
---|
| 267 | *pbCapture = m_Events.IsCapture() ? ATL_VARIANT_TRUE : ATL_VARIANT_FALSE; |
---|
| 268 | } |
---|
| 269 | _ATLCATCH(Exception) |
---|
| 270 | { |
---|
| 271 | _C(Exception); |
---|
| 272 | } |
---|
| 273 | return S_OK; |
---|
| 274 | } |
---|
| 275 | STDMETHOD(put_Capture)(VARIANT_BOOL bCapture) |
---|
| 276 | { |
---|
| 277 | _Z4(atlTraceCOM, 4, _T("bCapture %d\n"), bCapture); |
---|
| 278 | _ATLTRY |
---|
| 279 | { |
---|
| 280 | T* pT = static_cast<T*>(this); |
---|
| 281 | //CRoCriticalSectionLock DataLock(pT->GetDataCriticalSection()); |
---|
| 282 | m_Events.SetCapture(bCapture != ATL_VARIANT_FALSE); |
---|
| 283 | } |
---|
| 284 | _ATLCATCH(Exception) |
---|
| 285 | { |
---|
| 286 | _C(Exception); |
---|
| 287 | } |
---|
| 288 | return S_OK; |
---|
| 289 | } |
---|
| 290 | }; |
---|
| 291 | |
---|
[312] | 292 | #endif // !defined(DIRECTSHOWSPY) |
---|