Skip to content

Definition for SDK projection / object model#40121

Draft
florelis wants to merge 2 commits intomicrosoft:feature/wsl-for-appsfrom
florelis:sdk-midl
Draft

Definition for SDK projection / object model#40121
florelis wants to merge 2 commits intomicrosoft:feature/wsl-for-appsfrom
florelis:sdk-midl

Conversation

@florelis
Copy link
Copy Markdown
Member

@florelis florelis commented Apr 6, 2026

This is a proposal for a projection / object model for the SDK API, specifically intended for the C# projection.

It is written in MIDL 3, which means it represents a WinRT interface, but everything maps directly to C# so it should still allow us to talk about the design of the interface.

This is more or less a direct translation of the C header.

  • Mapped all the structs to classes.
  • Mapped the settings/options types that had required fields to classes with a single constructor taking the required fields, exposing them as read-only, and everything else as a settable property.
  • Mapped the creation of the main objects (like Session) to a static Create() factory method to avoid having constructors that may throw (and in case we ever want to have an async variant).
  • Mapped the handles used for loading an image to use an input stream type, based on what I understood of how it's used.
  • Removed the Release() functions.
  • Replaced the handle for the exit event by using an actual event.
  • Split WslcGetProcessIOHandle() into two functions to be able to return properly typed input/output streams.
  • Removed the error message out parameters, as the language supports exceptions.

This interface could be implemented in C++ as WinRT, and then using CsWinRT we can get a pretty natural C# projection with no or minimal changes. That would allow us to not have to deal with raw pointers and having to pin data from C#.

Copilot AI review requested due to automatic review settings April 6, 2026 21:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a proposed WinRT (MIDL 3) object model for the WSLC SDK intended to enable a natural C# projection (e.g., via CsWinRT) without raw pointers/handles.

Changes:

  • Introduces a new WinRT IDL describing Sessions, Containers, Processes, and related settings/options types as runtimeclasses/enums/delegates.
  • Replaces several handle/callback-style patterns with WinRT-friendly constructs (streams, events/delegates, factory methods).
  • Defines supporting types for install/version reporting and image progress reporting.

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#

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.

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.

IVector<String> CmdLine { get; set; };
// C# equivalent type: System.Collections.Specialized.StringDictionary
// C# projected type: System.Collections.Generic.IDictionary<string,string?>
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.

Comment on lines +241 to +244
// C# equivalent Windowstype: System.IO.StreamReader
Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle);
// 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 +220 to +221
// C# equivalent type: System.Collections.Specialized.StringDictionary
// C# projected type: System.Collections.Generic.IDictionary<string,string?>
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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 8 comments.


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.
Comment on lines +314 to +317
runtimeclass RegistryAuthenticationInformation
{
// TBD
String Placeholder {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.

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.
Comment on lines +221 to +224
// C# projected type: System.Collections.Generic.IDictionary<string,string?>
IMap<String, String> EnvironmentVariables { get; set; };
ProcessEventHandlers EventHandlers { 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.

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.
void PullImage(PullImageOptions options);

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

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# type: System.IO.Stream
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.
Comment on lines +241 to +243
// C# type: System.IO.Stream
Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle);
// C# type: System.IO.Stream
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 comments indicate these methods project to System.IO.Stream, but the WinRT signatures return IInputStream/IOutputStream. Unless your projection layer adds custom adapters, CsWinRT will surface WinRT stream interfaces here, so the comment may be inaccurate. Consider clarifying in the comment how .NET callers should obtain a Stream (or adjust the API surface accordingly).

Suggested change
// C# type: System.IO.Stream
Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle);
// C# type: System.IO.Stream
// C# projected type: Windows.Storage.Streams.IInputStream
// .NET callers can adapt this to System.IO.Stream using the standard WinRT stream extension methods if needed.
Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle);
// C# projected type: Windows.Storage.Streams.IOutputStream
// .NET callers can adapt this to System.IO.Stream using the standard WinRT stream extension methods if needed.

Copilot uses AI. Check for mistakes.
Comment on lines +242 to +244
Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle);
// C# type: System.IO.Stream
Windows.Storage.Streams.IOutputStream GetInputStream();
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.

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants