mirror of
https://gitee.com/csharpui/CPF.git
synced 2025-04-05 17:37:51 +08:00
114 lines
3.1 KiB
C#
114 lines
3.1 KiB
C#
![]() |
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Runtime.ConstrainedExecution;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
using System.Text;
|
|||
|
using System.Threading;
|
|||
|
|
|||
|
namespace CPF.Windows.MicroCom
|
|||
|
{
|
|||
|
public unsafe class MicroComProxyBase : CriticalFinalizerObject, IUnknown
|
|||
|
{
|
|||
|
private IntPtr _nativePointer;
|
|||
|
private bool _ownsHandle;
|
|||
|
private SynchronizationContext _synchronizationContext;
|
|||
|
|
|||
|
public IntPtr NativePointer
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (_nativePointer == IntPtr.Zero)
|
|||
|
throw new ObjectDisposedException(this.GetType().FullName);
|
|||
|
return _nativePointer;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void*** PPV => (void***)NativePointer;
|
|||
|
|
|||
|
public MicroComProxyBase(IntPtr nativePointer, bool ownsHandle)
|
|||
|
{
|
|||
|
_nativePointer = nativePointer;
|
|||
|
_ownsHandle = ownsHandle;
|
|||
|
_synchronizationContext = SynchronizationContext.Current;
|
|||
|
if (!_ownsHandle)
|
|||
|
GC.SuppressFinalize(this);
|
|||
|
}
|
|||
|
|
|||
|
protected virtual int VTableSize => 3;
|
|||
|
|
|||
|
public void AddRef()
|
|||
|
{
|
|||
|
LocalInterop.CalliStdCallvoid(PPV, (*PPV)[1]);
|
|||
|
}
|
|||
|
|
|||
|
public void Release()
|
|||
|
{
|
|||
|
LocalInterop.CalliStdCallvoid(PPV, (*PPV)[2]);
|
|||
|
}
|
|||
|
|
|||
|
public int QueryInterface(Guid guid, out IntPtr ppv)
|
|||
|
{
|
|||
|
IntPtr r = default;
|
|||
|
var rv = LocalInterop.CalliStdCallint(PPV, &guid, &r, (*PPV)[0]);
|
|||
|
ppv = r;
|
|||
|
return rv;
|
|||
|
}
|
|||
|
|
|||
|
public T QueryInterface<T>() where T : IUnknown
|
|||
|
{
|
|||
|
var guid = MicroComRuntime.GetGuidFor(typeof(T));
|
|||
|
var rv = QueryInterface(guid, out var ppv);
|
|||
|
if (rv == 0)
|
|||
|
return (T)MicroComRuntime.CreateProxyFor(typeof(T), ppv, true);
|
|||
|
throw new COMException("QueryInterface failed", rv);
|
|||
|
}
|
|||
|
|
|||
|
public bool IsDisposed => _nativePointer == IntPtr.Zero;
|
|||
|
|
|||
|
protected virtual void Dispose(bool disposing)
|
|||
|
{
|
|||
|
if (_nativePointer == null)
|
|||
|
return;
|
|||
|
if (_ownsHandle)
|
|||
|
{
|
|||
|
Release();
|
|||
|
_ownsHandle = false;
|
|||
|
}
|
|||
|
_nativePointer = IntPtr.Zero;
|
|||
|
GC.SuppressFinalize(this);
|
|||
|
}
|
|||
|
|
|||
|
public void Dispose() => Dispose(true);
|
|||
|
|
|||
|
public bool OwnsHandle => _ownsHandle;
|
|||
|
|
|||
|
public void EnsureOwned()
|
|||
|
{
|
|||
|
if (!_ownsHandle)
|
|||
|
{
|
|||
|
GC.ReRegisterForFinalize(true);
|
|||
|
AddRef();
|
|||
|
_ownsHandle = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static readonly SendOrPostCallback _disposeDelegate = DisposeOnContext;
|
|||
|
|
|||
|
private static void DisposeOnContext(object state)
|
|||
|
{
|
|||
|
(state as MicroComProxyBase)?.Dispose(false);
|
|||
|
}
|
|||
|
|
|||
|
~MicroComProxyBase()
|
|||
|
{
|
|||
|
if (!_ownsHandle)
|
|||
|
return;
|
|||
|
if (_synchronizationContext == null)
|
|||
|
Dispose();
|
|||
|
else
|
|||
|
_synchronizationContext.Post(_disposeDelegate, this);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|