Last active
July 31, 2025 11:04
-
-
Save cnbluefire/304580cf8e76e81d12f609f8040d3ed6 to your computer and use it in GitHub Desktop.
Create CompositionPath from ID2D1Geometry
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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