microsoft / microsoft/CsWinRT

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

Open
#2,065 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
665
Forks
134
Avg merge
1d 3h
Merged PRs (30d)
32

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the WPF net472 case using the provided CompositorController.CommitNeeded setup, then trace EventSourceCache.Create and IWeakReferenceSource in the call stack. Compare the net472 and net8 behavior; done means subscribing to CommitNeeded no longer throws InvalidCastException under .NET Framework 4.7.2.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.