Skip to content

Instantly share code, notes, and snippets.

@cnbluefire
Last active July 31, 2025 11:04
Show Gist options
  • Select an option

  • Save cnbluefire/304580cf8e76e81d12f609f8040d3ed6 to your computer and use it in GitHub Desktop.

Select an option

Save cnbluefire/304580cf8e76e81d12f609f8040d3ed6 to your computer and use it in GitHub Desktop.
Create CompositionPath from ID2D1Geometry
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.UI.Composition;
using WinRT;
public static class CompositionPathFactory
{
private static ref readonly Guid IID_ICompositionPathFactory
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ReadOnlySpan<byte> span = new byte[16]
{
106, 140, 30, 156, 51, 15, 81, 71, 148, 55,
235, 63, 185, 211, 171, 7
};
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(span));
}
}
private static nint pCompositionPathFactory;
public unsafe static CompositionPath Create(Compositor compositor, nint pD2D1Geometry)
{
var source = D2DGeometrySource.Create(pD2D1Geometry);
nint pCompositionPath = 0;
try
{
if (pCompositionPathFactory == 0)
{
using var factoryRef = ActivationFactory.Get("Windows.UI.Composition.CompositionPath", IID_ICompositionPathFactory);
pCompositionPathFactory = factoryRef.GetRef();
}
var hr = ((delegate* unmanaged[Stdcall]<nint, nint, nint*, int>)(*(void***)pCompositionPathFactory)[6])(pCompositionPathFactory, (nint)source, &pCompositionPath);
ExceptionHelpers.ThrowExceptionForHR(hr);
return CompositionPath.FromAbi(pCompositionPath);
}
finally
{
if (pCompositionPath != 0) Marshal.Release(pCompositionPath);
source->Release();
}
}
private unsafe struct D2DGeometrySource
{
private static readonly void** Vtbl = InitVtbl();
private static void** InitVtbl()
{
void** vtbl = (void**)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(D2DGeometrySource), sizeof(void*) * 5);
vtbl[0] = (delegate* unmanaged<D2DGeometrySource*, Guid*, void**, int>)&Impl.QueryInterface;
vtbl[1] = (delegate* unmanaged<D2DGeometrySource*, uint>)&Impl.AddRef;
vtbl[2] = (delegate* unmanaged<D2DGeometrySource*, uint>)&Impl.Release;
vtbl[3] = (delegate* unmanaged<D2DGeometrySource*, nint*, int>)&Impl.GetGeometry;
vtbl[4] = (delegate* unmanaged<D2DGeometrySource*, nint, nint*, int>)&Impl.TryGetGeometryUsingFactory;
return vtbl;
}
private void** vtbl;
private volatile uint referenceCount;
private nint pD2D1Geometry;
public static D2DGeometrySource* Create(nint pD2D1Geometry)
{
D2DGeometrySource* @this = (D2DGeometrySource*)NativeMemory.Alloc((nuint)sizeof(D2DGeometrySource));
Marshal.AddRef(pD2D1Geometry);
@this->vtbl = Vtbl;
@this->referenceCount = 1;
@this->pD2D1Geometry = pD2D1Geometry;
return @this;
}
public int Release() => Marshal.Release((nint)Unsafe.AsPointer(ref this));
private static class Impl
{
private const int S_OK = 0;
private const int E_NOINTERFACE = unchecked((int)0x80004002);
private const int E_FAIL = unchecked((int)0x80004005);
private const int E_NOTIMPL = unchecked((int)0x80004001);
public static ref readonly Guid IID_IGeometrySource2D
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ReadOnlySpan<byte> span = new byte[16]
{
2, 121, 255, 202, 12, 103, 129, 65, 166, 36,
218, 151, 114, 3, 184, 69
};
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(span));
}
}
public static ref readonly Guid IID_IGeometrySource2DInterop
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ReadOnlySpan<byte> span = new byte[16]
{
115, 175, 87, 6, 253, 83, 207, 71, 132, 255,
200, 73, 45, 42, 128, 163
};
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(span));
}
}
[UnmanagedCallersOnly]
public static int QueryInterface(D2DGeometrySource* @this, Guid* riid, void** ppvObject)
{
if (riid->Equals(WinRT.Interop.IID.IID_IUnknown) ||
riid->Equals(IID_IGeometrySource2D) ||
riid->Equals(IID_IGeometrySource2DInterop))
{
Interlocked.Increment(ref @this->referenceCount);
*ppvObject = @this;
return S_OK;
}
return E_NOINTERFACE;
}
[UnmanagedCallersOnly]
public static uint AddRef(D2DGeometrySource* @this)
{
return Interlocked.Increment(ref @this->referenceCount);
}
[UnmanagedCallersOnly]
public static uint Release(D2DGeometrySource* @this)
{
uint referenceCount = Interlocked.Decrement(ref @this->referenceCount);
if (referenceCount == 0)
{
var pD2D1Geometry = Interlocked.Exchange(ref @this->pD2D1Geometry, 0);
if (pD2D1Geometry != 0)
{
Marshal.Release(pD2D1Geometry);
}
NativeMemory.Free(@this);
}
return referenceCount;
}
[UnmanagedCallersOnly]
public static int GetGeometry(D2DGeometrySource* @this, nint* value)
{
if (@this->pD2D1Geometry == 0)
{
*value = 0;
return unchecked((int)0x80004005); // E_FAIL
}
Marshal.AddRef(@this->pD2D1Geometry);
*value = @this->pD2D1Geometry;
return S_OK;
}
[UnmanagedCallersOnly]
public static int TryGetGeometryUsingFactory(D2DGeometrySource* @this, nint factory, nint* value)
{
*value = 0;
return E_NOTIMPL;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment