Include .winmd in nuget and enable C++ usage (#40601)

JohnMcPMS committed May 20, 2026 at 08:24 UTC 43f78f4c71a38ac150a7b13a93555cab229e3034
8 files changed +174 -4
.pipelines/build-job.yml
+2
@@ -214,9 +214,11 @@ jobs:
214 if ('${{ parameters.isRelease }}' -eq 'True') {
215 Copy-Item -Path "$(packageStagingDir)\${{ parameters.platform }}\wslcsdk.dll" -Destination "$(ob_outputDirectory)\sdk\${{ parameters.platform }}\wslcsdk.dll"
216 Copy-Item -Path "$(packageStagingDir)\${{ parameters.platform }}\wslcsdkcs.dll" -Destination "$(ob_outputDirectory)\sdk\${{ parameters.platform }}\wslcsdkcs.dll"
217 + Copy-Item -Path "$(packageStagingDir)\${{ parameters.platform }}\Microsoft.WSL.Containers.winmd" -Destination "$(ob_outputDirectory)\sdk\${{ parameters.platform }}\Microsoft.WSL.Containers.winmd"
218 } else {
219 Copy-Item -Path "bin\${{ parameters.platform }}\release\wslcsdk.dll" -Destination "$(ob_outputDirectory)\sdk\${{ parameters.platform }}\wslcsdk.dll"
220 Copy-Item -Path "bin\${{ parameters.platform }}\release\wslcsdkcs.dll" -Destination "$(ob_outputDirectory)\sdk\${{ parameters.platform }}\wslcsdkcs.dll"
221 + Copy-Item -Path "bin\${{ parameters.platform }}\release\Microsoft.WSL.Containers.winmd" -Destination "$(ob_outputDirectory)\sdk\${{ parameters.platform }}\Microsoft.WSL.Containers.winmd"
222 }
223
224 - task: PowerShell@2
.pipelines/build-stage.yml
+1 -1
@@ -37,7 +37,7 @@ parameters:
37 - target: "msixgluepackage"
38 pattern: "gluepackage.msix"
39 - target: "msipackage;wslcsdkcs"
40 - pattern: "wsl.msi,wslcsdkcs.dll"
40 + pattern: "wsl.msi,wslcsdkcs.dll,Microsoft.WSL.Containers.winmd"
41
42 - name: pool
43 type: string
.pipelines/package-stage.yml
+2 -1
@@ -83,7 +83,8 @@ stages:
83 Copy-Item "$(Pipeline.Workspace)\drop_$($arch.platform)\installer\installer.$($arch.platform).msix" "$dest\installer.msix"
84 Copy-Item "$(Pipeline.Workspace)\drop_$($arch.platform)\sdk\$($arch.platform)\wslcsdk.lib" "$dest\wslcsdk.lib"
85 Copy-Item "$(Pipeline.Workspace)\drop_$($arch.platform)\sdk\$($arch.platform)\wslcsdk.dll" "$dest\wslcsdk.dll"
86 - Copy-Item "$(Pipeline.Workspace)\drop_$($arch.platform)\sdk\$($arch.platform)\wslcsdkcs.dll" "$dest\wslcsdkcs.dll"
86 + Copy-Item "$(Pipeline.Workspace)\drop_$($arch.platform)\sdk\$($arch.platform)\wslcsdkcs.dll" "$dest\wslcsdkcs.dll"
87 + Copy-Item "$(Pipeline.Workspace)\drop_$($arch.platform)\sdk\$($arch.platform)\Microsoft.WSL.Containers.winmd" "$dest\Microsoft.WSL.Containers.winmd"
88 }
89
90 # Copy MSIs to the output bundle directory
nuget/Microsoft.WSL.Containers.nuspec.in
+1
@@ -19,6 +19,7 @@
19 <file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/>
20
21 <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdkcs.dll" target="lib\${WSL_NUGET_TARGET_FRAMEWORK}\"/>
22 + <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\Microsoft.WSL.Containers.winmd" target="winmd\Microsoft.WSL.Containers.winmd"/>
23
24 <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdk.lib" target="runtimes\win-x64\"/>
25 <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdk.dll" target="runtimes\win-x64\native\"/>
nuget/Microsoft.WSL.Containers/build/native/Microsoft.WSL.Containers.targets
+14
@@ -3,6 +3,8 @@
3 <PropertyGroup>
4 <WslcPlatform Condition="'$(WslcPlatform)' == ''">$(Platform)</WslcPlatform>
5 <_wslcIsInvalidPlatform Condition="'$(WslcPlatform)' != 'x64' and '$(WslcPlatform)' != 'arm64'">true</_wslcIsInvalidPlatform>
6 + <!-- Set to false to suppress the C++/WinRT winmd reference and activation manifest injection. -->
7 + <WslcEnableCppWinRT Condition="'$(WslcEnableCppWinRT)' == ''">true</WslcEnableCppWinRT>
8 </PropertyGroup>
9
10 <ItemDefinitionGroup>
@@ -24,8 +26,20 @@
26 </Link>
27 </ItemDefinitionGroup>
28
29 + <!-- Inject the activatable class manifest so RoGetActivationFactory resolves wslcsdk.dll
30 + without requiring COM registration or renaming the DLL to match the namespace. -->
31 + <ItemDefinitionGroup Condition="'$(WslcEnableCppWinRT)' == 'true' and '$(ConfigurationType)' != 'StaticLibrary'">
32 + <Manifest>
33 + <AdditionalManifestFiles>$(MSBuildThisFileDirectory)..\..\manifests\Microsoft.WSL.Containers.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>
34 + </Manifest>
35 + </ItemDefinitionGroup>
36 +
37 <ItemGroup>
38 <ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-$(WslcPlatform)\native\wslcsdk.dll" />
39 + <Reference Include="Microsoft.WSL.Containers" Condition="'$(WslcEnableCppWinRT)' == 'true'">
40 + <HintPath>$(MSBuildThisFileDirectory)..\..\winmd\Microsoft.WSL.Containers.winmd</HintPath>
41 + <Implementation>wslcsdk.dll</Implementation>
42 + </Reference>
43 </ItemGroup>
44
45 <Target Name="WslcValidatePlatform" BeforeTargets="PrepareForBuild" Condition="'$(_wslcIsInvalidPlatform)' == 'true'">
nuget/Microsoft.WSL.Containers/docs/README.MD
+120 -2
@@ -1,7 +1,125 @@
1 -# WSL Containers
1 +# Microsoft.WSL.Containers
2
3 > **⚠️ Preview:** This SDK is currently in preview and is subject to breaking changes
4 > in future releases without prior notice. Do not rely on API stability for production
5 > workloads.
6
7 -This package contains the `wslcsdk.h` header which defines the WSL Containers interface.
7 +The WSL Containers SDK provides APIs for creating and managing Linux containers running inside WSL, and MSBuild/CMake integration for building container images as part of your project.
8 +
9 +**Supported platforms:** x64 and ARM64.
10 +
11 +---
12 +
13 +## Using the native C/C++ API
14 +
15 +MSBuild (via NuGet) and CMake both configure include directories and link libraries automatically when you reference the package. Include the header and link:
16 +
17 +```cpp
18 +#include <wslcsdk.h>
19 +```
20 +
21 +**MSBuild:** No manual configuration needed — `wslcsdk.lib` and the include directory are wired up by the imported targets.
22 +
23 +**CMake:**
24 +```cmake
25 +find_package(Microsoft.WSL.Containers REQUIRED)
26 +target_link_libraries(my_app PRIVATE Microsoft.WSL.Containers::SDK)
27 +```
28 +
29 +The runtime DLL (`wslcsdk.dll`) is automatically copied to the output directory.
30 +
31 +---
32 +
33 +## Using the WinRT projection
34 +
35 +### C++/WinRT
36 +
37 +The package includes a WinRT metadata file and automatically:
38 +- Adds `Microsoft.WSL.Containers.winmd` as a reference so C++/WinRT generates projection headers
39 +- Injects an activation manifest into your binary so `RoGetActivationFactory` resolves the classes to `wslcsdk.dll` without COM registration
40 +
41 +**MSBuild — C++/WinRT (requires the [Microsoft.Windows.CppWinRT](https://www.nuget.org/packages/Microsoft.Windows.CppWinRT) NuGet package):**
42 +```cpp
43 +#include <winrt/Microsoft.WSL.Containers.h>
44 +
45 +auto settings = winrt::Microsoft::WSL::Containers::SessionSettings(L"my-session", L"C:\\path\\to\\storage");
46 +```
47 +
48 +To disable C++/WinRT integration (suppress the winmd reference and manifest injection):
49 +```xml
50 +<PropertyGroup>
51 + <WslcEnableCppWinRT>false</WslcEnableCppWinRT>
52 +</PropertyGroup>
53 +```
54 +
55 +### C#/WinRT
56 +
57 +**MSBuild — C# (.NET 8+):** The `wslcsdkcs.dll` projection assembly is referenced automatically.
58 +```csharp
59 +using Microsoft.WSL.Containers;
60 +
61 +var settings = new SessionSettings("my-session", @"C:\path\to\storage");
62 +```
63 +
64 +---
65 +
66 +## Building container images
67 +
68 +The package integrates the `wslc` CLI into your build system so container images are built and saved as part of your normal project build, with incremental rebuild support (images only rebuild when sources change).
69 +
70 +### MSBuild
71 +
72 +Add `WslcImage` items to your project. Each item builds an image and saves it to a `.tar` archive at build time:
73 +
74 +```xml
75 +<ItemGroup>
76 + <WslcImage Include="my-server"
77 + Image="ghcr.io/myorg/my-server:latest"
78 + Dockerfile="container/Dockerfile"
79 + Context="container/"
80 + Sources="container/src/**"
81 + TarLocation="$(OutDir)my-server.tar" />
82 +</ItemGroup>
83 +```
84 +
85 +| Metadata | Required | Description |
86 +|---|---|---|
87 +| `Image` | Yes | Container image reference (`:latest` appended if no tag) |
88 +| `Dockerfile` | Yes | Path to the Dockerfile |
89 +| `Context` | Yes | Build context directory |
90 +| `Sources` | No | Glob patterns for incremental rebuild tracking (defaults to all files in `Context`) |
91 +| `TarLocation` | No | Output path for the saved `.tar` (defaults to `$(OutDir)<name>.tar`) |
92 +
93 +**Optional MSBuild properties:**
94 +
95 +| Property | Default | Description |
96 +|---|---|---|
97 +| `WslcCliPath` | `wslc` | Path to the `wslc` CLI executable |
98 +| `WslcPruneAfterBuild` | `false` | Run `wslc image prune` after each successful build |
99 +| `WslcTreatPruneFailureAsError` | `false` | Fail the build if the post-build prune fails |
100 +| `WslcPlatform` | `$(Platform)` | Override the detected platform (x64 or arm64) |
101 +
102 +### CMake
103 +
104 +```cmake
105 +find_package(Microsoft.WSL.Containers REQUIRED)
106 +
107 +wslc_add_image(my-server
108 + IMAGE ghcr.io/myorg/my-server:latest
109 + DOCKERFILE container/Dockerfile
110 + CONTEXT container/
111 + SOURCES container/src/*.cpp container/src/*.h
112 + TAR_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/my-server.tar
113 +)
114 +
115 +add_dependencies(my_app my-server)
116 +```
117 +
118 +Set `WSLC_CLI_PATH` to override the `wslc` executable location. Pass `PRUNE_AFTER_BUILD` to prune dangling images after each build.
119 +
120 +---
121 +
122 +## Prerequisites
123 +
124 +- **WSL** — Install with `wsl --install --no-distribution` (provides the `wslc` CLI)
125 +- **C++/WinRT** — Install the [Microsoft.Windows.CppWinRT](https://www.nuget.org/packages/Microsoft.Windows.CppWinRT) NuGet package for C++/WinRT projection support
nuget/Microsoft.WSL.Containers/manifests/Microsoft.WSL.Containers.manifest new
+23
@@ -0,0 +1,23 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3 + <file name="wslcsdk.dll">
4 + <activatableClass name="Microsoft.WSL.Containers.Container" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
5 + <activatableClass name="Microsoft.WSL.Containers.ContainerNamedVolume" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
6 + <activatableClass name="Microsoft.WSL.Containers.ContainerPortMapping" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
7 + <activatableClass name="Microsoft.WSL.Containers.ContainerSettings" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
8 + <activatableClass name="Microsoft.WSL.Containers.ContainerVolume" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
9 + <activatableClass name="Microsoft.WSL.Containers.ImageInfo" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
10 + <activatableClass name="Microsoft.WSL.Containers.ImageProgress" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
11 + <activatableClass name="Microsoft.WSL.Containers.InstallProgress" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
12 + <activatableClass name="Microsoft.WSL.Containers.Process" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
13 + <activatableClass name="Microsoft.WSL.Containers.ProcessSettings" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
14 + <activatableClass name="Microsoft.WSL.Containers.PullImageOptions" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
15 + <activatableClass name="Microsoft.WSL.Containers.PushImageOptions" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
16 + <activatableClass name="Microsoft.WSL.Containers.ServiceVersion" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
17 + <activatableClass name="Microsoft.WSL.Containers.Session" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
18 + <activatableClass name="Microsoft.WSL.Containers.SessionSettings" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
19 + <activatableClass name="Microsoft.WSL.Containers.TagImageOptions" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
20 + <activatableClass name="Microsoft.WSL.Containers.VhdOptions" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
21 + <activatableClass name="Microsoft.WSL.Containers.WslcService" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
22 + </file>
23 +</assembly>
src/windows/WslcSDK/winrt/CMakeLists.txt
+11
@@ -68,3 +68,14 @@ set_target_properties(
68 FOLDER windows
69 EXCLUDE_FROM_ALL FALSE
70 )
71 +
72 +# Copy the winmd to the bin output directory so the nuspec can reference it
73 +# from a stable, arch-aware path (bin\<platform>\<config>\Microsoft.WSL.Containers.winmd).
74 +set(WINMD_SRC ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslcsdk.winmd)
75 +set(WINMD_DEST ${CMAKE_SOURCE_DIR}/bin/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/Microsoft.WSL.Containers.winmd)
76 +
77 +add_custom_command(TARGET wslcsdkwinrtidl POST_BUILD
78 + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_SOURCE_DIR}/bin/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}"
79 + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${WINMD_SRC}" "${WINMD_DEST}"
80 + COMMENT "Copying Microsoft.WSL.Containers.winmd to bin output"
81 +)