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

Embedded nuget work and sample #1011

Merged
merged 48 commits into from
Nov 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
dd54404
embed winrt.runtime
j0shuams Oct 4, 2021
490c33c
merge master
j0shuams Oct 4, 2021
bf8659b
cswinrt
j0shuams Oct 4, 2021
87b2f56
cut
j0shuams Oct 4, 2021
b45018b
nuget, sample
j0shuams Oct 4, 2021
d1e4695
update
j0shuams Oct 5, 2021
4fdfdbb
class
j0shuams Oct 5, 2021
59c64e4
automate
j0shuams Oct 5, 2021
1c79323
test
j0shuams Oct 5, 2021
d2f3a4f
net2
j0shuams Oct 6, 2021
633e3fd
doc
j0shuams Oct 6, 2021
df5d9be
doc
j0shuams Oct 6, 2021
6ffcb4e
feedback
j0shuams Oct 7, 2021
29b4340
feedback
j0shuams Oct 12, 2021
2db8218
cut
j0shuams Oct 12, 2021
023bfb7
internal
j0shuams Oct 12, 2021
eaaad54
Merge branch 'master' into jlarkin/embed-1
j0shuams Oct 12, 2021
ec08dc5
options for embedding
j0shuams Oct 15, 2021
7622d68
Merge branch 'master' into jlarkin/embed-1
j0shuams Oct 21, 2021
b2b33ca
conflict
j0shuams Oct 22, 2021
bdf9c31
Merge branch 'master' into jlarkin/embed-2
j0shuams Oct 22, 2021
ef7eac7
static class
j0shuams Oct 22, 2021
8832c76
Merge branch 'master' into jlarkin/embed-3
j0shuams Oct 22, 2021
1ad8ab8
netcoreapp3.1
j0shuams Oct 22, 2021
4ea5cac
Merge branch 'jlarkin/embed-3' of https://github.com/microsoft/CsWinR…
j0shuams Oct 22, 2021
22257ab
Merge branch 'master' into jlarkin/embed-1
j0shuams Oct 28, 2021
cc7874e
Merge branch 'jlarkin/embed-1' into jlarkin/embed-2
j0shuams Oct 28, 2021
01ee662
+
j0shuams Oct 28, 2021
8ecdfe9
Merge branch 'master' into jlarkin/embed-1
j0shuams Oct 28, 2021
5fd8345
Merge branch 'jlarkin/embed-1' into jlarkin/embed-2
j0shuams Oct 28, 2021
f5c319e
Merge branch 'jlarkin/embed-2' into jlarkin/embed-3
j0shuams Oct 28, 2021
ea0a2c7
Merge branch 'master' into jlarkin/embed-3
j0shuams Oct 29, 2021
1a78573
Merge branch 'master' into jlarkin/embed-3
j0shuams Oct 29, 2021
6d4a3b7
updates
j0shuams Nov 1, 2021
cd8513e
feedback
j0shuams Nov 1, 2021
c41e840
Merge branch 'master' into jlarkin/embed-3
j0shuams Nov 1, 2021
5dd187f
quote
j0shuams Nov 1, 2021
aca8606
Merge branch 'master' into jlarkin/embed-3
j0shuams Nov 2, 2021
0916d48
tweak
j0shuams Nov 3, 2021
6d08556
space
j0shuams Nov 4, 2021
bc2155d
nuspec
j0shuams Nov 6, 2021
8a65cf5
feedback
j0shuams Nov 6, 2021
b6e3c2d
Update docs/embedded.md
j0shuams Nov 9, 2021
c15ab7e
Merge branch 'master' into jlarkin/embed-3
j0shuams Nov 12, 2021
69dd428
sample clean
j0shuams Nov 12, 2021
f27d786
BeforeTargets
j0shuams Nov 12, 2021
d1ec46b
cut
j0shuams Nov 12, 2021
ede8e90
Merge branch 'master' into jlarkin/embed-3
j0shuams Nov 12, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions docs/embedded.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Embedded C#/WinRT Support

## Overview

**Note**: Embedded support is currently **in preview**.

Embedded support is a C#/WinRT feature that allows you to compile the c# projection for the component, within the library/app itself.
j0shuams marked this conversation as resolved.
Show resolved Hide resolved

This is done by setting the build property `CsWinRTEmbedded` to `true` in the app or library's project file.

Enabling embedded support compiles the sources for WinRT.Runtime with the project.
For any types from the component which you want to embed in your project, they must be specified using `CsWinRTIncludes`.
The specified types will be projected and embedded into the project's *.dll*.
This means projects using embedded support no longer have a dependency on a projection for the component, `WinRT.Runtime.dll` or `Microsoft.Windows.SDK.NET.dll` in the case of the Windows SDK projection.

