-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a fully embedded WinRT interop option #304
Comments
How common are these scenarios? Are we referring only to app projects? Otherwise, how could a library project know whether it would ever be combined with other winrt code downstream? If a project is prepared to generate and compile the entirety of the cswinrt projection and runtime sources, could it not just as easily use il linking to eliminate the transitive winrt.runtime.dll dependency? This seems like a lot of work for a narrow speculative case. |
I expect these to be the most common case and should be the defaults for all libraries. The .NET Tool chain does not normally use IL Linking as standard practice for libraries and IL Linking currently interferes with reproducible builds. IL Linking and trimming would be done at the application level on publish. |
The greater concern is that this would make all such libraries mutually incompatible. The winrt.runtime.dll exists to provide single definitions for RCW/CCW caches, projected types, etc. A similar justification exists for the Windows SDK and WinUI interop dlls produced from cswinrt - these are effectively PIAs. The Windows/WinUI projections could be generated by each app (and the main readme.md page here allows for that as a fallback), but the consequence is conflicting definitions of projected types. |
PIA's can be, and are, embedded in .NET to avoid these issues. That has been the recommendation since .NET 4 https://docs.microsoft.com/en-us/dotnet/framework/interop/deploying-an-interop-application |
PIAs can rely in the runtime's support for Type Equivalence to avoid the type identity problem. The type equivalence algorithm does not cover all possible cases of the WinRT type system, so C#/WinRT can't rely on it without some harsh corners where support would just drop off. @AaronRobinsonMSFT would know more about the specifics of the limitations of Type Equivalence. |
Understood, and that's what we need to solve. |
PIA's have never worked for WinRT because of generic classes. As @jkoritzinsky mentioned Type Equivalence is the underlying technology that enables PIA and that is limited to COM scenarios and some small cut outs for other scenarios. Changing that feature to support WinRT would be substantial and has been discussed before - it is unlikely to happen. @Scottj1s What about the fully embedded scenario for cases where the WinRT use is entirely internal? That seems like a reasonable scenario to support, no? |
That scenario sounds like it's covered by #78, and only at app scope, yes? I.e., how can a library author be certain that theirs is the sole winrt-based module in any consuming process? The moment it's combined with any other winrt-based lib, we have the potential for compat issues. And these would be very easy to trip over - even two libs with modest, consume-only use of winrt APIs could have issues around RCW identity, etc. |
With a fix to dotnet/runtime#37492 with a corresponding fix to the WeakReference support to consume it, we should be able to come up with a design that says "if you don't use WinUI, you can have multiple isolated WinRT-based modules that work together as long as they never exchange objects" (Support for reference tracking makes the WinUI scenario significantly more difficult to safely reason about). A fix to the above issue should fix the RCW identity problem since each embedded system would be completely self-contained and neither system would have any way of knowing that there's another RCW for the same object since they never interact. |
What about custom winmd RCWs that are not part of Windows? Like user defined controls programmed in C++? We fully expect having to consume third party winmd files as well as providing custom projections for classic Windows COM. I hope that winrt.runtime.dll is "open enough" to live alongside third party projections, otherwise you are building a recipe for failure, there never can be a single source of truth for interop definitions. |
Also, what about the "triangle dependency" problem?
If referencing a WinRT control requires generating an RCW outside the runtime in (B1) and (B2) you better have some strategy for different RCWs to interop Similar problems may occur with CCWs. |
WinRT.Runtime only includes projections for type mappings, so it should be able to live alongside projections of 3rd party components since the third party components would depend on WinRT.Runtime (or be generated with an embedded runtime once one exists). For the triangle dependency problem in the non-embedded scenario: the owner of the C++ custom control library is required to produce the interop package and ship it themselves. That way there is one source of truth for the RCW definition. |
For the embedded scenario, here's a quick writeup of the proposal discussed over email: Provide a Microsoft.CsWinRT.Runtime.Embedded.Sources package that has cswinrt.exe, a copy of the WinRT.Runtime sources all marked as internal with modifications to not register the ComWrappers instance globally, and a file that includes an attribute, |
Clearing the milestone on this based on current timeline & resourcing. |
With .NET Core 3.1, I was able to use reflection to detect access to WinRT APIs and light them up if I'm running on Windows. This was great because I relied on WinRT APIs available since Windows 8.0. My thought was to build my own WinRT Projection and embed into my assembly, and throw some try/catch and OS checks around it, so I that way would detect support for those APIs and use them. However I didn't have much luck with that. So I made the following project to get access to GeoLocation APIs, and compiled it: <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="0.8.0" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup>
<CsWinRTIncludes>
Windows.Devices.Geolocation;
Windows.Foundation.Metadata.ContractVersion;
Windows.Foundation.UniversalApiContract;
Windows.Foundation.Metadata.DualApiPartition;
Windows.Foundation.Metadata.MarshalingBehavior;
Windows.Foundation.Metadata.MarshalingType;
Windows.Foundation.Metadata.Activatable;
Windows.Foundation.Metadata.Static;
Windows.Foundation.Metadata.Threading;
Windows.Foundation.Metadata.ThreadingModel;
Windows.Foundation.Metadata.Muse;
Windows.Foundation.Metadata.ExclusiveTo;
Windows.Foundation.Metadata.ApiContract;
Windows.Foundation.Metadata.AttributeName;
Windows.Foundation.Metadata.AllowMultiple;
Windows.Foundation.IAsyncOperation;
Windows.Foundation.TypedEventHandler;
Windows.Foundation.UniversalApiContract;
Windows.Foundation.FoundationContract;
Windows.Foundation.IAsyncInfo;
Windows.Foundation.IAsyncAction;
Windows.Foundation.AsyncStatus;
Windows.Foundation.AsyncActionCompletedHandler;
Windows.Foundation.AsyncActionProgressHandler;
Windows.Foundation.AsyncActionWithProgressCompletedHandler;
Windows.Foundation.AsyncOperationProgressHandler;
Windows.Foundation.AsyncOperationCompletedHandler;
Windows.Foundation.AsyncOperationWithProgressCompletedHandler;
</CsWinRTIncludes>
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
<CsWinRTWindowsMetadata>sdk</CsWinRTWindowsMetadata>
<CsWinRTGenerateProjection>true</CsWinRTGenerateProjection>
</PropertyGroup>
</Project> However, because it generates public classes, but the
My main problem in the first place is that it generates public classes. I want them all to be internal, as I don't actually want to expose these methods, (doesn't seem like the source generator has that option) but just use them internally in a light-up way. There's just no reason to embed WinRT types and expose them in your class library - if you needed that in your app, just target the TFM that include WinRT APIs. I then took the generated code from the obj folder and embedded them in a class library, and changed all public classes to internal. Now things actually do compile, but sadly I'm getting bad crashes at runtime, and in addition I'm forced to deploy a WinRT dependency as well ( WinRT.ComWrappersSupport.RegisterProjectionAssembly(typeof(Program).Assembly);
Geolocator g = new Geolocator(); //OK
g.DesiredAccuracy = PositionAccuracy.Default; // BOOM! |
I have the use case of "the usage of the WinRT API is entirely internal to the library". I abstract the Bluetooth LE Stack (I have four implementations in the project) and WinRT is one of the implementations. Currently the TFM |
Embedded support is now available with C#/WinRT v1.4.1! These docs and samples provide more details on how to use the support. |
There are scenarios where the developer would like to use a WinRT API without polluting/altering their dependencies. This could potentially be limited to cases where the usage of the WinRT API is entirely internal to the library.
It would be nice if the CsWinRT tool could provide a comprehensive WinRT interop scenario, that is internal to the assembly, in the form of just source code - no
WinRT.Runtime.dll
dependency./cc @jkotas @richlander @clairernovotny
The text was updated successfully, but these errors were encountered: