using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; namespace ScreenConnect; public abstract class DisposableComCallableWrapper : CriticalFinalizerDisposableObject { private delegate int NativeProc(IntPtr unknownPointer); private delegate void ManagedProc(IntPtr unknownPointer, int referenceCountFromNativeProc); private static Dictionary RedirectorMap = new Dictionary(); public DisposableComCallableWrapper() { foreach (IntPtr item in (from _ in GetType().GetInterfaces() where Marshal.IsTypeVisibleFromCom(_) select Marshal.GetComInterfaceForObject(this, _)).Append(Marshal.GetIUnknownForObject(this))) { TryHook(item, 2, Release)(item); } } private unsafe static NativeProc TryHook(IntPtr interfacePtr, int vtableIndex, ManagedProc managedProc) { lock (RedirectorMap) { IntPtr* ptr = (IntPtr*)((nint)(*(IntPtr*)(void*)interfacePtr) + (nint)vtableIndex * (nint)sizeof(IntPtr)); if (RedirectorMap.TryGetValue((IntPtr)ptr, out var value)) { return value.Item1; } NativeProc baseProc = (NativeProc)Marshal.GetDelegateForFunctionPointer(*ptr, typeof(NativeProc)); NativeProc nativeProc = delegate(IntPtr unknownPointer) { int num = baseProc(unknownPointer); managedProc(unknownPointer, num); return num; }; RedirectorMap.Add((IntPtr)ptr, (baseProc, nativeProc)); *ptr = Marshal.GetFunctionPointerForDelegate((Delegate)nativeProc); return baseProc; } } private static void Release(IntPtr unknownPointer, int referenceCountFromNativeProc) { if (referenceCountFromNativeProc == 0) { ((IDisposable)Marshal.GetObjectForIUnknown(unknownPointer)).DisposeQuietly(); } } }