Skip to content
Draft
Changes from 1 commit
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
348 changes: 348 additions & 0 deletions src/windows/WslcSDK/wslcsdk-winrt.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,348 @@
/*++

Copyright (c) Microsoft. All rights reserved.

Module Name:

wslcsdk.idl
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

Header comment has Module Name: wslcsdk.idl, but the file is wslcsdk-winrt.idl. Consider updating the module name to match the actual filename to avoid confusion when this is referenced in build/scripts.

Suggested change
wslcsdk.idl
wslcsdk-winrt.idl

Copilot uses AI. Check for mistakes.

Abstract:

This file contains the public WSL Container SDK api definitions.

--*/

namespace Microsoft.WSL.Containers
{
[flags]
enum SessionFeatureFlags
{
None = 0x00000000,
EnableGpu = 0x00000004
};

enum SessionTerminationReason
{
Unknown = 0,
Shutdown = 1,
Crashed = 2,
};

delegate void SessionTerminationHandler(Session session, SessionTerminationReason reason);
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.

I changed "Callback" to "Handler" because I think that's more idiomatic in C#


runtimeclass SessionSettings
{
SessionSettings(String name, String storagePath);

String Name { get; };
String StoragePath { get; };

UInt32 CpuCount { get; set; };
UInt32 MemoryMb { get; set; };
UInt32 TimeoutMS { get; set; };
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

TimeoutMS uses a different casing convention than the other properties (MemoryMb, CpuCount). For C# projections this will surface as an awkward TimeoutMS property name. Consider using consistent PascalCase with standard abbreviations (e.g., TimeoutMs) to align with the rest of this IDL and typical .NET naming.

Suggested change
UInt32 TimeoutMS { get; set; };
UInt32 TimeoutMs { get; set; };

Copilot uses AI. Check for mistakes.
VhdRequirements VhdRequirements { get; set; };
SessionFeatureFlags FeatureFlags { get; set; };
SessionTerminationHandler TerminationHandler { get; set; };
};

runtimeclass Session
{
static Session Create(SessionSettings settings);

void Terminate();

void PullImage(PullImageOptions options);

// C# equivalent type: System.IO.StreamReader
void ImportImage(String imageName, Windows.Storage.Streams.IInputStream imageStream, ImportImageOptions options);
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.

The C API uses a HANDLE for the image content. I changed it to a stream based on what I understood from how it's used, but I may be wrong.

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.

I don't think we can easily do that unfortunately, since the actual implementation of this API will have no way to "transform" a stream back to a handle to give it to the service

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

ImportImage only takes an IInputStream, but the underlying WSLC APIs require a content length (COM IWSLCSession::ImportImage takes ContentLength). IInputStream doesn’t reliably expose length, so implementations may be forced to buffer the entire stream. Consider using a size-bearing WinRT type (e.g., IRandomAccessStream/IRandomAccessStreamReference) or add an explicit UInt64 contentLength parameter.

Suggested change
void ImportImage(String imageName, Windows.Storage.Streams.IInputStream imageStream, ImportImageOptions options);
void ImportImage(String imageName, Windows.Storage.Streams.IInputStream imageStream, UInt64 contentLength, ImportImageOptions options);

Copilot uses AI. Check for mistakes.
void ImportImageFromFile(String imageName, String path, ImportImageOptions options);

// C# equivalent type: System.IO.StreamReader
void LoadImage(Windows.Storage.Streams.IInputStream imageStream, LoadImageOptions options);
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

LoadImage only takes an IInputStream, but the underlying WSLC APIs require a content length (COM IWSLCSession::LoadImage takes ContentLength). IInputStream doesn’t reliably expose length, so implementations may be forced to buffer the entire stream. Consider using a size-bearing WinRT type (e.g., IRandomAccessStream/IRandomAccessStreamReference) or add an explicit UInt64 contentLength parameter.

Suggested change
void LoadImage(Windows.Storage.Streams.IInputStream imageStream, LoadImageOptions options);
void LoadImage(Windows.Storage.Streams.IInputStream imageStream, UInt64 contentLength, LoadImageOptions options);

Copilot uses AI. Check for mistakes.
void LoadImageFromFile(String path, LoadImageOptions options);

void DeleteSessionImage(String nameOrId);

void CreateSessionVhdVolume(VhdRequirements options);
void DeleteSessionVhdVolume(String name);

// C# projected type: System.Collections.Generic.IReadOnlyList<ImageInfo>
IVectorView<ImageInfo> Images { get; };
};


enum ContainerNetworkingMode
{
None = 0,
Bridged = 1,
};

[flags]
enum ContainerFlags
{
None = 0x00000000,
AutoRemove = 0x00000001,
EnableGpu = 0x00000002,
Privileged = 0x00000004,
};

enum PortProtocol
{
TCP = 0,
UDP = 1,
};

runtimeclass ContainerPortMapping
{
ContainerPortMapping(UInt16 windowsPort, UInt16 containerPort, PortProtocol protocol);

UInt16 WindowsPort { get; };
UInt16 ContainerPort { get; };
PortProtocol Protocol { get; };

// TODO sockaddr_storage* WindowsAddress { get; set; };
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 one I didn't know how to map, so I left it as a TODO for now.

};

runtimeclass ContainerVolume
{
ContainerVolume(String windowsPath, String containerPath, Boolean readOnly);

String WindowsPath { get; };
String ContainerPath { get; };
Boolean ReadOnly { get; };
};

runtimeclass ContainerNamedVolume
{
ContainerNamedVolume(String name, String containerPath, Boolean readOnly);

String Name { get; };
String ContainerPath { get; };
Boolean ReadOnly { get; };
};

[flags]
enum ContainerStartFlags
{
None = 0x00000000,
Attach = 0x00000001,
};

enum ContainerState
{
Invalid = 0,
Created = 1,
Running = 2,
Exited = 3,
Deleted = 4,
};

[flags]
enum DeleteContainerFlags
{
None = 0,
Force = 0x01
};

runtimeclass ContainerSettings
{
ContainerSettings(String imageName);

String ImageName { get; };

String Name { get; set; };
ProcessSettings InitProcess { get; set; };
ContainerNetworkingMode NetworkingMode { get; set; };
String HostName { get; set; };
String DomainName { get; set; };
ContainerFlags Flags { get; set; };
// C# projected type: System.Collections.Generic.IList<ContainerPortMapping>
IVector<ContainerPortMapping> PortMappings { get; set; };
// C# projected type: System.Collections.Generic.IList<ContainerVolume>
IVector<ContainerVolume> Volumes { get; set; };
// C# projected type: System.Collections.Generic.IList<ContainerNamedVolume>
IVector<ContainerNamedVolume> NamedVolumes { get; set; };
};

enum Signal
{
None = 0, // No signal; reserved for future use
SIGHUP = 1, // SIGHUP: reload / hangup
SIGINT = 2, // SIGINT: interrupt (Ctrl-C)
SIGQUIT = 3, // SIGQUIT: quit with core dump
SIGKILL = 9, // SIGKILL: immediate termination
SIGTERM = 15, // SIGTERM: graceful shutdown


runtimeclass Container
{
static Container Create(Session session, ContainerSettings containerSettings);

void Start(ContainerStartFlags flags);
void Stop(Signal signal, UInt32 timeoutSeconds);
void Delete(DeleteContainerFlags flags);

Process CreateProcess(ProcessSettings newProcessSettings);

String Inspect();

String Id { get; };
Process InitProcess { get; };
ContainerState State { get; };
};

enum ProcessOutputHandle
{
StandardOutput = 1,
StandardError = 2,
};

delegate void ProcessOutputHandler(UInt8[] data);

delegate void ProcessExitHandler(Process process, Int32 exitCode);

runtimeclass ProcessEventHandlers
{
ProcessEventHandlers();

ProcessOutputHandler OnStdOut { get; set; };
ProcessOutputHandler OnStdErr { get; set; };
ProcessExitHandler OnExit { get; set; };
};

runtimeclass ProcessSettings
{
ProcessSettings();

String CurrentDirectory { get; set; };
// C projected type: System.Collections.Generic.IList<String>
IVector<String> CmdLine { get; set; };
// C# equivalent type: System.Collections.Specialized.StringDictionary
// C# projected type: System.Collections.Generic.IDictionary<string,string?>
Comment on lines +220 to +221
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.

C# equivalent type: What we could use if we define it in C# directly.
C# projected type: What we would get if we use CsWinRT to get a projection from the .idl.

IMap<String, String> EnvironmentVariables { get; set; };
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 an array of strings in the C API. I changed it to match the C# Process type.

ProcessEventHandlers EventHandlers { get; set; };
};
Comment on lines +221 to +224
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The API exposes both callback-style process I/O (ProcessSettings.EventHandlers) and stream-style I/O (Process.GetOutputStream/GetInputStream). In the existing C SDK these are mutually exclusive (callbacks consume the stdio handles), so the WinRT surface should either enforce the same exclusivity (fail fast if streams are requested when handlers are set) or clearly document which takes precedence to avoid surprising runtime failures.

Copilot uses AI. Check for mistakes.

enum ProcessState
{
Unknown = 0,
Running = 1,
Exited = 2,
Signalled = 3,
};

runtimeclass Process
{
UInt32 Pid { get; };
ProcessState State { get; };
Int32 ExitCode { get; };

void Signal(Signal signal);
// C# equivalent Windowstype: System.IO.StreamReader
Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle);
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.

In this direction I think returning a stream is the right thing to do for C#, but doing so will prevent the caller from doing asynchronous IO on stdout & stderr.

I'm not sure that there's an easy way to represent this in C#, but maybe what we could do could be to return a subclass of IInputStream that has a "GetHandle()" method to get the best of both worlds

// C# type: System.IO.StreamWriter
Windows.Storage.Streams.IOutputStream GetInputStream();
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.

These are a single function in the C API. For WinRT there is no generic Stream type that can do both AFAICT, but if we do direct C# implementation it can be a System.IO.Stream and a single function to match.

Comment on lines +242 to +244
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

GetOutputStream returns an IInputStream (read end) and GetInputStream returns an IOutputStream (write end). The names are easy to misread as “stream you write output to” vs “stream you read input from”. Consider renaming to make direction explicit (e.g., GetStdOutStream/GetStdErrStream/GetStdInStream) so callers don’t accidentally invert read/write usage.

Suggested change
Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle);
// C# type: System.IO.Stream
Windows.Storage.Streams.IOutputStream GetInputStream();
Windows.Storage.Streams.IInputStream GetStandardIoOutputReader(ProcessOutputHandle ioHandle);
// C# type: System.IO.Stream
Windows.Storage.Streams.IOutputStream GetStandardInputWriter();

Copilot uses AI. Check for mistakes.

event ProcessExitHandler Exited;
};

