Skip to content

Commit 71d9429

Browse files
authored
Add scaffolding for C# projection of the SDK (microsoft#40212)
1 parent d56c3d1 commit 71d9429

22 files changed

Lines changed: 764 additions & 30 deletions

CMakeLists.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ find_nuget_package(Microsoft.Windows.SDK.NET.Ref WINDOWS_SDK_DOTNET /)
158158
find_nuget_package(Microsoft.Xaml.Behaviors.WinUI.Managed XAML_BEHAVIORS /)
159159
find_nuget_package(WinUIEx WINUIEX /)
160160

161+
# WSLC C# API packages
162+
find_nuget_package(Microsoft.Windows.CsWinRT CSWINRT /)
163+
161164
set(WSLG_TS_PLUGIN_DLL "WSLDVCPlugin.dll")
162165

163166
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)
@@ -536,10 +539,6 @@ add_subdirectory(src/windows/wslinstall)
536539
add_subdirectory(src/windows/wslc)
537540
add_subdirectory(src/windows/WslcSDK)
538541

539-
if (WSL_BUILD_SDKCS)
540-
add_subdirectory(src/windows/WslcSDK/csharp)
541-
endif()
542-
543542
if (WSL_BUILD_WSL_SETTINGS)
544543
add_subdirectory(src/windows/libwsl)
545544
add_subdirectory(src/windows/wslsettings)

cmake/FindCSharp.cmake

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ function(configure_csharp_target TARGET)
1313
VS_GLOBAL_TargetPlatformMinVersion "${TARGET_PLATFORM_MIN_VERSION}"
1414
VS_GLOBAL_WindowsSdkPackageVersion "${WINDOWS_SDK_DOTNET_VERSION}"
1515
VS_GLOBAL_AppendRuntimeIdentifierToOutputPath false
16-
VS_GLOBAL_GenerateAssemblyInfo false
1716
VS_GLOBAL_TargetLatestRuntimePatch false
1817
DOTNET_SDK "Microsoft.NET.Sdk"
1918
DOTNET_TARGET_FRAMEWORK "net8.0-windows${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}"

cmake/FindIDL.cmake

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,49 @@ function(add_idl target idl_files_with_proxy idl_files_no_proxy)
8181
DEPENDS ${TARGET_OUTPUTS}
8282
SOURCES ${idl_files_with_proxy} ${idl_files_no_proxy})
8383

84-
endfunction()
84+
endfunction()
85+
86+
function(add_idl_winrt target idl_file)
87+
set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE})
88+
file(TO_NATIVE_PATH ${OUTPUT_DIR} OUTPUT_DIR) # midl is picky about path formats
89+
file(MAKE_DIRECTORY ${OUTPUT_DIR})
90+
91+
set(IDL_DEFINITIONS "")
92+
93+
get_directory_property(IDL_DEFS COMPILE_DEFINITIONS )
94+
foreach(e ${IDL_DEFS})
95+
set(IDL_DEFINITIONS ${IDL_DEFINITIONS} /D${e})
96+
endforeach()
97+
98+
string(TOLOWER ${TARGET_PLATFORM} IDL_ENV)
99+
100+
cmake_host_system_information(
101+
RESULT WINDOWS_SDK_DIR
102+
QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Microsoft/Windows Kits/Installed Roots"
103+
VALUE "KitsRoot10")
104+
set(WINRT_METADATA_DIR "${WINDOWS_SDK_DIR}\\UnionMetadata\\${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
105+
set(WINRT_REFERENCE "${WINRT_METADATA_DIR}\\Windows.winmd")
106+
set(WINRT_INCLUDE "${WINDOWS_SDK_DIR}\\Include\\${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}\\winrt")
107+
108+
cmake_path(GET idl_file STEM IDL_NAME)
109+
110+
set(IDL_WINMD ${OUTPUT_DIR}/${IDL_NAME}.winmd)
111+
112+
add_custom_command(
113+
OUTPUT ${IDL_WINMD}
114+
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}
115+
COMMAND cppwinrt -input ${IDL_WINMD} -reference "${WINRT_REFERENCE}" -output ${OUTPUT_DIR} -comp ${OUTPUT_DIR}/implementation_base -optimize -pch precomp.h -prefix
116+
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
117+
DEPENDS ${idl_file}
118+
MAIN_DEPENDENCY ${idl_file}
119+
VERBATIM
120+
)
121+
122+
set_source_files_properties(${IDL_WINMD} PROPERTIES GENERATED TRUE)
123+
124+
add_custom_target(${target}
125+
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}
126+
DEPENDS ${IDL_WINMD}
127+
SOURCES ${idl_file})
128+
129+
endfunction()

