Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,5 @@ directory.build.targets
test-storage/
*.vhdx
*.tar
*.etl
*.etl
*.lscache
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ find_package(NUGET REQUIRED)
find_package(VERSION REQUIRED)
find_package(MC REQUIRED)
find_package(Appx REQUIRED)
find_package(CSharp REQUIRED)

# Download nuget packages
restore_nuget_packages()
Expand Down Expand Up @@ -157,6 +158,9 @@ find_nuget_package(Microsoft.Windows.SDK.NET.Ref WINDOWS_SDK_DOTNET /)
find_nuget_package(Microsoft.Xaml.Behaviors.WinUI.Managed XAML_BEHAVIORS /)
find_nuget_package(WinUIEx WINUIEX /)

# WSLC C# API packages
find_nuget_package(Microsoft.Windows.CsWinRT CSWINRT /)

set(WSLG_TS_PLUGIN_DLL "WSLDVCPlugin.dll")

set(SUPPORTED_LANGS cs-CZ;da-DK;de-DE;en-GB;en-US;es-ES;fi-FI;fr-FR;hu-HU;it-IT;ja-JP;ko-KR;nb-NO;nl-NL;pl-PL;pt-BR;pt-PT;ru-RU;sv-SE;tr-TR;zh-CN;zh-TW)
Expand Down
15 changes: 15 additions & 0 deletions cmake/FindCSharp.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function(configure_csharp_target TARGET)
set(TARGET_PLATFORM_MIN_VERSION "10.0.19041.0")
target_compile_options(${TARGET} PRIVATE "/langversion:latest" "/debug:full")
set_target_properties(
${TARGET} PROPERTIES
VS_GLOBAL_TargetPlatformVersion "${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}"
VS_GLOBAL_TargetPlatformMinVersion "${TARGET_PLATFORM_MIN_VERSION}"
VS_GLOBAL_WindowsSdkPackageVersion "${WINDOWS_SDK_DOTNET_VERSION}"
VS_GLOBAL_AppendRuntimeIdentifierToOutputPath false
VS_GLOBAL_GenerateAssemblyInfo false
VS_GLOBAL_TargetLatestRuntimePatch false
DOTNET_SDK "Microsoft.NET.Sdk"
DOTNET_TARGET_FRAMEWORK "net8.0-windows${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}"
)
Comment thread
florelis marked this conversation as resolved.
endfunction()
47 changes: 46 additions & 1 deletion cmake/FindIDL.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,49 @@ function(add_idl target idl_files_with_proxy idl_files_no_proxy)
DEPENDS ${TARGET_OUTPUTS}
SOURCES ${idl_files_with_proxy} ${idl_files_no_proxy})

endfunction()
endfunction()

function(add_idl_winrt target idl_file)
set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE})
file(TO_NATIVE_PATH ${OUTPUT_DIR} OUTPUT_DIR) # midl is picky about path formats
file(MAKE_DIRECTORY ${OUTPUT_DIR})
Comment thread
florelis marked this conversation as resolved.

set(IDL_DEFINITIONS "")

get_directory_property(IDL_DEFS COMPILE_DEFINITIONS )
foreach(e ${IDL_DEFS})
set(IDL_DEFINITIONS ${IDL_DEFINITIONS} /D${e})
endforeach()

string(TOLOWER ${TARGET_PLATFORM} IDL_ENV)

cmake_host_system_information(
RESULT WINDOWS_SDK_DIR
QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Microsoft/Windows Kits/Installed Roots"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that developers will have to install additional devkits for this to build ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just querying where the Windows SDK is installed to, which I assume is already a requirement to build.

VALUE "KitsRoot10")
set(WINRT_METADATA_DIR "${WINDOWS_SDK_DIR}\\UnionMetadata\\${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
set(WINRT_REFERENCE "${WINRT_METADATA_DIR}\\Windows.winmd")
set(WINRT_INCLUDE "${WINDOWS_SDK_DIR}\\Include\\${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}\\winrt")

cmake_path(GET idl_file STEM IDL_NAME)

set(IDL_WINMD ${OUTPUT_DIR}/${IDL_NAME}.winmd)

add_custom_command(
OUTPUT ${IDL_WINMD}
COMMAND midl /nologo /nomidl /winrt /metadata_dir "${WINRT_METADATA_DIR}" /reference "${WINRT_REFERENCE}" /I "${WINRT_INCLUDE}" /env "${IDL_ENV}" /h nul /winmd ${IDL_WINMD} ${idl_file} ${IDL_DEFINITIONS}
COMMAND cppwinrt -input ${IDL_WINMD} -reference "${WINRT_REFERENCE}" -output ${OUTPUT_DIR} -comp ${OUTPUT_DIR}/implementation_base -optimize -pch precomp.h -prefix
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
Comment thread
florelis marked this conversation as resolved.
DEPENDS ${idl_file}
MAIN_DEPENDENCY ${idl_file}
VERBATIM
)

set_source_files_properties(${IDL_WINMD} PROPERTIES GENERATED TRUE)

add_custom_target(${target}
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}
DEPENDS ${IDL_WINMD}
SOURCES ${idl_file})