[flags]
enum ComponentFlags
{
None = 0,
VirtualMachinePlatform = 1,
WslPackage = 2,
};

struct Version
{
UInt32 Major;
UInt32 Minor;
UInt32 Revision;
};

delegate void InstallProgressHandler(ComponentFlags component, UInt32 progress, UInt32 total);

runtimeclass WslcService
{
static Boolean CanRun(out ComponentFlags missingComponents);
static Version GetVersion();
static void InstallWithDependencies(InstallProgressHandler progressCallback);
};

enum VhdType
{
Dynamic = 0,
Fixed = 1,
};

runtimeclass VhdRequirements
{
VhdRequirements(String name, UInt64 sizeInBytes, VhdType type);

String Name { get; };
UInt64 SizeInBytes { get; };
VhdType Type { get; };
};

struct ImageProgressDetail
{
UInt64 Current;
UInt64 Total;
};

enum ImageProgressStatus
{
Unknown = 0,
Pulling = 1,
Waiting = 2,
Downloading = 3,
Verifying = 4,
Extracting = 5,
Complete = 6,
};

struct ImageProgressMessage
{
String Id;
ImageProgressStatus Status;
ImageProgressDetail Detail;
};

delegate void ImageProgressHandler(ImageProgressMessage progress);

runtimeclass RegistryAuthenticationInformation
{
// TBD
String Placeholder {get; set;};
Comment on lines +314 to +317
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

RegistryAuthenticationInformation currently exposes a Placeholder property. If this IDL is intended to be a public SDK surface, shipping a placeholder member is likely to become a breaking-change trap when real auth fields are introduced. Consider either omitting AuthInfo until the shape is defined, or defining a minimal but real contract (e.g., auth scheme + token/username/password) now.

Suggested change
runtimeclass RegistryAuthenticationInformation
{
// TBD
String Placeholder {get; set;};
enum RegistryAuthenticationScheme
{
None = 0,
Basic = 1,
BearerToken = 2,
};
runtimeclass RegistryAuthenticationInformation
{
RegistryAuthenticationScheme Scheme { get; set; };
String Username { get; set; };
String Password { get; set; };
String Token { get; set; };

Copilot uses AI. Check for mistakes.
};

runtimeclass PullImageOptions
{
PullImageOptions(String uri);

String Uri { get; };
ImageProgressHandler ProgressHandler { get; set; };
RegistryAuthenticationInformation AuthInfo { get; set; };
};

runtimeclass ImportImageOptions
{
ImageProgressHandler ProgressHandler { get; set; };
};
runtimeclass LoadImageOptions
{
ImageProgressHandler ProgressHandler { get; set; };
};

runtimeclass ImageInfo
{
String Name { get; };
// C# equivalent type: byte[]
Windows.Storage.Streams.IBuffer Sha256 { get; };
UInt64 SizeBytes { get; };
// C# equivalent type: System.DateTime
// C# projected type. System.DateTimeOffset
Windows.Foundation.DateTime CreatedTimestamp { get; };
};
}