Skip to content
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

CsWinRT not removing WinMD references from deps.json (CoreCLR, 0x80070057) #1811

Open
AliveDevil opened this issue Oct 7, 2024 · 5 comments
Labels
bug Something isn't working

Comments

@AliveDevil
Copy link

Describe the bug
When referencing a NuGet package that includes for further CsWinRT referencing a .winmd file in net8.0-windows10.X subsequent launches of the application will fail (i.e. Projection B references Projection A, because Component B uses types from Component A).

To Reproduce
NuSpec file:

<file src="../../artifacts/bin/Component/Win32/Release/Component.winmd" target="lib/net8.0-windows10.0.17134.0" />
<file src="../../artifacts/bin/Component.Projection/Release/net8.0-windows10.0.22621.0/Component.Projection.dll" target="lib/net8.0-windows10.0.17134.0" />

Create a console application, that references this Nuget package.
The deps.json will include the .winmd files, resulting in the .NET 8 host to fail with

.\ConsoleApp1\bin\Debug\net8.0-windows10.0.22621.0\ConsoleApp1.exe
Failed to create CoreCLR, HRESULT: 0x80070057

Expected behavior
As mentioned here I expect this to seamlessly just work and not crash the CoreCLR runtime immediately.

Version Info
CsWinRT: 2.1.5

Additional context
Repro: CsWinRTNuGet.zip
Follow steps in embedded readme.md.

My workaround is to move the winmd to lib/netstandard2.0, then create a package build/net8.0-windows10.X/build.props file, that adds a reference to the netstandard2.0 winmd, which does get collected later.
This has the bad sideeffect, that Visual Studio complains about a non-existing file (the MSBuildThisFileDirectory macro doesn't resolve while a project is loaded).

<Project>
  <PropertyGroup>
    <_ComponentWinMDLibDir>$(MSBuildThisFileDirectory)../../lib/netstandard2.0/</_ComponentWinMDLibDir>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="Component">
      <HintPath>$(_ComponentWinMDLibDir)Component.winmd</HintPath>
      <IsWinMDFile>true</IsWinMDFile>
    </Reference>
  </ItemGroup>
</Project>
@AliveDevil AliveDevil added the bug Something isn't working label Oct 7, 2024
@AliveDevil
Copy link
Author

Looking at the binlog:
Target GenerateBuildDependencyFile, task GenerateDepsFile, argument CompileReferences="@(ResolvedCompileFileDefinitions)" isn't stripped from the WinMD references, thus is written to the deps.json regardless.

@dongle-the-gadget
Copy link
Contributor

You shouldn't add the WinMD into the lib\net8.0-xxx folders, as .NET will interpret that to mean you wish to include that WinMD as a reference, which isn't allowed. I think you should create a target that copies that WinMD to the output directory and add that to the build folder instead.

@AliveDevil
Copy link
Author

AliveDevil commented Oct 7, 2024

Well, the use case is:
There is one projection project, that exposes one WinRT component.

There is another WinRT component, that has a PackageReference to the first WinRT component, which is exposed by another CsWinRT projection.

This won't work, as CsWinRT doesn't find the type information for the first WinRT component in the NuGet package, because it's nowhere to be found, the guidance previously was to just include it in the lib/-folder (see linked issue).

Additionally, when including the WinRT in the lib/-folder the AppHost crashes immediately on startup, as it validates that there are no winmd-files referenced n the deps.json or side-by-side with the startup application.

This abomination of a nuspec works, but I see this as highly counter-intuitive:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>CsWinRT.ComponentA</id>
    <description>CsWinRT ComponentA Test</description>
    <version>$version$</version>
    <authors>microsoft/CsWinRT</authors>

    <dependencies>
      <group targetFramework="netstandard2.0" />
      <group targetFramework="net8.0-windows10.0.22621.0">
        <dependency id="Microsoft.Windows.CsWinRT" version="2.1.5" />
      </group>
    </dependencies>
    <references>
      <group targetFramework="net8.0-windows10.0.22621.0">
        <reference file="CsWinRT_ComponentA.winmd" />
        <reference file="CsWinRT.ComponentA.Projection.dll" />
      </group>
    </references>
  </metadata>

  <files>
    <file src="bin/$configuration$/net8.0-windows10.0.22621.0/CsWinRT.ComponentA.Projection.dll" target="lib/net8.0-windows10.0.22621.0" />
    <file src="bin/$configuration$/net8.0-windows10.0.22621.0/ref/CsWinRT.ComponentA.Projection.dll" target="ref/net8.0-windows10.0.22621.0" />

    <file src="../CsWinRT.ComponentA/bin/$configuration$/Win32/CsWinRT_ComponentA.winmd" target="lib/netstandard2.0" />
    <file src="../CsWinRT.ComponentA/bin/$configuration$/Win32/CsWinRT_ComponentA.winmd" target="ref/net8.0-windows10.0.22621.0" />

    <file src="../CsWinRT.ComponentA/bin/$configuration$/x64/CsWinRT.ComponentA.dll" target="runtimes/win-x64/native" />
    <file src="../CsWinRT.ComponentA/bin/$configuration$/Win32/CsWinRT.ComponentA.dll" target="runtimes/win-x86/native" />
    <file src="../CsWinRT.ComponentA/bin/$configuration$/ARM64/CsWinRT.ComponentA.dll" target="runtimes/win-arm64/native" />
  </files>

</package>

With the <reference>-group everything works fine, but is opposite to the previously stated way of including and referencing a WinMD file for consumption in CsWinRT.

So, to make sure, that .NET Sdk doesn't include the winmd as a runtime artifact, the winmd file must not end up in lib/, but for CsWinRT to realize there are consumable WinMD files, one has to duplicate the projection Dll into ref/, including the WinMD:

  • ref
    • net8.0-windows10
      • Component.winmd
      • Component.Projection.dll
  • lib
    • net8.0-windows10
      • Component.Projection.dll

With:

<references>
  <group targetFramework="net8.0-windows10">
    <reference file="Component.winmd" /> <!-- CsWinRT will remove this, but allow consumption when a WinMD ProjectReference uses a type from this -->
    <reference file="Component.Projection.dll" /> <!-- Make sure that C# can reference types in the Component.winmd -->
  </group>
</references>

@dongle-the-gadget
Copy link
Contributor

What I'd recommend you do is to put the WinMD somewhere else, then add the CsWinRTInputs item in an <ItemGroup> in a target.

@AliveDevil
Copy link
Author

With CsWinRTInputs there is another bad interaction with WindowsAppSdk, where target _CalculateInputsForGenerateCurrentProjectAppxManifest won't find the referenced WinMD, thus failing to successfully build the required ActivatableClass metadata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants