1

With C++/WinRT the AudioGraphSettings can be easily initialized with its constructor:

AudioGraphSettings settings(AudioRenderCategory::Media);

I'm having trouble to use it inside my WRL project. Below is my implementation

ComPtr<IAudioGraphSettings> settings;
Windows::Foundation::GetActivationFactory(
    HStringReference(RuntimeClass_Windows_Media_Audio_AudioGraphSettings).Get(),
    &settings
);

The settings still null and I don't know how to initialize it with the required AudioRenderCategory constructor.

If I do it like below, I got access violation crash because it's still null.

settings->put_AudioRenderCategory(AudioRenderCategory::AudioRenderCategory_Media);
IInspectable
  • 46,945
  • 8
  • 85
  • 181
gameon67
  • 3,981
  • 5
  • 35
  • 61
  • 1
    `GetActivationFactory` produces an object that implements the `IAudioGraphSettingsFactory` interface. The function also returns an `HRESULT`, so that is an easy way to understand what went wrong. But you're ignoring it. – IInspectable Mar 10 '22 at 15:07
  • @IInspectable right, using `IAudioGraphSettingsFactory` solves the problem – gameon67 Mar 10 '22 at 15:20
  • @IInspectable Please convert your comment into an answer because it solved the issue. – Roy Li - MSFT Mar 11 '22 at 01:08
  • @roy That's true. Please review my proposed answer and provide feedback on anything that could be improved. – IInspectable Mar 11 '22 at 12:58

1 Answers1

1

Type activation at the ABI level is more involved than, for example, instantiating types in C++. The admittedly terse documentation outlines the different mechanisms:

WinRT defines three activation mechanisms: direct activation (with no constructor parameters), factory activation (with one or more constructor parameters), and composition activation.

The IAudioGraphSettings type falls into the second category: It instantiates a type based on a single argument of type AudioRenderCategory. Instantiating a type is thus a two-phase process:

  1. Retrieve an activation factory
  2. Use the activation factory to instantiate a type

The code in the question conflates both operations, and the call to GetActivationFactory returns an HRESULT value of 0x80004002, i.e. E_NOINTERFACE. It needs to request the IAudioGraphSettingsFactory interface instead, and subsequently use that factory to instantiate the IAudioGraphSettings type.

The following is a complete implementation that illustrates how to activate an IAudioGraphSettings type:

#include <wrl/wrappers/corewrappers.h>
#include <wrl/client.h>

#include <windows.foundation.h>
#include <windows.media.audio.h>
#include <windows.media.render.h>

#pragma comment(lib, "windowsapp")

using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Media::Audio;
using namespace ABI::Windows::Media::Render;

int main()
{
    RoInitializeWrapper init { RO_INIT_MULTITHREADED };
    HRESULT hr { init };
    if (FAILED(hr))
        return hr;

    // Retrieve activation factory
     ComPtr<IAudioGraphSettingsFactory> settings_factory {};
     hr = GetActivationFactory(
         HStringReference(RuntimeClass_Windows_Media_Audio_AudioGraphSettings).Get(),
         &settings_factory);
     if (FAILED(hr))
         return hr;

     // Use activation factory to instantiate type
     ComPtr<IAudioGraphSettings> settings {};
     hr = settings_factory->Create(AudioRenderCategory_Media, &settings);
     if (FAILED(hr))
         return hr;

    return hr;
}

This is how things look at the ABI level, which is ultimately where the WRL lives. C++/WinRT takes care of all the boilerplate code, and neatly maps parameterized factory activation onto C++ constructor implementations. That's why the C++/WinRT implementation is so much more compact.

IInspectable
  • 46,945
  • 8
  • 85
  • 181