nuget/Microsoft.WSL.Containers.nuspec.in

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717
</metadata>
1818
<files>
1919
<file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/>
20-
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdkcs.dll" target="lib\${WSL_NUGET_TARGET_FRAMEWORK}"/>
21-
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdk.lib" target="runtimes\win-x64"/>
22-
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdk.dll" target="runtimes\win-x64\native"/>
23-
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\arm64\Release\wslcsdk.lib" target="runtimes\win-arm64"/>
24-
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\arm64\Release\wslcsdk.dll" target="runtimes\win-arm64\native"/>
20+
21+
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdkcs.dll" target="lib\${WSL_NUGET_TARGET_FRAMEWORK}\"/>
22+
23+
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdk.lib" target="runtimes\win-x64\"/>
24+
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\${CMAKE_BUILD_TYPE}\wslcsdk.dll" target="runtimes\win-x64\native\"/>
25+
26+
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\arm64\${CMAKE_BUILD_TYPE}\wslcsdk.lib" target="runtimes\win-arm64\"/>
27+
<file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\arm64\${CMAKE_BUILD_TYPE}\wslcsdk.dll" target="runtimes\win-arm64\native\"/>
28+
2529
<file src="${CMAKE_SOURCE_DIR_NATIVE}\nuget\Microsoft.WSL.Containers\**" exclude="**\net\**"/>
2630
<file src="${CMAKE_SOURCE_DIR_NATIVE}\nuget\Microsoft.WSL.Containers\build\net\**" target="build\${WSL_NUGET_TARGET_FRAMEWORK}"/>
2731
</files>

packages.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<package id="Microsoft.NETCore.App.Runtime.win-x64" version="10.0.6" />
1313
<package id="Microsoft.RemoteDesktop.Client.MSRDC.SessionHost" version="1.2.6676" />
1414
<package id="Microsoft.Taef" version="10.100.251104001" targetFramework="native" />
15+
<package id="Microsoft.Windows.CsWinRT" version="2.2.0" />
1516
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.251108.1" targetFramework="native" />
1617
<package id="Microsoft.Windows.SDK.NET.Ref" version="10.0.26100.81" />
1718
<package id="Microsoft.WindowsAppSDK" version="1.8.251106002" />

