From a0df126bcf4a0e9cf2497074e77c561dc9160703 Mon Sep 17 00:00:00 2001 From: Jeroen Saey Date: Mon, 1 Sep 2025 11:54:28 +0200 Subject: [PATCH] Fixed memory leak --- EonaCat.VolumeMixer.Tester/Program.cs | 8 + .../EonaCat.VolumeMixer.csproj | 6 +- .../Managers/VolumeMixerManager.cs | 138 ++++++++++++------ 3 files changed, 104 insertions(+), 48 deletions(-) diff --git a/EonaCat.VolumeMixer.Tester/Program.cs b/EonaCat.VolumeMixer.Tester/Program.cs index 8afeb67..5b61082 100644 --- a/EonaCat.VolumeMixer.Tester/Program.cs +++ b/EonaCat.VolumeMixer.Tester/Program.cs @@ -19,6 +19,14 @@ class Program var devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output); Console.WriteLine($"Found {devices.Count} playback devices:"); + while (true) + { + var test = await volumeMixer.GetDefaultAudioDeviceAsync(DataFlow.Output); + devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output); + devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Input); + await Task.Delay(1000); + } + foreach (var device in devices) { Console.WriteLine($"- {device.Name} (Default: {device.IsDefault})"); diff --git a/EonaCat.VolumeMixer/EonaCat.VolumeMixer.csproj b/EonaCat.VolumeMixer/EonaCat.VolumeMixer.csproj index 9298826..6180a9a 100644 --- a/EonaCat.VolumeMixer/EonaCat.VolumeMixer.csproj +++ b/EonaCat.VolumeMixer/EonaCat.VolumeMixer.csproj @@ -18,9 +18,9 @@ EonaCat, Audio, Volume, Mixer .NET Standard, Jeroen, Saey EonaCat VolumeMixer - 1.0.5 - 1.0.0.5 - 1.0.0.5 + 1.0.6 + 1.0.0.6 + 1.0.0.6 icon.png https://git.saey.me/EonaCat/EonaCat.VolumeMixer git diff --git a/EonaCat.VolumeMixer/Managers/VolumeMixerManager.cs b/EonaCat.VolumeMixer/Managers/VolumeMixerManager.cs index 7e8dadb..f51d5b2 100644 --- a/EonaCat.VolumeMixer/Managers/VolumeMixerManager.cs +++ b/EonaCat.VolumeMixer/Managers/VolumeMixerManager.cs @@ -49,9 +49,12 @@ namespace EonaCat.VolumeMixer.Managers lock (_syncLock) { + IMultiMediaDeviceCollection deviceCollection = null; + IMultiMediaDevice defaultDevice = null; + try { - var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out var deviceCollection); + var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out deviceCollection); if (result != 0 || deviceCollection == null) { return devices; @@ -60,18 +63,16 @@ namespace EonaCat.VolumeMixer.Managers result = deviceCollection.GetCount(out var count); if (result != 0) { - ComHelper.ReleaseComObject(deviceCollection); return devices; } string defaultId = ""; try { - result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out var defaultDevice); + result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out defaultDevice); if (result == 0 && defaultDevice != null) { defaultDevice.GetId(out defaultId); - ComHelper.ReleaseComObject(defaultDevice); } } catch @@ -81,9 +82,11 @@ namespace EonaCat.VolumeMixer.Managers for (uint i = 0; i < count; i++) { + IMultiMediaDevice device = null; + try { - result = deviceCollection.Item(i, out var device); + result = deviceCollection.Item(i, out device); if (result == 0 && device != null) { result = device.GetId(out var id); @@ -94,24 +97,37 @@ namespace EonaCat.VolumeMixer.Managers bool isDefault = id == defaultId; devices.Add(new AudioDevice(device, id, name, isDefault, dataFlow, type)); } - else - { - ComHelper.ReleaseComObject(device); - } } } catch { // Do nothing } + finally + { + if (device != null) + { + ComHelper.ReleaseComObject(device); + } + } } - - ComHelper.ReleaseComObject(deviceCollection); } catch { // Do nothing } + finally + { + if (deviceCollection != null) + { + ComHelper.ReleaseComObject(deviceCollection); + } + + if (defaultDevice != null) + { + ComHelper.ReleaseComObject(defaultDevice); + } + } } return devices; @@ -129,9 +145,11 @@ namespace EonaCat.VolumeMixer.Managers lock (_syncLock) { + IMultiMediaDevice device = null; + try { - var result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out var device); + var result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out device); if (result == 0 && device != null) { result = device.GetId(out var id); @@ -141,58 +159,81 @@ namespace EonaCat.VolumeMixer.Managers var type = GetDeviceType(device); return new AudioDevice(device, id, name, true, dataFlow, type); } - - ComHelper.ReleaseComObject(device); } } catch { // Do nothing } + finally + { + if (device != null) + { + ComHelper.ReleaseComObject(device); + } + } return null; } }); - } + } + + [DllImport("ole32.dll")] + private static extern int PropVariantClear(ref PropVariant pvar); + + private string GetDeviceName(IMultiMediaDevice device) + { + IPropertyStore? propertyStore = null; + PropVariant propVariant = new PropVariant(); + + try + { + var result = device.OpenPropertyStore(0, out propertyStore); + if (result == 0 && propertyStore != null) + { + var propertyKey = PKEY_Device_FriendlyName; + result = propertyStore.GetValue(ref propertyKey, out propVariant); + if (result == 0) + { + // Get string + string name = Marshal.PtrToStringUni(propVariant.data1); + return !string.IsNullOrEmpty(name) ? name : "Unknown Device"; + } + } + } + catch + { + // Do nothing + } + finally + { + // Clear memory + PropVariantClear(ref propVariant); + + if (propertyStore != null) + { + ComHelper.ReleaseComObject(propertyStore); + } + } + + return "Unknown Device"; + } - private string GetDeviceName(IMultiMediaDevice device) - { - try - { - var result = device.OpenPropertyStore(0, out var propertyStore); - if (result == 0 && propertyStore != null) - { - var propertyKey = PKEY_Device_FriendlyName; - result = propertyStore.GetValue(ref propertyKey, out var propVariant); - if (result == 0 && propVariant.data1 != IntPtr.Zero) - { - string name = Marshal.PtrToStringUni(propVariant.data1); - ComHelper.ReleaseComObject(propertyStore); - return !string.IsNullOrEmpty(name) ? name : "Unknown Device"; - } - - ComHelper.ReleaseComObject(propertyStore); - } - } - catch - { - // Do nothing - } - - return "Unknown Device"; - } private DeviceType GetDeviceType(IMultiMediaDevice device) { + IPropertyStore propertyStore = null; + PropVariant propVariant = new PropVariant(); + try { - int result = device.OpenPropertyStore(0, out var propertyStore); + int result = device.OpenPropertyStore(0, out propertyStore); if (result == 0 && propertyStore != null) { try { var propertyKey = PKEY_AudioEndpoint_FormFactor; - result = propertyStore.GetValue(ref propertyKey, out var propVariant); + result = propertyStore.GetValue(ref propertyKey, out propVariant); // 0x13 == VT_UI4 if (result == 0 && propVariant.vt == 0x13) @@ -227,7 +268,7 @@ namespace EonaCat.VolumeMixer.Managers } finally { - ComHelper.ReleaseComObject(propertyStore); + } } } @@ -235,7 +276,14 @@ namespace EonaCat.VolumeMixer.Managers { // Do nothing } - + finally + { + PropVariantClear(ref propVariant); + if (propertyStore != null) + { + ComHelper.ReleaseComObject(propertyStore); + } + } return DeviceType.Unknown; }