59 lines
2.1 KiB
C#
59 lines
2.1 KiB
C#
using System;
|
|
using System.Runtime.ConstrainedExecution;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Sta;
|
|
|
|
/// <summary>
|
|
/// SafeHandle-style lifetime wrapper for an <c>LMXProxyServer</c> COM connection. Per Task B.3
|
|
/// + decision #65: <see cref="ReleaseHandle"/> must call <c>Marshal.ReleaseComObject</c> until
|
|
/// refcount = 0, then <c>UnregisterProxy</c>. The finalizer runs as a
|
|
/// <see cref="CriticalFinalizerObject"/> to honor AppDomain-unload ordering.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This scaffold accepts any RCW (tagged as <see cref="object"/>) so we can unit-test the
|
|
/// release logic with a mock. The concrete wiring to <c>ArchestrA.MxAccess.LMXProxyServer</c>
|
|
/// lands when the actual Galaxy code moves over (the part deferred to the parity gate).
|
|
/// </remarks>
|
|
public sealed class MxAccessHandle : SafeHandle
|
|
{
|
|
private object? _comObject;
|
|
private readonly Action<object>? _unregister;
|
|
|
|
public MxAccessHandle(object comObject, Action<object>? unregister = null)
|
|
: base(IntPtr.Zero, ownsHandle: true)
|
|
{
|
|
_comObject = comObject ?? throw new ArgumentNullException(nameof(comObject));
|
|
_unregister = unregister;
|
|
|
|
// The pointer value itself doesn't matter — we're wrapping an RCW, not a native handle.
|
|
SetHandle(new IntPtr(1));
|
|
}
|
|
|
|
public override bool IsInvalid => handle == IntPtr.Zero;
|
|
|
|
public object? RawComObject => _comObject;
|
|
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
if (_comObject is null) return true;
|
|
|
|
try { _unregister?.Invoke(_comObject); }
|
|
catch { /* swallow — we're in finalizer/cleanup; log elsewhere */ }
|
|
|
|
try
|
|
{
|
|
if (Marshal.IsComObject(_comObject))
|
|
{
|
|
while (Marshal.ReleaseComObject(_comObject) > 0) { /* loop until fully released */ }
|
|
}
|
|
}
|
|
catch { /* swallow */ }
|
|
|
|
_comObject = null;
|
|
SetHandle(IntPtr.Zero);
|
|
return true;
|
|
}
|
|
}
|