I've been working on a C# application that interfaces with the Windows Audio APIs to check the processes used by the primary render device. However, I keep encountering an issue where the call to sessionManager.GetSessionEnumerator
always fails with an AccessViolationException
. Here's the relevant part of my code:
using System;
using System.Runtime.InteropServices;
namespace SystemAudio
{
public static class AudioChecker
{
static void Main()
{
int sessionCount;
sessionCount = CheckPrimaryRenderDeviceProcesses();
Console.WriteLine(sessionCount);
}
public static int CheckPrimaryRenderDeviceProcesses()
{
IMMDeviceEnumerator enumerator = (IMMDeviceEnumerator)new MMDeviceEnumerator();
IMMDevice device;
enumerator.GetDefaultAudioEndpoint(0, 0, out device);
string id;
device.GetId(out id);
Console.WriteLine("Primary Render Device ID: " + id);
// Activate IAudioSessionManager2 on the device (also tested with IAudioSessionManager)
Guid IID_IAudioSessionManager2 = new Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F");
int CLSCTX_ALL = 23;
device.Activate(ref IID_IAudioSessionManager2, CLSCTX_ALL, IntPtr.Zero, out object oSessionManager);
IAudioSessionManager2 sessionManager = (IAudioSessionManager2)oSessionManager;
// Attempt to get the session enumerator.
// This is ALWAYS failing with these error:
// System.AccessViolationException:
// 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
sessionManager.GetSessionEnumerator(out IAudioSessionEnumerator sessionEnumerator);
sessionEnumerator.GetCount(out int sessionCount);
return sessionCount;
}
}
}
And here are the COM interface definitions I'm using. For unused methods I was just listing the methods as defined in the vTable but without any parameters:
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
public class MMDeviceEnumerator { }
[ComImport, Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMMDeviceEnumerator
{
int EnumAudioEndpoints();
int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice endpoint);
int GetDevice();
int RegisterEndpointNotificationCallback();
int UnregisterEndpointNotificationCallback();
}
[ComImport, Guid("D666063F-1587-4E43-81F1-B948E807363F"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMMDevice
{
int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams,
[MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
int OpenPropertyStore();
int GetId([MarshalAs(UnmanagedType.LPWStr)] out string ppstrId);
int GetState();
}
[ComImport, Guid("BFA971F1-4D5E-40BB-935E-967039BFBEE4"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioSessionManager
{
int GetAudioSessionControl();
int GetSimpleAudioVolume();
}
[ComImport, Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioSessionManager2 : IAudioSessionManager
{
int GetSessionEnumerator(out IAudioSessionEnumerator sessionEnum);
int RegisterSessionNotification();
int UnregisterSessionNotification();
int RegisterDuckNotification();
int UnregisterDuckNotification();
}
[ComImport, Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioSessionEnumerator
{
int GetCount(out int count);
int GetSession();
}
[ComImport, Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioSessionControl
{
int GetState();
int GetDisplayName();
int SetDisplayName();
int GetIconPath();
int SetIconPath();
int GetGroupingParam();
int SetGroupingParam();
int RegisterAudioSessionNotification();
int UnregisterAudioSessionNotification();
}
[ComImport, Guid("bfb7ff88-7239-4fc9-8fa2-07c950be9c6d"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioSessionControl2 : IAudioSessionControl
{
new int GetState();
new int GetDisplayName();
new int SetDisplayName();
new int GetIconPath();
new int SetIconPath();
new int GetGroupingParam();
new int SetGroupingParam();
new int RegisterAudioSessionNotification();
new int UnregisterAudioSessionNotification();
int GetSessionIdentifier();
int GetSessionInstanceIdentifier();
int GetProcessId();
int IsSystemSoundsSession();
int SetDuckingPreferences();
}
Despite following the documentation and the implementation details, the call to GetSessionEnumerator
fails every time with the exception:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
I'm not sure what's causing this issue, and it's been quite a blocker for my project. Any insights or suggestions on what might be going wrong or how to troubleshoot this further would be greatly appreciated! Thank you in advance for your help.