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 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 | |
---|
18 | #include "rodshow.h" |
---|
19 | #include <..\Samples\multimedia\directshow\misc\mapper\fil_data.h> |
---|
20 | #include "DirectShowSpy_i.h" |
---|
21 | #include "Common.h" |
---|
22 | |
---|
23 | //////////////////////////////////////////////////////////// |
---|
24 | // CFilterMapperSpyT |
---|
25 | |
---|
26 | template <typename T, const CLSID* t_pFilterMapperClassIdentifier> |
---|
27 | class ATL_NO_VTABLE CFilterMapperSpyT : |
---|
28 | public CComObjectRootEx<CComMultiThreadModel>, |
---|
29 | //public CComCoClass<CFilterMapperSpyT, &CLSID_FilterMapperSpy>, |
---|
30 | public CTransparentCoClassT<T, t_pFilterMapperClassIdentifier>, |
---|
31 | public IDispatchImpl<IFilterMapperSpy>, |
---|
32 | public IAMFilterData, |
---|
33 | public IFilterMapper2 |
---|
34 | { |
---|
35 | typedef CFilterMapperSpyT<T, t_pFilterMapperClassIdentifier> CFilterMapperSpy; |
---|
36 | |
---|
37 | public: |
---|
38 | //enum { IDR = IDR_FILTERMAPPERSPY }; |
---|
39 | |
---|
40 | //DECLARE_REGISTRY_RESOURCEID(IDR) |
---|
41 | |
---|
42 | DECLARE_PROTECT_FINAL_CONSTRUCT() |
---|
43 | |
---|
44 | DECLARE_GET_CONTROLLING_UNKNOWN() |
---|
45 | |
---|
46 | DECLARE_QI_TRACE(CFilterMapperSpy) |
---|
47 | |
---|
48 | BEGIN_COM_MAP(CFilterMapperSpy) |
---|
49 | COM_INTERFACE_ENTRY(IFilterMapperSpy) |
---|
50 | COM_INTERFACE_ENTRY(IAMFilterData) |
---|
51 | COM_INTERFACE_ENTRY(IFilterMapper2) |
---|
52 | COM_INTERFACE_ENTRY_AGGREGATE_BLIND(m_pInnerUnknown) |
---|
53 | //COM_INTERFACE_ENTRY(IDispatch) |
---|
54 | END_COM_MAP() |
---|
55 | |
---|
56 | private: |
---|
57 | BOOL m_bIsAggregated; |
---|
58 | HINSTANCE m_hQuartzModule; |
---|
59 | CComPtr<IUnknown> m_pInnerUnknown; |
---|
60 | CComPtr<IFilterMapper2> m_pFilterMapper2; |
---|
61 | CComPtr<IAMFilterData> m_pAmFilterData; |
---|
62 | |
---|
63 | static VOID Trace(const REGFILTER2* pFilterInformation) |
---|
64 | { |
---|
65 | _A(pFilterInformation); |
---|
66 | _Z4(atlTraceCOM, 4, _T("pFilterInformation { dwVersion %d, dwMerit 0x%08x, cPins2 %d }\n"), pFilterInformation->dwVersion, pFilterInformation->dwMerit, pFilterInformation->cPins2); |
---|
67 | if(pFilterInformation->dwVersion == 2) |
---|
68 | for(ULONG nPinIndex = 0; nPinIndex < pFilterInformation->cPins2; nPinIndex++) |
---|
69 | { |
---|
70 | const REGFILTERPINS2& Pin = pFilterInformation->rgPins2[nPinIndex]; |
---|
71 | _Z4(atlTraceCOM, 4, _T("pFilterInformation->rgPins2[%d] { dwFlags 0x%x, cInstances %d, nMediaTypes %d, nMediums %d }\n"), nPinIndex, Pin.dwFlags, Pin.cInstances, Pin.nMediaTypes, Pin.nMediums, Pin.clsPinCategory ? (LPCWSTR) _PersistHelper::StringFromIdentifier(*Pin.clsPinCategory) : L"NULL"); |
---|
72 | for(UINT nIndex = 0; nIndex < Pin.nMediaTypes; nIndex++) |
---|
73 | { |
---|
74 | const REGPINTYPES& Type = Pin.lpMediaType[nIndex]; |
---|
75 | _Z4(atlTraceCOM, 4, _T("pFilterInformation->rgPins2[...].lpMediaType[%d] { clsMajorType %ls, clsMinorType %ls }\n"), nIndex, Type.clsMajorType ? (LPCWSTR) _PersistHelper::StringFromIdentifier(*Type.clsMajorType) : L"NULL", Type.clsMinorType ? (LPCWSTR) _PersistHelper::StringFromIdentifier(*Type.clsMinorType) : L"NULL"); |
---|
76 | } |
---|
77 | for(UINT nIndex = 0; nIndex < Pin.nMediums; nIndex++) |
---|
78 | { |
---|
79 | const REGPINMEDIUM& Medium = Pin.lpMedium[nIndex]; |
---|
80 | _Z4(atlTraceCOM, 4, _T("pFilterInformation->rgPins2[...].lpMedium[%d] { clsMedium %ls, dw1 0x%x, dw2 0x%x }\n"), nIndex, _PersistHelper::StringFromIdentifier(Medium.clsMedium), Medium.dw1, Medium.dw2); |
---|
81 | } |
---|
82 | } |
---|
83 | } |
---|
84 | BOOL IsAggregated() const throw() |
---|
85 | { |
---|
86 | return (ULONG) m_dwRef >= 0x00001000; |
---|
87 | } |
---|
88 | |
---|
89 | public: |
---|
90 | // CFilterMapperSpyT |
---|
91 | static LPCTSTR GetOriginalLibraryName() throw() |
---|
92 | { |
---|
93 | return _T("quartz.dll"); |
---|
94 | } |
---|
95 | static CString GetObjectFriendlyName() |
---|
96 | { |
---|
97 | return _StringHelper::GetLine(T::IDR, 2); |
---|
98 | } |
---|
99 | static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw() |
---|
100 | { |
---|
101 | _Z2(atlTraceRegistrar, 2, _T("bRegister %d\n"), bRegister); |
---|
102 | _ATLTRY |
---|
103 | { |
---|
104 | TreatAsUpdateRegistryFromResource<T>(*t_pFilterMapperClassIdentifier, bRegister); |
---|
105 | } |
---|
106 | _ATLCATCH(Exception) |
---|
107 | { |
---|
108 | _C(Exception); |
---|
109 | } |
---|
110 | return S_OK; |
---|
111 | } |
---|
112 | CFilterMapperSpyT() throw() : |
---|
113 | m_hQuartzModule(NULL) |
---|
114 | { |
---|
115 | _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this); |
---|
116 | } |
---|
117 | ~CFilterMapperSpyT() throw() |
---|
118 | { |
---|
119 | _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this); |
---|
120 | } |
---|
121 | HRESULT FinalConstruct() throw() |
---|
122 | { |
---|
123 | _ATLTRY |
---|
124 | { |
---|
125 | m_bIsAggregated = IsAggregated(); |
---|
126 | TCHAR pszPath[MAX_PATH] = { 0 }; |
---|
127 | _W(GetModuleFileName(NULL, pszPath, DIM(pszPath))); |
---|
128 | _Z4(atlTraceRefcount, 4, _T("pszPath \"%s\", this 0x%08x, m_dwRef %d, m_bIsAggregated %d\n"), pszPath, this, m_dwRef, m_bIsAggregated); |
---|
129 | const HINSTANCE hModule = CoLoadLibrary(const_cast<LPOLESTR>((LPCOLESTR) CT2COLE(GetOriginalLibraryName())), TRUE); |
---|
130 | _ATLTRY |
---|
131 | { |
---|
132 | typedef HRESULT (WINAPI *DLLGETCLASSOBJECT)(REFCLSID, REFIID, VOID**); |
---|
133 | DLLGETCLASSOBJECT DllGetClassObject = (DLLGETCLASSOBJECT) GetProcAddress(hModule, "DllGetClassObject"); |
---|
134 | __E(DllGetClassObject); |
---|
135 | CComPtr<IClassFactory> pClassFactory; |
---|
136 | __C(DllGetClassObject(*t_pFilterMapperClassIdentifier, __uuidof(IClassFactory), (VOID**) &pClassFactory)); |
---|
137 | _A(pClassFactory); |
---|
138 | const CComPtr<IUnknown> pControllingUnknown = GetControllingUnknown(); |
---|
139 | { |
---|
140 | CComPtr<IUnknown> pUnknown; |
---|
141 | __C(pClassFactory->CreateInstance(pControllingUnknown, __uuidof(IUnknown), (VOID**) &pUnknown)); |
---|
142 | const CComQIPtr<IFilterMapper2> pFilterMapper2 = pUnknown; |
---|
143 | __D(pFilterMapper2, E_NOINTERFACE); |
---|
144 | pFilterMapper2.p->Release(); |
---|
145 | const CComQIPtr<IAMFilterData> pAmFilterData = pUnknown; |
---|
146 | __D(pAmFilterData, E_NOINTERFACE); |
---|
147 | pAmFilterData.p->Release(); |
---|
148 | m_pInnerUnknown = pUnknown; |
---|
149 | m_pFilterMapper2 = pFilterMapper2; |
---|
150 | m_pAmFilterData = pAmFilterData; |
---|
151 | } |
---|
152 | } |
---|
153 | _ATLCATCHALL() |
---|
154 | { |
---|
155 | CoFreeLibrary(hModule); |
---|
156 | _ATLRETHROW; |
---|
157 | } |
---|
158 | _A(!m_hQuartzModule); |
---|
159 | m_hQuartzModule = hModule; |
---|
160 | } |
---|
161 | _ATLCATCH(Exception) |
---|
162 | { |
---|
163 | _C(Exception); |
---|
164 | } |
---|
165 | return S_OK; |
---|
166 | } |
---|
167 | VOID FinalRelease() throw() |
---|
168 | { |
---|
169 | _Z5(atlTraceRefcount, 5, _T("m_dwRef 0x%x\n"), m_dwRef); |
---|
170 | CComPtr<IUnknown> pControllingUnknown = GetControllingUnknown(); |
---|
171 | if(m_pFilterMapper2) |
---|
172 | { |
---|
173 | pControllingUnknown.p->AddRef(); |
---|
174 | m_pFilterMapper2 = NULL; |
---|
175 | } |
---|
176 | if(m_pAmFilterData) |
---|
177 | { |
---|
178 | pControllingUnknown.p->AddRef(); |
---|
179 | m_pAmFilterData = NULL; |
---|
180 | } |
---|
181 | _ATLTRY |
---|
182 | { |
---|
183 | m_pInnerUnknown = NULL; |
---|
184 | } |
---|
185 | _ATLCATCHALL() |
---|
186 | { |
---|
187 | _Z_EXCEPTION(); |
---|
188 | // NOTE: For some unidentified reason Quartz's FilterGraph may crash during final release, to smooth the effect the exception is silently caught |
---|
189 | m_pInnerUnknown.p = NULL; |
---|
190 | } |
---|
191 | if(m_hQuartzModule) |
---|
192 | { |
---|
193 | CoFreeLibrary(m_hQuartzModule); |
---|
194 | m_hQuartzModule = NULL; |
---|
195 | } |
---|
196 | } |
---|
197 | |
---|
198 | // IFilterMapperSpy |
---|
199 | |
---|
200 | // IAMFilterData |
---|
201 | STDMETHOD(ParseFilterData)(BYTE* pnFilterData, ULONG nFilterDataSize, BYTE** ppFilterInformation) throw() |
---|
202 | { |
---|
203 | _Z4(atlTraceCOM, 4, _T("nFilterDataSize %d\n"), nFilterDataSize); |
---|
204 | const HRESULT nResult = m_pAmFilterData->ParseFilterData(pnFilterData, nFilterDataSize, ppFilterInformation); |
---|
205 | if(SUCCEEDED(nResult) && ppFilterInformation && *ppFilterInformation && *((BYTE**) *ppFilterInformation)) |
---|
206 | _ATLTRY |
---|
207 | { |
---|
208 | Trace((REGFILTER2*) *((BYTE**) *ppFilterInformation)); |
---|
209 | } |
---|
210 | _ATLCATCHALL() |
---|
211 | { |
---|
212 | _Z_EXCEPTION(); |
---|
213 | } |
---|
214 | return nResult; |
---|
215 | } |
---|
216 | STDMETHOD(CreateFilterData)(REGFILTER2* pFilterInformation, BYTE** ppnFilterData, ULONG* pnFilterDataSize) throw() |
---|
217 | { |
---|
218 | _Z4(atlTraceCOM, 4, _T("...\n")); |
---|
219 | if(pFilterInformation) |
---|
220 | _ATLTRY |
---|
221 | { |
---|
222 | Trace(pFilterInformation); |
---|
223 | } |
---|
224 | _ATLCATCHALL() |
---|
225 | { |
---|
226 | _Z_EXCEPTION(); |
---|
227 | } |
---|
228 | return m_pAmFilterData->CreateFilterData(pFilterInformation, ppnFilterData, pnFilterDataSize); |
---|
229 | } |
---|
230 | |
---|
231 | // IFilterMapper2 |
---|
232 | STDMETHOD(CreateCategory)(REFCLSID CategoryIdentifier, DWORD nMerit, LPCWSTR pszDescription) throw() |
---|
233 | { |
---|
234 | _Z4(atlTraceCOM, 4, _T("CategoryIdentifier %ls, nMerit 0x%08x, pszDescription \"%s\"\n"), _PersistHelper::StringFromIdentifier(CategoryIdentifier), nMerit, CString(pszDescription)); |
---|
235 | return m_pFilterMapper2->CreateCategory(CategoryIdentifier, nMerit, pszDescription); |
---|
236 | } |
---|
237 | STDMETHOD(UnregisterFilter)(const CLSID* pCategoryIdentifier, LPCOLESTR pszInstance, REFCLSID FilterClassIdentifier) throw() |
---|
238 | { |
---|
239 | _Z4(atlTraceCOM, 4, _T("pCategoryIdentifier %ls, pszInstance %s, FilterClassIdentifier %ls\n"), pCategoryIdentifier ? (LPCWSTR) _PersistHelper::StringFromIdentifier(*pCategoryIdentifier) : L"NULL", pszInstance ? (LPCTSTR) AtlFormatString(_T("\"%s\""), CString(pszInstance)) : _T("NULL"), _PersistHelper::StringFromIdentifier(FilterClassIdentifier)); |
---|
240 | return m_pFilterMapper2->UnregisterFilter(pCategoryIdentifier, pszInstance, FilterClassIdentifier); |
---|
241 | } |
---|
242 | STDMETHOD(RegisterFilter)(REFCLSID FilterClassIdentifier, LPCWSTR pszName, IMoniker** ppMoniker, const CLSID* pCategoryIdentifier, LPCOLESTR pszInstance, const REGFILTER2* pFilterInformation) throw() |
---|
243 | { |
---|
244 | _Z4(atlTraceCOM, 4, _T("FilterClassIdentifier %ls, pszName \"%s\", pCategoryIdentifier %ls, pszInstance %s\n"), _PersistHelper::StringFromIdentifier(FilterClassIdentifier), CString(pszName), pCategoryIdentifier ? (LPCWSTR) _PersistHelper::StringFromIdentifier(*pCategoryIdentifier) : L"NULL", pszInstance ? (LPCTSTR) AtlFormatString(_T("\"%s\""), CString(pszInstance)) : _T("NULL")); |
---|
245 | if(pFilterInformation) |
---|
246 | _ATLTRY |
---|
247 | { |
---|
248 | Trace(pFilterInformation); |
---|
249 | } |
---|
250 | _ATLCATCHALL() |
---|
251 | { |
---|
252 | _Z_EXCEPTION(); |
---|
253 | } |
---|
254 | return m_pFilterMapper2->RegisterFilter(FilterClassIdentifier, pszName, ppMoniker, pCategoryIdentifier, pszInstance, pFilterInformation); |
---|
255 | } |
---|
256 | STDMETHOD(EnumMatchingFilters)(IEnumMoniker** ppEnumMoniker, DWORD nFlags, BOOL bExactMatch, DWORD nMinimalMerit, BOOL bInputNeeded, DWORD nInputTypeCount, const GUID* pInputTypes, const REGPINMEDIUM* pInputMedium, const CLSID* pInputPinCategory, BOOL bRender, BOOL bOutputNeeded, DWORD nOutputTypeCount, const GUID* pOutputTypes, const REGPINMEDIUM* pOutputMedium, const CLSID* pOutputPinCategory) throw() |
---|
257 | { |
---|
258 | _Z4(atlTraceCOM, 4, _T("nFlags 0x%x, bExactMatch %d, nMinimalMerit 0x%08x, bInputNeeded %d, nInputTypeCount %d, pInputPinCategory %ls, bRender %d, bOutputNeeded %d, nOutputTypeCount %d, pOutputPinCategory %ls\n"), nFlags, bExactMatch, nMinimalMerit, bInputNeeded, nInputTypeCount, pInputPinCategory ? (LPCWSTR) _PersistHelper::StringFromIdentifier(*pInputPinCategory) : L"NULL", bRender, bOutputNeeded, nOutputTypeCount, pOutputPinCategory ? (LPCWSTR) _PersistHelper::StringFromIdentifier(*pOutputPinCategory) : L"NULL"); |
---|
259 | for(DWORD nInputTypeIndex = 0; nInputTypeIndex < nInputTypeCount; nInputTypeIndex++) |
---|
260 | { |
---|
261 | const GUID& MajorType = pInputTypes[2 * nInputTypeIndex + 0]; |
---|
262 | const GUID& Subtype = pInputTypes[2 * nInputTypeIndex + 1]; |
---|
263 | _Z4(atlTraceCOM, 4, _T("nInputTypeIndex %d, MajorType %ls, Subtype %ls\n"), nInputTypeIndex, _PersistHelper::StringFromIdentifier(MajorType), _PersistHelper::StringFromIdentifier(Subtype)); |
---|
264 | } |
---|
265 | if(pInputMedium) |
---|
266 | _Z4(atlTraceCOM, 4, _T("pInputMedium { clsMedium %ls, dw1 0x%x, dw2 0x%x }\n"), _PersistHelper::StringFromIdentifier(pInputMedium->clsMedium), pInputMedium->dw1, pInputMedium->dw2); |
---|
267 | for(DWORD nOutputTypeIndex = 0; nOutputTypeIndex < nOutputTypeCount; nOutputTypeIndex++) |
---|
268 | { |
---|
269 | const GUID& MajorType = pOutputTypes[2 * nOutputTypeIndex + 0]; |
---|
270 | const GUID& Subtype = pOutputTypes[2 * nOutputTypeIndex + 1]; |
---|
271 | _Z4(atlTraceCOM, 4, _T("nOutputTypeIndex %d, MajorType %ls, Subtype %ls\n"), nOutputTypeIndex, _PersistHelper::StringFromIdentifier(MajorType), _PersistHelper::StringFromIdentifier(Subtype)); |
---|
272 | } |
---|
273 | if(pOutputMedium) |
---|
274 | _Z4(atlTraceCOM, 4, _T("pOutputMedium { clsMedium %ls, dw1 0x%x, dw2 0x%x }\n"), _PersistHelper::StringFromIdentifier(pOutputMedium->clsMedium), pOutputMedium->dw1, pOutputMedium->dw2); |
---|
275 | const HRESULT nResult = m_pFilterMapper2->EnumMatchingFilters(ppEnumMoniker, nFlags, bExactMatch, nMinimalMerit, bInputNeeded, nInputTypeCount, pInputTypes, pInputMedium, pInputPinCategory, bRender, bOutputNeeded, nOutputTypeCount, pOutputTypes, pOutputMedium, pOutputPinCategory); |
---|
276 | if(SUCCEEDED(nResult)) |
---|
277 | _ATLTRY |
---|
278 | { |
---|
279 | const CComPtr<IEnumMoniker>& pEnumMoniker = reinterpret_cast<const CComPtr<IEnumMoniker>&>(*ppEnumMoniker); |
---|
280 | __C(pEnumMoniker->Reset()); |
---|
281 | CComPtr<IMoniker> pMoniker; |
---|
282 | while(pEnumMoniker->Next(1, &pMoniker, NULL) == S_OK) |
---|
283 | { |
---|
284 | _Z4(atlTraceCOM, 4, _T("pMoniker %ls\n"), _FilterGraphHelper::GetMonikerDisplayName(pMoniker)); |
---|
285 | CComPtr<IBindCtx> pBindCtx; |
---|
286 | __C(CreateBindCtx(0, &pBindCtx)); |
---|
287 | CComPtr<IPropertyBag> pPropertyBag; |
---|
288 | __C(pMoniker->BindToStorage(pBindCtx, NULL, __uuidof(IPropertyBag), (VOID**) &pPropertyBag)); |
---|
289 | const CStringW sFriendlyName = _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, OLESTR("FriendlyName")); |
---|
290 | const CStringW sDescription = _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, OLESTR("Description")); |
---|
291 | const CStringW sDevicePath = _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, OLESTR("DevicePath")); |
---|
292 | _Z4(atlTraceCOM, 4, _T("sFriendlyName \"%ls\", sDescription \"%ls\", sDevicePath \"%ls\"\n"), sFriendlyName, sDescription, sDevicePath); |
---|
293 | pMoniker.Release(); |
---|
294 | } |
---|
295 | __C(pEnumMoniker->Reset()); |
---|
296 | } |
---|
297 | _ATLCATCHALL() |
---|
298 | { |
---|
299 | _Z_EXCEPTION(); |
---|
300 | } |
---|
301 | return nResult; |
---|
302 | } |
---|
303 | }; |
---|
304 | |
---|
305 | //////////////////////////////////////////////////////////// |
---|
306 | // CFilterMapperSpy |
---|
307 | |
---|
308 | class ATL_NO_VTABLE CFilterMapperSpy : |
---|
309 | public CFilterMapperSpyT<CFilterMapperSpy, &CLSID_FilterMapper2>, |
---|
310 | public CComCoClass<CFilterMapperSpy, &CLSID_FilterMapperSpy> |
---|
311 | { |
---|
312 | public: |
---|
313 | enum { IDR = IDR_FILTERMAPPERSPY }; |
---|
314 | |
---|
315 | private: |
---|
316 | static LPCTSTR g_pszClassName; |
---|
317 | |
---|
318 | public: |
---|
319 | //typedef CBlackListAwareComCreatorT<CComObjectCached<CFilterMapperSpy>, CFilterMapperSpy, &g_pszClassName> _ClassFactoryCreatorClass; // DECLARE_CLASSFACTORY override |
---|
320 | typedef CComCreator2<CBlackListAwareComCreatorT<CComObject<CFilterMapperSpy>, CFilterMapperSpy, &g_pszClassName>, CBlackListAwareComCreatorT<CComAggObject<CFilterMapperSpy>, CFilterMapperSpy, &g_pszClassName> > _CreatorClass; // DECLARE_AGGREGATABLE override |
---|
321 | |
---|
322 | public: |
---|
323 | // CFilterMapperSpy |
---|
324 | }; |
---|
325 | |
---|
326 | __declspec(selectany) LPCTSTR CFilterMapperSpy::g_pszClassName = _T("CFilterMapperSpy"); |
---|
327 | |
---|
328 | OBJECT_ENTRY_AUTO(__uuidof(FilterMapperSpy), CFilterMapperSpy) |
---|
329 | |
---|