Skip to content

Commit 7ff08a8

Browse files
authored
Project reference support (preview) (#728)
* add updated targets, move authoring targets to their own file
1 parent 213d9f4 commit 7ff08a8

File tree

5 files changed

+147
-129
lines changed

5 files changed

+147
-129
lines changed

docs/authoring.md

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
**Note: Authoring Support is still in preview**
66

77
C#/WinRT provides support for authoring Windows Runtime components. You can write a library in C#, and specify that it is a `CsWinRTComponent` for C#/WinRT to produce a WinMD that any WinRT compatible language can use. For example, a library written in C# can be used by a C++ program, via C#/WinRT and C++/WinRT.
8+
Managed apps only need a project or package reference to the authored component, and native apps will need some extra steps that we cover in this documentation.
89

910
## References
1011
Here are some resources that demonstrate authoring C#/WinRT components and the details discussed in this document.
@@ -36,23 +37,57 @@ The library you are authoring should specify the following properties in its pro
3637
```
3738
And don't forget to include a `PackageReference` to `Microsoft.Windows.CsWinRT`!
3839

39-
## Generate a NuGet package for the component
40-
To generate a NuGet package for the component, you can simply right click on the project and select **Pack**. Alternatively, you can add the following property to the library project file to automatically generate a NuGet package on build.
40+
## Using an Authored Component in a Native App
4141

42-
``` csproj
42+
You'll need to author some files to assist the hosting process of a consuming native app: `YourNativeApp.exe.manifest` and `WinRT.Host.runtimeconfig.json`.
43+
If your app is packaged with MSIX, then you don't need to include the manifest file, otherwise you need to include your activatable class registrations in the manifest file.
44+
45+
To add these files, **in Visual Studio**, right click on the project node on the "Solution Explorer" window, click "Add", then "New Item".
46+
Search for the "Text File" template and name your file `YourNativeApp.exe.manifest`.
47+
Repeat this for the `WinRT.Host.runtimeconfig.json` file.
48+
For each item, right-click on it in the "Solution Explorer" window of Visual Studio; then select "Properties" and change the "Content" property to "Yes" using the drop-down arrow on the right -- this ensures it will be added to the output directory of your solution.
49+
50+
We have some [hosting docs](https://github.com/microsoft/CsWinRT/blob/master/docs/hosting.md) as well, that provide more information on these files.
51+
52+
For consuming by "PackageReference", this is all that is required. C++ apps will need to use [C++/WinRT](https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/intro-to-using-cpp-with-winrt) to consume the authored component. So make sure you have C++/WinRT installed, and have added `#include <winrt/MyAuthoredComponent.h>` to the file `pch.h` of the native app.
53+
54+
## Native Consumption by Project Reference
55+
56+
If you choose to consume your component through a project reference in a native app, then some modifications to the native app's `.vcxproj` file are needed.
57+
Because dotnet will assume a `TargetFramework` for your app that conflicts with `net5`, we need to specify the `TargetFramwork`, `TargetFrameworkVersion` and `TargetRuntime`.
58+
Examples of this are seen in the code snippet below. This is needed for this preview version, as we continue working on proper support.
59+
60+
You will need to add a reference to both the C#/WinRT component project, and the WinMD produced for the component.
61+
The WinMD can be found in the output directory of the authored component's project. References are added by right-clicking on the project node you want to add a reference to, clicking "Add" then clicking "Reference" and browsing to the files.
62+
63+
Here are the additions made to the native app's project file:
64+
``` vcxproj
65+
<!-- Note: this property group is only required if you are using a project reference,
66+
and is a part of the preview while we work on proper support -->
4367
<PropertyGroup>
44-
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
68+
<TargetFrameworkVersion>net5.0</TargetFrameworkVersion>
69+
<TargetFramework>native</TargetFramework>
70+
<TargetRuntime>Native</TargetRuntime>
4571
</PropertyGroup>
4672
```
4773

48-
**If you are going to write your own nuspec, i.e. not rely on automatic packaging** then the CsWinRT target that adds the hosting dlls to your package will not run, and you should make sure your nuspec contains the following ```file``` entries for ```MyAuthoredComponent``` (note: your TargetFramework may vary).
74+
Project references for managed apps only need the reference to the authored component's project file.
75+
76+
## Packaging
77+
To generate a NuGet package for the component, you can simply right click on the project and select **Pack**. Alternatively, you can add the following property to the library project file to automatically generate a NuGet package on build: `GeneratePackageOnBuild`.
78+
79+
To make your component available as a NuGet package, it is important to include the DLLs necessary for C#/WinRT hosting.
80+
When you pack your C#/WinRT component the DLLs/WinMD are automatically added to your nupkg, based on a nuspec generated from your project file.
81+
82+
**If you are going to write your own nuspec**, then you should make sure your nuspec contains the following ```file``` entries for your component ```MyAuthoredComponent``` (note: your TargetFramework may vary). This is so our targets that supply the DLLs for any consumers of your package work.
83+
Similarly, any other dependencies, e.g. `Microsoft.WinUI`, will need to be included in your nuspec as well.
4984

5085
``` nuspec
5186
<files>
52-
<file src="$(TargetDir)MyAuthoredComponent.dll" target="lib\native\MyAuthoredComponent.dll" />
53-
<file src="$(TargetDir)MyAuthoredComponent.winmd" target="winmd\MyAuthoredComponent.winmd" />
87+
<file src="$(TargetDir)MyAuthoredComponent.dll" target="lib\$(TargetFramework)\MyAuthoredComponent.dll" />
88+
<file src="$(TargetDir)MyAuthoredComponent.winmd" target="lib\$(TargetFramework)\winmd\MyAuthoredComponent.winmd" />
5489

55-
<file src="$(TargetDir)Microsoft.Windows.SDK.NET.dll" target="lib\native\Microsoft.Windows.SDK.NET.dll" />
90+
<file src="$(TargetDir)Microsoft.Windows.SDK.NET.dll" target="lib\$(TargetFramework)\Microsoft.Windows.SDK.NET.dll" />
5691

5792
<!-- Note: you must rename the CsWinRt.Authoring.Targets as follows -->
5893
<file src="C:\Path\To\CsWinRT\NugetDir\buildTransitive\Microsoft.Windows.CsWinRT.Authoring.targets"
@@ -64,10 +99,10 @@ To generate a NuGet package for the component, you can simply right click on the
6499

65100
<!-- Include the managed DLLs -->
66101
<file src="C:\Path\To\CsWinRT\NugetDir\lib\net5.0\WinRT.Host.Shim.dll"
67-
target="lib\native\WinRT.Host.Shim.dll" />
102+
target="lib\$(TargetFramework)\WinRT.Host.Shim.dll" />
68103

69104
<file src="C:\Path\To\CsWinRT\NugetDir\lib\net5.0\WinRT.Runtime.dll"
70-
target="lib\native\WinRT.Runtime.dll" />
105+
target="lib\$(TargetFramework)\WinRT.Runtime.dll" />
71106

72107
<!-- Include the native DLLs -->
73108
<file src="C:\Path\To\CsWinRT\NugetDir\runtimes\win-x64\native\WinRT.Host.dll"
@@ -78,40 +113,9 @@ To generate a NuGet package for the component, you can simply right click on the
78113
</files>
79114
```
80115

81-
## Using your authored component
82-
To use the component in a C# app, the authored component just needs to be added as a project/package reference.
83-
84-
For native (C++) apps, there are DLLs needed to host your authored component. When you use the automatic NuGet packaging on-build support (in Visual Studio) to make a nupkg for your runtime component, the DLLs/WinMD are automatically added to your nupkg, before the ```GenerateNuspec``` MSBuild step.
85-
86-
### For native app (C++) consumption
87-
Install your authored component's package -- this will come with a targets file that automatically adds a reference to the component's WinMD and copies the DLLs necessary for native support.
116+
Your component can then be added as a PackageReference to any consumer.
88117

89-
You'll need to use [C++/WinRT](https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/intro-to-using-cpp-with-winrt) to consume your API. So make sure you have C++/WinRT installed, and have added `#include <winrt/MyAuthoredComponent.h>` to the file `pch.h` of the native app.
90-
91-
You'll need to author some files to assist the hosting process by the native app: `YourNativeApp.exe.manifest` and `WinRT.Host.runtimeconfig.json`.
92-
93-
If your app is packaged with MSIX, then you don't need to include the manifest file, otherwise you need to include your activatable class registrations in the manifest file.
94118

95-
To do this, **in Visual Studio**, right click on the project node on the "Solution Explorer" window, click "Add", then "New Item". Search for the "Text File" template and name your file "YourNativeApp.exe.manifest".
96-
Repeat this for the "WinRT.Host.runtimeconfig.json" file.
97-
98-
This process adds the nodes `<Manifest Include=... >` and `<None Include=... >` to your native app's project file -- **you need to update these to have `<DeploymentContent>true</DeploymentContent>` for them to be placed in the output directory with your executable**.
99-
100-
You should read the [hosting docs](https://github.com/microsoft/CsWinRT/blob/master/docs/hosting.md) as well, for more information on these files.
101-
102-
In summary, here is the fragment of additions made to the native app's project file:
103-
``` vcxproj
104-
<ItemGroup>
105-
<!-- the runtimeconfig.json -->
106-
<None Include="WinRT.Host.runtimeconfig.json">
107-
<DeploymentContent>true</DeploymentContent>
108-
</None>
109-
<!-- the manifest -->
110-
<Manifest Include="YourNativeApp.exe.manifest">
111-
<DeploymentContent>true</DeploymentContent>
112-
</Manifest>
113-
</ItemGroup>
114-
```
115119

116120
## Known Authoring Issues
117121
You can follow along [here](https://github.com/microsoft/CsWinRT/issues/663) as we develop authoring support.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!-- This file was produced from C#/WinRT -->
2+
<Project ToolsVersion="14.0" xmln="http://schemas.microsoft.com/developer/msbuild/2003">
3+
4+
<PropertyGroup>
5+
<!-- Add the hosting dlls to references so they get binplaced -->
6+
<ResolveReferencesDependsOn>CsWinRTCopyAuthoringDlls;$(ResolveReferencesDependsOn)</ResolveReferencesDependsOn>
7+
<!-- Add authored component's winmd to references before C++/WinRT runs -->
8+
<BuildDependsOn>CsWinRTAddAuthoredWinMDReference;$(BuildDependsOn)</BuildDependsOn>
9+
</PropertyGroup>
10+
11+
<PropertyGroup>
12+
<HostingSupport-Net5Dir>$(MSBuildThisFileDirectory)..\lib\net5.0*</HostingSupport-Net5Dir>
13+
<HostingSupport-MetadataDir>$(HostingSupport-Net5Dir)\winmd</HostingSupport-MetadataDir>
14+
<HostingSupport-RuntimesDir>$(MSBuildThisFileDirectory)..\runtimes</HostingSupport-RuntimesDir>
15+
<HostingSupport-IsNative Condition="'$(TargetFramework)' == 'native' OR '$(TargetFramework)' == ''">true</HostingSupport-IsNative>
16+
<HostingSupport-IsArmArch Condition="'$(Platform)' == 'arm' OR '$(Platform)' == 'arm64'">true</HostingSupport-IsArmArch>
17+
</PropertyGroup>
18+
19+
<Target Name="CsWinRTAddAuthoredWinMDReference" Condition="'$(HostingSupport-IsNative)' == 'true'" Outputs="@(Reference)">
20+
<ItemGroup Label="Add the WinMD file as a reference of the native app">
21+
<Reference Include="$(HostingSupport-MetadataDir)\*.winmd" IsWinMDFile="true" Implementation="WinRT.Host.dll" />
22+
</ItemGroup>
23+
</Target>
24+
25+
<Target Name="CsWinRTCopyAuthoringDlls" Condition="'$(HostingSupport-IsNative)' == 'true'" Outputs="@(ReferenceCopyLocalPaths)">
26+
<ItemGroup>
27+
<ReferenceCopyLocalPaths Include="$(HostingSupport-Net5Dir)\*.dll" />
28+
29+
<ReferenceCopyLocalPaths Include="$(HostingSupport-RuntimesDir)\win-$(Platform)\native\WinRT.Host.dll"
30+
Condition="'$(Platform)' == 'x64' OR '$(Platform)' == 'x86' OR '$(HostingSupport-IsArmArch)' == 'true'" />
31+
32+
<ReferenceCopyLocalPaths Include="$(HostingSupport-RuntimesDir)\win-x86\native\WinRT.Host.dll"
33+
Condition="'$(Platform)' == 'Win32'"/>
34+
</ItemGroup>
35+
</Target>
36+
37+
</Project>
Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,67 @@
1-
<Project ToolsVersion="15.0" xmln="http://schemas.microsoft.com/developer/msbuild/2003">
1+
<!--
2+
***********************************************************************************************
3+
Copyright (C) Microsoft Corporation. All rights reserved.
4+
***********************************************************************************************
5+
-->
6+
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
27

3-
<PropertyGroup>
4-
<!-- Add the hosting dlls to references so they get binplaced -->
5-
<ResolveReferencesDependsOn>CsWinRTCopyAuthoringDlls;$(ResolveReferencesDependsOn)</ResolveReferencesDependsOn>
6-
<!-- Add authored component's winmd to references before C++/WinRT runs -->
7-
<BuildDependsOn>CsWinRTAddAuthoredWinMDReference;$(BuildDependsOn)</BuildDependsOn>
8-
</PropertyGroup>
8+
<!-- For Project Reference consumers, copy the necessary WinRT DLLs to output directory -->
9+
<ItemGroup>
10+
<CsWinRTAuthoringDependencyDlls Condition="Exists('$(CsWinRTPath)lib\net5.0\WinRT.Host.Shim.dll')" Include="$(CsWinRTPath)lib\net5.0\WinRT.Host.Shim.dll" />
11+
<CsWinRTAuthoringDependencyDlls Condition="Exists('$(CsWinRTPath)lib\net5.0\WinRT.Runtime.dll')" Include="$(CsWinRTPath)lib\net5.0\WinRT.Runtime.dll" />
12+
<None Include="@(CsWinRTAuthoringDependencyDlls)" Link="%(RecursiveDir)%(FileName)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
13+
<None Include="$(CsWinRTPath)runtimes\win-$(Platform)\native\WinRT.Host.dll"
14+
Condition="Exists('$(CsWinRTPath)runtimes\win-$(Platform)\native\WinRT.Host.dll')"
15+
Link="%(RecursiveDir)%(FileName)%(Extension)"
16+
CopyToOutputDirectory="PreserveNewest" />
17+
</ItemGroup>
918

10-
<PropertyGroup>
11-
<HostingSupport-NativeDir>$(MSBuildThisFileDirectory)..\lib\net5.0*</HostingSupport-NativeDir>
12-
<HostingSupport-MetadataDir>$(HostingSupport-NativeDir)\winmd</HostingSupport-MetadataDir>
13-
<HostingSupport-RuntimesDir>$(MSBuildThisFileDirectory)..\runtimes</HostingSupport-RuntimesDir>
14-
<HostingSupport-IsNative Condition="'$(TargetFramework)' == 'native' OR '$(TargetFramework)' == ''">true</HostingSupport-IsNative>
15-
<HostingSupport-IsArmArch Condition="'$(Platform)' == 'arm' OR '$(Platform)' == 'arm64'">true</HostingSupport-IsArmArch>
16-
</PropertyGroup>
17-
18-
<!-- Happens before building, so C++/WinRT can make the corresponding header files -->
19-
<Target Name="CsWinRTAddAuthoredWinMDReference" Condition="'$(HostingSupport-IsNative)' == 'true'" Outputs="@(Reference)">
20-
21-
<ItemGroup Label="Add the WinMD file as a reference of the native app">
22-
<Reference Include="$(HostingSupport-MetadataDir)\*.winmd">
23-
<IsWinMDFile>true</IsWinMDFile>
24-
<Implementation>WinRT.Host.dll</Implementation>
25-
</Reference>
19+
<Target Name="CsWinRTCopySDKRefDllToOutDir" Condition="'$(CsWinRTComponent)' == 'true'" AfterTargets="ResolveRuntimePackAssets">
20+
<ItemGroup>
21+
<CsWinRTSDKRefDll Include="@(RuntimePackAsset)" Condition="'%(RuntimePackAsset.DestinationSubPath)' == 'Microsoft.Windows.SDK.NET.dll'" />
22+
<CsWinRTAuthoringDependencyDlls Include="@(CsWinRTSDKRefDll)" />
23+
<_ThisProjectItemstoCopyToOutputDirectory Include="@(CsWinRTSDKRefDll)">
24+
<Link>%(FileName)%(Extension)</Link>
25+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
26+
<TargetPath>Microsoft.Windows.SDK.NET.dll</TargetPath>
27+
</_ThisProjectItemstoCopyToOutputDirectory>
2628
</ItemGroup>
27-
2829
</Target>
2930

30-
<!-- Happens when resolving references, so the app can be hosted -->
31-
<Target Name="CsWinRTCopyAuthoringDlls" Condition="'$(HostingSupport-IsNative)' == 'true'" Outputs="@(ReferenceCopyLocalPaths)">
32-
33-
<ItemGroup Label="Copy Dlls needed for hosting/using authored components">
34-
<ReferenceCopyLocalPaths Include="$(HostingSupport-NativeDir)\*.dll" />
35-
</ItemGroup>
36-
37-
<ItemGroup Label="Copy the WinRT.Host dll, based on architecture">
38-
<ReferenceCopyLocalPaths Include="$(HostingSupport-RuntimesDir)\win-$(Platform)\native\WinRT.Host.dll"
39-
Condition="'$(Platform)' == 'x64' OR '$(Platform)' == 'x86' OR '$(HostingSupport-IsArmArch)' == 'true'" />
31+
<!-- When an authored component makes a nupkg, add the necessary hosting assets to the package -->
32+
<Target Name="CsWinRTIncludeHostDlls" Condition="'$(CsWinRTComponent)' == 'true'" BeforeTargets="AfterBuild" Outputs="@(Content)">
33+
<!-- When packing, include all necessary DLLs and the targets file for DLL copying on the native side -->
34+
<ItemGroup>
35+
<Content Include="@(CsWinRTAuthoringDependencyDlls)" Pack="true" PackagePath="lib\$(TargetFramework)" />
36+
<Content Include="$(TargetDir)$(AssemblyName).winmd" Pack="true" PackagePath="lib\$(TargetFramework)\winmd" />
4037

41-
<ReferenceCopyLocalPaths Include="$(HostingSupport-RuntimesDir)\win-x86\native\WinRT.Host.dll"
42-
Condition="'$(Platform)' == 'Win32'"/>
43-
</ItemGroup>
38+
<!-- Custom targets that copy dlls for consumers of the authored component. -->
39+
<Content Include="$(CsWinRTPath)buildTransitive\Microsoft.Windows.CsWinRT.Authoring.Transitive.targets"
40+
Pack="true"
41+
PackagePath="buildTransitive\$(AssemblyName).targets;build\$(AssemblyName).targets" />
4442

43+
<!-- We package a version of WinRT.Host.dll for each possible architecture -->
44+
<!-- x64 -->
45+
<Content Condition="Exists('$(CsWinRTPath)runtimes\win-x64\native\WinRT.Host.dll')"
46+
Include="$(CsWinRTPath)runtimes\win-x64\native\WinRT.Host.dll"
47+
Pack="true"
48+
PackagePath="runtimes\win-x64\native"/>
49+
<!-- x86 -->
50+
<Content Condition="Exists('$(CsWinRTPath)runtimes\win-x86\native\WinRT.Host.dll')"
51+
Include="$(CsWinRTPath)runtimes\win-x86\native\WinRT.Host.dll"
52+
Pack="true"
53+
PackagePath="runtimes\win-x86\native"/>
54+
<!-- arm -->
55+
<Content Condition="Exists('$(CsWinRTPath)runtimes\win-arm\native\WinRT.Host.dll')"
56+
Include="$(CsWinRTPath)runtimes\win-arm\native\WinRT.Host.dll"
57+
Pack="true"
58+
PackagePath="runtimes\win-arm\native"/>
59+
<!-- arm64 -->
60+
<Content Condition="Exists('$(CsWinRTPath)runtimes\win-arm64\native\WinRT.Host.dll')"
61+
Include="$(CsWinRTPath)runtimes\win-arm64\native\WinRT.Host.dll"
62+
Pack="true"
63+
PackagePath="runtimes\win-arm64\native"/>
64+
</ItemGroup>
4565
</Target>
4666

47-
</Project>
67+
</Project>

nuget/Microsoft.Windows.CsWinRT.nuspec

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@
2222
<file src="$cswinrt_exe$"/>
2323
<file src="Microsoft.Windows.CsWinRT.props" target="build"/>
2424
<file src="Microsoft.Windows.CsWinRT.targets" target="build"/>
25-
<file src="Microsoft.Windows.CsWinRT.Prerelease*.targets" target="build"/>
2625
<file src="Microsoft.Windows.CsWinRT.Authoring.targets" target="build"/>
27-
<file src="Microsoft.Windows.CsWinRT.Authoring.targets" target="buildTransitive"/>
26+
<file src="Microsoft.Windows.CsWinRT.Prerelease*.targets" target="build"/>
27+
<file src="Microsoft.Windows.CsWinRT.Authoring.Transitive.targets" target="build"/>
28+
<file src="Microsoft.Windows.CsWinRT.Authoring.Transitive.targets" target="buildTransitive"/>
2829
<file src="readme.txt"/>
2930
<file src="$net5_runtime$" target="lib\net5.0\"/>
3031
<file src="$source_generator$" target="analyzers\dotnet\cs\"/>

0 commit comments

Comments
 (0)