Why CoCreateInstance returns REGDB_E_CLASSNOTREG o

2019-08-10 21:14发布

问题:

I want to use DSound Audio Render in one of my application so I load it with CoCreateInstance. Here is a little snippet:

#include <iostream>
#include <strmif.h>
#include <uuids.h>

int main()
{
    std::cout << "Start" << std::endl;

    HRESULT hr = CoInitialize(NULL);

    printf("CoInitialize = 0x%x\n", hr);

    IBaseFilter* ptr = NULL;
    hr = CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**)&ptr);

    printf("CoCreateInstance = 0x%x\n", hr);

    ptr->Release();

    CoUninitialize();

    std::cout << "End" << std::endl;

    std::cin.get();
}

The problem is, on the Windows I use to develop my application, it works well and hr is always 0x0 (S_OK) but on the Windows of my client, it gets an error 0x0x80040154 (REGDB_E_CLASSNOTREG) when CoCreateInstance is called.

It's a 32 bits application running on Windows 10 64 bits (for the dev) and on Windows Server 2016 Datacenter 64 bits (for the prod).

I check the registry and the corresponding DLL (quartz.dll) is correctly registered. Indeed, I get those results on both Windows:

PS C:\Users\pierre> Get-ChildItem -Path "Registry::HKCR\CLSID\{79376820-07D0-11CF-A24D-0020AFD79767}"


    Hive: HKCR\CLSID\{79376820-07D0-11CF-A24D-0020AFD79767}


Name                           Property
----                           --------
InprocServer32                 (default)      : C:\Windows\System32\quartz.dll
                               ThreadingModel : Both


PS C:\Users\pierre> Get-ChildItem -Path "Registry::HKCR\WOW6432Node\CLSID\{79376820-07D0-11CF-A24D-0020AFD79767}"


    Hive: HKCR\WOW6432Node\CLSID\{79376820-07D0-11CF-A24D-0020AFD79767}


Name                           Property
----                           --------
InprocServer32                 (default)      : C:\Windows\SysWOW64\quartz.dll
                               ThreadingModel : Both

PS C:\Users\pierre> dir C:\Windows\System32\quartz.dll


    Répertoire : C:\Windows\System32


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       15/09/2018     09:29        1639424 quartz.dll


PS C:\Users\pierre> dir C:\Windows\SysWOW64\quartz.dll


    Répertoire : C:\Windows\SysWOW64


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       15/09/2018     09:29        1470464 quartz.dll

I also used procmon.exe and every calls look correct.

What should I change in the configuration of my client to make it work?

回答1:

MSDN explains under "Remarks" section how this DirectShow filter is supposed to participate in DirectShow graph pipelines:

This filter acts as a wrapper for an audio device. To enumerate the audio devices available on the user's system, use the ICreateDevEnum interface with the audio renderer category (CLSID_AudioRendererCategory). For each audio device, the audio renderer category contains two filter instances. One of these corresponds to the DirectSound Renderer, and the other corresponds to the Audio Renderer (WaveOut) filter. The DirectSound instance has the friendly name "DirectSound: DeviceName," where DeviceName is the name of the device. The WaveOut instance has the friendly name DeviceName.

Note that you are not generally supposed to instaniate the filter directly using CoCreateInstance, what you are doing. There is a good reason for this: it is a wrapping object and it normally needs its initialization context whcih binds it to specific audio output device. By doing direct initialization you implicitly instructing it to use default device.

On systems without audio output devices the filter would see no devices and might issue a failure at early instantiation step, resulting in COM error. You would see the COM registration but absence of hardware and early failure would trigger a generic COM error rather than API specific.

In general, you should still prefer use of ICreateDevEnum interface (as MSDN recommends) to CoCreateInstance.