2

I'm creating a "mixer" application that controls volumes of audio sessions and endpoints. My question is, does calling Release method on IMMDevice invalidate previously acquired IAudioEndpointVolume reference? In my program it looks something like this:

IMMDevice *device;
IMMDeviceEnumerator *deviceEnumerator;
IMMDeviceCollection *deviceCollection;
IAudioEndpointVolume *audioEndpoint;

... // Initializing device, deviceEnumerator and deviceCollection

// for cycle {
    ...
    deviceCollection->Item(i, &device);
    device->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&audioEndpoint);
    device->Release();  // Will this cause UB in the next line?
    audioEndpoint->GetMasterVolume(&volume);
    ...
//}

Should I use Release method like this or only after Releasing audioEndpoint?

  • 2
    [Managing Object Lifetimes Through Reference Counting](https://learn.microsoft.com/en-us/windows/win32/com/managing-object-lifetimes-through-reference-counting) – user7860670 Jan 14 '21 at 10:56
  • 1
    I recommend using Microsoft's [WIL](https://github.com/microsoft/wil/wiki/WinRT-and-COM-wrappers) to use the Winapi from C++. It has RAII handles, error code to exception conversion, and a couple other gadgets. – Quentin Jan 14 '21 at 10:59
  • The example code here releases the device after the endpoint - https://learn.microsoft.com/en-us/windows/win32/coreaudio/rendering-a-stream - TBH I'd follow reverse construction order for destruction. – Anya Shenanigans Jan 14 '21 at 11:13
  • @que That doesn't help. WIL makes it harder to violate COM rules by accident. It doesn't help determine, what those COM rules are. The question is asking about the latter. – IInspectable Jan 14 '21 at 11:24
  • 1
    @IInspectable it does not answer the question, but will still be helpful down the line, which is why I made it a comment and not an answer :) – Quentin Jan 14 '21 at 11:31
  • @que It's not at all helpful to hide implementation details, if the question is about those details. It's indeed actively harmful to hide those details. Surely, you wouldn't recommend someone asking about memory management in C to use C++ instead, to obscure the simple rules. – IInspectable Jan 14 '21 at 11:38
  • 1
    @IInspectable no, but I would advise someone using C-style resource management in C++ to use C++ resource management instead. Which is completely orthogonal to understanding how said management is implemented, so I'm not sure what your point is really. – Quentin Jan 14 '21 at 11:45
  • 1
    In theory, you can (must) call Release when you want. In practice, I've seen some (rare) badly written objects crash because internally they have some hierarchical ref issues. – Simon Mourier Jan 14 '21 at 12:39
  • Based on the [document](https://learn.microsoft.com/en-us/windows/win32/learnwin32/managing-the-lifetime-of-an-object): When you are finished using a pointer to the object, you can call `Release`. Do you mind sharing your use case or what problem are you trying to solve? – Rita Han Jan 15 '21 at 06:22
  • The documentation is ever so slightly inaccurate. Reference counts in COM are strictly per interface, not per object. Given that, the code in the question is perfectly valid, per COM rules. The following [documentation](https://learn.microsoft.com/en-us/windows/win32/com/rules-for-managing-reference-counts) is more accurate: *"From a COM client's perspective, reference counting is always done for each interface. Clients should never assume that an object uses the same counter for all interfaces."* This is not to say that all COM implementations actually follow those rules. – IInspectable Sep 02 '21 at 20:28
  • Now even if this particular implementation were to manage reference counts per object, and the same object that implements `IMMDevice` also implements `IAudioEndpointVolume`, the code is still correct. The reference count is at least 1 after executing `Next`, and at least 2 after calling `Activate`. The following call to `Release` will leave the reference count at or above 1, so everything is fine. – IInspectable Sep 02 '21 at 20:33

0 Answers0