endfunction()
1 change: 1 addition & 0 deletions nuget/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(NUGET_PACKAGES Microsoft.WSL.PluginApi.nuspec Microsoft.WSL.Containers.nuspec)
set(NUGET_TARGET_FRAMEWORK "net8.0-windows10.0.19041.0")

# generate vars with native paths since nuget won't accept unix path separators
cmake_path(NATIVE_PATH CMAKE_SOURCE_DIR CMAKE_SOURCE_DIR_NATIVE)
Expand Down
19 changes: 14 additions & 5 deletions nuget/Microsoft.WSL.Containers.nuspec.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,22 @@
<language>en-us</language>
<license type="expression">MIT</license>
<readme>docs\README.MD</readme>
<dependencies>
<group targetFramework="${NUGET_TARGET_FRAMEWORK}" />
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package now ships a managed projection (wslcsdkcs.dll) that depends on the CsWinRT/WinRT.Runtime assemblies (e.g., WinRTActivation.cs uses the WinRT namespace). The nuspec defines an empty dependency group, so consumers won’t automatically restore the required runtime package(s), leading to missing-assembly failures at runtime. Add an explicit NuGet dependency on the appropriate runtime package (e.g., Microsoft.Windows.CsWinRT or WinRT.Runtime), or alternatively include the required runtime DLLs in this package.

Suggested change
<group targetFramework="${NUGET_TARGET_FRAMEWORK}" />
<group targetFramework="${NUGET_TARGET_FRAMEWORK}">
<dependency id="WinRT.Runtime" version="[2.2.0,3.0.0)" />
</group>

Copilot uses AI. Check for mistakes.
</dependencies>
</metadata>
<files>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdk.lib" target="runtimes\win-x64"/>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdk.dll" target="runtimes\win-x64"/>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\arm64\Release\wslcsdk.lib" target="runtimes\win-arm64"/>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\arm64\Release\wslcsdk.dll" target="runtimes\win-arm64"/>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\nuget\Microsoft.WSL.Containers\**"/>

<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdkcs.dll" target="lib\${NUGET_TARGET_FRAMEWORK}\"/>

<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdk.lib" target="runtimes\win-x64\"/>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdk.dll" target="runtimes\win-x64\native\"/>

<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\arm64\${CMAKE_BUILD_TYPE}\wslcsdk.lib" target="runtimes\win-arm64\"/>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\arm64\${CMAKE_BUILD_TYPE}\wslcsdk.dll" target="runtimes\win-arm64\native\"/>

<file src="${CMAKE_SOURCE_DIR_NATIVE}\nuget\Microsoft.WSL.Containers\**" exclude="**\net\**"/>
<file src="${CMAKE_SOURCE_DIR_NATIVE}\nuget\Microsoft.WSL.Containers\build\net\**" target="build\${NUGET_TARGET_FRAMEWORK}"/>
</files>
</package>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(WSLCSDK_Platform)' == ''">
<WSLCSDK_Platform>$(Platform)</WSLCSDK_Platform>
<PropertyGroup>
<WslcPlatform Condition="'$(WslcPlatform)' == ''">$(Platform)</WslcPlatform>
Comment thread
florelis marked this conversation as resolved.
<_wslcIsInvalidPlatform Condition="'$(WslcPlatform)' != 'x64' and '$(WslcPlatform)' != 'arm64'">true</_wslcIsInvalidPlatform>
</PropertyGroup>
Comment on lines +3 to 6
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WslcPlatform defaults to $(Platform), but the validation compares case-sensitively against x64/arm64. In VS native builds $(Platform) is commonly ARM64, which will trip _wslcIsInvalidPlatform and fail the build even though the package supports ARM64. Consider normalizing $(WslcPlatform) to lower-case (or accepting both ARM64/arm64).

