Using Filters Without Registration

Sometimes it’s useful to use filters without COM registration. COM registration requires admin rights, and allows other apps to use the filters. You can bypass this and use the filters directly, if you create them yourself and insert them into the graph.

Create using new

There are two ways to create a filter yourself. If you have the source to the filter, or a private API, you can just construct the filter with new. The important thing to remember is that you need to AddRef() the filter immediately, and then treat it like a normal COM object. When you are finished with it, Release() it rather than deleting it. If you use a smart pointer, this will all be taken care of for you.

#include <comdef.h>
_COM_SMARTPTR_TYPEDEF(IBaseFilter, __uuidof(IBaseFilter));

IBaseFilterPtr pFilter = new CMyFilterClass();

Create using a private CoCreateInstance

Of course, in many cases, you will only have the filter DLL. Since the DLL is not registered, there is no way of mapping the filter’s CLSID to the DLL that contains it, so you can’t call CoCreateInstance. But if you know which DLL the filter is in, you can bypass that lookup and simply instantiate the filter exactly as CoCreateInstance does.

This function will create an in-proc server for a COM object, given the filename and the CLSID.

// define the prototype of the class factory entry point in a COM dll
typedef HRESULT (STDAPICALLTYPE* FN_DLLGETCLASSOBJECT)(REFCLSID clsid, REFIID iid, void** ppv);

HRESULT CreateObjectFromPath(TCHAR* pPath, REFCLSID clsid, IUnknown** ppUnk)
{
	// load the target DLL directly
	HMODULE lib = LoadLibrary(pPath);
	if (!lib)
	{
		return HRESULT_FROM_WIN32(GetLastError());
	}

	// the entry point is an exported function
	FN_DLLGETCLASSOBJECT fn = (FN_DLLGETCLASSOBJECT)GetProcAddress(lib, "DllGetClassObject");
	if (fn == NULL)
	{
		return HRESULT_FROM_WIN32(GetLastError());
	}

	// create a class factory
	IUnknownPtr pUnk;
	HRESULT hr = fn(clsid,  IID_IUnknown,  (void**)(IUnknown**)&pUnk);
	if (SUCCEEDED(hr))
	{
		IClassFactoryPtr pCF = pUnk;
		if (pCF == NULL)
		{
			hr = E_NOINTERFACE;
		}
		else
		{
			// ask the class factory to create the object
			hr = pCF->CreateInstance(NULL, IID_IUnknown, (void**)ppUnk);
		}
	}

	return hr;
}

Graph-building with private filters

In most cases, you can use an unregistered filter simply by adding it to the graph before calling RenderFile (or any other intelligent connect or render operation). The graph manager will try all the filters in the graph before looking through the registry to find new filters. If you have a custom demux, decoder or renderer, you can use it like this:

IUnknownPtr pUnk;
HRESULT hr = CreateObjectFromPath(TEXT("c:\\path\\to\\myfilter.dll"), IID_MyFilter, &pUnk);
if (SUCCEEDED(hr))
{
	IBaseFilterPtr pFilter = pUnk;
	pGraph->AddFilter(pFilter, L"Private Filter");
	pGraph->RenderFile(pMediaClip, NULL);
}