@samitouri / QOSAMI-WSL / commits / ed3d63fb

Apply WinRT API review feedback to WSLC SDK projection (#40847)

Apply WinRT API review feedback to WSLC SDK projection (#40847) * Apply WinRT API review feedback to WSLC SDK projection Address API design review recommendations for the Microsoft.WSL.Containers WinRT projection. C SDK layer is unchanged; all changes are projection-only. Naming: - Drop "Flags" suffix: DeleteContainerFlags -> DeleteContainerOption, ComponentFlags -> Component - Rename MemoryMB -> MemorySizeInMB, CmdLine -> CommandLine, SizeBytes/SizeInBytes -> Size Type shape: - Replace SessionFeatureFlags/ContainerFlags enums with individual boolean properties (IsGpuEnabled, IsAutoRemoveEnabled, IsPrivileged) - Make Component a non-flags enum; GetMissingComponents() now returns IVectorView<Component> - Replace VhdOptions OwnerUid/OwnerGid with a VhdOwner struct exposed via IReference<VhdOwner> Owner - Convert Images property to GetImages() method Lifetime: - Implement IClosable on Session, Container, and Process; final_release routes through Close() - Guard Container handle access with EnsureNotClosed() (RO_E_CLOSED) Async: - Add synchronous variants for PullImage, ImportImage, LoadImage, PushImage, and InstallWithDependencies, implemented directly against the C SDK per the synchronous API guidance Add TODO for structured Inspect() return. Update WinRT tests for all renames and shape changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Flor Chacón committed Jun 22, 2026 at 17:50 UTC ed3d63fb14a03a72676386f56bd5aaa93535d6f5
23 files changed +412 -216
src/windows/WslcSDK/winrt/Container.cpp
+26 -3
@@ -46,13 +46,13 @@ void Container::Start()
46 }
47
48 wil::unique_cotaskmem_string errorMessage;
49 - auto hr = WslcStartContainer(m_container.get(), startFlags, errorMessage.put());
49 + auto hr = WslcStartContainer(ToHandle(), startFlags, errorMessage.put());
50 THROW_MSG_IF_FAILED(hr, errorMessage);
51
52 if (m_initProcess)
53 {
54 WslcProcess initHandle;
55 - winrt::check_hresult(WslcGetContainerInitProcess(m_container.get(), &initHandle));
55 + winrt::check_hresult(WslcGetContainerInitProcess(ToHandle(), &initHandle));
56 m_initProcess->AttachHandle(initHandle);
57 }
58 }
@@ -75,7 +75,7 @@ void Container::Stop(winrt::Microsoft::WSL::Containers::Signal const& signal, Ti
75 THROW_MSG_IF_FAILED(hr, errorMessage);
76 }
77
78 -void Container::Delete(winrt::Microsoft::WSL::Containers::DeleteContainerFlags const& flags)
78 +void Container::Delete(winrt::Microsoft::WSL::Containers::DeleteContainerOption const& flags)
79 {
80 wil::unique_cotaskmem_string errorMessage;
81 auto hr = WslcDeleteContainer(ToHandle(), static_cast<WslcDeleteContainerFlags>(flags), errorMessage.put());
@@ -118,9 +118,32 @@ winrt::Microsoft::WSL::Containers::ContainerState Container::State()
118 return static_cast<winrt::Microsoft::WSL::Containers::ContainerState>(state);
119 }
120
121 +void Container::EnsureNotClosed() const
122 +{
123 + if (!m_container)
124 + {
125 + throw winrt::hresult_error(RO_E_CLOSED, L"Container has been closed");
126 + }
127 +}
128 +
129 WslcContainer Container::ToHandle()
130 {
131 + EnsureNotClosed();
132 return m_container.get();
133 }
134
135 +void Container::Close()
136 +{
137 + m_initProcess = nullptr;
138 +
139 + // Methods called after Close() will fail due to EnsureNotClosed().
140 + m_container.reset();
141 +}
142 +
143 +void Container::final_release(std::unique_ptr<Container> self)
144 +{
145 + // Ensure cleanup when refcount drops to zero even if Close() was not called explicitly.
146 + self->Close();
147 +}
148 +
149 } // namespace winrt::Microsoft::WSL::Containers::implementation
src/windows/WslcSDK/winrt/Container.h
+6 -1
@@ -25,16 +25,21 @@ struct Container : ContainerT<Container>
25
26 void Start();
27 void Stop(winrt::Microsoft::WSL::Containers::Signal const& signal, winrt::Windows::Foundation::TimeSpan timeout);
28 - void Delete(winrt::Microsoft::WSL::Containers::DeleteContainerFlags const& flags);
28 + void Delete(winrt::Microsoft::WSL::Containers::DeleteContainerOption const& flags);
29 winrt::Microsoft::WSL::Containers::Process CreateProcess(winrt::Microsoft::WSL::Containers::ProcessSettings const& newProcessSettings);
30 hstring Inspect();
31 hstring Id();
32 winrt::Microsoft::WSL::Containers::Process InitProcess();
33 winrt::Microsoft::WSL::Containers::ContainerState State();
34
35 + void Close();
36 + static void final_release(std::unique_ptr<Container> self);
37 +
38 WslcContainer ToHandle();
39
40 private:
41 + void EnsureNotClosed() const;
42 +
43 winrt::com_ptr<implementation::Process> m_initProcess;
44
45 // Releasing the container handle will end the processes and disconnect the callbacks.
src/windows/WslcSDK/winrt/ContainerSettings.cpp
+36 -6
@@ -126,19 +126,49 @@ void ContainerSettings::DomainName(hstring const& value)
126 m_domainName = winrt::to_string(value);
127 }
128
129 -ContainerFlags ContainerSettings::Flags()
129 +bool ContainerSettings::EnableAutoRemove()
130 {
131 - return m_flags;
131 + return WI_IsFlagSet(m_containerFlags, WSLC_CONTAINER_FLAG_AUTO_REMOVE);
132 }
133
134 -void ContainerSettings::Flags(ContainerFlags const& value)
134 +void ContainerSettings::EnableAutoRemove(bool value)
135 {
136 if (m_containerSettings)
137 {
138 - throw winrt::hresult_illegal_state_change(L"Cannot change container flags after container has been initialized");
138 + throw winrt::hresult_illegal_state_change(L"Cannot change container settings after container has been initialized");
139 }
140
141 - m_flags = value;
141 + WI_UpdateFlag(m_containerFlags, WSLC_CONTAINER_FLAG_AUTO_REMOVE, value);
142 +}
143 +
144 +bool ContainerSettings::EnableGpu()
145 +{
146 + return WI_IsFlagSet(m_containerFlags, WSLC_CONTAINER_FLAG_ENABLE_GPU);
147 +}
148 +
149 +void ContainerSettings::EnableGpu(bool value)
150 +{
151 + if (m_containerSettings)
152 + {
153 + throw winrt::hresult_illegal_state_change(L"Cannot change container settings after container has been initialized");
154 + }
155 +
156 + WI_UpdateFlag(m_containerFlags, WSLC_CONTAINER_FLAG_ENABLE_GPU, value);
157 +}
158 +
159 +bool ContainerSettings::Privileged()
160 +{
161 + return WI_IsFlagSet(m_containerFlags, WSLC_CONTAINER_FLAG_PRIVILEGED);
162 +}
163 +
164 +void ContainerSettings::Privileged(bool value)
165 +{
166 + if (m_containerSettings)
167 + {
168 + throw winrt::hresult_illegal_state_change(L"Cannot change container settings after container has been initialized");
169 + }
170 +
171 + WI_UpdateFlag(m_containerFlags, WSLC_CONTAINER_FLAG_PRIVILEGED, value);
172 }
173
174 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::WSL::Containers::ContainerPortMapping> ContainerSettings::PortMappings()
@@ -234,7 +264,7 @@ WslcContainerSettings* ContainerSettings::ToStructPointer()
264 winrt::check_hresult(WslcSetContainerSettingsDomainName(m_containerSettings.get(), m_domainName.c_str()));
265 }
266
237 - winrt::check_hresult(WslcSetContainerSettingsFlags(m_containerSettings.get(), static_cast<WslcContainerFlags>(m_flags)));
267 + winrt::check_hresult(WslcSetContainerSettingsFlags(m_containerSettings.get(), m_containerFlags));
268
269 if (m_portMappings.Size() > 0)
270 {
src/windows/WslcSDK/winrt/ContainerSettings.h
+7 -3
@@ -35,8 +35,12 @@ struct ContainerSettings : ContainerSettingsT<ContainerSettings>
35 void HostName(hstring const& value);
36 hstring DomainName();
37 void DomainName(hstring const& value);
38 - winrt::Microsoft::WSL::Containers::ContainerFlags Flags();
39 - void Flags(winrt::Microsoft::WSL::Containers::ContainerFlags const& value);
38 + bool EnableAutoRemove();
39 + void EnableAutoRemove(bool value);
40 + bool EnableGpu();
41 + void EnableGpu(bool value);
42 + bool Privileged();
43 + void Privileged(bool value);
44 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::WSL::Containers::ContainerPortMapping> PortMappings();
45 void PortMappings(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::WSL::Containers::ContainerPortMapping> const& value);
46 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::WSL::Containers::ContainerVolume> Volumes();
@@ -53,7 +57,7 @@ private:
57 winrt::Windows::Foundation::IReference<winrt::Microsoft::WSL::Containers::ContainerNetworkingMode> m_networkingMode{nullptr};
58 std::string m_hostName;
59 std::string m_domainName;
56 - winrt::Microsoft::WSL::Containers::ContainerFlags m_flags{winrt::Microsoft::WSL::Containers::ContainerFlags::None};
60 + WslcContainerFlags m_containerFlags{WSLC_CONTAINER_FLAG_NONE};
61 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::WSL::Containers::ContainerPortMapping> m_portMappings{
62 winrt::single_threaded_vector<winrt::Microsoft::WSL::Containers::ContainerPortMapping>()};
63 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::WSL::Containers::ContainerVolume> m_volumes{
src/windows/WslcSDK/winrt/ImageInfo.cpp
+3 -3
@@ -20,7 +20,7 @@ namespace winrt::Microsoft::WSL::Containers::implementation {
20 ImageInfo::ImageInfo(WslcImageInfo const& info)
21 {
22 m_name = winrt::to_hstring(info.name);
23 - m_sizeBytes = info.sizeBytes;
23 + m_size = info.sizeBytes;
24 m_createdTimestamp = winrt::clock::from_time_t(static_cast<time_t>(info.createdUnixTime));
25
26 winrt::Windows::Storage::Streams::DataWriter writer;
@@ -38,9 +38,9 @@ winrt::Windows::Storage::Streams::IBuffer ImageInfo::Sha256()
38 return m_sha256;
39 }
40
41 -uint64_t ImageInfo::SizeBytes()
41 +uint64_t ImageInfo::Size()
42 {
43 - return m_sizeBytes;
43 + return m_size;
44 }
45
46 winrt::Windows::Foundation::DateTime ImageInfo::CreatedTimestamp()
src/windows/WslcSDK/winrt/ImageInfo.h
+5 -5
@@ -24,14 +24,14 @@ struct ImageInfo : ImageInfoT<ImageInfo>
24
25 hstring Name();
26 winrt::Windows::Storage::Streams::IBuffer Sha256();
27 - uint64_t SizeBytes();
27 + uint64_t Size();
28 winrt::Windows::Foundation::DateTime CreatedTimestamp();
29
30 private:
31 - hstring m_name;
32 - winrt::Windows::Storage::Streams::IBuffer m_sha256;
33 - uint64_t m_sizeBytes;
34 - winrt::Windows::Foundation::DateTime m_createdTimestamp;
31 + hstring m_name{};
32 + winrt::Windows::Storage::Streams::IBuffer m_sha256{};
33 + uint64_t m_size{};
34 + winrt::Windows::Foundation::DateTime m_createdTimestamp{};
35 };
36 } // namespace winrt::Microsoft::WSL::Containers::implementation
37
src/windows/WslcSDK/winrt/InstallProgress.cpp
+2 -2
@@ -17,12 +17,12 @@ Abstract:
17 #include "Microsoft.WSL.Containers.InstallProgress.g.cpp"
18
19 namespace winrt::Microsoft::WSL::Containers::implementation {
20 -InstallProgress::InstallProgress(ComponentFlags component, uint32_t progress, uint32_t total) :
20 +InstallProgress::InstallProgress(winrt::Microsoft::WSL::Containers::Component component, uint32_t progress, uint32_t total) :
21 m_component(component), m_progress(progress), m_total(total)
22 {
23 }
24
25 -ComponentFlags InstallProgress::Component()
25 +winrt::Microsoft::WSL::Containers::Component InstallProgress::Component()
26 {
27 return m_component;
28 }
src/windows/WslcSDK/winrt/InstallProgress.h
+3 -3
@@ -20,14 +20,14 @@ namespace winrt::Microsoft::WSL::Containers::implementation {
20 struct InstallProgress : InstallProgressT<InstallProgress>
21 {
22 InstallProgress() = default;
23 - InstallProgress(winrt::Microsoft::WSL::Containers::ComponentFlags component, uint32_t progress, uint32_t total);
23 + InstallProgress(winrt::Microsoft::WSL::Containers::Component component, uint32_t progress, uint32_t total);
24
25 - winrt::Microsoft::WSL::Containers::ComponentFlags Component();
25 + winrt::Microsoft::WSL::Containers::Component Component();
26 uint32_t Progress();
27 uint32_t Total();
28
29 private:
30 - winrt::Microsoft::WSL::Containers::ComponentFlags m_component{};
30 + winrt::Microsoft::WSL::Containers::Component m_component{};
31 uint32_t m_progress{};
32 uint32_t m_total{};
33 };
src/windows/WslcSDK/winrt/Process.cpp
+21 -2
@@ -141,10 +141,10 @@ void Process::EnsureCanStart() const
141 throw winrt::hresult_illegal_method_call(L"Start() cannot be called on the init process, it is started by the container");
142 }
143
144 - auto cmdLine = GetImplementation(m_settings)->CmdLine();
144 + auto cmdLine = GetImplementation(m_settings)->CommandLine();
145 if (!cmdLine || cmdLine.Size() == 0)
146 {
147 - throw winrt::hresult_invalid_argument(L"Process requires a non-empty CmdLine to start");
147 + throw winrt::hresult_invalid_argument(L"Process requires a non-empty CommandLine to start");
148 }
149 }
150
@@ -261,4 +261,23 @@ WslcProcess Process::ToHandle()
261 EnsureStarted();
262 return m_process.get();
263 }
264 +
265 +void Process::Close()
266 +{
267 + if (m_waitForExitAction)
268 + {
269 + m_waitForExitAction.Cancel();
270 + m_waitForExitAction = nullptr;
271 + }
272 +
273 + // Methods called after Close() will fail due to EnsureStarted().
274 + m_process.reset();
275 +}
276 +
277 +void Process::final_release(std::unique_ptr<Process> self)
278 +{
279 + // Ensure cleanup when refcount drops to zero even if Close() was not called explicitly.
280 + self->Close();
281 +}
282 +
283 } // namespace winrt::Microsoft::WSL::Containers::implementation
src/windows/WslcSDK/winrt/Process.h
+3 -9
@@ -37,19 +37,13 @@ struct Process : ProcessT<Process>
37 winrt::event_token Exited(winrt::Microsoft::WSL::Containers::ProcessExitHandler const& handler);
38 void Exited(winrt::event_token const& token) noexcept;
39
40 + void Close();
41 + static void final_release(std::unique_ptr<Process> self);
42 +
43 WslcProcess ToHandle();
44 ProcessOutputMode OutputMode();
45 void AttachHandle(WslcProcess handle);
46
44 - static void final_release(std::unique_ptr<Process> self)
45 - {
46 - self->m_process.reset();
47 - if (self->m_waitForExitAction)
48 - {
49 - self->m_waitForExitAction.Cancel();
50 - }
51 - }
52 -
47 private:
48 void EnsureStarted() const;
49 void EnsureNotStarted() const;
src/windows/WslcSDK/winrt/ProcessSettings.cpp
+11 -11
@@ -51,12 +51,12 @@ void ProcessSettings::WorkingDirectory(hstring const& value)
51 m_workingDirectory = winrt::to_string(value);
52 }
53
54 -winrt::Windows::Foundation::Collections::IVector<hstring> ProcessSettings::CmdLine()
54 +winrt::Windows::Foundation::Collections::IVector<hstring> ProcessSettings::CommandLine()
55 {
56 - return m_cmdLine;
56 + return m_commandLine;
57 }
58
59 -void ProcessSettings::CmdLine(winrt::Windows::Foundation::Collections::IVector<hstring> const& value)
59 +void ProcessSettings::CommandLine(winrt::Windows::Foundation::Collections::IVector<hstring> const& value)
60 {
61 if (m_processSettings)
62 {
@@ -65,10 +65,10 @@ void ProcessSettings::CmdLine(winrt::Windows::Foundation::Collections::IVector<h
65
66 if (!value)
67 {
68 - throw winrt::hresult_error(E_POINTER, L"CmdLine cannot be null");
68 + throw winrt::hresult_error(E_POINTER, L"CommandLine cannot be null");
69 }
70
71 - m_cmdLine = value;
71 + m_commandLine = value;
72 }
73
74 winrt::Windows::Foundation::Collections::IMap<hstring, hstring> ProcessSettings::EnvironmentVariables()
@@ -121,16 +121,16 @@ WslcProcessSettings* ProcessSettings::ToStructPointer()
121 winrt::check_hresult(WslcSetProcessSettingsWorkingDirectory(m_processSettings.get(), m_workingDirectory.c_str()));
122 }
123
124 - if (m_cmdLine && m_cmdLine.Size() > 0)
124 + if (m_commandLine && m_commandLine.Size() > 0)
125 {
126 - auto argc = m_cmdLine.Size();
127 - m_cmdLineStrings = StringArray{argc};
128 - for (auto const& arg : m_cmdLine)
126 + auto argc = m_commandLine.Size();
127 + m_commandLineStrings = StringArray{argc};
128 + for (auto const& arg : m_commandLine)
129 {
130 - m_cmdLineStrings.Add(winrt::to_string(arg));
130 + m_commandLineStrings.Add(winrt::to_string(arg));
131 }
132
133 - winrt::check_hresult(WslcSetProcessSettingsCmdLine(m_processSettings.get(), m_cmdLineStrings.GetRawPointer(), argc));
133 + winrt::check_hresult(WslcSetProcessSettingsCmdLine(m_processSettings.get(), m_commandLineStrings.GetRawPointer(), argc));
134 }
135
136 if (m_environmentVariables.Size() > 0)
src/windows/WslcSDK/winrt/ProcessSettings.h
+4 -4
@@ -36,8 +36,8 @@ struct ProcessSettings : ProcessSettingsT<ProcessSettings>
36
37 hstring WorkingDirectory();
38 void WorkingDirectory(hstring const& value);
39 - winrt::Windows::Foundation::Collections::IVector<hstring> CmdLine();
40 - void CmdLine(winrt::Windows::Foundation::Collections::IVector<hstring> const& value);
39 + winrt::Windows::Foundation::Collections::IVector<hstring> CommandLine();
40 + void CommandLine(winrt::Windows::Foundation::Collections::IVector<hstring> const& value);
41 winrt::Windows::Foundation::Collections::IMap<hstring, hstring> EnvironmentVariables();
42 void EnvironmentVariables(winrt::Windows::Foundation::Collections::IMap<hstring, hstring> const& value);
43 winrt::Microsoft::WSL::Containers::ProcessOutputMode OutputMode();
@@ -47,12 +47,12 @@ struct ProcessSettings : ProcessSettingsT<ProcessSettings>
47
48 private:
49 std::string m_workingDirectory;
50 - winrt::Windows::Foundation::Collections::IVector<hstring> m_cmdLine{winrt::single_threaded_vector<hstring>()};
50 + winrt::Windows::Foundation::Collections::IVector<hstring> m_commandLine{winrt::single_threaded_vector<hstring>()};
51 winrt::Windows::Foundation::Collections::IMap<hstring, hstring> m_environmentVariables{winrt::single_threaded_map<hstring, hstring>()};
52 winrt::Microsoft::WSL::Containers::ProcessOutputMode m_outputMode{winrt::Microsoft::WSL::Containers::ProcessOutputMode::Discard};
53
54 std::unique_ptr<WslcProcessSettings> m_processSettings;
55 - StringArray m_cmdLineStrings;
55 + StringArray m_commandLineStrings;
56 StringArray m_envStrings;
57 };
58 } // namespace winrt::Microsoft::WSL::Containers::implementation
src/windows/WslcSDK/winrt/Session.cpp
+89 -1
@@ -93,6 +93,22 @@ winrt::Microsoft::WSL::Containers::Container Session::CreateContainer(winrt::Mic
93 return winrt::make<implementation::Container>(ToHandle(), containerSettings);
94 }
95
96 +void Session::PullImage(winrt::Microsoft::WSL::Containers::PullImageOptions const& options)
97 +{
98 + if (!options)
99 + {
100 + throw winrt::hresult_error(E_POINTER, L"Options for pull cannot be null");
101 + }
102 +
103 + EnsureStarted();
104 +
105 + auto pullOptions = GetStruct(options);
106 +
107 + wil::unique_cotaskmem_string errorMessage;
108 + auto hr = WslcPullSessionImage(ToHandle(), &pullOptions, errorMessage.put());
109 + THROW_MSG_IF_FAILED(hr, errorMessage);
110 +}
111 +
112 IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> Session::PullImageAsync(winrt::Microsoft::WSL::Containers::PullImageOptions options)
113 {
114 if (!options)
@@ -116,6 +132,29 @@ IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> Sessi
132 THROW_MSG_IF_FAILED(hr, errorMessage);
133 }
134
135 +void Session::ImportImage(hstring const& path, hstring const& imageName)
136 +{
137 + if (path.empty())
138 + {
139 + throw winrt::hresult_invalid_argument(L"Path cannot be empty");
140 + }
141 +
142 + if (imageName.empty())
143 + {
144 + throw winrt::hresult_invalid_argument(L"Image name cannot be empty");
145 + }
146 +
147 + EnsureStarted();
148 +
149 + auto name = winrt::to_string(imageName);
150 +
151 + WslcImportImageOptions importOptions{};
152 +
153 + wil::unique_cotaskmem_string errorMessage;
154 + auto hr = WslcImportSessionImageFromFile(ToHandle(), name.c_str(), path.c_str(), &importOptions, errorMessage.put());
155 + THROW_MSG_IF_FAILED(hr, errorMessage);
156 +}
157 +
158 IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> Session::ImportImageAsync(hstring path, hstring imageName)
159 {
160 if (path.empty())
@@ -146,6 +185,22 @@ IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> Sessi
185 THROW_MSG_IF_FAILED(hr, errorMessage);
186 }
187
188 +void Session::LoadImage(hstring const& path)
189 +{
190 + if (path.empty())
191 + {
192 + throw winrt::hresult_invalid_argument(L"Path cannot be empty");
193 + }
194 +
195 + EnsureStarted();
196 +
197 + WslcLoadImageOptions loadOptions{};
198 +
199 + wil::unique_cotaskmem_string errorMessage;
200 + auto hr = WslcLoadSessionImageFromFile(ToHandle(), path.c_str(), &loadOptions, errorMessage.put());
201 + THROW_MSG_IF_FAILED(hr, errorMessage);
202 +}
203 +
204 IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> Session::LoadImageAsync(hstring path)
205 {
206 if (path.empty())
@@ -169,6 +224,22 @@ IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> Sessi
224 THROW_MSG_IF_FAILED(hr, errorMessage);
225 }
226
227 +void Session::PushImage(winrt::Microsoft::WSL::Containers::PushImageOptions const& options)
228 +{
229 + if (!options)
230 + {
231 + throw winrt::hresult_error(E_POINTER, L"Options for push cannot be null");
232 + }
233 +
234 + EnsureStarted();
235 +
236 + auto pushOptions = GetStruct(options);
237 +
238 + wil::unique_cotaskmem_string errorMessage;
239 + auto hr = WslcPushSessionImage(ToHandle(), &pushOptions, errorMessage.put());
240 + THROW_MSG_IF_FAILED(hr, errorMessage);
241 +}
242 +
243 IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> Session::PushImageAsync(winrt::Microsoft::WSL::Containers::PushImageOptions options)
244 {
245 if (!options)
@@ -295,7 +366,7 @@ void Session::ProcessCrashed(winrt::event_token const& token) noexcept
366 m_crashDumpEvent.remove(token);
367 }
368
298 -IVectorView<winrt::Microsoft::WSL::Containers::ImageInfo> Session::Images()
369 +IVectorView<winrt::Microsoft::WSL::Containers::ImageInfo> Session::GetImages()
370 {
371 EnsureStarted();
372
@@ -318,6 +389,23 @@ WslcSession Session::ToHandle()
389 return m_session.get();
390 }
391
392 +void Session::Close()
393 +{
394 + m_terminationWait.reset();
395 + m_terminationEvent.reset();
396 + m_crashDumpSubscription.reset();
397 +
398 + // Methods called after Close() will fail due to EnsureStarted().
399 + m_settings = nullptr;
400 + m_session.reset();
401 +}
402 +
403 +void Session::final_release(std::unique_ptr<Session> self)
404 +{
405 + // Ensure cleanup when refcount drops to zero even if Close() was not called explicitly.
406 + self->Close();
407 +}
408 +
409 void CALLBACK Session::OnTerminated(PTP_CALLBACK_INSTANCE /* instance */, PVOID context, PTP_WAIT /* wait */, TP_WAIT_RESULT /* waitResult */) noexcept
410 {
411 try
src/windows/WslcSDK/winrt/Session.h
+8 -1
@@ -24,10 +24,14 @@ struct Session : SessionT<Session>
24 void Start();
25 void Terminate();
26 winrt::Microsoft::WSL::Containers::Container CreateContainer(winrt::Microsoft::WSL::Containers::ContainerSettings const& containerSettings);
27 + void PullImage(winrt::Microsoft::WSL::Containers::PullImageOptions const& options);
28 winrt::Windows::Foundation::IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> PullImageAsync(
29 winrt::Microsoft::WSL::Containers::PullImageOptions options);
30 + void ImportImage(hstring const& path, hstring const& imageName);
31 winrt::Windows::Foundation::IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> ImportImageAsync(hstring path, hstring imageName);
32 + void LoadImage(hstring const& path);
33 winrt::Windows::Foundation::IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> LoadImageAsync(hstring path);
34 + void PushImage(winrt::Microsoft::WSL::Containers::PushImageOptions const& options);
35 winrt::Windows::Foundation::IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::ImageProgress> PushImageAsync(
36 winrt::Microsoft::WSL::Containers::PushImageOptions options);
37 void DeleteImage(hstring const& nameOrId);
@@ -35,12 +39,15 @@ struct Session : SessionT<Session>
39 void CreateVhdVolume(winrt::Microsoft::WSL::Containers::VhdOptions const& options);
40 void DeleteVhdVolume(hstring const& name);
41 hstring Authenticate(winrt::Windows::Foundation::Uri const& serverAddress, hstring const& username, hstring const& password);
38 - winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::WSL::Containers::ImageInfo> Images();
42 + winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::WSL::Containers::ImageInfo> GetImages();
43 winrt::event_token Terminated(winrt::Microsoft::WSL::Containers::SessionTerminationHandler const& handler);
44 void Terminated(winrt::event_token const& token) noexcept;
45 winrt::event_token ProcessCrashed(winrt::Microsoft::WSL::Containers::ProcessCrashHandler const& handler);
46 void ProcessCrashed(winrt::event_token const& token) noexcept;
47
48 + void Close();
49 + static void final_release(std::unique_ptr<Session> self);
50 +
51 WslcSession ToHandle();
52
53 private:
src/windows/WslcSDK/winrt/SessionSettings.cpp
+12 -12
@@ -93,12 +93,12 @@ void SessionSettings::CpuCount(IReference<uint32_t> const& value)
93 m_cpuCount = value;
94 }
95
96 -IReference<uint32_t> SessionSettings::MemoryMB()
96 +IReference<uint32_t> SessionSettings::MemorySizeInMB()
97 {
98 - return m_memoryMB;
98 + return m_memorySizeInMB;
99 }
100
101 -void SessionSettings::MemoryMB(IReference<uint32_t> const& value)
101 +void SessionSettings::MemorySizeInMB(IReference<uint32_t> const& value)
102 {
103 if (m_sessionSettings)
104 {
@@ -110,7 +110,7 @@ void SessionSettings::MemoryMB(IReference<uint32_t> const& value)
110 throw hresult_invalid_argument(L"Memory size cannot be 0");
111 }
112
113 - m_memoryMB = value;
113 + m_memorySizeInMB = value;
114 }
115
116 IReference<TimeSpan> SessionSettings::Timeout()
@@ -168,19 +168,19 @@ void SessionSettings::VhdRequirements(winrt::Microsoft::WSL::Containers::VhdOpti
168 m_vhdRequirements = value;
169 }
170
171 -winrt::Microsoft::WSL::Containers::SessionFeatureFlags SessionSettings::FeatureFlags()
171 +bool SessionSettings::EnableGpu()
172 {
173 - return m_featureFlags;
173 + return WI_IsFlagSet(m_featureFlags, WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU);
174 }
175
176 -void SessionSettings::FeatureFlags(winrt::Microsoft::WSL::Containers::SessionFeatureFlags const& value)
176 +void SessionSettings::EnableGpu(bool value)
177 {
178 if (m_sessionSettings)
179 {
180 - throw hresult_illegal_state_change(L"Cannot change feature flags after session has been initialized");
180 + throw hresult_illegal_state_change(L"Cannot change GPU setting after session has been initialized");
181 }
182
183 - m_featureFlags = value;
183 + WI_UpdateFlag(m_featureFlags, WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU, value);
184 }
185
186 WslcSessionSettings* SessionSettings::ToStructPointer()
@@ -198,9 +198,9 @@ WslcSessionSettings* SessionSettings::ToStructPointer()
198 winrt::check_hresult(WslcSetSessionSettingsCpuCount(m_sessionSettings.get(), m_cpuCount.Value()));
199 }
200
201 - if (m_memoryMB)
201 + if (m_memorySizeInMB)
202 {
203 - winrt::check_hresult(WslcSetSessionSettingsMemory(m_sessionSettings.get(), m_memoryMB.Value()));
203 + winrt::check_hresult(WslcSetSessionSettingsMemory(m_sessionSettings.get(), m_memorySizeInMB.Value()));
204 }
205
206 if (m_timeout)
@@ -214,7 +214,7 @@ WslcSessionSettings* SessionSettings::ToStructPointer()
214 winrt::check_hresult(WslcSetSessionSettingsVhd(m_sessionSettings.get(), GetStructPointer(m_vhdRequirements)));
215 }
216
217 - winrt::check_hresult(WslcSetSessionSettingsFeatureFlags(m_sessionSettings.get(), static_cast<WslcSessionFeatureFlags>(m_featureFlags)));
217 + winrt::check_hresult(WslcSetSessionSettingsFeatureFlags(m_sessionSettings.get(), m_featureFlags));
218
219 return m_sessionSettings.get();
220 }
src/windows/WslcSDK/winrt/SessionSettings.h
+6 -6
@@ -29,14 +29,14 @@ struct SessionSettings : SessionSettingsT<SessionSettings>
29 void StoragePath(hstring const& value);
30 winrt::Windows::Foundation::IReference<uint32_t> CpuCount();
31 void CpuCount(winrt::Windows::Foundation::IReference<uint32_t> const& value);
32 - winrt::Windows::Foundation::IReference<uint32_t> MemoryMB();
33 - void MemoryMB(winrt::Windows::Foundation::IReference<uint32_t> const& value);
32 + winrt::Windows::Foundation::IReference<uint32_t> MemorySizeInMB();
33 + void MemorySizeInMB(winrt::Windows::Foundation::IReference<uint32_t> const& value);
34 winrt::Windows::Foundation::IReference<winrt::Windows::Foundation::TimeSpan> Timeout();
35 void Timeout(winrt::Windows::Foundation::IReference<winrt::Windows::Foundation::TimeSpan> const& value);
36 winrt::Microsoft::WSL::Containers::VhdOptions VhdRequirements();
37 void VhdRequirements(winrt::Microsoft::WSL::Containers::VhdOptions const& value);
38 - winrt::Microsoft::WSL::Containers::SessionFeatureFlags FeatureFlags();
39 - void FeatureFlags(winrt::Microsoft::WSL::Containers::SessionFeatureFlags const& value);
38 + bool EnableGpu();
39 + void EnableGpu(bool value);
40
41 WslcSessionSettings* ToStructPointer();
42
@@ -44,10 +44,10 @@ private:
44 std::wstring m_name;
45 std::wstring m_storagePath;
46 winrt::Windows::Foundation::IReference<uint32_t> m_cpuCount{nullptr};
47 - winrt::Windows::Foundation::IReference<uint32_t> m_memoryMB{nullptr};
47 + winrt::Windows::Foundation::IReference<uint32_t> m_memorySizeInMB{nullptr};
48 winrt::Windows::Foundation::IReference<winrt::Windows::Foundation::TimeSpan> m_timeout{nullptr};
49 winrt::Microsoft::WSL::Containers::VhdOptions m_vhdRequirements{nullptr};
50 - winrt::Microsoft::WSL::Containers::SessionFeatureFlags m_featureFlags{winrt::Microsoft::WSL::Containers::SessionFeatureFlags::None};
50 + WslcSessionFeatureFlags m_featureFlags{WSLC_SESSION_FEATURE_FLAG_NONE};
51
52 std::unique_ptr<WslcSessionSettings> m_sessionSettings;
53 };
src/windows/WslcSDK/winrt/VhdOptions.cpp
+19 -13
@@ -18,10 +18,10 @@ Abstract:
18
19 namespace winrt::Microsoft::WSL::Containers::implementation {
20
21 -VhdOptions::VhdOptions(hstring const& name, uint64_t sizeInBytes, VhdType const& type) :
22 - m_name(winrt::to_string(name)), m_sizeInBytes(sizeInBytes), m_type(type)
21 +VhdOptions::VhdOptions(hstring const& name, uint64_t size, VhdType const& type) :
22 + m_name(winrt::to_string(name)), m_size(size), m_type(type)
23 {
24 - if (sizeInBytes == 0)
24 + if (size == 0)
25 {
26 throw hresult_invalid_argument(L"VHD size cannot be zero");
27 }
@@ -42,12 +42,12 @@ void VhdOptions::Name(hstring const& value)
42 m_name = winrt::to_string(value);
43 }
44
45 -uint64_t VhdOptions::SizeInBytes()
45 +uint64_t VhdOptions::Size()
46 {
47 - return m_sizeInBytes;
47 + return m_size;
48 }
49
50 -void VhdOptions::SizeInBytes(uint64_t value)
50 +void VhdOptions::Size(uint64_t value)
51 {
52 if (m_vhdOptions)
53 {
@@ -59,7 +59,7 @@ void VhdOptions::SizeInBytes(uint64_t value)
59 throw hresult_invalid_argument(L"VHD size cannot be zero");
60 }
61
62 - m_sizeInBytes = value;
62 + m_size = value;
63 }
64
65 VhdType VhdOptions::Type()
@@ -77,14 +77,19 @@ void VhdOptions::Type(VhdType const& value)
77 m_type = value;
78 }
79
80 -void VhdOptions::SetOwner(uint32_t uid, uint32_t gid)
80 +winrt::Windows::Foundation::IReference<winrt::Microsoft::WSL::Containers::VhdOwner> VhdOptions::Owner()
81 +{
82 + return m_owner;
83 +}
84 +
85 +void VhdOptions::Owner(winrt::Windows::Foundation::IReference<winrt::Microsoft::WSL::Containers::VhdOwner> const& value)
86 {
87 if (m_vhdOptions)
88 {
89 throw hresult_illegal_state_change(L"Cannot change value after options have been applied");
90 }
91
87 - m_owner = {uid, gid};
92 + m_owner = value;
93 }
94
95 WslcVhdRequirements* VhdOptions::ToStructPointer()
@@ -93,13 +98,14 @@ WslcVhdRequirements* VhdOptions::ToStructPointer()
98 {
99 m_vhdOptions = std::make_unique<WslcVhdRequirements>();
100 m_vhdOptions->name = m_name.c_str();
96 - m_vhdOptions->sizeBytes = m_sizeInBytes;
101 + m_vhdOptions->sizeBytes = m_size;
102 m_vhdOptions->type = static_cast<WslcVhdType>(m_type);
103
99 - if (m_owner)
104 + if (m_owner != nullptr)
105 {
101 - m_vhdOptions->uid = m_owner->first;
102 - m_vhdOptions->gid = m_owner->second;
106 + auto owner = m_owner.Value();
107 + m_vhdOptions->uid = owner.Uid;
108 + m_vhdOptions->gid = owner.Gid;
109 WI_SetFlag(m_vhdOptions->flags, WSLC_VHD_REQ_FLAG_OWNER);
110 }
111 }
src/windows/WslcSDK/winrt/VhdOptions.h
+10 -9
@@ -22,25 +22,26 @@ struct VhdOptions : VhdOptionsT<VhdOptions>
22 {
23 VhdOptions() = default;
24
25 - VhdOptions(hstring const& name, uint64_t sizeInBytes, winrt::Microsoft::WSL::Containers::VhdType const& type);
25 + VhdOptions(hstring const& name, uint64_t size, winrt::Microsoft::WSL::Containers::VhdType const& type);
26 hstring Name();
27 void Name(hstring const& value);
28 - uint64_t SizeInBytes();
29 - void SizeInBytes(uint64_t value);
28 + uint64_t Size();
29 + void Size(uint64_t value);
30 winrt::Microsoft::WSL::Containers::VhdType Type();
31 void Type(winrt::Microsoft::WSL::Containers::VhdType const& value);
32
33 - void SetOwner(uint32_t uid, uint32_t gid);
33 + winrt::Windows::Foundation::IReference<winrt::Microsoft::WSL::Containers::VhdOwner> Owner();
34 + void Owner(winrt::Windows::Foundation::IReference<winrt::Microsoft::WSL::Containers::VhdOwner> const& value);
35
36 WslcVhdRequirements* ToStructPointer();
37
38 private:
38 - std::string m_name;
39 - uint64_t m_sizeInBytes = s_DefaultStorageSize;
40 - winrt::Microsoft::WSL::Containers::VhdType m_type = winrt::Microsoft::WSL::Containers::VhdType::Dynamic;
41 - std::optional<std::pair<uint32_t, uint32_t>> m_owner;
39 + std::string m_name{};
40 + uint64_t m_size{s_DefaultStorageSize};
41 + winrt::Microsoft::WSL::Containers::VhdType m_type{winrt::Microsoft::WSL::Containers::VhdType::Dynamic};
42 + winrt::Windows::Foundation::IReference<winrt::Microsoft::WSL::Containers::VhdOwner> m_owner{nullptr};
43
43 - std::unique_ptr<WslcVhdRequirements> m_vhdOptions;
44 + std::unique_ptr<WslcVhdRequirements> m_vhdOptions{nullptr};
45 };
46 } // namespace winrt::Microsoft::WSL::Containers::implementation
47
src/windows/WslcSDK/winrt/WslcService.cpp
+24 -3
@@ -19,6 +19,7 @@ Abstract:
19 #include "InstallProgress.h"
20
21 using namespace winrt::Windows::Foundation;
22 +using namespace winrt::Windows::Foundation::Collections;
23
24 namespace winrt::Microsoft::WSL::Containers::implementation {
25
@@ -28,18 +29,32 @@ namespace {
29 try
30 {
31 auto installProgress = winrt::make<implementation::InstallProgress>(
31 - static_cast<winrt::Microsoft::WSL::Containers::ComponentFlags>(component), progressSteps, totalSteps);
32 + static_cast<winrt::Microsoft::WSL::Containers::Component>(component), progressSteps, totalSteps);
33 ProgressCallbackHelper<decltype(installProgress)>::ReportProgress(context, installProgress);
34 }
35 CATCH_LOG();
36 }
37 } // namespace
38
38 -winrt::Microsoft::WSL::Containers::ComponentFlags WslcService::GetMissingComponents()
39 +winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::WSL::Containers::Component> WslcService::GetMissingComponents()
40 {
41 WslcComponentFlags missing;
42 winrt::check_hresult(WslcGetMissingComponents(&missing));
42 - return static_cast<winrt::Microsoft::WSL::Containers::ComponentFlags>(missing);
43 +
44 + auto result = winrt::single_threaded_vector<winrt::Microsoft::WSL::Containers::Component>();
45 + if (WI_IsFlagSet(missing, WSLC_COMPONENT_FLAG_VIRTUAL_MACHINE_PLATFORM))
46 + {
47 + result.Append(winrt::Microsoft::WSL::Containers::Component::VirtualMachinePlatform);
48 + }
49 + if (WI_IsFlagSet(missing, WSLC_COMPONENT_FLAG_WSL_PACKAGE))
50 + {
51 + result.Append(winrt::Microsoft::WSL::Containers::Component::WslPackage);
52 + }
53 + if (WI_IsFlagSet(missing, WSLC_COMPONENT_FLAG_SDK_NEEDS_UPDATE))
54 + {
55 + result.Append(winrt::Microsoft::WSL::Containers::Component::SdkNeedsUpdate);
56 + }
57 + return result.GetView();
58 }
59
60 winrt::Microsoft::WSL::Containers::ServiceVersion WslcService::GetVersion()
@@ -52,7 +67,13 @@ winrt::Microsoft::WSL::Containers::ServiceVersion WslcService::GetVersion()
67 IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::InstallProgress> WslcService::InstallWithDependenciesAsync()
68 {
69 co_await winrt::resume_background();
70 +
71 auto context = ProgressCallbackHelper<winrt::Microsoft::WSL::Containers::InstallProgress>{co_await winrt::get_progress_token()};
72 winrt::check_hresult(WslcInstallWithDependencies(InstallProgressCallback, &context));
73 }
74 +
75 +void WslcService::InstallWithDependencies()
76 +{
77 + winrt::check_hresult(WslcInstallWithDependencies(nullptr, nullptr));
78 +}
79 } // namespace winrt::Microsoft::WSL::Containers::implementation
src/windows/WslcSDK/winrt/WslcService.h
+2 -1
@@ -21,8 +21,9 @@ struct WslcService
21 {
22 WslcService() = default;
23
24 - static winrt::Microsoft::WSL::Containers::ComponentFlags GetMissingComponents();
24 + static winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::WSL::Containers::Component> GetMissingComponents();
25 static winrt::Microsoft::WSL::Containers::ServiceVersion GetVersion();
26 + static void InstallWithDependencies();
27 static winrt::Windows::Foundation::IAsyncActionWithProgress<winrt::Microsoft::WSL::Containers::InstallProgress> InstallWithDependenciesAsync();
28 };
29 } // namespace winrt::Microsoft::WSL::Containers::implementation
src/windows/WslcSDK/winrt/precomp.h
+3
@@ -23,6 +23,9 @@ Abstract:
23 #include <winrt/Windows.Foundation.Collections.h>
24 #include <winrt/Windows.Storage.Streams.h>
25
26 +// Windows' LoadImage macro conflicts with Session::LoadImage
27 +#undef LoadImage
28 +
29 #include "Container.h"
30 #include "ContainerNamedVolume.h"
31 #include "ContainerPortMapping.h"
src/windows/WslcSDK/winrt/wslcsdk.idl
+32 -36
@@ -14,13 +14,6 @@ Abstract:
14
15 namespace Microsoft.WSL.Containers
16 {
17 - [flags]
18 - enum SessionFeatureFlags
19 - {
20 - None = 0x00000000,
21 - EnableGpu = 0x00000004
22 - };
23 -
17 enum SessionTerminationReason
18 {
19 Unknown = 0,
@@ -49,13 +42,13 @@ namespace Microsoft.WSL.Containers
42 String StoragePath;
43
44 Windows.Foundation.IReference<UInt32> CpuCount;
52 - Windows.Foundation.IReference<UInt32> MemoryMB;
45 + Windows.Foundation.IReference<UInt32> MemorySizeInMB;
46 Windows.Foundation.IReference<Windows.Foundation.TimeSpan> Timeout;
47 VhdOptions VhdRequirements;
55 - SessionFeatureFlags FeatureFlags;
48 + Boolean EnableGpu;
49 };
50
58 - runtimeclass Session
51 + runtimeclass Session : Windows.Foundation.IClosable
52 {
53 Session(SessionSettings settings);
54
@@ -64,10 +57,14 @@ namespace Microsoft.WSL.Containers
57
58 Container CreateContainer(ContainerSettings containerSettings);
59
60 + void PullImage(PullImageOptions options);
61 Windows.Foundation.IAsyncActionWithProgress<ImageProgress> PullImageAsync(PullImageOptions options);
62 // TODO: Explore additional overloads for other types of input streams
63 + void ImportImage(String path, String imageName);
64 Windows.Foundation.IAsyncActionWithProgress<ImageProgress> ImportImageAsync(String path, String imageName);
65 + void LoadImage(String path);
66 Windows.Foundation.IAsyncActionWithProgress<ImageProgress> LoadImageAsync(String path);
67 + void PushImage(PushImageOptions options);
68 Windows.Foundation.IAsyncActionWithProgress<ImageProgress> PushImageAsync(PushImageOptions options);
69
70 void DeleteImage(String nameOrId);
@@ -78,7 +75,7 @@ namespace Microsoft.WSL.Containers
75
76 String Authenticate(Windows.Foundation.Uri serverAddress, String username, String password);
77
81 - IVectorView<ImageInfo> Images { get; };
78 + IVectorView<ImageInfo> GetImages();
79
80 event SessionTerminationHandler Terminated;
81 event ProcessCrashHandler ProcessCrashed;
@@ -91,15 +88,6 @@ namespace Microsoft.WSL.Containers
88 Bridged = 1,
89 };
90
94 - [flags]
95 - enum ContainerFlags
96 - {
97 - None = 0x00000000,
98 - AutoRemove = 0x00000001,
99 - EnableGpu = 0x00000002,
100 - Privileged = 0x00000004,
101 - };
102 -
91 enum PortProtocol
92 {
93 TCP = 0,
@@ -145,7 +133,7 @@ namespace Microsoft.WSL.Containers
133 };
134
135 [flags]
148 - enum DeleteContainerFlags
136 + enum DeleteContainerOption
137 {
138 None = 0,
139 Force = 0x00000001
@@ -162,7 +150,9 @@ namespace Microsoft.WSL.Containers
150 Windows.Foundation.IReference<ContainerNetworkingMode> NetworkingMode;
151 String HostName;
152 String DomainName;
165 - ContainerFlags Flags;
153 + Boolean EnableAutoRemove;
154 + Boolean EnableGpu;
155 + Boolean Privileged;
156 IVector<ContainerPortMapping> PortMappings;
157 IVector<ContainerVolume> Volumes;
158 IVector<ContainerNamedVolume> NamedVolumes;
@@ -178,14 +168,15 @@ namespace Microsoft.WSL.Containers
168 SIGTERM = 15, // SIGTERM: graceful shutdown
169 };
170
181 - runtimeclass Container
171 + runtimeclass Container : Windows.Foundation.IClosable
172 {
173 void Start();
174 void Stop(Signal signal, Windows.Foundation.TimeSpan timeout);
185 - void Delete(DeleteContainerFlags flags);
175 + void Delete(DeleteContainerOption flags);
176
177 Process CreateProcess(ProcessSettings newProcessSettings);
178
179 + // JSON response schema at: https://docs.docker.com/reference/api/engine/version/v1.53/#tag/Container/operation/ContainerInspect
180 String Inspect();
181
182 String Id { get; };
@@ -211,7 +202,7 @@ namespace Microsoft.WSL.Containers
202 ProcessSettings();
203
204 String WorkingDirectory;
214 - IVector<String> CmdLine;
205 + IVector<String> CommandLine;
206 IMap<String, String> EnvironmentVariables;
207 ProcessOutputMode OutputMode;
208 };
@@ -227,7 +218,7 @@ namespace Microsoft.WSL.Containers
218 delegate void ProcessOutputHandler(UInt8[] data);
219 delegate void ProcessExitHandler(Int32 exitCode);
220
230 - runtimeclass Process
221 + runtimeclass Process : Windows.Foundation.IClosable
222 {
223 void Start();
224
@@ -244,10 +235,8 @@ namespace Microsoft.WSL.Containers
235 event ProcessExitHandler Exited;
236 };
237
247 - [flags]
248 - enum ComponentFlags
238 + enum Component
239 {
250 - None = 0,
240 VirtualMachinePlatform = 1,
241 WslPackage = 2,
242 SdkNeedsUpdate = 4,
@@ -262,15 +251,16 @@ namespace Microsoft.WSL.Containers
251
252 runtimeclass InstallProgress
253 {
265 - ComponentFlags Component { get; };
254 + Component Component { get; };
255 UInt32 Progress { get; };
256 UInt32 Total { get; };
257 };
258
259 runtimeclass WslcService
260 {
272 - static ComponentFlags GetMissingComponents();
261 + static IVectorView<Component> GetMissingComponents();
262 static ServiceVersion GetVersion();
263 + static void InstallWithDependencies();
264 static Windows.Foundation.IAsyncActionWithProgress<InstallProgress> InstallWithDependenciesAsync();
265 };
266
@@ -280,18 +270,24 @@ namespace Microsoft.WSL.Containers
270 Fixed = 1,
271 };
272
273 + struct VhdOwner
274 + {
275 + UInt32 Uid;
276 + UInt32 Gid;
277 + };
278 +
279 runtimeclass VhdOptions
280 {
285 - VhdOptions(String name, UInt64 sizeInBytes, VhdType type);
281 + VhdOptions(String name, UInt64 size, VhdType type);
282
283 String Name;
288 - UInt64 SizeInBytes;
284 + UInt64 Size;
285 VhdType Type;
286
291 - // Sets owner uid/gid on the volume root inode at mkfs time. Only
287 + // Owner uid/gid on the volume root inode at mkfs time. Only
288 // supported on named volumes; setting this on a SessionSettings
289 // VhdOptions fails at property-set time with E_INVALIDARG.
294 - void SetOwner(UInt32 uid, UInt32 gid);
290 + Windows.Foundation.IReference<VhdOwner> Owner;
291 };
292
293 enum ImageProgressStatus
@@ -342,7 +338,7 @@ namespace Microsoft.WSL.Containers
338 {
339 String Name { get; };
340 Windows.Storage.Streams.IBuffer Sha256 { get; };
345 - UInt64 SizeBytes { get; };
341 + UInt64 Size { get; };
342 Windows.Foundation.DateTime CreatedTimestamp { get; };
343 };
344
test/windows/WslcSdkWinRTTests.cpp
+80 -82
@@ -51,7 +51,7 @@ extern bool g_fastTestRun;
51 } \
52 CATCH_LOG()
53 #define SCOPE_CLEANUP(operation) wil::scope_exit([&]() { IGNORE_ERRORS(operation) })
54 -#define DELETE_CONTAINER_ON_SCOPE_EXIT(container) SCOPE_CLEANUP(container.Delete(WSLCSDK::DeleteContainerFlags::Force))
54 +#define DELETE_CONTAINER_ON_SCOPE_EXIT(container) SCOPE_CLEANUP(container.Delete(WSLCSDK::DeleteContainerOption::Force))
55 #define DELETE_IMAGE_ON_SCOPE_EXIT(imageName) SCOPE_CLEANUP(m_defaultSession.DeleteImage(imageName))
56
57 struct ProcessOutput
@@ -152,8 +152,8 @@ class WslcSdkWinRtTests
152
153 struct RunContainerOptions
154 {
155 - std::vector<winrt::hstring> cmdLine = {};
156 - WSLCSDK::ContainerFlags flags = WSLCSDK::ContainerFlags::None;
155 + std::vector<winrt::hstring> commandLine = {};
156 + bool enableGpu = false;
157 std::optional<winrt::hstring> name = std::nullopt;
158 std::chrono::milliseconds timeout = 2min;
159 std::optional<WSLCSDK::ContainerNetworkingMode> networkingMode = std::nullopt;
@@ -164,16 +164,16 @@ class WslcSdkWinRtTests
164 ProcessOutput RunContainerAndWaitForExit(winrt::hstring imageName, RunContainerOptions options = {})
165 {
166 auto procSettings = WSLCSDK::ProcessSettings();
167 - if (!options.cmdLine.empty())
167 + if (!options.commandLine.empty())
168 {
169 - procSettings.CmdLine(winrt::single_threaded_vector(std::move(options.cmdLine)));
169 + procSettings.CommandLine(winrt::single_threaded_vector(std::move(options.commandLine)));
170 }
171
172 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Stream);
173
174 auto containerSettings = WSLCSDK::ContainerSettings(imageName);
175 containerSettings.InitProcess(procSettings);
176 - containerSettings.Flags(options.flags);
176 + containerSettings.EnableGpu(options.enableGpu);
177
178 if (options.name)
179 {
@@ -191,14 +191,14 @@ class WslcSdkWinRtTests
191 StartContainerAndWaitForInitProcessExit(container, options.timeout);
192 auto output = GetProcessOutput(container.InitProcess());
193
194 - IGNORE_ERRORS(container.Delete(WSLCSDK::DeleteContainerFlags::Force));
194 + IGNORE_ERRORS(container.Delete(WSLCSDK::DeleteContainerOption::Force));
195
196 return output;
197 }
198
199 bool HasImage(winrt::hstring const& imageName)
200 {
201 - auto images = m_defaultSession.Images();
201 + auto images = m_defaultSession.GetImages();
202 return std::any_of(images.begin(), images.end(), [&](auto const& img) { return img.Name() == imageName; });
203 }
204
@@ -244,7 +244,7 @@ class WslcSdkWinRtTests
244 // Build session settings using the WinRT API
245 auto settings = WSLCSDK::SessionSettings(c_testSessionName, m_storagePath.wstring());
246 settings.CpuCount(4);
247 - settings.MemoryMB(2048);
247 + settings.MemorySizeInMB(2048);
248 settings.Timeout(std::chrono::duration_cast<TimeSpan>(30s));
249 settings.VhdRequirements(WSLCSDK::VhdOptions(L"", 4096ull * 1024 * 1024, WSLCSDK::VhdType::Dynamic));
250
@@ -293,7 +293,7 @@ class WslcSdkWinRtTests
293
294 auto settings = WSLCSDK::SessionSettings(L"wslc-winrt-extra-session", extraStorage.wstring());
295 settings.CpuCount(2);
296 - settings.MemoryMB(1024);
296 + settings.MemorySizeInMB(1024);
297 settings.Timeout(std::chrono::duration_cast<TimeSpan>(30s));
298 settings.VhdRequirements(WSLCSDK::VhdOptions(L"", 1024ull * 1024 * 1024, WSLCSDK::VhdType::Dynamic));
299
@@ -306,7 +306,7 @@ class WslcSdkWinRtTests
306 // Negative: Must throw if used before Start()
307 {
308 auto session = WSLCSDK::Session(settings);
309 - VERIFY_THROWS_HR(std::ignore = session.Images(), E_ILLEGAL_METHOD_CALL);
309 + VERIFY_THROWS_HR(std::ignore = session.GetImages(), E_ILLEGAL_METHOD_CALL);
310 }
311
312 // Positive: Starting the session must succeed.
@@ -350,7 +350,7 @@ class WslcSdkWinRtTests
350 // drops kill()-sent signals with default disposition when targeting PID 1 in a
351 // PID namespace, so no core dump would be generated if we crash the init process.
352 auto initProcSettings = WSLCSDK::ProcessSettings();
353 - initProcSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
353 + initProcSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
354
355 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
356 containerSettings.InitProcess(initProcSettings);
@@ -375,7 +375,7 @@ class WslcSdkWinRtTests
375 });
376
377 auto execSettings = WSLCSDK::ProcessSettings();
378 - execSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"kill -SEGV $$"}));
378 + execSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"kill -SEGV $$"}));
379
380 const auto beforeCrash = winrt::clock::now();
381 StartProcessAndWaitForExit(container.CreateProcess(execSettings), 30s);
@@ -407,7 +407,7 @@ class WslcSdkWinRtTests
407 }
408
409 auto execSettings = WSLCSDK::ProcessSettings();
410 - execSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"kill -SEGV $$"}));
410 + execSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"kill -SEGV $$"}));
411
412 StartProcessAndWaitForExit(container.CreateProcess(execSettings), 60s);
413
@@ -449,14 +449,14 @@ class WslcSdkWinRtTests
449 WSLC_TEST_METHOD(ImageList)
450 {
451 // Session has images pre-loaded - list must return at least one entry.
452 - const auto images = m_defaultSession.Images();
452 + const auto images = m_defaultSession.GetImages();
453 VERIFY_IS_TRUE(images.Size() >= 1);
454
455 // At least one image must be non-empty
456 bool foundNonEmpty = false;
457 for (auto const& img : images)
458 {
459 - if (!img.Name().empty() && img.SizeBytes() != 0)
459 + if (!img.Name().empty() && img.Size() != 0)
460 {
461 foundNonEmpty = true;
462 break;
@@ -510,7 +510,7 @@ class WslcSdkWinRtTests
510
511 VERIFY_IS_TRUE(HasImage(c_importedImageName));
512
513 - auto output = RunContainerAndWaitForExit(c_importedImageName, {.cmdLine = {L"/hello"}});
513 + auto output = RunContainerAndWaitForExit(c_importedImageName, {.commandLine = {L"/hello"}});
514 VERIFY_ARE_EQUAL(output.ExitCode, 0);
515 VERIFY_IS_TRUE(output.StandardOutput.find(L"Hello from Docker!") != std::string::npos);
516 }
@@ -560,7 +560,7 @@ class WslcSdkWinRtTests
560 {
561 // Positive: stdout is captured correctly.
562 {
563 - auto output = RunContainerAndWaitForExit(L"debian:latest", {.cmdLine = {L"/bin/echo", L"OK"}});
563 + auto output = RunContainerAndWaitForExit(L"debian:latest", {.commandLine = {L"/bin/echo", L"OK"}});
564 VERIFY_ARE_EQUAL(output.ExitCode, 0);
565 VERIFY_ARE_EQUAL(output.StandardOutput, L"OK\n");
566 VERIFY_ARE_EQUAL(output.StandardError, L"");
@@ -568,8 +568,8 @@ class WslcSdkWinRtTests
568
569 // Positive: stdout and stderr are routed independently.
570 {
571 - auto output =
572 - RunContainerAndWaitForExit(L"debian:latest", {.cmdLine = {L"/bin/sh", L"-c", L"echo stdout && echo stderr >&2"}});
571 + auto output = RunContainerAndWaitForExit(
572 + L"debian:latest", {.commandLine = {L"/bin/sh", L"-c", L"echo stdout && echo stderr >&2"}});
573 VERIFY_ARE_EQUAL(output.ExitCode, 0);
574 VERIFY_ARE_EQUAL(output.StandardOutput, L"stdout\n");
575 VERIFY_ARE_EQUAL(output.StandardError, L"stderr\n");
@@ -606,7 +606,7 @@ class WslcSdkWinRtTests
606 WSLC_TEST_METHOD(ContainerGetState)
607 {
608 auto procSettings = WSLCSDK::ProcessSettings();
609 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
609 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
610
611 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
612 containerSettings.InitProcess(procSettings);
@@ -631,7 +631,7 @@ class WslcSdkWinRtTests
631 WSLC_TEST_METHOD(ContainerStopAndDelete)
632 {
633 auto procSettings = WSLCSDK::ProcessSettings();
634 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"999"}));
634 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"999"}));
635
636 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
637 containerSettings.InitProcess(procSettings);
@@ -644,14 +644,14 @@ class WslcSdkWinRtTests
644 VERIFY_NO_THROW(container.Stop(WSLCSDK::Signal::SIGKILL, TimeSpan::zero()));
645 VERIFY_ARE_EQUAL(container.State(), WSLCSDK::ContainerState::Exited);
646
647 - VERIFY_NO_THROW(container.Delete(WSLCSDK::DeleteContainerFlags::None));
647 + VERIFY_NO_THROW(container.Delete(WSLCSDK::DeleteContainerOption::None));
648 VERIFY_ARE_EQUAL(container.State(), WSLCSDK::ContainerState::Deleted);
649 }
650
651 WSLC_TEST_METHOD(ProcessIOHandles)
652 {
653 auto procSettings = WSLCSDK::ProcessSettings();
654 - procSettings.CmdLine(
654 + procSettings.CommandLine(
655 winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"echo STDOUT_TOKEN; echo STDERR_TOKEN >&2"}));
656 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Stream);
657
@@ -689,8 +689,7 @@ class WslcSdkWinRtTests
689 {
690 auto output = RunContainerAndWaitForExit(
691 L"debian:latest",
692 - {.cmdLine = {L"/bin/sh", L"-c", L"[ -d /sys/class/net/eth0 ] && echo 'HAS_ETH0' || echo 'NO_ETH0'"},
693 - .flags = WSLCSDK::ContainerFlags::None,
692 + {.commandLine = {L"/bin/sh", L"-c", L"[ -d /sys/class/net/eth0 ] && echo 'HAS_ETH0' || echo 'NO_ETH0'"},
693 .networkingMode = WSLCSDK::ContainerNetworkingMode::Bridged});
694
695 VERIFY_ARE_EQUAL(output.StandardOutput, L"HAS_ETH0\n");
@@ -700,8 +699,7 @@ class WslcSdkWinRtTests
699 {
700 auto output = RunContainerAndWaitForExit(
701 L"debian:latest",
703 - {.cmdLine = {L"/bin/sh", L"-c", L"[ -d /sys/class/net/eth0 ] && echo 'HAS_ETH0' || echo 'NO_ETH0'"},
704 - .flags = WSLCSDK::ContainerFlags::None,
702 + {.commandLine = {L"/bin/sh", L"-c", L"[ -d /sys/class/net/eth0 ] && echo 'HAS_ETH0' || echo 'NO_ETH0'"},
703 .networkingMode = WSLCSDK::ContainerNetworkingMode::None});
704
705 VERIFY_ARE_EQUAL(output.StandardOutput, L"NO_ETH0\n");
@@ -729,7 +727,7 @@ class WslcSdkWinRtTests
727 // Functional: BRIDGED networking with port mapping; HTTP server must be reachable.
728 {
729 auto procSettings = WSLCSDK::ProcessSettings();
732 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"python3", L"-m", L"http.server", L"8000"}));
730 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"python3", L"-m", L"http.server", L"8000"}));
731 procSettings.EnvironmentVariables(
732 winrt::single_threaded_map(std::map<winrt::hstring, winrt::hstring>{{L"PYTHONUNBUFFERED", L"1"}}));
733 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Stream);
@@ -754,7 +752,7 @@ class WslcSdkWinRtTests
752 // Functional: port mapping with explicit IPv4 WindowsAddress.
753 {
754 auto procSettings = WSLCSDK::ProcessSettings();
757 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"python3", L"-m", L"http.server", L"8000"}));
755 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"python3", L"-m", L"http.server", L"8000"}));
756 procSettings.EnvironmentVariables(
757 winrt::single_threaded_map(std::map<winrt::hstring, winrt::hstring>{{L"PYTHONUNBUFFERED", L"1"}}));
758 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Stream);
@@ -781,7 +779,7 @@ class WslcSdkWinRtTests
779 // Functional: port mapping with explicit IPv6 WindowsAddress.
780 {
781 auto procSettings = WSLCSDK::ProcessSettings();
784 - procSettings.CmdLine(
782 + procSettings.CommandLine(
783 winrt::single_threaded_vector<winrt::hstring>({L"python3", L"-m", L"http.server", L"--bind", L"::", L"8000"}));
784 procSettings.EnvironmentVariables(
785 winrt::single_threaded_map(std::map<winrt::hstring, winrt::hstring>{{L"PYTHONUNBUFFERED", L"1"}}));
@@ -837,7 +835,7 @@ class WslcSdkWinRtTests
835 containerSettings.Volumes(winrt::single_threaded_vector<WSLCSDK::ContainerVolume>(
836 {WSLCSDK::ContainerVolume(currentDirectory, L"/mnt/path", false)}));
837 auto container = m_defaultSession.CreateContainer(containerSettings);
840 - container.Delete(WSLCSDK::DeleteContainerFlags::None);
838 + container.Delete(WSLCSDK::DeleteContainerOption::None);
839 }
840 }
841
@@ -869,7 +867,7 @@ class WslcSdkWinRtTests
867 "! touch /mnt/ro/probe 2>/dev/null";
868
869 auto procSettings = WSLCSDK::ProcessSettings();
872 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", winrt::to_hstring(c_script)}));
870 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", winrt::to_hstring(c_script)}));
871
872 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
873 containerSettings.InitProcess(procSettings);
@@ -882,7 +880,7 @@ class WslcSdkWinRtTests
880 StartContainerAndWaitForInitProcessExit(container);
881
882 VERIFY_ARE_EQUAL(container.InitProcess().ExitCode(), 0);
885 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
883 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
884
885 // Verify the file written by the container is visible on the host.
886 std::ifstream written(hostRwDir / "written.txt");
@@ -905,7 +903,7 @@ class WslcSdkWinRtTests
903 // The inspect JSON must contain the container ID.
904 VERIFY_IS_TRUE(winrt::to_string(inspectJson).find(winrt::to_string(id)) != std::string::npos);
905
908 - container.Delete(WSLCSDK::DeleteContainerFlags::None);
906 + container.Delete(WSLCSDK::DeleteContainerOption::None);
907 cleanup.release();
908 }
909
@@ -913,7 +911,7 @@ class WslcSdkWinRtTests
911 {
912 // Start a long-running container so we can exec into it.
913 auto initProcSettings = WSLCSDK::ProcessSettings();
916 - initProcSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
914 + initProcSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
915
916 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
917 containerSettings.InitProcess(initProcSettings);
@@ -926,7 +924,7 @@ class WslcSdkWinRtTests
924 // Positive: exec a command that exits 0.
925 {
926 auto execSettings = WSLCSDK::ProcessSettings();
929 - execSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/true"}));
927 + execSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/true"}));
928
929 auto execProcess = container.CreateProcess(execSettings);
930 StartProcessAndWaitForExit(execProcess);
@@ -948,7 +946,7 @@ class WslcSdkWinRtTests
946 // Functional: container process should see the configured hostname.
947 {
948 auto procSettings = WSLCSDK::ProcessSettings();
951 - procSettings.CmdLine(
949 + procSettings.CommandLine(
950 winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"test \"$(hostname)\" = my-test-host"}));
951
952 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -958,14 +956,14 @@ class WslcSdkWinRtTests
956 auto container = m_defaultSession.CreateContainer(containerSettings);
957 StartContainerAndWaitForInitProcessExit(container);
958 VERIFY_ARE_EQUAL(container.InitProcess().ExitCode(), 0);
961 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
959 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
960 }
961 }
962
963 WSLC_TEST_METHOD(ContainerDomainName)
964 {
965 auto procSettings = WSLCSDK::ProcessSettings();
968 - procSettings.CmdLine(
966 + procSettings.CommandLine(
967 winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"test \"$(domainname)\" = test.local"}));
968
969 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -975,7 +973,7 @@ class WslcSdkWinRtTests
973 auto container = m_defaultSession.CreateContainer(containerSettings);
974 StartContainerAndWaitForInitProcessExit(container);
975 VERIFY_ARE_EQUAL(container.InitProcess().ExitCode(), 0);
978 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
976 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
977 }
978
979 // -----------------------------------------------------------------------
@@ -985,7 +983,7 @@ class WslcSdkWinRtTests
983 WSLC_TEST_METHOD(ProcessEnvVariables)
984 {
985 auto procSettings = WSLCSDK::ProcessSettings();
988 - procSettings.CmdLine(
986 + procSettings.CommandLine(
987 winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"test \"$MY_TEST_VAR\" = hello-from-test"}));
988 procSettings.EnvironmentVariables(
989 winrt::single_threaded_map(std::map<winrt::hstring, winrt::hstring>{{L"MY_TEST_VAR", L"hello-from-test"}}));
@@ -996,7 +994,7 @@ class WslcSdkWinRtTests
994 auto container = m_defaultSession.CreateContainer(containerSettings);
995 StartContainerAndWaitForInitProcessExit(container);
996 VERIFY_ARE_EQUAL(container.InitProcess().ExitCode(), 0);
999 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
997 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
998 }
999
1000 WSLC_TEST_METHOD(ProcessSignal)
@@ -1008,7 +1006,7 @@ class WslcSdkWinRtTests
1006 }
1007
1008 auto procSettings = WSLCSDK::ProcessSettings();
1011 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1009 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1010
1011 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1012 containerSettings.InitProcess(procSettings);
@@ -1041,7 +1039,7 @@ class WslcSdkWinRtTests
1039 }
1040
1041 auto procSettings = WSLCSDK::ProcessSettings();
1044 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1042 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1043
1044 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1045 containerSettings.InitProcess(procSettings);
@@ -1059,7 +1057,7 @@ class WslcSdkWinRtTests
1057 {
1058 auto runAndGetExitCode = [&](int code) -> int32_t {
1059 auto procSettings = WSLCSDK::ProcessSettings();
1062 - procSettings.CmdLine(
1060 + procSettings.CommandLine(
1061 winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", winrt::to_hstring(std::format("exit {}", code))}));
1062
1063 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -1069,7 +1067,7 @@ class WslcSdkWinRtTests
1067 StartContainerAndWaitForInitProcessExit(container);
1068 auto exitCode = container.InitProcess().ExitCode();
1069
1072 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
1070 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
1071 return exitCode;
1072 };
1073
@@ -1079,7 +1077,7 @@ class WslcSdkWinRtTests
1077 // Negative: querying ExitCode while process is still running must throw.
1078 {
1079 auto procSettings = WSLCSDK::ProcessSettings();
1082 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1080 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1081
1082 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1083 containerSettings.InitProcess(procSettings);
@@ -1099,7 +1097,7 @@ class WslcSdkWinRtTests
1097 WSLC_TEST_METHOD(ProcessGetState)
1098 {
1099 auto procSettings = WSLCSDK::ProcessSettings();
1102 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1100 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1101
1102 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1103 containerSettings.InitProcess(procSettings);
@@ -1136,7 +1134,7 @@ class WslcSdkWinRtTests
1134 {
1135 // Functional: container should see the configured working directory.
1136 auto procSettings = WSLCSDK::ProcessSettings();
1139 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"test \"$(pwd)\" = /tmp"}));
1137 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"test \"$(pwd)\" = /tmp"}));
1138 procSettings.WorkingDirectory(L"/tmp");
1139
1140 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -1145,7 +1143,7 @@ class WslcSdkWinRtTests
1143 auto container = m_defaultSession.CreateContainer(containerSettings);
1144 StartContainerAndWaitForInitProcessExit(container);
1145 VERIFY_ARE_EQUAL(container.InitProcess().ExitCode(), 0);
1148 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
1146 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
1147 }
1148
1149 // -----------------------------------------------------------------------
@@ -1161,13 +1159,13 @@ class WslcSdkWinRtTests
1159 WSLC_TEST_METHOD(GetMissingComponents)
1160 {
1161 const auto missing = WSLCSDK::WslcService::GetMissingComponents();
1164 - VERIFY_ARE_EQUAL(missing, WSLCSDK::ComponentFlags::None);
1162 + VERIFY_ARE_EQUAL(missing.Size(), 0u);
1163 }
1164
1165 WSLC_TEST_METHOD(InstallWithDependencies)
1166 {
1167 WSLCSDK::WslcService::InstallWithDependenciesAsync().get();
1170 - VERIFY_ARE_EQUAL(WSLCSDK::WslcService::GetMissingComponents(), WSLCSDK::ComponentFlags::None);
1168 + VERIFY_ARE_EQUAL(WSLCSDK::WslcService::GetMissingComponents().Size(), 0u);
1169 }
1170
1171 // -----------------------------------------------------------------------
@@ -1179,7 +1177,7 @@ class WslcSdkWinRtTests
1177 // Negative: registering OutputReceived/ErrorReceived without OutputMode::Event must throw.
1178 {
1179 auto procSettings = WSLCSDK::ProcessSettings();
1182 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"1"}));
1180 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"1"}));
1181
1182 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1183 containerSettings.InitProcess(procSettings);
@@ -1199,7 +1197,7 @@ class WslcSdkWinRtTests
1197 // Positive: with OutputMode::Event, registering and revoking event handlers must succeed.
1198 {
1199 auto procSettings = WSLCSDK::ProcessSettings();
1202 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"1"}));
1200 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"1"}));
1201 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Event);
1202
1203 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -1226,7 +1224,7 @@ class WslcSdkWinRtTests
1224 // Negative: OutputReceived/ErrorReceived with OutputMode::Stream must throw.
1225 {
1226 auto procSettings = WSLCSDK::ProcessSettings();
1229 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"1"}));
1227 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"1"}));
1228 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Stream);
1229
1230 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -1246,7 +1244,7 @@ class WslcSdkWinRtTests
1244 std::string stdoutData, stderrData;
1245
1246 auto procSettings = WSLCSDK::ProcessSettings();
1249 - procSettings.CmdLine(
1247 + procSettings.CommandLine(
1248 winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"echo STDOUT && echo STDERR >&2"}));
1249 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Event);
1250
@@ -1274,7 +1272,7 @@ class WslcSdkWinRtTests
1272 {
1273 // Long-running init process to keep the container alive.
1274 auto initProcSettings = WSLCSDK::ProcessSettings();
1277 - initProcSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1275 + initProcSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1276
1277 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1278 containerSettings.InitProcess(initProcSettings);
@@ -1287,7 +1285,7 @@ class WslcSdkWinRtTests
1285 std::string stdoutData, stderrData;
1286
1287 auto execProcSettings = WSLCSDK::ProcessSettings();
1290 - execProcSettings.CmdLine(
1288 + execProcSettings.CommandLine(
1289 winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"echo EXEC_OUT && echo EXEC_ERR >&2"}));
1290 execProcSettings.OutputMode(WSLCSDK::ProcessOutputMode::Event);
1291
@@ -1312,7 +1310,7 @@ class WslcSdkWinRtTests
1310 // (draining uncallbacked streams to prevent deadlock), so both stdout and stderr
1311 // handles are consumed and neither can be obtained via GetOutputStream.
1312 auto procSettings = WSLCSDK::ProcessSettings();
1315 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1313 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"99"}));
1314 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Event);
1315
1316 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -1341,7 +1339,7 @@ class WslcSdkWinRtTests
1339 std::promise<int32_t> exitPromise;
1340
1341 auto procSettings = WSLCSDK::ProcessSettings();
1344 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>(
1342 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>(
1343 {L"/bin/sh", L"-c", winrt::hstring(std::format(L"echo HELLO && exit {}", exitCodeArg))}));
1344 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Event);
1345
@@ -1388,7 +1386,7 @@ class WslcSdkWinRtTests
1386
1387 // Long-running init process to keep the container alive.
1388 auto initProcSettings = WSLCSDK::ProcessSettings();
1391 - initProcSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"999"}));
1389 + initProcSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"999"}));
1390
1391 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1392 containerSettings.InitProcess(initProcSettings);
@@ -1402,7 +1400,7 @@ class WslcSdkWinRtTests
1400 std::atomic<bool> exitFired{false};
1401
1402 auto execProcSettings = WSLCSDK::ProcessSettings();
1405 - execProcSettings.CmdLine(
1403 + execProcSettings.CommandLine(
1404 winrt::single_threaded_vector<winrt::hstring>({L"/bin/sh", L"-c", L"while true; do echo LINE; sleep 0.05; done"}));
1405 execProcSettings.OutputMode(WSLCSDK::ProcessOutputMode::Event);
1406
@@ -1441,7 +1439,7 @@ class WslcSdkWinRtTests
1439 stdoutData.reserve(c_expectedBytes + 4096);
1440
1441 auto procSettings = WSLCSDK::ProcessSettings();
1444 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>(
1442 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>(
1443 {L"/bin/sh", L"-c", L"dd if=/dev/zero bs=1024 count=1024 2>/dev/null | base64 -w 0"}));
1444 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Event);
1445
@@ -1495,7 +1493,7 @@ class WslcSdkWinRtTests
1493 // Positive: write a marker via a container that mounts the named volume.
1494 {
1495 auto procSettings = WSLCSDK::ProcessSettings();
1498 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>(
1496 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>(
1497 {L"/bin/sh", L"-c", L"echo wslc-winrt-vhd-test > /data/marker.txt"}));
1498
1499 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -1506,13 +1504,13 @@ class WslcSdkWinRtTests
1504 auto container = session.CreateContainer(containerSettings);
1505 StartContainerAndWaitForInitProcessExit(container);
1506 VERIFY_ARE_EQUAL(container.InitProcess().ExitCode(), 0);
1509 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
1507 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
1508 }
1509
1510 // Positive: read back the marker in a second container (read-only mount).
1511 {
1512 auto procSettings = WSLCSDK::ProcessSettings();
1515 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>(
1513 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>(
1514 {L"/bin/sh", L"-c", L"test \"$(cat /data/marker.txt)\" = wslc-winrt-vhd-test"}));
1515
1516 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -1523,7 +1521,7 @@ class WslcSdkWinRtTests
1521 auto container = session.CreateContainer(containerSettings);
1522 StartContainerAndWaitForInitProcessExit(container);
1523 VERIFY_ARE_EQUAL(container.InitProcess().ExitCode(), 0);
1526 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
1524 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
1525 }
1526
1527 // Positive: delete the volume.
@@ -1533,7 +1531,7 @@ class WslcSdkWinRtTests
1531 // Negative: zero size must fail.
1532 VERIFY_THROWS_HR(session.CreateVhdVolume(WSLCSDK::VhdOptions(c_volumeName, 0, WSLCSDK::VhdType::Dynamic)), E_INVALIDARG);
1533
1536 - // Positive: fixed-allocation VHD; on-disk file size must be >= SizeBytes.
1534 + // Positive: fixed-allocation VHD; on-disk file size must be >= Size.
1535 {
1536 constexpr auto c_fixedVolumeName = L"wslc-sdk-vhd-fixed";
1537 constexpr auto c_fixedSizeBytes = 64ull * _1MB;
@@ -1546,18 +1544,18 @@ class WslcSdkWinRtTests
1544 VERIFY_IS_GREATER_THAN_OR_EQUAL(std::filesystem::file_size(expectedVhdPath), c_fixedSizeBytes);
1545 }
1546
1549 - // Positive: SetOwner() bakes uid/gid into the volume root inode at mkfs time.
1547 + // Positive: Owner() bakes uid/gid into the volume root inode at mkfs time.
1548 // Verify by stat-ing the mount inside a container.
1549 {
1550 constexpr auto c_ownedVolumeName = L"wslc-sdk-vhd-owned";
1551 auto vhdOptions = WSLCSDK::VhdOptions(c_ownedVolumeName, c_vhdSizeBytes, WSLCSDK::VhdType::Dynamic);
1554 - vhdOptions.SetOwner(65534, 65534); // nobody:nogroup
1552 + vhdOptions.Owner(WSLCSDK::VhdOwner{65534, 65534}); // nobody:nogroup
1553 session.CreateVhdVolume(vhdOptions);
1554
1555 auto deleteVolume = SCOPE_CLEANUP(session.DeleteVhdVolume(c_ownedVolumeName));
1556
1557 auto procSettings = WSLCSDK::ProcessSettings();
1560 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/usr/bin/stat", L"-c", L"%u %g", L"/data"}));
1558 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/usr/bin/stat", L"-c", L"%u %g", L"/data"}));
1559 procSettings.OutputMode(WSLCSDK::ProcessOutputMode::Stream);
1560
1561 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
@@ -1570,7 +1568,7 @@ class WslcSdkWinRtTests
1568 auto output = GetProcessOutput(container.InitProcess());
1569 VERIFY_ARE_EQUAL(container.InitProcess().ExitCode(), 0);
1570 VERIFY_ARE_EQUAL(output.StandardOutput, L"65534 65534\n");
1573 - container.Delete(WSLCSDK::DeleteContainerFlags::Force);
1571 + container.Delete(WSLCSDK::DeleteContainerOption::Force);
1572 }
1573 }
1574
@@ -1695,7 +1693,7 @@ class WslcSdkWinRtTests
1693 WSLC_TEST_METHOD(ExecOnStoppedContainer)
1694 {
1695 auto procSettings = WSLCSDK::ProcessSettings();
1698 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"10"}));
1696 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"10"}));
1697
1698 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1699 containerSettings.InitProcess(procSettings);
@@ -1707,7 +1705,7 @@ class WslcSdkWinRtTests
1705
1706 // The init process has now exited. Attempting to exec on a stopped container must fail.
1707 auto execSettings = WSLCSDK::ProcessSettings();
1710 - execSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/echo", L"should-fail"}));
1708 + execSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/echo", L"should-fail"}));
1709
1710 VERIFY_THROWS_HR(container.CreateProcess(execSettings).Start(), static_cast<HRESULT>(WSLC_E_CONTAINER_NOT_RUNNING));
1711 }
@@ -1715,7 +1713,7 @@ class WslcSdkWinRtTests
1713 WSLC_TEST_METHOD(DuplicateContainerName)
1714 {
1715 auto procSettings = WSLCSDK::ProcessSettings();
1718 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"10"}));
1716 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"10"}));
1717
1718 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1719 containerSettings.InitProcess(procSettings);
@@ -1733,7 +1731,7 @@ class WslcSdkWinRtTests
1731 WSLC_TEST_METHOD(DeleteRunningContainerWithoutForce)
1732 {
1733 auto procSettings = WSLCSDK::ProcessSettings();
1736 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"10"}));
1734 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>({L"/bin/sleep", L"10"}));
1735
1736 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1737 containerSettings.InitProcess(procSettings);
@@ -1744,7 +1742,7 @@ class WslcSdkWinRtTests
1742 auto cleanup = DELETE_CONTAINER_ON_SCOPE_EXIT(container);
1743
1744 // Deleting a running container without Force must fail.
1747 - VERIFY_THROWS_HR(container.Delete(WSLCSDK::DeleteContainerFlags::None), static_cast<HRESULT>(WSLC_E_CONTAINER_IS_RUNNING));
1745 + VERIFY_THROWS_HR(container.Delete(WSLCSDK::DeleteContainerOption::None), static_cast<HRESULT>(WSLC_E_CONTAINER_IS_RUNNING));
1746 }
1747
1748 WSLC_TEST_METHOD(DeleteNonExistentImage)
@@ -1762,7 +1760,7 @@ class WslcSdkWinRtTests
1760 // Negative: creating a GPU container on a session without GPU support must fail.
1761 {
1762 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1765 - containerSettings.Flags(WSLCSDK::ContainerFlags::EnableGpu);
1763 + containerSettings.EnableGpu(true);
1764
1765 VERIFY_THROWS_HR(m_defaultSession.CreateContainer(containerSettings).Start(), HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
1766 }
@@ -1775,7 +1773,7 @@ class WslcSdkWinRtTests
1773 });
1774
1775 auto settings = WSLCSDK::SessionSettings(L"wslc-winrt-gpu-test", gpuStorage.wstring());
1778 - settings.FeatureFlags(WSLCSDK::SessionFeatureFlags::EnableGpu);
1776 + settings.EnableGpu(true);
1777 settings.VhdRequirements(WSLCSDK::VhdOptions(L"", 4096ull * 1024 * 1024, WSLCSDK::VhdType::Dynamic));
1778
1779 auto gpuSession = WSLCSDK::Session(settings);
@@ -1788,7 +1786,7 @@ class WslcSdkWinRtTests
1786 // the WSL GPU libraries inside a GPU container.
1787 {
1788 auto procSettings = WSLCSDK::ProcessSettings();
1791 - procSettings.CmdLine(winrt::single_threaded_vector<winrt::hstring>(
1789 + procSettings.CommandLine(winrt::single_threaded_vector<winrt::hstring>(
1790 {L"/bin/sh",
1791 L"-c",
1792 L"test -c /dev/dxg && test -r /dev/dxg && test -w /dev/dxg && cat /etc/ld.so.conf.d/ld.wsl.conf"}));
@@ -1796,7 +1794,7 @@ class WslcSdkWinRtTests
1794
1795 auto containerSettings = WSLCSDK::ContainerSettings(L"debian:latest");
1796 containerSettings.InitProcess(procSettings);
1799 - containerSettings.Flags(WSLCSDK::ContainerFlags::EnableGpu);
1797 + containerSettings.EnableGpu(true);
1798
1799 auto container = gpuSession.CreateContainer(containerSettings);
1800 auto cleanup = DELETE_CONTAINER_ON_SCOPE_EXIT(container);