Copilot uses AI. Check for mistakes.

<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>
Expand All @@ -16,11 +18,17 @@
%(AdditionalDependencies)
</AdditionalDependencies>
<AdditionalLibraryDirectories>
$(MSBuildThisFileDirectory)..\..\runtimes\win-$(Platform);
$(MSBuildThisFileDirectory)..\..\runtimes\win-$(WslcPlatform);
%(AdditionalLibraryDirectories)
</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>

<Import Project="$(MSBuildThisFileDirectory)..\Microsoft.WSL.Containers.common.targets" />
<ItemGroup>
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-$(WslcPlatform)\native\wslcsdk.dll" />
</ItemGroup>
Comment on lines +27 to +29
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file copies runtimes\win-$(WslcPlatform)\native\Microsoft.WSL.Containers.dll, but the package currently places the managed projection under lib\<TFM>\wslcsdkcs.dll and the native runtime under runtimes\win-<arch>\native\wslcsdk.dll. As-is, the copy step points at a non-existent file and also no longer copies wslcsdk.dll for native (VC++) consumers, which will lead to runtime load failures. Update ReferenceCopyLocalPaths to copy the actual native DLL (and only copy managed assets if they’re actually shipped under runtimes).

Copilot uses AI. Check for mistakes.

<Target Name="WslcValidatePlatform" BeforeTargets="PrepareForBuild" Condition="'$(_wslcIsInvalidPlatform)' == 'true'">
<Error Text="wslcsdk.dll could not be copied because platform '$(WslcPlatform)' is not supported. Only x64 and arm64 platforms are supported. You can override the detected platform by setting the property WslcPlatform." />
</Target>
</Project>
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(WSLCSDK_Platform)' == ''">
<WSLCSDK_Platform Condition="$(RuntimeIdentifier.EndsWith('-x64'))">x64</WSLCSDK_Platform>
<WSLCSDK_Platform Condition="$(RuntimeIdentifier.EndsWith('-arm64'))">arm64</WSLCSDK_Platform>
</PropertyGroup>
<!-- If we have a RuntimeIdentifier, the DLL is referenced automatically.
If it is missing, we fall back to PlatformTarget to reference it manually. -->
<Choose>
<When Condition="'$(RuntimeIdentifier)' != ''">
<PropertyGroup>
<_wslcPlatform Condition="$(RuntimeIdentifier.EndsWith('-x64'))">x64</_wslcPlatform>
<_wslcPlatform Condition="$(RuntimeIdentifier.EndsWith('-arm64'))">arm64</_wslcPlatform>
<_wslcInvalidPlatformProperty Condition="'$(_wslcPlatform)' == ''">RuntimeIdentifier</_wslcInvalidPlatformProperty>
<_wslcInvalidPlatform Condition="'$(_wslcPlatform)' == ''">$(RuntimeIdentifier)</_wslcInvalidPlatform>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<_wslcPlatform Condition="'$(PlatformTarget)' == 'x64'">x64</_wslcPlatform>
<_wslcPlatform Condition="'$(PlatformTarget)' == 'arm64'">arm64</_wslcPlatform>
<_wslcInvalidPlatformProperty Condition="'$(_wslcPlatform)' == ''">PlatformTarget</_wslcInvalidPlatformProperty>
<_wslcInvalidPlatform Condition="'$(_wslcPlatform)' == ''">$(PlatformTarget)</_wslcInvalidPlatform>
</PropertyGroup>

<PropertyGroup Condition="'$(WSLCSDK_Platform)' == ''">
<WSLCSDK_Platform Condition="'$(Platform)' != 'AnyCPU'">$(Platform)</WSLCSDK_Platform>
</PropertyGroup>

