Creating Kernel-Mode Filters

 
Microsoft DirectShow 9.0

Creating Kernel-Mode Filters

Certain kernel-mode filters cannot be created through CoCreateInstance, and thus do not have CLSIDs. These filters include the Tee/Sink-to-Sink Converter, the CC Decoder filter, and the WST Codec filter. To create one of these filters, use the System Device Enumerator object and search by the filter's name.

  1. Create the System Device Enumerator.
  2. Call the ICreateDevEnum::CreateClassEnumerator method with the CLSID of the filter category for that filter. This method creates an enumerator for the filter category. (An enumerator is simply an object that returns a list of other objects, using a defined COM interface.) The enumerator returns IMoniker pointers, which represent the filters in that category.
  3. For each moniker, call IMoniker::BindToStorage to get an IPropertyBag interface.
  4. Call IPropertyBag::Read to get the name of the filter.
  5. If the name matches, call IMoniker::BindToObject to create the filter.

The following code shows a function that performs these steps:

HRESULT CreateKernelFilter(
    const GUID &guidCategory,  // Filter category.
    LPCOLESTR szName,          // The name of the filter.
    IBaseFilter **ppFilter     // Receives a pointer to the filter.
)
{
    HRESULT hr;
    ICreateDevEnum *pDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    if (!szName || !ppFilter) 
    {
        return E_POINTER;
    }

    // Create the system device enumerator.
    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
        IID_ICreateDevEnum, (void**)&pDevEnum);
    if (FAILED(hr))
    {
        return hr;
    }

    // Create a class enumerator for the specified category.
    hr = pDevEnum->CreateClassEnumerator(guidCategory, &pEnum, 0);
    pDevEnum->Release();
    if (hr != S_OK) // S_FALSE means the category is empty.
    {
        return E_FAIL;
    }

    // Enumerate devices within this category.
    bool bFound = false;
    IMoniker *pMoniker;
    while (!bFound && (S_OK == pEnum->Next(1, &pMoniker, 0)))
    {
        IPropertyBag *pBag = NULL;
        hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
        if (FAILED(hr))
        {
            pMoniker->Release();
            continue; // Maybe the next one will work.
        }
        // Check the friendly name.
        VARIANT var;
        VariantInit(&var);
        hr = pBag->Read(L"FriendlyName", &var, NULL);
        if (SUCCEEDED(hr) && (lstrcmpiW(var.bstrVal, szName) == 0))
        {
            // This is the right filter.
            hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter,
                (void**)ppFilter);
            bFound = true;
        }
        VariantClear(&var);
        pBag->Release();
        pMoniker->Release();
    }
    pEnum->Release();
    return (bFound ? hr : E_FAIL);
}

The following code example uses this function to create the CC Decoder filter and add it to the filter graph:

IBaseFilter *pCC = NULL;
hr = CreateKernelFilter(AM_KSCATEGORY_VBICODEC, 
    OLESTR("CC Decoder"), &pCC);
if (SUCCEEDED(hr))
{
    hr = pGraph->AddFilter(pCC, L"CC Decoder");
    pCC->Release();
}

See Also