-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathMicroComVtblBase.cs
63 lines (56 loc) · 2.2 KB
/
MicroComVtblBase.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace MicroCom.Runtime
{
public unsafe class MicroComVtblBase
{
private List<IntPtr> _methods = new List<IntPtr>();
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int AddRefDelegate(Ccw* ccw);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int QueryInterfaceDelegate(Ccw* ccw, Guid* guid, void** ppv);
public static IntPtr Vtable { get; } = new MicroComVtblBase().CreateVTable();
public MicroComVtblBase()
{
#if NET5_0_OR_GREATER
AddMethod((delegate* unmanaged[Stdcall]<Ccw*, Guid*, void**, int>)&QueryInterface);
AddMethod((delegate* unmanaged[Stdcall]<Ccw*, int>)&AddRef);
AddMethod((delegate* unmanaged[Stdcall]<Ccw*, int>)&Release);
#else
AddMethod((QueryInterfaceDelegate)QueryInterface);
AddMethod((AddRefDelegate)AddRef);
AddMethod((AddRefDelegate)Release);
#endif
}
protected void AddMethod(Delegate d)
{
GCHandle.Alloc(d);
_methods.Add(Marshal.GetFunctionPointerForDelegate(d));
}
protected void AddMethod(void* m)
{
_methods.Add(new IntPtr(m));
}
protected unsafe IntPtr CreateVTable()
{
var ptr = (IntPtr*)Marshal.AllocHGlobal((IntPtr.Size + 1) * _methods.Count);
for (var c = 0; c < _methods.Count; c++)
ptr[c] = _methods[c];
return new IntPtr(ptr);
}
#if NET5_0_OR_GREATER
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
#endif
static int QueryInterface(Ccw* ccw, Guid* guid, void** ppv) => ccw->GetShadow().QueryInterface(ccw, guid, ppv);
#if NET5_0_OR_GREATER
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
#endif
static int AddRef(Ccw* ccw) => ccw->GetShadow().AddRef(ccw);
#if NET5_0_OR_GREATER
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
#endif
static int Release(Ccw* ccw) => ccw->GetShadow().Release(ccw);
}
}