<Import Project="$(MSBuildThisFileDirectory)..\Microsoft.WSL.Containers.common.targets" />
<ItemGroup Condition="'$(_wslcPlatform)' != ''">
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When RuntimeIdentifier is not set, this targets file only adds the native DLLs to ReferenceCopyLocalPaths, but it does not add a reference to the managed projection assembly (the package places it under runtimes/win-*/lib/<tfm>/wslcsdkcs.dll). In that configuration NuGet restore typically won’t select RID-specific runtimes/*/lib assets, so consumers may fail to compile because Microsoft.WSL.Containers isn’t referenced at all. Consider adding a non-RID lib/<tfm>/ (or ref/<tfm>/) managed assembly for compile-time, or extend the fallback branch to add an explicit <Reference>/<Compile> reference to the managed DLL based on PlatformTarget.

Suggested change
<ItemGroup Condition="'$(_wslcPlatform)' != ''">
<ItemGroup Condition="'$(_wslcPlatform)' != ''">
<Reference Include="wslcsdkcs">
<HintPath>$(MSBuildThisFileDirectory)..\..\runtimes\win-$(_wslcPlatform)\lib\$(TargetFramework)\wslcsdkcs.dll</HintPath>
<Private>true</Private>
</Reference>

Copilot uses AI. Check for mistakes.
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-$(_wslcPlatform)\native\wslcsdk.dll" />
</ItemGroup>
</Otherwise>
</Choose>

<Target Name="WslcValidatePlatform" BeforeTargets="PrepareForBuild" Condition="'$(_wslcInvalidPlatform)' != ''">
<Error Text="wslcsdk.dll could not be copied because the $(_wslcInvalidPlatformProperty) '$(_wslcInvalidPlatform)' is not supported. Only x64 and arm64 platforms are supported." />
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ add_library(Microsoft.WSL.Containers::SDK SHARED IMPORTED GLOBAL)
set_target_properties(Microsoft.WSL.Containers::SDK PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_wslcsdk_include_dir}"
IMPORTED_IMPLIB "${_wslcsdk_lib_dir}/wslcsdk.lib"
IMPORTED_LOCATION "${_wslcsdk_lib_dir}/wslcsdk.dll"
IMPORTED_LOCATION "${_wslcsdk_lib_dir}/native/wslcsdk.dll"
)

# Clean up temporary variables
Expand Down
1 change: 1 addition & 0 deletions packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<package id="Microsoft.NETCore.App.Runtime.win-x64" version="10.0.6" />
<package id="Microsoft.RemoteDesktop.Client.MSRDC.SessionHost" version="1.2.6676" />
<package id="Microsoft.Taef" version="10.100.251104001" targetFramework="native" />
<package id="Microsoft.Windows.CsWinRT" version="2.2.0" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.251108.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.NET.Ref" version="10.0.26100.81" />
<package id="Microsoft.WindowsAppSDK" version="1.8.251106002" />
Expand Down
18 changes: 13 additions & 5 deletions src/windows/WslcSDK/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(SOURCES
WslcsdkPrivate.cpp
)
set(HEADERS
Defaults.h
IOCallback.h
ProgressCallback.h
TerminationCallback.h
Expand All @@ -14,8 +15,15 @@ set(HEADERS
)

add_library(wslcsdk SHARED ${SOURCES} ${HEADERS} wslcsdk.def)
set_target_properties(wslcsdk PROPERTIES EXCLUDE_FROM_ALL FALSE)
add_dependencies(wslcsdk wslserviceidl)
target_link_libraries(wslcsdk ${COMMON_LINK_LIBRARIES} legacy_stdio_definitions common)
target_precompile_headers(wslcsdk REUSE_FROM common)
set_target_properties(wslcsdk PROPERTIES FOLDER windows)
set_target_properties(wslcsdk
PROPERTIES
EXCLUDE_FROM_ALL FALSE
FOLDER windows
)

add_subdirectory(winrt)
add_subdirectory(csharp)

add_dependencies(wslcsdk wslserviceidl wslcsdkwinrt)
target_link_libraries(wslcsdk ${COMMON_LINK_LIBRARIES} legacy_stdio_definitions common wslcsdkwinrt)
target_precompile_headers(wslcsdk REUSE_FROM common)
22 changes: 22 additions & 0 deletions src/windows/WslcSDK/Defaults.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*++

Copyright (c) Microsoft. All rights reserved.

Module Name:

Defaults.h

Abstract:

Contains default values for settings used in the WSL Container SDK.

--*/

#pragma once

constexpr uint32_t s_DefaultCPUCount = 2;
constexpr uint32_t s_DefaultMemoryMB = 2000;
// Maximum value per use with HVSOCKET_CONNECT_TIMEOUT_MAX
constexpr ULONG s_DefaultBootTimeout = 300000;
// Default to 1 GB
constexpr UINT64 s_DefaultStorageSize = 1000 * 1000 * 1000;
Comment on lines +17 to +22
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaults.h uses Windows typedefs (ULONG, UINT64) but doesn’t include a header that defines them, making it sensitive to include order (and harder to reuse from non-Windows-header contexts). Consider switching these constants to fixed-width types (uint32_t/uint64_t) or adding the minimal required include so the header is self-contained.