For an example, you can look at the [sample](https://github.com/microsoft/CsWinRT/tree/master/src/Samples/TestEmbedded).

Embedded support introduces new features to the C#/WinRT toolchain:
j0shuams marked this conversation as resolved.
Show resolved Hide resolved
* Decreased component/app size: The developer only needs to include the minimum necessary parts of the Windows SDK required by their component or app, reducing the size of the output .dll significantly.
* Downlevel support: App developers on .NET 5+ can target Windows 7 (`net5.0-windows`) and light-up on Windows 10
(and Windows 11) when consuming an embedded .NET 5+ library.
* Removes the need for multi-targeting: Library authors can support all .NET Standard 2.0 app consumers, including .NET 5+, without the need for multi-targeting. App consumers are able to target any .NET Standard 2.0 compatible TFM (e.g. `netcoreapp3.1`, `net48`, and `net5.0-windows`).
j0shuams marked this conversation as resolved.
Show resolved Hide resolved

It is important to remember that embedded support constrains the scope of Windows Runtime types to your binary.

## Scenarios

j0shuams marked this conversation as resolved.
Show resolved Hide resolved
This feature allows C# apps and libraries to target `net5.0` (and above), .NET Framework 4.6.1+, `netcoreapp3.1`, and `netstandard2.0` while also using the Windows SDK.
Moreover, a library can target `netstandard2.0` and be able to run on NetFX, Net Core and Net 5.
j0shuams marked this conversation as resolved.
Show resolved Hide resolved

Note: the `netstandard2.0` generated projection is not optimized for .NET 5 and won't be as performant.

## Usage

Using embedded support allows you to target non-Windows specific TFMs and older versions of .NET.
You will need to set a few properties:
* `CsWinRTEmbedded` - must be set to `true` to include the sources
* `CsWinRTIncludes` - Specify the types to be projected; error `CS0246` will highlight any missing namespaces
* `CsWinRTWindowsMetadata` - must be set to the Windows SDK release to use for Windows APIs
* `LangVersion` - must be set to `9` because the CsWinRT generated sources use C# 9

j0shuams marked this conversation as resolved.
Show resolved Hide resolved
Targeting `netstandard2.0` requires adding the following two package references:

```xml
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Runtime.Extensions" Version="4.3.1" />
```

Here is an example project file for a library cross-targeting and embedding a C#/WinRT generated projection.

```csproj
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0-windows;net5.0-windows;netstandard2.0</TargetFrameworks>
<Platforms>x64;x86</Platforms>
</PropertyGroup>

<PropertyGroup>
<LangVersion>9</LangVersion>
<CsWinRTEmbedded>true</CsWinRTEmbedded>
<CsWinRTWindowsMetadata>10.0.19041.0</CsWinRTWindowsMetadata>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="$(CsWinRTVersion)" />
</ItemGroup>

<ItemGroup>
j0shuams marked this conversation as resolved.
Show resolved Hide resolved
<ProjectReference Include="..\path\CppwinrtComponent\CppwinrtComponent.vcxproj" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Runtime.Extensions" Version="4.3.1" />
</ItemGroup>

<PropertyGroup>
<CsWinRTIncludes>
CppwinrtComponent;
Windows.Devices.Geolocation;
Windows.Foundation;
</CsWinRTIncludes>
</PropertyGroup>

</Project>
```

You will need to enable Windows Desktop Compatible for all your referenced C++/WinRT components -- either via the properties or in the `.vcxproj` file.

If you try to use an embedded projection of a native (C++/WinRT) component, via ProjectReference, then you may encounter a runtime error `CLASS_NOT_REGISTERED`.
You can fix this by unloading the native component project in Visual Studio, and adding the following:

```vcxproj
<PropertyGroup Label="Configuration">
<DesktopCompatible>true</DesktopCompatible>
</PropertyGroup>
```

Alternatively, you can right-click the C++ project in Visual Studio, select Properties > General > Project Defaults,
and set Windows Desktop Compatible to Yes for all configurations/platforms.

If you find any other issues using embedded support, please [file an issue]()!
75 changes: 75 additions & 0 deletions nuget/Microsoft.Windows.CsWinRT.Embedded.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!--
***********************************************************************************************
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup>

<!-- Activate the internal version of the runtime layer -->
<DefineConstants>$(DefineConstants);EMBED</DefineConstants>
<!-- Path to runtime sources, must update if their location changes in the .nuspec -->
<CsWinRTEmbeddedTFMNet5OrGreater Condition="$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)')) >= 5">true</CsWinRTEmbeddedTFMNet5OrGreater>
</PropertyGroup>

<ItemGroup>
<CsWinRTEmbeddedSourcesAny Include="$(CsWinRTPath)embedded\any\*.cs"/>
<CsWinRTEmbeddedSourcesNet5 Include="$(CsWinRTPath)embedded\net5.0\*.cs"/>
<CsWinRTEmbeddedSourcesNet2 Include="$(CsWinRTPath)embedded\netstandard2.0\*.cs"/>
</ItemGroup>

<!-- Copy sources that are for any framework -->
<Target Name="CsWinRTAddEmbeddedRuntime_AnySources"
AfterTargets="CsWinRTGenerateProjection"
BeforeTargets="CsWinRTIncludeProjection">

<Copy SourceFiles="@(CsWinRTEmbeddedSourcesAny)"
DestinationFolder="$(CsWinRTGeneratedFilesDir)"
UseHardlinksIfPossible="false"
SkipUnchangedFiles="true"/>

</Target>

<!-- Copy netstandard2.0 sources -->
<Target Name="CsWinRTAddEmbeddedRuntime_Net2Sources"
Condition="'$(CsWinRTEmbeddedTFMNet5OrGreater)' != 'true'"
AfterTargets="CsWinRTGenerateProjection"
BeforeTargets="CsWinRTIncludeProjection">

<Copy SourceFiles="@(CsWinRTEmbeddedSourcesNet2)"
DestinationFolder="$(CsWinRTGeneratedFilesDir)"
UseHardlinksIfPossible="false"
SkipUnchangedFiles="true"/>

</Target>

<!-- Copy net5.0 sources -->
<Target Name="CsWinRTAddEmbeddedRuntime_Net5Sources"
Condition="'$(CsWinRTEmbeddedTFMNet5OrGreater)' == 'true'"
AfterTargets="CsWinRTGenerateProjection"
BeforeTargets="CsWinRTIncludeProjection">

<Copy SourceFiles="@(CsWinRTEmbeddedSourcesNet5)"
DestinationFolder="$(CsWinRTGeneratedFilesDir)"
UseHardlinksIfPossible="false"
SkipUnchangedFiles="true"/>

</Target>


<!-- Prevent collisions of WinRT.Runtime types -->
<Target Name="RemoveWinRTRuntimeReference"
Inputs="@(RuntimeCopyLocalItems)"
AfterTargets="ResolvePackageAssets"
Outputs="@(RuntimeCopyLocalItems)">

<ItemGroup>
<Reference Remove="WinRT.Runtime" />
<RuntimeCopyLocalItems Remove="@(RuntimeCopyLocalItems)" Condition="'%(DestinationSubPath)' == 'WinRT.Runtime.dll'"/>
<ResolvedCompileFileDefinitions Remove="@(ResolvedCompileFileDefinitions)" Condition="'%(HintPath)' == '$(CsWinRTPath)lib\net5.0\WinRT.Runtime.dll'"/>
</ItemGroup>

</Target>

</Project>
16 changes: 16 additions & 0 deletions nuget/Microsoft.Windows.CsWinRT.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<file src="Microsoft.Windows.CsWinRT.props" target="build"/>
<file src="Microsoft.Windows.CsWinRT.targets" target="build"/>
<file src="Microsoft.Windows.CsWinRT.Authoring.targets" target="build"/>
<file src="Microsoft.Windows.CsWinRT.Embedded.targets" target="build"/>
<file src="Microsoft.Windows.CsWinRT.IIDOptimizer.targets" target="build"/>
<file src="Microsoft.Windows.CsWinRT.Prerelease*.targets" target="build"/>
<file src="Microsoft.Windows.CsWinRT.Authoring.Transitive.targets" target="build"/>
Expand All @@ -36,6 +37,21 @@
<file src="$winrt_host_arm$" target ="runtimes\win-arm\native"/>
<file src="$winrt_host_arm64$" target ="runtimes\win-arm64\native"/>
<file src="$winrt_shim$" target ="lib\net5.0\"/>

<!-- Add the WinRT.Runtime sources to the pkg for embedded scenarios -->

<file src="..\src\WinRT.Runtime\*.cs" exclude="..\src\WinRT.Runtime\*.net*.cs" target="embedded\any\" />
<file src="..\src\WinRT.Runtime\*net5*.cs" target="embedded\net5.0\" />
<file src="..\src\WinRT.Runtime\*netstandard2.0*.cs" target="embedded\netstandard2.0\" />

<file src="..\src\WinRT.Runtime\Interop\*.cs" exclude="..\src\WinRT.Runtime\Interop\*.net*.cs" target="embedded\any\" />
<file src="..\src\WinRT.Runtime\Interop\*net5*.cs" target="embedded\net5.0\" />
<file src="..\src\WinRT.Runtime\Interop\*netstandard2.0*.cs" target="embedded\netstandard2.0\" />

<file src="..\src\WinRT.Runtime\Projections\*.cs" exclude="..\src\WinRT.Runtime\Projections\*.net*.cs" target="embedded\any\" />
<file src="..\src\WinRT.Runtime\Projections\*net5*.cs" target="embedded\net5.0\" />
<file src="..\src\WinRT.Runtime\Projections\*netstandard2.0*.cs" target="embedded\netstandard2.0\" />

<file src="$guid_patch$" target ="build\tools\IIDOptimizer"/>
</files>
</package>
10 changes: 8 additions & 2 deletions nuget/Microsoft.Windows.CsWinRT.targets
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<TrackFileAccess Condition="'$(CsWinRTComponent)' != 'true'">false</TrackFileAccess>
</PropertyGroup>

<Import Project="$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Embedded.targets" Condition="'$(CsWinRTEmbedded)' == 'true'"/>

<!-- Remove WinRT.Host.dll and WinRT.Host.Shim.dll references -->
<Target Name="CsWinRTRemoveHostingDllReferences" AfterTargets="ResolvePackageAssets" BeforeTargets="ResolveLockFileAnalyzers" Outputs="@(Reference)">
<PropertyGroup>
Expand Down Expand Up @@ -99,14 +101,18 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-input $(CsWinRTInteropMetadata)
-include WinRT.Interop
</CsWinRTIncludeWinRTInterop>
<CsWinRTEmbeddedParam Condition="'$(CsWinRTEmbedded)' == 'true'">-embedded</CsWinRTEmbeddedParam>
<CsWinRTExeTFM Condition="$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)')) >= 5">$(TargetFramework)</CsWinRTExeTFM>
<CsWinRTExeTFM Condition="'$(CsWinRTExeTFM)' == ''">netstandard2.0</CsWinRTExeTFM>
<CsWinRTParams Condition="'$(CsWinRTParams)' == ''">
$(CsWinRTCommandVerbosity)
-target $(TargetFramework)
-target $(CsWinRTExeTFM)
$(CsWinRTWindowsMetadataInput)
-input @(CsWinRTInputs->'"%(FullPath)"', ' ')
-output "$(CsWinRTGeneratedFilesDir.TrimEnd('\'))"
$(CsWinRTFilters)
$(CsWinRTIncludeWinRTInterop)
$(CsWinRTEmbeddedParam)
</CsWinRTParams>
</PropertyGroup>
<MakeDir Directories="$(CsWinRTGeneratedFilesDir)" />
Expand All @@ -131,7 +137,7 @@ $(CsWinRTIncludeWinRTInterop)
<Compile Include="$(CsWinRTGeneratedFilesDir)*.cs" Exclude="@(Compile)" />
</ItemGroup>
</Target>

<Import Project="$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Prerelease.targets" Condition="Exists('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Prerelease.targets')"/>
<Import Project="$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Authoring.targets" Condition="'$(CsWinRTComponent)' == 'true'"/>
<Import Project="$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.IIDOptimizer.targets" Condition="'$(CsWinRTIIDOptimizerOptOut)' != 'true'"/>
Expand Down
7 changes: 7 additions & 0 deletions src/Samples/TestEmbedded/C++ Components/Alpha/Alpha.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "pch.h"
#include "Alpha.h"
#include "Class.g.cpp"

namespace winrt::Alpha::implementation
{
}
3 changes: 3 additions & 0 deletions src/Samples/TestEmbedded/C++ Components/Alpha/Alpha.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
EXPORTS
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
18 changes: 18 additions & 0 deletions src/Samples/TestEmbedded/C++ Components/Alpha/Alpha.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include "Class.g.h"

namespace winrt::Alpha::implementation
{
struct Class : ClassT<Class>
{
Class() = default;
};
}

namespace winrt::Alpha::factory_implementation
{
struct Class : ClassT<Class, implementation::Class>
{
};
}
13 changes: 13 additions & 0 deletions src/Samples/TestEmbedded/C++ Components/Alpha/Alpha.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Alpha
{
[default_interface]
runtimeclass Class
{
Class();
}

interface IAlpha
{
Int32 Five();
}
}
Loading