diff --git a/src/LibVLCSharp.Tests/LibVLCTests.cs b/src/LibVLCSharp.Tests/LibVLCTests.cs index c3acebe5e..9a56a00a5 100644 --- a/src/LibVLCSharp.Tests/LibVLCTests.cs +++ b/src/LibVLCSharp.Tests/LibVLCTests.cs @@ -119,6 +119,39 @@ public void DisposeLibVLC() Assert.That(_libVLC.DialogHandlersSet, Is.False); } + [Test] + public void DisposeLibVLCIsIdempotent() + { + const string childProcessVariable = "LIBVLCSHARP_DOUBLE_DISPOSE_CHILD"; + if (Environment.GetEnvironmentVariable(childProcessVariable) == "1") + { + var childLibVLC = new LibVLC("--no-audio", "--no-video"); + childLibVLC.Dispose(); + childLibVLC.Dispose(); + Assert.That(childLibVLC.NativeReference, Is.EqualTo(IntPtr.Zero)); + return; + } + + var startInfo = new ProcessStartInfo + { + FileName = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH") ?? "dotnet", + UseShellExecute = false + }; + startInfo.ArgumentList.Add(typeof(LibVLCTests).Assembly.Location); + startInfo.ArgumentList.Add($"--test={typeof(LibVLCTests).FullName}.{nameof(DisposeLibVLCIsIdempotent)}"); + startInfo.ArgumentList.Add("--workers=1"); + startInfo.ArgumentList.Add("--noheader"); + startInfo.Environment[childProcessVariable] = "1"; + + using (var process = Process.Start(startInfo)) + { + Assert.That(process, Is.Not.Null); + Assert.That(process.WaitForExit(60_000), Is.True, "The double-dispose child process should terminate"); + Assert.That(process.ExitCode, Is.Zero, + "Disposing LibVLC twice should not crash the process"); + } + } + [Test] public void LibVLCVersion() { diff --git a/src/LibVLCSharp/Shared/LibVLC.cs b/src/LibVLCSharp/Shared/LibVLC.cs index f3bc34957..341fbbe40 100644 --- a/src/LibVLCSharp/Shared/LibVLC.cs +++ b/src/LibVLCSharp/Shared/LibVLC.cs @@ -372,11 +372,15 @@ static string[] PatchOptions(string[] options, bool enableDebugLogs = false, boo /// protected override void Dispose(bool disposing) { + if (IsDisposed) + return; + if (disposing) { UnsetDialogHandlers(); Native.LibVLCLogUnset(NativeReference); - _gcHandle.Free(); + if (_gcHandle.IsAllocated) + _gcHandle.Free(); _exitCallback = null; _log = null; #if DESKTOP