图1 添加头文件 |
图2 添加动态库 |
图3 |
图4 |
DllMain DllGetClassObject DllCanUnloadNow DllRegisterServer DllUnregisterServer |
extern "C" _declspec(dllexport)BOOL DllRegisterServer; |
LIBRARY MyFilter.ax EXPORTS DllMain PRIVATE DllGetClassObject PRIVATE DllCanUnloadNow PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE |
STDAPI DllRegisterServer() { return AMovieDllRegisterServer2(TRUE); } STDAPI DllUnregisterServer() { return AMovieDllRegisterServer2(FALSE); } extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved); } |
图5 |
此时你编译一下,好像还是通不过,它提示有一个全局的用于实现COM接口的变量没有定义,不着急,下面我们就开始实现Filter的com接口。
三 如何实现Filter 的类厂对象
我们知道一个Filter是一个com组件,所以它com特性的实现其实在其基类中实现的,比如IUnknown接口,我们直接从基类派生出我们的Filter后,它就支持com接口了,它就是一个com组件了。
所有的com组件为了实现二进制的封装,所以连创建的接口都封装了,因此每个com对象都有个类对象(也叫类厂对象,本身也是com对象,用来创建com组件)来创建com组件。
下面温习一下com组件的创建过程,其中涉及到几个函数
1、当客户端要创建一个com组件时,它通过底层的COM API函数 CoGetClassObject()使用SCM的服务,这个函数请SCM把一个指针绑定到客户端请求的com组件的类对象上,其实在CoGetClassObject()里它装载了该DLL的库,通过该dll的导出函数DllGetClassObject();DllGetClassObject根据客户端提供的com组件CLASSID,返回该com组件类对象的指针。下面com组件的创建和SCM无关了。
2、客户端利用组件的类对象(类厂对象)的IClassFactory::CreateInstance方法创建com组件。
Filter在这里使用了一个类厂模板类来当作Filter的类厂对象。下面看看类厂在DShow是怎么工作的。
类厂对象也是一个com组件。本来DllGetClassObject是应该由我们自己完成一个函数,在directshow基类里已经完成了,我们不用管它了。它的功能就是来寻找这个DLL中的类厂对象,看是否有符合客户端请求的类厂对象。
DLL里声明了一个全局的类厂模板数组,当DllGetClassObject请求类厂对象的时候,它就搜索这个数组,看是否有和CLSID匹配的类厂对象。当它找到一个匹配的CLSID,它就创建一个类厂对象,然后讲类厂指针返回给CoGetClassObject,然后客户端可以根据返回去的类厂指针,调用 IClassFactory::CreateInstance方法创建组件,类厂就根据数组里定义的方法创建com组件。
factory template包含下列变量:
const WCHAR * m_Name; // Name const CLSID * m_ClsID; // CLSID LPFNNewCOMObject m_lpfnNew; // Function to create an instance of the component LPFNInitRoutine m_lpfnInit; // Initialization function (optional) const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; // Set-up information (for filters) |
typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr); typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); |
CUnknown * WINAPI CMyFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr) { CMyFilter *pFilter = new CMyFilter(NAME("my Filter"), pUnk, pHr); if (pFilter== NULL) { *pHr = E_OUTOFMEMORY; } return pFilter; } |
CFactoryTemplate g_Templates[1] = { { L"my filter", // Name &CLSID_MYFilter, // CLSID CMyFilter::CreateInstance, // Method to create an instance of MyComponent NULL, // Initialization function &sudInfTee // Set-up information (for filters) } }; int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); |
class CMyFilter : public CCritSec, public CBaseFilter { public: CMyFilter(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *hr); virtual ~CMyFilter(); static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); CBasePin *GetPin(int n); int GetPinCount(); } |
// {1915C5C7-02AA-415f-890F-76D94C85AAF1} DEFINE_GUID(CLSID_MYFilter, 0x1915c5c7, 0x2aa, 0x415f, 0x89, 0xf, 0x76, 0xd9, 0x4c, 0x85, 0xaa, 0xf1); |
CMyFilter::CMyFilter(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *hr) :CBaseFilter(NAME("my filter"), pUnk, this, CLSID_MYFilter) { } CMyFilter::~CMyFilter() {} // Public method that returns a new instance. CUnknown * WINAPI CMyFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr) { CMyFilter *pFilter = new CMyFilter(NAME("my Filter"), pUnk, pHr); if (pFilter== NULL) { *pHr = E_OUTOFMEMORY; } return pFilter; } CBasePin * CMyFilter::GetPin(int n) { return NULL; } int CMyFilter::GetPinCount() { return 0; } |
CFactoryTemplate g_Templates[1] = { { L"my filter", // Name &CLSID_MYFilter, // CLSID CMyFilter::CreateInstance, // Method to create an instance of MyComponent NULL, // Initialization function &sudInfTee // Set-up information (for filters) } }; int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); |
static const WCHAR g_wszName[] = L"Some Filter"; AMOVIESETUP_MEDIATYPE sudMediaTypes[] = { { &MEDIATYPE_Video, &MEDIASUBTYPE_RGB24 }, { &MEDIATYPE_Video, &MEDIASUBTYPE_RGB32 }, }; AMOVIESETUP_PIN sudOutputPin = { L"", // Obsolete, not used. FALSE, // Is this pin rendered? TRUE, // Is it an output pin? FALSE, // Can the filter create zero instances? FALSE, // Does the filter create multiple instances? &GUID_NULL, // Obsolete. NULL, // Obsolete. 2, // Number of media types. sudMediaTypes // Pointer to media types. }; AMOVIESETUP_FILTER sudFilterReg = { &CLSID_SomeFilter, // Filter CLSID. g_wszName, // Filter name. MERIT_NORMAL, // Merit. 1, // Number of pin types. &sudOutputPin // Pointer to pin information. }; |
#include streams.h #include initguid.h #include tchar.h #include stdio.h |