-
Notifications
You must be signed in to change notification settings - Fork 122
Description
Describe the bug
I'm noticing random crashes in my Win2D WASDK Win32 sample, which I've narrowed down to what seems to be invalid use when calling the As<I>() method from CsWinRT to retrieve the activation factory of a given WinRT type and cast it to some type.
To double check, I've tried calling RoGetActivationFactory manually to get the activation factory, which does work just fine (though I can't use it, as it's not guaranteed to work in unpackaged scenarios, as it doesn't have the fallback .dll loading paths). The issue only seems to happen when using As<I>() to cast the activation factory to some interface and then marshalling that.
Note: this is blocking Sergio0694/ComputeSharp#509.
To Reproduce
- Create a new project, use this .csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-windows10.0.22621</TargetFramework>
<Nullable>enable</Nullable>
<Platforms>x64</Platforms>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.1.0-preview1" />
</ItemGroup>
</Project>- If needed, configure the platform in the solution to use x64 as CPU architecture
- Paste this code:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.Graphics.Canvas;
using WinRT;
using WinRT.Interop;
unsafe
{
ICanvasFactoryNative.Interface canvasDeviceActivationFactory = CanvasDevice.As<ICanvasFactoryNative.Interface>();
ICanvasFactoryNative* factoryNative = (ICanvasFactoryNative*)MarshalInspectable<ICanvasFactoryNative.Interface>.FromManaged(canvasDeviceActivationFactory);
int hresult = factoryNative->RegisterWrapper(null, null);
Debug.Assert(hresult == unchecked((int)0x80070057U));
}
[Guid("695C440D-04B3-4EDD-BFD9-63E51E9F7202")]
internal unsafe struct ICanvasFactoryNative
{
public void** lpVtbl;
public int RegisterWrapper(IUnknownVftbl* resource, IInspectable.Vftbl* wrapper)
{
return ((delegate* unmanaged[Stdcall]<ICanvasFactoryNative*, IUnknownVftbl*, IInspectable.Vftbl*, int>)this.lpVtbl[7])(
(ICanvasFactoryNative*)Unsafe.AsPointer(ref this),
resource,
wrapper);
}
[Guid("695C440D-04B3-4EDD-BFD9-63E51E9F7202")]
[WindowsRuntimeType]
[WindowsRuntimeHelperType(typeof(Interface))]
public interface Interface
{
[Guid("695C440D-04B3-4EDD-BFD9-63E51E9F7202")]
public readonly struct Vftbl
{
public static readonly IntPtr AbiToProjectionVftablePtr = IUnknownVftbl.AbiToProjectionVftblPtr;
}
}
}- Run the sample
Expected behavior
The code should return E_INVALIDARG (as we're calling the method passing null as params).
Actual behavior
The method will return seemingly random HRESULTs. Debugging the code, it seems some completely unrelated method is being invoked. Sometimes this ends up invoking the destructor of the activation factory, for whatever reason. It seems like CsWinRT is marshalling the activation factory incorrect? Or is my projected interface somehow wrong? 🤔