Suggested change
constexpr uint32_t s_DefaultCPUCount = 2;
constexpr uint32_t s_DefaultMemoryMB = 2000;
// Maximum value per use with HVSOCKET_CONNECT_TIMEOUT_MAX
constexpr ULONG s_DefaultBootTimeout = 300000;
// Default to 1 GB
constexpr UINT64 s_DefaultStorageSize = 1000 * 1000 * 1000;
#include <cstdint>
constexpr uint32_t s_DefaultCPUCount = 2;
constexpr uint32_t s_DefaultMemoryMB = 2000;
// Maximum value per use with HVSOCKET_CONNECT_TIMEOUT_MAX
constexpr uint32_t s_DefaultBootTimeout = 300000;
// Default to 1 GB
constexpr uint64_t s_DefaultStorageSize = 1000 * 1000 * 1000;

Copilot uses AI. Check for mistakes.
29 changes: 29 additions & 0 deletions src/windows/WslcSDK/csharp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
enable_language(CSharp)

add_library(wslcsdkcs SHARED)
configure_csharp_target(wslcsdkcs)

set(WSLCSDK_WINMD "${CMAKE_CURRENT_BINARY_DIR}/../winrt/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslcsdk.winmd")

target_sources(wslcsdkcs
PRIVATE
"${WSLCSDK_WINMD}"
"${CMAKE_CURRENT_SOURCE_DIR}/WinRTActivation.cs"
)

set_source_files_properties(
"${WSLCSDK_WINMD}"
PROPERTIES
GENERATED TRUE
VS_TOOL_OVERRIDE "CsWinRTInputs"
)

set_target_properties(
wslcsdkcs PROPERTIES
FOLDER windows
LINKER_LANGUAGE CSharp
VS_PACKAGE_REFERENCES "Microsoft.Windows.CsWinRT_${CSWINRT_VERSION}"
VS_GLOBAL_CsWinRTIncludes "Microsoft.WSL.Containers"
)

add_dependencies(wslcsdkcs wslcsdkwinrt)
69 changes: 69 additions & 0 deletions src/windows/WslcSDK/csharp/WinRTActivation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (C) Microsoft Corporation. All rights reserved.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using WinRT;

namespace Microsoft.WSL.Containers;

internal static class WinRTActivation
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int DllGetActivationFactoryFn(IntPtr classId, out IntPtr factory);

private static DllGetActivationFactoryFn s_getDllFactory;

[ModuleInitializer]
internal static void Initialize()
{
s_getDllFactory = Marshal.GetDelegateForFunctionPointer<DllGetActivationFactoryFn>(
NativeLibrary.GetExport(
NativeLibrary.Load("wslcsdk.dll", typeof(WinRTActivation).Assembly, DllImportSearchPath.AssemblyDirectory),
"DllGetActivationFactory"));

var previousHandler = ActivationFactory.ActivationHandler;
ActivationFactory.ActivationHandler = (typeName, iid) =>
typeName.StartsWith("Microsoft.WSL.Containers.", StringComparison.Ordinal)
? GetActivationFactory(typeName, iid)
: previousHandler?.Invoke(typeName, iid) ?? IntPtr.Zero;
}

private static IntPtr GetActivationFactory(string typeName, Guid iid)
{
WindowsCreateString(typeName, (uint)typeName.Length, out var hstring);
try
{
if (s_getDllFactory(hstring, out var factory) < 0)
{
return IntPtr.Zero;
}

if (iid == IID_IActivationFactory)
{
return factory;
}

try
{
return Marshal.QueryInterface(factory, ref iid, out var queried) >= 0 ? queried : IntPtr.Zero;
}
finally
{
Marshal.Release(factory);
}
}
finally
{
WindowsDeleteString(hstring);
}
Comment on lines +34 to +59
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WindowsCreateString/WindowsDeleteString return HRESULTs but the code ignores them. If WindowsCreateString fails, hstring may be invalid and the subsequent calls into s_getDllFactory / WindowsDeleteString can misbehave. Capture and validate the return value from these P/Invokes (and ensure WindowsDeleteString is only called when creation succeeded).

Copilot uses AI. Check for mistakes.
}

private static readonly Guid IID_IActivationFactory = new(0x00000035, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

[DllImport("combase.dll", CharSet = CharSet.Unicode)]
private static extern int WindowsCreateString(string sourceString, uint length, out IntPtr hstring);

[DllImport("combase.dll")]
private static extern int WindowsDeleteString(IntPtr hstring);
}
Loading