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
+)