I've written a small transform filter (derived from TransInPlaceFilter baseclass), and managed to make it work properly in a Directshow graph, entirely coded in C++. I basically followed the 5 first steps described on MSDN, and the last part of the 6th step (in order to use the filter directly within an application).
For a lot of reasons (including being able to use the filter in GraphEdit), I need to export that filter in a DLL and register it.
I've been trying to follow these steps : setting up the "CreateInstance" method, the CFactoryTemplate class, filter/pins description (AMOVIESETUP_FILTER, AMOVIESETUP_PIN, AMOVIESETUP_MEDIA), Registering/Unregistering functions, and finally DLLmain/entrypoint.
The code successfully compiles and provides a DLL, which seems to register without any problem using Regsvr32.
But then I'm unable to use the filter :
- It appears in the list in GraphEdit, but fails when I try to insert it : 0x800401f9 ("Error in DLL").
- When I try to create it in C++ (using
pCustomFilter.CoCreateInstance(CLSID_Custom)
, after defining the correct GUID), I get error 0x80040154 (REGDB_E_CLASSNOTREG)
I'm quite confused here. Have I missed something in the DLL/registration code ? I'm posting most of the code I'm using, if it's of any use.
Any help would be greatly appreciated.
static const WCHAR g_wszName[] = L"Custom Filter";
AMOVIESETUP_MEDIATYPE sudMediaTypes[] = {
{ &MEDIATYPE_Video, &MEDIASUBTYPE_NULL },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_NULL },
};
AMOVIESETUP_PIN sudPins[2] = {
{
L"Input", // Name
FALSE, // Is this pin rendered?
FALSE, // 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.
},
{
L"Output", // Name
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_Custom, // Filter CLSID.
g_wszName, // Filter name.
MERIT_DO_NOT_USE, // Merit.
2, // Number of pin types.
sudPins // Pointer to pin information.
};
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_Custom,
CCustomFilter::CreateInstance,
NULL,
&sudFilterReg
}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)
{
return DllEntryPoint(reinterpret_cast<HINSTANCE>(hDllHandle), dwReason, lpReserved);
}
// ---
// Meanwhile, in my filter class...
// ---
CUnknown * WINAPI CCustomFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CCustomFilter *pFilter = new CCustomFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
One thing to check would be that the GUID is the same everywhere: AMOVIESETUP_FILTER, CFactoryTemplate, and passed to the CTransInPlaceFilter constructor.
Also, it is good practice to pass the pUnk, and pHr parameter of CCustomFilter::CreateInstance to your CCustomFilter constructor and from there to the CTransInPlaceFilter constructor, so that any errors can be propagated to the caller. In your case any such errors would be swallowed by your constructor. Example: