Search code examples
c++winapicomdirectshowmultimedia

How to use property pages on unregistrated filter?


I use filter DS LAME for compressing audio. I loaded it from file "lame.ax" as follows:

// pPath - path to LAME "lame.ax"
HRESULT CMyFilter::CreateObjectFromPath(wchar_t *pPath, REFCLSID clsid, IUnknown **ppUnk)
{
    // load the target DLL directly
    if (!m_hLibFilter) m_hLibFilter = LoadLibrary(pPath);
    if (!m_hLibFilter)
    {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    // the entry point is an exported function
    FN_DLLGETCLASSOBJECT fn = (FN_DLLGETCLASSOBJECT)GetProcAddress(m_hLibFilter, "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;
}

further

HRESULT hr = 0;
IUnknown *ppUnk = 0;
ULONG lRef = 0;    
hr = CreateObjectFromPath(L"lame.ax", CLSID_LAMEDShowFilter, (IUnknown **)&ppUnk);
hr = ppUnk->QueryInterface(&m_pFilter);
lRef = ppUnk->Release();

It works perfectly. LAME encoding audio.

I want to show the filter settings - property page, but this code failed

bool ShowConfigWindow(HWND hParent)
{
    ISpecifyPropertyPages *pProp;
    HRESULT hr = m_pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
    if (SUCCEEDED(hr))
    {
        // Get the filter's name and IUnknown pointer.
        FILTER_INFO FilterInfo;
        hr = m_pFilter->QueryFilterInfo(&FilterInfo);
        IUnknown *pFilterUnk;
        m_pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);

        // Show the page. 
        CAUUID caGUID;
        pProp->GetPages(&caGUID);
        pProp->Release();
        HRESULT hr = OleCreatePropertyFrame(
            hParent,                   // Parent window
            0, 0,                   // Reserved
            FilterInfo.achName,     // Caption for the dialog box
            1,                      // Number of objects (just the filter)
            &pFilterUnk,            // Array of object pointers. 
            caGUID.cElems,          // Number of property pages
            caGUID.pElems,          // Array of property page CLSIDs
            0,                      // Locale identifier
            0, NULL                 // Reserved
        );

        // Clean up.
        pFilterUnk->Release();
        FilterInfo.pGraph->Release();
        CoTaskMemFree(caGUID.pElems);
    }
    return true;
}

I find https://groups.google.com/forum/#!topic/microsoft.public.win32.programmer.directx.video/jknSbMenWeM

I should call CoRegisterClassObject for each property page, but how to do it? Or what the right way?


Solution

  • OleCreatePropertyFrame takes property page class identifiers (CLSIDs) so you need to find a way to make them "visible" for the API.

    Use of CoRegisterClassObject is one of the ways to achieve the mentioned task (perhaps the easiest, another method would be reg-free COM). You need to retrieve IClassFactory pointers for property page CLSIDs the same way as you do it in the first snippet. Then instead of calling IClassFactory::CreateInstance you use the interface pointers as arguments for CoRegisterClassObject API. Make sure you do it on the same thread as the following OleCreatePropertyFrame call. CoRevokeClassObject will clean things up afterwards.