CFactoryTemplate g_Templates[] = { { g_wszName, // Name. &CLSID_SomeFilter, // CLSID. CSomeFilter::CreateInstance, // Creation function. NULL, &sudFilterReg // Pointer to filter information. } }; int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
了解一下:
typedef struct { const CLSID *clsMajorType; const CLSID *clsMinorType; } REGPINTYPES; typedef REGPINTYPES AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * LPAMOVIESETUP_MEDIATYPE;
typedef struct { LPWSTR strName; BOOL bRendered; BOOL bOutput; BOOL bZero; BOOL bMany; const CLSID *clsConnectsToFilter; const WCHAR *strConnectsToPin; UINT nMediaTypes; const REGPINTYPES *lpMediaType; } REGFILTERPINS; typedef REGFILTERPINS AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * LPAMOVIESETUP_PIN;
typedef struct _AMOVIESETUP_FILTER { const CLSID *clsID; const WCHAR *strName; DWORD dwMerit; UINT nPins; const AMOVIESETUP_PIN *lpPin; } AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER;
原因在于DirectShow的BaseClasses已经为我们设计好了Filter的架构,在基类中已经实现了DllGetClassObject,我们知道它是用来创建类工厂的,OK,来看一下其实现:
//called by COM to get the class factory object for a given class
STDAPI
DllGetClassObject(
REFCLSID rClsID, //客户端传进来的,来自于CoCreateInstance或CoDllGetClassObject
REFIID riid,
void **pv)
{
if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
return E_NOINTERFACE;
}
// traverse the array of templates looking for one with this
// class id
for (int i = 0; i < g_cTemplates; i++) {
const CFactoryTemplate * pT = &g_Templates[i];
if (pT->IsClassID(rClsID)) {
// found a template - make a class factory based on this
// template
*pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
if (*pv == NULL) {
return E_OUTOFMEMORY;
}
((LPUNKNOWN)*pv)->AddRef();
return NOERROR;
}
}
return CLASS_E_CLASSNOTAVAILABLE;
}
从上面的代码可以清楚地看到,当在类工厂模板中找到客户端传进来的CLSID时就创建对应的类工厂组件。当类工厂创建后,客户就可以调用类工厂的CreateInstance来创建我们的自己组件,即Filter。看一下CreateInstance的具体实现。
STDMETHODIMP
CClassFactory::CreateInstance(
LPUNKNOWN pUnkOuter, // 客户传进来,一般为NULL,非聚合
REFIID riid,
void **pv)
{
CheckPointer(pv,E_POINTER)
ValidateReadWritePtr(pv,sizeof(void *));
/* Enforce the normal OLE rules regarding interfaces and delegation */
if (pUnkOuter != NULL) {
if (IsEqualIID(riid,IID_IUnknown) == FALSE) {
return ResultFromScode(E_NOINTERFACE);
}
}
/* Create the new object through the derived class's create function */
HRESULT hr = NOERROR; //和pUnkOuter一起传给我们自己实现的CreateInstance
CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
if (pObj == NULL) {
if (SUCCEEDED(hr)) {
hr = E_OUTOFMEMORY;
}
return hr;
}
/* Delete the object if we got a construction error */
if (FAILED(hr)) {
delete pObj;
return hr;
}
/* Get a reference counted interface on the object */
/* We wrap the non-delegating QI with NDAddRef & NDRelease. */
/* This protects any outer object from being prematurely */
/* released by an inner object that may have to be created */
/* in order to supply the requested interface. */
pObj->NonDelegatingAddRef();
hr = pObj->NonDelegatingQueryInterface(riid, pv);
pObj->NonDelegatingRelease();
/* Note that if NonDelegatingQueryInterface fails, it will */
/* not increment the ref count, so the NonDelegatingRelease */
/* will drop the ref back to zero and the object will "self-*/
/* destruct". Hence we don't need additional tidy-up code */
/* to cope with NonDelegatingQueryInterface failing. */
if (SUCCEEDED(hr)) {
ASSERT(*pv);
}
return hr;
}
m_pTemplate->CreateInstance(pUnkOuter, &hr);//这里实际上调用了我们自己Filter组件类中的CreateInstance,因为这里的m_pTemplate中保存了我们自己定义的类模板(在CClassFactory的构造函数中)。
好了,再看一下CFactoryTemplate的定义,其实就是一个结构体,到了这里也就知道上面的g_Templates为什么要那样写了!注意这里的m_lpfnNew,它是一个函数指针,对应我们自己写的CreateInstance,这是Filter能够被创建的关键之处.
/* A function that can create a new COM object */
typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
/* A function (can be NULL) which is called from the DLL entrypoint
routine for each factory template:
bLoading - TRUE on DLL load, FALSE on DLL unload
rclsid - the m_ClsID of the entry
*/
typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
class CFactoryTemplate {
public:
const WCHAR * m_Name;
const CLSID * m_ClsID;
LPFNNewCOMObject m_lpfnNew;
LPFNInitRoutine m_lpfnInit; //用于DLL加载时初始化的,一般不用
const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter;
BOOL IsClassID(REFCLSID rclsid) const {
return (IsEqualCLSID(*m_ClsID,rclsid));
};
CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const {
CheckPointer(phr,NULL);
return m_lpfnNew(pUnk, phr);
};
};
OK,有了上面的这些基础,我们就可以清楚自己开发的Filter是如何被创建的。
总结一下Filter创建的大概过程:
客户端在将Filter加入到FilterGraph之前,必须先创建对应某个CLSID的Filter组件(只有Filter被创建了,才能够通过AddFilter将其加入到FilterGraph中,继续实现Pin的连接等过程),客户可以通过CoCreateInstance创建Filter,而在CoCreateInstance会调用CoDllGetClassObject,CoDllGetClassObject又会调用DirectShow基类中DllGetClassObject来创建对应这个CLSID的类工厂,类工厂创建好了之后返回到CoDllGetClassObject中,在这里继续查询刚才创建的类工厂组件的IClassFactory接口,获得这个接口指针后就可以利用这个接口指针来调用类工厂中的CreateInstance,这样可以跳转至我们自己实现的CreateInstance中实现自己开发的Filter能够被创建。
出处:http://blog.chinaunix.net/u2/66646/showart_572919.html