src/windows/WslcSDK/CMakeLists.txt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ set(SOURCES
66
WslcsdkPrivate.cpp
77
)
88
set(HEADERS
9+
Defaults.h
910
IOCallback.h
1011
ProgressCallback.h
1112
TerminationCallback.h
@@ -14,8 +15,18 @@ set(HEADERS
1415
)
1516

1617
add_library(wslcsdk SHARED ${SOURCES} ${HEADERS} wslcsdk.def)
17-
set_target_properties(wslcsdk PROPERTIES EXCLUDE_FROM_ALL FALSE)
18-
add_dependencies(wslcsdk wslserviceidl)
19-
target_link_libraries(wslcsdk ${COMMON_LINK_LIBRARIES} legacy_stdio_definitions common)
20-
target_precompile_headers(wslcsdk REUSE_FROM common)
21-
set_target_properties(wslcsdk PROPERTIES FOLDER windows)
18+
set_target_properties(wslcsdk
19+
PROPERTIES
20+
EXCLUDE_FROM_ALL FALSE
21+
FOLDER windows
22+
)
23+
24+
add_subdirectory(winrt)
25+
26+
if (WSL_BUILD_SDKCS)
27+
add_subdirectory(csharp)
28+
endif()
29+
30+
add_dependencies(wslcsdk wslserviceidl wslcsdkwinrt)
31+
target_link_libraries(wslcsdk ${COMMON_LINK_LIBRARIES} legacy_stdio_definitions common wslcsdkwinrt)
32+
target_precompile_headers(wslcsdk REUSE_FROM common)

src/windows/WslcSDK/Defaults.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*++
2+
3+
Copyright (c) Microsoft. All rights reserved.
4+
5+
Module Name:
6+
7+
Defaults.h
8+
9+
Abstract:
10+
11+
Contains default values for settings used in the WSL Container SDK.
12+
13+
--*/
14+
15+
#pragma once
16+
17+
constexpr uint32_t s_DefaultCPUCount = 2;
18+
constexpr uint32_t s_DefaultMemoryMB = 2000;
19+
// Maximum value per use with HVSOCKET_CONNECT_TIMEOUT_MAX
20+
constexpr ULONG s_DefaultBootTimeout = 300000;
21+
// Default to 1 GB
22+
constexpr UINT64 s_DefaultStorageSize = 1000 * 1000 * 1000;
Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
enable_language(CSharp)
22

3-
add_library(wslcsdkcs SHARED "Projection.cs")
3+
add_library(wslcsdkcs SHARED)
44
configure_csharp_target(wslcsdkcs)
55

6+
set(WSLCSDK_WINMD "${CMAKE_CURRENT_BINARY_DIR}/../winrt/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslcsdk.winmd")
7+
8+
target_sources(wslcsdkcs
9+
PRIVATE
10+
"${WSLCSDK_WINMD}"
11+
"${CMAKE_CURRENT_LIST_DIR}/WinRTActivation.cs"
12+
)
13+
14+
set_source_files_properties(
15+
"${WSLCSDK_WINMD}"
16+
PROPERTIES
17+
GENERATED TRUE
18+
VS_TOOL_OVERRIDE "CsWinRTInputs"
19+
)
20+
621
set_target_properties(
722
wslcsdkcs PROPERTIES
823
FOLDER windows
924
LINKER_LANGUAGE CSharp
10-
VS_GLOBAL_PlatformTarget "AnyCPU"
25+
VS_PACKAGE_REFERENCES "Microsoft.Windows.CsWinRT_${CSWINRT_VERSION}"
26+
VS_GLOBAL_CsWinRTIncludes "Microsoft.WSL.Containers"
1127
)
1228

13-
add_dependencies(wslcsdkcs wslcsdk)
29+
add_dependencies(wslcsdkcs wslcsdkwinrt)
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (C) Microsoft Corporation. All rights reserved.
2+
3+
using System;
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
using WinRT;
7+
8+
namespace Microsoft.WSL.Containers;
9+
10+
internal static class WinRTActivation
11+
{
12+
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
13+
private delegate int DllGetActivationFactoryFn(IntPtr classId, out IntPtr factory);
14+
15+
private static DllGetActivationFactoryFn s_getDllFactory;
16+
17+
// Overrides the WinRT activation to route activation of our types through our native DLL.
18+
#pragma warning disable CA2255
19+
// CA2255 warns against using ModuleInitializer to discourage using it without thinking through some possible issues.
20+
// For example, unintuitive timing (it runs the first time a type is used, not when the module is loaded or inspected),
21+
// and limiting possible optimizations (if the module is loaded, but nothing that depended on the initializer is ever used).
22+
// In this case, we only need it to run before using any of our types, and everything in the assembly needs this
23+
// initialization, so it's fine.
24+
[ModuleInitializer]
25+
#pragma warning restore CA2255
26+
internal static void Initialize()
27+
{
28+
// Get a pointer to the function in the DLL that creates activation factories.
29+
s_getDllFactory = Marshal.GetDelegateForFunctionPointer<DllGetActivationFactoryFn>(
30+
NativeLibrary.GetExport(
31+
NativeLibrary.Load("wslcsdk.dll", typeof(WinRTActivation).Assembly, DllImportSearchPath.AssemblyDirectory),
32+
"DllGetActivationFactory"));
33+
34+
// Custom WinRT activation handler:
35+
// If it is one of our types, we resolve it with our native DLL. Otherwise, we defer to the previous handler if one exists.
36+
var previousHandler = ActivationFactory.ActivationHandler;
37+
ActivationFactory.ActivationHandler = (typeName, iid) =>
38+
{
39+
if (typeName.StartsWith("Microsoft.WSL.Containers.", StringComparison.Ordinal))
40+
{
41+
return GetActivationFactory(typeName, iid);
42+
}
43+
44+
if (previousHandler != null)
45+
{
46+
return previousHandler(typeName, iid);
47+
}
48+
49+
return IntPtr.Zero;
50+
};
51+
52+
}
53+
54+
private static IntPtr GetActivationFactory(string typeName, Guid iid)
55+
{
56+
// Convert the type name to HSTRING
57+
WindowsCreateString(typeName, (uint)typeName.Length, out var hstring);
58+
try
59+
{
60+
if (s_getDllFactory(hstring, out var factory) < 0)
61+
{
62+
return IntPtr.Zero;
63+
}
64+
65+
if (iid == IID_IActivationFactory)
66+
{
67+
return factory;
68+
}
69+
70+
try
71+
{
72+
if (Marshal.QueryInterface(factory, ref iid, out var queried) >= 0)
73+
{
74+
return queried;
75+
}
76+
else
77+
{
78+
return IntPtr.Zero;
79+
}
80+
}
81+
finally
82+
{
83+
Marshal.Release(factory);
84+
}
85+
}
86+
finally
87+
{
88+
WindowsDeleteString(hstring);
89+
}
90+
}
91+
92+
private static readonly Guid IID_IActivationFactory = new(0x00000035, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
93+
94+
[DllImport("combase.dll", CharSet = CharSet.Unicode)]
95+
private static extern int WindowsCreateString(string sourceString, uint length, out IntPtr hstring);
96+
97+
[DllImport("combase.dll")]
98+
private static extern int WindowsDeleteString(IntPtr hstring);
99+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
add_idl_winrt(wslcsdkwinrtidl "wslcsdk.idl")
2+
set_target_properties(wslcsdkwinrtidl PROPERTIES FOLDER windows)
3+
4+
set(SOURCES
5+
Session.cpp
6+
SessionSettings.cpp
7+
VhdRequirements.cpp
8+
)
9+
10+
set(HEADERS
11+
Helpers.h
12+
Session.h
13+
SessionSettings.h
14+
VhdRequirements.h
15+
)
16+
17+
add_library(wslcsdkwinrt STATIC ${SOURCES} ${HEADERS})
18+
add_dependencies(wslcsdkwinrt wslcsdkwinrtidl)
19+
20+
set(MODULE_G_CPP ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/module.g.cpp)
21+
target_sources(wslcsdkwinrt PRIVATE ${MODULE_G_CPP})
22+
set_source_files_properties(
23+
${MODULE_G_CPP}
24+
PROPERTIES
25+
GENERATED TRUE)
26+
27+
target_precompile_headers(wslcsdkwinrt PRIVATE precomp.h)
28+
target_include_directories(wslcsdkwinrt PRIVATE
29+
${CMAKE_CURRENT_BINARY_DIR}/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}
30+
${CMAKE_SOURCE_DIR}/src/windows/WslcSDK
31+
)
32+
33+
set_target_properties(
34+
wslcsdkwinrt
35+
PROPERTIES
36+
FOLDER windows
37+
EXCLUDE_FROM_ALL FALSE
38+
)

0 commit comments

Comments
 (0)