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