Skip to content

Bug: CompositorController.CommitNeeded += is broken in .Net Framework #2065

@Shan-Zhou

Description

@Shan-Zhou

Description

The event CompositorController.CommitNeeded is unusable when using embedded C#/WinRT + .Net Framework 4.7.2. An exception System.InvalidCastException: 'Specified cast is not valid.' is thrown.

Steps To Reproduce

  1. Create an empty WPF project, then modify the csproj to embed C#/WinRT (CsWinRTWindowsMetadata can be local because I just copied them from my local machine...; the include/exclude is a combination I found that can make Windows.UI.Composition work without embedding unnecessary components)
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
	<LangVersion>latest</LangVersion>
	<TargetFrameworks>net472;net8.0-windows</TargetFrameworks>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

	<ItemGroup>
		<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
		<PackageReference Include="System.Memory" Version="4.6.3" />
	</ItemGroup>

	<PropertyGroup>
		<NoWarn>$(NoWarn);CS8305</NoWarn>
		<CsWinRTMessageImportance>high</CsWinRTMessageImportance>
		<CsWinRTEmbedded>true</CsWinRTEmbedded>
		<CsWinRTWindowsMetadata>
			WinMetadata\Windows.Data.winmd
			WinMetadata\Windows.Devices.winmd
			WinMetadata\Windows.Foundation.winmd
			WinMetadata\Windows.Globalization.winmd
			WinMetadata\Windows.Graphics.winmd
			WinMetadata\Windows.Storage.winmd
			WinMetadata\Windows.System.winmd
			WinMetadata\Windows.UI.winmd
		</CsWinRTWindowsMetadata>
		<CsWinRTIncludes>
			Windows.Data.Text.TextSegment;
			Windows.Devices.Geolocation;
			Windows.Devices.Input;
			Windows.Foundation;
			Windows.Globalization.DayOfWeek;
			Windows.Graphics.DirectX;
			Windows.Graphics.Effects;
			Windows.Graphics.IGeometrySource2D;
			Windows.Graphics.PointInt32;
			Windows.Graphics.RectInt32;
			Windows.Graphics.SizeInt32;
			Windows.Storage;
			Windows.System.DispatcherQueue;
			Windows.System.IDispatcherQueue;
			Windows.System.IDispatcherQueueController;
			Windows.System.IDispatcherQueueShutdownStartingEventArgs;
			Windows.System.IUser;
			Windows.System.User;
			Windows.System.VirtualKey;
			Windows.UI;
		</CsWinRTIncludes>
		<CsWinRTExcludes>
			Windows.Devices.Input.IPenDevice;
			Windows.Devices.Input.IPenDevice2;
			Windows.Devices.Input.PenDevice;
			Windows.Devices.Input.Preview;
			Windows.Foundation.Diagnostics;
			Windows.Foundation.PropertyType;
			Windows.UI.ApplicationSettings;
			Windows.UI.Composition.Scenes;
			Windows.UI.Core.Preview;
			Windows.UI.Input.Core;
			Windows.UI.Input.Inking;
			Windows.UI.Input.IRadialController;
			Windows.UI.Input.Preview;
			Windows.UI.Input.RadialController;
			Windows.UI.Input.Spatial;
			Windows.UI.Notifications;
			Windows.UI.Shell;
			Windows.UI.StartScreen;
			Windows.UI.Text.Core;
			Windows.UI.ViewManagement;
			Windows.UI.WebUI;
			Windows.UI.WindowManagement;
			Windows.UI.Xaml;
		</CsWinRTExcludes>
	</PropertyGroup>
</Project>
  1. Create compositor controller and set up its CommitNeeded
var controller = DispatcherQueueController.CreateOnDedicatedThread();
controller.DispatcherQueue.TryEnqueue(() =>
{
    try
    {
        var controller = new Windows.UI.Composition.Core.CompositorController();
        controller.CommitNeeded += (s, e) => { s.Commit(); };
        var compositor = controller.Compositor;
        // ...
    }
    catch (Exception e) {  }
});

Expected Behavior

No exception (currently I can only use it when targeting .Net 8)

Version Info

Tested with both C#/WinRT 2.2 and 2.3.0-prerelease.250720.1
.Net SDK version is 10.0.100-rc.1.25451.107
OS: Windows 11 27954.1
winmd files are copied from my local machine

Additional Context

Call Stack

 	mscorlib.dll!System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(int errorCode)	Unknown
 	WpfApp1.exe!WinRT.IObjectReference.As<ABI.WinRT.Interop.IWeakReferenceSource.Vftbl>(System.Guid iid) Line 170	C#
 	WpfApp1.exe!WinRT.IObjectReference.As<ABI.WinRT.Interop.IWeakReferenceSource.Vftbl>() Line 166	C#
 	WpfApp1.exe!ABI.WinRT.Interop.IWeakReferenceSource.IWeakReferenceSource(WinRT.IObjectReference obj) Line 112	C#
 	[Native to Managed Transition]	
 	[Managed to Native Transition]	
 	WpfApp1.exe!ABI.WinRT.Interop.EventSourceCache.Create(WinRT.IObjectReference obj, int index, System.WeakReference<object> state) Line 77	C#
 	WpfApp1.exe!ABI.WinRT.Interop.EventSource<Windows.Foundation.TypedEventHandler<Windows.UI.Composition.Core.CompositorController, object>>.Subscribe(Windows.Foundation.TypedEventHandler<Windows.UI.Composition.Core.CompositorController, object> handler) Line 104	C#
 	WpfApp1.exe!ABI.Windows.UI.Composition.Core.ICompositorController.CommitNeeded.add(Windows.Foundation.TypedEventHandler<Windows.UI.Composition.Core.CompositorController, object> value) Line 438	C#
 	WpfApp1.exe!Windows.UI.Composition.Core.CompositorController.CommitNeeded.add(Windows.Foundation.TypedEventHandler<Windows.UI.Composition.Core.CompositorController, object> value) Line 103	C#
 	WpfApp1.exe!WpfApp1.MainWindow..ctor.AnonymousMethod__0_1() Line 28	C#
 	WpfApp1.exe!ABI.Windows.System.DispatcherQueueHandler.Do_Abi_Invoke.AnonymousMethod__26_0(Windows.System.DispatcherQueueHandler invoke) Line 1498	C#
 	WpfApp1.exe!WinRT.ComWrappersSupport.MarshalDelegateInvoke<Windows.System.DispatcherQueueHandler>(System.IntPtr thisPtr, System.Action<Windows.System.DispatcherQueueHandler> invoke) Line 72	C#
 	WpfApp1.exe!ABI.Windows.System.DispatcherQueueHandler.Do_Abi_Invoke(System.IntPtr thisPtr) Line 1496	C#

I tried to let the debugger go step by step and it seems that the issue is that the CompositorController cannot be casted (QueryInterface) to IWeakReferenceSource

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions